[Rt-commit] rt branch, master, updated. rt-4.1.6-82-ge88e1b8

Alex Vandiver alexmv at bestpractical.com
Wed Jan 16 18:43:24 EST 2013


The branch, master has been updated
       via  e88e1b8dccf686e62aadadfa5183b192937f5722 (commit)
       via  a1d66f6b7465f93e0bf01bac0d7cf1c568b486e2 (commit)
       via  4ce7ee69b1ff0331441863a62d4ddc023f3e99f4 (commit)
       via  fc223e12eb194dd6ee4482d23f588da6ddf2ea39 (commit)
       via  1dee3fd6e761593863734ac0c8e62ae185381e40 (commit)
       via  507e226eb60ac1451e0d4bdc81ba75603beba6b4 (commit)
       via  2b86810ad2c9610bbebad7d2e2b2889dacbc5d35 (commit)
       via  6dd02cbb781d952c59eeda44db33f35eeebb0085 (commit)
       via  5bf8bcfcd0527f5b2f3df0c7faefc4cb538bfba3 (commit)
       via  5da1fb270fe0df5e6ec48493281061696e3782cc (commit)
       via  b3dda046d78a197fc3ce1c88b4fc4737ec960abb (commit)
       via  af82074c2f49cdeb4a0aab2839c778b45204c97f (commit)
       via  c003785d13fcb9267ab431b3efb46fa25053244c (commit)
       via  242fee056d8a611ccdc7db80fd050797b768a493 (commit)
       via  e4abe1956e5baf9dcff8cfd35a0d85a800424b08 (commit)
       via  f67d6ced2e0561ca88313031b528b187cfdcbccd (commit)
       via  bfd1f18f48d6b6a340ff7f943dc0b207ec59bd73 (commit)
       via  83fe8566e7d2e6e88bd8e82cf81425c72a54d358 (commit)
       via  e8ba13f980f21445aa3daac53091a7173506e1c1 (commit)
       via  ea2d72f7f56057a0c402435793d82516eabe0ad5 (commit)
       via  8126c55507ecb17bbcadacb2b39368fd82e50ca0 (commit)
       via  89ab6e6c68475bd70bc49003b3445a19f095bdbe (commit)
       via  fb86e1b9153adc2e4024e52c27abfffb0c616475 (commit)
       via  280a48c59fc90d8ef734c61068ee06dc2d6dff06 (commit)
       via  522788cd9bb1f3638088d8aae0ddbdda1c7f3cfc (commit)
       via  34bd21a256b1a8c17848b73b33db7d56821d3323 (commit)
       via  260239ee9bce09b62d45e2bc89a4b0ea4e570d8d (commit)
       via  8296c7fb124d83d4d4e43e3c7732c6704ffc83c7 (commit)
       via  82e95bcd9da3ab7b4deec8096dda536589d0d1d5 (commit)
       via  82db49450d4e643ef9ae35750b73729f8bda7921 (commit)
       via  57a3879de223865b656137f97c18f4e2ffc43f8c (commit)
       via  8310ae76a7b58c283e70d3c4b1f1e2eee8665eed (commit)
       via  32cbe5378010716656e05effa38e226b22ccce4a (commit)
       via  73137e74d64b7abf3a0bfb87eb975d21c57fdeae (commit)
       via  d684b5798ea5c72e61b45738fb65167d737ffaef (commit)
       via  63447eea5437b7dbdac1ade8cfdc30b5ee0fa8e9 (commit)
       via  f0e2cdaeb686d290a783bd7ef68f17f3469737a9 (commit)
       via  ac2f9f9ef858efefe34075b45f1885725e2762a7 (commit)
       via  d5bc26912534315361fb0a0d0833d62c4e9b5300 (commit)
       via  080e0abc7e92ed1a3c543b59464ccbe97c467dfd (commit)
       via  888ccc3b41ab6130c111f9aa25db5d7fa96c37c9 (commit)
       via  d8cdb11605707e839ef5649aea5116c1cce04e1b (commit)
       via  f4ddf057f52d3815e0650a72f018abb61314c016 (commit)
       via  3878a73e493aecc3d48e4a11f701bef418358a41 (commit)
       via  4b1ddff04fee8f495050505c97f5734bedce2b19 (commit)
       via  e7e391ce9da59cdd2daa0c20e6844f46d0dfa5ba (commit)
       via  ea40af18601d337d4c8e067942b07ca81e78d774 (commit)
       via  78b7db504afbe489f5fcf2049745354af7879342 (commit)
       via  76b8a64bf81781cfd8462de91b38019c9fbf73a5 (commit)
       via  d9b23316c95ec0403c2da22565c47d3f3018fef1 (commit)
       via  ff960b2b752ef57ad19eeb442d92888ee3d2bfff (commit)
       via  11024f4115175e8fc9f6a92e589e28b5d45e83e0 (commit)
       via  d589a1052bc27a227a9d0e8c83013a61696e5b68 (commit)
       via  f69b46cda25bef472237d08332c289b1792ee7f9 (commit)
       via  4cd6bb6727d0902a583067d51004cb03543e1878 (commit)
       via  869de6884d7a2e3ab9ea9dda1b810a6ad810ed07 (commit)
       via  36a79711bfc0d1b541f252c5341eb8cfc067b3e6 (commit)
       via  3cb96ef3deb55e536a09b4af19adad29a94e0856 (commit)
       via  db2d5aa187b8a12eed8f6ebb55c0e1831591ea93 (commit)
       via  deba89e24e13ec34ccdd7fab9c557144e1fd8b94 (commit)
       via  efe8bc7b153f7c29083405977444cffb9aef49ca (commit)
       via  db66946956d94d6229f79be1808e7f1815613ca2 (commit)
      from  79a157f2bc9c5ac457bfa407300106ecaf12c6e3 (commit)

Summary of changes:
 Makefile.in                                        |   2 +-
 README                                             |   2 +-
 bin/rt-crontool.in                                 |   2 +-
 bin/rt-mailgate.in                                 |   2 +-
 bin/rt.in                                          |   2 +-
 devel/tools/change-loc-msgstr                      |   2 +-
 devel/tools/cmd-boilerplate                        |   2 +-
 devel/tools/extract-message-catalog                |   2 +-
 devel/tools/license_tag                            |   4 +-
 devel/tools/merge-rosetta.pl                       |   2 +-
 devel/tools/rt-apache                              |   2 +-
 devel/tools/rt-attributes-editor                   |   2 +-
 devel/tools/rt-static-docs                         |   8 +-
 devel/tools/tweak-template-locstring               |   2 +-
 docs/UPGRADING-4.0                                 |  25 ++
 docs/customizing/lifecycles.pod                    | 448 +++++++++++++++++++++
 docs/customizing/styling_rt.pod                    | 169 ++++++++
 docs/images/action-decline.png                     | Bin 0 -> 16331 bytes
 docs/images/global-lifecycle-group-rights.png      | Bin 0 -> 47224 bytes
 docs/images/lifecycle-choices.png                  | Bin 0 -> 14691 bytes
 docs/images/order-history-example.png              | Bin 0 -> 190835 bytes
 docs/images/theme_editor_defaults.png              | Bin 0 -> 131855 bytes
 etc/upgrade/3.8-branded-queues-extension.in        |   2 +-
 etc/upgrade/3.8-ical-extension.in                  |   2 +-
 etc/upgrade/3.9.8/content                          |   2 +-
 etc/upgrade/4.0.9/content                          |  26 +-
 etc/upgrade/generate-rtaddressregexp.in            |   2 +-
 etc/upgrade/sanity-check-stylesheets.pl            |   2 +-
 etc/upgrade/shrink_cgm_table.pl                    |   2 +-
 etc/upgrade/shrink_transactions_table.pl           |   2 +-
 etc/upgrade/split-out-cf-categories.in             |   2 +-
 etc/upgrade/upgrade-articles.in                    |   2 +-
 etc/upgrade/upgrade-mysql-schema.pl                |   2 +-
 etc/upgrade/vulnerable-passwords.in                |   2 +-
 lib/RT.pm                                          |   2 +-
 lib/RT/ACE.pm                                      |   2 +-
 lib/RT/ACL.pm                                      |   2 +-
 lib/RT/Action.pm                                   |   2 +-
 lib/RT/Action/AutoOpen.pm                          |   2 +-
 lib/RT/Action/Autoreply.pm                         |   2 +-
 lib/RT/Action/CreateTickets.pm                     |   2 +-
 lib/RT/Action/EscalatePriority.pm                  |   2 +-
 lib/RT/Action/ExtractSubjectTag.pm                 |   2 +-
 lib/RT/Action/LinearEscalate.pm                    |   2 +-
 lib/RT/Action/Notify.pm                            |   2 +-
 lib/RT/Action/NotifyAsComment.pm                   |   2 +-
 lib/RT/Action/NotifyGroup.pm                       |   2 +-
 lib/RT/Action/NotifyGroupAsComment.pm              |   2 +-
 lib/RT/Action/RecordComment.pm                     |   2 +-
 lib/RT/Action/RecordCorrespondence.pm              |   2 +-
 lib/RT/Action/SendEmail.pm                         |   2 +-
 lib/RT/Action/SetPriority.pm                       |   2 +-
 lib/RT/Action/SetStatus.pm                         |   2 +-
 lib/RT/Action/UserDefined.pm                       |   2 +-
 lib/RT/Approval.pm                                 |   2 +-
 lib/RT/Approval/Rule.pm                            |   2 +-
 lib/RT/Approval/Rule/Created.pm                    |   2 +-
 lib/RT/Approval/Rule/NewPending.pm                 |   2 +-
 lib/RT/Approval/Rule/Passed.pm                     |   2 +-
 lib/RT/Approval/Rule/Rejected.pm                   |   2 +-
 lib/RT/Article.pm                                  |   2 +-
 lib/RT/Articles.pm                                 |   2 +-
 lib/RT/Attachment.pm                               |   2 +-
 lib/RT/Attachments.pm                              |   2 +-
 lib/RT/Attribute.pm                                |   2 +-
 lib/RT/Attributes.pm                               |   2 +-
 lib/RT/Base.pm                                     |   2 +-
 lib/RT/CachedGroupMember.pm                        |   2 +-
 lib/RT/CachedGroupMembers.pm                       |   2 +-
 lib/RT/Class.pm                                    |   2 +-
 lib/RT/Classes.pm                                  |   2 +-
 lib/RT/Condition.pm                                |   2 +-
 lib/RT/Condition/AnyTransaction.pm                 |   2 +-
 lib/RT/Condition/BeforeDue.pm                      |   2 +-
 lib/RT/Condition/CloseTicket.pm                    |   2 +-
 lib/RT/Condition/Overdue.pm                        |   2 +-
 lib/RT/Condition/OwnerChange.pm                    |   2 +-
 lib/RT/Condition/PriorityChange.pm                 |   2 +-
 lib/RT/Condition/PriorityExceeds.pm                |   2 +-
 lib/RT/Condition/QueueChange.pm                    |   2 +-
 lib/RT/Condition/ReopenTicket.pm                   |   2 +-
 lib/RT/Condition/StatusChange.pm                   |   2 +-
 lib/RT/Condition/UserDefined.pm                    |   2 +-
 lib/RT/Config.pm                                   |   2 +-
 lib/RT/Crypt/GnuPG.pm                              |   2 +-
 lib/RT/CurrentUser.pm                              |   2 +-
 lib/RT/CustomField.pm                              |   2 +-
 lib/RT/CustomFieldValue.pm                         |   2 +-
 lib/RT/CustomFieldValues.pm                        |   2 +-
 lib/RT/CustomFieldValues/External.pm               |   2 +-
 lib/RT/CustomFieldValues/Groups.pm                 |   2 +-
 lib/RT/CustomFields.pm                             |   2 +-
 lib/RT/Dashboard.pm                                |   2 +-
 lib/RT/Dashboard/Mailer.pm                         |   2 +-
 lib/RT/Dashboards.pm                               |   2 +-
 lib/RT/Date.pm                                     |   2 +-
 lib/RT/EmailParser.pm                              |   2 +-
 lib/RT/Generated.pm.in                             |   2 +-
 lib/RT/Graph/Tickets.pm                            |   2 +-
 lib/RT/Group.pm                                    |   2 +-
 lib/RT/GroupMember.pm                              |   2 +-
 lib/RT/GroupMembers.pm                             |   2 +-
 lib/RT/Groups.pm                                   |   2 +-
 lib/RT/Handle.pm                                   |   2 +-
 lib/RT/I18N.pm                                     |   2 +-
 lib/RT/I18N/cs.pm                                  |   2 +-
 lib/RT/I18N/i_default.pm                           |   2 +-
 lib/RT/I18N/ru.pm                                  |   2 +-
 lib/RT/Installer.pm                                |   2 +-
 lib/RT/Interface/CLI.pm                            |   2 +-
 lib/RT/Interface/Email.pm                          |   2 +-
 lib/RT/Interface/Email/Auth/GnuPG.pm               |   2 +-
 lib/RT/Interface/Email/Auth/MailFrom.pm            |   2 +-
 lib/RT/Interface/REST.pm                           |   2 +-
 lib/RT/Interface/Web.pm                            |  74 +++-
 lib/RT/Interface/Web/Handler.pm                    |   2 +-
 lib/RT/Interface/Web/Menu.pm                       |   2 +-
 lib/RT/Interface/Web/QueryBuilder.pm               |   2 +-
 lib/RT/Interface/Web/QueryBuilder/Tree.pm          |   2 +-
 lib/RT/Interface/Web/Request.pm                    |   2 +-
 lib/RT/Interface/Web/Session.pm                    |   2 +-
 lib/RT/Lifecycle.pm                                |   2 +-
 lib/RT/Lifecycle/Ticket.pm                         |   2 +-
 lib/RT/Link.pm                                     |   2 +-
 lib/RT/Links.pm                                    |   2 +-
 lib/RT/ObjectClass.pm                              |   2 +-
 lib/RT/ObjectClasses.pm                            |   2 +-
 lib/RT/ObjectCustomField.pm                        |   3 +-
 lib/RT/ObjectCustomFieldValue.pm                   |   2 +-
 lib/RT/ObjectCustomFieldValues.pm                  |   2 +-
 lib/RT/ObjectCustomFields.pm                       |   3 +-
 lib/RT/ObjectScrip.pm                              |   2 +-
 lib/RT/ObjectScrips.pm                             |   2 +-
 lib/RT/ObjectTopic.pm                              |   2 +-
 lib/RT/ObjectTopics.pm                             |   2 +-
 lib/RT/Plugin.pm                                   |   2 +-
 lib/RT/Pod/HTML.pm                                 |   2 +-
 lib/RT/Pod/HTMLBatch.pm                            |   2 +-
 lib/RT/Pod/Search.pm                               |   2 +-
 lib/RT/Principal.pm                                |   2 +-
 lib/RT/Principals.pm                               |   2 +-
 lib/RT/Queue.pm                                    |   2 +-
 lib/RT/Queues.pm                                   |   2 +-
 lib/RT/Record.pm                                   |   2 +-
 lib/RT/Record/AddAndSort.pm                        |   2 +-
 lib/RT/Reminders.pm                                |   2 +-
 lib/RT/Report/Tickets.pm                           |   2 +-
 lib/RT/Report/Tickets/Entry.pm                     |   2 +-
 lib/RT/Role/Record.pm                              |   2 +-
 lib/RT/Role/Record/Lifecycle.pm                    |   2 +-
 lib/RT/Role/Record/Status.pm                       |   2 +-
 lib/RT/Rule.pm                                     |   2 +-
 lib/RT/Ruleset.pm                                  |   2 +-
 lib/RT/SQL.pm                                      |   2 +-
 lib/RT/SavedSearch.pm                              |   2 +-
 lib/RT/SavedSearches.pm                            |   2 +-
 lib/RT/Scrip.pm                                    |   2 +-
 lib/RT/ScripAction.pm                              |   2 +-
 lib/RT/ScripActions.pm                             |   2 +-
 lib/RT/ScripCondition.pm                           |   2 +-
 lib/RT/ScripConditions.pm                          |   2 +-
 lib/RT/Scrips.pm                                   |   2 +-
 lib/RT/Search.pm                                   |   2 +-
 lib/RT/Search/ActiveTicketsInQueue.pm              |   2 +-
 lib/RT/Search/FromSQL.pm                           |   2 +-
 lib/RT/Search/Googleish.pm                         |   2 +-
 lib/RT/SearchBuilder.pm                            |   2 +-
 lib/RT/SearchBuilder/AddAndSort.pm                 |   2 +-
 lib/RT/SharedSetting.pm                            |   2 +-
 lib/RT/SharedSettings.pm                           |   2 +-
 lib/RT/Shredder.pm                                 |   2 +-
 lib/RT/Shredder/ACE.pm                             |   2 +-
 lib/RT/Shredder/Attachment.pm                      |   2 +-
 lib/RT/Shredder/CachedGroupMember.pm               |   2 +-
 lib/RT/Shredder/Constants.pm                       |   2 +-
 lib/RT/Shredder/CustomField.pm                     |   2 +-
 lib/RT/Shredder/CustomFieldValue.pm                |   2 +-
 lib/RT/Shredder/Dependencies.pm                    |   2 +-
 lib/RT/Shredder/Dependency.pm                      |   2 +-
 lib/RT/Shredder/Exceptions.pm                      |   2 +-
 lib/RT/Shredder/Group.pm                           |   2 +-
 lib/RT/Shredder/GroupMember.pm                     |   2 +-
 lib/RT/Shredder/Link.pm                            |   2 +-
 lib/RT/Shredder/ObjectCustomFieldValue.pm          |   2 +-
 lib/RT/Shredder/POD.pm                             |   2 +-
 lib/RT/Shredder/Plugin.pm                          |   2 +-
 lib/RT/Shredder/Plugin/Attachments.pm              |   2 +-
 lib/RT/Shredder/Plugin/Base.pm                     |   2 +-
 lib/RT/Shredder/Plugin/Base/Dump.pm                |   2 +-
 lib/RT/Shredder/Plugin/Base/Search.pm              |   2 +-
 lib/RT/Shredder/Plugin/Objects.pm                  |   2 +-
 lib/RT/Shredder/Plugin/SQLDump.pm                  |   2 +-
 lib/RT/Shredder/Plugin/Summary.pm                  |   2 +-
 lib/RT/Shredder/Plugin/Tickets.pm                  |   2 +-
 lib/RT/Shredder/Plugin/Users.pm                    |   2 +-
 lib/RT/Shredder/Principal.pm                       |   2 +-
 lib/RT/Shredder/Queue.pm                           |   2 +-
 lib/RT/Shredder/Record.pm                          |   2 +-
 lib/RT/Shredder/Scrip.pm                           |   2 +-
 lib/RT/Shredder/ScripAction.pm                     |   2 +-
 lib/RT/Shredder/ScripCondition.pm                  |   2 +-
 lib/RT/Shredder/Template.pm                        |   2 +-
 lib/RT/Shredder/Ticket.pm                          |   2 +-
 lib/RT/Shredder/Transaction.pm                     |   2 +-
 lib/RT/Shredder/User.pm                            |   2 +-
 lib/RT/Squish.pm                                   |   2 +-
 lib/RT/Squish/CSS.pm                               |   2 +-
 lib/RT/Squish/JS.pm                                |   2 +-
 lib/RT/System.pm                                   |   2 +-
 lib/RT/Template.pm                                 |   2 +-
 lib/RT/Templates.pm                                |   2 +-
 lib/RT/Test.pm                                     |   2 +-
 lib/RT/Test/Apache.pm                              |   2 +-
 lib/RT/Test/Email.pm                               |   2 +-
 lib/RT/Test/GnuPG.pm                               |   2 +-
 lib/RT/Test/Shredder.pm                            |   2 +-
 lib/RT/Test/Web.pm                                 |   2 +-
 lib/RT/Ticket.pm                                   |   2 +-
 lib/RT/Tickets.pm                                  |   7 +-
 lib/RT/Tickets_SQL.pm                              |  11 +-
 lib/RT/Topic.pm                                    |   2 +-
 lib/RT/Topics.pm                                   |   2 +-
 lib/RT/Transaction.pm                              |   2 +-
 lib/RT/Transactions.pm                             |   2 +-
 lib/RT/URI.pm                                      |   2 +-
 lib/RT/URI/a.pm                                    |   2 +-
 lib/RT/URI/base.pm                                 |   2 +-
 lib/RT/URI/fsck_com_article.pm                     |   2 +-
 lib/RT/URI/fsck_com_rt.pm                          |   2 +-
 lib/RT/URI/t.pm                                    |   2 +-
 lib/RT/User.pm                                     |  17 +-
 lib/RT/Users.pm                                    |   2 +-
 lib/RT/Util.pm                                     |   2 +-
 sbin/rt-attributes-viewer.in                       |   2 +-
 sbin/rt-clean-sessions.in                          |   2 +-
 sbin/rt-dump-metadata.in                           |   2 +-
 sbin/rt-email-dashboards.in                        |   2 +-
 sbin/rt-email-digest.in                            |   2 +-
 sbin/rt-email-group-admin.in                       |   2 +-
 sbin/rt-fulltext-indexer.in                        |   2 +-
 sbin/rt-message-catalog                            |   2 +-
 sbin/rt-preferences-viewer.in                      |   2 +-
 sbin/rt-server.in                                  |   2 +-
 sbin/rt-session-viewer.in                          |   2 +-
 sbin/rt-setup-database.in                          |   2 +-
 sbin/rt-setup-fulltext-index.in                    |   2 +-
 sbin/rt-shredder.in                                |   2 +-
 sbin/rt-test-dependencies.in                       |   3 +-
 sbin/rt-validate-aliases.in                        |   2 +-
 sbin/rt-validator.in                               |   2 +-
 .../html/Admin/Articles/Classes/CustomFields.html  |   2 +-
 share/html/Admin/Articles/Classes/GroupRights.html |   2 +-
 share/html/Admin/Articles/Classes/Modify.html      |   2 +-
 share/html/Admin/Articles/Classes/Objects.html     |   2 +-
 share/html/Admin/Articles/Classes/Topics.html      |   2 +-
 share/html/Admin/Articles/Classes/UserRights.html  |   2 +-
 share/html/Admin/Articles/Classes/index.html       |   2 +-
 share/html/Admin/Articles/Elements/Topics          |   2 +-
 share/html/Admin/Articles/index.html               |   2 +-
 share/html/Admin/CustomFields/GroupRights.html     |   2 +-
 share/html/Admin/CustomFields/Modify.html          |   4 +-
 share/html/Admin/CustomFields/Objects.html         |   2 +-
 share/html/Admin/CustomFields/UserRights.html      |   2 +-
 share/html/Admin/CustomFields/index.html           |   2 +-
 share/html/Admin/Elements/AddCustomFieldValue      |   2 +-
 .../html/Admin/Elements/ConfigureDashboardsInMenu  |   2 +-
 share/html/Admin/Elements/ConfigureMyRT            |   2 +-
 share/html/Admin/Elements/CreateUserCalled         |   2 +-
 share/html/Admin/Elements/EditCustomField          |   2 +-
 share/html/Admin/Elements/EditCustomFieldValues    |   2 +-
 .../Admin/Elements/EditCustomFieldValuesSource     |   2 +-
 share/html/Admin/Elements/EditCustomFields         |   2 +-
 share/html/Admin/Elements/EditQueueWatcherGroup    |   2 +-
 share/html/Admin/Elements/EditQueueWatchers        |   2 +-
 share/html/Admin/Elements/EditRights               |  44 +-
 share/html/Admin/Elements/EditRightsCategoryTabs   |   2 +-
 share/html/Admin/Elements/EditScrips               |   2 +-
 share/html/Admin/Elements/EditTemplates            |   2 +-
 share/html/Admin/Elements/EditUserComments         |   2 +-
 share/html/Admin/Elements/Header                   |   2 +-
 share/html/Admin/Elements/ListGlobalCustomFields   |   2 +-
 share/html/Admin/Elements/MembershipsPage          |   2 +-
 share/html/Admin/Elements/ModifyTemplate           |   5 +-
 share/html/Admin/Elements/PickCustomFields         |   2 +-
 share/html/Admin/Elements/PickObjects              |   2 +-
 share/html/Admin/Elements/Portal                   |   2 +-
 share/html/Admin/Elements/QueueRightsForUser       |   2 +-
 share/html/Admin/Elements/SelectCustomField        |   2 +-
 .../Admin/Elements/SelectCustomFieldLookupType     |   2 +-
 .../Admin/Elements/SelectCustomFieldRenderType     |   2 +-
 share/html/Admin/Elements/SelectCustomFieldType    |   2 +-
 share/html/Admin/Elements/SelectGroups             |   2 +-
 share/html/Admin/Elements/SelectModifyGroup        |   2 +-
 share/html/Admin/Elements/SelectModifyQueue        |   2 +-
 share/html/Admin/Elements/SelectModifyUser         |   2 +-
 share/html/Admin/Elements/SelectNewGroupMembers    |   2 +-
 share/html/Admin/Elements/SelectRights             |   2 +-
 share/html/Admin/Elements/SelectScripAction        |   2 +-
 share/html/Admin/Elements/SelectScripCondition     |   2 +-
 share/html/Admin/Elements/SelectSingleOrMultiple   |   2 +-
 share/html/Admin/Elements/SelectStage              |   2 +-
 share/html/Admin/Elements/SelectStageForAdded      |   2 +-
 share/html/Admin/Elements/SelectUsers              |   2 +-
 share/html/Admin/Elements/ShowKeyInfo              |   2 +-
 .../Admin/Global/CustomFields/Class-Article.html   |   2 +-
 share/html/Admin/Global/CustomFields/Groups.html   |   2 +-
 .../Admin/Global/CustomFields/Queue-Tickets.html   |   2 +-
 .../Global/CustomFields/Queue-Transactions.html    |   2 +-
 share/html/Admin/Global/CustomFields/Queues.html   |   2 +-
 share/html/Admin/Global/CustomFields/Users.html    |   2 +-
 share/html/Admin/Global/CustomFields/index.html    |   2 +-
 share/html/Admin/Global/DashboardsInMenu.html      |   2 +-
 share/html/Admin/Global/GroupRights.html           |   2 +-
 share/html/Admin/Global/MyRT.html                  |   2 +-
 share/html/Admin/Global/Scrips.html                |   2 +-
 share/html/Admin/Global/Template.html              |   2 +-
 share/html/Admin/Global/Templates.html             |   2 +-
 share/html/Admin/Global/Topics.html                |   2 +-
 share/html/Admin/Global/UserRights.html            |   2 +-
 share/html/Admin/Global/index.html                 |   2 +-
 share/html/Admin/Groups/GroupRights.html           |   2 +-
 share/html/Admin/Groups/History.html               |   2 +-
 share/html/Admin/Groups/Members.html               |   2 +-
 share/html/Admin/Groups/Memberships.html           |   2 +-
 share/html/Admin/Groups/Modify.html                |   2 +-
 share/html/Admin/Groups/UserRights.html            |   2 +-
 share/html/Admin/Groups/index.html                 |   2 +-
 share/html/Admin/Queues/CustomField.html           |   2 +-
 share/html/Admin/Queues/CustomFields.html          |   2 +-
 share/html/Admin/Queues/GroupRights.html           |   2 +-
 share/html/Admin/Queues/History.html               |   2 +-
 share/html/Admin/Queues/Modify.html                |   2 +-
 share/html/Admin/Queues/People.html                |   2 +-
 share/html/Admin/Queues/Scrips.html                |   2 +-
 share/html/Admin/Queues/Template.html              |   2 +-
 share/html/Admin/Queues/Templates.html             |   2 +-
 share/html/Admin/Queues/UserRights.html            |   2 +-
 share/html/Admin/Queues/index.html                 |   2 +-
 share/html/Admin/Scrips/Create.html                |   2 +-
 share/html/Admin/Scrips/Elements/EditBasics        |   2 +-
 share/html/Admin/Scrips/Elements/EditCustomCode    |   2 +-
 share/html/Admin/Scrips/Elements/SelectTemplate    |   2 +-
 share/html/Admin/Scrips/Modify.html                |   2 +-
 share/html/Admin/Scrips/Objects.html               |   2 +-
 share/html/Admin/Scrips/index.html                 |   2 +-
 share/html/Admin/Tools/Configuration.html          |   2 +-
 share/html/Admin/Tools/Queries.html                |   2 +-
 share/html/Admin/Tools/Shredder/Dumps/dhandler     |   2 +-
 .../Admin/Tools/Shredder/Elements/DumpFileLink     |   2 +-
 .../Admin/Tools/Shredder/Elements/Error/NoRights   |   2 +-
 .../Admin/Tools/Shredder/Elements/Error/NoStorage  |   2 +-
 .../Tools/Shredder/Elements/Object/RT--Attachment  |   2 +-
 .../Tools/Shredder/Elements/Object/RT--Ticket      |   2 +-
 .../Admin/Tools/Shredder/Elements/Object/RT--User  |   2 +-
 .../Admin/Tools/Shredder/Elements/ObjectCheckBox   |   2 +-
 .../Admin/Tools/Shredder/Elements/PluginArguments  |   2 +-
 .../html/Admin/Tools/Shredder/Elements/PluginHelp  |   2 +-
 .../Admin/Tools/Shredder/Elements/SelectObjects    |   2 +-
 .../Admin/Tools/Shredder/Elements/SelectPlugin     |   2 +-
 share/html/Admin/Tools/Shredder/autohandler        |   2 +-
 share/html/Admin/Tools/Shredder/index.html         |   2 +-
 share/html/Admin/Tools/Theme.html                  |   2 +-
 share/html/Admin/Tools/index.html                  |   2 +-
 share/html/Admin/Users/CustomFields.html           |   2 +-
 share/html/Admin/Users/DashboardsInMenu.html       |   2 +-
 share/html/Admin/Users/GnuPG.html                  |   2 +-
 share/html/Admin/Users/History.html                |   2 +-
 share/html/Admin/Users/Memberships.html            |   2 +-
 share/html/Admin/Users/Modify.html                 |   2 +-
 share/html/Admin/Users/MyRT.html                   |   2 +-
 share/html/Admin/Users/index.html                  |   2 +-
 share/html/Admin/autohandler                       |   2 +-
 share/html/Admin/index.html                        |   2 +-
 share/html/Approvals/Display.html                  |   2 +-
 share/html/Approvals/Elements/Approve              |   2 +-
 share/html/Approvals/Elements/PendingMyApproval    |   2 +-
 share/html/Approvals/Elements/ShowDependency       |   2 +-
 share/html/Approvals/autohandler                   |   2 +-
 share/html/Approvals/index.html                    |   2 +-
 share/html/Articles/Article/Delete.html            |   2 +-
 share/html/Articles/Article/Display.html           |   2 +-
 share/html/Articles/Article/Edit.html              |   2 +-
 share/html/Articles/Article/Elements/EditBasics    |   2 +-
 .../Articles/Article/Elements/EditCustomFields     |   2 +-
 share/html/Articles/Article/Elements/EditLinks     |   2 +-
 share/html/Articles/Article/Elements/EditTopics    |   2 +-
 .../Article/Elements/LinkEntryInstructions         |   2 +-
 share/html/Articles/Article/Elements/Preformatted  |   2 +-
 .../Articles/Article/Elements/SearchByCustomField  |   2 +-
 .../Articles/Article/Elements/SelectSavedSearches  |   2 +-
 .../Articles/Article/Elements/SelectSearchPrivacy  |   2 +-
 share/html/Articles/Article/Elements/ShowLinks     |   2 +-
 .../Articles/Article/Elements/ShowSavedSearches    |   2 +-
 .../Articles/Article/Elements/ShowSearchCriteria   |   2 +-
 share/html/Articles/Article/Elements/ShowTopics    |   2 +-
 share/html/Articles/Article/ExtractFromTicket.html |   2 +-
 share/html/Articles/Article/ExtractIntoClass.html  |   2 +-
 share/html/Articles/Article/ExtractIntoTopic.html  |   2 +-
 share/html/Articles/Article/History.html           |   2 +-
 share/html/Articles/Article/PreCreate.html         |   2 +-
 share/html/Articles/Article/Search.html            |   2 +-
 share/html/Articles/Elements/BeforeMessageBox      |   2 +-
 share/html/Articles/Elements/CheckSkipCreate       |   2 +-
 share/html/Articles/Elements/CreateArticle         |   2 +-
 share/html/Articles/Elements/GotoArticle           |   2 +-
 share/html/Articles/Elements/IncludeArticle        |   2 +-
 share/html/Articles/Elements/NewestArticles        |   2 +-
 share/html/Articles/Elements/QuickSearch           |   2 +-
 share/html/Articles/Elements/SelectClass           |   2 +-
 share/html/Articles/Elements/ShowTopic             |   2 +-
 share/html/Articles/Elements/ShowTopicLink         |   2 +-
 share/html/Articles/Elements/SubjectOverride       |   2 +-
 share/html/Articles/Elements/UpdatedArticles       |   2 +-
 share/html/Articles/Topics.html                    |   2 +-
 share/html/Articles/index.html                     |   2 +-
 share/html/Dashboards/Elements/DashboardsForObject |   2 +-
 share/html/Dashboards/Elements/Deleted             |   2 +-
 share/html/Dashboards/Elements/HiddenSearches      |   2 +-
 share/html/Dashboards/Elements/ListOfDashboards    |   2 +-
 share/html/Dashboards/Elements/SelectPrivacy       |   2 +-
 share/html/Dashboards/Elements/ShowDashboards      |   2 +-
 .../html/Dashboards/Elements/ShowPortlet/component |   2 +-
 .../html/Dashboards/Elements/ShowPortlet/dashboard |   2 +-
 share/html/Dashboards/Elements/ShowPortlet/search  |   2 +-
 share/html/Dashboards/Modify.html                  |   2 +-
 share/html/Dashboards/Queries.html                 |   2 +-
 share/html/Dashboards/Render.html                  |   2 +-
 share/html/Dashboards/Subscription.html            |   2 +-
 share/html/Dashboards/dhandler                     |   2 +-
 share/html/Dashboards/index.html                   |   2 +-
 share/html/Download/CustomFieldValue/dhandler      |   2 +-
 share/html/Elements/BevelBoxRaisedEnd              |   2 +-
 share/html/Elements/BevelBoxRaisedStart            |   2 +-
 share/html/Elements/CSRF                           |   2 +-
 share/html/Elements/Callback                       |   2 +-
 share/html/Elements/Checkbox                       |   2 +-
 share/html/Elements/CollectionAsTable/Header       |   2 +-
 share/html/Elements/CollectionAsTable/ParseFormat  |   2 +-
 share/html/Elements/CollectionAsTable/Row          |   2 +-
 share/html/Elements/CollectionList                 |   2 +-
 share/html/Elements/CollectionListPaging           |   2 +-
 share/html/Elements/ColumnMap                      |   2 +-
 share/html/Elements/CreateTicket                   |   2 +-
 share/html/Elements/Dashboards                     |   2 +-
 share/html/Elements/EditCustomField                |   2 +-
 share/html/Elements/EditCustomFieldAutocomplete    |   2 +-
 share/html/Elements/EditCustomFieldBinary          |   2 +-
 share/html/Elements/EditCustomFieldCombobox        |   2 +-
 share/html/Elements/EditCustomFieldCustomGroupings |   2 +-
 share/html/Elements/EditCustomFieldDate            |   2 +-
 share/html/Elements/EditCustomFieldDateTime        |   2 +-
 share/html/Elements/EditCustomFieldFreeform        |   2 +-
 share/html/Elements/EditCustomFieldIPAddress       |   2 +-
 share/html/Elements/EditCustomFieldIPAddressRange  |   2 +-
 share/html/Elements/EditCustomFieldImage           |   2 +-
 share/html/Elements/EditCustomFieldSelect          |   2 +-
 share/html/Elements/EditCustomFieldText            |   2 +-
 share/html/Elements/EditCustomFieldWikitext        |   2 +-
 share/html/Elements/EditCustomFields               |   2 +-
 share/html/Elements/EditLinks                      |   2 +-
 share/html/Elements/EditPassword                   |   2 +-
 share/html/Elements/EditTimeValue                  |   2 +-
 share/html/Elements/EmailInput                     |   2 +-
 share/html/Elements/Error                          |   2 +-
 share/html/Elements/FoldStanzaJS                   |   2 +-
 share/html/Elements/Footer                         |   2 +-
 share/html/Elements/Framekiller                    |   2 +-
 share/html/Elements/GnuPG/KeyIssues                |   2 +-
 share/html/Elements/GnuPG/SelectKeyForEncryption   |   2 +-
 share/html/Elements/GnuPG/SelectKeyForSigning      |   2 +-
 share/html/Elements/GnuPG/SignEncryptWidget        |   2 +-
 share/html/Elements/GotoTicket                     |   2 +-
 share/html/Elements/Header                         |   4 +-
 share/html/Elements/HeaderJavascript               |   2 +-
 share/html/Elements/JavascriptConfig               |   2 +-
 share/html/Elements/ListActions                    |   2 +-
 share/html/Elements/ListMenu                       |   2 +-
 share/html/Elements/Login                          |   2 +-
 share/html/Elements/LoginRedirectWarning           |   2 +-
 share/html/Elements/Logo                           |   2 +-
 share/html/Elements/MakeClicky                     |   2 +-
 share/html/Elements/Menu                           |   2 +-
 share/html/Elements/MessageBox                     |   2 +-
 share/html/Elements/MyAdminQueues                  |   2 +-
 share/html/Elements/MyRT                           |   2 +-
 share/html/Elements/MyReminders                    |   2 +-
 share/html/Elements/MySupportQueues                |   2 +-
 share/html/Elements/PageLayout                     |   2 +-
 share/html/Elements/PersonalQuickbar               |   2 +-
 share/html/Elements/QueriesAsComment               |   2 +-
 share/html/Elements/QueryString                    |   2 +-
 share/html/Elements/QueueSummaryByLifecycle        |   2 +-
 share/html/Elements/QueueSummaryByStatus           |   2 +-
 share/html/Elements/QuickCreate                    |   2 +-
 share/html/Elements/Quicksearch                    |   2 +-
 share/html/Elements/RT__Article/ColumnMap          |   2 +-
 share/html/Elements/RT__Class/ColumnMap            |   2 +-
 share/html/Elements/RT__CustomField/ColumnMap      |   2 +-
 share/html/Elements/RT__Dashboard/ColumnMap        |   2 +-
 share/html/Elements/RT__Group/ColumnMap            |   2 +-
 share/html/Elements/RT__Queue/ColumnMap            |   2 +-
 share/html/Elements/RT__SavedSearch/ColumnMap      |   2 +-
 share/html/Elements/RT__Scrip/ColumnMap            |   2 +-
 share/html/Elements/RT__Template/ColumnMap         |   2 +-
 share/html/Elements/RT__Ticket/ColumnMap           |   2 +-
 share/html/Elements/RT__User/ColumnMap             |   2 +-
 share/html/Elements/Refresh                        |   2 +-
 share/html/Elements/RefreshHomepage                |   2 +-
 share/html/Elements/SavedSearches                  |   2 +-
 share/html/Elements/ScrubHTML                      |   2 +-
 share/html/Elements/Section                        |   2 +-
 share/html/Elements/SelectAttachmentField          |   2 +-
 share/html/Elements/SelectBoolean                  |   2 +-
 share/html/Elements/SelectCustomFieldOperator      |   2 +-
 share/html/Elements/SelectCustomFieldValue         |   2 +-
 share/html/Elements/SelectDate                     |   2 +-
 share/html/Elements/SelectDateRelation             |   2 +-
 share/html/Elements/SelectDateType                 |   2 +-
 share/html/Elements/SelectEqualityOperator         |   2 +-
 share/html/Elements/SelectGroups                   |   2 +-
 share/html/Elements/SelectIPRelation               |   2 +-
 share/html/Elements/SelectLang                     |   2 +-
 share/html/Elements/SelectLinkType                 |   2 +-
 share/html/Elements/SelectMatch                    |   2 +-
 share/html/Elements/SelectNewTicketQueue           |   2 +-
 share/html/Elements/SelectOwner                    |   2 +-
 share/html/Elements/SelectOwnerAutocomplete        |   2 +-
 share/html/Elements/SelectOwnerDropdown            |   2 +-
 share/html/Elements/SelectPriority                 |   2 +-
 share/html/Elements/SelectQueue                    |   2 +-
 share/html/Elements/SelectResultsPerPage           |   2 +-
 share/html/Elements/SelectSortOrder                |   2 +-
 share/html/Elements/SelectStatus                   |   2 +-
 share/html/Elements/SelectTicketSortBy             |   2 +-
 share/html/Elements/SelectTicketTypes              |   2 +-
 share/html/Elements/SelectTimeUnits                |   2 +-
 share/html/Elements/SelectTimezone                 |   2 +-
 share/html/Elements/SelectUsers                    |   2 +-
 share/html/Elements/SelectWatcherType              |   2 +-
 share/html/Elements/SetupSessionCookie             |   2 +-
 share/html/Elements/ShowCustomFieldBinary          |   2 +-
 share/html/Elements/ShowCustomFieldCustomGroupings |   2 +-
 share/html/Elements/ShowCustomFieldDate            |   2 +-
 share/html/Elements/ShowCustomFieldDateTime        |   2 +-
 share/html/Elements/ShowCustomFieldImage           |   2 +-
 share/html/Elements/ShowCustomFieldText            |   2 +-
 share/html/Elements/ShowCustomFieldWikitext        |   2 +-
 share/html/Elements/ShowCustomFields               |   2 +-
 share/html/Elements/ShowGnuPGStatus                |   2 +-
 share/html/Elements/ShowHistory                    |  30 +-
 share/html/Elements/ShowLink                       |   2 +-
 share/html/Elements/ShowLinks                      |   2 +-
 share/html/Elements/ShowLinksOfType                |   2 +-
 share/html/Elements/ShowMemberships                |   2 +-
 share/html/Elements/ShowMessageHeaders             |   2 +-
 share/html/Elements/ShowMessageStanza              |   2 +-
 share/html/Elements/ShowRelationLabel              |   2 +-
 share/html/Elements/ShowReminders                  |   2 +-
 share/html/Elements/ShowSearch                     |   2 +-
 share/html/Elements/ShowTransaction                |  30 +-
 share/html/Elements/ShowTransactionAttachments     |   2 +-
 share/html/Elements/ShowUser                       |   2 +-
 share/html/Elements/ShowUserEmailFrequency         |   2 +-
 share/html/Elements/SimpleSearch                   |   2 +-
 share/html/Elements/Submit                         |   2 +-
 share/html/Elements/Tabs                           |   4 +-
 share/html/Elements/TicketList                     |   2 +-
 share/html/Elements/TitleBox                       |   2 +-
 share/html/Elements/TitleBoxEnd                    |   2 +-
 share/html/Elements/TitleBoxStart                  |   2 +-
 share/html/Elements/ValidateCustomFields           |   2 +-
 share/html/Elements/WidgetBar                      |   2 +-
 share/html/Errors/WebExternalAuth/AutoCreate       |   2 +-
 share/html/Errors/WebExternalAuth/Deauthorized     |   2 +-
 share/html/Errors/WebExternalAuth/NoInternalUser   |   2 +-
 share/html/Errors/WebExternalAuth/NoRemoteUser     |   2 +-
 share/html/Errors/WebExternalAuth/Wrapper          |   2 +-
 share/html/Helpers/Autocomplete/CustomFieldValues  |   2 +-
 share/html/Helpers/Autocomplete/Groups             |   2 +-
 share/html/Helpers/Autocomplete/Owners             |   2 +-
 share/html/Helpers/Autocomplete/Users              |  20 +-
 share/html/Helpers/TicketHistory                   |   2 +-
 share/html/Helpers/Toggle/ShowRequestor            |   2 +-
 share/html/Helpers/Toggle/TicketBookmark           |   2 +-
 share/html/Helpers/UserInfo                        |   2 +-
 share/html/Install/Basics.html                     |   2 +-
 share/html/Install/DatabaseDetails.html            |   2 +-
 share/html/Install/DatabaseType.html               |   2 +-
 share/html/Install/Elements/Errors                 |   2 +-
 share/html/Install/Elements/Wrapper                |   2 +-
 share/html/Install/Finish.html                     |   2 +-
 share/html/Install/Global.html                     |   2 +-
 share/html/Install/Initialize.html                 |   2 +-
 share/html/Install/Sendmail.html                   |   2 +-
 share/html/Install/autohandler                     |   2 +-
 share/html/Install/index.html                      |   2 +-
 share/html/NoAuth/Helpers/CustomLogo/dhandler      |   2 +-
 share/html/NoAuth/Login.html                       |   7 +-
 share/html/NoAuth/Logout.html                      |   2 +-
 share/html/NoAuth/Reminder.html                    |   2 +-
 share/html/NoAuth/RichText/autohandler             |   2 +-
 share/html/NoAuth/css/aileron/AfterMenus           |   2 +-
 share/html/NoAuth/css/aileron/InHeader             |   2 +-
 share/html/NoAuth/css/aileron/base.css             |   2 +-
 share/html/NoAuth/css/aileron/boxes.css            |   2 +-
 share/html/NoAuth/css/aileron/forms.css            |   5 +-
 share/html/NoAuth/css/aileron/layout.css           |   2 +-
 share/html/NoAuth/css/aileron/login.css            |   2 +-
 share/html/NoAuth/css/aileron/main.css             |   2 +-
 share/html/NoAuth/css/aileron/misc.css             |   2 +-
 share/html/NoAuth/css/aileron/msie.css             |   2 +-
 share/html/NoAuth/css/aileron/msie6.css            |   2 +-
 share/html/NoAuth/css/aileron/nav.css              |   2 +-
 share/html/NoAuth/css/aileron/ticket-lists.css     |   2 +-
 share/html/NoAuth/css/aileron/ticket-search.css    |   2 +-
 share/html/NoAuth/css/aileron/ticket.css           |   2 +-
 share/html/NoAuth/css/autohandler                  |   2 +-
 share/html/NoAuth/css/ballard/InHeader             |   2 +-
 share/html/NoAuth/css/ballard/base.css             |   2 +-
 share/html/NoAuth/css/ballard/boxes.css            |   2 +-
 share/html/NoAuth/css/ballard/layout.css           |   2 +-
 share/html/NoAuth/css/ballard/main.css             |   2 +-
 share/html/NoAuth/css/ballard/misc.css             |   2 +-
 share/html/NoAuth/css/ballard/msie.css             |   2 +-
 share/html/NoAuth/css/ballard/msie6.css            |   2 +-
 share/html/NoAuth/css/ballard/nav.css              |   2 +-
 share/html/NoAuth/css/ballard/ticket-lists.css     |   2 +-
 share/html/NoAuth/css/ballard/ticket-search.css    |   2 +-
 share/html/NoAuth/css/base/admin.css               |   2 +-
 share/html/NoAuth/css/base/articles.css            |   2 +-
 share/html/NoAuth/css/base/collection.css          |   2 +-
 share/html/NoAuth/css/base/forms.css               |   2 +-
 share/html/NoAuth/css/base/history-folding.css     |   2 +-
 share/html/NoAuth/css/base/history.css             |   2 +-
 share/html/NoAuth/css/base/jquery-ui.css           |   2 +-
 share/html/NoAuth/css/base/login.css               |   2 +-
 share/html/NoAuth/css/base/main.css                |   2 +-
 share/html/NoAuth/css/base/misc.css                |   2 +-
 share/html/NoAuth/css/base/nav.css                 |   2 +-
 share/html/NoAuth/css/base/portlets.css            |   2 +-
 share/html/NoAuth/css/base/rights-editor.css       |   2 +-
 share/html/NoAuth/css/base/theme-editor.css        |   2 +-
 share/html/NoAuth/css/base/ticket-form.css         |   2 +-
 share/html/NoAuth/css/base/ticket.css              |   2 +-
 share/html/NoAuth/css/base/tools.css               |   2 +-
 share/html/NoAuth/css/dhandler                     |   2 +-
 share/html/NoAuth/css/print.css                    |   2 +-
 share/html/NoAuth/css/web2/AfterMenus              |   2 +-
 share/html/NoAuth/css/web2/InHeader                |   2 +-
 share/html/NoAuth/css/web2/base.css                |   2 +-
 share/html/NoAuth/css/web2/boxes.css               |   2 +-
 share/html/NoAuth/css/web2/layout.css              |   2 +-
 share/html/NoAuth/css/web2/main.css                |   2 +-
 share/html/NoAuth/css/web2/misc.css                |   2 +-
 share/html/NoAuth/css/web2/msie.css                |   2 +-
 share/html/NoAuth/css/web2/msie6.css               |   2 +-
 share/html/NoAuth/css/web2/nav.css                 |   2 +-
 share/html/NoAuth/css/web2/ticket-lists.css        |   2 +-
 share/html/NoAuth/css/web2/ticket-search.css       |   2 +-
 share/html/NoAuth/iCal/dhandler                    |   2 +-
 share/html/NoAuth/js/autohandler                   |   2 +-
 share/html/NoAuth/js/cascaded.js                   |   2 +-
 share/html/NoAuth/js/combobox.js                   |   2 +-
 share/html/NoAuth/js/dhandler                      |   2 +-
 share/html/NoAuth/js/event-registration.js         |   2 +-
 share/html/NoAuth/js/history-folding.js            |   2 +-
 share/html/NoAuth/js/jquery-ui-patch-datepicker.js |   2 +-
 share/html/NoAuth/js/jquery.cookie.js              |  89 ++++
 share/html/NoAuth/js/jquery.modal-defaults.js      |   2 +-
 share/html/NoAuth/js/jquery_noconflict.js          |   2 +-
 share/html/NoAuth/js/late.js                       |   2 +-
 share/html/NoAuth/js/titlebox-state.js             |   2 +-
 share/html/NoAuth/js/userautocomplete.js           |   2 +-
 share/html/NoAuth/js/util.js                       |   2 +-
 share/html/NoAuth/rss/dhandler                     |   2 +-
 share/html/Prefs/DashboardsInMenu.html             |   2 +-
 share/html/Prefs/MyRT.html                         |   2 +-
 share/html/Prefs/Other.html                        |   2 +-
 share/html/Prefs/Quicksearch.html                  |   2 +-
 share/html/Prefs/Search.html                       |   2 +-
 share/html/Prefs/SearchOptions.html                |   2 +-
 share/html/REST/1.0/Forms/attachment/default       |   2 +-
 share/html/REST/1.0/Forms/group/customfields       |   2 +-
 share/html/REST/1.0/Forms/group/default            |   2 +-
 share/html/REST/1.0/Forms/group/ns                 |   2 +-
 share/html/REST/1.0/Forms/queue/customfields       |   2 +-
 share/html/REST/1.0/Forms/queue/default            |   2 +-
 share/html/REST/1.0/Forms/queue/ns                 |   2 +-
 share/html/REST/1.0/Forms/queue/ticketcustomfields |   2 +-
 share/html/REST/1.0/Forms/ticket/attachments       |   2 +-
 share/html/REST/1.0/Forms/ticket/comment           |   2 +-
 share/html/REST/1.0/Forms/ticket/default           |  15 +-
 share/html/REST/1.0/Forms/ticket/history           |   2 +-
 share/html/REST/1.0/Forms/ticket/links             |   2 +-
 share/html/REST/1.0/Forms/ticket/merge             |   2 +-
 share/html/REST/1.0/Forms/ticket/take              |   2 +-
 share/html/REST/1.0/Forms/transaction/default      |   2 +-
 share/html/REST/1.0/Forms/user/default             |   2 +-
 share/html/REST/1.0/Forms/user/ns                  |   2 +-
 share/html/REST/1.0/NoAuth/mail-gateway            |   2 +-
 share/html/REST/1.0/autohandler                    |   2 +-
 share/html/REST/1.0/dhandler                       |   2 +-
 share/html/REST/1.0/logout                         |   2 +-
 share/html/REST/1.0/search/dhandler                |   2 +-
 share/html/REST/1.0/search/ticket                  |   2 +-
 share/html/REST/1.0/ticket/comment                 |   2 +-
 share/html/REST/1.0/ticket/link                    |   2 +-
 share/html/REST/1.0/ticket/merge                   |   2 +-
 share/html/Search/Article.html                     |   2 +-
 share/html/Search/Build.html                       |   2 +-
 share/html/Search/Bulk.html                        |   2 +-
 share/html/Search/Chart                            |   2 +-
 share/html/Search/Chart.html                       |   2 +-
 share/html/Search/Edit.html                        |   2 +-
 share/html/Search/Elements/Article                 |   2 +-
 share/html/Search/Elements/BuildFormatString       |   2 +-
 share/html/Search/Elements/Chart                   |   2 +-
 share/html/Search/Elements/ConditionRow            |   2 +-
 share/html/Search/Elements/DisplayOptions          |   2 +-
 share/html/Search/Elements/EditFormat              |   2 +-
 share/html/Search/Elements/EditQuery               |   2 +-
 share/html/Search/Elements/EditSearches            |   2 +-
 share/html/Search/Elements/EditSort                |   2 +-
 share/html/Search/Elements/Graph                   |   2 +-
 share/html/Search/Elements/NewListActions          |   2 +-
 share/html/Search/Elements/PickBasics              |   2 +-
 share/html/Search/Elements/PickCFs                 |   2 +-
 share/html/Search/Elements/PickCriteria            |   2 +-
 share/html/Search/Elements/ResultsRSSView          |   2 +-
 share/html/Search/Elements/SearchPrivacy           |   2 +-
 share/html/Search/Elements/SearchesForObject       |   2 +-
 share/html/Search/Elements/SelectAndOr             |   2 +-
 share/html/Search/Elements/SelectChartType         |   2 +-
 share/html/Search/Elements/SelectGroup             |   2 +-
 share/html/Search/Elements/SelectGroupBy           |   2 +-
 share/html/Search/Elements/SelectLinks             |   2 +-
 share/html/Search/Elements/SelectPersonType        |   2 +-
 share/html/Search/Elements/SelectSearchObject      |   2 +-
 .../html/Search/Elements/SelectSearchesForObjects  |   2 +-
 share/html/Search/Graph.html                       |   2 +-
 share/html/Search/Results.html                     |   2 +-
 share/html/Search/Results.rdf                      |   2 +-
 share/html/Search/Results.tsv                      |   2 +-
 share/html/Search/Simple.html                      |   2 +-
 share/html/SelfService/Article/Display.html        |   2 +-
 share/html/SelfService/Article/Search.html         |   2 +-
 share/html/SelfService/Article/autohandler         |   2 +-
 share/html/SelfService/Attachment/dhandler         |   2 +-
 share/html/SelfService/Closed.html                 |   2 +-
 share/html/SelfService/Create.html                 |   2 +-
 share/html/SelfService/CreateTicketInQueue.html    |   2 +-
 share/html/SelfService/Display.html                |   2 +-
 share/html/SelfService/Elements/GotoTicket         |   2 +-
 share/html/SelfService/Elements/Header             |   2 +-
 share/html/SelfService/Elements/MyRequests         |   2 +-
 share/html/SelfService/Elements/SearchArticle      |   2 +-
 share/html/SelfService/Error.html                  |   2 +-
 share/html/SelfService/Prefs.html                  |   2 +-
 share/html/SelfService/Update.html                 |   2 +-
 share/html/SelfService/index.html                  |   2 +-
 share/html/Ticket/Attachment/WithHeaders/dhandler  |   2 +-
 share/html/Ticket/Attachment/dhandler              |   2 +-
 share/html/Ticket/Create.html                      |   2 +-
 share/html/Ticket/Display.html                     |   2 +-
 share/html/Ticket/Elements/AddAttachments          |   2 +-
 share/html/Ticket/Elements/AddWatchers             |   2 +-
 share/html/Ticket/Elements/Bookmark                |   2 +-
 share/html/Ticket/Elements/BulkLinks               |   2 +-
 share/html/Ticket/Elements/ClickToShowHistory      |   2 +-
 share/html/Ticket/Elements/DelayShowHistory        |   2 +-
 share/html/Ticket/Elements/EditBasics              |   2 +-
 share/html/Ticket/Elements/EditCustomFields        |   2 +-
 share/html/Ticket/Elements/EditDates               |   2 +-
 share/html/Ticket/Elements/EditPeople              |   2 +-
 .../Ticket/Elements/EditTransactionCustomFields    |   2 +-
 share/html/Ticket/Elements/EditWatchers            |   2 +-
 share/html/Ticket/Elements/LoadTextAttachments     |   2 +-
 share/html/Ticket/Elements/PreviewScrips           |   2 +-
 share/html/Ticket/Elements/Reminders               |   2 +-
 share/html/Ticket/Elements/SelectStatus            |   2 +-
 share/html/Ticket/Elements/ShowAttachments         |   2 +-
 share/html/Ticket/Elements/ShowBasics              |   2 +-
 share/html/Ticket/Elements/ShowCustomFields        |   2 +-
 share/html/Ticket/Elements/ShowDates               |   2 +-
 share/html/Ticket/Elements/ShowDependencies        |   2 +-
 share/html/Ticket/Elements/ShowDependencyStatus    |   2 +-
 share/html/Ticket/Elements/ShowGroupMembers        |   2 +-
 share/html/Ticket/Elements/ShowPeople              |   2 +-
 share/html/Ticket/Elements/ShowPriority            |   2 +-
 share/html/Ticket/Elements/ShowQueue               |   2 +-
 share/html/Ticket/Elements/ShowRequestor           |   2 +-
 share/html/Ticket/Elements/ShowRequestorExtraInfo  |   2 +-
 share/html/Ticket/Elements/ShowRequestorTickets    |   2 +-
 .../Ticket/Elements/ShowRequestorTicketsActive     |   2 +-
 share/html/Ticket/Elements/ShowRequestorTicketsAll |   2 +-
 .../Ticket/Elements/ShowRequestorTicketsInactive   |   2 +-
 .../html/Ticket/Elements/ShowSimplifiedRecipients  |   2 +-
 share/html/Ticket/Elements/ShowSummary             |   2 +-
 share/html/Ticket/Elements/ShowTime                |   2 +-
 share/html/Ticket/Elements/ShowUpdateStatus        |   2 +-
 share/html/Ticket/Elements/ShowUserEntry           |   2 +-
 share/html/Ticket/Elements/UpdateCc                |   2 +-
 share/html/Ticket/Forward.html                     |   2 +-
 share/html/Ticket/GnuPG.html                       |   2 +-
 .../Ticket/Graphs/Elements/EditGraphProperties     |   2 +-
 share/html/Ticket/Graphs/Elements/ShowGraph        |   2 +-
 share/html/Ticket/Graphs/Elements/ShowLegends      |   2 +-
 share/html/Ticket/Graphs/dhandler                  |   2 +-
 share/html/Ticket/Graphs/index.html                |   2 +-
 share/html/Ticket/History.html                     |   2 +-
 share/html/Ticket/Modify.html                      |   2 +-
 share/html/Ticket/ModifyAll.html                   |   2 +-
 share/html/Ticket/ModifyDates.html                 |   2 +-
 share/html/Ticket/ModifyLinks.html                 |   2 +-
 share/html/Ticket/ModifyPeople.html                |   2 +-
 share/html/Ticket/Reminders.html                   |   2 +-
 share/html/Ticket/ShowEmailRecord.html             |   2 +-
 share/html/Ticket/Update.html                      |   2 +-
 share/html/Ticket/autohandler                      |   2 +-
 share/html/Tools/MyDay.html                        |   2 +-
 share/html/Tools/MyReminders.html                  |   2 +-
 share/html/Tools/Offline.html                      |   2 +-
 share/html/Tools/index.html                        |   2 +-
 share/html/User/Prefs.html                         |  12 +-
 share/html/Widgets/BulkEdit                        |   2 +-
 share/html/Widgets/BulkProcess                     |   2 +-
 share/html/Widgets/ComboBox                        |   2 +-
 share/html/Widgets/FinalizeWidgetArguments         |   2 +-
 share/html/Widgets/Form/Boolean                    |   2 +-
 share/html/Widgets/Form/Integer                    |   2 +-
 share/html/Widgets/Form/Select                     |   2 +-
 share/html/Widgets/Form/String                     |   2 +-
 share/html/Widgets/SavedSearch                     |   2 +-
 share/html/Widgets/SelectionBox                    |   2 +-
 share/html/Widgets/TitleBox                        |   2 +-
 share/html/Widgets/TitleBoxEnd                     |   2 +-
 share/html/Widgets/TitleBoxStart                   |   2 +-
 share/html/autohandler                             |   2 +-
 share/html/dhandler                                |   2 +-
 share/html/index.html                              |   2 +-
 share/html/l                                       |   2 +-
 share/html/l_unsafe                                |   2 +-
 share/html/m/_elements/footer                      |   2 +-
 share/html/m/_elements/full_site_link              |   2 +-
 share/html/m/_elements/header                      |   2 +-
 share/html/m/{ => _elements}/login                 |  75 ++--
 share/html/m/_elements/menu                        |   2 +-
 share/html/m/_elements/raw_style                   |  11 +-
 share/html/m/_elements/ticket_list                 |   2 +-
 share/html/m/_elements/ticket_menu                 |   2 +-
 share/html/m/_elements/wrapper                     |   5 +-
 share/html/m/dhandler                              |   2 +-
 share/html/m/index.html                            |   2 +-
 share/html/m/logout                                |   2 +-
 share/html/m/style.css                             |   2 +-
 share/html/m/ticket/autohandler                    |   2 +-
 share/html/m/ticket/create                         |   2 +-
 share/html/m/ticket/history                        |   2 +-
 share/html/m/ticket/reply                          |   2 +-
 share/html/m/ticket/select_create_queue            |   2 +-
 share/html/m/ticket/show                           |   2 +-
 share/html/m/tickets/search                        |   2 +-
 t/ticket/search_by_queue.t                         |  60 +++
 t/web/login.t                                      | 133 ++++++
 t/web/rest.t                                       | 180 ++++++++-
 t/web/template.t                                   |  34 +-
 t/web/user_update.t                                |  30 +-
 867 files changed, 2255 insertions(+), 996 deletions(-)
 create mode 100644 docs/customizing/lifecycles.pod
 create mode 100644 docs/customizing/styling_rt.pod
 create mode 100644 docs/images/action-decline.png
 create mode 100644 docs/images/global-lifecycle-group-rights.png
 create mode 100644 docs/images/lifecycle-choices.png
 create mode 100644 docs/images/order-history-example.png
 create mode 100644 docs/images/theme_editor_defaults.png
 create mode 100644 share/html/NoAuth/js/jquery.cookie.js
 rename share/html/m/{ => _elements}/login (64%)
 create mode 100644 t/ticket/search_by_queue.t
 create mode 100644 t/web/login.t

- Log -----------------------------------------------------------------
commit e88e1b8dccf686e62aadadfa5183b192937f5722
Merge: 79a157f a1d66f6
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Wed Jan 16 18:30:12 2013 -0500

    Merge branch '4.0-trunk'
    
    4.0-trunk and master fixed two opposing parts of setting the Language
    preference; master ensured that the "Lang set to 'en'" message was in
    the new language, whereas 4.0-trunk ensured that setting the language
    back to the system default kicks in immediately.
    
    These two are a complex interaction, requiring the addition of a SetLang
    method to correctly update the language handle for the message (which is
    set before any redirect) even when the new language is ''.
    
    As the set of files in master differs from 4.0-trunk,
    devel/tools/license_tag was run as part of the merge.
    
    Conflicts:
    	devel/tools/factory
    	etc/RT_Config.pm.in
    	etc/upgrade/3.9.8/content
    	etc/upgrade/4.0.9/content
    	lib/RT/Interface/Web.pm
    	lib/RT/Tickets_SQL.pm
    	share/html/Admin/Elements/EditScrip
    	share/html/Elements/ShowHistory
    	share/html/NoAuth/css/ballard/ticket.css
    	share/html/NoAuth/css/web2/images/dhandler
    	share/html/NoAuth/images/autohandler
    	share/html/Ticket/Elements/DelayShowHistory
    	share/html/Ticket/Elements/ShowTransaction
    	t/web/user_update.t

diff --cc devel/tools/cmd-boilerplate
index 65dcbc2,9475ba1..09942cd
mode 100755,100644..100755
--- a/devel/tools/cmd-boilerplate
+++ b/devel/tools/cmd-boilerplate
diff --cc etc/upgrade/3.9.8/content
index 40c2c0a,db717cd..9ade6a1
--- a/etc/upgrade/3.9.8/content
+++ b/etc/upgrade/3.9.8/content
@@@ -22,6 -19,6 +22,6 @@@ our @Initial = sub 
      my $result = $dbh->selectall_arrayref("SELECT count(*) AS articlecount FROM FM_Articles", { Slice => {} } );
  
      if ($result->[0]{articlecount} > 0) {
-         RT->Logger->error("You appear to have RTFM Articles.  You can upgrade using the etc/upgrade/upgrade-articles script.  Read more about it in UPGRADING");
 -        $RT::Logger->error("You appear to have RTFM Articles.  You can upgrade using the etc/upgrade/upgrade-articles script.  Read more about it in docs/UPGRADING-4.0");
++        RT->Logger->error("You appear to have RTFM Articles.  You can upgrade using the etc/upgrade/upgrade-articles script.  Read more about it in docs/UPGRADING-4.0");
      }
  };
diff --cc etc/upgrade/4.0.9/content
index fb7cfbf,f2abf62..246b1eb
--- a/etc/upgrade/4.0.9/content
+++ b/etc/upgrade/4.0.9/content
@@@ -1,9 -1,6 +1,9 @@@
 - at Initial = (
 +use strict;
 +use warnings;
 +
- our @Final = (
++our @Initial = (
      sub {
 -        $RT::Logger->debug(
 +        RT->Logger->debug(
              'Going to update empty Queue Lifecycle column to "default"');
  
          my $queues = RT::Queues->new( RT->SystemUser );
@@@ -29,5 -26,27 +29,27 @@@
          while ( my $q = $queues->Next ) {
              $q->SetLifecycle('default');
          }
-     }
+     },
+     sub {
+         use strict;
+         my $groups = RT::Groups->new(RT->SystemUser);
+         $groups->Limit( FIELD    => 'Domain',
+                         OPERATOR => '=',
+                         VALUE    => 'Personal'
+                       );
+         $groups->LimitToDeleted;
+         while ( my $group = $groups->Next ) {
+             my $members = $group->MembersObj();
+             while ( my $member = $members->Next ) {
+                 my ( $ok, $msg ) = $group->DeleteMember( $member->MemberId );
+                 if ( !$ok ) {
 -                    $RT::Logger->warn(   "Unable to remove group member "
++                    RT->Logger->warn(   "Unable to remove group member "
+                                        . $member->id . ": "
+                                        . $msg );
+                 }
+             }
+             $group->PrincipalObj->Delete;
+             $group->RT::Record::Delete();
+         }
+     },
  );
diff --cc lib/RT/Interface/Web.pm
index 92b6f3b,1eaefc7..09a0027
--- a/lib/RT/Interface/Web.pm
+++ b/lib/RT/Interface/Web.pm
@@@ -100,32 -100,6 +100,33 @@@ sub SquishedJS 
      return $js;
  }
  
 +=head2 JSFiles
 +
 +=cut
 +
 +sub JSFiles {
 +    return qw/
 +      jquery-1.4.2.min.js
 +      jquery_noconflict.js
 +      jquery-ui-1.8.4.custom.min.js
 +      jquery-ui-timepicker-addon.js
 +      jquery-ui-patch-datepicker.js
 +      jquery.modal.min.js
 +      jquery.modal-defaults.js
++      jquery.cookie.js
 +      titlebox-state.js
 +      util.js
 +      userautocomplete.js
 +      jquery.event.hover-1.0.js
 +      superfish.js
 +      supersubs.js
 +      jquery.supposition.js
 +      history-folding.js
 +      event-registration.js
 +      late.js
 +      /, RT->Config->Get('JSFiles');
 +}
 +
  =head2 ClearSquished
  
  Removes the cached CSS and JS entries, forcing them to be regenerated
@@@ -479,9 -443,13 +485,13 @@@ sub TangentForLoginURL 
      my $ARGS  = shift;
      my $hash  = SetNextPage($ARGS);
      my %query = (@_, next => $hash);
+ 
+     $query{mobile} = 1
+         if $HTML::Mason::Commands::m->request_comp->path =~ m{^/m(/|$)};
+ 
 -    my $login = RT->Config->Get('WebURL') . 'NoAuth/Login.html?';
 +    my $login = RT->Config->Get('WebPath') . '/NoAuth/Login.html?';
      $login .= $HTML::Mason::Commands::m->comp('/Elements/QueryString', %query);
 -    Redirect($login);
 +    return $login;
  }
  
  =head2 TangentForLoginWithError ERROR
diff --cc lib/RT/ObjectCustomField.pm
index 9ecf36e,e7f350a..b883e97
--- a/lib/RT/ObjectCustomField.pm
+++ b/lib/RT/ObjectCustomField.pm
@@@ -45,6 -45,9 +45,7 @@@
  # those contributions and any derivatives thereof.
  #
  # END BPS TAGGED BLOCK }}}
+ 
 -package RT::ObjectCustomField;
 -
  use strict;
  use warnings;
  
diff --cc lib/RT/ObjectCustomFields.pm
index f39adac,5bdc069..a591157
--- a/lib/RT/ObjectCustomFields.pm
+++ b/lib/RT/ObjectCustomFields.pm
@@@ -45,6 -45,9 +45,7 @@@
  # those contributions and any derivatives thereof.
  #
  # END BPS TAGGED BLOCK }}}
+ 
 -package RT::ObjectCustomFields;
 -
  use strict;
  use warnings;
  
diff --cc lib/RT/ObjectScrip.pm
index 1a8990f,0000000..d85391e
mode 100644,000000..100644
--- a/lib/RT/ObjectScrip.pm
+++ b/lib/RT/ObjectScrip.pm
@@@ -1,252 -1,0 +1,252 @@@
 +# BEGIN BPS TAGGED BLOCK {{{
 +#
 +# COPYRIGHT:
 +#
- # This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
++# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
 +#                                          <sales at bestpractical.com>
 +#
 +# (Except where explicitly superseded by other copyright notices)
 +#
 +#
 +# LICENSE:
 +#
 +# This work is made available to you under the terms of Version 2 of
 +# the GNU General Public License. A copy of that license should have
 +# been provided with this software, but in any event can be snarfed
 +# from www.gnu.org.
 +#
 +# This work is distributed in the hope that it will be useful, but
 +# WITHOUT ANY WARRANTY; without even the implied warranty of
 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 +# General Public License for more details.
 +#
 +# You should have received a copy of the GNU General Public License
 +# along with this program; if not, write to the Free Software
 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 +# 02110-1301 or visit their web page on the internet at
 +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
 +#
 +#
 +# CONTRIBUTION SUBMISSION POLICY:
 +#
 +# (The following paragraph is not intended to limit the rights granted
 +# to you to modify and distribute this software under the terms of
 +# the GNU General Public License and is only of importance to you if
 +# you choose to contribute your changes and enhancements to the
 +# community by submitting them to Best Practical Solutions, LLC.)
 +#
 +# By intentionally submitting any modifications, corrections or
 +# derivatives to this work, or any other work intended for use with
 +# Request Tracker, to Best Practical Solutions, LLC, you confirm that
 +# you are the copyright holder for those contributions and you grant
 +# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
 +# royalty-free, perpetual, license to use, copy, create derivative
 +# works based on those contributions, and sublicense and distribute
 +# those contributions and any derivatives thereof.
 +#
 +# END BPS TAGGED BLOCK }}}
 +
 +use strict;
 +use warnings;
 +
 +package RT::ObjectScrip;
 +use base 'RT::Record::AddAndSort';
 +
 +use RT::Scrip;
 +use RT::ObjectScrips;
 +
 +=head1 NAME
 +
 +RT::ObjectScrip - record representing addition of a scrip to a queue
 +
 +=head1 DESCRIPTION
 +
 +This record is created if you want to add a scrip to a queue or globally.
 +
 +Inherits methods from L<RT::Record::AddAndSort>.
 +
 +For most operations it's better to use methods in L<RT::Scrip>.
 +
 +=head1 METHODS
 +
 +=head2 Table
 +
 +Returns table name for records of this class.
 +
 +=cut
 +
 +sub Table {'ObjectScrips'}
 +
 +=head2 ObjectCollectionClass
 +
 +Returns class name of collection of records scrips can be added to.
 +Now it's only L<RT::Queue>, so 'RT::Queues' is returned.
 +
 +=cut
 +
 +sub ObjectCollectionClass {'RT::Queues'}
 +
 +=head2 ScripObj
 +
 +Returns the Scrip Object which has the id returned by Scrip
 +
 +=cut
 +
 +sub ScripObj {
 +    my $self = shift;
 +    my $id = shift || $self->Scrip;
 +    my $obj = RT::Scrip->new( $self->CurrentUser );
 +    $obj->Load( $id );
 +    return $obj;
 +}
 +
 +=head2 Neighbors
 +
 +Stage splits scrips into neighborhoods. See L<RT::Record::AddAndSort/Neighbors and Siblings>.
 +
 +=cut
 +
 +sub Neighbors {
 +    my $self = shift;
 +    my %args = @_;
 +
 +    my $res = $self->CollectionClass->new( $self->CurrentUser );
 +    $res->Limit( FIELD => 'Stage', VALUE => $args{'Stage'} || $self->Stage );
 +    return $res;
 +}
 +
 +=head2 id
 +
 +Returns the current value of id.
 +(In the database, id is stored as int(11).)
 +
 +
 +=cut
 +
 +
 +=head2 Scrip
 +
 +Returns the current value of Scrip.
 +(In the database, Scrip is stored as int(11).)
 +
 +
 +
 +=head2 SetScrip VALUE
 +
 +
 +Set Scrip to VALUE.
 +Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 +(In the database, Scrip will be stored as a int(11).)
 +
 +=head2 Stage
 +
 +Returns the current value of Stage.
 +(In the database, Stage is stored as varchar(32).)
 +
 +=head2 SetStage VALUE
 +
 +Set Stage to VALUE.
 +Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 +(In the database, Stage will be stored as a varchar(32).)
 +
 +=head2 ObjectId
 +
 +Returns the current value of ObjectId.
 +(In the database, ObjectId is stored as int(11).)
 +
 +
 +
 +=head2 SetObjectId VALUE
 +
 +
 +Set ObjectId to VALUE.
 +Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 +(In the database, ObjectId will be stored as a int(11).)
 +
 +
 +=cut
 +
 +
 +=head2 SortOrder
 +
 +Returns the current value of SortOrder.
 +(In the database, SortOrder is stored as int(11).)
 +
 +
 +
 +=head2 SetSortOrder VALUE
 +
 +
 +Set SortOrder to VALUE.
 +Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 +(In the database, SortOrder will be stored as a int(11).)
 +
 +
 +=cut
 +
 +
 +=head2 Creator
 +
 +Returns the current value of Creator.
 +(In the database, Creator is stored as int(11).)
 +
 +
 +=cut
 +
 +
 +=head2 Created
 +
 +Returns the current value of Created.
 +(In the database, Created is stored as datetime.)
 +
 +
 +=cut
 +
 +
 +=head2 LastUpdatedBy
 +
 +Returns the current value of LastUpdatedBy.
 +(In the database, LastUpdatedBy is stored as int(11).)
 +
 +
 +=cut
 +
 +
 +=head2 LastUpdated
 +
 +Returns the current value of LastUpdated.
 +(In the database, LastUpdated is stored as datetime.)
 +
 +
 +=cut
 +
 +
 +
 +sub _CoreAccessible {
 +    {
 +
 +        id =>
 +		{read => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => ''},
 +        Scrip =>
 +		{read => 1, write => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => ''},
 +        Stage =>
 +		{read => 1, write => 1, sql_type => 12, length => 32,  is_blob => 0,  is_numeric => 0,  type => 'varchar(32)', default => 'TransactionCreate'},
 +        ObjectId =>
 +		{read => 1, write => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => ''},
 +        SortOrder =>
 +		{read => 1, write => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
 +        Creator =>
 +		{read => 1, auto => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
 +        Created =>
 +		{read => 1, auto => 1, sql_type => 11, length => 0,  is_blob => 0,  is_numeric => 0,  type => 'datetime', default => ''},
 +        LastUpdatedBy =>
 +		{read => 1, auto => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
 +        LastUpdated =>
 +		{read => 1, auto => 1, sql_type => 11, length => 0,  is_blob => 0,  is_numeric => 0,  type => 'datetime', default => ''},
 +
 + }
 +};
 +
 +RT::Base->_ImportOverlays();
 +
 +1;
diff --cc lib/RT/Record/AddAndSort.pm
index f547cf5,0000000..2feb3eb
mode 100644,000000..100644
--- a/lib/RT/Record/AddAndSort.pm
+++ b/lib/RT/Record/AddAndSort.pm
@@@ -1,621 -1,0 +1,621 @@@
 +# BEGIN BPS TAGGED BLOCK {{{
 +#
 +# COPYRIGHT:
 +#
- # This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
++# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
 +#                                          <sales at bestpractical.com>
 +#
 +# (Except where explicitly superseded by other copyright notices)
 +#
 +#
 +# LICENSE:
 +#
 +# This work is made available to you under the terms of Version 2 of
 +# the GNU General Public License. A copy of that license should have
 +# been provided with this software, but in any event can be snarfed
 +# from www.gnu.org.
 +#
 +# This work is distributed in the hope that it will be useful, but
 +# WITHOUT ANY WARRANTY; without even the implied warranty of
 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 +# General Public License for more details.
 +#
 +# You should have received a copy of the GNU General Public License
 +# along with this program; if not, write to the Free Software
 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 +# 02110-1301 or visit their web page on the internet at
 +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
 +#
 +#
 +# CONTRIBUTION SUBMISSION POLICY:
 +#
 +# (The following paragraph is not intended to limit the rights granted
 +# to you to modify and distribute this software under the terms of
 +# the GNU General Public License and is only of importance to you if
 +# you choose to contribute your changes and enhancements to the
 +# community by submitting them to Best Practical Solutions, LLC.)
 +#
 +# By intentionally submitting any modifications, corrections or
 +# derivatives to this work, or any other work intended for use with
 +# Request Tracker, to Best Practical Solutions, LLC, you confirm that
 +# you are the copyright holder for those contributions and you grant
 +# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
 +# royalty-free, perpetual, license to use, copy, create derivative
 +# works based on those contributions, and sublicense and distribute
 +# those contributions and any derivatives thereof.
 +#
 +# END BPS TAGGED BLOCK }}}
 +
 +use strict;
 +use warnings;
 +
 +package RT::Record::AddAndSort;
 +use base 'RT::Record';
 +
 +=head1 NAME
 +
 +RT::Record::AddAndSort - base class for records that can be added and sorted
 +
 +=head1 DESCRIPTION
 +
 +Base class for L<RT::ObjectCustomField> and L<RT::ObjectScrip> that unifies
 +application of L<RT::CustomField>s and L<RT::Scrip>s to various objects. Also,
 +deals with order of the records.
 +
 +=head1 METHODS
 +
 +=head2 Meta information
 +
 +=head3 CollectionClass
 +
 +Returns class representing collection for this record class. Basicly adds 's'
 +at the end. Should be overriden if default doesn't work.
 +
 +For example returns L<RT::ObjectCustomFields> when called on L<RT::ObjectCustomField>.
 +
 +=cut
 +
 +sub CollectionClass {
 +    return (ref($_[0]) || $_[0]).'s';
 +}
 +
 +=head3 TargetField
 +
 +Returns name of the field in the table where id of object we add is stored.
 +By default deletes everything up to '::Object' from class name.
 +This method allows to use friendlier argument names and methods.
 +
 +For example returns 'Scrip' for L<RT::ObjectScrip>.
 +
 +=cut
 +
 +sub TargetField {
 +    my $class = ref($_[0]) || $_[0];
 +    $class =~ s/.*::Object// or return undef;
 +    return $class;
 +}
 +
 +=head3 ObjectCollectionClass
 +
 +Takes an object under L</TargetField> name and should return class
 +name representing collection the object can be added to.
 +
 +Must be overriden by sub classes.
 +
 +
 +See L<RT::ObjectScrip/ObjectCollectionClass> and L<RT::ObjectCustomField/CollectionClass>.
 +
 +=cut
 +
 +sub ObjectCollectionClass { die "should be subclassed" }
 +
 +=head2 Manipulation
 +
 +=head3 Create
 +
 +Takes 'ObjectId' with id of an object we can be added to, object we can
 +add to under L</TargetField> name, Disabled and SortOrder.
 +
 +This method doesn't create duplicates. If record already exists then it's not created, but
 +loaded instead. Note that nothing is updated if record exist.
 +
 +If SortOrder is not defined then it's calculated to place new record last. If it's
 +provided then it's caller's duty to make sure it is correct value.
 +
 +Example:
 +
 +    my $ocf = RT::ObjectCustomField->new( RT->SystemUser );
 +    my ($id, $msg) = $ocf->Create( CustomField => 1, ObjectId => 0 );
 +
 +See L</Add> which has more error checks. Also, L<RT::Scrip> and L<RT::CustomField>
 +have more appropriate methods that B<should be> prefered over calling this directly.
 +
 +=cut
 +
 +sub Create {
 +    my $self = shift;
 +    my %args = (
 +        ObjectId    => 0,
 +        SortOrder   => undef,
 +        @_
 +    );
 +
 +    my $tfield = $self->TargetField;
 +
 +    my $target = $self->TargetObj( $args{ $tfield } );
 +    unless ( $target->id ) {
 +        $RT::Logger->error("Couldn't load ". ref($target) ." '$args{$tfield}'");
 +        return 0;
 +    }
 +
 +    my $exist = $self->new($self->CurrentUser);
 +    $exist->LoadByCols( ObjectId => $args{'ObjectId'}, $tfield => $target->id );
 +    if ( $exist->id ) {
 +        $self->Load( $exist->id );
 +        return $self->id;
 +    }
 +
 +    unless ( defined $args{'SortOrder'} ) {
 +        $args{'SortOrder'} = $self->NextSortOrder(
 +            %args,
 +            $tfield  => $target,
 +        );
 +    }
 +
 +    return $self->SUPER::Create(
 +        %args,
 +        $tfield   => $target->id,
 +    );
 +}
 +
 +=head3 Add
 +
 +Helper method that wraps L</Create> and does more checks to make sure
 +result is consistent. Doesn't allow adding a record to an object if the
 +record is already global. Removes record from particular objects when
 +asked to add the record globally.
 +
 +=cut
 +
 +sub Add {
 +    my $self = shift;
 +    my %args = (@_);
 +
 +    my $field = $self->TargetField;
 +
 +    my $tid = $args{ $field };
 +    $tid = $tid->id if ref $tid;
 +    $tid ||= $self->TargetObj->id;
 +
 +    my $oid = $args{'ObjectId'};
 +    $oid = $oid->id if ref $oid;
 +    $oid ||= 0;
 +
 +    if ( $self->IsAdded( $tid => $oid ) ) {
 +        return ( 0, $self->loc("Is already added to the object") );
 +    }
 +
 +    if ( $oid ) {
 +        # adding locally
 +        return (0, $self->loc("Couldn't add as it's global already") )
 +            if $self->IsAdded( $tid => 0 );
 +    }
 +    else {
 +        $self->DeleteAll( $field => $tid );
 +    }
 +
 +    return $self->Create(
 +        %args, $field => $tid, ObjectId => $oid,
 +    );
 +}
 +
 +sub IsAdded {
 +    my $self = shift;
 +    my ($tid, $oid) = @_;
 +    my $record = $self->new( $self->CurrentUser );
 +    $record->LoadByCols( $self->TargetField => $tid, ObjectId => $oid );
 +    return $record->id;
 +}
 +
 +=head3 AddedTo
 +
 +Returns collection with objects target of this record is added to.
 +Class of the collection depends on L</ObjectCollectionClass>.
 +See all L</NotAddedTo>.
 +
 +For example returns L<RT::Queues> collection if the target is L<RT::Scrip>.
 +
 +Returns empty collection if target is added globally.
 +
 +=cut
 +
 +sub AddedTo {
 +    my $self = shift;
 +
 +    my ($res, $alias) = $self->_AddedTo( @_ );
 +    return $res unless $res;
 +
 +    $res->Limit(
 +        ALIAS     => $alias,
 +        FIELD     => 'id',
 +        OPERATOR  => 'IS NOT',
 +        VALUE     => 'NULL',
 +    );
 +
 +    return $res;
 +}
 +
 +=head3 NotAddedTo
 +
 +Returns collection with objects target of this record is not added to.
 +Class of the collection depends on L</ObjectCollectionClass>.
 +See all L</AddedTo>.
 +
 +Returns empty collection if target is added globally.
 +
 +=cut
 +
 +sub NotAddedTo {
 +    my $self = shift;
 +
 +    my ($res, $alias) = $self->_AddedTo( @_ );
 +    return $res unless $res;
 +
 +    $res->Limit(
 +        ALIAS     => $alias,
 +        FIELD     => 'id',
 +        OPERATOR  => 'IS',
 +        VALUE     => 'NULL',
 +    );
 +
 +    return $res;
 +}
 +
 +sub _AddedTo {
 +    my $self = shift;
 +    my %args = (@_);
 +
 +    my $field = $self->TargetField;
 +    my $target = $args{ $field } || $self->TargetObj;
 +
 +    my ($class) = $self->ObjectCollectionClass( $field => $target );
 +    return undef unless $class;
 +
 +    my $res = $class->new( $self->CurrentUser );
 +
 +    # If target added to a Group, only display user-defined groups
 +    $res->LimitToUserDefinedGroups if $class eq 'RT::Groups';
 +
 +    $res->OrderBy( FIELD => 'Name' );
 +    my $alias = $res->Join(
 +        TYPE   => 'LEFT',
 +        ALIAS1 => 'main',
 +        FIELD1 => 'id',
 +        TABLE2 => $self->Table,
 +        FIELD2 => 'ObjectId',
 +    );
 +    $res->Limit(
 +        LEFTJOIN => $alias,
 +        ALIAS    => $alias,
 +        FIELD    => $field,
 +        VALUE    => $target->id,
 +    );
 +    return ($res, $alias);
 +}
 +
 +=head3 Delete
 +
 +Deletes this record.
 +
 +=cut
 +
 +sub Delete {
 +    my $self = shift;
 +
 +    return $self->SUPER::Delete if $self->IsSortOrderShared;
 +
 +    # Move everything below us up
 +    my $siblings = $self->Neighbors;
 +    $siblings->Limit( FIELD => 'SortOrder', OPERATOR => '>=', VALUE => $self->SortOrder );
 +    $siblings->OrderBy( FIELD => 'SortOrder', ORDER => 'ASC' );
 +    foreach my $record ( @{ $siblings->ItemsArrayRef } ) {
 +        $record->SetSortOrder($record->SortOrder - 1);
 +    }
 +
 +    return $self->SUPER::Delete;
 +}
 +
 +=head3 DeleteAll
 +
 +Helper method to delete all applications for one target (Scrip, CustomField, ...).
 +Target can be provided in arguments. If it's not then L</TargetObj> is used.
 +
 +    $object_scrip->DeleteAll;
 +
 +    $object_scrip->DeleteAll( Scrip => $scrip );
 +
 +=cut
 +
 +sub DeleteAll {
 +    my $self = shift;
 +    my %args = (@_);
 +
 +    my $field = $self->TargetField;
 +
 +    my $id = $args{ $field };
 +    $id = $id->id if ref $id;
 +    $id ||= $self->TargetObj->id;
 +
 +    my $list = $self->CollectionClass->new( $self->CurrentUser );
 +    $list->Limit( FIELD => $field, VALUE => $id );
 +    $_->Delete foreach @{ $list->ItemsArrayRef };
 +}
 +
 +=head3 MoveUp
 +
 +Moves record up.
 +
 +=cut
 +
 +sub MoveUp { return shift->Move( Up => @_ ) }
 +
 +=head3 MoveDown
 +
 +Moves record down.
 +
 +=cut
 +
 +sub MoveDown { return shift->Move( Down => @_ ) }
 +
 +=head3 Move
 +
 +Takes 'up' or 'down'. One method that implements L</MoveUp> and L</MoveDown>.
 +
 +=cut
 +
 +sub Move {
 +    my $self = shift;
 +    my $dir = lc(shift || 'up');
 +
 +    my %meta;
 +    if ( $dir eq 'down' ) {
 +        %meta = qw(
 +            next_op    >
 +            next_order ASC
 +            prev_op    <=
 +            diff       +1
 +        );
 +    } else {
 +        %meta = qw(
 +            next_op    <
 +            next_order DESC
 +            prev_op    >=
 +            diff       -1
 +        );
 +    }
 +
 +    my $siblings = $self->Siblings;
 +    $siblings->Limit( FIELD => 'SortOrder', OPERATOR => $meta{'next_op'}, VALUE => $self->SortOrder );
 +    $siblings->OrderBy( FIELD => 'SortOrder', ORDER => $meta{'next_order'} );
 +
 +    my @next = ($siblings->Next, $siblings->Next);
 +    unless ($next[0]) {
 +        return $dir eq 'down'
 +            ? (0, "Can not move down. It's already at the bottom")
 +            : (0, "Can not move up. It's already at the top")
 +        ;
 +    }
 +
 +    my ($new_sort_order, $move);
 +
 +    unless ( $self->ObjectId ) {
 +        # moving global, it can not share sort order, so just move it
 +        # on place of next global and move everything in between one number
 +
 +        $new_sort_order = $next[0]->SortOrder;
 +        $move = $self->Neighbors;
 +        $move->Limit(
 +            FIELD => 'SortOrder', OPERATOR => $meta{'next_op'}, VALUE => $self->SortOrder,
 +        );
 +        $move->Limit(
 +            FIELD => 'SortOrder', OPERATOR => $meta{'prev_op'}, VALUE => $next[0]->SortOrder,
 +            ENTRYAGGREGATOR => 'AND',
 +        );
 +    }
 +    elsif ( $next[0]->ObjectId == $self->ObjectId ) {
 +        # moving two locals, just swap them, they should follow 'so = so+/-1' rule
 +        $new_sort_order = $next[0]->SortOrder;
 +        $move = $next[0];
 +    }
 +    else {
 +        # moving local behind global
 +        unless ( $self->IsSortOrderShared ) {
 +            # not shared SO allows us to swap
 +            $new_sort_order = $next[0]->SortOrder;
 +            $move = $next[0];
 +        }
 +        elsif ( $next[1] ) {
 +            # more records there and shared SO, we have to move everything
 +            $new_sort_order = $next[0]->SortOrder;
 +            $move = $self->Neighbors;
 +            $move->Limit(
 +                FIELD => 'SortOrder', OPERATOR => $meta{prev_op}, VALUE => $next[0]->SortOrder,
 +            );
 +        }
 +        else {
 +            # shared SO and place after is free, so just jump
 +            $new_sort_order = $next[0]->SortOrder + $meta{'diff'};
 +        }
 +    }
 +
 +    if ( $move ) {
 +        foreach my $record ( $move->isa('RT::Record')? ($move) : @{ $move->ItemsArrayRef } ) {
 +            my ($status, $msg) = $record->SetSortOrder(
 +                $record->SortOrder - $meta{'diff'}
 +            );
 +            return (0, "Couldn't move: $msg") unless $status;
 +        }
 +    }
 +
 +    my ($status, $msg) = $self->SetSortOrder( $new_sort_order );
 +    unless ( $status ) {
 +        return (0, "Couldn't move: $msg");
 +    }
 +
 +    return (1,"Moved");
 +}
 +
 +=head2 Accessors, instrospection and traversing.
 +
 +=head3 TargetObj
 +
 +Returns target object of this record. Returns L<RT::Scrip> object for
 +L<RT::ObjectScrip>.
 +
 +=cut
 +
 +sub TargetObj {
 +    my $self = shift;
 +    my $id   = shift;
 +
 +    my $method = $self->TargetField .'Obj';
 +    return $self->$method( $id );
 +}
 +
 +=head3 NextSortOrder
 +
 +Returns next available SortOrder value in the L<neighborhood|/Neighbors>.
 +Pass arguments to L</Neighbors> and can take optional ObjectId argument,
 +calls ObjectId if it's not provided.
 +
 +=cut
 +
 +sub NextSortOrder {
 +    my $self = shift;
 +    my %args = (@_);
 +
 +    my $oid = $args{'ObjectId'};
 +    $oid = $self->ObjectId unless defined $oid;
 +    $oid ||= 0;
 +
 +    my $neighbors = $self->Neighbors( %args );
 +    if ( $oid ) {
 +        $neighbors->LimitToObjectId( $oid );
 +        $neighbors->LimitToObjectId( 0 );
 +    } elsif ( !$neighbors->_isLimited ) {
 +        $neighbors->UnLimit;
 +    }
 +    $neighbors->OrderBy( FIELD => 'SortOrder', ORDER => 'DESC' );
 +    return 0 unless my $first = $neighbors->First;
 +    return $first->SortOrder + 1;
 +}
 +
 +=head3 IsSortOrderShared
 +
 +Returns true if this record shares SortOrder value with a L<neighbor|/Neighbors>.
 +
 +=cut
 +
 +sub IsSortOrderShared {
 +    my $self = shift;
 +    return 0 unless $self->ObjectId;
 +
 +    my $neighbors = $self->Neighbors;
 +    $neighbors->Limit( FIELD => 'id', OPERATOR => '!=', VALUE => $self->id );
 +    $neighbors->Limit( FIELD => 'SortOrder', VALUE => $self->SortOrder );
 +    return $neighbors->Count;
 +}
 +
 +=head2 Neighbors and Siblings
 +
 +These two methods should only be understood by developers who wants
 +to implement new classes of records that can be added to other records
 +and sorted.
 +
 +Main purpose is to maintain SortOrder values.
 +
 +Let's take a look at custom fields. A custom field can be created for tickets,
 +queues, transactions, users... Custom fields created for tickets can
 +be added globally or to particular set of queues. Custom fields for
 +tickets are neighbors. Neighbor custom fields added to the same objects
 +are siblings. Custom fields added globally are sibling to all neighbors.
 +
 +For scrips Stage defines neighborhood.
 +
 +Let's look at the three scrips in create stage S1, S2 and S3, queues Q1 and Q2 and
 +G for global.
 +
 +    S1 at Q1, S3 at Q2 0
 +    S2 at G         1
 +    S1 at Q2        2
 +
 +Above table says that S2 is added globally, S1 is added to Q1 and executed
 +before S2 in this queue, also S1 is added to Q1, but exectued after S2 in this
 +queue, S3 is only added to Q2 and executed before S2 and S1.
 +
 +Siblings are scrips added to an object including globally added or only
 +globally added. In our example there are three different collection
 +of siblings: (S2) - global, (S1, S2) for Q1, (S3, S2, S1) for Q2.
 +
 +Sort order can be shared between neighbors, but can not be shared between siblings.
 +
 +Here is what happens with sort order if we move S1 at Q2 one position up:
 +
 +           S3 at Q2 0
 +    S1 at Q1, S1 at Q2 1
 +    S2 at G         2
 +
 +One position more:
 +
 +           S1 at Q2 0
 +    S1 at Q1, S3 at Q2 1
 +    S2 at G         2
 +
 +Hopefuly it's enough to understand how it works.
 +
 +Targets from different neighborhood can not be sorted against each other.
 +
 +=head3 Neighbors
 +
 +Returns collection of records of this class with all
 +neighbors. By default all possible targets are neighbors.
 +
 +Takes the same arguments as L</Create> method. If arguments are not passed
 +then uses the current record.
 +
 +See L</Neighbors and Siblings> for detailed description.
 +
 +See L<RT::ObjectCustomField/Neighbors> for example.
 +
 +=cut
 +
 +sub Neighbors {
 +    my $self = shift;
 +    return $self->CollectionClass->new( $self->CurrentUser );
 +}
 +
 +=head3 Siblings
 +
 +Returns collection of records of this class with siblings.
 +
 +Takes the same arguments as L</Neighbors>. Siblings is subset of L</Neighbors>.
 +
 +=cut
 +
 +sub Siblings {
 +    my $self = shift;
 +    my %args = @_;
 +
 +    my $oid = $args{'ObjectId'};
 +    $oid = $self->ObjectId unless defined $oid;
 +    $oid ||= 0;
 +
 +    my $res = $self->Neighbors( %args );
 +    $res->LimitToObjectId( $oid );
 +    $res->LimitToObjectId( 0 ) if $oid;
 +    return $res;
 +}
 +
 +RT::Base->_ImportOverlays();
 +
 +1;
diff --cc lib/RT/Role/Record/Lifecycle.pm
index a739a5b,0000000..2ee5e05
mode 100644,000000..100644
--- a/lib/RT/Role/Record/Lifecycle.pm
+++ b/lib/RT/Role/Record/Lifecycle.pm
@@@ -1,219 -1,0 +1,219 @@@
 +# BEGIN BPS TAGGED BLOCK {{{
 +#
 +# COPYRIGHT:
 +#
- # This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
++# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
 +#                                          <sales at bestpractical.com>
 +#
 +# (Except where explicitly superseded by other copyright notices)
 +#
 +#
 +# LICENSE:
 +#
 +# This work is made available to you under the terms of Version 2 of
 +# the GNU General Public License. A copy of that license should have
 +# been provided with this software, but in any event can be snarfed
 +# from www.gnu.org.
 +#
 +# This work is distributed in the hope that it will be useful, but
 +# WITHOUT ANY WARRANTY; without even the implied warranty of
 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 +# General Public License for more details.
 +#
 +# You should have received a copy of the GNU General Public License
 +# along with this program; if not, write to the Free Software
 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 +# 02110-1301 or visit their web page on the internet at
 +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
 +#
 +#
 +# CONTRIBUTION SUBMISSION POLICY:
 +#
 +# (The following paragraph is not intended to limit the rights granted
 +# to you to modify and distribute this software under the terms of
 +# the GNU General Public License and is only of importance to you if
 +# you choose to contribute your changes and enhancements to the
 +# community by submitting them to Best Practical Solutions, LLC.)
 +#
 +# By intentionally submitting any modifications, corrections or
 +# derivatives to this work, or any other work intended for use with
 +# Request Tracker, to Best Practical Solutions, LLC, you confirm that
 +# you are the copyright holder for those contributions and you grant
 +# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
 +# royalty-free, perpetual, license to use, copy, create derivative
 +# works based on those contributions, and sublicense and distribute
 +# those contributions and any derivatives thereof.
 +#
 +# END BPS TAGGED BLOCK }}}
 +
 +use strict;
 +use warnings;
 +
 +package RT::Role::Record::Lifecycle;
 +use Role::Basic;
 +use Scalar::Util qw(blessed);
 +
 +=head1 NAME
 +
 +RT::Role::Record::Lifecycle - Common methods for records which have a Lifecycle column
 +
 +=head1 REQUIRES
 +
 +=head2 L<RT::Role::Record>
 +
 +=head2 LifecycleType
 +
 +Used as a role parameter.  Must return a string of the type of lifecycles the
 +record consumes, i.e.  I<ticket> for L<RT::Queue>.
 +
 +=head2 Lifecycle
 +
 +A Lifecycle method which returns a lifecycle name is required.  Currently
 +unenforced at compile-time due to poor interactions with
 +L<DBIx::SearchBuilder::Record/AUTOLOAD>.  You'll hit run-time errors if this
 +method isn't available in consuming classes, however.
 +
 +=cut
 +
 +with 'RT::Role::Record';
 +requires 'LifecycleType';
 +
 +# XXX: can't require column methods due to DBIx::SB::Record's AUTOLOAD
 +#requires 'Lifecycle';
 +
 +=head1 PROVIDES
 +
 +=head2 LifecycleObj
 +
 +Returns an L<RT::Lifecycle> object for this record's C<Lifecycle>.  If called
 +as a class method, returns an L<RT::Lifecycle> object which is an aggregation
 +of all lifecycles of the appropriate type.
 +
 +=cut
 +
 +sub LifecycleObj {
 +    my $self = shift;
 +    my $type = $self->LifecycleType;
 +    my $fallback = $self->_Accessible( Lifecycle => "default" );
 +
 +    unless (blessed($self) and $self->id) {
 +        return RT::Lifecycle->Load( Type => $type );
 +    }
 +
 +    my $name = $self->Lifecycle || $fallback;
 +    my $res  = RT::Lifecycle->Load( Name => $name, Type => $type );
 +    unless ( $res ) {
 +        RT->Logger->error(
 +            sprintf "Lifecycle '%s' of type %s for %s #%d doesn't exist",
 +                    $name, $type, ref($self), $self->id);
 +        return RT::Lifecycle->Load( Name => $fallback, Type => $type );
 +    }
 +    return $res;
 +}
 +
 +=head2 SetLifecycle
 +
 +Validates that the specified lifecycle exists before updating the record.
 +
 +Takes a lifecycle name.
 +
 +=cut
 +
 +sub SetLifecycle {
 +    my $self  = shift;
 +    my $value = shift || $self->_Accessible( Lifecycle => "default" );
 +
 +    return (0, $self->loc('[_1] is not a valid lifecycle', $value))
 +        unless $self->ValidateLifecycle($value);
 +
 +    return $self->_Set( Field => 'Lifecycle', Value => $value, @_ );
 +}
 +
 +=head2 ValidateLifecycle
 +
 +Takes a lifecycle name.  Returns true if it's an OK name and such lifecycle is
 +configured.  Returns false otherwise.
 +
 +=cut
 +
 +sub ValidateLifecycle {
 +    my $self  = shift;
 +    my $value = shift;
 +    return unless $value;
 +    return unless RT::Lifecycle->Load( Name => $value, Type => $self->LifecycleType );
 +    return 1;
 +}
 +
 +=head2 ActiveStatusArray
 +
 +Returns an array of all ActiveStatuses for the lifecycle
 +
 +=cut
 +
 +sub ActiveStatusArray {
 +    my $self = shift;
 +    return $self->LifecycleObj->Valid('initial', 'active');
 +}
 +
 +=head2 InactiveStatusArray
 +
 +Returns an array of all InactiveStatuses for the lifecycle
 +
 +=cut
 +
 +sub InactiveStatusArray {
 +    my $self = shift;
 +    return $self->LifecycleObj->Inactive;
 +}
 +
 +=head2 StatusArray
 +
 +Returns an array of all statuses for the lifecycle
 +
 +=cut
 +
 +sub StatusArray {
 +    my $self = shift;
 +    return $self->LifecycleObj->Valid( @_ );
 +}
 +
 +=head2 IsValidStatus
 +
 +Takes a status.
 +
 +Returns true if STATUS is a valid status.  Otherwise, returns 0.
 +
 +=cut
 +
 +sub IsValidStatus {
 +    my $self  = shift;
 +    return $self->LifecycleObj->IsValid( shift );
 +}
 +
 +=head2 IsActiveStatus
 +
 +Takes a status.
 +
 +Returns true if STATUS is a Active status.  Otherwise, returns 0
 +
 +=cut
 +
 +sub IsActiveStatus {
 +    my $self  = shift;
 +    return $self->LifecycleObj->IsValid( shift, 'initial', 'active');
 +}
 +
 +=head2 IsInactiveStatus
 +
 +Takes a status.
 +
 +Returns true if STATUS is a Inactive status.  Otherwise, returns 0
 +
 +=cut
 +
 +sub IsInactiveStatus {
 +    my $self  = shift;
 +    return $self->LifecycleObj->IsInactive( shift );
 +}
 +
 +1;
diff --cc lib/RT/Role/Record/Status.pm
index afcab13,0000000..165c02c
mode 100644,000000..100644
--- a/lib/RT/Role/Record/Status.pm
+++ b/lib/RT/Role/Record/Status.pm
@@@ -1,302 -1,0 +1,302 @@@
 +# BEGIN BPS TAGGED BLOCK {{{
 +#
 +# COPYRIGHT:
 +#
- # This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
++# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
 +#                                          <sales at bestpractical.com>
 +#
 +# (Except where explicitly superseded by other copyright notices)
 +#
 +#
 +# LICENSE:
 +#
 +# This work is made available to you under the terms of Version 2 of
 +# the GNU General Public License. A copy of that license should have
 +# been provided with this software, but in any event can be snarfed
 +# from www.gnu.org.
 +#
 +# This work is distributed in the hope that it will be useful, but
 +# WITHOUT ANY WARRANTY; without even the implied warranty of
 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 +# General Public License for more details.
 +#
 +# You should have received a copy of the GNU General Public License
 +# along with this program; if not, write to the Free Software
 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 +# 02110-1301 or visit their web page on the internet at
 +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
 +#
 +#
 +# CONTRIBUTION SUBMISSION POLICY:
 +#
 +# (The following paragraph is not intended to limit the rights granted
 +# to you to modify and distribute this software under the terms of
 +# the GNU General Public License and is only of importance to you if
 +# you choose to contribute your changes and enhancements to the
 +# community by submitting them to Best Practical Solutions, LLC.)
 +#
 +# By intentionally submitting any modifications, corrections or
 +# derivatives to this work, or any other work intended for use with
 +# Request Tracker, to Best Practical Solutions, LLC, you confirm that
 +# you are the copyright holder for those contributions and you grant
 +# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
 +# royalty-free, perpetual, license to use, copy, create derivative
 +# works based on those contributions, and sublicense and distribute
 +# those contributions and any derivatives thereof.
 +#
 +# END BPS TAGGED BLOCK }}}
 +
 +use strict;
 +use warnings;
 +
 +package RT::Role::Record::Status;
 +use Role::Basic;
 +use Scalar::Util qw(blessed);
 +
 +=head1 NAME
 +
 +RT::Role::Record::Status - Common methods for records which have a Status column
 +
 +=head1 DESCRIPTION
 +
 +Lifecycles are generally set on container records, and Statuses on records
 +which belong to one of those containers.  L<RT::Role::Record::Lifecycle>
 +handles the containers with the I<Lifecycle> column.  This role is for the
 +records with a I<Status> column within those containers.  It includes
 +convenience methods for grabbing an L<RT::Lifecycle> object as well setters for
 +validating I<Status> and the column which points to the container object.
 +
 +=head1 REQUIRES
 +
 +=head2 L<RT::Role::Record>
 +
 +=head2 LifecycleColumn
 +
 +Used as a role parameter.  Must return a string of the column name which points
 +to the container object that consumes L<RT::Role::Record::Lifecycle> (or
 +conforms to it).  The resulting string is used to construct two method names:
 +as-is to fetch the column value and suffixed with "Obj" to fetch the object.
 +
 +=head2 Status
 +
 +A Status method which returns a lifecycle name is required.  Currently
 +unenforced at compile-time due to poor interactions with
 +L<DBIx::SearchBuilder::Record/AUTOLOAD>.  You'll hit run-time errors if this
 +method isn't available in consuming classes, however.
 +
 +=cut
 +
 +with 'RT::Role::Record';
 +requires 'LifecycleColumn';
 +
 +# XXX: can't require column methods due to DBIx::SB::Record's AUTOLOAD
 +#requires 'Status';
 +
 +=head1 PROVIDES
 +
 +=head2 LifecycleObj
 +
 +Returns an L<RT::Lifecycle> object for this record's C<Lifecycle>.  If called
 +as a class method, returns an L<RT::Lifecycle> object which is an aggregation
 +of all lifecycles of the appropriate type.
 +
 +=cut
 +
 +sub LifecycleObj {
 +    my $self = shift;
 +    my $obj  = $self->LifecycleColumn . "Obj";
 +    return $self->$obj->LifecycleObj;
 +}
 +
 +=head2 Lifecycle
 +
 +Returns the L<RT::Lifecycle/Name> of this record's L</LifecycleObj>.
 +
 +=cut
 +
 +sub Lifecycle {
 +    my $self = shift;
 +    return $self->LifecycleObj->Name;
 +}
 +
 +=head2 ValidateStatus
 +
 +Takes a status.  Returns true if that status is a valid status for this record,
 +otherwise returns false.
 +
 +=cut
 +
 +sub ValidateStatus {
 +    my $self = shift;
 +    return $self->LifecycleObj->IsValid(@_);
 +}
 +
 +=head2 ValidateStatusChange
 +
 +Validates the new status with the current lifecycle.  Returns a tuple of (OK,
 +message).
 +
 +Expected to be called from this role's L</SetStatus> or the consuming class'
 +equivalent.
 +
 +=cut
 +
 +sub ValidateStatusChange {
 +    my $self = shift;
 +    my $new  = shift;
 +    my $old  = $self->Status;
 +
 +    my $lifecycle = $self->LifecycleObj;
 +
 +    unless ( $lifecycle->IsValid( $new ) ) {
 +        return (0, $self->loc("Status '[_1]' isn't a valid status for this [_2].", $self->loc($new), $self->loc($lifecycle->Type)));
 +    }
 +
 +    unless ( $lifecycle->IsTransition( $old => $new ) ) {
 +        return (0, $self->loc("You can't change status from '[_1]' to '[_2]'.", $self->loc($old), $self->loc($new)));
 +    }
 +
 +    my $check_right = $lifecycle->CheckRight( $old => $new );
 +    unless ( $self->CurrentUser->HasRight( Right => $check_right, Object => $self ) ) {
 +        return ( 0, $self->loc('Permission Denied') );
 +    }
 +
 +    return 1;
 +}
 +
 +=head2 SetStatus
 +
 +Validates the status transition before updating the Status column.  This method
 +may want to be overridden by a more specific method in the consuming class.
 +
 +=cut
 +
 +sub SetStatus {
 +    my $self = shift;
 +    my $new  = shift;
 +
 +    my ($valid, $error) = $self->ValidateStatusChange($new);
 +    return ($valid, $error) unless $valid;
 +
 +    return $self->_SetStatus( Status => $new );
 +}
 +
 +=head2 _SetStatus
 +
 +Sets the Status column without validating the change.  Intended to be used
 +as-is by methods provided by the role, or overridden in the consuming class to
 +take additional action.  For example, L<RT::Ticket/_SetStatus> sets the Started
 +and Resolved dates on the ticket as necessary.
 +
 +Takes a paramhash where the only required key is Status.  Other keys may
 +include Lifecycle and NewLifecycle when called from L</_SetLifecycleColumn>,
 +which may assist consuming classes.  NewLifecycle defaults to Lifecycle if not
 +provided; this indicates the lifecycle isn't changing.
 +
 +=cut
 +
 +sub _SetStatus {
 +    my $self = shift;
 +    my %args = (
 +        Status      => undef,
 +        Lifecycle   => $self->LifecycleObj,
 +        @_,
 +    );
 +    $args{NewLifecycle} ||= $args{Lifecycle};
 +
 +    return $self->_Set(
 +        Field   => 'Status',
 +        Value   => $args{Status},
 +    );
 +}
 +
 +=head2 _SetLifecycleColumn
 +
 +Validates and updates the column named by L</LifecycleColumn>.  The Status
 +column is also updated if necessary (via lifecycle transition maps).
 +
 +On success, returns a tuple of (1, I<message>, I<new status>) where I<new
 +status> is the status that was transitioned to, if any.  On failure, returns
 +(0, I<error message>).
 +
 +Takes a paramhash with keys I<Value> and (optionally) I<RequireRight>.
 +I<RequireRight> is a right name which the current user must have on the new
 +L</LifecycleColumn> object in order for the method to succeed.
 +
 +This method is expected to be used from within another method such as
 +L<RT::Ticket/SetQueue>.
 +
 +=cut
 +
 +sub _SetLifecycleColumn {
 +    my $self = shift;
 +    my %args = @_;
 +
 +    my $column     = $self->LifecycleColumn;
 +    my $column_obj = "${column}Obj";
 +
 +    my $current = $self->$column_obj;
 +    my $class   = blessed($current);
 +
 +    my $new = $class->new( $self->CurrentUser );
 +    $new->Load($args{Value});
 +
 +    return (0, $self->loc("[_1] [_2] does not exist", $self->loc($column), $args{Value}))
 +        unless $new->id;
 +
 +    my $name = eval { $current->Name } || $current->id;
 +
 +    return (0, $self->loc("[_1] [_2] is disabled", $self->loc($column), $name))
 +        if $new->Disabled;
 +
 +    return (0, $self->loc("[_1] is already set to [_2]", $self->loc($column), $name))
 +        if $new->id == $current->id;
 +
 +    return (0, $self->loc("Permission Denied"))
 +        if $args{RequireRight} and not $self->CurrentUser->HasRight(
 +            Right   => $args{RequireRight},
 +            Object  => $new,
 +        );
 +
 +    my $new_status;
 +    my $old_lifecycle = $current->LifecycleObj;
 +    my $new_lifecycle = $new->LifecycleObj;
 +    if ( $old_lifecycle->Name ne $new_lifecycle->Name ) {
 +        unless ( $old_lifecycle->HasMoveMap( $new_lifecycle ) ) {
 +            return ( 0, $self->loc("There is no mapping for statuses between lifecycle [_1] and [_2]. Contact your system administrator.", $old_lifecycle->Name, $new_lifecycle->Name) );
 +        }
 +        $new_status = $old_lifecycle->MoveMap( $new_lifecycle )->{ $self->Status };
 +        return ( 0, $self->loc("Mapping between lifecycle [_1] and [_2] is incomplete. Contact your system administrator.", $old_lifecycle->Name, $new_lifecycle->Name) )
 +            unless $new_status;
 +    }
 +
 +    my ($ok, $msg) = $self->_Set( Field => $column, Value => $new->id );
 +    if ($ok) {
 +        if ( $new_status ) {
 +            my $as_system = blessed($self)->new( RT->SystemUser );
 +            $as_system->Load( $self->Id );
 +            unless ( $as_system->Id ) {
 +                return ( 0, $self->loc("Couldn't load copy of [_1] #[_2]", blessed($self), $self->Id) );
 +            }
 +
 +            my ($val, $msg) = $as_system->_SetStatus(
 +                Lifecycle       => $old_lifecycle,
 +                NewLifecycle    => $new_lifecycle,
 +                Status          => $new_status,
 +            );
 +
 +            if ($val) {
 +                # Pick up the change made by the clone above
 +                $self->Load( $self->id );
 +            } else {
 +                RT->Logger->error("Status change to $new_status failed on $column change: $msg");
 +                undef $new_status;
 +            }
 +        }
 +        return (1, $msg, $new_status);
 +    } else {
 +        return (0, $msg);
 +    }
 +}
 +
 +1;
diff --cc lib/RT/SearchBuilder/AddAndSort.pm
index 2334798,0000000..3d8ef11
mode 100644,000000..100644
--- a/lib/RT/SearchBuilder/AddAndSort.pm
+++ b/lib/RT/SearchBuilder/AddAndSort.pm
@@@ -1,243 -1,0 +1,243 @@@
 +# BEGIN BPS TAGGED BLOCK {{{
 +#
 +# COPYRIGHT:
 +#
- # This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
++# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
 +#                                          <sales at bestpractical.com>
 +#
 +# (Except where explicitly superseded by other copyright notices)
 +#
 +#
 +# LICENSE:
 +#
 +# This work is made available to you under the terms of Version 2 of
 +# the GNU General Public License. A copy of that license should have
 +# been provided with this software, but in any event can be snarfed
 +# from www.gnu.org.
 +#
 +# This work is distributed in the hope that it will be useful, but
 +# WITHOUT ANY WARRANTY; without even the implied warranty of
 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 +# General Public License for more details.
 +#
 +# You should have received a copy of the GNU General Public License
 +# along with this program; if not, write to the Free Software
 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 +# 02110-1301 or visit their web page on the internet at
 +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
 +#
 +#
 +# CONTRIBUTION SUBMISSION POLICY:
 +#
 +# (The following paragraph is not intended to limit the rights granted
 +# to you to modify and distribute this software under the terms of
 +# the GNU General Public License and is only of importance to you if
 +# you choose to contribute your changes and enhancements to the
 +# community by submitting them to Best Practical Solutions, LLC.)
 +#
 +# By intentionally submitting any modifications, corrections or
 +# derivatives to this work, or any other work intended for use with
 +# Request Tracker, to Best Practical Solutions, LLC, you confirm that
 +# you are the copyright holder for those contributions and you grant
 +# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
 +# royalty-free, perpetual, license to use, copy, create derivative
 +# works based on those contributions, and sublicense and distribute
 +# those contributions and any derivatives thereof.
 +#
 +# END BPS TAGGED BLOCK }}}
 +
 +use strict;
 +use warnings;
 +
 +package RT::SearchBuilder::AddAndSort;
 +use base 'RT::SearchBuilder';
 +
 +=head1 NAME
 +
 +RT::SearchBuilder::AddAndSort - base class for 'add and sort' collections
 +
 +=head1 DESCRIPTION
 +
 +Base class for collections where records can be added to objects with order.
 +See also L<RT::Record::AddAndSort>. Used by L<RT::ObjectScrips> and
 +L<RT::ObjectCustomFields>.
 +
 +As it's about sorting then collection is sorted by SortOrder field.
 +
 +=head1 METHODS
 +
 +=cut
 +
 +sub _Init {
 +    my $self = shift;
 +
 +    # By default, order by SortOrder
 +    $self->OrderByCols(
 +         { ALIAS => 'main',
 +           FIELD => 'SortOrder',
 +           ORDER => 'ASC' },
 +         { ALIAS => 'main',
 +           FIELD => 'id',
 +           ORDER => 'ASC' },
 +    );
 +
 +    return $self->SUPER::_Init(@_);
 +}
 +
 +=head2 RecordClass
 +
 +Returns class name of records in this collection. This generic implementation
 +just strips trailing 's'.
 +
 +=cut
 +
 +sub RecordClass {
 +    my $class = ref($_[0]) || $_[0];
 +    $class =~ s/s$// or return undef;
 +    return $class;
 +}
 +
 +=head2 LimitToObjectId
 +
 +Takes id of an object and limits collection.
 +
 +=cut
 +
 +sub LimitToObjectId {
 +    my $self = shift;
 +    my $id = shift || 0;
 +    $self->Limit( FIELD => 'ObjectId', VALUE => $id );
 +}
 +
 +=head2 NewItem
 +
 +Returns an empty new collection's item
 +
 +=cut
 +
 +sub NewItem {
 +    my $self = shift;
 +    return $self->RecordClass->new( $self->CurrentUser );
 +}
 +
 +=head1 METHODS FOR TARGETS
 +
 +Rather than implementing a base class for targets (L<RT::Scrip>,
 +L<RT::CustomField>) and its collections. This class provides
 +class methods to limit target collections.
 +
 +=head2 LimitTargetToNotAdded
 +
 +Takes a collection object and optional list of object ids. Limits the
 +collection to records not added to listed objects or if the list is
 +empty then any object. Use 0 (zero) to mean global.
 +
 +=cut
 +
 +sub LimitTargetToNotAdded {
 +    my $self = shift;
 +    my $collection = shift;
 +    my @ids = @_;
 +
 +    my $alias = $self->JoinTargetToAdded($collection => @ids);
 +
 +    $collection->Limit(
 +        ENTRYAGGREGATOR => 'AND',
 +        ALIAS    => $alias,
 +        FIELD    => 'id',
 +        OPERATOR => 'IS',
 +        VALUE    => 'NULL',
 +    );
 +    return $alias;
 +}
 +
 +=head2 LimitTargetToAdded
 +
 +L</LimitTargetToNotAdded> with reverse meaning. Takes the same
 +arguments.
 +
 +=cut
 +
 +sub LimitTargetToAdded {
 +    my $self = shift;
 +    my $collection = shift;
 +    my @ids = @_;
 +
 +    my $alias = $self->JoinTargetToAdded($collection => @ids);
 +
 +    $collection->Limit(
 +        ENTRYAGGREGATOR => 'AND',
 +        ALIAS    => $alias,
 +        FIELD    => 'id',
 +        OPERATOR => 'IS NOT',
 +        VALUE    => 'NULL',
 +    );
 +    return $alias;
 +}
 +
 +=head2 JoinTargetToAdded
 +
 +Joins collection to this table using left join, limits joined table
 +by ids if those are provided.
 +
 +Returns alias of the joined table. Join is cached and re-used for
 +multiple calls.
 +
 +=cut
 +
 +sub JoinTargetToAdded {
 +    my $self = shift;
 +    my $collection = shift;
 +    my @ids = @_;
 +
 +    my $alias = $self->JoinTargetToThis( $collection, New => 0, Left => 1 );
 +    return $alias unless @ids;
 +
 +    # XXX: we need different EA in join clause, but DBIx::SB
 +    # doesn't support them, use IN (X) instead
 +    my $dbh = $self->_Handle->dbh;
 +    $collection->Limit(
 +        LEFTJOIN   => $alias,
 +        ALIAS      => $alias,
 +        FIELD      => 'ObjectId',
 +        OPERATOR   => 'IN',
 +        QUOTEVALUE => 0,
 +        VALUE      => "(". join( ',', map $dbh->quote($_), @ids ) .")",
 +    );
 +
 +    return $alias;
 +}
 +
 +=head2 JoinTargetToThis
 +
 +Joins target collection to this table using TargetField.
 +
 +Takes New and Left arguments. Use New to avoid caching and re-using
 +this join. Use Left to create LEFT JOIN rather than inner.
 +
 +=cut
 +
 +sub JoinTargetToThis {
 +    my $self = shift;
 +    my $collection = shift;
 +    my %args = ( New => 0, Left => 0, @_ );
 +
 +    my $table = $self->Table;
 +    my $key = "_sql_${table}_alias";
 +
 +    return $collection->{ $key } if $collection->{ $key } && !$args{'New'};
 +
 +    my $alias = $collection->Join(
 +        $args{'Left'} ? (TYPE => 'LEFT') : (),
 +        ALIAS1 => 'main',
 +        FIELD1 => 'id',
 +        TABLE2 => $table,
 +        FIELD2 => $self->RecordClass->TargetField,
 +    );
 +    return $alias if $args{'New'};
 +    return $collection->{ $key } = $alias;
 +}
 +
 +RT::Base->_ImportOverlays();
 +
 +1;
diff --cc lib/RT/Test/Shredder.pm
index 43bc09c,7be9513..dfbc90b
--- a/lib/RT/Test/Shredder.pm
+++ b/lib/RT/Test/Shredder.pm
@@@ -1,50 -1,3 +1,50 @@@
 +# BEGIN BPS TAGGED BLOCK {{{
 +#
 +# COPYRIGHT:
 +#
- # This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
++# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
 +#                                          <sales at bestpractical.com>
 +#
 +# (Except where explicitly superseded by other copyright notices)
 +#
 +#
 +# LICENSE:
 +#
 +# This work is made available to you under the terms of Version 2 of
 +# the GNU General Public License. A copy of that license should have
 +# been provided with this software, but in any event can be snarfed
 +# from www.gnu.org.
 +#
 +# This work is distributed in the hope that it will be useful, but
 +# WITHOUT ANY WARRANTY; without even the implied warranty of
 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 +# General Public License for more details.
 +#
 +# You should have received a copy of the GNU General Public License
 +# along with this program; if not, write to the Free Software
 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 +# 02110-1301 or visit their web page on the internet at
 +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
 +#
 +#
 +# CONTRIBUTION SUBMISSION POLICY:
 +#
 +# (The following paragraph is not intended to limit the rights granted
 +# to you to modify and distribute this software under the terms of
 +# the GNU General Public License and is only of importance to you if
 +# you choose to contribute your changes and enhancements to the
 +# community by submitting them to Best Practical Solutions, LLC.)
 +#
 +# By intentionally submitting any modifications, corrections or
 +# derivatives to this work, or any other work intended for use with
 +# Request Tracker, to Best Practical Solutions, LLC, you confirm that
 +# you are the copyright holder for those contributions and you grant
 +# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
 +# royalty-free, perpetual, license to use, copy, create derivative
 +# works based on those contributions, and sublicense and distribute
 +# those contributions and any derivatives thereof.
 +#
 +# END BPS TAGGED BLOCK }}}
  
  use strict;
  use warnings;
diff --cc lib/RT/Tickets_SQL.pm
index 08c1ed8,608862a..8471c44
--- a/lib/RT/Tickets_SQL.pm
+++ b/lib/RT/Tickets_SQL.pm
@@@ -57,10 -57,7 +57,7 @@@ use RT::SQL
  # Import configuration data from the lexcial scope of __PACKAGE__ (or
  # at least where those two Subroutines are defined.)
  
- our (%FIELD_METADATA, %dispatch);
- 
- # Lower Case version of FIELDS, for case insensitivity
- my %lcfields = map { ( lc($_) => $_ ) } (keys %FIELD_METADATA);
 -our (%FIELD_METADATA, %LOWER_CASE_FIELDS, %dispatch, %can_bundle);
++our (%FIELD_METADATA, %LOWER_CASE_FIELDS, %dispatch);
  
  sub _InitSQL {
    my $self = shift;
diff --cc lib/RT/User.pm
index cf31492,938e5b6..af25dce
--- a/lib/RT/User.pm
+++ b/lib/RT/User.pm
@@@ -1747,6 -1624,6 +1747,21 @@@ sub SetPrivateKey 
      return ($status, $self->loc("Set private key"));
  }
  
++sub SetLang {
++    my $self = shift;
++    my ($lang) = @_;
++
++    unless ($self->CurrentUserCanModify('Lang')) {
++        return (0, $self->loc("Permission Denied"));
++    }
++
++    # Local hack to cause the result message to be in the _new_ language
++    # if we're updating ourselves
++    $self->CurrentUser->{LangHandle} = RT::I18N->get_handle( $lang )
++        if $self->CurrentUser->id == $self->id;
++    return $self->_Set( Field => 'Lang', Value => $lang );
++}
++
  sub BasicColumns {
      (
      [ Name => 'Username' ],
diff --cc share/html/Admin/Scrips/Create.html
index 8473c06,0000000..ac9317c
mode 100644,000000..100644
--- a/share/html/Admin/Scrips/Create.html
+++ b/share/html/Admin/Scrips/Create.html
@@@ -1,138 -1,0 +1,138 @@@
 +%# BEGIN BPS TAGGED BLOCK {{{
 +%#
 +%# COPYRIGHT:
 +%#
- %# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
++%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
 +%#                                          <sales at bestpractical.com>
 +%#
 +%# (Except where explicitly superseded by other copyright notices)
 +%#
 +%#
 +%# LICENSE:
 +%#
 +%# This work is made available to you under the terms of Version 2 of
 +%# the GNU General Public License. A copy of that license should have
 +%# been provided with this software, but in any event can be snarfed
 +%# from www.gnu.org.
 +%#
 +%# This work is distributed in the hope that it will be useful, but
 +%# WITHOUT ANY WARRANTY; without even the implied warranty of
 +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 +%# General Public License for more details.
 +%#
 +%# You should have received a copy of the GNU General Public License
 +%# along with this program; if not, write to the Free Software
 +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 +%# 02110-1301 or visit their web page on the internet at
 +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
 +%#
 +%#
 +%# CONTRIBUTION SUBMISSION POLICY:
 +%#
 +%# (The following paragraph is not intended to limit the rights granted
 +%# to you to modify and distribute this software under the terms of
 +%# the GNU General Public License and is only of importance to you if
 +%# you choose to contribute your changes and enhancements to the
 +%# community by submitting them to Best Practical Solutions, LLC.)
 +%#
 +%# By intentionally submitting any modifications, corrections or
 +%# derivatives to this work, or any other work intended for use with
 +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
 +%# you are the copyright holder for those contributions and you grant
 +%# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
 +%# royalty-free, perpetual, license to use, copy, create derivative
 +%# works based on those contributions, and sublicense and distribute
 +%# those contributions and any derivatives thereof.
 +%#
 +%# END BPS TAGGED BLOCK }}}
 +<& /Admin/Elements/Header, Title => $title &>
 +<& /Elements/Tabs &>
 +<& /Elements/ListActions, actions => \@results &>
 +
 +<form method="post" action="Create.html" id="CreateScrip" name="CreateScrip">
 +<input type="hidden" class="hidden" name="Queue" value="<% $Queue %>" />
 +
 +<&| /Widgets/TitleBox, title => loc('Basics') &>
 +<table>
 +
 +<& Elements/EditBasics, %ARGS, Scrip => $scrip, Queue => $queue_obj &>
 +
 +<tr><td class="label"><&|/l&>Stage</&>:</td><td class="value">\
 +<& /Admin/Elements/SelectStage, Default => $ARGS{"Stage"} &></td></tr>
 +
 +<tr><td class="label"> </td><td>
 +<input type="hidden" class="hidden" name="SetEnabled" value="1" />
 +<input type="checkbox" class="checkbox" name="Enabled" value="1" <% $ARGS{'Enabled'}? 'checked="checked"': '' |n%> />
 +<label for="Enabled"><&|/l&>Enabled (Unchecking this box disables this scrip)</&></label>
 +</td></tr>
 +
 +</table>
 +</&>
 +
 +<& /Elements/Submit,
 +    Label => loc('Create'),
 +    Name => 'Create',
 +&>
 +
 +% if ($session{CurrentUser}->HasRight(Object => $RT::System, Right => 'ExecuteCode')) {
 +<& Elements/EditCustomCode, %ARGS, Scrip => $scrip &>
 +<& /Elements/Submit,
 +    Label => loc('Create'),
 +    Name => 'Create',
 +&>
 +% }
 +
 +</form>
 +<%ARGS>
 +$Queue => 0
 +$Create => undef
 +</%ARGS>
 +<%INIT>
 +my @results;
 +
 +$ARGS{'Enabled'} = 1 unless $ARGS{'SetEnabled'};
 +
 +my $queue_obj;
 +if ( $Queue ) {
 +    $queue_obj = RT::Queue->new( $session{'CurrentUser'} );
 +    $queue_obj->Load( $Queue );
 +    Abort( loc("Couldn't load queue [_1]", $Queue) )
 +        unless $queue_obj->id;
 +}
 +
 +my $title;
 +if ( $queue_obj ) {
 +    $title = loc('Create a scrip and add to queue [_1]', $queue_obj->Name );
 +} else {
 +    $title = loc('Create a global scrip');
 +}
 +
 +my $scrip = RT::Scrip->new( $session{'CurrentUser'} );
 +if ( $Create ) {
 +    my ($status, $msg) = $scrip->Create(
 +        Description            => $ARGS{"Description"},
 +
 +        Queue                  => $Queue || 0,
 +        Stage                  => $ARGS{"Stage"},
 +        Disabled               => $ARGS{"Disabled"},
 +
 +        ScripAction            => $ARGS{"ScripAction"},
 +        ScripCondition         => $ARGS{"ScripCondition"},
 +        Template               => $ARGS{"Template"},
 +
 +        CustomPrepareCode      => $ARGS{"CustomPrepareCode"},
 +        CustomCommitCode       => $ARGS{"CustomCommitCode"},
 +        CustomIsApplicableCode => $ARGS{"CustomIsApplicableCode"},
 +    );
 +
 +    MaybeRedirectForResults(
 +        Force     => 1,
 +        Actions   => [ $msg ],
 +        Path      => 'Admin/Scrips/Modify.html',
 +        Arguments => { id => $scrip->id },
 +    ) if $status;
 +
 +    push @results, $msg;
 +}
 +
 +</%INIT>
diff --cc share/html/Admin/Scrips/Modify.html
index 27a9cd5,0000000..1e3a94d
mode 100644,000000..100644
--- a/share/html/Admin/Scrips/Modify.html
+++ b/share/html/Admin/Scrips/Modify.html
@@@ -1,136 -1,0 +1,136 @@@
 +%# BEGIN BPS TAGGED BLOCK {{{
 +%#
 +%# COPYRIGHT:
 +%#
- %# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
++%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
 +%#                                          <sales at bestpractical.com>
 +%#
 +%# (Except where explicitly superseded by other copyright notices)
 +%#
 +%#
 +%# LICENSE:
 +%#
 +%# This work is made available to you under the terms of Version 2 of
 +%# the GNU General Public License. A copy of that license should have
 +%# been provided with this software, but in any event can be snarfed
 +%# from www.gnu.org.
 +%#
 +%# This work is distributed in the hope that it will be useful, but
 +%# WITHOUT ANY WARRANTY; without even the implied warranty of
 +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 +%# General Public License for more details.
 +%#
 +%# You should have received a copy of the GNU General Public License
 +%# along with this program; if not, write to the Free Software
 +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 +%# 02110-1301 or visit their web page on the internet at
 +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
 +%#
 +%#
 +%# CONTRIBUTION SUBMISSION POLICY:
 +%#
 +%# (The following paragraph is not intended to limit the rights granted
 +%# to you to modify and distribute this software under the terms of
 +%# the GNU General Public License and is only of importance to you if
 +%# you choose to contribute your changes and enhancements to the
 +%# community by submitting them to Best Practical Solutions, LLC.)
 +%#
 +%# By intentionally submitting any modifications, corrections or
 +%# derivatives to this work, or any other work intended for use with
 +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
 +%# you are the copyright holder for those contributions and you grant
 +%# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
 +%# royalty-free, perpetual, license to use, copy, create derivative
 +%# works based on those contributions, and sublicense and distribute
 +%# those contributions and any derivatives thereof.
 +%#
 +%# END BPS TAGGED BLOCK }}}
 +<& /Admin/Elements/Header, Title => loc("Modify scrip #[_1]", $id) &>
 +<& /Elements/Tabs &>
 +<& /Elements/ListActions, actions => \@results &>
 +
 +<form method="post" action="Modify.html" id="ModifyScrip" name="ModifyScrip">
 +<input type="hidden" class="hidden" name="id" value="<% $id %>" />
 +
 +<&| /Widgets/TitleBox, title => loc('Basics') &>
 +<table>
 +
 +<& Elements/EditBasics, %ARGS, Scrip => $scrip &>
 +
 +% if ( not $disabled ) {
 +<tr><td class="label"><a href="Objects.html?id=<% $id %>"><&|/l&>Applies to</&></a>:</td>
 +<td class="value">\
 +% if ( $scrip->IsGlobal ) {
 +<a href="<% RT->Config->Get('WebPath') %>/Admin/Global/Scrips.html"><% loc('Global') %></a>
 +% } else {
 +% my $added_to = $scrip->AddedTo;
 +% my $found = 0;
 +% while ( my $queue = $added_to->Next ) {
 +% $m->out(', ') if $found++;
 +<a href="<% RT->Config->Get('WebPath') %>/Admin/Queues/Scrips.html?id=<% $queue->id %>">\
 +<% $queue->Name %></a>\
 +% last if $found == 10;
 +% }
 +% $m->out(', ...') if $found == 10;
 +% }
 +<td></tr>
 +% }
 +
 +<tr><td class="label"> </td><td>
 +<input type="hidden" class="hidden" name="SetEnabled" value="1" />
 +<input type="checkbox" class="checkbox" name="Enabled" value="1" <% $EnabledChecked |n%> />
 +<label for="Enabled"><&|/l&>Enabled (Unchecking this box disables this scrip)</&></label>
 +</td></tr>
 +
 +</table>
 +</&>
 +
 +<& /Elements/Submit, Label => loc('Save Changes'), Name => 'Update', Reset => 1 &>
 +
 +% if ($session{CurrentUser}->HasRight(Object => $RT::System, Right => 'ExecuteCode')) {
 +<& Elements/EditCustomCode, %ARGS, Scrip => $scrip &>
 +<& /Elements/Submit, Label => loc('Save Changes'), Name => 'Update', Reset => 1 &>
 +% }
 +
 +</form>
 +<%ARGS>
 +$id     => undef
 +$Update => undef
 +</%ARGS>
 +<%INIT>
 +my $scrip = RT::Scrip->new( $session{'CurrentUser'} );
 +$scrip->Load( $id );
 +Abort(loc("Couldn't load scrip #[_1]", $id))
 +    unless $scrip->id;
 +
 +my $disabled = $scrip->Disabled;
 +
 +if ( $Update ) {
 +    my @attribs = qw(
 +        Description
 +        ScripAction ScripCondition
 +        CustomPrepareCode CustomCommitCode CustomIsApplicableCode
 +    );
 +    push @attribs, "Template" if defined $ARGS{Template} and length $ARGS{Template};
 +    if ($ARGS{"SetEnabled"}) {
 +        push @attribs, "Disabled";
 +        $ARGS{"Disabled"} = not $ARGS{"Enabled"};
 +    }
 +    my @results = UpdateRecordObject(
 +        AttributesRef   => \@attribs,
 +        Object          => $scrip,
 +        ARGSRef         => \%ARGS
 +    );
 +    MaybeRedirectForResults(
 +        Actions   => \@results,
 +        Arguments => { id => $scrip->id },
 +    );
 +}
 +
 +my $EnabledChecked = qq[checked="checked"];
 +$EnabledChecked = '' if $disabled;
 +
 +my @results;
 +my ($ok, $msg) = $scrip->CompileCheck;
 +push @results, $msg if !$ok;
 +</%INIT>
diff --cc share/html/Elements/ShowHistory
index 3c48a97,610038d..7659b9e
--- a/share/html/Elements/ShowHistory
+++ b/share/html/Elements/ShowHistory
@@@ -43,11 -43,14 +43,11 @@@
  %# royalty-free, perpetual, license to use, copy, create derivative
  %# works based on those contributions, and sublicense and distribute
  %# those contributions and any derivatives thereof.
- %# 
+ %#
  %# END BPS TAGGED BLOCK }}}
 -<%doc>
 -#   This is (ab)used in Admin/(Users|Groups)/History.html and should probably
 -#   be generalized at some point.
 -</%doc>
 +<div class="history <% lc $record_type %>" id="<% $histid %>">
  <%perl>
 -if ($ShowDisplayModes or $ShowTitle) {
 +if ( $ShowDisplayModes or $ShowTitle ) {
      my $title = $ShowTitle
                      ? loc('History')
                      : ' ';
diff --cc share/html/Elements/ShowTransaction
index be953bf,0000000..7785356
mode 100644,000000..100644
--- a/share/html/Elements/ShowTransaction
+++ b/share/html/Elements/ShowTransaction
@@@ -1,267 -1,0 +1,267 @@@
 +%# BEGIN BPS TAGGED BLOCK {{{
- %# 
++%#
 +%# COPYRIGHT:
- %# 
- %# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC
- %#                                          <jesse at bestpractical.com>
- %# 
++%#
++%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
++%#                                          <sales at bestpractical.com>
++%#
 +%# (Except where explicitly superseded by other copyright notices)
- %# 
- %# 
++%#
++%#
 +%# LICENSE:
- %# 
++%#
 +%# This work is made available to you under the terms of Version 2 of
 +%# the GNU General Public License. A copy of that license should have
 +%# been provided with this software, but in any event can be snarfed
 +%# from www.gnu.org.
- %# 
++%#
 +%# This work is distributed in the hope that it will be useful, but
 +%# WITHOUT ANY WARRANTY; without even the implied warranty of
 +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 +%# General Public License for more details.
- %# 
++%#
 +%# You should have received a copy of the GNU General Public License
 +%# along with this program; if not, write to the Free Software
 +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 +%# 02110-1301 or visit their web page on the internet at
 +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
- %# 
- %# 
++%#
++%#
 +%# CONTRIBUTION SUBMISSION POLICY:
- %# 
++%#
 +%# (The following paragraph is not intended to limit the rights granted
 +%# to you to modify and distribute this software under the terms of
 +%# the GNU General Public License and is only of importance to you if
 +%# you choose to contribute your changes and enhancements to the
 +%# community by submitting them to Best Practical Solutions, LLC.)
- %# 
++%#
 +%# By intentionally submitting any modifications, corrections or
 +%# derivatives to this work, or any other work intended for use with
 +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
 +%# you are the copyright holder for those contributions and you grant
 +%# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
 +%# royalty-free, perpetual, license to use, copy, create derivative
 +%# works based on those contributions, and sublicense and distribute
 +%# those contributions and any derivatives thereof.
- %# 
++%#
 +%# END BPS TAGGED BLOCK }}}
 +<div class="<% join ' ', @classes %>">
 +  <div class="metadata">
 +    <span class="type">
 +      <a name="txn-<% $Transaction->id %>" \
 +% if ( $DisplayPath ) {
 +      href="<% $DisplayPath %>?id=<% $Object->id %>#txn-<% $Transaction->id %>" \
 +% }
 +      >#</a>
 +    </span>
 +% $m->callback( %ARGS, Transaction => $Transaction, CallbackName => 'AfterAnchor' );
 +    <span class="date"><% $date |n %></span>
 +    <span class="description">
 +      <& /Elements/ShowUser, User => $Transaction->CreatorObj &> - <% $desc |n %>
 +% $m->callback( %ARGS, Transaction => $Transaction, CallbackName => 'AfterDescription' );
 +    </span>
 +    <span class="time-taken"><% $time %></span>
 +% if ( $actions ) {
 +    <span class="actions"><% $actions |n %></span>
 +% }
 +  </div>
 +
 +  <div class="content">
 +<%PERL>
 +if ( $Transaction->CustomFieldValues->Count ) {
 +    $m->comp('/Elements/ShowCustomFields', Object => $Transaction );
 +}
 +$m->comp(
 +    'ShowTransactionAttachments',
 +    %ARGS,
 +    Parent => 0
 +) if $ShowBody;
 +</%PERL>
 +  </div>
 +% $m->callback( %ARGS, Transaction => $Transaction, CallbackName => 'AfterContent' );
 +</div>
 +
 +<%ARGS>
 +$Transaction
 +$Object => $Transaction->Object
 +
 +$Attachments => undef
 +$AttachmentContent => undef
 +
 +$ShowBody => 1
 +$ShowActions => 1
 +$RowNum => 1
 +
 +$DisplayPath => undef
 +$AttachmentPath => undef
 +$UpdatePath => undef
 +$ForwardPath => undef
 +$EncryptionPath => undef
 +$EmailRecordPath => undef
 +</%ARGS>
 +
 +<%ONCE>
 +
 +</%ONCE>
 +<%INIT>
 +my $record_type = $Object->RecordType;
 +my $type_class  = $Object->ClassifyTransaction( $Transaction );
 +
 +$m->callback(
 +    CallbackName => 'MassageTypeClass',
 +    Transaction  => $Transaction,
 +    TypeClassRef => \$type_class,
 +    ARGSRef      => \%ARGS,
 +);
 +
 +my @classes = (
 +    "transaction",
 +    "$record_type-transaction",
 +    $type_class,
 +    ($RowNum % 2 ? 'odd' : 'even')
 +);
 +
 +my $desc = $Transaction->BriefDescriptionAsHTML;
 +if ( $Object->id != $Transaction->ObjectId ) {
 +    # merged objects
 +    $desc = join " - ",
 +        $m->interp->apply_escapes(
 +            loc("[_1] #[_1]:", loc($record_type), $Transaction->ObjectId), 'h'),
 +        $desc;
 +}
 +
 +my $date = $Transaction->CreatedAsString;
 +
 +my $time = '';
 +$time = loc('[quant,_1,min,min]', $Transaction->TimeTaken)
 +    if $Transaction->TimeTaken;
 +
 +if ( $ShowBody && !$Attachments ) {
 +    $ARGS{'Attachments'} = $Attachments = {};
 +
 +    my $attachments = $Transaction->Attachments( WithHeaders => 1 );
 +    push @{ $Attachments->{ $_->Parent || 0 } ||= [] }, $_
 +        foreach @{ $attachments->ItemsArrayRef };
 +}
 +
 +my @actions = ();
 +if ( $ShowActions ) {
 +    my $txn_type = $Transaction->Type;
 +    if ( $txn_type =~ /EmailRecord$/ ) {
 +        push @actions, {
 +            title  => loc('Show'),
 +            target => '_blank',
 +            path   => $EmailRecordPath
 +                .'?id='. $Object->id
 +                .'&Transaction='. $Transaction->id
 +                .'&Attachment='. ( $Attachments->{0}[0] && $Attachments->{0}[0]->id ),
 +        } if $EmailRecordPath;
 +
 +        $ShowBody = 0;
 +    }
 +
 +    # If the transaction has anything attached to it at all
 +    elsif ( %$Attachments ) {
 +        my %has_right = map {
 +            $_ => RT::ACE->CanonicalizeRightName( $_ . $record_type )
 +        } qw(Modify CommentOn ReplyTo);
 +        $has_right{'Forward'} = RT::ACE->CanonicalizeRightName('ForwardMessage');
 +
 +        my $can_modify = $has_right{'Modify'}
 +            && $Object->CurrentUserHasRight( $has_right{'Modify'} );
 +
 +        if ( $UpdatePath && $has_right{'ReplyTo'}
 +            && ( $can_modify
 +                || $Object->CurrentUserHasRight( $has_right{'ReplyTo'} )
 +            )
 +        ) {
 +            push @actions, {
 +                class  => "reply-link",
 +                title  => loc('Reply'),
 +                path   => $UpdatePath
 +                    .'?id='. $Object->id
 +                    .'&QuoteTransaction='. $Transaction->id
 +                    .'&Action=Respond'
 +                ,
 +            };
 +        }
 +        if ( $UpdatePath && $has_right{'CommentOn'}
 +            && ( $can_modify
 +                || $Object->CurrentUserHasRight( $has_right{'CommentOn'} )
 +            )
 +        ) {
 +            push @actions, {
 +                class  => "comment-link",
 +                title  => loc('Comment'),
 +                path   => $UpdatePath
 +                    .'?id='. $Object->id
 +                    .'&QuoteTransaction='. $Transaction->id
 +                    .'&Action=Comment'
 +                ,
 +            };
 +        }
 +        if ( $ForwardPath && $has_right{'Forward'}
 +            && $Object->CurrentUserHasRight( $has_right{'Forward'} )
 +        ) {
 +            push @actions, {
 +                class  => "forward-link",
 +                title  => loc('Forward'),
 +                path   => $ForwardPath
 +                    .'?id='. $Object->id
 +                    .'&QuoteTransaction='. $Transaction->id
 +                ,
 +            };
 +        }
 +        if ( $EncryptionPath && $can_modify
 +            && RT->Config->Get('GnuPG')->{'Enable'}
 +            && RT->Config->Get('GnuPG')->{'AllowEncryptDataInDB'}
 +        ) {
 +            push @actions, {
 +                class  => "gpg-link",
 +                title  => loc('Encrypt/Decrypt'),
 +                path   => $EncryptionPath
 +                    .'?id='. $Transaction->id
 +                    .'&QuoteTransaction='. $Transaction->id
 +                ,
 +            };
 +        }
 +    }
 +}
 +
 +$m->callback(
 +    %ARGS,
 +    Transaction => $Transaction,
 +    Object      => $Object,
 +
 +    Classes     => \@classes,
 +    Actions     => \@actions,
 +    Created     => \$date,
 +    TimeTaken   => \$time,
 +    Description => \$desc,
 +);
 +
 +my $actions = '';
 +if ( @actions ) {
 +    my $i = $m->interp;
 +
 +    foreach my $a ( @actions ) {
 +        $a = '<a'
 +            .' href="'. $i->apply_escapes( $a->{'path'}, 'h' ) .'"'
 +            . ($a->{'target'}
 +                ? ' target="'. $i->apply_escapes( $a->{'target'}, 'h' ) .'"'
 +                : ''
 +            )
 +            . ($a->{'class'}
 +                ? ' class="'. $i->apply_escapes( $a->{'class'}, 'h' ) .'"'
 +                : ''
 +            )
 +            .'>'. $i->apply_escapes( $a->{'title'}, 'h' ) .'</a>'
 +        ;
 +    }
 +    $actions = join ' ', map "[$_]", @actions;
 +}
 +
 +# make date unbreakable
 +$date = $m->interp->apply_escapes( $date, 'h' );
 +$date =~ s/\s/ /g;
 +</%INIT>
diff --cc t/web/user_update.t
index e2fb9e7,f55c773..f6fc66b
--- a/t/web/user_update.t
+++ b/t/web/user_update.t
@@@ -7,23 -7,37 +7,35 @@@ my ( $url, $m ) = RT::Test->started_ok
  ok( $m->login(), 'logged in' );
  
  $m->follow_link_ok({text => 'About me'});
- $m->form_with_fields('Lang');
- $m->field(Lang => 'ja');
- $m->submit;
- 
+ $m->submit_form_ok({ with_fields => { Lang => 'ja'} },
+                "Change to Japanese");
 -$m->text_contains("Lang changed from (no value) to 'ja'");
 +$m->text_contains("Langは「(値なし)」から「'ja'」に変更されました");
+ $m->text_contains("実名", "Page content is japanese");
  
  # we only changed one field, and it wasn't the default, so this feedback is
  # spurious and annoying
  $m->content_lacks("That is already the current value");
  
  # change back to English
- $m->form_with_fields('Lang');
- $m->field(Lang => 'en_us');
- $m->submit;
+ $m->submit_form_ok({ with_fields => { Lang => 'en_us'} },
+                "Change back to english");
  
 -# This message shows up in Japanese
 -# $m->text_contains("Lang changed from 'ja' to 'en_us'");
 -$m->text_contains("Langは「'ja'」から「'en_us'」に変更されました");
 +$m->text_contains("Lang changed from 'ja' to 'en_us'");
+ $m->text_contains("Real Name", "Page content is english");
  
- # another spurious update
+ # Check for a lack of spurious updates
  $m->content_lacks("That is already the current value");
  
+ # Ensure that we can change the language back to the default.
+ $m->submit_form_ok({ with_fields => { Lang => 'ja'} },
+                    "Back briefly to Japanese");
 -$m->text_contains("Lang changed from 'en_us' to 'ja'");
++$m->text_contains("Langは「'en_us'」から「'ja'」に変更されました");
+ $m->text_contains("実名", "Page content is japanese");
+ $m->submit_form_ok({ with_fields => { Lang => ''} },
+                    "And set to the default");
 -$m->text_contains("Langは「'ja'」から「''」に変更されました");
++$m->text_contains("Lang changed from 'ja' to ''");
+ $m->text_contains("Real Name", "Page content is english");
+ 
+ undef $m;
+ 
+ done_testing;

-----------------------------------------------------------------------


More information about the Rt-commit mailing list