Browse Source

added log_filter contrib module

Bachir Soussi Chiadmi 5 years ago
parent
commit
ccd47590d5
100 changed files with 7690 additions and 0 deletions
  1. 211 0
      sites/all/modules/contrib/admin/log_filter/CHANGELOG.txt
  2. 18 0
      sites/all/modules/contrib/admin/log_filter/COPYRIGHT.txt
  3. 339 0
      sites/all/modules/contrib/admin/log_filter/LICENSE.txt
  4. 1989 0
      sites/all/modules/contrib/admin/log_filter/LogFilter.inc
  5. 12 0
      sites/all/modules/contrib/admin/log_filter/admin/log_filter.admin.css
  6. 108 0
      sites/all/modules/contrib/admin/log_filter/admin/log_filter.admin.inc
  7. BIN
      sites/all/modules/contrib/admin/log_filter/css/img/log-16-alert.png
  8. BIN
      sites/all/modules/contrib/admin/log_filter/css/img/log-16-critical.png
  9. BIN
      sites/all/modules/contrib/admin/log_filter/css/img/log-16-emergency.png
  10. BIN
      sites/all/modules/contrib/admin/log_filter/css/img/log-16-error.png
  11. BIN
      sites/all/modules/contrib/admin/log_filter/css/img/log-16-info.png
  12. BIN
      sites/all/modules/contrib/admin/log_filter/css/img/log-16-notice.png
  13. BIN
      sites/all/modules/contrib/admin/log_filter/css/img/log-16-warning.png
  14. BIN
      sites/all/modules/contrib/admin/log_filter/css/img/message-16-error.png
  15. BIN
      sites/all/modules/contrib/admin/log_filter/css/img/message-16-help.png
  16. BIN
      sites/all/modules/contrib/admin/log_filter/css/img/message-16-info.png
  17. BIN
      sites/all/modules/contrib/admin/log_filter/css/img/message-16-ok.png
  18. BIN
      sites/all/modules/contrib/admin/log_filter/css/img/message-16-warning.png
  19. 829 0
      sites/all/modules/contrib/admin/log_filter/css/log_filter.css
  20. 0 0
      sites/all/modules/contrib/admin/log_filter/css/log_filter.min.css
  21. 2 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery-ui-i18n.min.js
  22. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-af.min.js
  23. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-ar-DZ.min.js
  24. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-ar.min.js
  25. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-az.min.js
  26. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-bg.min.js
  27. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-bs.min.js
  28. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-ca.min.js
  29. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-cs.min.js
  30. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-cy-GB.min.js
  31. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-da.min.js
  32. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-de.min.js
  33. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-el.min.js
  34. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-en-AU.min.js
  35. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-en-GB.min.js
  36. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-en-NZ.min.js
  37. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-en.min.js
  38. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-eo.min.js
  39. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-es.min.js
  40. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-et.min.js
  41. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-eu.min.js
  42. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-fa.min.js
  43. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-fi.min.js
  44. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-fo.min.js
  45. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-fr-CH.min.js
  46. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-fr.min.js
  47. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-gl.min.js
  48. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-he.min.js
  49. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-hi.min.js
  50. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-hr.min.js
  51. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-hu.min.js
  52. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-hy.min.js
  53. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-id.min.js
  54. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-is.min.js
  55. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-it.min.js
  56. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-ja.min.js
  57. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-ka.min.js
  58. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-kk.min.js
  59. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-km.min.js
  60. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-ko.min.js
  61. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-lb.min.js
  62. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-lt.min.js
  63. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-lv.min.js
  64. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-mk.min.js
  65. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-ml.min.js
  66. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-ms.min.js
  67. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-nl-BE.min.js
  68. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-nl.min.js
  69. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-no.min.js
  70. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-pl.min.js
  71. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-pt-BR.min.js
  72. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-pt.min.js
  73. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-rm.min.js
  74. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-ro.min.js
  75. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-ru.min.js
  76. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-sk.min.js
  77. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-sl.min.js
  78. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-sq.min.js
  79. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-sr-SR.min.js
  80. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-sr.min.js
  81. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-sv.min.js
  82. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-ta.min.js
  83. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-th.min.js
  84. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-tj.min.js
  85. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-tr.min.js
  86. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-uk.min.js
  87. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-vi.min.js
  88. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-zh-CN.min.js
  89. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-zh-HK.min.js
  90. 4 0
      sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-zh-TW.min.js
  91. 2932 0
      sites/all/modules/contrib/admin/log_filter/js/log_filter.js
  92. 0 0
      sites/all/modules/contrib/admin/log_filter/js/log_filter.min.js
  93. 17 0
      sites/all/modules/contrib/admin/log_filter/log_filter.info
  94. 200 0
      sites/all/modules/contrib/admin/log_filter/log_filter.install
  95. 181 0
      sites/all/modules/contrib/admin/log_filter/log_filter.module
  96. 9 0
      sites/all/modules/contrib/admin/log_filter/release_notes/release_notes_7.x-1.0.txt
  97. 14 0
      sites/all/modules/contrib/admin/log_filter/release_notes/release_notes_7.x-y.z.txt
  98. 196 0
      sites/all/modules/contrib/judy/CHANGELOG.txt
  99. 18 0
      sites/all/modules/contrib/judy/COPYRIGHT.txt
  100. 339 0
      sites/all/modules/contrib/judy/LICENSE.txt

+ 211 - 0
sites/all/modules/contrib/admin/log_filter/CHANGELOG.txt

@@ -0,0 +1,211 @@
+log_filter 7.x-1.x, 2014-11-08
+------------------------------
+* Release 7.x-1.4.
+
+log_filter 7.x-1.x, 2014-11-07
+------------------------------
+* Don't display entries of type 'log_filter delete logs' unless, unless user actually want to see log deletions.
+* Fixed that 'log_filter delete logs' actually _were_ deletable, due to wrong removal of that filter deleting.
+
+log_filter 7.x-1.x, 2014-10-31
+------------------------------
+* Release 7.x-1.3.
+
+log_filter 7.x-1.x, 2014-07-14
+------------------------------
+* Use Drupal's JS API to attach behaviours.
+
+log_filter 7.x-1.2, 2014-04-27
+--------------------------------------------------
+* Released.
+
+log_filter 7.x-1.x, 2014-04-27
+------------------------------
+* Added styling of jQuery UI dialog close button, for later versions of jQuery UI (jquery_update module support).
+* Removed meaningless url = url JS expression.
+* Fixed that jQuery >=1.9 has no browser property (~ jquery_update module support).
+
+log_filter 7.x-1.x, 2014-04-24
+------------------------------
+* Fixed that sites using jQuery >v1.4.4 continually get 'form outdated' in the log viewer, due to AJAX http status 403 errors (issue 2073905).
+
+log_filter 7.x-1.x, 2013-09-01
+------------------------------
+* Increase log_filter's module weight to 10; the module's hook_menu() must be invoked _after_ dblog's ditto.
+* Do only add dblog's viewer as menu tab if that module is enabled.
+
+log_filter 7.x-1.1, 2013-07-21
+--------------------------------------------------
+* Released.
+
+log_filter 7.x-1.x, 2013-07-21
+------------------------------
+* Now uses Judy.ajaxcomplete instead of own custom ditto.
+* Fixed username autocomplete result ordering.
+
+log_filter 7.x-1.x, 2013-07-20
+------------------------------
+* Removed small viewport (<1136 px wide) css support.
+* Removed AJAX callback form_token check, because provides little additional security, and is no good for GET requests.
+* Implemented searching by user name.
+
+log_filter 7.x-1.0, 2013-07-04
+--------------------------------------------------
+* Released.
+
+log_filter 7.x-1.x, 2013-07-04
+------------------------------
+* Frontend now checks that the Judy library exists and has version 2.0+.
+
+log_filter 7.x-1.x, 2013-06-29
+------------------------------
+* Prevent deletion of events that log log deletion.
+* Fixed defaults of settings variables.
+* Moved filter delete button to prevent mix-up with delete logs button.
+* Added overlay when user goes from one filter to another.
+* Increased max allowed value of time_range to 9999 (from 1000).
+* Removed menu option; Log Filter now always takes over dblog's menu item, and adds dblog's view as a tab instead.
+* Install now inserts some default filters.
+
+log_filter 7.x-1.x, 2013-06-28
+------------------------------
+* Don't show filter by event message when validation fails.
+
+log_filter 7.x-1.x, 2013-06-27
+------------------------------
+* Time date is allowed to be the same for From as well as To, regardless of the time values.
+* Implemented set filter condition by event column feature.
+
+log_filter 7.x-1.x, 2013-06-25
+------------------------------
+* Added support for Inspect output folding/formatting.
+
+log_filter 7.x-1.x, 2013-06-24
+------------------------------
+* Made sure, for backend db queries, that there's a max when there's an offset.
+* Fixed deletion of zero events.
+* Fixed pager display for when current offset is out of range of total matched events.
+* Frontend translation error.
+* Made text in log list table selectable (preventing dialog pop after dragging mouse).
+* Made log deletion feed back messages fade.
+
+log_filter 7.x-1.x, 2013-06-23
+------------------------------
+* Log deletion offset and max now reflects equivalent of current log list.
+
+log_filter 7.x-1.x, 2013-06-22
+------------------------------
+* Implemented proxy type condition field, to prevent 'Illegal choice' errors for checklist due to dynamic options range.
+* Paging done.
+
+log_filter 7.x-1.x, 2013-06-20
+------------------------------
+* Use admin theme on log view pages (unless that setting is turned off).
+* Renamed module css default variable.
+* Now removes clear log form from standard dblog log view page.
+* Filter name from url now requires non-digit as first character, and at least 2 chars length.
+* Now allows for overwriting existing filter; implemented using non-AJAX request.
+* Fixed bug in type_some handler; failed to notice change in criteria if unchecking an option.
+* The update list buttons are no longer being disabled (no need for that anymore because the list is always AJAXed using current criteria).
+* Implemented single event view.
+
+log_filter 7.x-1.x, 2013-05-25
+------------------------------
+* Implemented log details view.
+
+log_filter 7.x-1.x, 2013-05-12
+------------------------------
+* Implemented log deletion.
+
+log_filter 7.x-1.x, 2013-05-01
+------------------------------
+* Get log list.
+
+log_filter 7.x-1.x, 2013-04-02
+------------------------------
+* Changing a criterion of a stored filter now triggers edit mode, not adhoc mode.
+
+log_filter 7.x-1.x, 2013-04-01
+------------------------------
+* _listFilters().
+
+log_filter 7.x-1.x, 2013-03-28
+------------------------------
+* Saving filters works.
+* Implemented standards compliant url GET parameter (filter name) regime.
+
+log_filter 7.x-1.x, 2013-03-28
+------------------------------
+* Working on saving (creating/updating) filter.
+
+log_filter 7.x-1.x, 2013-03-26
+------------------------------
+* Now uses singular development branch.
+* Implemented use of Judy.
+
+log_filter 7.x-1.0.x, 2013-03-26
+--------------------------------
+* Removed Inspect module dependency.
+
+log_filter 7.x-1.0.x, 2013-02-09
+--------------------------------
+* Frontend now strips tags off text fields.
+
+log_filter 7.x-1.0.x, 2013-02-05
+--------------------------------
+* Finished message box; .showAll() working, and fully documented.
+
+log_filter 7.x-1.0.x, 2013-02-03
+--------------------------------
+* Frontend now uses inspect.errorHandler().
+* Implemented message box.
+
+log_filter 7.x-1.0.x, 2013-02-02
+--------------------------------
+* Filter styling done.
+* Implemented time fields.
+
+log_filter 7.x-1.0.x, 2013-01-28
+--------------------------------
+* em-styling to get rid of nauseously complex javascript resizing.
+
+log_filter 7.x-1.0.x, 2013-01-27
+--------------------------------
+* Filter selector is no longer read-only during create/edit; user is allowed to change filter even in these modes (previous behaviour was too restrictive, instead let the user makes his mistakes and learn).
+* Changing filter to default no longer fires a page refresh.
+* Implemented 2 update list buttons.
+* Lots of visual tweaking.
+
+log_filter 7.x-1.0.x, 2013-01-27
+--------------------------------
+* Delete logs: don't prompt user for confirmation again if there's a limit, if already prompted for confirmation whilst there was no limit.
+* Create filter: names 'default' and 'adhoc' are illegal.
+* Worked on setting filter name as url parameter.
+
+log_filter 7.x-1.0.x, 2013-01-13
+--------------------------------
+* Added role condition.
+* Put validation on more condition fields.
+* Create filter done.
+* Apparantly fixed frontend mode bugs.
+* Added delete max. field.
+* Log deletion only allowed upon fresh log list update; the log list must reflect the filter.
+* Made the first steps toward log deletion - establishing current criteria and setting up confirm()s.
+
+log_filter 7.x-1.0.x, 2013-01-06
+--------------------------------
+* Removed create mode from viewer form, because that mode is handled solely via AJAX.
+* Frontend almost ready, except mode and name get wrong when alternating between create, edit, cancel etc.
+
+log_filter 7.x-1.0.x, 2013-01-05
+--------------------------------
+* Declared menu items now optionally hide default dblog viewer/remover page.
+* Frontend modes seem fully resolved.
+
+log_filter 7.x-1.0.x, 2013-01-04
+--------------------------------
+* Fronted now use elements directly for DOM and event modifications, instead of css selectors (the selectors only used initially for getting the elements).
+
+log_filter 7.x-1.0.x, 2012-12-16
+---------------------------
+* Project started.

+ 18 - 0
sites/all/modules/contrib/admin/log_filter/COPYRIGHT.txt

@@ -0,0 +1,18 @@
+
+All code of the Drupal module Log Filter (log_filter) is Copyright 2012-2014 Jacob Friis Mathiasen.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+This program 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 as the file LICENSE.txt; if not, please see
+http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+
+Drupal is a registered trademark of Dries Buytaert.

+ 339 - 0
sites/all/modules/contrib/admin/log_filter/LICENSE.txt

@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.

+ 1989 - 0
sites/all/modules/contrib/admin/log_filter/LogFilter.inc

@@ -0,0 +1,1989 @@
+<?php
+/**
+ * @file
+ *  Drupal Log Filter module
+ */
+
+class LogFilter {
+
+  /**
+   * Numeric index of filter name request argument, if any.
+   *
+   * @type integer
+   */
+  const FILTER_NAME_ARG = 4;
+
+  /**
+   * @type integer
+   */
+  const TYPE_SOME_MAX = 102400;
+
+  /**
+   * @type integer
+   */
+  const PAGE_RANGE_DEFAULT = 20;
+
+  /**
+   * @type integer
+   */
+  const PAGE_RANGE_MAX = 1000;
+
+  /**
+   * @type integer
+   */
+  const LIST_MESSAGE_TRUNCATE = 100;
+
+  /**
+   * Does databases (MySQL) support LIMIT for sub queries?
+   *
+   * @type boolean
+   */
+  const DB_SUBQUERY_LIMIT = FALSE;
+
+  /**
+   * @type array $_errorCodes
+   */
+  protected static $_errorCodes = array(
+    'unknown' => 1,
+    //  Programmatic errors and wrong use of program.
+    'algo' => 100,
+    'use' => 101,
+    //  Missing permission.
+    'perm_general' => 200,
+    'form_expired' => 201,
+    'perm_filter_crud' => 202,
+    'perm_filter_restricted' => 203,
+    //  Database.
+    'db_general' => 500,
+    //  Misc.
+    'filter_name_composition' => 1001,
+    'filter_name_nonunique' => 1002,
+    'filter_doesnt_exist' => 1003,
+    'bad_filter_condition' => 1010,
+  );
+
+  /**
+   * Traces and logs via Inspect tracer, or watchdog (no trace).
+   *
+   * @param Exception $xc
+   * @param integer $severity
+   *  - default: WATCHDOG_ERROR
+   * @return void
+   */
+  protected static function _errorHandler($xc, $severity = WATCHDOG_ERROR) {
+    if (module_exists('inspect')) {
+      inspect_trace($xc, array('category' => 'log_filter', 'severity' => $severity));
+    }
+    else {
+      watchdog(
+        'log_filter',
+        '(' . (int)$xc->getCode() . ') ' . check_plain($xc->getMessage()),
+        NULL,
+        $severity
+      );
+    }
+  }
+
+  /**
+   * @type array
+   */
+  protected static $_fields = array(
+    'settings' => array(
+      'only_own',
+      'delete_logs_max',
+      'translate',
+      'pager_range',
+    ),
+    'filter' => array(
+      'name', // Hidden.
+      'origin',
+      'name_suggest',
+      'description',
+      'require_admin',
+    ),
+    'conditions' => array(
+      'time_range',
+      'time_from',
+      'time_from_proxy', // Skip in actual conditions.
+      'time_to',
+      'time_to_proxy', // Skip in actual conditions.
+      'severity',
+      'type_wildcard', // Skip in actual conditions.
+      'type',
+      'role', // Default in database: -1.
+      'uid', // Default in database: -1.
+      'hostname',
+      'location',
+      'referer',
+    ),
+    'order_by' => array(
+      'orderby_',
+      'descending_',
+    ),
+  );
+
+  /**
+   * Defines log viewer form and GUI.
+   *
+   * @param array $form
+   * @param array &$form_state
+   * @return array
+   */
+  public static function viewerForm($form, &$form_state) {
+    $path = drupal_get_path('module', 'log_filter');
+    //  Get Judy.
+    drupal_add_library('judy', 'judy');
+    //  Get jQuery UI dialog.
+    drupal_add_library('system', 'ui.dialog');
+    //  Get jQuery UI datepicker.
+    drupal_add_library('system', 'ui.datepicker');
+    //  Get jQuery UI autocomplete for username.
+    drupal_add_library('system', 'ui.autocomplete');
+    //  Have to include own datepicker localisation, because it doesnt seem to exist in neither core nor the Date Popup module.
+    drupal_add_js(
+      $path . '/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-' . $GLOBALS['language']->language . '.min.js',
+      array('type' => 'file', 'group' => JS_DEFAULT, 'preprocess' => FALSE, 'every_page' => FALSE)
+    );
+
+    // Use the module's default css.
+    if (($use_module_css = variable_get('log_filter_cssdefault', TRUE))) {
+      drupal_add_css(
+        $path . '/css/log_filter' . '.min' . '.css',
+        array('type' => 'file', 'group' => CSS_DEFAULT, 'preprocess' => FALSE, 'every_page' => FALSE)
+      );
+    }
+    // Add table header script.
+    drupal_add_js('misc/tableheader.js');
+
+    drupal_add_js(
+      $path . '/js/log_filter' . '.min' . '.js',
+      array('type' => 'file', 'group' => JS_DEFAULT, 'preprocess' => FALSE, 'every_page' => FALSE)
+    );
+
+    try {
+      $allow_filter_edit = user_access('log_filter edit filters');
+
+      //  Get submitted vars from session, and remove them (for later form build and submission).
+      $formSubmitted = $session = $settings = $submitted = $messages = NULL;
+      if (module_exists('state')) {
+        if (($session = State::sessionGet('module', 'log_filter')) && array_key_exists('submitted', $session)) {
+          State::sessionRemove('module', 'log_filter', 'submitted');
+          State::sessionRemove('module', 'log_filter', 'messages');
+        }
+      }
+      else {
+        drupal_session_start();
+        if (!empty($_SESSION['module']) && !empty($_SESSION['module']['log_filter'])) {
+          $session = $_SESSION['module']['log_filter'];
+          unset($_SESSION['module']['log_filter']['submitted']);
+          unset($_SESSION['module']['log_filter']['messages']);
+        }
+      }
+      if ($session) {
+        if (array_key_exists('settings', $session)) {
+          $settings =& $session['settings'];
+        }
+        if (array_key_exists('submitted', $session)) {
+          $formSubmitted = TRUE;
+          $submitted =& $session['submitted'];
+        }
+        if (array_key_exists('messages', $session)) {
+          $messages =& $session['messages'];
+        }
+      }
+
+      //  Get current filter name from url, if any.
+      $filter_name = $submitted ? $submitted['filter']['name'] :
+        (($le = strlen($v = arg(self::FILTER_NAME_ARG))) // Deliberately not drupal_...().
+          && $le <= 32
+          && $v != 'log_filter' && $v != 'default' && $v != 'adhoc'
+          && preg_match('/^[a-z_][a-z\d_]+$/', $v) ? $v : '');
+
+      $require_admin = $submitted ? $submitted['filter']['require_admin'] : FALSE;
+      $user_admin_permission = user_access('log_filter administer');
+
+      //  Get mode: default | adhoc | stored (create|edit|delete_filter aren't allowed at form build).
+      $mode = $submitted ? $submitted['mode'] : ($filter_name ? 'stored' : 'default');
+
+      //  Stored mode may degrade to default.
+      if ($mode == 'stored') {
+        $success = TRUE;
+        if (!$filter_name) {
+          throw new Exception('Filter name[' . $filter_name . '] cannot be empty in mode[stored].');
+        }
+        if (!($stored_filter = self::_readFilter($filter_name))) {
+          $success = FALSE;
+          if (!$formSubmitted) { // Don't put these errors twice.
+            if ($stored_filter === FALSE) {
+              drupal_set_message(
+                t('The filter \'!name\' doesn\'t exist.', array('!name' => $filter_name)),
+                'warning'
+              );
+            }
+            else {
+              drupal_set_message(
+                t('You\'re not allowed to use the filter named \'!name\'.', array('!name' => $filter_name)),
+                'warning'
+              );
+            }
+          }
+          $mode = 'default';
+        }
+        if ($success) {
+          $filter = array(
+            'origin' => '',
+            'description' => $stored_filter['description'],
+            'require_admin' => $require_admin = $stored_filter['require_admin'],
+          );
+          $fields_conditions =& self::$_fields['conditions'];
+          $conditions = array();
+          foreach ($fields_conditions as $name) {
+            switch ($name) {
+              case 'time_range':
+              case 'time_from':
+              case 'time_to':
+              case 'role':
+                $conditions[$name] = ($v = $stored_filter[$name]) > 0 ? $v : '';
+              case 'uid':
+                $conditions[$name] = ($v = $stored_filter[$name]) > 0 || $v === '0' || $v === 0 ? $v : '';
+                break;
+              case 'severity':
+                if (!strlen($v = $stored_filter['severity'])) { // Deliberately not drupal_...().
+                  $v = array('-1');
+                }
+                else {
+                  $v = str_replace(',0,', ',zero,', ',' . $v . ',');
+                  $v = explode(',', substr($v, 1, strlen($v) - 1)); // Deliberately not drupal_...().
+                }
+                $conditions['severity'] = $v;
+                break;
+              case 'type_wildcard':
+                $conditions['type_wildcard'] = !$stored_filter['type'] ? TRUE : FALSE;
+                break;
+              case 'type':
+                $conditions['type'] = ($v = $stored_filter['type']) ? explode(',', $v) : array();
+                break;
+              case 'time_from_proxy':
+              case 'time_to_proxy':
+                //  Set by frontend, if non-empty time_from/time_to
+                $conditions[$name] = '';
+                break;
+              default:
+                $conditions[$name] = $stored_filter[$name];
+            }
+          }
+          unset($fields_conditions);
+          $order_by = array();
+          if (($v = $stored_filter['order_by'])) {
+            $le = count($arr = explode(',', $v));
+            for ($i = 0; $i < $le; $i++) {
+              $v = explode(':', $arr[$i]);
+              $order_by[] = array(
+                $v[0],
+                $v[1] == 'DESC' // ~ To boolean.
+              );
+            }
+          }
+          $title = $filter_name . (($v = $filter['description']) ? ('<span> - ' . $v . '</span>') : '');
+        }
+        else {
+          $mode = 'default';
+          $filter_name = 'default';
+        }
+        unset($stored_filter);
+      }
+      //  Do other modes.
+      switch ($mode) {
+        case 'default':
+          $filter = array(
+            'origin' => '',
+            'description' => '',
+            'require_admin' => FALSE,
+          );
+          $fields_conditions =& self::$_fields['conditions'];
+          $conditions = array();
+          foreach ($fields_conditions as $name) {
+            switch ($name) {
+              case 'severity':
+                $conditions[$name] = array('-1');
+                break;
+              case 'type_wildcard':
+                $conditions[$name] = TRUE;
+                break;
+              case 'type':
+                $conditions[$name] = array();
+                break;
+              default:
+                $conditions[$name] = '';
+            }
+          }
+          unset($fields_conditions);
+          $order_by = array(
+            array('time', TRUE),
+          );
+          $title = t('Default');
+          break;
+        case 'adhoc':
+          $filter =& $submitted['filter'];
+          $conditions =& $submitted['conditions'];
+          if (!$conditions['severity']) {
+            $conditions['severity'] = array('-1');
+          }
+          $order_by =& $submitted['order_by'];
+          $title = t('Ad hoc') . (($v = $filter['origin']) ? ('<span> - ' . t('based on !origin', array('!origin' => $v)) . '</span>') : '');
+          break;
+        case 'stored':
+          //  Done earlier.
+          break;
+        case 'create':
+        case 'edit':
+        case 'delete_filter':
+          throw new Exception('Mode[' . $mode . '] not allowed at form build.', self::$_errorCodes['algo']);
+          break;
+        default:
+          throw new Exception('Unsupported mode[' . $mode . '].', self::$_errorCodes['algo']);
+      }
+
+      //  Prepare some fields.
+      //  Type (frontend: type_some).
+      if (($options_type = db_select('watchdog')
+          ->fields('watchdog', array('type'))
+          ->distinct()
+          ->execute()->fetchCol())) {
+        sort($options_type);
+        foreach ($options_type as &$v) {
+          $v = str_replace(array("\r", "\n", ','), ' ', $v);
+        }
+        unset($v); // Clear reference.
+        $options_type = array_combine($options_type, $options_type);
+        //  The filter may contain types that do not exist currently.
+        $prepend_types = array();
+        if ($conditions['type']) {
+          foreach ($conditions['type'] as $v) {
+            if ($v) {
+              if (isset($options_type[$v])) {
+                unset($options_type[$v]);
+              }
+              $prepend_types[$v] = $v;
+            }
+          }
+          if ($prepend_types) {
+            $options_type = array_merge($prepend_types, $options_type);
+          }
+        }
+      }
+      elseif ($conditions['type']) {
+        $options_type = $conditions['type'];
+      }
+      else { // Make sure that there's always at least a single option.
+        $options_type = array('php' => 'php');
+      }
+      //  Severity.
+      $options_severity = array(
+        '-1' => t('Any'),
+        'zero' => t('emergency'),
+        '1' => t('alert'),
+        '2' => t('critical'),
+        '3' => t('error'),
+        '4' => t('warning'),
+        '5' => t('notice'),
+        '6' => t('info'),
+        '7' => t('debug'),
+      );
+      //  Role.
+      $options_role = user_roles();
+      foreach ($options_role as &$v) {
+        $v = t($v);
+      }
+      unset($v); // Clear reference.
+      $options_role = array('' => t('Any')) + $options_role; // Union operator (+) doesnt re-index numerical keys like array_merge() does.
+      //  Order by.
+      $options_order_by = array(
+        '' => '',
+        'time' => t('Time'),
+        'severity' => t('Severity'),
+        'type' => t('Type'),
+        'role' => t('User role'),
+        'uid' => t('User ID'),
+        'hostname' => t('Visitor\'s hostname'),
+        'location' => t('Location'),
+        'referer' => t('Referrer'),
+      );
+      $length_order_by = count($order_by);
+
+
+      //  Only own filters.
+      $value_only_own = $settings && array_key_exists('only_own', $settings) ? $settings['only_own'] : FALSE;
+
+      //  Filter selector.
+      $uid = $GLOBALS['user']->uid;
+      if ( ($options_filters = self::_listFilters(!$value_only_own ? NULL : array($uid), array('name'), array(array('name')), $uid) ) ) {
+        $js_filters = '["' . join('","', $options_filters) . '"]';
+        $options_filters = array_merge(
+          array('' => t('Default')),
+          array_combine($options_filters, $options_filters)
+        );
+      }
+      else {
+        $js_filters = '[]';
+        $options_filters = array('' => t('Default'));
+      }
+
+      //  Get current theme.
+      $theme = $GLOBALS['theme'];
+
+      //  Build form.
+      $form['#attributes'] = array('autocomplete' => 'off');
+      $form['log_filter_filter_edit'] = array(
+        '#type' => 'fieldset',
+        '#title' => t('Filter') . ': <span id="log_filter_title_display">' . $title . '</span>',
+        '#collapsible' => TRUE,
+        '#collapsed' => FALSE,
+        'frontend_init' => array(
+          '#type' => 'markup',
+          '#markup' => '<script type="text/javascript"> LogFilter.init(' . (int)$use_module_css . ', "' . $theme . '"); </script>',
+        ),
+        //  Control vars.
+        'log_filter_mode' => array(
+          '#type' => 'hidden',
+          '#default_value' => $mode,
+        ),
+        'log_filter_name' => array(
+          '#type' => 'hidden',
+          '#default_value' => $filter_name,
+        ),
+        'log_filter_origin' => array(
+          '#type' => 'hidden',
+          '#default_value' => $filter['origin'],
+        ),
+        //  Conditions.
+        //  Time.
+        'log_filter_time_range' => array( // (3 open)
+          '#type' => 'textfield',
+          '#title' => t('Preceding hours'),
+          '#default_value' => $conditions['time_range'] ? $conditions['time_range'] : '',
+          '#size' => 2,
+          '#prefix' => '<div id="log_filter_criteria"><div class="filter-conditions"><div class="form-item log-filter-time">'
+            . '<label>' . t('Time') . '</label>',
+        ),
+        'log_filter_time_from_proxy' => array(
+          '#type' => 'textfield',
+          '#title' => t('From') . '<span>?</span>',
+          '#default_value' => '', // Frontend sets it, if non-empty time_from.
+          '#size' => 10,
+          '#prefix' => '<div class="log-filter-time-or">' . t('or') . '</div>',
+        ),
+        'log_filter_time_from' => array(
+          '#type' => 'hidden',
+          '#default_value' => $conditions['time_from'],
+        ),
+        'log_filter_time_to_proxy' => array(
+          '#type' => 'textfield',
+          '#title' => t('To'),
+          '#default_value' => '', // Frontend sets it, if non-empty time_to.
+          '#size' => 10,
+        ),
+        'log_filter_time_to' => array( // End: log-filter-time (2 open).
+          '#type' => 'hidden',
+          '#default_value' => $conditions['time_to'],
+          '#suffix' => '</div>',
+        ),
+        //  Severity.
+        'log_filter_severity' => array(
+          '#type' => 'checkboxes',
+          '#title' => t('Severity'),
+          '#multiple' => TRUE,
+          '#options' => $options_severity,
+          '#default_value' => $conditions['severity'],
+        ),
+        //  Type.
+        'log_filter_type_wildcard' => array( // (3 open).
+          '#type' => 'checkbox',
+          '#title' => t('Any'),
+          '#default_value' => $conditions['type_wildcard'],
+          '#prefix' => '<div class="form-item log-filter-type">'
+            . '<label>' . t('Type') . '</label>',
+        ),
+        'log_filter_type_proxy' => array(
+          '#type' => 'checkboxes',
+          '#options' => $options_type,
+          '#default_value' => array(),
+          '#prefix' => '<div class="log-filter-type-container">',
+        ),
+        'log_filter_type' => array( // End: log-filter-type (2 open).
+          '#type' => 'textarea',
+          '#default_value' => join("\n", $conditions['type']),
+          '#resizable' => FALSE,
+          '#suffix' => '</div></div>',
+        ),
+        //  Various.
+        'log_filter_role' => array( // (4 open).
+          '#type' => 'select',
+          '#title' => t('User role'),
+          '#options' => $options_role,
+          '#default_value' => $conditions['role'],
+          '#prefix' => '<div class="form-item log-filter-various"><div class="log-filter-user">',
+        ),
+        'log_filter_uid' => array(
+          '#type' => 'textfield',
+          '#title' => t('ID'),
+          '#default_value' => $conditions['uid'],
+          '#size' => 11,
+        ),
+        'log_filter_username' => array( // End: log-filter-user (3 open).
+          '#type' => 'textfield',
+          '#title' => t('Name'),
+          '#default_value' => $conditions['uid'],
+          '#size' => 20,
+          // Can't use Drupal Form API autocomplete, because we need to pass value to the uid field upon selection.
+          '#attributes' => array(
+            'class' => array('form-autocomplete'),
+          ),
+          '#suffix' => '</div>',
+        ),
+        'log_filter_hostname' => array(
+          '#type' => 'textfield',
+          '#title' => t('Visitor\'s hostname') . '<span title="' . t('Use * to display in event list, without filtering') . '">?</span>',
+          '#default_value' => $conditions['hostname'],
+          '#size' => 64,
+        ),
+        'log_filter_location' => array(
+          '#type' => 'textfield',
+          '#title' => t('Location') . '<span title="' . t('Use * to display in event list, without filtering') . '">?</span>',
+          '#default_value' => $conditions['location'],
+          '#size' => 64,
+        ),
+        'log_filter_referer' => array( // End: filter-conditions, (1 open).
+          '#type' => 'textfield',
+          '#title' => t('Referrer') . '<span title="'
+            . t('Use \'none\' for empty referrer.!nlUse * to display in event list, without filtering.', array('!nl' => "\n"))
+            . '">?</span>',
+          '#default_value' => $conditions['referer'],
+          '#size' => 64,
+          '#suffix' => '</div></div>',
+        ),
+        //  Order by.
+        'log_filter_orderby_1' => array( // (2 open)
+          '#type' => 'select',
+          '#options' => $options_order_by,
+          '#default_value' => $length_order_by ? array($order_by[0][0]) : array(),
+          '#prefix' => '<div class="filter-orderby"><label>' . t('Order by') . '</label>',
+        ),
+        'log_filter_descending_1' => array(
+          '#type' => 'checkbox',
+          '#default_value' => $length_order_by ? $order_by[0][1] : FALSE,
+          '#attributes' => array(
+            'title' => t('Descending'),
+          ),
+        ),
+        'log_filter_orderby_2' => array(
+          '#type' => 'select',
+          '#options' => $options_order_by,
+          '#default_value' => $length_order_by > 1 ? array($order_by[1][0]) : array(),
+        ),
+        'log_filter_descending_2' => array(
+          '#type' => 'checkbox',
+          '#default_value' => $length_order_by > 1 ? $order_by[1][1] : FALSE,
+          '#attributes' => array(
+            'title' => t('Descending'),
+          ),
+        ),
+        'log_filter_orderby_3' => array(
+          '#type' => 'select',
+          '#options' => $options_order_by,
+          '#default_value' => $length_order_by > 2 ? array($order_by[2][0]) : array(),
+        ),
+        'log_filter_descending_3' => array(
+          '#type' => 'checkbox',
+          '#default_value' => $length_order_by > 2 ? $order_by[2][1] : FALSE,
+          '#attributes' => array(
+            'title' => t('Descending'),
+          ),
+        ),
+        'log_filter_reset' => array( // End: log-filter-reset, filter-orderby, log_filter_criteria (0 open).
+          '#type' => 'button',
+          '#name' => 'log_filter_reset',
+          '#value' => t('Reset'),
+          '#button_type' => 'button', // Doesnt work; still type:submit.
+          '#attributes' => array(
+            'type' => 'button', // Doesnt work; still type:submit.
+            'class' => array('form-submit', 'edit-reset'),
+          ),
+          '#prefix' => '<div class="log-filter-reset">',
+          '#suffix' => '</div></div></div>',
+        ),
+        //  Filters.
+        array(
+          '#type' => 'markup',
+          '#markup' => '<div id="log_filter_filters"><div id="log_filter_box_filter"><div id="log_filter_filters_cell_0">',
+        ),
+        'log_filter_filter' => array( // (2 open)
+          '#type' => 'select',
+          '#title' => t('Filter'),
+          '#options' => $options_filters,
+          '#default_value' => $filter_name,
+        ),
+        'log_filter_only_own' => array(
+          '#access' => $allow_filter_edit,
+          '#type' => 'checkbox',
+          '#title' => t('List my filters only'),
+          '#default_value' => $value_only_own,
+        ),
+        array(
+          '#type' => 'markup',
+          '#markup' => '</div>' // End: log_filter_filters_cell_0
+            . '<div id="log_filter_filters_cell_1">',
+        ),
+        'log_filter_name_suggest' => array(
+          '#access' => $allow_filter_edit,
+          '#type' => 'textfield',
+          '#title' => t('Name'),
+          '#default_value' => '', // Only used frontend.
+          '#size' => 32,
+          '#attributes' => array(
+            'maxlength' => 32,
+          ),
+        ),
+        'log_filter_require_admin' => array(
+          '#access' => $allow_filter_edit && $user_admin_permission,
+          '#type' => 'checkbox',
+          '#title' => t('Restrict access') . '<span title="' . ($title = t('Require the \'Administer log filtering\' permission.')) . '">?</span>',
+          '#default_value' => $require_admin,
+          '#attributes' => array(
+            'title' => $title,
+          ),
+        ),
+        array( // End: log_filter_filters_cell_1
+          '#type' => 'markup',
+          '#markup' => '</div>',
+        ),
+        'log_filter_description' => array(
+          '#access' => $allow_filter_edit,
+          '#type' => 'textarea',
+          '#title' => t('Description'),
+          '#default_value' => $filter['description'],
+          '#rows' => 3,
+          '#cols' => 32,
+          '#resizable' => FALSE, // Otherwise styling too complicated, and browsers support it natively.
+        ),
+        array( // (3 open)
+          '#type' => 'markup',
+          '#markup' => '<div class="log-filter-edit-create">',
+        ),
+        'log_filter_edit' => array(
+          '#access' => $allow_filter_edit,
+          '#type' => 'button',
+          '#name' => 'log_filter_edit',
+          '#value' => t('Edit'),
+          '#button_type' => 'button', // Doesnt work; still type:submit.
+          '#attributes' => array(
+            'type' => 'button', // Doesnt work; still type:submit.
+            'class' => array('form-submit'),
+            'style' => 'display:none;',
+          ),
+        ),
+        'log_filter_create' => array( // (2 open)
+          '#access' => $allow_filter_edit,
+          '#type' => 'button',
+          '#name' => 'log_filter_create',
+          '#value' => t('Save as...'),
+          '#button_type' => 'button', // Doesnt work; still type:submit.
+          '#attributes' => array(
+            'type' => 'button', // Doesnt work; still type:submit.
+            'class' => array('form-submit'),
+            'style' => 'display:none;',
+          ),
+        ),
+        array(
+          '#type' => 'markup',
+          '#markup' => '</div>' // End. log-filter-edit-create
+            . '<div class="log-filter-cancel-save'
+            . (strpos(strtolower(PHP_OS), 'win') === 0 ? ' log-filter-reversed-button-sequence' : '') // Deliberately not drupal_...().
+            . '">',
+        ),
+        'log_filter_cancel' => array( // (3 open)
+          '#access' => $allow_filter_edit,
+          '#type' => 'button',
+          '#name' => 'log_filter_cancel',
+          '#value' => t('Cancel'),
+          '#button_type' => 'button', // Doesnt work; still type:submit.
+          '#attributes' => array(
+            'type' => 'button', // Doesnt work; still type:submit.
+            'class' => array('form-submit', 'edit-cancel'),
+            'style' => 'display:none;',
+          ),
+        ),
+        'log_filter_save' => array(
+          '#access' => $allow_filter_edit,
+          '#type' => 'button',
+          '#name' => 'log_filter_save',
+          '#value' => t('Save'),
+          '#button_type' => 'button', // Doesnt work; still type:submit.
+          '#attributes' => array(
+            'type' => 'button', // Doesnt work; still type:submit.
+            'class' => array('form-submit'),
+            'style' => 'display:none;',
+          ),
+        ),
+        array(
+          '#type' => 'markup',
+          '#markup' => '</div>' // End: log-filter-cancel-save
+            . '<div class="log-filter-delete">',
+        ),
+        'log_filter_delete' => array(
+          '#access' => $allow_filter_edit,
+          '#type' => 'button',
+          '#name' => 'log_filter_delete',
+          '#value' => t('Delete filter'),
+          '#button_type' => 'button', // Doesnt work; still type:submit.
+          '#attributes' => array(
+            'type' => 'button', // Doesnt work; still type:submit.
+            'class' => array('form-submit', 'edit-delete'),
+            'style' => 'display:none;',
+          ),
+        ),
+        array(
+          '#type' => 'markup',
+          '#markup' => '</div>' // End: log-filter-delete
+            . '</div>', // End: log_filter_box_filter
+        ),
+        array(
+          '#access' => ($allow_delete_logs = user_access('log_filter remove logs')),
+          '#type' => 'markup',
+          '#markup' => '<div id="log_filter_box_delete_logs">',
+        ),
+        array(
+          '#access' => !$allow_delete_logs,
+          '#type' => 'markup',
+          '#markup' => '<div id="log_filter_box_delete_logs" class="log-filter-delete-logs-none">&nbsp;',
+        ),
+        array( // (2 open)
+          '#access' => $allow_delete_logs,
+          '#type' => 'button',
+          '#name' => 'log_filter_delete_logs_button',
+          '#value' => t('Delete logs'),
+          '#button_type' => 'button', // Doesnt work; still type:submit.
+          '#attributes' => array(
+            'type' => 'button', // Doesnt work; still type:submit.
+            'class' => array('form-submit', 'edit-delete'),
+            'style' => 'display:none;',
+          ),
+        ),
+        array(
+          '#access' => $allow_delete_logs,
+          '#type' => 'textfield',
+          '#name' => 'log_filter_delete_logs_max',
+          '#title' => t('Max.'),
+          '#default_value' =>  $settings && array_key_exists('delete_logs_max', $settings) ? $settings['delete_logs_max'] : '',
+          '#attributes' => array(
+            'maxlength' => 11,
+          ),
+        ),
+        array(
+          '#type' => 'markup',
+          '#markup' => '</div>' // End: log_filter_box_delete_logs
+            . '</div>', // End: log_filter_filters
+        ),
+      );
+
+      $form['log_filter_list_controls'] = array(
+        'frontend_setup' => array(
+          '#type' => 'markup',
+          '#markup' => '<script type="text/javascript">
+(function($) {
+  if(!$) {
+    return;
+  }
+  $(document).bind("ready", function() {
+    var elm;
+    // t() ruins this, because of some hocus pocus.
+    $("div.form-item-log-filter-time-from-proxy label").get(0).setAttribute("title", "'
+      . t('Date format: YYYY-MM-DD!newlineTime formats: N, NN, NNNN, NNNNNN, NN:NN, NN:NN:NN') . '".replace(/\!newline/, "\n"));
+    // Go.
+    LogFilter.setup(
+      ' . $js_filters . ',
+      ' . ($messages ? json_encode($messages) : 'null') . '
+    );
+  } );
+})(jQuery);
+</script>
+',
+        ),
+        'log_filter_update_list' => array(
+          '#type' => 'button',
+          '#name' => 'log_filter_update_list',
+          '#value' => t('Update list'),
+          '#button_type' => 'button', // Doesnt work; still type:submit.
+          '#attributes' => array(
+            'class' => array('form-submit'),
+            'title' => t('[CTR + U / CMD + U]'),
+          ),
+          '#prefix' => '<div class="log-filter-button log-filter-update-list">',
+          '#suffix' => '</div>',
+        ),
+        'log_filter_pager_controls' => array(
+          '#type' => 'markup',
+          '#markup' => '<div class="log-filter-pager-controls">'
+            . '<div id="log_filter_pager_first" class="log-filter-pager-button log-filter-pager-button-disabled" title="'
+              . t('First') . '">&#x25c4;&#x25c4;</div>'
+            . '<div id="log_filter_pager_previous" class="log-filter-pager-button log-filter-pager-button-disabled" title="'
+              . t('Previous') . '">&#x25c4;</div>'
+            . '<div id="log_filter_pager_current" title="' . t('Update list') . '">&nbsp;</div>'
+            . '<div id="log_filter_pager_progress" class="ajax-progress"><div class="throbber"></div>' . t('Loading...') . '</div>'
+            . '<div id="log_filter_pager_next" class="log-filter-pager-button log-filter-pager-button-disabled" title="'
+              . t('Next') . '">&#x25ba;</div>'
+            . '<div id="log_filter_pager_last" class="log-filter-pager-button log-filter-pager-button-disabled" title="'
+              . t('Last') . '">&#x25ba;&#x25ba;</div>'
+            . '</div>',
+        ),
+        'log_filter_pager_range' => array(
+          '#type' => 'textfield',
+          '#title' => t('Logs per page'),
+          '#default_value' => $settings && array_key_exists('pager_range', $settings) && $settings['pager_range'] > 0 ?
+            $settings['pager_range'] : variable_get('log_filter_pgrng', self::PAGE_RANGE_DEFAULT),
+          '#size' => 4,
+        ),
+        'log_filter_translate' => array(
+          '#type' => 'checkbox',
+          '#title' => t('Translate messages') . '<span title="' . ($title = t('Translating messages is heavy performance-wise.')) . '">?</span>',
+          '#default_value' => $settings && array_key_exists('translate', $settings) ? $settings['translate'] : variable_get('log_filter_trnslt', 0),
+          '#attributes' => array(
+            'title' => $title,
+          ),
+        ),
+        'actions' => array(
+          '#type' => 'actions',
+          'submit' => array(
+            '#type' => 'submit',
+            '#value' => t('Update list'),
+            '#attributes' => array('style' => 'display:none;'),
+          ),
+        ),
+        '#prefix' => '<div id="log_filter_list_controls">',
+        '#suffix' => '</div>',
+      );
+
+      $logList = '';
+      for ($i = 97; $i < 97 + 26; $i++) {
+        //$logList .= '<div class="' . str_repeat(chr($i), 3) . '">' . str_repeat(chr($i), 3) . '</div>';
+      }
+
+
+      $form['log_filter_log_list'] = array(
+        '#type' => 'markup',
+        '#markup' => '<div id="log_filter_log_list" class="scrollable">' . $logList . '</div>',
+      );
+
+      //  Add our submit form;
+      $form['#submit'][] = '_log_filter_form_submit';
+      return $form;
+    }
+    catch (Exception $xc) {
+      self::_errorHandler($xc);
+      drupal_set_message($xc->getMessage(), 'error');
+      return array();
+    }
+  }
+
+  /**
+   * Called when log viewer form submits.
+   *
+   * @param array $form
+   * @param array &$form_state
+   * @return void
+   */
+  public static function viewerFormSubmit($form, &$form_state) {
+    try {
+      $values =& $form_state['values'];
+      $prefix = 'log_filter_';
+
+      $messages = array();
+
+      $settings = array(
+        'only_own' => !array_key_exists($prefix . 'only_own', $values) ? FALSE : $values[$prefix . 'only_own'],
+        'delete_logs_max' => !array_key_exists($prefix . 'delete_logs_max', $values) ? '' : $values[$prefix . 'delete_logs_max'],
+        'translate' => $values[$prefix . 'translate'],
+        'only_own' => !array_key_exists($prefix . 'only_own', $values) ? FALSE : $values[$prefix . 'only_own'],
+        'pager_range' => ($v = (int)$values[$prefix . 'pager_range']) > -1 ? ($v > self::PAGE_RANGE_MAX ? self::PAGE_RANGE_MAX : $v) :
+          variable_get('log_filter_pgrng', self::PAGE_RANGE_DEFAULT),
+      );
+
+      $submitted = array(
+        'mode' => $values[$prefix . 'mode'],
+        'filter' => array(
+          'name' => '',
+          'origin' => '',
+          'name_suggest' => '',
+          'description' => '',
+          'require_admin' => !array_key_exists($prefix . 'require_admin', $values) ? FALSE : $values[$prefix . 'require_admin'],
+        ),
+      );
+
+      $use_form_values = $save = FALSE;
+      switch (($mode = $submitted['mode'])) {
+        case 'default':
+          //  Use default values.
+          break;
+        case 'adhoc':
+          //  Get specs from form.
+          $use_form_values = TRUE;
+          $submitted['filter']['origin'] = $values[$prefix . 'origin']; // ~ Hidden field.
+          break;
+        case 'stored': // Saved filter.
+          //  Just get filter name; in stored mode we do absolutely nothing at submission but establishing the filter's name.
+          //  Whether the filter require_admin and user has that permission will be checked at form build - no reason to check twice.
+          if (!($submitted['filter']['name'] = $filter_name = $values[$prefix . 'name'])) {
+            throw new Exception('Mode[' . $mode . '], empty name[' . $filter_name . '].', self::$_errorCodes['filter_name_composition']);
+          }
+          break;
+        case 'create': // Always AJAX-handled.
+          throw new Exception('Mode[' . $mode . '] not allowed at form submission.', self::$_errorCodes['algo']);
+          break;
+        case 'edit':
+        case 'delete_filter':
+          //  Get name.
+          if (!($submitted['filter']['name'] = $filter_name = $values[$prefix . 'name'])) {
+            throw new Exception('Mode[' . $mode . '], empty name[' . $filter_name . '].', self::$_errorCodes['filter_name_composition']);
+          }
+          $success = TRUE;
+          //  Check CRUD permission.
+          if (!user_access('log_filter edit filters')) {
+            $success = FALSE;
+            //  Horrible; have to make almost exactly same message, because of shortcomings of the localization regime.
+            switch ($mode) {
+              case 'edit':
+                watchdog(
+                  'log_filter',
+                  'Won\'t edit the filter \'!name\' because user !user doesn\'t have \'log_filter edit filters\' permission.',
+                  array('!name' => $filter_name, '!user' => $GLOBALS['user']->name),
+                  WATCHDOG_WARNING
+                );
+                drupal_set_message(
+                  t('Cannot edit the filter \'!name\', because you don\'t have permission to edit log filters.', array('!name' => $filter_name)),
+                  'warning'
+                );
+                break;
+              default: // delete
+                watchdog(
+                  'log_filter',
+                  'Won\'t delete the filter \'!name\' because user !user doesn\'t have \'log_filter edit filters\' permission.',
+                  array('!name' => $filter_name, '!user' => $GLOBALS['user']->name),
+                  WATCHDOG_WARNING
+                );
+                drupal_set_message(
+                  t('Cannot delete the filter \'!name\', because you don\'t have permission to edit log filters.', array('!name' => $filter_name)),
+                  'warning'
+                );
+            }
+          }
+          //  Check if exists, and get require_admin field.
+          elseif (!($require_admin = db_select('log_filter')
+            ->fields('log_filter', array('require_admin'))
+            ->condition('name', $filter_name, '=')
+            ->execute()->fetchField())
+          ) {
+            if ($require_admin === FALSE) { // Doesn't exist.
+              $success = FALSE;
+              /* drupal_set_message(
+                  t('The filter \'!name\' doesn\'t exist.', array('!name' => $filter_name)),
+                  'warning'
+              ); */
+              $messages[] = array(
+                  t('The filter \'!name\' doesn\'t exist.', array('!name' => $filter_name)),
+                  'warning'
+              );
+            }
+            //  else... the filter doesnt require admin permission.
+          }
+          elseif (!user_access('log_filter administer')) {
+            $success = FALSE;
+          }
+          if ($success) {
+            switch ($mode) {
+              case 'edit':
+                //  Get specs from form, and save to database.
+                $use_form_values = TRUE;
+                $save = TRUE;
+                $submitted['filter']['description'] = $values[$prefix . 'description'];
+                //  Change mode.
+                $submitted['mode'] = $mode = 'stored';
+                break;
+              default: // delete
+                global $user;
+                db_delete('log_filter')->condition('name', $filter_name, '=')->execute();
+                watchdog(
+                  'log_filter',
+                  'User (%uid) %name deleted the log filter \'!filter\'.',
+                  array('%uid' => $user->uid, '%name' => $user->name, '!filter' => $filter_name),
+                  WATCHDOG_INFO
+                );
+                $messages[] = array(
+                    t('Deleted the filter \'!name\'.', array('!name' => $filter_name))
+                );
+                //  Change mode.
+                $submitted['mode'] = $mode = 'default';
+            }
+          }
+          else {
+            $use_form_values = $save = FALSE;
+            //  Change mode.
+            $submitted['mode'] = $mode = 'default';
+          }
+          break;
+        default:
+          throw new Exception('Unsupported mode[' . $mode . '].', self::$_errorCodes['algo']);
+      }
+
+      //  Load values from form.
+      if ($use_form_values) {
+        $fields_conditions =& self::$_fields['conditions'];
+        $conditions = array();
+        foreach ($fields_conditions as $name) {
+          switch ($name) {
+            case 'time_range':
+              $conditions[$name] = ($v = trim($values[$prefix . $name])) ? $v : '';
+              break;
+            case 'role':
+              $conditions[$name] = ($v = trim($values[$prefix . $name])) > 0 ? $v : -1;
+              break;
+            case 'uid': // Accepts zero.
+              $conditions[$name] = ($v = trim($values[$prefix . $name])) > 0 || $v === '0' || $v === 0 ? $v : -1;
+              break;
+            case 'time_from':
+              $conditions[$name] = $conditions['time_range'] ? '' : (($v = trim($values[$prefix . $name])) ? $v : '');
+              break;
+            case 'time_from_proxy':
+              if (!$save) { // Because save doesnt use the proxy field.
+                $conditions[$name] = !$conditions['time_from'] ? '' : $values[$prefix . $name];
+              }
+              break;
+            case 'time_to':
+              $conditions[$name] = $conditions['time_range'] ? '' : (($v = trim($values[$prefix . $name])) ? $v : '');
+              break;
+            case 'time_to_proxy':
+              if (!$save) { // Because save doesnt use the proxy field.y
+                $conditions[$name] = !$conditions['time_to'] ? '' : $values[$prefix . $name];
+              }
+              break;
+            case 'severity':
+              $arr = $values[$prefix . $name];
+              $vals = array();
+              foreach ($arr as $k => $v) {
+                if ($v) {
+                  if ('' . $k == '-1') {
+                    $vals = array();
+                    break;
+                  }
+                  else {
+                    $vals[] = $k;
+                  }
+                }
+              }
+              $conditions[$name] = $vals;
+              break;
+            case 'type_wildcard':
+              $conditions[$name] = $values[$prefix . $name] ? TRUE : FALSE;
+              break;
+            case 'type':
+              //  Dont remember type list (may be very long), if wildcard on.
+              $conditions[$name] = $conditions['type_wildcard'] ? array() :
+                array_combine($a = explode("\n", str_replace("\r", '', $values[$prefix . $name])), $a);
+              if ($save) {
+                unset($conditions['type_wildcard']);
+              }
+              break;
+            default:
+              $conditions[$name] = trim($values[$prefix . $name]);
+          }
+        }
+        unset($fields_conditions);
+        $submitted['conditions'] =& $conditions;
+
+        $fields_order_by =& self::$_fields['order_by'];
+        $order_by = array();
+        for ($i = 1; $i < 10; $i++) {
+          if (array_key_exists($key = $prefix . $fields_order_by[0] . $i, $values)) {
+            if (($key = $values[ $key ])) {
+              if (!$save) {
+                $order_by[] = array($key, $values[ $prefix . $fields_order_by[1] . $i ]);
+              }
+              else {
+                $order_by[] = array($key, $values[ $prefix . $fields_order_by[1] . $i ] ? 'DESC' : 'ASC');
+              }
+            }
+          }
+          else {
+            break;
+          }
+        }
+        $submitted['order_by'] =& $order_by;
+        unset($order_by, $fields_order_by);
+      }
+      if ($save) { // edit mode.
+        $success = TRUE;
+        try {
+          self::_saveFilter($filter_name, $submitted);
+        }
+        catch (Exception $xc) {
+          self::_errorHandler($xc);
+          $success = FALSE;
+          $messages[] = array(
+            t('Failed to update filter \'!name\'.', array('!name' => $filter_name)),
+            'warning'
+          );
+        }
+        //  Change mode.
+        if ($success) {
+          $submitted['mode'] = $mode = 'stored';
+        }
+        else {
+          $submitted['mode'] = $mode = 'default';
+        }
+      }
+
+      //  Clear conditions and order_by from vars to be passed to session, unless adhoc filter.
+      if ($mode != 'adhoc') {
+        unset( $submitted['conditions'], $submitted['order_by'] );
+      }
+
+      //  Pass to session.
+      $session = array('settings' => $settings, 'submitted' => $submitted);
+      if ($messages) {
+        $session['messages'] = $messages;
+      }
+      if (module_exists('state')) {
+        State::sessionSet('module', 'log_filter', $session);
+      }
+      else {
+        drupal_session_start();
+        if (!isset($_SESSION['module'])) {
+          $_SESSION['module'] = array(
+            'log_filter' => $session,
+          );
+        }
+        else {
+          $_SESSION['module']['log_filter'] = $session;
+        }
+      }
+    }
+    catch (Exception $xc) {
+      self::_errorHandler($xc);
+      drupal_set_message($xc->getMessage(), 'error');
+    }
+  }
+
+  /**
+   * Filters off restricted filters if current user isnt allowed to administer filters.
+   *
+   * @throws PDOException
+   * @param integer|string|array|NULL $creatorIds
+   *  - default: NULL (~ any user)
+   *  - integer|string: list only filters created by that user
+   *  - array: list only filters created by those users
+   * @param array|NULL $fields
+   *  - default: all fields
+   * @param arrayNULL $orderBy
+   *  - default: unordered
+   *  - array: multi-dimensional; every bucket being an array listing field name and 'ASC'|'DESC'
+   * @param integer|string|NULL $latestAtTop
+   *  - default: not
+   *  - user id: place lastest changed of that user at the very top of the list (requires that $fields is falsy or has 'name' bucket)
+   * @return array
+   */
+  protected static function _listFilters($creatorIds = NULL, $fields = NULL, $orderBy = NULL, $latestAtTop = NULL) {
+    $uid = $GLOBALS['user']->uid;
+
+    if ( ($creatorIds && !is_array($creatorIds)) || (!$creatorIds && $creatorIds !== NULL)) {
+      $creatorIds = array($creatorIds);
+    }
+
+    $list = db_select('log_filter')
+      ->fields('log_filter', $fields ? $fields : array('*'));
+
+    if ($creatorIds) {
+      $list->condition('creator', $creatorIds, 'IN');
+    }
+    if (!user_access('log_filter administer')) {
+      $list->condition('require_admin', 0);
+    }
+    if ($orderBy) {
+      foreach ($orderBy as $subArr) {
+        $list->orderBy($subArr[0], !empty($subArr[1]) ? $subArr[1] : 'ASC');
+      }
+    }
+    $list = ($singleColumned = ($fields && count($fields) == 1)) ? $list->execute()->fetchCol() : $list->execute()->fetchAll();
+
+    if ($list && $latestAtTop !== NULL
+      && (!$creatorIds || in_array($latestAtTop, $creatorIds))
+      && (!$fields || in_array('name', $fields))
+    ) {
+      if (($listLatest = db_select('log_filter')
+        ->fields('log_filter', array('name', 'changed'))
+        ->condition('editor', $latestAtTop, '=')
+        ->execute()
+        ->fetchAll()
+      )) {
+        $latestChange = $latestName = 0;
+        foreach ($listLatest as $subObj) {
+          if ($subObj->changed > $latestChange) {
+            $latestChange = $subObj->changed;
+            $latestName = $subObj->name;
+          }
+        }
+        if ($latestName) {
+          if ($singleColumned) {
+            if (($index = array_search($latestName, $list))) { // No need to check !== FALSE, because if zero there's nothing to be done.
+              array_splice($list, $index, 1);
+              array_unshift($list, $latestName);
+            }
+          }
+          else {
+            $index = 0;
+            foreach ($list as $k => $subObj) {
+              if ($subObj->name == $latestName) {
+                $index = $k;
+                break;
+              }
+            }
+            if ($index) {
+              $latest = array_splice($list, $index, 1);
+              array_unshift($list, $latest);
+            }
+          }
+        }
+      }
+    }
+    return $list;
+  }
+
+  /**
+   * Checks if the filter requires log_filter administrative permission and whether the user has that permission.
+   *
+   * @throws PDOException
+   * @param string $name
+   * @return array|boolean|NULL
+   *  - FALSE: the filter doesnt exist
+   *  - NULL: user not allowed to use that filter
+   */
+  protected static function _readFilter($name) {
+    return !(
+      $filter = db_select('log_filter')
+      ->fields('log_filter')
+      ->condition('name', $name, '=')
+      ->execute()->fetchAssoc()
+    ) ? FALSE : $filter['require_admin'] && !user_access('log_filter administer') ? NULL : $filter;
+  }
+
+  /**
+   * Insert/update filter in database.
+   *
+   * @throws Exception
+   * @param string $name
+   * @param array $values
+   * @param boolean $create
+   *  - default: FALSE
+   * @return void
+   *  - throws error on failure
+   */
+  protected static function _saveFilter($name, $values, $create = FALSE) {
+    $uid = $GLOBALS['user']->uid;
+
+    if (!user_access('log_filter edit filters')) {
+      throw new Exception(
+        'You\'re not allowed to edit filters.',
+        self::$_errorCodes['perm_filter_crud']
+      );
+    }
+
+    //  Filter metadata and last updated by.
+    $fields = array(
+      'editor' => $uid,
+      'changed' => REQUEST_TIME,
+      'require_admin' => !empty($values['filter']['require_admin']) ? 1 : 0,
+      'description' => $values['filter']['description'],
+    );
+    if ($create) {
+      $fields['creator'] = $uid;
+      $fields['created'] = REQUEST_TIME;
+    }
+
+    //  Conditions.
+    $names =& self::$_fields['conditions'];
+    $conditions =& $values['conditions'];
+    foreach ($names as $key) {
+      switch ($key) {
+        case 'severity':
+          if (!empty($conditions[$key])) {
+            if (!is_array($v = $conditions[$key])) {
+              throw new Exception('Non-empty condition[' . $key . '], type[' . gettype($v) . '], must be array.',
+                self::$_errorCodes['bad_filter_condition']);
+            }
+            //  Use array values, but convert 'zero' to zero.
+            //  And make sure it's all integers.
+            $fields[$key] = preg_replace('/[^\d,]/', '', str_replace('zero', '0', join(',', $v)));
+          }
+          else {
+            $fields[$key] = '';
+          }
+          break;
+        case 'type':
+          if (!empty($conditions[$key])) {
+            if (!is_array($v = $conditions[$key])) {
+              throw new Exception('Non-empty condition[' . $key . '], type[' . gettype($v) . '], must be array.',
+                self::$_errorCodes['bad_filter_condition']);
+            }
+            //  Use array values, because key is simply numeric index.
+            $fields[$key] = check_plain(join(',', $v));
+          }
+          else {
+            $fields[$key] = '';
+          }
+          break;
+        case 'time_range':
+          $fields[$key] = !empty($conditions[$key]) && ($v = (int)$conditions[$key]) > 0 && $v < 10000 ? $v : 0;
+          break;
+        case 'time_from':
+        case 'time_to':
+          $fields[$key] = !empty($conditions[$key]) && ($v = (int)$conditions[$key]) > 0 && $v <= PHP_INT_MAX ? $v : 0;
+          break;
+        case 'role':
+        case 'uid':
+          $fields[$key] = array_key_exists($key, $conditions) ? (int)$conditions[$key] : -1;
+          break;
+        case 'hostname':
+        case 'location':
+        case 'referer':
+          $fields[$key] = !empty($conditions[$key]) ? check_plain($conditions[$key]) : '';
+          break;
+        default:
+          //  Ignore.
+      }
+    }
+
+    //  Order by.
+    $order_by = '';
+    if (!empty($values['order_by'])) {
+      $order_by = array();
+      foreach ($values['order_by'] as $k => $v) {
+        if (preg_match('/^[a-z\d_]{2,32}$/', $k) && ($v === 'DESC' || $v === 'ASC')) {
+          $order_by[] = $k . ':' . $v;
+        }
+      }
+      $fields['order_by'] = join(',', $order_by);
+    }
+    else {
+      $fields['order_by'] = '';
+    }
+
+    //  Use unique key on name column for testing uniqueness.
+    if ($create) {
+      $fields['name'] = $name;
+      try {
+        db_insert('log_filter')
+          ->fields($fields)
+          ->execute();
+      }
+      catch (PDOException $xc) {
+        if ((int)$xc->getCode() == 23000) { // Fair chance that it's a duplicate key error, though 23000 may also (MySQL) mean null error.
+          throw new Exception('Filter name[' . $name . '] already exists.', self::$_errorCodes['filter_name_nonunique']);
+        }
+        else {
+          throw $xc;
+        }
+      }
+    }
+    elseif (!($filter = self::_readFilter($name))) {
+      if ($filter === FALSE) {
+        throw new Exception('Filter name[' . $name . '] doesnt exist.', self::$_errorCodes['filter_doesnt_exist']);
+      }
+      throw new Exception('User (' . $uid . ') ' . $GLOBALS['user']->name . ' is not allowed to use filter[' . $name . '].',
+          self::$_errorCodes['perm_filter_restricted']);
+    }
+    elseif (
+      !db_update('log_filter')
+        ->fields($fields)
+        ->condition('name', $name)
+        ->execute()
+    ) {
+      throw new Exception('Failed to update filter[' . $name . '].', self::$_errorCodes['unknown']);
+    }
+  }
+
+  /**
+   * @param array &$conditions
+   *  - empty or invalid conditions will be removed from the array
+   * @param array $order_by
+   * @param integer $offset
+   *  - default: zero
+   *  - ignored until MySQL supports LIMIT for sub queries
+   * @param integer $max
+   *  - default: zero
+   *  - ignored until MySQL supports LIMIT for sub queries
+   * @param array|NULL|boolean $log_columns
+   *  - default: NULL (~ all watchdog columns)
+   *  - FALSE: count only
+   * @param array|boolean $user_columns
+   *  - default: FALSE (~ no user columns)
+   * @param boolean $deletion
+   *  - default: FALSE (~ not for deleting logs)
+   * @return SelectQuery|SelectQueryInterface
+   * @throws Exception
+   *  - PDOException
+   */
+  protected static function _logListQuery(&$conditions, $order_by, $offset = 0, $max = 0, $log_columns = NULL, $user_columns = FALSE, $deletion = FALSE) {
+    $query = db_select('watchdog', 'w');
+    if ($user_columns) {
+      $query->leftJoin('users', 'u', 'w.uid = u.uid');
+    }
+    if (!$log_columns) {
+      if ($log_columns !== FALSE) {
+        $query->fields('w'); // Wildcard columns.
+        //->fields('w', array('wid', 'uid', 'type', 'message', 'variables', 'severity', 'link', 'location', 'referer', 'hostname', 'timestamp'))
+      }
+    }
+    else {
+      $query->fields('w', $log_columns);
+    }
+    if ($user_columns) {
+      $le = count($user_columns);
+      for ($i = 0; $i < $le; $i++) {
+        $query->addField('u', $user_columns[$i]);
+      }
+    }
+    //  Conditions.
+    if ($deletion || $conditions) {
+      // The wid (log id) condition is not part of the overall used conditions, so we have to handle it differently.
+      // @todo: Explain just how, the code is certainly not self-explanatory in this sense.
+      $wid = 0;
+      if (isset($conditions['wid'])) {
+        if (($v = (int)$conditions['wid']) && $v > -1 && $v <= PHP_INT_MAX) {
+          $wid = $v;
+          $query->condition('w.' . 'wid', $v, '=');
+          // Remove all other conditions.
+          array_splice($conditions, 0);
+          $conditions['wid'] = $wid;
+        }
+        else {
+          unset($conditions['wid']);
+        }
+      }
+      if (!$wid) {
+        $names =& self::$_fields['conditions'];
+
+        // Use user id instead of role (anonymous user role doesnt really exists - only as a lack of any roles)?
+        $is_anonymous = $not_anonymous = FALSE;
+        if (isset($conditions['role'])) {
+          switch ($conditions['role']) {
+            case DRUPAL_ANONYMOUS_RID:
+              $is_anonymous = TRUE;
+              $conditions['uid'] = 0;
+              break;
+            case DRUPAL_AUTHENTICATED_RID:
+              $not_anonymous = TRUE;
+              $conditions['uid'] = 0;
+              break;
+          }
+        }
+
+        // Deleting events that log deletion of events is illegal.
+        if ($deletion) {
+          if (!empty($conditions['type']) && ($index = array_search('log_filter delete logs', $conditions['type'], TRUE)) !== FALSE) {
+            if (count($conditions['type']) == 1) {
+              unset($conditions['type']);
+            }
+            else {
+              array_splice($conditions['type'], $index, 1);
+            }
+          }
+          $query->condition('w.' . 'type', 'log_filter delete logs', '!=');
+        }
+
+        foreach ($names as $key) {
+          if (isset($conditions[$key])) {
+            if (!($v = $conditions[$key]) && $key != 'uid') {
+              unset($conditions[$key]);
+            }
+            else {
+              switch ($key) {
+                case 'severity':
+                  if (!is_array($v)) {
+                    throw new Exception('Non-empty condition[' . $key . '], type[' . gettype($v) . '], must be array.',
+                      self::$_errorCodes['bad_filter_condition']);
+                  }
+                  //  Convert 'zero' to zero.
+                  $query->condition('w.' . $key, explode(',', str_replace('zero', '0', join(',', $v))), 'IN');
+                  break;
+                case 'type':
+                  if (!is_array($v)) {
+                    throw new Exception('Non-empty condition[' . $key . '], type[' . gettype($v) . '], must be array.',
+                      self::$_errorCodes['bad_filter_condition']);
+                  }
+                  $query->condition('w.' . $key, explode(',', check_plain(join(',', $v))), 'IN');
+                  break;
+                case 'time_range':
+                  if (($v = (int)$v) > 0 && $v < 10000) {
+                    $query->condition('w.' . 'timestamp', REQUEST_TIME - ($v * 60 * 60), '>=');
+                  }
+                  else {
+                    unset($conditions[$key]);
+                  }
+                  break;
+                case 'time_from':
+                  if (($v = (int)$v) > 0 && $v <= PHP_INT_MAX) {
+                    $query->condition('w.' . 'timestamp', $v, '>=');
+                  }
+                  else {
+                    unset($conditions[$key]);
+                  }
+                  break;
+                case 'time_to':
+                  if (($v = (int)$v) > 0 && $v <= PHP_INT_MAX) {
+                    $query->condition('w.' . 'timestamp', $v, '<=');
+                  }
+                  else {
+                    unset($conditions[$key]);
+                  }
+                  break;
+                case 'role':
+                  if (($v = (int)$v) > 0 && $v <= PHP_INT_MAX) {
+                    if (!$is_anonymous && !$not_anonymous) {
+                      $query->join('users_roles', 'ur', 'w.uid = ur.uid AND ur.rid = :rid', array(':rid' => $v));
+                    }
+                  }
+                  else {
+                    unset($conditions[$key]);
+                  }
+                  break;
+                case 'uid':
+                  if (($v = (int)$v) > -1 && $v <= PHP_INT_MAX) {
+                    $query->condition('w.' . $key, $v, !$not_anonymous ? '=' : '!=');
+                  }
+                  else {
+                    unset($conditions[$key]);
+                  }
+                  break;
+                case 'hostname':
+                case 'location':
+                  if (($v = trim(check_plain($v))) && $v !== '*') {
+                    $query->condition('w.' . $key, $v, '=');
+                  }
+                  else {
+                    unset($conditions[$key]);
+                  }
+                  break;
+                case 'referer': // Support strictly empty value 'none'
+                  if (($v = trim(check_plain($v))) && $v !== '*') {
+                    if ($v != 'none') {
+                      $query->condition('w.' . $key, $v, '=');
+                    }
+                    else {
+                      $query->condition(db_or()->condition('w.' . $key, '', '=')->isNull('w.' . $key));
+                    }
+                  }
+                  else {
+                    unset($conditions[$key]);
+                  }
+                  break;
+                default:
+                  //  Ignore.
+              }
+            }
+          }
+        }
+        // Remove uid again, if only used as surrogate for role.
+        if ($is_anonymous || $not_anonymous) {
+          unset($conditions['uid']);
+        }
+      }
+    }
+
+    // Simple log listing defaults to hide previous log deletions, unless user actually want to list log deletions.
+    if (!$deletion
+      && (empty($conditions['type']) || array_search('log_filter delete logs', $conditions['type'], TRUE) === FALSE)
+      && !variable_get('log_filter_showdeletions', FALSE)
+    ) {
+      $query->condition('w.' . 'type', 'log_filter delete logs', '!=');
+    }
+
+    if ($log_columns === FALSE) {
+      return $query->countQuery();
+    }
+
+    //  Order by.
+    //  Will always be qualified extra by log id order, to secure correct (sub) order.
+    if (!empty($order_by)) {
+      $timeAscending = FALSE;
+      foreach($order_by as &$orderBy) {
+        if (preg_match('/^[a-z\d_]{2,32}$/', $k = $orderBy[0]) && (($v = $orderBy[1]) === 'DESC' || $v === 'ASC')) {
+          if ($k == 'time' || $k == 'timestamp') {
+            $query->orderBy('w.timestamp', $v);
+            if ($v == 'ASC') {
+              $timeAscending = TRUE;
+            }
+          }
+          else {
+            $query->orderBy('w.' . $k, $v);
+          }
+        }
+      }
+      unset($orderBy);
+      $query->orderBy('w.wid', !$timeAscending ? 'DESC' : 'ASC');
+    }
+    else {
+      $query->orderBy('timestamp', 'DESC')->orderBy('w.wid', 'DESC');
+    }
+    if (($offset || $max) && self::DB_SUBQUERY_LIMIT) {
+      // A range must have a max length, otherwise it's ignored.
+      if (!$max) {
+        $max = PHP_INT_MAX - $offset;
+      }
+      $query->range($offset, $max);
+    }
+    return $query;
+  }
+
+  /**
+   * @param array &$conditions
+   * @param array $order_by
+   * @param integer $offset
+   * - minus one: list $max number of items from end of total matching items
+   * @param integer $max
+   * @param boolean $translate
+   *  - default: FALSE
+   * @return array
+   */
+  protected static function _listLogs(&$conditions, $order_by, $offset, $max, $translate = FALSE) {
+    // Find total matching items.
+    $total = (int)self::_logListQuery($conditions, $order_by, 0, 0, FALSE)->execute()->fetchField();
+
+    // Max number of items from end of total matching items?
+    if ($offset < 0) {
+      $offset = $max ? $total - $max : 0;
+    }
+
+    $query = self::_logListQuery($conditions, $order_by, $offset, $max, NULL, array('name'));
+
+    if (($offset || $max) && !self::DB_SUBQUERY_LIMIT) {
+      // A range must have a max length, otherwise it's ignored.
+      if (!$max) {
+        $max = PHP_INT_MAX - $offset;
+      }
+      $query->range($offset, $max);
+    }
+    //  Work on event buckets.
+    if (($rows = $query->execute()->fetchAll())) {
+      foreach($rows as &$event) {
+        //  Translate?
+        if (($vars = $event->variables) === 'N;') {
+          $event->variables = '';
+        }
+        elseif (!$translate) { // Do variables replacement frontend.
+          $event->variables = unserialize($vars);
+        }
+        else { // Do translate if any variables
+          $event->message = t($event->message, unserialize($vars));
+          $event->variables = '';
+        }
+        //  Filter link.
+        if ($event->link) {
+          $event->link = filter_xss($event->link);
+        }
+      }
+      unset($event); // Clear reference.
+    }
+    // Tell which conditions were used, but not what their values where - except for the wid (log id) condition.
+    $responseConditions = array_fill_keys(array_keys($conditions), true);
+    if (!empty($conditions['wid'])) {
+      $responseConditions['wid'] = $conditions['wid'];
+    }
+    return array(
+      $rows,
+      $responseConditions,
+      $offset,
+      $total,
+    );
+  }
+
+  /**
+   * Using a LIMIT for delete queryies is kind of hard since db_delete doesnt support LIMIT (because PostgresSQL doesnt support that),
+   * and MySQL doesnt support LIMIT for sub queries.
+   *
+   * And MySQL doesnt support using the same table in a sub query and in an outer CRUD query.
+   *
+   * So we have to do a separate select getting the relevant ids, and then do a delete using that - potentially too long - list of ids.
+   * Does it in chunks of 40000 items; that should work even when db query max length is only half a megabyte.
+   *
+   * @param array $conditions
+   * @param array $order_by
+   * @param integer $offset
+   * @param integer $max
+   * @return integer
+   */
+  protected static function _deleteLogs($conditions, $order_by, $offset, $max) {
+    global $user;
+
+    // Deleting all logs unconditionally is not an option, because deleting logs of type 'log_filter delete logs' is illegal.
+    //if (!$conditions && !$offset && !$max) {
+    //  $deleted = db_delete('watchdog')
+    //    ->execute();
+    //}
+    //else {
+    $query = self::_logListQuery($conditions, $order_by, $offset, $max, array('wid'), FALSE, TRUE);
+    if (($offset || $max) && !self::DB_SUBQUERY_LIMIT) {
+      // A range must have a max length, otherwise it's ignored.
+      if (!$max) {
+        $max = PHP_INT_MAX - $offset;
+      }
+      $query->range($offset, $max);
+    }
+    $ids = $query->execute()->fetchCol();
+
+    if (!($le = count($ids))) {
+      return 0;
+    }
+    //  This may fail because the list of ids may exceed query limit (query max length).
+    if ($le > 40000) {
+      $le = count($ids = array_chunk($ids, 40000));
+      $deleted = 0;
+      for ($i = 0; $i < $le; $i++) {
+        $deleted += db_delete('watchdog')
+          ->condition('wid', $ids[$i], 'IN')
+          ->execute();
+      }
+    }
+    else {
+      $deleted = db_delete('watchdog')
+        ->condition('wid', $ids, 'IN')
+        ->execute();
+    }
+    //}
+    watchdog(
+      'log_filter delete logs',
+      'User (%uid) %name deleted !deleted log events.',
+      array('%uid' => $user->uid, '%name' => $user->name, '!deleted' => $deleted),
+      WATCHDOG_NOTICE
+    );
+    return $deleted;
+  }
+
+  /**
+   * Access permission: 'access site reports'.
+   *
+   * All actions require the POST var form_token.
+   *
+   *  Expects (requires) POST vars on actions:
+   *  - filter_create|filter_edit: name, filter, conditions, order_by
+   *  - list_logs: conditions, order_by, offset, max, translate
+   *  - delete_logs: conditions, order_by, offset, max
+   *
+   * @see LogFilter::ajaxCallback
+   * @param string $action
+   * @return void
+   *  - sends 403 header if the expected POST vars arent set or their sanitized values evaluates to empty
+   */
+  public static function ajaxCallback($action) {
+    if ( // Require permission.
+      !user_access('access site reports')
+      //  Require valid composition of the 'action' parameter (presumably a GET var).
+      || !$action || !($le = strlen($action)) // Deliberately not drupal_...().
+        || $le > 32
+    ) {
+      header('HTTP/1.1 403 Forbidden');
+      exit;
+    }
+    $action = '' . $action;
+    $oResp = new stdClass();
+    $oResp->action = check_plain($action); // Redundant; vs. code review.
+    $oResp->error = '';
+    $oResp->success = TRUE;
+    $oResp->error_code = 0;
+
+    try {
+      switch ($action) {
+        case 'username_autocomplete':
+          $oResp = array();
+          if (isset($_GET['term']) && strlen($needle = trim($_GET['term'])) && drupal_validate_utf8($needle)) {
+            $maxResult = 9;
+            //$oResp = array( array('value' => '8', 'label' => 'someuser'), );
+            $uids = array();
+            $users = db_select('users', 'u')
+              ->fields('u', array('uid', 'name'))
+              ->condition('name', db_like($needle) . '%', 'LIKE')
+              ->orderBy('u.name', 'ASC')
+              ->range(0, $maxResult)
+              ->execute()
+              ->fetchAll();
+            if (($le = count($users))) {
+              for ($i = 0; $i < $le; ++$i) {
+                $oResp[] = array('value' => $uids[] = $users[$i]->uid, 'label' => $users[$i]->name);
+              }
+            }
+            if ($le < $maxResult) {
+              $users = db_select('users', 'u')
+                ->fields('u', array('uid', 'name'));
+              if ($uids) {
+                $users = $users->condition('uid', $uids, 'NOT IN');
+              }
+              $users = $users->condition('name', '%' . db_like($needle) . '%', 'LIKE')
+                ->orderBy('u.name', 'ASC')
+                ->range(0, $maxResult - $le)
+                ->execute()
+                ->fetchAll();
+              if (($le = count($users))) {
+                for ($i = 0; $i < $le; ++$i) {
+                  $oResp[] = array('value' => $users[$i]->uid, 'label' => $users[$i]->name);
+                }
+              }
+            }
+          }
+          break;
+        case 'filter_create':
+        case 'filter_edit':
+          $conditions = $order_by = NULL;
+          if (
+            !array_key_exists('name', $_POST) || !($le = strlen($name = $_POST['name'])) // Deliberately not drupal_...(). And composition is checked later.
+              || $le > 32
+            || !array_key_exists('filter', $_POST) || !is_array($filter = $_POST['filter']) // It is an array!
+            || !array_key_exists('require_admin', $filter) || !(($require_admin = (int)$filter['require_admin']) == 0 || $require_admin == 1)
+            || !array_key_exists('description', $filter)
+              || ( ($description = $filter['description']) !== '' && (!drupal_validate_utf8($description) || drupal_strlen($description) > 255) )
+            // conditions may not exist, because jQuery.ajax() >v1.4.4 doesn't POST empty object.
+            // _saveFilter() checks/filters conditions buckets vs. xss.
+            || (array_key_exists('conditions', $_POST) && ($conditions = $_POST['conditions']) && !is_array($conditions))
+            // order_by may not exist, because jQuery.ajax() >v1.4.4 doesn't POST empty object.
+            // _saveFilter() checks/filters order_by buckets vs. xss.
+            || (array_key_exists('order_by', $_POST) && ($order_by = $_POST['order_by']) && !is_array($order_by))
+          ) {
+            header('HTTP/1.1 403 Forbidden');
+            exit;
+          }
+          if (!user_access('log_filter edit filters')) {
+            $oResp->success = FALSE;
+            $oResp->error_code = self::$_errorCodes['perm_filter_crud'];
+          }
+          elseif (!preg_match('/^[a-z_][a-z\d_]+$/', $name) || $name == 'default' || $name == 'adhoc') { // @IDE: var $name is declared.
+            $oResp->success = FALSE;
+            $oResp->error_code = self::$_errorCodes['filter_name_composition'];
+            //  $oResp->error = t('Invalid machine name[' . $name . '].'); Frontend creates own message.
+            $oResp->name = check_plain($name);
+          }
+          else {
+            $oResp->name = $name = check_plain(strtolower($name)); // Deliberately not drupal_...().
+            $oResp->description = !$description ? '' : check_plain(trim(str_replace(array("\r", "\n", "\t"), ' ', $description)));
+            self::_saveFilter(
+              $name,
+              array(
+                'filter' => array(
+                  'require_admin' => $require_admin,
+                  'description' => $description
+                ),
+                'conditions' => $conditions ? $conditions : array(), // _saveFilter() checks/filters conditions buckets vs. xss.
+                'order_by' => $order_by ? $order_by : array(), // _saveFilter() checks/filters order_by buckets vs. xss.
+              ),
+              $action == 'filter_create'
+            );
+          }
+          break;
+        case 'list_logs':
+          $conditions = $order_by = NULL;
+          if (
+            // conditions may not exist, because jQuery.ajax() >v1.4.4 doesn't POST empty object.
+            // _logListQuery() checks/filters conditions buckets vs. xss.
+            (array_key_exists('conditions', $_POST) && ($conditions = $_POST['conditions']) && !is_array($conditions))
+            // order_by may not exist, because jQuery.ajax() >v1.4.4 doesn't POST empty object.
+            // _logListQuery() checks/filters order_by buckets vs. xss.
+            || (array_key_exists('order_by', $_POST) && ($order_by = $_POST['order_by']) && !is_array($order_by))
+            || !array_key_exists('offset', $_POST) || ($offset = (int)$_POST['offset']) < -1 || $offset > PHP_INT_MAX
+            || !array_key_exists('max', $_POST) || ($max = (int)$_POST['max']) < 0 || $max > PHP_INT_MAX
+            || !array_key_exists('translate', $_POST)
+          ) {
+            header('HTTP/1.1 403 Forbidden');
+            exit;
+          }
+          if ($max > self::PAGE_RANGE_MAX) {
+            $max = self::PAGE_RANGE_MAX;
+          }
+          if (!$conditions) {
+            $conditions = array();
+          }
+          $oResp->log_list = self::_listLogs(
+            $conditions,
+            $order_by ? $order_by : array(),
+            $offset,
+            $max,
+            $translate = (bool)$_POST['translate']
+          );
+          //  Save pager_range and translate to session.
+          $session = array(
+            'settings' => array(
+              'pager_range' => $max > 0 ? $max : variable_get('log_filter_pgrng', self::PAGE_RANGE_DEFAULT),
+              'translate' => $translate,
+            ),
+          );
+          if (module_exists('state')) {
+            State::sessionSet('module', 'log_filter', $session);
+          }
+          else {
+            drupal_session_start();
+            if (!isset($_SESSION['module'])) {
+              $_SESSION['module'] = array(
+                'log_filter' => $session,
+              );
+            }
+            else {
+              $_SESSION['module']['log_filter'] = $session;
+            }
+          }
+          break;
+        case 'delete_logs':
+          $conditions = $order_by = NULL;
+          if (
+            // conditions may not exist, because jQuery.ajax() >v1.4.4 doesn't POST empty object.
+            // _logListQuery() checks/filters conditions buckets vs. xss.
+            (array_key_exists('conditions', $_POST) && ($conditions = $_POST['conditions']) && !is_array($conditions))
+            // order_by may not exist, because jQuery.ajax() >v1.4.4 doesn't POST empty object.
+            // _logListQuery() checks/filters order_by buckets vs. xss.
+            || (array_key_exists('order_by', $_POST) && ($order_by = $_POST['order_by']) && !is_array($order_by))
+            || !array_key_exists('offset', $_POST) || ($offset = (int)$_POST['offset']) < -1 || $offset > PHP_INT_MAX
+            || !array_key_exists('max', $_POST) || ($max = (int)$_POST['max']) < 0 || $max > PHP_INT_MAX
+          ) {
+            header('HTTP/1.1 403 Forbidden');
+            exit;
+          }
+          $oResp->delete_logs = self::_deleteLogs(
+            $conditions ? $conditions : array(),
+            $order_by ? $order_by : array(),
+            $offset,
+            $max
+          );
+          break;
+        default:
+          $oResp->success = FALSE;
+          $oResp->error_code = 1;
+          $oResp->error = 'Unsupported action[' . $action . '].';
+      }
+    }
+    catch (PDOException $xc) {
+      self::_errorHandler($xc);
+      $oResp->success = FALSE;
+      $oResp->error_code = self::$_errorCodes['db_general'];
+    }
+    catch (Exception $xc) {
+      self::_errorHandler($xc);
+      $oResp->success = FALSE;
+      if (($error_code = $xc->getCode()) && in_array($error_code, self::$_errorCodes)) {
+        $oResp->error_code = $error_code;
+      }
+      else {
+        $oResp->error_code = self::$_errorCodes['unknown'];
+      }
+    }
+
+    header('Content-Type: application/json; charset=utf-8');
+    header('Cache-Control: private, no-store, no-cache, must-revalidate');
+    header('Expires: Thu, 01 Jan 1970 00:00:01 GMT');
+    echo drupal_json_encode($oResp);
+    flush();
+    exit;
+  }
+}

+ 12 - 0
sites/all/modules/contrib/admin/log_filter/admin/log_filter.admin.css

@@ -0,0 +1,12 @@
+
+body.page-admin-config-system-log_filter * {
+
+}
+  body.page-admin-config-system-log-filter input#edit-log-filter-trnct {
+    text-align: right;
+  }
+    body.page-admin-config-system-log-filter div.form-item-log-filter-hidedblog label,
+    body.page-admin-config-system-log-filter div.form-item-log-filter-hidedblog .form-item label.option {
+      font-weight: bold;
+      font-size: 1em;
+    }

+ 108 - 0
sites/all/modules/contrib/admin/log_filter/admin/log_filter.admin.inc

@@ -0,0 +1,108 @@
+<?php
+/**
+ * @file
+ *  Drupal Log Filter module
+ */
+
+/**
+ * Defines configuration form fields.
+ *
+ * @param array $form
+ * @param array &$form_state
+ * @return array
+ *   - the return value of system_settings_form()
+ */
+function _log_filter_admin_form($form, &$form_state) {
+  module_load_include('inc', 'log_filter', 'LogFilter');
+  if (variable_get('log_filter_css', TRUE)) {
+    drupal_add_css(
+      ($path = drupal_get_path('module', 'log_filter')) . '/admin/log_filter.admin.css',
+      array('type' => 'file', 'group' => CSS_DEFAULT, 'preprocess' => FALSE, 'every_page' => FALSE)
+    );
+  }
+  //  Clear menu cache if just submitted.
+  if (!empty($_SESSION) && !empty($_SESSION['module']) && !empty($_SESSION['module']['log_filter'])
+      && array_key_exists('admin_form_submitted', $_SESSION['module']['log_filter'])) {
+    menu_rebuild();
+    unset($_SESSION['module']['log_filter']['admin_form_submitted']);
+    if (empty($_SESSION['module']['log_filter'])) {
+      unset($_SESSION['module']['log_filter']);
+      if (empty($_SESSION['module'])) {
+        unset($_SESSION['module']);
+      }
+    }
+  }
+  $form['general'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('General settings'),
+    '#collapsible' => FALSE,
+    '#collapsed' => FALSE,
+    'log_filter_admintheme' => array(
+      '#type' => 'checkbox',
+      '#title' => t('Do always use the administrative theme on log view pages'),
+      '#default_value' => variable_get('log_filter_admintheme', TRUE),
+      '#attributes' => array('autocomplete' => 'off'),
+    ),
+    'log_filter_cssdefault' => array(
+      '#type' => 'checkbox',
+      '#title' => t('Link this module\'s default stylesheet'),
+      '#description' => t('Otherwise, implement styling in the site\'s theme layer.'),
+      '#default_value' => variable_get('log_filter_cssdefault', TRUE),
+      '#attributes' => array('autocomplete' => 'off'),
+    ),
+  );
+  $form['log_list'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Log list settings'),
+    '#collapsible' => FALSE,
+    '#collapsed' => FALSE,
+    'log_filter_pgrng' => array(
+      '#type' => 'textfield',
+      '#title' => t('Default log list page range'),
+      '#default_value' => variable_get('log_filter_pgrng', LogFilter::PAGE_RANGE_DEFAULT),
+      '#attributes' => array('autocomplete' => 'off'),
+      '#size' => 3,
+    ),
+    'log_filter_trnslt' => array(
+      '#type' => 'checkbox',
+      '#title' => t('Default to translate log message'),
+      '#description' => t('Translating log messages is heavy performance-wise'),
+      '#default_value' => variable_get('log_filter_trnslt', FALSE),
+      '#attributes' => array('autocomplete' => 'off'),
+    ),
+    'log_filter_showdeletions' => array(
+      '#type' => 'checkbox',
+      '#title' => t('List log entries that record that logs have been deleted'),
+      '#description' => t('Log entries of type \'log_filter delete logs\' defaults to be hidden, unless when that type is selected specifically.'),
+      '#default_value' => variable_get('log_filter_showdeletions', FALSE),
+      '#attributes' => array('autocomplete' => 'off'),
+    ),
+  );
+
+  $form['#submit'][] = 'log_filter_admin_form_submit';
+  return system_settings_form($form);
+}
+
+/**
+ * @param array $form
+ * @param array &$form_state
+ * @return void
+ */
+function _log_filter_admin_form_submit($form, &$form_state) {
+  //  Make form clear menu cache upon submission.
+  if (!isset($_SESSION['module'])) {
+    $_SESSION['module'] = array(
+      'log_filter' => array('admin_form_submitted' => TRUE),
+    );
+  }
+  elseif (!isset($_SESSION['module']['log_filter'])) {
+    $_SESSION['module']['log_filter'] = array('admin_form_submitted' => TRUE);
+  }
+  else {
+    $_SESSION['module']['log_filter']['admin_form_submitted'] = TRUE;
+  }
+
+  $values =& $form_state['values'];
+  $values['log_filter_pgrng'] = !($val = (int)trim($values['log_filter_pgrng'])) || $val < 0 ? LogFilter::PAGE_RANGE_DEFAULT :
+    ($val > LogFilter::PAGE_RANGE_MAX ? LogFilter::PAGE_RANGE_MAX : $val);
+}

BIN
sites/all/modules/contrib/admin/log_filter/css/img/log-16-alert.png


BIN
sites/all/modules/contrib/admin/log_filter/css/img/log-16-critical.png


BIN
sites/all/modules/contrib/admin/log_filter/css/img/log-16-emergency.png


BIN
sites/all/modules/contrib/admin/log_filter/css/img/log-16-error.png


BIN
sites/all/modules/contrib/admin/log_filter/css/img/log-16-info.png


BIN
sites/all/modules/contrib/admin/log_filter/css/img/log-16-notice.png


BIN
sites/all/modules/contrib/admin/log_filter/css/img/log-16-warning.png


BIN
sites/all/modules/contrib/admin/log_filter/css/img/message-16-error.png


BIN
sites/all/modules/contrib/admin/log_filter/css/img/message-16-help.png


BIN
sites/all/modules/contrib/admin/log_filter/css/img/message-16-info.png


BIN
sites/all/modules/contrib/admin/log_filter/css/img/message-16-ok.png


BIN
sites/all/modules/contrib/admin/log_filter/css/img/message-16-warning.png


+ 829 - 0
sites/all/modules/contrib/admin/log_filter/css/log_filter.css

@@ -0,0 +1,829 @@
+
+body.page-admin-reports-dblog #page,
+body.page-admin-reports-dblog-log-filter #page {
+}
+
+/* dblog module injects a general help message */
+body.page-admin-reports-dblog #help,
+body.page-admin-reports-dblog-log-filter #help {
+  display: none;
+}
+
+/* admin_menu <7.x-3.0-rc4 creates horizontal scroll */
+div#admin-menu {
+  margin-left: 0;
+  margin-right: 0;
+}
+
+form#log-filter-form {
+}
+
+form#log-filter-form .form-item label {
+  margin: 0;
+  padding: 0;
+  font-size: 1em;
+}
+
+form#log-filter-form input[type="checkbox"],
+form#log-filter-form input[type="submit"],
+form#log-filter-form input[type="reset"],
+form#log-filter-form input[type="button"],
+form#log-filter-form button,
+form#log-filter-form select {
+  cursor: pointer;
+}
+form#log-filter-form input:disabled,
+form#log-filter-form textarea:disabled,
+form#log-filter-form button:disabled,
+form#log-filter-form select:disabled {
+  cursor: not-allowed;
+}
+/* :readonly is useless */
+form#log-filter-form input.form-item-readonly,
+form#log-filter-form input[type="checkbox"].form-item-readonly,
+form#log-filter-form textarea.form-item-readonly,
+form#log-filter-form select.form-item-readonly {
+  cursor: not-allowed;
+  background-color: #E8E8E8;
+}
+form#log-filter-form input[type="text"].form-item-readonly,
+form#log-filter-form input[type="password"].form-item-readonly,
+form#log-filter-form textarea.form-item-readonly {
+  cursor: not-allowed;
+  background-color: #E8E8E8;
+}
+
+form#log-filter-form .form-item {
+  padding: 0;
+  margin: 0;
+}
+
+form#log-filter-form input.form-button {
+  margin: 0;
+  min-width: 5em;
+}
+form#log-filter-form input.form-button-disabled,
+form#log-filter-form input.form-button-disabled:hover,
+form#log-filter-form input.form-button-disabled:active {
+  background-color: #DDD;
+  border-color: #DDD;
+  color: #666;
+}
+
+form#log-filter-form fieldset#edit-filter-filter-edit input.form-submit {
+}
+form#log-filter-form input.form-submit:hover {
+  opacity:0.8; -ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=80)'; filter:alpha(opacity=80);
+}
+form#log-filter-form input.form-submit:disabled,
+form#log-filter-form input.form-submit.form-button-disabled {
+}
+form#log-filter-form input.form-submit:disabled:hover,
+form#log-filter-form input.form-submit.form-button-disabled {
+  opacity:1.0; -ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=100)'; filter:alpha(opacity=100);
+}
+
+form#log-filter-form input.form-submit {
+  color: #333;
+}
+form#log-filter-form input.form-submit.form-button-disabled {
+  color: #666;
+}
+form#log-filter-form input.form-submit.edit-reset,
+form#log-filter-form input.form-submit.edit-cancel {
+  color: #336699;
+}
+form#log-filter-form input.form-submit.edit-delete {
+  color: #993300;
+}
+form#log-filter-form label span { /* hover title marker */
+  display: inline-block;
+  cursor: default;
+  vertical-align: top;
+  padding: 0 2px;  margin: 0 2px;  border: 1px solid #999;  border-radius: 4px;
+  font-family: Verdana, sans-serif;  font-size: 0.9em; line-height: 1em;  font-weight: bold;  color: #666;
+}
+form#log-filter-form div#log_filter_filters label span { /* hover title marker */
+  border-color: #888;  background-color: #E8E8E8;  color: #555;
+}
+
+/* theming */
+body.page-admin-reports-dblog #page.theme-seven,
+body.page-admin-reports-dblog-log-filter #page.theme-seven {
+  margin-left: 20px; /*margin-left: 40px;*/
+  margin-right: 20px; /*margin-right: 40px;*/
+  padding: 10px 0 10px; /*padding: 20px 0 40px;*/
+}
+#page.theme-seven form#log-filter-form input.form-submit {
+  border-radius: 11px;
+  padding: 2px 8px 3px;
+}
+#page.theme-seven form#log-filter-form input.theme-seven.form-button-disabled,
+#page.theme-seven form#log-filter-form input.theme-seven.form-button-disabled:hover,
+#page.theme-seven form#log-filter-form input.theme-seven.form-button-disabled:active {
+  background-color: #EFEFEF;
+  border-color: #EFEFEF;
+  color: #666;
+}
+
+
+/* messages */
+div#log_filter__message {
+  width: 67%;
+  text-align: center;
+  height: 0; max-height: 0;
+}
+  div#log_filter__message > div {
+    position: relative;
+    display: inline-block;
+    text-align: left;
+    width: 40em; max-width: 40em;
+  }
+    div#log_filter__message_list {
+      position: absolute;
+      top: -1em;
+      z-index: 901; /* above overlay */
+    }
+      div#log_filter__message_list > div { /* a message */
+        display: none;
+        width: 40em; max-width: 40em;
+        margin-bottom: 0.2em;
+        border: 0.1em solid #BBB;
+        border-radius: 0.4em;
+        box-shadow: 0.1em 0.15em 0.2em #999;
+        background-repeat: no-repeat;
+        background-position: 0.5em 0.5em;
+      }
+        div#log_filter__message_list > div:after {
+          /*clearfix*/clear:both;content:".";display:block;height:0;visibility:hidden;font-size:0;
+        }
+        div#log_filter__message_list > div > div:first-child { /* message content */
+          float: left;
+          padding: 0.6em 0em 0.6em 3em;
+          line-height: 1.3em;
+          width: 34.5em; max-width: 34.5em;
+        }
+          div#log_filter__message_list > div > div:first-child span {
+          }
+        div#log_filter__message_list > div > div:last-child { /* message close button */
+          float: right;
+          font-family: Verdana,sans-serif;
+          font-weight: bold;
+          font-size: 1.1em;
+          line-height: 1em;
+          padding: 0.5em 0.7em 0.4em 0.6em;
+          color: #666;
+          cursor: pointer;
+          user-select: none; -moz-user-select: none; -webkit-user-select: none;
+        }
+        div#log_filter__message_list > div > div:last-child:hover {
+          color: #999;
+        }
+      div#log_filter__message_list > div.log-filter-message-status {
+        background-color: #F8FFF0;
+        background-image: url("img/message-16-ok.png");
+      }
+      div#log_filter__message_list > div.log-filter-message-info,
+      div#log_filter__message_list > div.log-filter-message-notice {
+        background-color: #FFFCE5;
+        background-image: url("img/message-16-info.png");
+      }
+      div#log_filter__message_list > div.log-filter-message-warning {
+        background-color: #FFFCE5;
+        background-image: url("img/message-16-warning.png");
+      }
+      div#log_filter__message_list > div.log-filter-message-error {
+        background-color: #FEF5F1;
+        background-image: url("img/message-16-error.png");
+      }
+
+
+  form#log-filter-form fieldset#edit-log-filter-filter-edit .fieldset-legend span span {
+    text-transform: none;
+  }
+  form#log-filter-form div.fieldset-wrapper {
+    padding-right: 0.5em;
+    padding-bottom: 0.5em;
+  }
+    form#log-filter-form div.fieldset-wrapper:after {
+      /*clearfix*/clear:both;content:".";display:block;height:0;visibility:hidden;font-size:0;
+    }
+    form#log-filter-form div.fieldset-wrapper > div {
+      float: left;
+    }
+
+    form#log-filter-form div#log_filter_criteria {
+        margin-top: 0.2em;
+        padding-right: 1.3em;
+    }
+      /* conditions */
+      form#log-filter-form div#log_filter_criteria div.filter-conditions {
+      }
+        form#log-filter-form div#log_filter_criteria div.filter-conditions:after {
+          /*clearfix*/clear:both;content:".";display:block;height:0;visibility:hidden;font-size:0;
+        }
+        form#log-filter-form div#log_filter_criteria div.filter-conditions > div {
+          float: left;
+          padding: 0 1.1em;
+          border-right: 0.1em dotted #999;
+        }
+        form#log-filter-form div#log_filter_criteria div.filter-conditions > div:first-child {
+          padding-left: 0;
+        }
+        form#log-filter-form div#log_filter_criteria div.filter-conditions > div:last-child {
+          padding-right: 0;
+          border-right: none;
+        }
+
+        form#log-filter-form div#log_filter_criteria div.filter-conditions div.form-item.log-filter-time {
+          overflow: hidden;
+          /* ~ form#log-filter-form div#log_filter_criteria div.filter-orderby > label:first-child */
+          padding: 0.8em 1em 0 1.3em;
+          width: 11em; max-width: 11em;
+
+          height: 17em; max-height: 17em;
+          background-color: #E2E2E2;
+          border: 0;
+        }
+          form#log-filter-form div#log_filter_criteria div.filter-conditions div div.form-item.form-item-log-filter-time-range {
+            margin-top: 0.4em;
+          }
+            form#log-filter-form div#log_filter_criteria div.filter-conditions div div.form-item.form-item-log-filter-time-range input {
+              display: inline-block;
+              width: 2.8em;
+              text-align: right;
+            }
+          form#log-filter-form div#log_filter_criteria div.filter-conditions div div.log-filter-time-or {
+            padding: 0.6em 0 0.5em 0.2em;
+          }
+          form#log-filter-form div#log_filter_criteria div.filter-conditions div div.form-item.form-item-log-filter-time-to-proxy {
+            margin-top: 0.6em;
+          }
+            form#log-filter-form div#log_filter_criteria div.filter-conditions div div.form-item.form-item-log-filter-time-range label,
+            form#log-filter-form div#log_filter_criteria div.filter-conditions div div.form-item.form-item-log-filter-time-from-proxy label,
+            form#log-filter-form div#log_filter_criteria div.filter-conditions div div.form-item.form-item-log-filter-time-to-proxy label,
+            form#log-filter-form div#log_filter_criteria div.filter-conditions div div.form-item.form-item-log-filter-type-wildcard label,
+            form#log-filter-form div#log_filter_criteria div.filter-conditions div#edit-log-filter-severity.form-checkboxes div.form-item:first-child label {
+              font-size: 0.92em;
+            }
+            form#log-filter-form div#log_filter_criteria div.filter-conditions div div.form-item.form-item-log-filter-time-from-proxy input,
+            form#log-filter-form div#log_filter_criteria div.filter-conditions div div.form-item.form-item-log-filter-time-to-proxy input {
+              width: 5.5em;
+            }
+            form#log-filter-form div#log_filter_criteria div.filter-conditions div div.form-item input[name="log_filter_time_from_time"],
+            form#log-filter-form div#log_filter_criteria div.filter-conditions div div.form-item input[name="log_filter_time_to_time"] {
+              width: 4em;
+            }
+          form#log-filter-form div#log_filter_criteria div.filter-conditions div.form-item.form-type-checkbox {
+            padding: 0 0.1em;
+          }
+          form#log-filter-form div#log_filter_criteria div.filter-conditions div#edit-log-filter-severity.form-checkboxes div.form-item:first-child {
+            margin-top: 0.4em;
+            margin-bottom: 0.3em;
+          }
+            form#log-filter-form div#log_filter_criteria div.filter-conditions div#edit-log-filter-severity.form-checkboxes div.form-item:first-child label {
+              color: #666;
+              font-weight: bold;
+            }
+        form#log-filter-form div#log_filter_criteria div.filter-conditions div.form-item.form-item-log-filter-severity {
+          padding: 0.8em 0.5em 0 1.2em;
+          width: 8em; min-width: 8em;
+        }
+        form#log-filter-form div#log_filter_criteria div.filter-conditions div.form-item.log-filter-type {
+          padding: 0.8em 1.2em 0 1.1em;
+        }
+          form#log-filter-form div#log_filter_criteria div.filter-conditions div div.form-item.form-item-log-filter-type-wildcard {
+            margin-top: 0.4em;
+            margin-bottom: 0.3em;
+          }
+            form#log-filter-form div#log_filter_criteria div.filter-conditions div div.form-item.form-item-log-filter-type-wildcard label {
+              color: #666;
+              font-weight: bold;
+            }
+          form#log-filter-form div#log_filter_criteria div.filter-conditions div div.log-filter-type-container {
+            overflow: auto;
+            border: 0.1em dotted #999;
+            border-width: 0.1em 0;
+            width: 16em; max-width: 16em;
+            height: 12.5em; max-height: 12.5em;
+          }
+            form#log-filter-form div#log_filter_criteria div.filter-conditions div div.log-filter-type-container input[type='text'] {
+              width: 12em;
+              padding-top: 0; padding-bottom: 0;
+            }
+            form#log-filter-form div#log_filter_criteria div.filter-conditions div div.log-filter-type-container textarea {
+              display: none;
+            }
+        form#log-filter-form div#log_filter_criteria div.filter-conditions div div.log-filter-user {
+          padding-top: 0.8em;
+          padding-bottom: 1.2em;
+          border-bottom: 0.1em dotted #999;
+        }
+          form#log-filter-form div#log_filter_criteria div.filter-conditions div div.log-filter-user:after {
+            /*clearfix*/clear:both;content:".";display:block;height:0;visibility:hidden;font-size:0;
+          }
+          form#log-filter-form div#log_filter_criteria div.filter-conditions div div.log-filter-user > div {
+            float: left;
+          }
+            form#log-filter-form div#log_filter_criteria div.filter-conditions div div.log-filter-user > div > label {
+              margin-bottom: 0.5em;
+            }
+            form#log-filter-form div#log_filter_criteria div.filter-conditions div div.log-filter-user div.form-item-log-filter-role select {
+              max-width: 10.5em;
+            }
+          form#log-filter-form div#log_filter_criteria div.filter-conditions div div div.form-item.form-item-log-filter-uid,
+          form#log-filter-form div#log_filter_criteria div.filter-conditions div div div.form-item.form-item-log-filter-username {
+            padding-left: 0.5em;
+          }
+            form#log-filter-form div#log_filter_criteria div.filter-conditions div div div.form-item.form-item-log-filter-uid input {
+              text-align: right;
+              width: 3em;
+            }
+            form#log-filter-form div#log_filter_criteria div.filter-conditions div div div.form-item.form-item-log-filter-username input {
+              width: 8em;
+            }
+ul.ui-autocomplete {
+  padding: 0;
+}
+  ul.ui-autocomplete a {
+    font-weight: normal;
+    color: #000;
+    cursor: pointer;
+  }
+  ul.ui-autocomplete a:hover,
+  ul.ui-autocomplete a.ui-state-hover,
+  ul.ui-autocomplete a.ui-state-active {
+    background: #0072b9;
+    color: #fff;
+    margin: 0;
+  }
+        form#log-filter-form div#log_filter_criteria div.filter-conditions div div.form-item.form-item-log-filter-hostname {
+          padding: 0.8em 0 0.2em 0;
+        }
+        form#log-filter-form div#log_filter_criteria div.filter-conditions div div.form-item.form-item-log-filter-location,
+        form#log-filter-form div#log_filter_criteria div.filter-conditions div div.form-item.form-item-log-filter-referer {
+          padding: 0.2em 0;
+        }
+          form#log-filter-form div#log_filter_criteria div.filter-conditions div div.form-item.form-item-log-filter-hostname label,
+          form#log-filter-form div#log_filter_criteria div.filter-conditions div div.form-item.form-item-log-filter-location label,
+          form#log-filter-form div#log_filter_criteria div.filter-conditions div div.form-item.form-item-log-filter-referer label {
+            font-size: 0.92em;
+            line-height: 1.5em;
+          }
+          form#log-filter-form div#log_filter_criteria div.filter-conditions div div.form-item.form-item-log-filter-hostname input,
+          form#log-filter-form div#log_filter_criteria div.filter-conditions div div.form-item.form-item-log-filter-location input,
+          form#log-filter-form div#log_filter_criteria div.filter-conditions div div.form-item.form-item-log-filter-referer input {
+            width: 23em;
+          }
+
+      /* orderBy */
+      form#log-filter-form div#log_filter_criteria div.filter-orderby {
+        clear: left;
+        /* ~ form#log-filter-form div#log_filter_filters > div#log_filter_box_delete_logs */
+        padding-top: 1em;
+        min-height: 3em;
+        background-color: #B8B8B8;
+      }
+        form#log-filter-form div#log_filter_criteria div.filter-orderby > label:first-child {
+          /* ~ form#log-filter-form div#log_filter_criteria div.filter-conditions div.form-item.log-filter-time */
+          padding-left: 1.3em;
+          padding-right: 2em;
+          width: 10em; max-width: 10em;
+          text-align: right;
+        }
+        form#log-filter-form div#log_filter_criteria div.filter-orderby:after {
+          /*clearfix*/clear:both;content:".";display:block;height:0;visibility:hidden;font-size:0;
+        }
+          form#log-filter-form div#log_filter_criteria div.filter-orderby > label {
+            float: left;
+            margin-top: 0.1em;
+            color: #FFF;
+          }
+          form#log-filter-form div#log_filter_criteria div.filter-orderby > div {
+            float: left;
+            padding: 0;
+          }
+          form#log-filter-form div#log_filter_criteria div.filter-orderby > div.form-item.form-type-select {
+          }
+            form#log-filter-form div#log_filter_criteria div.filter-orderby select {
+              max-width: 10em;
+              background: #F8F8F8;
+            }
+          form#log-filter-form div#log_filter_criteria div.filter-orderby > div.form-item.form-type-checkbox input {
+            margin-left: 0.1em;
+            margin-right: 1em;
+          }
+          form#log-filter-form div#log_filter_criteria div.filter-orderby > div.log-filter-reset {
+            float: right;
+            margin-right: 2em;
+          }
+
+    /* filter */
+    form#log-filter-form div#log_filter_filters {
+      margin-top: 0.2em;
+      /* ~ #log_filter_filters width */
+      width: 19.1em; max-width: 19.1em;
+      height: 21.8em;
+      background-color: #E2E2E2;
+    }
+    form#log-filter-form div#log_filter_filters:after {
+      /*clearfix*/clear:both;content:".";display:block;height:0;visibility:hidden;font-size:0;
+    }
+      form#log-filter-form div#log_filter_filters > div#log_filter_box_filter {
+        float: left;
+        padding-top: 0.8em;
+        /* ~ #log_filter_filters height */
+        height: 17em;
+      }
+        form#log-filter-form  div#log_filter_filters > div#log_filter_box_filter:after {
+          /*clearfix*/clear:both;content:".";display:block;height:0;visibility:hidden;font-size:0;
+        }
+        form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div,
+        form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div#log_filter_filters_cell_0 {
+          float: left;
+          /* ~ #log_filter_filters width */
+          width: 16.5em; min-width: 16.5em;
+          padding-left: 1.3em;
+          padding-right: 1.3em;
+        }
+          form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div#log_filter_filters_cell_0:after,
+          form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div#log_filter_filters_cell_1:after {
+            /*clearfix*/clear:both;content:".";display:block;height:0;visibility:hidden;font-size:0;
+          }
+          form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div#log_filter_filters_cell_0,
+          form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div#log_filter_filters_cell_1 {
+            float: left;
+          }
+            form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div#log_filter_filters_cell_0 > div.form-item-log-filter-filter label {
+              padding-bottom: 0.3em;
+            }
+            form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div > div.form-item-log-filter-filter select {
+              /* ~ #log_filter_filters width */
+              width: 15.5em; max-width: 15.5em;
+
+              font-size: 1.05em;  font-weight: bold;
+            }
+              form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div > div.form-item-log-filter-filter option {
+                font-size: 1.05em;
+                padding: 0.1em 0;
+                color: #000;  font-weight: normal;
+              }
+              form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div.form-item-log-filter-filter option:selected {
+                font-size: 1.05em;  font-weight: bold; /* doesnt work; setting directly on select work */
+              }
+            form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div#log_filter_filters_cell_0 > div.form-item-log-filter-only-own {
+              display: none;
+              margin-top: 0.5em;
+              margin-bottom: 1em;
+            }
+            form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div > div.form-item-log-filter-only-own label {
+              font-weight: bold;
+            }
+        form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div#log_filter_filters_cell_1 {
+        }
+          form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div#log_filter_filters_cell_1 > div.form-item-log-filter-name-suggest {
+            display: none;
+          }
+            form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div > div.form-item-log-filter-name-suggest label {
+              margin-top: 1em;
+            }
+            form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div > div.form-item-log-filter-name-suggest input {
+              /* ~ #log_filter_filters width */
+              width: 15.5em;
+            }
+          form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div#log_filter_filters_cell_1 > div.form-item-log-filter-require-admin {
+            display: none;
+            margin-top: 1em;
+          }
+            form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div > div.form-item-log-filter-require-admin label {
+              font-weight: bold;
+            }
+
+        form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div.log-filter-edit-create {
+        }
+          form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div.log-filter-edit-create:after {
+            /*clearfix*/clear:both;content:".";display:block;height:0;visibility:hidden;font-size:0;
+          }
+          form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div.log-filter-edit-create input {
+            display: block;
+            margin-top: 1em;
+          }
+          form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div.log-filter-edit-create input[name="log_filter_edit"] {
+            float: left;
+          }
+          form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div.log-filter-edit-create input[name="log_filter_create"] {
+            float: right;
+          }
+        form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div.form-item-log-filter-description {
+          display: none;
+          margin-top: 0.5em;
+          margin-bottom: 1em;
+        }
+          form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div.form-item-log-filter-description textarea {
+            /* ~ #log_filter_filters width */
+            width: 15.5em;
+            max-height: 3em; /* gecko always adds an extra row to textarea */
+          }
+        form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div.log-filter-cancel-save {
+        }
+          form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div.log-filter-cancel-save:after {
+            /*clearfix*/clear:both;content:".";display:block;height:0;visibility:hidden;font-size:0;
+          }
+          form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div.log-filter-cancel-save > input[name="log_filter_cancel"] {
+            display: block;
+            float: left;
+          }
+          form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div.log-filter-cancel-save > input[name="log_filter_save"] {
+            display: block;
+            float: right;
+          }
+          form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div.log-filter-cancel-save.log-filter-reversed-button-sequence > input[name="log_filter_cancel"] {
+            float: right;
+          }
+          form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div.log-filter-cancel-save.log-filter-reversed-button-sequence > input[name="log_filter_save"] {
+            float: left;
+          }
+        form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div.log-filter-delete {
+            margin-top: 1.5em;
+        }
+          form#log-filter-form div#log_filter_filters > div#log_filter_box_filter > div.log-filter-delete input {
+          }
+      form#log-filter-form div#log_filter_filters > div#log_filter_box_delete_logs {
+        float: right;
+        background-color: #B8B8B8;
+        /* ~ #log_filter_filters width */
+        width: 16.5em; min-width: 16.5em;
+        /* ~ form#log-filter-form div#log_filter_criteria div.filter-orderby */
+        padding: 1em 1.3em 0 1.3em;
+        /* ~ #log_filter_filters height */
+        min-height: 3em;
+      }
+      form#log-filter-form div#log_filter_filters > div#log_filter_box_delete_logs.log-filter-delete-logs-none {
+        display: none;
+      }
+        form#log-filter-form div#log_filter_filters > div#log_filter_box_delete_logs:after {
+          /*clearfix*/clear:both;content:".";display:block;height:0;visibility:hidden;font-size:0;
+        }
+        form#log-filter-form div#log_filter_filters > div#log_filter_box_delete_logs > input[type="button"] {
+          display: block;
+          float: right;
+        }
+        form#log-filter-form div#log_filter_filters > div#log_filter_box_delete_logs > div.form-item-log-filter-delete-logs-max {
+          float: left;
+        }
+          form#log-filter-form div#log_filter_filters > div#log_filter_box_delete_logs div.form-item-log-filter-delete-logs-max:after {
+            /*clearfix*/clear:both;content:".";display:block;height:0;visibility:hidden;font-size:0;
+          }
+          form#log-filter-form div#log_filter_filters > div#log_filter_box_delete_logs div.form-item-log-filter-delete-logs-max label,
+          form#log-filter-form div#log_filter_filters > div#log_filter_box_delete_logs div.form-item-log-filter-delete-logs-max input {
+            float: left;
+          }
+          form#log-filter-form div#log_filter_filters > div#log_filter_box_delete_logs div.form-item-log-filter-delete-logs-max label {
+            margin-top: 0.1em;
+            margin-right: 0.2em;
+            color: #FFF;
+          }
+          form#log-filter-form div#log_filter_filters > div#log_filter_box_delete_logs div.form-item-log-filter-delete-logs-max input[type="text"] {
+            width: 4em;
+            background-color: #F8F8F8;
+            text-align: right;
+          }
+              form#log-filter-form div#log_filter_filters > div#log_filter_box_delete_logs div input.form-submit:hover {
+                opacity:0.9; -ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=90)'; filter:alpha(opacity=90);
+                background: #FFF;
+              }
+              form#log-filter-form div#log_filter_filters > div#log_filter_box_delete_logs div input.form-submit:disabled,
+              form#log-filter-form div#log_filter_filters > div#log_filter_box_delete_logs div input.form-submit:disabled:hover {
+                opacity:1; -ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=100)'; filter:alpha(opacity=100);
+                background: #D8D8D8;
+                color: #555;
+              }
+
+form#log-filter-form div#log_filter_list_controls {
+  padding-bottom: 0.5em;
+}
+  form#log-filter-form div#log_filter_list_controls:after {
+    /*clearfix*/clear:both;content:".";display:block;height:0;visibility:hidden;font-size:0;
+  }
+  form#log-filter-form div#log_filter_list_controls > div {
+    float: left;
+    margin-right: 3em;
+  }
+  form#log-filter-form div#log_filter_list_controls > div.log-filter-update-list-right {
+    float: right;
+    margin: 0;
+  }
+  form#log-filter-form div#log_filter_list_controls div#edit-actions {
+    display: none;
+  }
+  form#log-filter-form div#log_filter_list_controls > div.log-filter-pager-controls {
+    min-width: 27em;
+    margin-left: 3em;
+    margin-right: 0;
+  }
+    form#log-filter-form div#log_filter_list_controls > div.log-filter-pager-controls:after {
+      /*clearfix*/clear:both;content:".";display:block;height:0;visibility:hidden;font-size:0;
+    }
+    form#log-filter-form div#log_filter_list_controls > div.log-filter-pager-controls > div {
+      float: left;
+      cursor: pointer;
+    }
+    form#log-filter-form div#log_filter_list_controls > div.log-filter-pager-controls > div.log-filter-pager-button {
+      font-family: 'Verdana,Aria,sans-serif';
+      font-size: 1.1em;
+    }
+    form#log-filter-form div#log_filter_list_controls > div.log-filter-pager-controls > div.log-filter-pager-button:hover {
+      opacity:0.6; -ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=60)'; filter:alpha(opacity=60);
+    }
+    form#log-filter-form div#log_filter_list_controls > div.log-filter-pager-controls > div.log-filter-pager-button-disabled {
+      visibility: hidden;
+    }
+    form#log-filter-form div#log_filter_list_controls > div.log-filter-pager-controls > div#log_filter_pager_first,
+    form#log-filter-form div#log_filter_list_controls > div.log-filter-pager-controls > div#log_filter_pager_last {
+      letter-spacing: -0.3em;
+      padding-right: 0.3em;
+    }
+    form#log-filter-form div#log_filter_list_controls > div.log-filter-pager-controls > div#log_filter_pager_previous,
+    form#log-filter-form div#log_filter_list_controls > div.log-filter-pager-controls > div#log_filter_pager_next {
+      margin-left: 0.5em;
+      margin-right: 0.5em;
+      padding-left: 0.5em;
+      padding-right: 0.5em;
+    }
+    form#log-filter-form div#log_filter_list_controls > div.log-filter-pager-controls > div#log_filter_pager_current {
+      text-align: center;
+      min-width: 10em;
+      font-weight: bold;
+    }
+    form#log-filter-form div#log_filter_list_controls > div.log-filter-pager-controls > div#log_filter_pager_current:hover {
+      opacity:0.6; -ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=60)'; filter:alpha(opacity=60);
+    }
+    form#log-filter-form div#log_filter_list_controls > div.log-filter-pager-controls > div#log_filter_pager_progress {
+      display: none;
+      min-width: 7em;
+      padding-left: 3em;
+    }
+  form#log-filter-form div#log_filter_list_controls > div.form-item-log-filter-pager-range {
+
+  }
+    form#log-filter-form div#log_filter_list_controls > div.form-item-log-filter-pager-range:after {
+      /*clearfix*/clear:both;content:".";display:block;height:0;visibility:hidden;font-size:0;
+    }
+    form#log-filter-form div#log_filter_list_controls > div.form-item-log-filter-pager-range label,
+    form#log-filter-form div#log_filter_list_controls > div.form-item-log-filter-pager-range input {
+      display: block;
+      float: left;
+    }
+    form#log-filter-form div#log_filter_list_controls > div.form-item-log-filter-pager-range label {
+      font-weight: normal;
+      margin-right: 0.5em;
+    }
+  form#log-filter-form div#log_filter_list_controls > div.form-item-log-filter-cache {
+
+  }
+    form#log-filter-form div#log_filter_list_controls > div.form-item-log-filter-cache label {
+      font-weight: bold;
+      font-size: inherit;
+    }
+
+div#log_filter_log_list {
+  overflow-x: hidden;
+  border-right: 1px solid #CCC;
+}
+  div#log_filter_log_list > table {
+  }
+      div#log_filter_log_list th {
+        padding-left: 0.7em;
+      }
+      div#log_filter_log_list th:first-of-type {
+        padding: 0;
+      }
+    div#log_filter_log_list tr.even:hover,
+    div#log_filter_log_list tr.odd:hover,
+    div#log_filter_log_list tr.log-filter-list-displayed {
+      background-color: #D8E8F7;
+    }
+      div#log_filter_log_list td {
+        white-space: nowrap;
+        cursor: pointer;
+        text-align: left;
+        vertical-align: middle;
+        line-height: 1.2em;
+        padding: 0.7em;
+      }
+      div#log_filter_log_list td:hover {
+        background-color: #E8F3FF;
+      }
+      div#log_filter_log_list td.log-filter-list-message:hover {
+        background-color: #D8E8F7;
+      }
+      div#log_filter_log_list td.log-filter-list-user {
+        padding: 0 0.7em;
+      }
+        div#log_filter_log_list td.log-filter-list-user a {
+          display: block;
+          white-space: nowrap;
+          cursor: pointer;
+          text-align: left;
+          vertical-align: middle;
+          line-height: 1.2em;
+          padding: 0.7em 0;
+        }
+      div#log_filter_log_list td.log-filter-list-no-match {
+        font-weight: bold;
+      }
+      div#log_filter_log_list td.log-filter-list-event-from-url {
+      }
+      div#log_filter_log_list td.log-filter-list-severity {
+        width: 37px; max-width: 37px;
+        padding: 0;
+        background-repeat: no-repeat; background-position: center;
+      }
+      div#log_filter_log_list td.log-filter-list-severity.log-filter-list-info {
+        background-image: url("img/log-16-info.png");
+      }
+      div#log_filter_log_list td.log-filter-list-severity.log-filter-list-notice {
+        background-image: url("img/log-16-notice.png");
+      }
+      div#log_filter_log_list td.log-filter-list-severity.log-filter-list-warning {
+        background-image: url("img/log-16-warning.png");
+      }
+      div#log_filter_log_list td.log-filter-list-severity.log-filter-list-error {
+        background-image: url("img/log-16-error.png");
+      }
+      div#log_filter_log_list td.log-filter-list-severity.log-filter-list-critical {
+        background-image: url("img/log-16-critical.png");
+      }
+      div#log_filter_log_list td.log-filter-list-severity.log-filter-list-alert {
+        background-image: url("img/log-16-alert.png");
+      }
+      div#log_filter_log_list td.log-filter-list-severity.log-filter-list-emergency {
+        background-image: url("img/log-16-emergency.png");
+      }
+      div#log_filter_log_list td.log-filter-list-time {
+        white-space: nowrap;
+      }
+      div#log_filter_log_list td.log-filter-list-message > div {
+        white-space: nowrap;
+        overflow: hidden;
+      }
+
+div.log-filter-log-display-dialog {
+  box-shadow:0px 2px 5px #555;
+}
+  div.log-filter-log-display-dialog a.ui-dialog-titlebar-close,
+  div.log-filter-log-display-dialog button.ui-dialog-titlebar-close {
+    width: 33%;
+    background-color: #C8C9C5;
+  }
+  div.log-filter-log-display-dialog a.ui-dialog-titlebar-close:hover,
+  div.log-filter-log-display-dialog a.ui-dialog-titlebar-close:focus,
+  div.log-filter-log-display-dialog button.ui-dialog-titlebar-close:hover,
+  div.log-filter-log-display-dialog button.ui-dialog-titlebar-close:focus {
+    padding: 1px;
+    opacity:0.7; -ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=70)'; filter:alpha(opacity=70);
+  }
+    div.log-filter-log-display-dialog a.ui-dialog-titlebar-close:after,
+    div.log-filter-log-display-dialog button.ui-dialog-titlebar-close:after {
+      /*clearfix*/clear:both;content:".";display:block;height:0;visibility:hidden;font-size:0;
+    }
+    div.log-filter-log-display-dialog a.ui-dialog-titlebar-close > span,
+    div.log-filter-log-display-dialog button.ui-dialog-titlebar-close > span {
+      float: right;
+    }
+  div.log-filter-log-display {
+    overflow: auto;
+  }
+    div.log-filter-log-display > table.dblog-event {
+      margin: 0;
+    }
+        div.log-filter-log-display > table.dblog-event th {
+          width: 5em;
+        }
+        div.log-filter-log-display > table.dblog-event td div.log-filter-log-display-severity {
+          display: inline-block;
+          width: 37px;
+          margin-left: 1em;
+          background-repeat: no-repeat; background-position: left;
+        }
+        div.log-filter-log-display > table.dblog-event td div.log-filter-log-display-info {
+          background-image: url("img/log-16-info.png");
+        }
+        div.log-filter-log-display > table.dblog-event td div.log-filter-log-display-notice {
+          background-image: url("img/log-16-notice.png");
+        }
+        div.log-filter-log-display > table.dblog-event td div.log-filter-log-display-warning {
+          background-image: url("img/log-16-warning.png");
+        }
+        div.log-filter-log-display > table.dblog-event td div.log-filter-log-display-error {
+          background-image: url("img/log-16-error.png");
+        }
+        div.log-filter-log-display > table.dblog-event td div.log-filter-log-display-critical {
+          background-image: url("img/log-16-critical.png");
+        }
+        div.log-filter-log-display > table.dblog-event td div.log-filter-log-display-alert {
+          background-image: url("img/log-16-alert.png");
+        }
+        div.log-filter-log-display > table.dblog-event td div.log-filter-log-display-emergency {
+          background-image: url("img/log-16-emergency.png");
+        }

File diff suppressed because it is too large
+ 0 - 0
sites/all/modules/contrib/admin/log_filter/css/log_filter.min.css


File diff suppressed because it is too large
+ 2 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery-ui-i18n.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-af.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-ar-DZ.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-ar.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-az.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-bg.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-bs.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-ca.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-cs.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-cy-GB.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-da.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-de.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-el.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-en-AU.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-en-GB.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-en-NZ.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-en.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-eo.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-es.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-et.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-eu.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-fa.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-fi.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-fo.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-fr-CH.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-fr.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-gl.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-he.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-hi.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-hr.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-hu.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-hy.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-id.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-is.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-it.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-ja.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-ka.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-kk.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-km.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-ko.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-lb.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-lt.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-lv.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-mk.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-ml.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-ms.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-nl-BE.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-nl.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-no.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-pl.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-pt-BR.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-pt.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-rm.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-ro.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-ru.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-sk.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-sl.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-sq.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-sr-SR.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-sr.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-sv.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-ta.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-th.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-tj.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-tr.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-uk.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-vi.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-zh-CN.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-zh-HK.min.js


File diff suppressed because it is too large
+ 4 - 0
sites/all/modules/contrib/admin/log_filter/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-zh-TW.min.js


+ 2932 - 0
sites/all/modules/contrib/admin/log_filter/js/log_filter.js

@@ -0,0 +1,2932 @@
+/**
+ * @file
+ *  Drupal Log Filter module
+ */
+
+
+/*jslint browser: true, continue: true, indent: 2, newcap: true, nomen: true, plusplus: true, regexp: true, white: true, ass: true*/
+/*global alert: false, confirm: false, console: false*/
+/*global jQuery: false, Drupal: false, inspect: false, Judy: false*/
+
+/**
+ * @param {function} $
+ * @returns {object}
+ */
+(function($) {
+  'use strict';
+
+  /**
+   * Singleton, instantiated to itself.
+   * @constructor
+   * @namespace
+   * @name LogFilter
+   * @singleton
+   * @param {function} $
+   */
+  var LogFilter = function($) {
+    /**
+     * @ignore
+     * @private
+     * @type {LogFilter}
+     */
+    var self = this,
+    /**
+     * @ignore
+     * @private
+     * @type {string}
+     */
+    _name = "LogFilter",
+    /**
+     * @ignore
+     * @private
+     * @type {object}
+     */
+    _errorCodes = {
+      unknown: 1,
+      //  Programmatic errors and wrong use of program.
+      algo: 100,
+      use: 101,
+      //  Missing permission.
+      perm_general: 200,
+      form_expired: 201,
+      perm_filter_crud: 202,
+      perm_filter_restricted: 203,
+      //  Database.
+      db_general: 500,
+      //  Misc.
+      filter_name_composition: 1001,
+      filter_name_nonunique: 1002,
+      filter_doesnt_exist: 1003,
+      bad_filter_condition: 1010
+    },
+    /**
+     * @ignore
+     * @private
+     * @type {object}
+     */
+    _ = {
+      //  {arr}
+      errors: [],
+      dateFormat: "YYYY-MM-DD",
+      dateFormat_datepicker: "yy-mm-dd",
+      mode: "default", // default | adhoc | stored | create | edit | delete_filter
+      modePrevious: "default",
+      name: "",
+      origin: "",
+      crudFilters: false,
+      recordedValues: { // For some fields (having pattern validation) we have to record last value to safely detect change.
+        time_range: "",
+        uid: "",
+        hostname: "",
+        location: "",
+        referer: "",
+        orderBy: [],
+        type_options: []
+      },
+      deleteLogs_allowed: false,
+      saveEditFilterAjaxed: false, // Save/update filter using AJAX or ordinary POST request?
+      listMessageTruncate: 250,
+      adminOverlayOffset: 80, // Module Overlay.
+      currentOffset: 0,
+      currentMax: 100,
+      logs: {},
+      library_judy_version: 2.1,
+      library_judy_compatible: true
+    },
+    /**
+     * @ignore
+     * @private
+     * @type {array}
+     */
+    _severity = ['emergency', 'alert', 'critical', 'error', 'warning', 'notice', 'info', 'debug'],
+    /**
+     * @ignore
+     * @private
+     * @type {boolean|undefined}
+     */
+    _submitted,
+    /**
+     * @ignore
+     * @private
+     * @type {boolean|undefined}
+     */
+    _ajaxRequestingBlocking,
+    /**
+     * List of previously used localized labels/messages.
+     *
+     * @ignore
+     * @private
+     * @type {object}
+     */
+    _local = {},
+    /**
+     * @ignore
+     * @private
+     * @type {object}
+     */
+    _selectors = {
+      page: "div#page",
+      form: "form#log-filter-form",
+      settings: {
+        mode: "input[name='log_filter_mode']",
+        onlyOwn: "input[name='log_filter_only_own']",
+        delete_logs_max: "input[name='log_filter_delete_logs_max']", // May not exist.
+        translate: "input[name='log_filter_translate']",
+        pager_range: "input[name='log_filter_pager_range']"
+      },
+      filter: {
+        filter: "select[name='log_filter_filter']",
+        name: "input[name='log_filter_name']", // Hidden.
+        origin: "input[name='log_filter_origin']", // Hidden.
+        name_suggest: "input[name='log_filter_name_suggest']",
+        description: "textarea[name='log_filter_description']",
+        require_admin: "input[name='log_filter_require_admin']" // May not exist.
+      },
+      conditions: {
+        time_range: "input[name='log_filter_time_range']", // For iteration: must go before the other time fields.
+        time_from: "input[name='log_filter_time_from']",
+        time_from_proxy: "input[name='log_filter_time_from_proxy']",
+        time_to: "input[name='log_filter_time_to']",
+        time_to_proxy: "input[name='log_filter_time_to_proxy']",
+        severity_any: "input[name='log_filter_severity[-1]']", // For iteration: must go before severity_some.
+        severity_some: "div#edit-log-filter-severity input:not([name='log_filter_severity[-1]'])", // More elements.
+        type_any: "input[name='log_filter_type_wildcard']", // For iteration: must go before type_proxy.
+        type_some: "textarea[name='log_filter_type']", // For iteration: must go before type_proxy.
+        type_proxy: "div#edit-log-filter-type-proxy input", // We only store the first, because we only need one for getting/setting value.
+        role: "select[name='log_filter_role']", // For iteration: must go before uid.
+        uid: "input[name='log_filter_uid']",
+        username: "input[name='log_filter_username']",
+        hostname: "input[name='log_filter_hostname']",
+        location: "input[name='log_filter_location']",
+        referer: "input[name='log_filter_referer']"
+      },
+      orderBy: {
+        options: "div.filter-orderby select",
+        bools: "div.filter-orderby input[type='checkbox']"
+      },
+      buttons: {
+        //  Not part of filter dialog.
+        submit: "input#edit-submit",
+        update_list: "input[name='log_filter_update_list']",
+        reset: "input[name='log_filter_reset']",
+        //  Filter dialog.
+        create: "input[name='log_filter_create']",
+        edit: "input[name='log_filter_edit']",
+        delete_filter: "input[name='log_filter_delete']",
+        cancel: "input[name='log_filter_cancel']",
+        save: "input[name='log_filter_save']", // Doesnt exist if user isnt permitted to create|edit|save filter.
+        delete_logs_button: "input[name='log_filter_delete_logs_button']"
+      },
+      pager: {
+        first: 'div#log_filter_pager_first',
+        previous: 'div#log_filter_pager_previous',
+        current: 'div#log_filter_pager_current',
+        progress: 'div#log_filter_pager_progress',
+        next: 'div#log_filter_pager_next',
+        last: 'div#log_filter_pager_last'
+      },
+      misc: {
+        title: "#log_filter_title_display"
+      }
+    },
+    _elements = {
+      settings: {},
+      filter: {},
+      conditions: {},
+      orderBy: [], // Array.
+      buttons: {
+        crudFilters: [] // create, edit, delete_filter, cancel, save.
+      },
+      pager: {
+      },
+      misc: {
+      }
+    },
+    /**
+     * @ignore
+     * @private
+     * @type {array}
+     */
+    _filters = [],
+    /**
+     * @ignore
+     * @private
+     * @type {object}
+     */
+    _logs = {},
+
+    //  Declare private methods, to make IDEs list them
+    _errorHandler, _oGet, _toAscii,
+    _textareaRemoveWrapper,
+    _machineNameConvert, _machineNameIllegals, _machineNameValidate,
+    _validateTimeSequence,
+    _url, _submit, _typeProxyHandler, _prepareForm, _setMode, _crudRelay, _changedCriterion, _resetCriteria, _deleteLogs, _filterByEventColumn,
+    _getLogList, _listLogs,
+    _ajaxResponse, _ajaxRequest;
+    /**
+     * @see inspect.errorHandler
+     * @ignore
+     * @private
+     * @param {Error} [error]
+     * @param {mixed} [variable]
+     * @param {object|integer|boolean|string} [options]
+     * @return {void}
+     */
+    _errorHandler = function(error, variable, options) {
+      var u = options, o = {}, t;
+      //  Do nothing, if inspect is the 'no action' type.
+      if(typeof window.inspect === "function" && inspect.tcepsni) {
+        if(typeof inspect.errorHandler === "function") {
+          if(u) {
+            if((t = typeof u) === "string") {
+              o.message = u;
+              o.wrappers = 1; // This function wraps Inspect.errorHandler().
+            }
+            else if(t === "object") {
+              o = u;
+              o.wrappers = !u.wrappers ? 1 : (u.wrappers + 1);
+            }
+            //  Otherwise: ignore; use object argument for options if other properties are needed.
+          }
+          o.category = "log_filter";
+          inspect.errorHandler(error, variable, o);
+        }
+        else {
+          inspect.console("Please update Inspect.");
+        }
+      }
+    };
+    /**
+     * Object/function property getter, Object.hasOwnproperty() alternative.
+     *
+     * @ignore
+     * @param {object} o
+     * @param {string|integer} k0
+     * @param {string|integer} [k1]
+     * @return {mixed}
+     *  - undefined: o not object, or o doesnt have property k0, or the value of o[k1] is undefined; and the same goes if arg k1 is used
+     */
+    _oGet = function(o, k0, k1) {
+      var t = typeof o;
+      return o && (t === "object" || t === "function") && o.hasOwnProperty(k0) ?
+          (k1 === undefined ? o[k0] : (
+              (o = o[k0]) && ((t = typeof o) === "object" || t === "function") && o.hasOwnProperty(k1) ? o[k1] : undefined
+          ) ) : undefined;
+    };
+    _toAscii = function(s) {
+      var ndl = _toAscii.needles, rpl = _toAscii.replacers, le = ndl.length, i, u;
+      if(typeof ndl[0] === "string") { // First time called.
+        u = ndl.concat();
+        for(i = 0; i < le; i++) {
+            ndl[i] = new RegExp("\\u" + Judy.toLeading(u[i].charCodeAt(0).toString(16), 4), "g");
+        }
+      }
+      for(i = 0; i < le; i++) {
+          s = s.replace(ndl[i], rpl[i]);
+      }
+      return s;
+    };
+    /**
+     * Removes parent form-textarea-wrapper div from (non-resizable) textarea, for easier (standard) DOM access.
+     *
+     * @ignore
+     * @param {element} elm
+     * @return {void}
+     */
+    _textareaRemoveWrapper = function(elm) {
+      var jq;
+      if ((jq = $(elm.parentNode)).hasClass("form-textarea-wrapper")) {
+        jq.after( $(elm).remove() );
+        jq.remove();
+      }
+    };
+    _toAscii.needles = [
+      //  iso-8859-1
+  //JSLINT_IGNORE--- jslint unsafe chars,but _toAscii() starts out converting them to \uNNNN regexes.
+      "Ä","Æ","ä","æ","Ö","Ø","ö","ø","Ü","ü","ß","Å","å","À","Á","Â","Ã","à","á","â","ã","Ç","ç","Ð","ð","È","É","Ê","Ë","è","é","ê","ë","Ì","Í","Î","Ï","ì","í","î","ï","Ñ","ñ","Ò","Ó","Ô","Õ","ò","ó","ô","õ","Ù","Ú","Û","ù","ú","û","Ý","ý","ÿ","Þ","þ"
+  //---JSLINT_IGNORE
+    ];
+    _toAscii.replacers = [
+      //  iso-8859-1
+      "Ae","Ae","ae","ae","Oe","Oe","oe","oe","Ue","ue","ss","Aa","aa","A","A","A","A","a","a","a","a","C","c","D","d","E","E","E","E","e","e","e","e","I","I","I","I","i","i","i","i","N","n","O","O","O","O","o","o","o","o","U","U","U","u","u","u","Y","y","y","Th","th"
+    ];
+    /**
+     * @ignore
+     * @return {void}
+     */
+    _machineNameConvert = function() {
+      var v = this.value, rgx = /^[a-z\d_]$/;
+      if(v.length > 1 && !rgx.test(v)) {
+        if(!rgx.test(v = v.toLowerCase())) {
+          if(!rgx.test(v = v.replace(/[ \-]/g, "_"))) {
+            if(!rgx.test(v = _toAscii(v))) {
+              v = v.replace(/[^a-z\d_]/g, "_");
+            }
+          }
+        }
+        this.value = v;
+      }
+    };
+    /**
+     * @ignore
+     * @type {array}
+     */
+    _machineNameIllegals = [
+      "log_filter",
+      "default",
+      "adhoc"
+    ];
+    /**
+     * @ignore
+     * @param {Event|falsy} evt
+     *  - default: falsy (~ use arg elm)
+     * @param {element} [elm]
+     *  - default: falsy (~ use arg value)
+     * @param {string} [value]
+     * @param {boolean} [noFeedback]
+     *  - default: false (~ do pop alert upon validation failure)
+     * @return {boolean}
+     */
+    _machineNameValidate = function(evt, elm, value, noFeedback) {
+      var v = evt ? this.value : (elm ? elm.value : value), le = v.length;
+      if(le < 2 || le > 32 || !/[a-z_]/.test(v.charAt(0)) || !/[a-z\d_]/.test(v) || $.inArray(v.toLowerCase(), _machineNameIllegals) > -1) {
+        if(!noFeedback) {
+          self.Message.set( self.local("error_machine_name_composition", {"!illegals": _machineNameIllegals.join(", ")}), "warning", {
+            modal: true,
+            close: function() {
+              Judy.focus(_elements.filter.name_suggest);
+            }
+          });
+        }
+        return false;
+      }
+      return true;
+    };
+    /**
+     * @ignore
+     * @param {string} nm
+     * @param {boolean} [date]
+     * @return {boolean}
+     */
+    _validateTimeSequence = function(nm, date) {
+      var o = _elements.conditions, v, from = (v = o.time_from.value) ? parseInt(v, 10) : 0, to;
+      if (from && (to = (v = o.time_to.value) ? parseInt(v, 10) : 0) && from > to) {
+        // Date To and From must be allowed to be the same, otherwise user can't enter same date.
+        if (date && $.trim(o.time_to_proxy.value) === $.trim(o.time_from_proxy.value)) {
+          return true;
+        }
+        o[ "time_" + nm ].value = o[ "time_" + nm + "_proxy" ].value = o[ "time_" + nm + "_time" ].value = "";
+        self.Message.set( self.local("invalid_timeSequence_" + nm), "warning", { modal: true });
+        return false;
+      }
+      return true;
+    };
+    /**
+     * @ignore
+     * @param {boolean} [top]
+     *  - default: false (~ use current window's location, not top.location)
+     * @return {string}
+     */
+    _url = function(top) {
+      var loc = (!top ? window : top).location, v;
+      return loc.protocol + "//" + loc.hostname + (!(v = loc.port) ? "" : (":" + v)) + loc.pathname.replace(/\/dblog(\/.+)?$/, "/dblog/log_filter");
+    };
+    /**
+     * @ignore
+     * @return {void}
+     */
+    _submit = function() {
+      var nm = "", elm;
+      if(_submitted) {
+        return;
+      }
+      _submitted = true;
+      switch(_.mode) {
+        case "adhoc":
+          nm = "adhoc";
+          break;
+        case "stored":
+          nm = _.name;
+          break;
+      }
+      // Add filter name to action url.
+      _elements.form.setAttribute(
+        "action",
+        _elements.form.getAttribute("action").replace(/\/dblog(\/[^\?&]+)([\?&].+)?$/, "/dblog/log_filter/" + nm + "$2")
+      );
+      //  Delay; otherwise it may in some situations not submit, presumably because Judy.enable() hasnt finished it's job yet(?).
+      setTimeout(function() {
+        $(_elements.buttons.submit).trigger("click");
+      }, 100);
+    };
+    /**
+     * @ignore
+     * @return {void}
+     */
+    _typeProxyHandler = function() {
+      var v, i;
+      if(this.checked) { // Un-check type_any.
+        _elements.conditions.type_any.checked = false;
+        // Pass value to type_some.
+        if (Judy.arrayIndexOf(v = $.trim(_elements.conditions.type_some.value).split(/\n/), this.value) === -1) {
+          v.push(this.value);
+          _elements.conditions.type_some.value = $.trim(v.join("\n"));
+        }
+      }
+      else {
+        // Remove from hidden type_some.
+        if ((i = Judy.arrayIndexOf(v = $.trim(_elements.conditions.type_some.value).split(/\n/), this.value)) > -1) {
+          v.splice(i, 1);
+          if (v.length) {
+            _elements.conditions.type_some.value = $.trim(v.join("\n"));
+          }
+          else {
+            _elements.conditions.type_some.value = "";
+            _elements.conditions.type_any.checked = "checked";
+          }
+        }
+      }
+      _changedCriterion();
+    };
+    /**
+     * @ignore
+     * @return {void}
+     */
+    _prepareForm = function() {
+      var oSels, oElms, nm, jq, elm, par, aElms, a, le, i, v, nOrderBy, u, elm2, d;
+      try {
+        _elements.page = $(_selectors.page).get(0);
+        _elements.form = $(_selectors.form).get(0);
+        //  Filter; do first because we need references to name and origin.
+        oSels = _selectors.filter;
+        oElms = _elements.filter;
+        for(nm in oSels) {
+          if(oSels.hasOwnProperty(nm) && (elm = (jq = $(oSels[nm])).get(0))) {
+            oElms[nm] = elm;
+            switch(nm) {
+              case "filter":
+                //  Selecting a stored filter means submit form.
+                jq.change(function() {
+                  var v;
+                  _elements.filter.name.value = _.name = v = Judy.fieldValue(this);
+                  _elements.settings.mode.value = _.mode = v ? "stored" : "default";
+                  if(!v) { // default|adhoc
+                    _resetCriteria(null, "default");
+                    return;
+                  }
+                  Judy.overlay(1, false, self.local("wait")); // Transparent.
+                  _submit();
+                });
+                break;
+              case "name_suggest": // May not exist.
+                jq.keyup(_machineNameConvert);
+                break;
+              case "description": // May not exist.
+                _textareaRemoveWrapper(elm); // Remove parent form-textarea-wrapper.
+                jq.change(function() {
+                  var v;
+                  if((v = this.value)) {
+                    this.value = Judy.stripTags(v);
+                  }
+                });
+                break;
+            }
+          }
+        }
+        _.name = _elements.filter.name.value;
+        _.origin = _elements.filter.origin.value;
+        //  Fields; get element references, and fix some issues.
+        //  Settings.
+        oSels = _selectors.settings;
+        oElms = _elements.settings;
+        for(nm in oSels) {
+          if(oSels.hasOwnProperty(nm) && (elm = (jq = $(oSels[nm])).get(0))) {
+            oElms[nm] = elm;
+            switch(nm) {
+              case "mode":
+                //  Get mode.
+                _.mode = elm.value;
+                break;
+              case "onlyOwn": // May not exist.
+                //  Submit if user (un)checks filter_only_own.
+                jq.change(function() {
+                  if(_.mode === "stored") {
+                    _elements.settings.mode.value = "adhoc";
+                    Judy.fieldValue(_elements.filter.filter, null, "");
+                    _elements.filter.origin.value = _.name; // Pass name to origin.
+                    _elements.filter.name.value = "";
+                  }
+                  Judy.overlay(1, false, self.local("wait")); // Transparent.
+                  _submit();
+                });
+                break;
+              case "delete_logs_max": // May not exist.
+                jq.change(function() {
+                  var v = this.value;
+                  if(v !== "") {
+                    if((v = $.trim(v)) !== "" && !/^[1-9]\d*$/.test(v)) {
+                      v = "";
+                    }
+                    this.value = v;
+                  }
+                });
+                break;
+              case "pager_range":
+                _.currentMax = parseInt(elm.value, 10);
+                // Pass value to delete max logs field.
+                if ($(_selectors.buttons.delete_logs_button).get(0)) {
+                  oElms.delete_logs_max.value = _.currentMax;
+                }
+                jq.change(function() {
+                  var v = this.value, n, m;
+                  if(v !== "") {
+                    if((v = $.trim(v)) !== "" && /^\d+$/.test(v)) {
+                      _.currentMax = n = parseInt(v, 10);
+                      if (_.deleteLogs_allowed &&
+                        ((m = _elements.settings.delete_logs_max.value) === '' || (m = parseInt(m, 10)) > n)
+                      ) {
+                        _elements.settings.delete_logs_max.value = n;
+                      }
+                    }
+                    else {
+                      v = "";
+                    }
+                    this.value = v;
+                  }
+                });
+                break;
+            }
+          }
+        }
+        //  Conditions.
+        oSels = _selectors.conditions;
+        oElms = _elements.conditions;
+        for(nm in oSels) {
+          if(oSels.hasOwnProperty(nm) && (elm = (jq = $(oSels[nm])).get(0))) {
+            switch(nm) {
+              case "time_range":
+                oElms[nm] = elm;
+                _.recordedValues[nm] = elm.value;
+                //  Clear time_to and time_from when setting a time_range.
+                jq.change(function() {
+                  var v = this.value, o;
+                  if(v !== "") {
+                    this.value = v = $.trim(v);
+                  }
+                  if(v !== "") {
+                    if(v === "0" || !/^[1-9]\d*$/.test(v)) {
+                      this.value = v = "";
+                    }
+                    else {
+                      if (v.length > 4) {
+                        this.value = v = '9999';
+                      }
+                      (o = _elements.conditions).time_from.value =
+                        o.time_from_proxy.value =
+                        o.time_from_time.value =
+                        o.time_to.value =
+                        o.time_to_proxy.value =
+                        o.time_to_time.value = "";
+                    }
+                  }
+                  if(v !== _.recordedValues.time_range) {
+                    _.recordedValues.time_range = v;
+                    _changedCriterion();
+                  }
+                });
+                break;
+              case "time_from": // Hidden fields.
+              case "time_to":
+                oElms[nm] = elm;
+                break;
+              case "time_from_proxy":
+              case "time_to_proxy":
+                oElms[nm] = elm;
+                u = nm === "time_from_proxy" ? "from" : "to";
+                //  Create time field.
+                jq.after(
+                  "<input class=\"form-text\" type=\"text\" maxlength=\"8\" size=\"8\" value=\"\" name=\"log_filter_time_" + u + "_time\" autocomplete=\"off\" />"
+                );
+                //  Put jQuery UI datepicker on time fields.
+                jq.datepicker({
+                  dateFormat: _.dateFormat_datepicker
+                });
+                //  Refer time field.
+                oElms[ "time_" + u + "_time" ] = elm2 = $("input[name=\'log_filter_time_" + u + "_time\']").get(0);
+                //  Set datepicker and time field values.
+                if((v = _elements.conditions[ u === "from" ? "time_from" : "time_to" ].value) && (v = parseInt(v, 10))) {
+                  jq.datepicker("setDate", d = new Date(v * 1000));
+                  elm2.value = Judy.timeFormat(d);
+                }
+                //  Date proxy field handler.
+                jq.change(function() {
+                  var v, d, nm = this.name.indexOf("from") > 1 ? "from" : "to", r = _elements.conditions[ "time_" + nm ],
+                    rT = _elements.conditions[ "time_" + nm + "_time" ];
+                  if((v = $.trim(this.value)).length) {
+                    if((d = Judy.dateFromFormat(v, _.dateFormat))) {
+                      _.recordedValues.time_range = _elements.conditions.time_range.value = ""; // Clear time_range.
+                      rT.value = Judy.timeFormat(d, rT.value);
+                      r.value = v = Math.floor(d.getTime() / 1000);
+                      //  If time_to, and same as time_from, and no hours/minutes/seconds: make time_to the end of the day.
+                      if(nm === "to" && ("" + v) === _elements.conditions.time_from.value &&
+                        d.getHours() === 0 && d.getMinutes() === 0 && d.getSeconds() === 0
+                      ) {
+                        rT.value = Judy.timeFormat(d, "24");
+                        r.value = Math.floor(d.getTime() / 1000);
+                      }
+                      else {
+                        _validateTimeSequence(nm, true);
+                      }
+                    }
+                    else {
+                      self.Message.set( self.local("invalid_date", {"!date": v, "!format": _.dateFormat}), "warning", { modal: true });
+                      r.value = "";
+                      return; // No change, skip _changedCriterion()
+                    }
+                  }
+                  _changedCriterion();
+                });
+                //  Time field handler.
+                $(elm2).change(function() {
+                  var nm = this.name.indexOf("from") > -1 ? "from" : "to", rD = _elements.conditions[ "time_" + nm ], d;
+                  //  Cant set time when no date.
+                  if(!(d = rD.value)) {
+                    this.value = "";
+                    return;
+                  }
+                  d = new Date(d * 1000);
+                  this.value = Judy.timeFormat(d, this.value);
+                  rD.value = Math.floor(d / 1000);
+                  _validateTimeSequence(nm);
+                  _changedCriterion();
+                });
+                break;
+              case "severity_any":
+                oElms[nm] = elm;
+                //  Un-check specific severities upon checking severity:any.
+                jq.change(function() {
+                  var a = _elements.conditions.severity_some, le = a.length, i, v;
+                  if(this.checked) { // Un-check all severity_some.
+                    for(i = 0; i < le; i++) {
+                      a[i].checked = false;
+                    }
+                  }
+                  else { // If no severity_some, re-check severity_any.
+                    for(i = 0; i < le; i++) {
+                      if(a[i].checked) {
+                        v = true;
+                        break;
+                      }
+                    }
+                    if(!v) {
+                      this.checked = "checked";
+                      return; // No change.
+                    }
+                  }
+                  _changedCriterion();
+                });
+                break;
+              case "severity_some": // More elements.
+                oElms[nm] = jq.get();
+                //  Un-check severity:any upon change in list of severity.
+                jq.change(function() {
+                  var a, le, i, someChecked;
+                  if(this.checked) {
+                    _elements.conditions.severity_any.checked = false;
+                  }
+                  else {
+                    le = (a = _elements.conditions.severity_some).length;
+                    for(i = 0; i < le; i++) {
+                      if(a[i].checked) {
+                        someChecked = true;
+                        break;
+                      }
+                    }
+                    if(!someChecked) {
+                      _elements.conditions.severity_any.checked = "checked";
+                    }
+                  }
+                  _changedCriterion();
+                });
+                break;
+              case "type_any": // check list
+                oElms[nm] = elm;
+                jq.change(function() {
+                  var elm;
+                  if(this.checked) {
+                    _elements.conditions.type_some.value = "";
+                    Judy.fieldValue(_elements.conditions.type_proxy, null, "", "checkboxes");
+                  }
+                  _changedCriterion();
+                });
+                break;
+              case "type_some": // Real name: log_filter_type.
+                oElms[nm] = elm;
+                _textareaRemoveWrapper(elm);
+                elm.value = elm.value.replace(/\r/g, '');
+                break;
+              case "type_proxy": // check list
+                oElms[nm] = elm;
+                // Un-name checklist options, to prevent backend validation error (Illegal choice...).
+                // And make list of all options.
+                $("input[type='checkbox']", par = Judy.ancestor(elm, 'div.form-checkboxes')).each(function() {
+                  this.id = '';
+                  this.setAttribute('name', '');
+                  _.recordedValues.type_options.push(this.value);
+                });
+                // Pass values from type_some (hidden textarea; real name: log_filter_type).
+                Judy.fieldValue(_elements.conditions.type_proxy, _elements.form, $.trim(_elements.conditions.type_some.value).split(/\n/), "checkboxes");
+                jq.change(_typeProxyHandler);
+                // Insert 'Add type' option.
+                $(par).prepend(
+                  '<div class="form-item form-type-checkbox">' +
+                    '<input type="checkbox" class="form-checkbox" value="" name="log_filter_type_proxy_add_item" autocomplete="off" />' +
+                    ' <input type="text" value="" name="log_filter_type_proxy_add_item_value" autocomplete="off" class="form-text" placeholder="' +
+                      self.local('add_type_item') + '" />' +
+                  '</div>'
+                );
+                $('input[name="log_filter_type_proxy_add_item"]', _elements.form).change(function() {
+                  var elm, v;
+                  if (this.checked) {
+                    elm = $('input[name="log_filter_type_proxy_add_item_value"]', _elements.form).get(0);
+                    if ((v = elm.value) && (v = $.trim(Judy.stripTags(v.replace(/[\r\n]/g, ''))))) {
+                      if (Judy.arrayIndexOf(_.recordedValues.type_options, v) === -1) { // IDE may wrongly report error.
+                        _.recordedValues.type_options.push(v);
+                        _elements.conditions.type_some.value += (_elements.conditions.type_some.value ? "\n" : '') + v;
+                        $(elm.parentNode).after(
+                          '<div class="form-item form-type-checkbox">' +
+                            '<input type="checkbox" class="form-checkbox" value="' + v + '" checked="checked" />' +
+                            ' <label class="option">' + v + '</label>' +
+                           '</div>'
+                        );
+                        $('input[value="' + v +'"]', par).change(_typeProxyHandler);
+                        _elements.conditions.type_any.checked = false;
+                      }
+                      else {
+                        self.Message.set(self.local('type_option_dupe', { '!option': v }), "warning", {
+                          modal: true,
+                          close: function() {
+                            Judy.focus(elm);
+                          }
+                        });
+                      }
+                    }
+                    this.checked = false;
+                    elm.value = '';
+                  }
+                });
+                break;
+              case "role":
+                oElms[nm] = elm;
+                //  Clear uid when selecting a role.
+                jq.change(function() {
+                  if(Judy.fieldValue(this)) {
+                    _elements.conditions.uid.value = _elements.conditions.username.value = "";
+                  }
+                  _changedCriterion();
+                });
+                break;
+              case "uid":
+                oElms[nm] = elm;
+                _.recordedValues[nm] = elm.value;
+                //  Clear role when setting a uid.
+                jq.change(function() {
+                  var v = this.value;
+                  if(v !== "") {
+                    this.value = v = $.trim(v);
+                  }
+                  if(v !== "") {
+                    if(!/^\d+$/.test(v)) {
+                      self.Message.set( self.local("invalid_uid"), "warning", {
+                        modal: true,
+                        close: function() {
+                          Judy.focus(_elements.conditions.uid);
+                        }
+                      });
+                      this.value = v = "";
+                    }
+                    else {
+                      // Clear role when setting a uid.
+                      Judy.fieldValue(_elements.conditions.role, null, "");
+                      _elements.conditions.username.value = '';
+                    }
+                  }
+                  // Always clear username when setting uid.
+                  _elements.conditions.username.value = '';
+                  if(v !== _.recordedValues.uid) {
+                    _.recordedValues.uid = v;
+                    _changedCriterion();
+                  }
+                });
+                break;
+              case "username":
+                oElms[nm] = elm;
+                $(elm).autocomplete({
+                  source: "/log_filter/ajax/username_autocomplete",
+                  minLength: 2,
+                  select: function(event, ui) {
+                    var v;
+                    if (ui.item) {
+                      _elements.conditions.uid.value = (v = ui.item.value);
+                      _elements.conditions.username.value = ui.item.label;
+                      if(v !== _.recordedValues.uid) {
+                        _.recordedValues.uid = v;
+                        Judy.fieldValue(_elements.conditions.role, null, ""); // Clear role when setting a uid.
+                        _changedCriterion();
+                      }
+                    }
+                    return false;
+                  }
+                }).bind('autocompletesearch', function() {
+                  $(this).addClass('throbbing');
+                }).bind('autocompleteresponse', function() { // Doesnt work, propably old version of jQuery UI.
+                  $(this).removeClass('throbbing');
+                });
+                Judy.ajaxcomplete(_selectors.conditions.username, '/log_filter/ajax/username_autocomplete', function(event) { // This works, instead.
+                  $(this).removeClass('throbbing');
+                });
+                break;
+              case "hostname":
+                oElms[nm] = elm;
+                _.recordedValues[nm] = elm.value;
+                jq.change(function() {
+                  var v = this.value;
+                  if(v !== "") {
+                    this.value = v = Judy.stripTags(v);
+                  }
+                  if(v !== _.recordedValues.hostname) {
+                    _.recordedValues.hostname = v;
+                    _changedCriterion();
+                  }
+                });
+                break;
+              case "location":
+              case "referer":
+                oElms[nm] = elm;
+                _.recordedValues[nm]= elm.value;
+                //  Check for url pattern.
+                jq.change(function() {
+                  var v = $.trim(this.value), nm = this.name === "log_filter_location" ? "location" : "referer"; // Not the same nm as iteration nm ;-)
+                  if(nm === "referer" && (v === "none" || v === "<none>")) {
+                    this.value = "none";
+                  }
+                  else {
+                    if(v !== "") {
+                      this.value = v = Judy.stripTags(v);
+                    }
+                    if(v !== "" && v !== "*" && !/^https?:\/\/.+$/.test(v)) {
+                      if(!/^https?:\/\/.+$/.test(v = "http://" + v)) {
+                        self.Message.set( self.local(nm === "location" ? "invalid_location" : "invalid_referer"), "warning", {
+                            modal: true,
+                            close: function() {
+                              Judy.focus(_elements.conditions[ nm ]);
+                            }
+                        });
+                        this.value = v = "";
+                      }
+                      else {
+                        this.value = v;
+                      }
+                    }
+                  }
+                  if(v !== _.recordedValues[nm]) {
+                    _.recordedValues[nm] = v;
+                    _changedCriterion();
+                  }
+                });
+                break;
+              default:
+                oElms[nm] = elm;
+                jq.change(_changedCriterion); // Criterion change handler.
+            }
+          }
+        }
+        //  Order by.
+        oElms = _elements.orderBy; // Array.
+        if((nOrderBy = (aElms = $(_selectors.orderBy.options).get()).length)) {
+          for(i = 0; i < nOrderBy; i++) {
+            oElms.push(
+              [ elm = aElms[i] ]
+            );
+            _.recordedValues.orderBy.push(Judy.fieldValue(elm));
+            //  There can't be two orderBys having same value.
+            $(elm).change(function() {
+              var v, index, i, a;
+              if((v = Judy.fieldValue(this)) && v !== "_none") {
+                index = parseInt(this.name.replace(/^log_filter_orderby_/, ""), 10) - 1;
+                a = _elements.orderBy;
+                for(i = 0; i < nOrderBy; i++) {
+                  if(i !== index && Judy.fieldValue(a[i][0]) === v) {
+                    Judy.fieldValue(this, null, v = "");
+                    break;
+                  }
+                }
+              }
+              if(v !== _.recordedValues.orderBy[index]) {
+                _.recordedValues.orderBy[index] = v;
+                _changedCriterion();
+              }
+            });
+          }
+          if((le = (aElms = $(_selectors.orderBy.bools).get()).length)) {
+            for(i = 0; i < le; i++) {
+              oElms[i].push(
+                elm = aElms[i]
+              );
+              $(elm).change(_changedCriterion);
+            }
+          }
+        }
+
+        //  Miscellaneous.
+        oSels = _selectors.pager;
+        oElms = _elements.pager;
+        for(nm in oSels) {
+          if(oSels.hasOwnProperty(nm) && (elm = (jq = $(oSels[nm])).get(0))) {
+            oElms[nm] = elm;
+            switch(nm) {
+              case "first":
+                jq.click(function() {
+                  _ajaxRequestingBlocking = true; // Prevent consecutive clicks on update buttons.
+                  _getLogList(0, 0);
+                });
+                break;
+              case "previous":
+                jq.click(function() {
+                  _ajaxRequestingBlocking = true; // Prevent consecutive clicks on update buttons.
+                  _getLogList(0, (v = _.currentOffset - _.currentMax) > 0 ? v : 0);
+                });
+                break;
+              case "current":
+                jq.click(function() {
+                  _ajaxRequestingBlocking = true; // Prevent consecutive clicks on update buttons.
+                  _getLogList();
+                });
+                break;
+              case "next":
+                jq.click(function() {
+                  _ajaxRequestingBlocking = true; // Prevent consecutive clicks on update buttons.
+                  _getLogList(0, _.currentOffset + _.currentMax);
+                });
+                break;
+              case "last":
+                jq.click(function() {
+                  _ajaxRequestingBlocking = true; // Prevent consecutive clicks on update buttons.
+                  _getLogList(0, -1);
+                });
+                break;
+            }
+          }
+        }
+
+        //  Miscellaneous.
+        oSels = _selectors.misc;
+        oElms = _elements.misc;
+        for(nm in oSels) {
+          if(oSels.hasOwnProperty(nm) && (elm = (jq = $(oSels[nm])).get(0))) {
+            oElms[nm] = elm;
+          }
+        }
+
+        //  Buttons; get element references, and fix some issues.
+        oSels = _selectors.buttons;
+        oElms = _elements.buttons;
+        for(nm in oSels) {
+          if(oSels.hasOwnProperty(nm) && (elm = (jq = $(oSels[nm])).get(0))) {
+            switch(nm) {
+              case "submit":
+                //  Hidden, but we do submit by triggering a click on it anyway, in case Form API sets some javascript behaviour on it.
+                //  ...jQuery behaviour, really. Because a jQuery(elm).trigger("click") apparantly doesnt trigger a real click event(?).
+                oElms[nm] = elm;
+                break;
+              case "update_list":
+                oElms[nm] = elm;
+                elm.setAttribute("type", "button");
+                jq.unbind(); // Remove Drupal native button handlers.
+                jq.click(function() {
+                  _ajaxRequestingBlocking = true; // Prevent consecutive clicks on update buttons.
+                  _getLogList();
+                });
+                Judy.keydown(document.documentElement, "ctr+u cmd+u", function(event) {
+                  event.preventDefault();
+                  _ajaxRequestingBlocking = true; // Prevent consecutive clicks on update buttons.
+                  _getLogList();
+                });
+                break;
+              default:
+                oElms[nm] = elm;
+                elm.setAttribute("type", "button"); // Fix type (apparant Form API shortcoming).
+                jq.unbind(); // Remove Drupal native button handlers.
+                switch(nm) {
+                  case "create":
+                  case "edit":
+                  case "delete_filter":
+                  case "cancel":
+                  case "save":
+                    _.crudFilters = true;
+                    oElms.crudFilters.push(elm);
+                    jq.click(_crudRelay); // Set our common button handler.
+                    break;
+                  case "delete_logs_button":
+                    _.deleteLogs_allowed = true;
+                    Judy.disable(elm, null, self.local("deleteLogs_prohibit"));
+                    jq.click(_crudRelay); // Set our common button handler.
+                    break;
+                  case "reset":
+                    jq.click(_resetCriteria);
+                    break;
+                }
+            }
+          }
+        }
+
+        //  Prevent click on hover title label span from resulting in checking/unchecking checkbox.
+        $("label span").click(function(evt) {
+          evt.stopPropagation();
+          return false;
+        });
+      }
+      catch(er) {
+        _errorHandler(er, 0, _name + "._prepareForm()");
+      }
+    };
+
+    self.inspector = function(u) {
+      inspect(u, {wrappers:1});
+    };
+
+    /**
+     * Sets current mode.
+     *
+     * Values:
+     * - default
+     * - adhoc
+     * - stored
+     * - create
+     * - edit
+     * - delete
+     *
+     * @ignore
+     * @param {string} mode
+     * @param {boolean} [submit]
+     * @param {boolean} [initially]
+     * @return {void}
+     */
+    _setMode = function(mode, submit, initially) {
+      var fromMode = _.mode, doSubmit, elm, nm;
+      try {
+        if(_submitted) {
+          return;
+        }
+        if(!initially && mode !== "delete_filter") {
+          if(!submit && _.crudFilters) {
+            //  Hide all filter buttons.
+            $(_elements.buttons.crudFilters).hide();
+          }
+        }
+        switch(mode) {
+          case "default":
+            $("option[value='']", _elements.filter.filter).html( self.local("default") ); // Set visual value of filter selector's empty option.
+            $(_elements.misc.title).html(self.local("default"));
+            if(!initially) {
+              Judy.fieldValue(_elements.filter.filter, null, "");
+              _elements.filter.name.value = _.name = _elements.filter.origin.value = _.origin = "";
+            }
+            if(_.crudFilters) {
+              $(_elements.settings.onlyOwn.parentNode).show();
+              $(_elements.buttons.create).show();
+              if ((elm = _elements.filter.require_admin)) {
+                $(elm.parentNode).hide();
+              }
+              $(_elements.filter.name_suggest.parentNode).hide();
+              $(_elements.filter.description.parentNode).hide();
+            }
+            if(_.deleteLogs_allowed) {
+              $(_elements.settings.delete_logs_max).show();
+              $(elm = _elements.buttons.delete_logs_button).show();
+              $(elm.parentNode).show();
+            }
+            if(fromMode === "create") {
+              fromMode = ""; // Dont keep 'create' as _.modePrevious.
+            }
+            break;
+          case "adhoc":
+            if(!initially) {
+              Judy.fieldValue(_elements.filter.filter, null, "");
+            }
+            if(fromMode === "stored") {
+              //  Pass current name to origin field.
+              _elements.filter.origin.value = _.origin = nm = _.name;
+              _elements.filter.name.value = _.name = "";
+              $("option[value='']", _elements.filter.filter).html("(" + nm + ")"); // Set visual value of filter selector's empty option.
+              $(_elements.misc.title).html( self.local("adhocForOrigin", {"!origin": nm} ) );
+            }
+            else {
+              fromMode = ""; // Dont keep 'create' as _.modePrevious.
+              $("option[value='']", _elements.filter.filter).html(self.local("adhoc")); // Set visual value of filter selector's empty option.
+              $(_elements.misc.title).html(self.local("adhoc"));
+            }
+            if(_.crudFilters) {
+              $(_elements.settings.onlyOwn.parentNode).show();
+              $(_elements.buttons.create).show();
+              if ((elm = _elements.filter.require_admin)) {
+                $(elm.parentNode).hide();
+              }
+              $(_elements.filter.name_suggest.parentNode).hide();
+              $(_elements.filter.description.parentNode).hide();
+            }
+            if(_.deleteLogs_allowed) {
+              $(_elements.settings.delete_logs_max).show();
+              $(elm = _elements.buttons.delete_logs_button).show();
+              $(elm.parentNode).show();
+            }
+            break;
+          case "stored": // stored mode may only appear on page load and after cancelling create.
+            if(!initially) {
+              if(fromMode === "create") {
+                _elements.filter.name.value = _.name = _.origin;
+                _elements.filter.origin.value = _.origin = "";
+              }
+              Judy.fieldValue(elm = _elements.filter.filter, null, nm = _.name);
+              $("option[value='']", elm).html( self.local("default") ); // Set visual value of filter selector's empty option.
+              $(_elements.misc.title).html( nm );
+              if(_.crudFilters) {
+                if ((elm = _elements.filter.require_admin)) {
+                  $(elm.parentNode).hide();
+                }
+                $(_elements.filter.name_suggest.parentNode).hide();
+                $(_elements.filter.description.parentNode).hide();
+              }
+            }
+            if(_.crudFilters) {
+              $(_elements.settings.onlyOwn.parentNode).show();
+              $(_elements.buttons.create).show();
+              $(_elements.buttons.edit).show();
+              $(_elements.buttons.delete_filter).show();
+            }
+            if(_.deleteLogs_allowed) {
+              $(_elements.settings.delete_logs_max).show();
+              $(elm = _elements.buttons.delete_logs_button).show();
+              $(elm.parentNode).show();
+            }
+            switch(fromMode) {
+              case "create":
+              case "edit":
+                fromMode = "stored"; // Dont keep 'create' as _.modePrevious.
+                break;
+            }
+            break;
+          case "create":
+            if(!_.crudFilters) {
+              throw new Error("Mode[" + mode + "] not allowed.");
+            }
+            switch(fromMode) {
+              case "default":
+              case "adhoc":
+                $("option[value='']", _elements.filter.filter).html("(" + self.local("newName") + ")"); // Set visual value of filter selector's empty option.
+                $(_elements.misc.title).html( self.local("newTitle") );
+                break;
+              case "stored":
+                Judy.fieldValue(_elements.filter.filter, null, "");
+                //  Pass current name to origin field.
+                _elements.filter.origin.value = _.origin = nm = _.name;
+                _elements.filter.name.value = _.name = "";
+                $("option[value='']", _elements.filter.filter).html("(" + nm + ")"); // Set visual value of filter selector's empty option.
+                $(_elements.misc.title).html( self.local("newForOrigin", {"!origin": nm} ) );
+                break;
+              default:
+                throw new Error("Cant create from mode[" + fromMode + "].");
+            }
+            $(_elements.settings.onlyOwn.parentNode).hide();
+            $(_elements.filter.name_suggest.parentNode).show();
+            if ((elm = _elements.filter.require_admin)) {
+              $(elm.parentNode).show();
+            }
+            $(_elements.filter.description.parentNode).show();
+            $(_elements.buttons.save).show();
+            $(_elements.buttons.cancel).show();
+            if(_.deleteLogs_allowed) {
+              $(_elements.buttons.delete_logs_button.parentNode).hide();
+            }
+            break;
+          case "edit":
+            if(!_.crudFilters) {
+              throw new Error("Mode[" + mode + "] not allowed.");
+            }
+            if(fromMode === "create") {
+              //  If going from create to edit: memorize mode right before create, to prevent ending up having (useless) create as previous mode.
+              fromMode = _.modePrevious;
+              $("option[value='']", elm = _elements.filter.filter).after(
+                "<option value=\"" + (nm = _.name) + "\">" + nm + "</option>"
+              );
+              $("option[value='']", elm).html( self.local("default") );
+              Judy.fieldValue(elm, null, nm);
+            }
+            if ((elm = _elements.filter.require_admin)) {
+              $(elm.parentNode).show();
+            }
+            $(_elements.filter.name_suggest.parentNode).hide();
+            $(_elements.filter.description.parentNode).show();
+            $(_elements.buttons.cancel).show();
+            $(_elements.buttons.save).show();
+            $(_elements.settings.onlyOwn.parentNode).hide();
+            if(_.deleteLogs_allowed) {
+              $(_elements.buttons.delete_logs_button.parentNode).hide();
+            }
+            break;
+          case "delete_filter": // Pop confirm(), and submit upon positive confirmation.
+            if(!_.crudFilters) {
+              throw new Error("Mode[" + mode + "] not allowed.");
+            }
+            Judy.overlay(1, true); // Opaque.
+            if (_elements.filter.name.value) {
+              if(!confirm( self.local(
+                "confirmDelete",
+                {"!filter": _elements.filter.name.value}
+              ))) {
+                Judy.overlay(0);
+                return;
+              }
+              doSubmit = true;
+              Judy.overlay(1, false, self.local("wait")); // Transparent.
+            }
+            else {
+              throw new Error("Cant delete filter having empty name[" + _elements.filter.name.value + "].");
+            }
+            break;
+          default:
+            throw new Error("Mode[" + mode + "] not supported.");
+        }
+        _.modePrevious = fromMode;
+        _elements.settings.mode.value = _.mode = mode;
+        if(submit || doSubmit) {
+          _submit();
+        }
+      }
+      catch(er) {
+        _errorHandler(er, 0, _name + "._setMode()");
+      }
+    };
+    /**
+     * Common handler for all CRUD buttons.
+     *
+     * @ignore
+     * @return {boolean}
+     */
+    _crudRelay = function() {
+      var nm = this.name, // The element's name, not _.name.
+        elm, v, rqa;
+      try {
+        switch(nm) {
+          case "log_filter_reset":
+            _resetCriteria();
+            break;
+          case "log_filter_create":
+            _setMode("create");
+            Judy.focus(_elements.filter.name_suggest);
+            break;
+          case "log_filter_edit":
+            _setMode("edit");
+            break;
+          case "log_filter_delete":
+            _setMode("delete_filter");
+            break;
+          case "log_filter_cancel":
+            switch(_.mode) {
+              case "create":
+              case "edit":
+                switch(_.modePrevious) {
+                  case "default":
+                  case "adhoc":
+                    break;
+                  case "stored":
+                    break;
+                  default:
+                    throw new Error("Previous mode[" + _.modePrevious + "] not supported when cancelling.");
+                }
+                _setMode(_.modePrevious);
+                break;
+              default:
+                throw new Error("Cant cancel in mode[" + _.mode + "].");
+            }
+            break;
+          case "log_filter_save":
+            if(_.mode === "edit" && !_.saveEditFilterAjaxed) {
+              Judy.overlay(1, false, self.local("wait_" + _.mode));
+              _submit();
+              return false;
+            }
+            else {
+              //  Prevent double-click.
+              if(_ajaxRequestingBlocking) {
+                return false; // false for IE<9's sake.
+              }
+              if(_.mode === "create") {
+                //  No reason to trim(), because change handler (_machineNameChange()) replaces spaces with underscores.
+                if(!_machineNameValidate(null, null, v = (elm = _elements.filter.name_suggest).value)) {
+                  Judy.focus(elm);
+                  return false; // false for IE<9's sake.
+                }
+                if($.inArray(v, _filters) > -1) {
+                  Judy.overlay(1, true);
+                  if (!confirm(self.local("error_filter_name_nonunique", {"!name": v}))) {
+                    Judy.overlay(0);
+                    return false;
+                  }
+                  else {
+                    Judy.overlay(1, false, self.local("wait_edit"));
+                    _elements.settings.mode.value = _.mode = "edit";
+                    _elements.filter.name.value = v;
+                    _submit();
+                    return false;
+                  }
+                }
+                nm = v;
+                rqa = _elements.filter.require_admin ? 1 : 0; // Create with require_admin if the element exists (the user has the permission).
+              }
+              else {
+                nm = _.name;
+                rqa = (elm = _elements.filter.require_admin) && Judy.fieldValue(elm);
+              }
+              Judy.overlay(1, false, self.local("wait_" + _.mode));
+              _ajaxRequestingBlocking = true;
+              v = self.getCriteria();
+              _ajaxRequest("filter_" + _.mode, { // filter_create|filter_edit
+                name: nm,
+                filter: {
+                  require_admin: rqa,
+                  description: $.trim(Judy.stripTags(_elements.filter.description.value).replace(/[\r\n\t]/g, " ").replace(/\ +/g, " ")).substr(0, 255)
+                },
+                conditions: v.conditions,
+                order_by: v.order_by
+              });
+            }
+            break;
+          case "log_filter_delete_logs_button":
+            if(_.deleteLogs_allowed) {
+              Judy.overlay(1, false, self.local("wait"));
+              setTimeout(_deleteLogs, 200);
+            }
+            else {
+              throw new Error("Button name[" + nm + "] not allowed.");
+            }
+            break;
+          default:
+            throw new Error("Unsupported button name[" + nm + "].");
+        }
+      }
+      catch(er) {
+        _errorHandler(er, 0, _name + "._crudRelay()");
+      }
+      return false; // false for IE<9's sake.
+    };
+    /**
+     * Change handler for all condition and orderBy fields.
+     *
+     * @ignore
+     * @return {void}
+     */
+    _changedCriterion = function() {
+      if(_.deleteLogs_allowed) {
+        Judy.disable(_elements.buttons.delete_logs_button, null, self.local("deleteLogs_prohibit"));
+      }
+      try {
+        switch(_.mode) {
+          case "default":
+            _setMode("adhoc");
+            break;
+          case "adhoc":
+            break;
+          case "stored":
+            //  A change of a stored filter triggers edit mode if the user is allowed to edit filters.
+            _setMode(!_.crudFilters ? "adhoc" : "edit");
+            break;
+          case "create":
+            break;
+          case "edit":
+            break;
+          case "delete_filter":
+            break;
+          default:
+            throw new Error("Mode[" + _.mode + "] not supported.");
+        }
+      }
+      catch(er) {
+        _errorHandler(er, 0, _name + "._changedCriterion()");
+      }
+    };
+    /**
+     * Clear all condition and orderby fields, and set defaults.
+     *
+     * @ignore
+     * @param {Event} [evt]
+     *  - when used as event handler
+     * @param {string|falsy} [mode]
+     *  - set mode to that
+     * @param {boolean} [noModeChange]
+     *  - do not change mode
+     * @return {void}
+     */
+    _resetCriteria = function(evt, mode, noModeChange) {
+      var o = _elements.conditions, nm, r, a, le, i;
+      if(_.deleteLogs_allowed) {
+        Judy.disable(_elements.buttons.delete_logs_button, null, self.local("deleteLogs_prohibit"));
+      }
+      for(nm in o) {
+        if(o.hasOwnProperty(nm)) {
+          r = o[nm];
+          //  Default to severity any and type any.
+          switch(nm) {
+            case "severity_any":
+            case "type_any":
+              r.checked = true;
+              break;
+            case "severity_some": // Array.
+              le = r.length;
+              for(i = 0; i < le; i++) {
+                r[i].checked = false;
+              }
+              break;
+            case "type_proxy":
+              if(r) { // Doesnt exists if no logs at all.
+                Judy.fieldValue(r, null, "", "checkboxes");
+              }
+              break;
+            default:
+              r.value = "";
+          }
+        }
+      }
+      le = (a = _elements.orderBy).length;
+      //  Default to order by time ascending, only.
+      for(i = 0; i < le; i++) {
+        Judy.fieldValue(a[i][0], null, i ? "" : "time");
+        a[i][1].checked = i ? false : "checked";
+      }
+      if(!noModeChange) {
+        //  Degrade mode.
+        if(mode) {
+          _setMode(mode);
+        }
+        else {
+          _setMode("default");
+        }
+      }
+    };
+    /**
+     * @ignore
+     * @return {void}
+     */
+    _deleteLogs = function() {
+      var o = self.getCriteria(), v, offset = _.currentOffset, max = (v = _elements.settings.delete_logs_max.value) !== "" ? parseInt(v) : 0;
+      if(!o.nConditions) { // Even stored filters go here; if a stored filter has no conditions, than THAT is the important thing.
+        //  We warn every time, when no conditions at all.
+        if(!max) {
+          if (!offset) {
+            if(!confirm( self.local("deleteLogs_all") )) {
+              Judy.overlay(0);
+              Judy.focus(_elements.settings.delete_logs_max);
+              return;
+            }
+          }
+          else if(!confirm( self.local("deleteLogs_noMax", {"!offset": offset}) )) {
+            Judy.overlay(0);
+            Judy.focus(_elements.settings.delete_logs_max);
+            return;
+          }
+        }
+        else if (!offset) {
+          if(!confirm( self.local("deleteLogs_noOffset", {"!max": max}) )) {
+            Judy.overlay(0);
+            Judy.focus(_elements.settings.delete_logs_max);
+            return;
+          }
+        }
+        else if(!confirm( self.local("deleteLogs_noConditions", {"!offset": offset, "!max": max}) )) {
+          Judy.overlay(0);
+          Judy.focus(_elements.settings.delete_logs_max);
+          return;
+        }
+      }
+      else if(_.mode === "stored") {
+        if(!max) {
+          if (!offset) {
+            if(!confirm( self.local("deleteLogs_storedAll", {"!name": _.name}) )) {
+              Judy.overlay(0);
+              Judy.focus(_elements.settings.delete_logs_max);
+              return;
+            }
+          }
+          else if(!confirm( self.local("deleteLogs_storedNoMax", {"!offset": offset, "!name": _.name}) )) {
+            Judy.overlay(0);
+            Judy.focus(_elements.settings.delete_logs_max);
+            return;
+          }
+        }
+        else if (!offset) {
+          if(!confirm( self.local("deleteLogs_storedNoOffset", {"!max": max, "!name": _.name}) )) {
+            Judy.overlay(0);
+            Judy.focus(_elements.settings.delete_logs_max);
+            return;
+          }
+        }
+        else if(!confirm( self.local("deleteLogs_stored", {"!offset": offset, "!max": max, "!name": _.name}) )) {
+          Judy.overlay(0);
+          Judy.focus(_elements.settings.delete_logs_max);
+          return;
+        }
+      }
+      else if(!max) {
+        if (!offset) {
+          if(!confirm( self.local("deleteLogs_adhocAll") )) {
+            Judy.overlay(0);
+            Judy.focus(_elements.settings.delete_logs_max);
+            return;
+          }
+        }
+        else if(!confirm( self.local("deleteLogs_adhocNoMax", {"!offset": offset}) )) {
+          Judy.overlay(0);
+          Judy.focus(_elements.settings.delete_logs_max);
+          return;
+        }
+      }
+      else if (!offset) {
+        if(!confirm( self.local("deleteLogs_adhocNoOffset", {"!max": max}) )) {
+          Judy.overlay(0);
+          Judy.focus(_elements.settings.delete_logs_max);
+          return;
+        }
+      }
+      else if(!confirm( self.local("deleteLogs_adhoc", {"!offset": offset, "!max": max}) )) {
+        Judy.overlay(0);
+        Judy.focus(_elements.settings.delete_logs_max);
+        return;
+      }
+      _ajaxRequestingBlocking = true;
+      v = self.getCriteria();
+      _ajaxRequest("delete_logs", {
+        conditions: v.conditions,
+        order_by: v.order_by,
+        offset: offset,
+        max: max
+      });
+    };
+
+    /**
+     * @ignore
+     * @param {Event} evt
+     * @return {void}
+     */
+    _filterByEventColumn = function(evt) {
+      var that = evt.target, tag, logId, col, log, u, o = _elements.conditions, elm, elm1, v, v1, a, vShow, username;
+      if (evt.type === 'contextmenu') {
+        evt.preventDefault();
+      }
+      // Get out if not td or link within td.
+      switch ((tag = that.tagName || 'none').toLowerCase()) {
+        case 'td':
+          break;
+        case 'a': // User column may contain link.
+          username = $(that).text();
+          that = that.parentNode;
+          break;
+        default:
+          return;
+      }
+      // The td must have column attribute.
+      if (!(col = that.getAttribute('log_filter_list_event_column'))) {
+        return;
+      }
+      // Parent tr must have a log id attribute, and the log must exist.
+      if (!(logId = that.parentNode.getAttribute('log_filter_list_event_id')) ||
+        !(log = _logs['_' + logId]) || !_logs.hasOwnProperty('_' + logId)
+      ) {
+        return;
+      }
+
+      switch (col) {
+        case 'severity':
+          vShow = self.local(_severity[ log.severity ]);
+          v = log.severity || 'zero';
+          if ((a = Judy.fieldValue(elm = o.severity_some, _elements.form, undefined, 'checklist'))) {
+            a.push(v);
+            v = a;
+          }
+          Judy.fieldValue(elm, _elements.form, v, 'checklist');
+          $(elm).trigger('change');
+          break;
+        case 'type':
+          // If no such option exists yet: add it.
+          if (Judy.arrayIndexOf(_.recordedValues.type_options, v = log.type) === -1) {
+            $('input[name="log_filter_type_proxy_add_item_value"]', _elements.form).val(v);
+            $('input[name="log_filter_type_proxy_add_item"]', _elements.form).get(0).checked = 'checked';
+            $('input[name="log_filter_type_proxy_add_item"]', _elements.form).trigger('change');
+          }
+          else {
+            if ((a = Judy.fieldValue(elm = o.type_proxy, _elements.form, undefined, 'checklist'))) {
+              a.push(v);
+              v = a;
+            }
+            Judy.fieldValue(elm, _elements.form, v, 'checklist');
+            $('div#edit-log-filter-type-proxy input[value="' + v + '"]').trigger('change');
+          }
+          vShow = v;
+          break;
+        case 'time': // Time: right-click/f means Time From, shift+f means Time To.
+          u = evt.type === 'keydown' && evt.keystrokes !== 'f' ? 'time_to' : 'time_from';
+          (elm = o[u + '_proxy']).value = v = log.time.substr(0, 10);
+          $(elm).trigger('change');
+          (elm1 = o[u + '_time']).value = v1 = log.time.substr(11);
+          $(elm1).trigger('change');
+          if (elm.value !== v || elm1.value !== v1) {
+            return; // Dont set message.
+          }
+          col = u; // For Message.
+          vShow = log.time;
+          break;
+        default:
+          (elm = o[col]).value = vShow = v = log[col];
+          $(elm).trigger('change');
+          if (col === 'uid' && username) {
+            _elements.conditions.username.value = username;
+          }
+      }
+      self.Message.set( self.local("filtered_event_column", { '!column': self.local('log_' + col), '!value': vShow }), "info");
+    };
+
+    /**
+     * @ignore
+     * @param {integer} [wid]
+     *  - for single log view
+     * @param {integer|undefined} [offset]
+     *  - default: current offset
+     *  - minus one means last
+     * @return {void}
+     */
+    _getLogList = function(wid, offset) {
+      var v = self.getCriteria();
+      Judy.overlay(1, false, self.local("wait"));
+      if(wid) {
+        v.conditions = {
+          wid: wid
+        };
+        offset = 0;
+      }
+      _ajaxRequest("list_logs", {
+        conditions: v.conditions,
+        order_by: v.order_by,
+        offset: offset || offset === 0 ? offset : _.currentOffset,
+        max: _.currentMax,
+        translate: Judy.fieldValue(_elements.settings.translate)
+      });
+      $(_elements.pager.first).addClass("log-filter-pager-button-disabled");
+      $(_elements.pager.previous).addClass("log-filter-pager-button-disabled");
+      $(_elements.pager.current).hide();
+      $(_elements.pager.progress).show();
+      $(_elements.pager.next).addClass("log-filter-pager-button-disabled");
+      $(_elements.pager.last).addClass("log-filter-pager-button-disabled");
+    };
+
+    /**
+     * @ignore
+     * @param {array} logs
+     * @param {object} conditions
+     *  - list of conditions used, values are always true (except for the 'wid' condition)
+     * @param {integer} offset
+     * @param {integer} nTotal
+     * @return {void}
+     */
+    _listLogs = function(logs, conditions, offset, nTotal) {
+      var le = logs.length, i, o, v, css = 'log-filter-list', s, nCols = 5, wid, optionalColumns = {}, tabindex = 999;
+      _logs = {};
+      _.currentOffset = offset || 0;
+      if(le) {
+        for(i = 0; i < le; i++) {
+          o = logs[i];
+          //  Replace variables if exist and not done already by backend (is done if translate is on).
+          if(o.variables) {
+            o.message = Drupal.formatString(o.message, o.variables);
+          }
+          delete o.variables;
+          //  Resolve severity.
+          o.severity = parseInt('' + o.severity, 10);
+          o.severity_string = _severity[o.severity];
+          // Set other properties.
+          o.time = Judy.dateTime(new Date(o.timestamp * 1000));
+          if (!o.uid || o.uid === "0") {
+            o.uid = 0;
+            o.name = self.local("anonymous_user");
+          }
+          _logs[ "_" + o.wid ] = o;
+        }
+      }
+      // Render.
+      s = '<table id="log_filter_log_list_table" class="sticky-enabled" tabindex="' + (++tabindex) + '"><thead><tr>' +
+        '<th>' + Drupal.t('Severity') + '</th>' +
+        '<th>' + Drupal.t('Type') + '</th>' +
+        '<th>' + Drupal.t('Time') + '</th>' +
+        '<th>' + Drupal.t('User') + '</th>';
+      if(conditions.hostname || _elements.conditions.hostname.value === '*') {
+        ++nCols;
+        optionalColumns.hostname = true;
+        s += '<th>' + Drupal.t('Hostname') + '</th>';
+      }
+      if(conditions.location || _elements.conditions.location.value === '*') {
+        ++nCols;
+        optionalColumns.location = true;
+        s += '<th>' + Drupal.t('Location') + '</th>';
+      }
+      if(conditions.referer || _elements.conditions.referer.value === '*') {
+        ++nCols;
+        optionalColumns.referer = true;
+        s += '<th>' + Drupal.t('Referrer') + '</th>';
+      }
+      s += '<th>' + Drupal.t('Message') + '</th>' +
+        '</tr></thead><tbody>';
+      if(le) {
+        // Listing only a single log (from url)?
+        if ((wid = conditions.wid) && conditions.hasOwnProperty('wid')) {
+          s += '<tr class="even">' +
+            '<td class="' + css + '-event-from-url" colspan="' + nCols + '">' +
+            self.local('event_from_url', { '!number': wid }) +
+            '</td>' +
+            '</tr>';
+          setTimeout(function() {
+            self.displayLog(wid);
+          }, 100);
+        }
+        for(i = 0; i < le; i++) {
+          o = logs[i];
+          s += '<tr id="log_filter_list_log_' + o.wid + '" log_filter_list_event_id="' + o.wid + '" onclick="LogFilter.displayLog(' + o.wid +
+              ');" class="' + (i % 2 ? 'even' : 'odd') + '" title="' + self.local("eventItem_display", { '!logId': o.wid }) + '">' +
+            '<td log_filter_list_event_column="severity" class="' + css + '-severity ' + css + '-' + (v = o.severity_string) + '" title="' +
+              self.local('eventItemHover_severity', { '!logId': o.wid, '!severity': self.local(v) }) + '" tabindex="' + (++tabindex) +
+              '" onmouseover="focus(this);">&#160;</td>' +
+            '<td log_filter_list_event_column="type" class="' + css + '-type" title="' +
+              self.local('eventItemHover_filter', { '!logId': o.wid, '!filter': self.local('log_type') }) +
+              '" tabindex="' + (++tabindex) + '" onmouseover="focus(this);">' + o.type + '</td>' +
+            '<td log_filter_list_event_column="time" class="' + css + '-time" title="' + self.local('eventItemHover_time', { '!logId': o.wid }) +
+              '" tabindex="' + (++tabindex) + '" onmouseover="focus(this);">' + o.time + '</td>' +
+            '<td log_filter_list_event_column="uid" class="' + css + '-user" title="' +
+              self.local('eventItemHover_user', { '!logId': o.wid, '!uid': o.uid }) + '"' +
+              (!o.uid || o.name === null ? (!o.uid ? (' onmouseover="focus(this);">' + (o.name)) : ('>-' + self.local("deleted_user") + '-')) :
+                ('><a href="/user/' + o.uid + '" onmouseover="focus(this);">' + o.name + '</a>')) +
+              '</td>' +
+            (!optionalColumns.hostname ? '' :
+              '<td log_filter_list_event_column="hostname" class="' + css + '-hostname" title="' +
+                self.local('eventItemHover_filter', { '!logId': o.wid, '!filter': self.local('log_hostname') }) +
+                '" tabindex="' + (++tabindex) + '" onmouseover="focus(this);">' + o.hostname + '</td>') +
+            (!optionalColumns.location ? '' :
+              '<td log_filter_list_event_column="location" class="' + css + '-location" title="' +
+                self.local('eventItemHover_filter', { '!logId': o.wid, '!filter': self.local('log_location') }) +
+                '" tabindex="' + (++tabindex) + '" onmouseover="focus(this);">' + o.location + '</td>') +
+            (!optionalColumns.referer ? '' :
+              '<td log_filter_list_event_column="referer" class="' + css + '-referer" title="' +
+                self.local('eventItemHover_filter', { '!logId': o.wid, '!filter': self.local('log_referer') }) +
+                '" tabindex="' + (++tabindex) + '" onmouseover="focus(this);">' + o.referer + '</td>') +
+            '<td class="' + css + '-message"><div>' +
+              Judy.stripTags(o.message.replace(/\r?\n/g, " ")).substr(0, _.listMessageTruncate) + '</div></td>' +
+            '</tr>';
+        }
+        // Pager.
+        $(_elements.pager.progress).hide();
+        if (offset) {
+          $(_elements.pager.first).removeClass("log-filter-pager-button-disabled");
+          $(_elements.pager.previous).removeClass("log-filter-pager-button-disabled");
+        }
+        $(_elements.pager.current).html(self.local('pager_current', { '!first': (offset + 1), '!last': (offset + le), '!total': nTotal })).show();
+        if (offset + le < nTotal) {
+          $(_elements.pager.next).removeClass("log-filter-pager-button-disabled");
+          $(_elements.pager.last).removeClass("log-filter-pager-button-disabled");
+        }
+      }
+      else {
+        s += '<tr class="odd">' +
+          '<td class="' + css + '-no-match" colspan="' + nCols + '">' +
+          (!conditions.wid ? self.local('no_event_matches') : self.local('non_existing_event', { '!number': conditions.wid })) +
+          '</td>' +
+          '</tr>';
+        // Pager.
+        $(_elements.pager.progress).hide();
+        if (offset) {
+          $(_elements.pager.first).removeClass("log-filter-pager-button-disabled");
+          $(_elements.pager.previous).removeClass("log-filter-pager-button-disabled");
+        }
+        if (!nTotal) {
+          $(_elements.pager.current).html(self.local('pager_current_none')).show();
+        }
+        else {
+          $(_elements.pager.current).html(self.local('pager_current_outofrange', { '!offset': offset, '!total': nTotal })).show();
+        }
+      }
+      s += "</tbody></table>";
+      // Display the table, after updating pager (displaying the table may take some time).
+      $("#log_filter_log_list").html(s);
+
+      setTimeout(function() {
+        // Apply Drupal tableheader.
+        $('#log_filter_log_list table.sticky-enabled').once('tableheader', function () {
+          $(this).data("drupal-tableheader", new Drupal.tableHeader(this));
+        });
+        // Add filter by event column value handlers.
+        $('table#log_filter_log_list_table').bind('contextmenu', _filterByEventColumn);
+        Judy.keydown('table#log_filter_log_list_table', 'f shift+f', _filterByEventColumn, true); // preventDefault
+      }, 100);
+    };
+
+    /**
+     * @ignore
+     * @param {string} action
+     * @param {object} oData
+     * @return {void}
+     */
+    _ajaxRequest = function(action, oData) {
+      $.ajax({
+        url: "/log_filter/ajax/" + action,
+        type: "POST",
+        data: oData,
+        dataType: "json", // expects json formatted response data
+        cache: false,
+        /**
+          * @return {void}
+          * @param {object} oResp
+          *  - (string) action
+          *  - (boolean) success
+          *  - (string) error
+          *  - (integer) error_code
+          * @param {string} textStatus
+          * @param {object} jqXHR
+          */
+        success: function(oResp, textStatus, jqXHR) {
+          var o;
+          if(textStatus === "success" && typeof action === "string" && $.type(oResp) === "object") {
+            _ajaxResponse(action, oResp);
+          }
+          else {
+            o = {
+              source: "ajax request",
+              action: action,
+              textStatus: textStatus,
+              oResp: oResp
+            };
+            _.errors.push(o);
+            _errorHandler(null, o, _name + "._ajaxRequest()");
+          }
+        },
+        error: function(jqXHR, textStatus, errorThrown) {
+          var o;
+          if(jqXHR && jqXHR.status === 403) {
+            _ajaxResponse(action, { success: false, error_code: _errorCodes.perm_general });
+          }
+          else {
+            o = {
+              source: "ajax request",
+              action: action,
+              textStatus: textStatus,
+              errorThrown: errorThrown
+            };
+            _.errors.push(o);
+            _errorHandler(null, o, _name + "._ajaxRequest()");
+          }
+        }
+      });
+    };
+    /**
+     * @ignore
+     * @param {string} action
+     * @param {object} oResp
+     * @return {void}
+     */
+    _ajaxResponse = function(action, oResp) {
+      var errorCode = oResp.error_code || 0, url;
+      //  Handle general errors.
+      if (!oResp.success || errorCode) {
+        switch(errorCode) {
+          //  General errors.
+          case _errorCodes.perm_general: // Probably session timeout.
+            //  Reload page, to get 403. And remove form.
+            $(_elements.form).html("");
+            self.Message.set( self.local("error_form_expired", { "!url": url = _url() }), "warning", { // In case Javascript redirect fails.
+                modal: true,
+                close: function() {
+                  window.location.href = url;
+                }
+            });
+            return;
+          case _errorCodes.form_expired:
+            self.Message.set( self.local("error_form_expired", { "!url": url = _url() }), "warning", {
+                modal: true,
+                close: function() {
+                  window.location.href = url;
+                }
+            });
+            return;
+          //  Errors by more than one request type.
+          case _errorCodes.perm_filter_crud:
+            self.Message.set( self.local("error_perm_filter_crud"), "warning", {
+                modal: true,
+                close: function() {
+                  window.location.href = _url(); // Reload to make GUI reflect permissions; omitting create/edit/save/delete controls.
+                }
+            });
+            return;
+          case _errorCodes.db_general: // Database error.
+            self.Message.set( self.local("error_db_general"), "error", {
+                modal: true,
+                close: function() {
+                  window.location.href = _url();
+                }
+            });
+            break;
+          // default: Let action function handle the error, and optionally return false if it doesnt know that error code.
+        }
+      }
+      if(_ajaxResponse.hasOwnProperty(action)) { // IE<9 wont like that, has no function.hasOwnProperty() method ;-)
+        if(!_ajaxResponse[action](oResp)) {
+          _errorHandler(null, oResp, _name + "._ajaxResponse." + action + "()");
+          self.Message.set( self.local("error_unknown"), "error", {
+              modal: true,
+              close: function() {
+                window.location.href = _url();
+              }
+          });
+        }
+      }
+      else {
+        _errorHandler(null, oResp, _name + "._ajaxResponse(), unsupported action[" + action + "]");
+      }
+    };
+    /**
+     * @ignore
+     * @param {object} oResp
+     * @return {boolean}
+     */
+    _ajaxResponse.filter_create = function(oResp) { // Only saves a default filter with a name; progress to edit mode on success.
+      var nm = oResp.name;
+      if(oResp.success) {
+        _elements.filter.name_suggest.value = "";
+        _elements.filter.origin.value = _.origin = _.name;
+        _elements.filter.name.value = _.name = nm;
+        _filters.push(nm);
+        _setMode("edit");
+        $(_elements.misc.title).html(nm + "<span> - " + oResp.description + "</span>");
+        Judy.overlay(0);
+        self.Message.set(self.local("savedNew", {"!filter": nm}));
+      }
+      else {
+        switch(oResp.error_code) {
+          case _errorCodes.filter_name_composition: // Invalid machine name.
+            Judy.overlay(0);
+            self.Message.set( self.local("error_machine_name_composition"), "warning", {
+                modal: true,
+                close: function() {
+                  Judy.focus(_elements.filter.name_suggest);
+                }
+            });
+            break;
+          case _errorCodes.filter_name_nonunique: // Filter name already exists.
+            Judy.overlay(0);
+            self.Message.set( self.local("error_filter_name_nonunique", {"!name": nm}), "warning", {
+                modal: true,
+                close: function() {
+                  Judy.focus(_elements.filter.name_suggest);
+                }
+            });
+            break;
+          default: // Unknown error code.
+            return false;
+        }
+      }
+      _ajaxRequestingBlocking = false;
+      return true;
+    };
+    /**
+     * @ignore
+     * @param {object} oResp
+     * @return {boolean}
+     */
+    _ajaxResponse.filter_edit = function(oResp) {
+      var nm = oResp.name;
+      if(oResp.success) {
+        $("span", _elements.misc.title).html(" - " + oResp.description);
+        Judy.overlay(0);
+        self.Message.set(self.local("saved", {"!filter": nm}));
+      }
+      else if(oResp.error_code === _errorCodes.filter_doesnt_exist) {
+        self.Message.set( self.local("error_filter_doesnt_exist", {"!name": nm}), "warning", {
+            modal: true,
+            close: function() {
+              window.location.href = _url(); // Reload to make GUI reflect missing filter.
+            }
+        });
+      }
+      else if(oResp.error_code === _errorCodes.perm_filter_restricted) {
+        self.Message.set( self.local("error_perm_filter_restricted"), "error", {
+            modal: true,
+            close: function() {
+              window.location.href = _url(); // Reload to make get out of that situation.
+            }
+        });
+      }
+      else {
+        return false;
+      }
+      _ajaxRequestingBlocking = false;
+      return true;
+    };
+    /**
+     * @ignore
+     * @param {object} oResp
+     * @return {boolean}
+     */
+    _ajaxResponse.list_logs = function(oResp) {
+      var nm = oResp.name, conditions = oResp.log_list[1];
+      if(oResp.success) {
+        _listLogs(oResp.log_list[0], oResp.log_list[1], oResp.log_list[2], oResp.log_list[3]);
+        //  Deleting logs is allowed when evenever the log list reflects the filter.
+        if(_.deleteLogs_allowed &&
+          // If wid condition, we list a single log (from url) and thus the list doesnt reflect current filter.
+          (!conditions.wid || !conditions.hasOwnProperty('wid'))
+        ) {
+          Judy.enable(_elements.buttons.delete_logs_button, null, "");
+        }
+        Judy.overlay(0);
+      }
+      else {
+        return false;
+      }
+      _ajaxRequestingBlocking = false;
+      return true;
+    };
+    /**
+     * @ignore
+     * @param {object} oResp
+     * @return {boolean}
+     */
+    _ajaxResponse.delete_logs = function(oResp) {
+      if(oResp.success) {
+        self.Message.set(self.local("deleteLogs_success", { "!number": oResp.delete_logs }), "notice", { noFade: false });
+        _getLogList();
+        return true;
+      }
+      else {
+        return false;
+      }
+    };
+
+    /**
+     * Does nothing if no Inspect module (or no-action version of Inspect; user not allowed to use frontend instection).
+     *
+     * @function
+     * @name LogFilter.inspect
+     * @param {string|falsy} [prop]
+     * @return {void}
+     */
+    this.inspect = function(prop) {
+      if(typeof window.inspect === "function" && inspect.tcepsni === true) {
+        inspect(!prop ? _ : _[prop], _name + (!prop ? "" : (" - " + prop)));
+      }
+    };
+    /**
+     * @function
+     * @name LogFilter.inspectElements
+     * @param {string|falsy} [group]
+     * @return {void}
+     */
+    this.inspectElements = function(group) {
+      if(typeof window.inspect === "function" && inspect.tcepsni === true) {
+        inspect(!group ? _elements : _elements[group], "_elements" + (!group ? "" : ("." + group)));
+      }
+    };
+    /**
+     * Caches translated labels/message having no replacers.
+     *
+     * @function
+     * @name LogFilter.local
+     * @param {string} name
+     * @param {object|falsy} [replacers]
+     * @return {string}
+     */
+    this.local = function(name, replacers) {
+      var nm = name, s;
+      //  S.... Drupal.t() doesnt use the 'g' flag when replace()'ing, so Drupal.t() replacement is utterly useless - and nowhere to report the bug :-(
+      if(!(s = _oGet(_local, nm))) {
+        switch(nm) {
+          case "default":
+            _local[nm] = s = Drupal.t("Default");
+            break;
+          case "adhoc":
+            _local[nm] = s = Drupal.t("Ad hoc");
+            break;
+          case "adhocForOrigin":
+            //  {"!origin": nm}
+            s = Drupal.t("Ad hoc - based on !origin", replacers );
+            break;
+          case "newForOrigin":
+            //  {"!origin": nm}
+            s = Drupal.t("New - based on !origin", replacers );
+            break;
+          case "newTitle":
+            _local[nm] = s = Drupal.t("New");
+            break;
+          case "newName":
+            _local[nm] = s = Drupal.t("new");
+            break;
+          case "savedNew":
+            //  { "!filter": name }
+            s = Drupal.t("Saved new filter '!filter'.", replacers);
+            break;
+          case "saved":
+            //  { "!filter": name }
+            s = Drupal.t("Saved filter '!filter'.", replacers);
+            break;
+          case "confirmDelete":
+            //  { "!filter": _elements.filter.name.value }
+            s = Drupal.t("Are you sure you want to delete the filter!newline!filter?", replacers);
+            break;
+          case "invalid_date":
+            //  {"!date": v, "!format": _.dateFormat}
+            s = Drupal.t("The date '!date' is not valid!newline- please use the format: !format", replacers);
+            break;
+          case "invalid_timeSequence_from":
+            _local[nm] = s = Drupal.t("'From' time cannot be later than 'To' time.");
+            break;
+          case "invalid_timeSequence_to":
+            _local[nm] = s = Drupal.t("'To' time cannot be earlier than 'From' time.");
+            break;
+          case "invalid_uid":
+            _local[nm] = s = Drupal.t("User ID must be a positive number, or empty.");
+            break;
+          case "invalid_location":
+            _local[nm] = s = Drupal.t("Requested URL must be a URL, or empty.");
+            break;
+          case "invalid_referer":
+            _local[nm] = s = Drupal.t("Referrer URL must be a URL, 'none', or empty.");
+            break;
+          case "error_machine_name_composition":
+            //  { "!illegals": "default, adhoc" }
+            s = Drupal.t("The filter name:!newline- must be 2 to 32 characters long!newline- must only consist of the characters a-z, letters, and underscore (_)!newline- cannot start with a number!newline- cannot be: !illegals", replacers);
+            break;
+          case "error_filter_name_nonunique":
+            //  {"!name": name}
+            s = Drupal.t("There's already a filter named!newline'!name'.!newlineDo you want to overwrite that filter?", replacers);
+            break;
+          case "error_filter_doesnt_exist":
+            //  {"!name": name}
+            s = Drupal.t("There's no filter named!newline'!name'.", replacers);
+            break;
+          case "wait":
+            _local[nm] = s = Drupal.t("Please wait a sec...");
+            break;
+          case "wait_create":
+            _local[nm] = s = Drupal.t("Creating new filter. Please wait a sec...");
+            break;
+          case "wait_ereate":
+            _local[nm] = s = Drupal.t("Saving filter changes. Please wait a sec...");
+            break;
+          case "deleteLogs_prohibit":
+            _local[nm] = s = Drupal.t("Only allowed when the log list is freshly updated,!newlinereflecting current filter - press the 'Update list' button.");
+            break;
+          case "deleteLogs_all":
+            _local[nm] = s = Drupal.t("Do you want to delete!newlineALL logs?");
+            break;
+          case "deleteLogs_noMax":
+            //  {"!offset": offset}
+            s = Drupal.t("Do you want to delete!newlineALL logs after event no. !offset?", replacers);
+            break;
+          case "deleteLogs_noOffset":
+            //  {"!max": max}
+            s = Drupal.t("Do you want to delete logs!newlinewithout ANY condition!newlineexcept limited by a maximum of !max?", replacers);
+            break;
+          case "deleteLogs_noConditions":
+            //  {"!offset": offset, "!max": max}
+            s = Drupal.t("Do you want to delete logs after event no. !offset!newlinewithout ANY condition!newlineexcept limited by a maximum of !max?", replacers);
+            break;
+          case "deleteLogs_storedAll":
+            //  {"!name": name}
+            s = Drupal.t("Do you want to delete all logs matching!newlinethe '!name' filter!newlinelimited by NO maximum?", replacers);
+            break;
+          case "deleteLogs_storedNoMax":
+            //  {"!offset": offset, !name": name}
+            s = Drupal.t("Do you want to delete all logs matching!newlinethe '!name' filter!newlineafter matching event no. !offset!newlinelimited by NO maximum?", replacers);
+            break;
+          case "deleteLogs_storedNoOffset":
+            //  {"!offset": offset, !name": name}
+            s = Drupal.t("Do you want to delete all logs matching!newlinethe '!name' filter!newlineexcept limited by a maximum of !max?", replacers);
+            break;
+          case "deleteLogs_stored":
+            //  {"!offset": offset, "!max": max, "!name": name}
+            s = Drupal.t("Do you want to delete all logs matching!newlinethe '!name' filter!newlineafter matching event no. !offset!newlinelimited by a maximum of !max?", replacers);
+            break;
+          case "deleteLogs_adhocAll":
+            _local[nm] = s = Drupal.t("Do you want to delete all logs!newlinematching current ad hoc filter!newlinelimited by NO maximum?");
+            break;
+          case "deleteLogs_adhocNoMax":
+            //  {"!offset": offset}
+            s = Drupal.t("Do you want to delete all logs!newlinematching current ad hoc filter!newlineafter matching event no. !offset!newlinelimited by NO maximum?", replacers);
+            break;
+          case "deleteLogs_adhocNoOffset":
+            //  {"!max": max}
+            s = Drupal.t("Do you want to delete all logs!newlinematching current ad hoc filter!newlineexcept limited by a maximum of !max?", replacers);
+            break;
+          case "deleteLogs_adhoc":
+            //  {"!offset": offset, "!max": max}
+            s = Drupal.t("Do you want to delete all logs!newlinematching current ad hoc filter!newlineafter matching event no. !offset!newlinelimited by a maximum of !max?", replacers);
+            break;
+          case "deleteLogs_success":
+            //  {"!number": integer}
+            s = Drupal.t("Deleted !number log events.", replacers);
+            break;
+          case "error_form_expired":
+            //  {"!url": url}
+            s = Drupal.t("The form has become outdated!newline- please <a href=\"!url\">reload this page</a>.", replacers);
+            break;
+          case "error_perm_filter_crud":
+            _local[nm] = s = Drupal.t("Sorry, you're not allowed to edit saveable filters.");
+            break;
+          case "error_perm_filter_restricted":
+            _local[nm] = s = Drupal.t("You're not allowed to use that filter.");
+            break;
+          case "error_db_general":
+            _local[nm] = s = Drupal.t("Sorry, failed to save data.");
+            break;
+          case "error_unknown":
+            _local[nm] = s = Drupal.t("Sorry, something unexpected happened.");
+            break;
+          case "emergency":
+            _local[nm] = s = Drupal.t("emergency");
+            break;
+          case "alert":
+            _local[nm] = s = Drupal.t("alert");
+            break;
+          case "critical":
+            _local[nm] = s = Drupal.t("critical");
+            break;
+          case "error":
+            _local[nm] = s = Drupal.t("error");
+            break;
+          case "warning":
+            _local[nm] = s = Drupal.t("warning");
+            break;
+          case "notice":
+            _local[nm] = s = Drupal.t("notice");
+            break;
+          case "info":
+            _local[nm] = s = Drupal.t("info");
+            break;
+          case "debug":
+            _local[nm] = s = Drupal.t("debug");
+            break;
+          case "anonymous_user":
+            _local[nm] = s = Drupal.t("anonymous");
+            break;
+          case "deleted_user":
+            _local[nm] = s = Drupal.t("deleted");
+            break;
+          case "log_event":
+            _local[nm] = s = Drupal.t("Event");
+            break;
+          case "log_severity":
+            _local[nm] = s = Drupal.t("Severity");
+            break;
+          case "log_type":
+            _local[nm] = s = Drupal.t("Type");
+            break;
+          case "log_time":
+            _local[nm] = s = Drupal.t("Time");
+            break;
+          case "log_time_from":
+            _local[nm] = s = Drupal.t("Time From");
+            break;
+          case "log_time_to":
+            _local[nm] = s = Drupal.t("Time To");
+            break;
+          case "log_user":
+          case "log_uid":
+            _local[nm] = s = Drupal.t("User");
+            break;
+          case "log_location":
+            _local[nm] = s = Drupal.t("Location");
+            break;
+          case "log_referer":
+            _local[nm] = s = Drupal.t("Referrer");
+            break;
+          case "log_hostname":
+            _local[nm] = s = Drupal.t("Hostname");
+            break;
+          case "log_message":
+            _local[nm] = s = Drupal.t("Message");
+            break;
+          case "log_link":
+            _local[nm] = s = Drupal.t("Link");
+            break;
+          case "eventItem_display":
+            //  {"!logId": integer}
+            s = Drupal.t("Event !logId", replacers);
+            break;
+          case "eventItemHover_filter":
+            //  {"!logId": logId, '!filter': filter }
+            s = Drupal.t("Event !logId - press F key (or right-click) to filter !filter", replacers);
+            break;
+          case "eventItemHover_severity":
+            //  {"!logId": logId, '!severity': severity}
+            s = Drupal.t("Event !logId (!severity) - press F key (or right-click) to filter Severity", replacers);
+            break;
+          case "eventItemHover_time":
+            //  {"!logId": logId }
+            s = Drupal.t("Event !logId!newline - press F key (or right-click) to filter Time From!newline - press shift+F to filter Time To", replacers);
+            break;
+          case "eventItemHover_user":
+            //  {"!logId": logId, '!uid': uid}
+            s = Drupal.t("Event !logId (user !uid) - press F key (or right-click) to filter User", replacers);
+            break;
+          case "filtered_event_column":
+            //  {"!logId": logId, '!value': value }
+            s = Drupal.t("Filter !column by '!value'.", replacers);
+            break;
+          case "event_link":
+            _local[nm] = s = Drupal.t("Link to this log event");
+            break;
+          case "no_event_matches":
+            _local[nm] = s = Drupal.t("The current filter matches no events.");
+            break;
+          case "non_existing_event":
+            //  {"!number": integer}
+            s = Drupal.t("Event ID !number doesn't exist.", replacers);
+            break;
+          case "event_from_url":
+            //  {"!number": integer}
+            s = Drupal.t("Listing event ID !number, according to URL. Press 'Update list' button to reflect current filter.", replacers);
+            break;
+          case "add_type_item":
+            _local[nm] = s = Drupal.t("Add type...");
+            break;
+          case "type_option_dupe":
+            //  {"!option": string}
+            s = Drupal.t("Type !option already exists.", replacers);
+            break;
+          case "pager_current":
+            //  { '!first': (offset + 1), '!last': (offset + le), '!total': nTotal }
+            s = Drupal.t("!first-!last of !total", replacers);
+            break;
+          case "pager_current_none":
+            _local[nm] = s = Drupal.t("None");
+            break;
+          case "pager_current_outofrange":
+            //  { '!offset': offset, '!total': nTotal }
+            s = Drupal.t("None after !offset, of !total", replacers);
+            break;
+          case "library_judy_incompatible":
+            //  { '!version': version }
+            s = Drupal.t("Log Filter doesn't work without the Judy library, version !version or newer.", replacers);
+            break;
+          default:
+            s = "[LOCAL: " + nm + "]";
+        }
+      }
+      return s.replace(/\!newline/g, "\n");
+    };
+
+    /**
+     * For querying backend.
+     *
+     * Must be called delayed (after displaying overlay) to secure that validation (set-up in _prepareForm()) has done it's job.
+     *
+     * @function
+     * @name LogFilter.getCriteria
+     * @return {object}
+     */
+    this.getCriteria = function() {
+      var n = 0, conditions = {}, order_by = [], oElms = _elements.conditions, nm, r, v, le, i;
+      try {
+        //  Rely on validation set-up in _prepareForm(), dont do the same thing once over.
+        for(nm in oElms) {
+          if(oElms.hasOwnProperty(nm)) {
+            r = oElms[nm];
+            switch(nm) {
+              case "time_from_proxy":
+              case "time_to_proxy":
+              case "time_from_time":
+              case "time_to_time":
+                break;
+              case "time_range":
+              case "time_from":
+              case "time_to":
+              case "uid":
+                if((v = r.value) !== "" && (v = $.trim(v)).length && (v = parseInt(v, 10)) > -1) {
+                  ++n;
+                  conditions[nm] = v;
+                }
+                break;
+              case "username":
+                // Skip, we use uid instead.
+                break;
+              case "role":
+                if((v = Judy.fieldValue(r)) !== "" && v !== "_none" && (v = $.trim(v)) && (v = parseInt(v, 10))) {
+                  ++n;
+                  conditions[nm] = v;
+                }
+                break;
+              case "severity_any":
+              case "type_any":
+              case "type_proxy":
+                //  Check at severity_some/type_some instead.
+                break;
+              case "severity_some":
+                if(!oElms.severity_any.checked) {
+                  v = [];
+                  le = r.length;
+                  for(i = 0; i < le; i++) {
+                    if(r[i].checked) {
+                      v.push(r[i].value);
+                    }
+                  }
+                  if(v.length) {
+                    ++n;
+                    conditions.severity = v;
+                  }
+                }
+                break;
+              case "type_some":
+                if((v = r.value) !== "" && (v = $.trim(v))) {
+                  ++n;
+                  conditions.type = v.split(/\n/);
+                }
+                break;
+              case "hostname":
+              case "location":
+              case "referer":
+                if((v = r.value) !== "" && (v = $.trim(v)) && v !== '*') {
+                  ++n;
+                  conditions[nm] = v;
+                }
+                break;
+              default:
+                throw new Error("Condition[" + nm + "] not supported.");
+            }
+          }
+        }
+        le = (oElms = _elements.orderBy).length;
+        for(i = 0; i < le; i++) {
+          if((v = Judy.fieldValue(oElms[i][0])) && v !== "_none" && (v = $.trim(v))) {
+            order_by.push([
+              v,
+              oElms[i][1].checked ? "DESC" : "ASC"
+            ]);
+          }
+        }
+      }
+      catch(er) {
+        _errorHandler(er, 0, _name + ".getCriteria()");
+      }
+      return {
+        nConditions: n,
+        conditions: conditions,
+        order_by: order_by
+      };
+    };
+
+    /**
+     * Singleton, instantiated to itself.
+     * @constructor
+     * @namespace
+     * @name LogFilter.Message
+     * @singleton
+     */
+    this.Message = function() {
+      var _self = this,
+      _n = -1,
+      _htmlList = "<div id=\"log_filter__message\"><div><div id=\"log_filter__message_list\"></div></div></div>",
+      _htmlItem = "<div id=\"log_filter__message___NO__\" class=\"log-filter-message-__TYPE__\"><div class=\"log-filter--message-content\"><span>__CONTENT__</span></div><div title=\"" +
+          Drupal.t("Close") + "\">x</div></div>",
+      _list,
+      _faders = {},
+      /**
+      * @function
+      * @name LogFilter.Message._close
+      * @return {void}
+      */
+      _close = function() {
+        $(this.parentNode).hide();
+      },
+      /**
+      * Message item fader.
+      *
+      * Not prototypal because the 'this' of prototypal methods as event handlers is masked by jQuery's element 'this' (or for inline handlers the global window 'this').
+      * Could use prototypal methods if we passed the the 'this' of the fader to jQuery handlers, but that would result in lots of references to the fader object (and probably more overall overhead).
+      *
+      * @constructor
+      * @class
+      * @name LogFilter.Message._fader
+      * @param {string} selector
+      * @param {integer|float|falsy} [delay]
+      *  - default: 3000 (milliseconds)
+      *  - if less than 1000 it will be used as multiplier against the default delay
+      */
+      _fader = function(selector, delay) {
+        var __self = this,
+        /**
+        * Default delay.
+        *
+        * @name LogFilter.Message._fader#_delayDefault
+        * @type integer
+        */
+        _delayDefault = 3000,
+        /**
+        * Interval setting.
+        *
+        * @name LogFilter.Message._fader#_pause
+        * @type integer
+        */
+        _pause = 150, // Milliseconds.
+        /**
+        * Opacity decrease factor setting.
+        *
+        * @name LogFilter.Message._fader#_factor
+        * @type float
+        */
+        _factor = 1.2,
+        /**
+        * State.
+        *
+        * @name LogFilter.Message._fader#_stopped
+        * @type boolean
+        */
+        _stopped,
+        /**
+        * @name LogFilter.Message._fader#_opacity
+        * @type integer
+        */
+        _opacity = 100,
+        /**
+        * @name LogFilter.Message._fader#_subtractor
+        * @type integer
+        */
+        _subtractor = 1,
+        /**
+        * @function
+        * @name LogFilter.Message._fader#_start
+        * @return {void}
+        */
+        _start = function() {
+          /** @ignore */
+          __self._interval = setInterval(_fade, _pause)
+        },
+        /**
+        * @function
+        * @name LogFilter.Message._fader#_fade
+        * @return {void}
+        */
+        _fade = function() {
+          var n = _opacity, jq = __self._jq;
+          if(!_stopped) {
+            if((_opacity = (n -= (_subtractor *= _factor))) > 0) {
+              if(Judy.browserIE < 11) {
+                jq.css("opacity", n / 100);
+              }
+              else {
+                jq.css({
+                  "-ms-filter": "progid:DXImageTransform.Microsoft.Alpha(Opacity=" + (n = Math.round(n)) + ")",
+                  filter: "alpha(opacity=" + n + ")"
+                });
+              }
+            }
+            else {
+              _stopped = true;
+              clearInterval(__self._interval);
+              jq.hide();
+            }
+          }
+        },
+        /** @ignore */
+        jq;
+        /**
+        * @function
+        * @name LogFilter.Message._fader#stop
+        * @return {void}
+        */
+        this.stop = function() {
+          if(!_stopped) {
+            _stopped = true;
+            clearTimeout(__self._timeout);
+            clearInterval(__self._interval);
+          }
+        };
+        /**
+        * @function
+        * @name LogFilter.Message._fader#unfade
+        * @return {void}
+        */
+        this.unfade = function() {
+          __self.stop();
+          if(_opacity < 100) {
+            if(Judy.browserIE < 11) {
+              __self._jq.css("opacity", 1);
+            }
+            else {
+              __self._jq.css({
+                "-ms-filter": "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)",
+                filter: "alpha(opacity=100)"
+              });
+            }
+          }
+        };
+        /**
+        * @function
+        * @name LogFilter.Message._fader#destroy
+        * @return {void}
+        */
+        this.destroy = function() {
+          __self.stop();
+          delete __self._jq;
+        };
+        //  Construction logics.
+        if((jq = $(selector)).get(0)) {
+          /**
+          * @name LogFilter.Message._fader#_jq
+          * @type jquery
+          */
+          this._jq = jq;
+          /** @ignore */
+          this._timeout = setTimeout(
+              _start,
+              !delay ? _delayDefault : (delay < 1000 ? Math.floor(delay * _delayDefault) : _delayDefault)
+          );
+        }
+      };
+      /**
+      * @function
+      * @name LogFilter.Message.setup
+      * @return {void}
+      */
+      this.setup = function() {
+        var elm, jq;
+        if((elm = document.getElementById("console"))) {
+          $(elm).after(_htmlList);
+        }
+        else {
+          $("#content").prepend(_htmlList);
+        }
+        _list = document.getElementById("log_filter__message_list");
+        //  Draggable.
+        if((jq = $(_list)).draggable) {
+          jq.draggable({ handle: "div.log-filter--message-content", cancel: "span", cursor: "move" });
+        }
+      };
+      /**
+      * @function
+      * @name LogFilter.Message.set
+      * @param {mixed} txt
+      * @param {string} [type]
+      *  - default: 'status'
+      *  - values: 'status' | 'info' |  'notice' |  'warning' | 'error'
+      * @param {object} [options]
+      *  - (boolean) noFade: default false ~ a 'status' or 'info' message will eventually fade away, unless clicked/mousedowned
+      *  - (number) fadeDelay: default zero ~ use default delay before starting fade ('status' message only)
+      *  - (number) fadeDelay: >1000 ~ use that delay | < 1000 multiply default delay with that number (both 'status' message only)
+      *  - (boolean) modal: default false ~ do not display blocking overlay
+      *  - (function) close: function to execute upon click on close button
+      * @param {integer} [delay]
+      *  - default: 4000 (milliseconds)
+      * @return {void}
+      */
+      this.set = function(txt, type, options) {
+        var t = type || "status", s, f, k, jq, o = {
+          noFade: true,
+          fadeDelay: 0,
+          modal: false,
+          close: null
+        };
+        switch(t) {
+          case "status":
+          case "info":
+            o.noFade = false;
+            break;
+          case "notice":
+          case "warning":
+            break;
+          default:
+            t = "error";
+        }
+        if(options) {
+          for(k in o) {
+            if(o.hasOwnProperty(k) && options.hasOwnProperty(k)) {
+              o[k] = options[k];
+            }
+          }
+        }
+        //  Add message to DOM.
+        $(_list).prepend(
+          _htmlItem.replace(/__NO__/, ++_n).replace(/__TYPE__/, t).replace(/__CONTENT__/, txt ? txt.replace(/\n/g, "<br/>") : "")
+        );
+        //  Close behaviours.
+        (jq = $((s = "#log_filter__message_" + _n) + " > div:last-child")).click(_close);
+        //  If modal, show overlay.
+        if(o.modal) {
+          jq.click(Judy.overlay); // And hide it on close click.
+          Judy.overlay(1, true); // Opaque, no hover title.
+        }
+        //  Close function.
+        if(o.close) {
+          jq.click(o.close);
+        }
+        //  If to be fading, make click on message content unfade the message.
+        if(!o.noFade) {
+          _faders[ "_" + _n ] = f = new _fader(s, o.fadeDelay);
+          $(s + " > div:first-child").bind("click mousedown", f.unfade); // And mousedown, otherwise dragging wont prevent fade.
+        }
+        //  Display the message.
+        $(s).show();
+      };
+      /**
+      * @function
+      * @name LogFilter.Message.showAll
+      * @return {void}
+      */
+      this.showAll = function() {
+        var le = _n + 1, i, f;
+        for(i = 0; i < le; i++) {
+          if((f = _faders[ "_" + i ]) && _faders.hasOwnProperty("_" + i)) {
+            f.unfade();
+          }
+          $("#log_filter__message_" + i).show();
+        }
+      };
+    };
+
+    /**
+     * @param {integer|falsy|string} logId
+     * @return {void}
+     */
+    this.displayLog = function(logId) {
+      var o, s, v, css = 'log-filter-log-display', dialId = 'log_filter_logDisplay_' + logId, elm, $dialOuter, dialInner;
+      if ((o = _logs['_' + logId]) && _logs.hasOwnProperty('_' + logId)) {
+        // If already open: close the dialog.
+        if ((elm = document.getElementById(dialId))) {
+          $('#log_filter_list_log_' + logId).removeClass('log-filter-list-displayed');
+          Judy.dialog(dialId, "close");
+        }
+        else {
+          $('#log_filter_list_log_' + logId).addClass('log-filter-list-displayed');
+          o = _logs['_' + logId];
+          s = '<div class="' + css + '">' +
+              '<table class="dblog-event"><tbody>' +
+              '<tr class="odd"><th>' + self.local('log_severity') + '</th>' +
+                '<td>' + (v = o.severity_string) + '<div class="' + css + '-severity ' + css + '-' + v + '">&#160;</div></td></tr>' +
+              '<tr class="even"><th>' + self.local('log_type') + '</th><td>' + o.type + '</td></tr>' +
+              '<tr class="odd"><th>' + self.local('log_time') + '</th><td>' + o.time + '</td></tr>' +
+              '<tr class="even"><th>' + self.local('log_user') + '</th>' +
+                '<td>' + (!o.uid ? o.name : ('<a href="/user/' + o.uid + '" title="' + o.uid + '">(' + o.uid + ') ' + o.name + '</a>')) +
+                ' &#160; &bull; &#160; ' + self.local('log_hostname') + ': ' + o.hostname + '</td></tr>' +
+              '<tr class="odd"><th>' + self.local('log_location') + '</th><td><a href="' + o.location + '">' + o.location + '</a></td></tr>' +
+              '<tr class="even"><th>' + self.local('log_referer') + '</th>' +
+                '<td>' + (!o.referer ? '&#160;' : ('<a href="' + o.referer + '">' + o.referer + '</a>')) + '</td></tr>' +
+              '<tr class="odd"><th>' + self.local('log_message') + '</th><td>' + o.message + '</td></tr>' +
+              (!o.link ? '' : ('<tr class="even"><th>' + self.local('log_link') + '</th><td><a href="' + o.link + '">' + o.link + '</a></td></tr>')) +
+              '</tbody></table>' +
+            '</div>';
+          Judy.dialog(dialId, {
+            title: '<a href="' + _url() + '/' + o.wid + '" title="' + self.local('event_link') + '">' + self.local('log_event') + ': ' + o.wid + '</a>',
+            content: s,
+            fixed: true,
+            resizable: false,
+            closeOnEscape: false, // Set behaviour that closes all log filter dialogs on escape, disregarding current focus.
+            dialogClass: "log-filter-log-display-dialog",
+            contentClass: "log-filter-log-display-content",
+            autoOpen: false,
+            close: function(event, ui) {
+              setTimeout(function() {
+                $('#log_filter_logDisplay_' + logId).dialog('destroy').remove();
+                $('#log_filter_list_log_' + logId).removeClass('log-filter-list-displayed');
+              });
+            }
+          });
+          ($dialOuter = $( (dialInner = $('#' + dialId).get(0)).parentNode )).css({
+            visibility: 'hidden',
+            overflow: 'visible'
+          });
+          Judy.dialog(dialId, "open");
+          Judy.outerWidth($dialOuter, true, Judy.innerWidth(window) - 200, 2);
+          Judy.outerHeight('#' + dialId, true,
+            Judy.outerHeight($dialOuter, true, Judy.outerHeight(window) - 10, 1) -
+              Judy.outerHeight($('div.ui-dialog-titlebar', $dialOuter)) -
+              Math.ceil(parseFloat($dialOuter.css("padding-top")) + parseFloat($dialOuter.css("padding-bottom"))) -
+              _.adminOverlayOffset,
+            1
+          );
+
+          $dialOuter.css({
+            visibility: 'visible',
+            left: '150px', // jQuery UI dialog position apparantly doesnt work well when css position is fixed.
+            top: (4 + _.adminOverlayOffset) + 'px'
+          });
+
+          // Apply behaviours (if any).
+          Drupal.attachBehaviors($dialOuter.get(0));
+        }
+      }
+    };
+
+    /**
+     * Called before page load.
+     *
+     * @function
+     * @name LogFilter.init
+     * @param {boolean|integer} useModuleCss
+     * @param {string} theme
+     * @return {void}
+     */
+    this.init = function(useModuleCss, theme) {
+      var v;
+      /** @ignore */
+      self.init = function() {};
+
+      // Make sure Judy exists and is version 2.0+.
+      if (typeof window.Judy !== 'object' || !(v = Judy.version) || Judy.version < _.library_judy_version) {
+        _.library_judy_compatible = false;
+        return;
+      }
+
+      //  Tell styles about theme.
+      if((_.useModuleCss = useModuleCss)) {
+        $("div#page").addClass("theme-" + theme);
+      }
+      //	Set overlay, to prevent user from doing anything before page load and after form submission.
+      Judy.overlay(1, false, self.local("wait"));
+    };
+    /**
+     * Called upon page load.
+     *
+     * @function
+     * @name LogFilter.setup
+     * @param {object} [filters]
+     * @param {array} [messages]
+     * @return {void}
+     */
+    this.setup = function(filters, messages) {
+      var a = messages, le, i, o = { fadeDelay: 2 }, url, wid; // Long (double) delay when at page load.
+      /** @ignore */
+      self.setup = function() {};
+      _filters = filters || [];
+
+      if (!_.library_judy_compatible) {
+        alert(self.local('library_judy_incompatible', { '!version': _.library_judy_version }));
+        return;
+      }
+
+      _prepareForm();
+      _setMode(_.mode, false, true);
+
+      //  Display messages, if any.
+      (self.Message = new self.Message()).setup();
+      if(a) {
+        le = a.length;
+        //  Check if any message isnt of type status; status message should fade, unless there's another message of a different (more urgent) type.
+        for(i = 0; i < le; i++) {
+          if(a[i][1] && a[i][1] !== "status") {
+            o.noFade = true;
+            break;
+          }
+        }
+        for(i = 0; i < le; i++) {
+          self.Message.set(a[i][0], a[i][1], o);
+        }
+      }
+
+      // Set title attribute of all labels containing a span that has a non-empty title attribute.
+      $('label > span[title]').each(function() {
+        var t = this.getAttribute('title');
+        if (t) {
+          this.parentNode.setAttribute('title', t);
+        }
+      });
+
+      // Check if administrative Overlay is on.
+      if (!/^#overlay=admin\//.test(top.location.hash)) {
+        url = window.location.href;
+        _.adminOverlayOffset = 0;
+      }
+      else {
+        url = top.location.href + top.location.hash;
+      }
+
+      //  Prepare log list.
+      _getLogList(
+        // Check if url ends with /integer ~ single log view.
+        /^.+\/(\d+)\/?$/.test(url) && (wid = parseInt(url.replace(/^.+\/(\d+)\/?$/, '$1'), 10)) &&
+          wid <= Math.pow(2, 31) ? wid : 0
+      );
+
+      // Make all event dialogs close on escape, and no matter what has focus.
+      Judy.keydown(document.documentElement, "escape", function() {
+        $('div.log-filter-log-display-content').each(function() {
+          $(this).dialog("close");
+        });
+      });
+
+      Judy.overlay(0);
+    };
+  }
+  window.LogFilter = new LogFilter($);
+
+})(jQuery);

File diff suppressed because it is too large
+ 0 - 0
sites/all/modules/contrib/admin/log_filter/js/log_filter.min.js


+ 17 - 0
sites/all/modules/contrib/admin/log_filter/log_filter.info

@@ -0,0 +1,17 @@
+name = "Log Filter"
+description = "Log Filter provides means of filtering, displaying and deleting dblog/watchdog logs."
+package = Administration
+;Utility
+
+core = 7.x
+php = 5.3
+
+dependencies[] = judy
+
+configure = admin/config/system/log_filter
+; Information added by Drupal.org packaging script on 2014-11-09
+version = "7.x-1.4"
+core = "7.x"
+project = "log_filter"
+datestamp = "1415558584"
+

+ 200 - 0
sites/all/modules/contrib/admin/log_filter/log_filter.install

@@ -0,0 +1,200 @@
+<?php
+/**
+ * @file
+ *  Drupal Log Filter module (un)installation
+ */
+
+
+/**
+ * Implements hook_install().
+ *
+ * @return void
+ */
+function log_filter_install() {
+  // Invoke our hook_menu() later than dblog's ditto.
+  db_update('system')
+    ->fields(array('weight' => 10))
+    ->condition('type', 'module')
+    ->condition('name', 'log_filter')
+    ->execute();
+
+  // Insert some default filters.
+  $uid = $GLOBALS['user']->uid;
+  $filters = array(
+    array('name' => 'errors_day', 'creator' => $uid, 'description' => '', 'require_admin' => 1, 'severity' => '0,1,2,3', 'type' => '', 'time_range' => 30, 'time_from' => 0, 'time_to' => 0, 'role' => -1, 'uid' => -1, 'hostname' => '', 'location' => '', 'referer' => '', 'order_by' => '', 'editor' => $uid, 'created' => 1, 'changed' => 1),
+    array('name' => 'errors_month', 'creator' => $uid, 'description' => '', 'require_admin' => 1, 'severity' => '0,1,2,3', 'type' => '', 'time_range' => 750, 'time_from' => 0, 'time_to' => 0, 'role' => -1, 'uid' => -1, 'hostname' => '', 'location' => '', 'referer' => '', 'order_by' => '', 'editor' => $uid, 'created' => 1, 'changed' => 1),
+    array('name' => 'errors_week', 'creator' => $uid, 'description' => '', 'require_admin' => 1, 'severity' => '0,1,2,3', 'type' => '', 'time_range' => 175, 'time_from' => 0, 'time_to' => 0, 'role' => -1, 'uid' => -1, 'hostname' => '', 'location' => '', 'referer' => '', 'order_by' => '', 'editor' => $uid, 'created' => 1, 'changed' => 1),
+    array('name' => 'latest_day', 'creator' => $uid, 'description' => '', 'require_admin' => 0, 'severity' => '', 'type' => '', 'time_range' => 30, 'time_from' => 0, 'time_to' => 0, 'role' => -1, 'uid' => -1, 'hostname' => '', 'location' => '', 'referer' => '', 'order_by' => '', 'editor' => $uid, 'created' => 1, 'changed' => 1),
+    array('name' => 'latest_month', 'creator' => $uid, 'description' => '', 'require_admin' => 0, 'severity' => '', 'type' => '', 'time_range' => 750, 'time_from' => 0, 'time_to' => 0, 'role' => -1, 'uid' => -1, 'hostname' => '', 'location' => '', 'referer' => '', 'order_by' => '', 'editor' => $uid, 'created' => 1, 'changed' => 1),
+    array('name' => 'latest_week', 'creator' => $uid, 'description' => '', 'require_admin' => 0, 'severity' => '', 'type' => '', 'time_range' => 175, 'time_from' => 0, 'time_to' => 0, 'role' => -1, 'uid' => -1, 'hostname' => '', 'location' => '', 'referer' => '', 'order_by' => '', 'editor' => $uid, 'created' => 1, 'changed' => 1),
+    array('name' => 'severity_debug', 'creator' => $uid, 'description' => 'Debug severity', 'require_admin' => 1, 'severity' => 7, 'type' => '', 'time_range' => 0, 'time_from' => 0, 'time_to' => 0, 'role' => -1, 'uid' => -1, 'hostname' => '', 'location' => '', 'referer' => '', 'order_by' => '', 'editor' => $uid, 'created' => 1, 'changed' => 1),
+    array('name' => 'severity_error', 'creator' => $uid, 'description' => 'All error severities', 'require_admin' => 1, 'severity' => '0,1,2,3', 'type' => '', 'time_range' => 0, 'time_from' => 0, 'time_to' => 0, 'role' => -1, 'uid' => -1, 'hostname' => '', 'location' => '', 'referer' => '', 'order_by' => '', 'editor' => $uid, 'created' => 1, 'changed' => 1),
+    array('name' => 'severity_warning_notice_info', 'creator' => $uid, 'description' => 'All non-error severities but debug', 'require_admin' => 1, 'severity' => '4,5,6', 'type' => '', 'time_range' => 0, 'time_from' => 0, 'time_to' => 0, 'role' => -1, 'uid' => -1, 'hostname' => '', 'location' => '', 'referer' => '', 'order_by' => '', 'editor' => $uid, 'created' => 1, 'changed' => 1)
+  );
+  try {
+    $le = count($filters);
+    for ($i = 0; $i < $le; ++$i) {
+      db_insert('log_filter')
+        ->fields($filters[$i])
+        ->execute();
+    }
+  }
+  catch (Exception $xc) {
+    watchdog(
+      'log_filter',
+      'Failed to insert default filters during installation of module Log Filter.',
+      NULL,
+      WATCHDOG_ERROR
+    );
+  }
+}
+
+/**
+ * Implements hook_schema().
+ *
+ * @return array
+ */
+function log_filter_schema() {
+  return array(
+    'log_filter' => array(
+      'description' => 'Log filters.',
+      'fields' => array(
+        'id' => array(
+          'type' => 'serial',
+          'not null' => TRUE,
+        ),
+        'name' => array(
+          'type' => 'varchar',
+          'length' => 32,
+          'not null' => TRUE,
+        ),
+        'creator' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'description' => 'The user.uid that created the filter.',
+        ),
+        'description' => array(
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => TRUE,
+          'default' => '',
+        ),
+        'require_admin' => array(
+          'type' => 'int',
+          'size' => 'tiny',
+          'not null' => TRUE,
+          'default' => 0,
+          'description' => 'Require the \'Administer log filtering\' role.',
+        ),
+        'severity' => array(
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => TRUE,
+          'default' => '',
+          'description' => 'Comma-separated list.',
+        ),
+        'type' => array(
+          'type' => 'text',
+          'not null' => TRUE,
+          //  Text fields don't support default value; at least not MySQL.
+          'description' => 'Comma-separated list. Empty default because it\'s a text field (not char/varchar).',
+        ),
+        'time_range' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'default' => 0,
+        ),
+        'time_from' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'default' => 0,
+        ),
+        'time_to' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'default' => 0,
+        ),
+        'role' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'default' => -1,
+        ),
+        'uid' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'default' => -1,
+        ),
+        'hostname' => array(
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => TRUE,
+          'default' => '',
+        ),
+        'location' => array(
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => TRUE,
+          'default' => '',
+        ),
+        'referer' => array(
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => TRUE,
+          'default' => '',
+          'description' => 'Url, \'none\' or empty.',
+        ),
+        'order_by' => array(
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => TRUE,
+          'default' => 'time:DESC',
+          'description' => 'Comma-separated list, like: \'time:DESC,severity:ASC\'.',
+        ),
+        'editor' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'description' => 'The user.uid that most recently changed (or created) the filter.',
+        ),
+        'created' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'description' => 'The Unix timestamp when the filter was created.',
+        ),
+        'changed' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'description' => 'The Unix timestamp when the filter was most recently saved.',
+        ),
+      ),
+      'primary key' => array('id'),
+      'unique keys' => array(
+          'name' => array('name'),
+      ),
+    ),
+  );
+}
+
+/**
+ * Deletes configuration variables.
+ *
+ * Implements hook_uninstall().
+ */
+function log_filter_uninstall() {
+  variable_del('log_filter_admintheme');
+  variable_del('log_filter_cssdefault');
+  variable_del('log_filter_trnslt');
+  variable_del('log_filter_pgrng');
+  variable_del('log_filter_showdeletions');
+}
+
+/**
+ * Increase log_filter's module weight to 10; the module's hook_menu() must be invoked _after_ dblog's ditto.
+ */
+function log_filter_update_7001() {
+  // Invoke our hook_menu() later than dblog's ditto.
+  db_update('system')
+    ->fields(array('weight' => 10))
+    ->condition('type', 'module')
+    ->condition('name', 'log_filter')
+    ->execute();
+}

+ 181 - 0
sites/all/modules/contrib/admin/log_filter/log_filter.module

@@ -0,0 +1,181 @@
+<?php
+/**
+ * @file
+ *  Drupal Log Filter module
+ */
+
+/**
+ * Implements hook_permission().
+ *
+ * Define permission types (Drupal API function).
+ *
+ * @return array
+ */
+function log_filter_permission() {
+  return array(
+    'log_filter administer' => array(
+      'title' => t('Administer log filtering'),
+      'restrict access' => TRUE,
+    ),
+    'log_filter edit filters' => array(
+      'title' => t('Create/edit/delete saveable log filters'),
+    ),
+    'log_filter remove logs' => array(
+      'title' => t('Remove logs'),
+      'restrict access' => TRUE,
+    ),
+  );
+}
+
+/**
+ * Implements hook_menu().
+ *
+ * Declares configuration page.
+ *
+ * @return array
+ */
+function log_filter_menu() {
+  $items = array(
+    //  Settings page.
+    'admin/config/system/log_filter' => array(
+      'title' => 'Log Filter',
+      'description' => 'Configure Log Filtering',
+      'page callback' => 'drupal_get_form', // hook to implement
+      'page arguments' => array('_log_filter_admin_form'), // name of implementing function
+      'access arguments' => array('log_filter administer'), // permission required
+      'file' => 'admin/log_filter.admin.inc',
+      'type' => MENU_NORMAL_ITEM,
+      'theme callback' => 'log_filter_use_admin_theme',
+    ),
+    //  AJAX callback.
+    'log_filter/ajax/%' => array( // % ~ action
+      'page callback' => 'log_filter_ajax_callback',
+      'page arguments' => array(2), // start at that bucket index
+      'access callback' => TRUE,
+      'access arguments' => array('access site reports'), // Permission required.
+      'type' => MENU_CALLBACK,
+    ),
+  );
+
+  //  NB: Accessing a saved filter is done via an extra url argument after admin/reports/dblog/log_filter; see LogFilter::FILTER_NAME_ARG.
+  //  And accessing a log event is done by adding /NUMBER to the end of url (saved filter or not).
+
+  // Take over the url of dblog's default viewer.
+  $i = 0;
+  // Overwrite dblog's default viewer.
+  $items['admin/reports/dblog'] = array(
+    'title' => 'Recent log messages',
+    'description' => 'View logged events using filters',
+    'page callback' => 'drupal_get_form', // Hook to implement.
+    'page arguments' => array('log_filter_form'), // Name of implementing function.
+    'access arguments' => array('access site reports'), // Permission required.
+    'type' => MENU_NORMAL_ITEM,
+    'theme callback' => 'log_filter_use_admin_theme', // Do always administrative theme, if set so.
+    'weight' => -1,
+  );
+  $items['admin/reports/dblog/log_filter'] = array(
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'title' => 'Recent log messages',
+    'weight' => ++$i,
+  );
+  $items['admin/reports/dblog/log_filter_settings'] = array(
+    'title' => 'Log filter settings',
+    'description' => 'Configure Log Filtering',
+    'page callback' => 'drupal_get_form', // hook to implement
+    'page arguments' => array('_log_filter_admin_form'), // name of implementing function
+    'access arguments' => array('log_filter administer'), // permission required
+    'file' => 'admin/log_filter.admin.inc',
+    'type' => MENU_LOCAL_TASK,
+    'theme callback' => 'log_filter_use_admin_theme', // Do always administrative theme, if set so.
+    'weight' => ++$i,
+  );
+  // Add dblog's default viewer as a tab.
+  if (module_exists('dblog')) {
+    $items['admin/reports/dblog/dblog_view'] = array(
+      'title' => 'Standard dblog view',
+      'description' => 'View events that have recently been logged.',
+      'page callback' => 'dblog_overview',
+      'access arguments' => array('access site reports'),
+      'type' => MENU_LOCAL_TASK,
+      'file path' => drupal_get_path('module', 'dblog'),
+      'file' => 'dblog.admin.inc',
+      'theme callback' => 'log_filter_use_admin_theme', // Do always administrative theme, if set so.
+      'weight' => ++$i,
+    );
+  }
+
+  return $items;
+}
+
+/**
+ * Forces administrative on log view pages, unless this feature has been turned off on this module's settings page.
+ *
+ * @return string
+ */
+function log_filter_use_admin_theme() {
+  return variable_get('log_filter_admintheme', TRUE) ? variable_get('admin_theme') : (
+    !empty($GLOBALS['user']->theme) ? $GLOBALS['user']->theme : variable_get('theme_default', 'seven')
+  );
+}
+
+/**
+ * Removes clear log form from standard dblog log view page.
+ *
+ * @param array &$form
+ * @param array &$form_state
+ * @return void
+ */
+function log_filter_form_dblog_clear_log_form_alter(&$form, &$form_state) {
+  $form['dblog_clear'] = array();
+}
+
+/**
+ * Defines log viewer form and GUI.
+ *
+ * Function name not underscore prefixed to prevent html form id starting with hyphen (unhealthy naming).
+ *
+ * @param array $form
+ * @param array &$form_state
+ * @return array
+ */
+function log_filter_form($form, &$form_state) {
+  module_load_include('inc', 'log_filter', 'LogFilter');
+  return LogFilter::viewerForm($form, $form_state);
+}
+
+/**
+ * Called when log viewer form submits.
+ *
+ * @param array $form
+ * @param array &$form_state
+ * @return void
+ */
+function _log_filter_form_submit($form, &$form_state) {
+  module_load_include('inc', 'log_filter', 'LogFilter');
+  LogFilter::viewerFormSubmit($form, $form_state);
+}
+
+/**
+ * @param array $form
+ * @param array &$form_state
+ * @return void
+ */
+function log_filter_admin_form_submit($form, &$form_state) {
+  module_load_include('inc', 'log_filter', 'log_filter.admin');
+  _log_filter_admin_form_submit($form, $form_state);
+}
+
+/**
+ * Access permission: 'access site reports'.
+ *
+ * @see LogFilter::ajaxCallback()
+ * @param string $action
+ * @param string $arg
+ *  Default: empty.
+ * @return void
+ *  Sends 403 header if the expected POST vars arent set or their sanitized values evaluates to empty.
+ */
+function log_filter_ajax_callback($action, $arg = '') {
+  module_load_include('inc', 'log_filter', 'LogFilter');
+  LogFilter::ajaxCallback($action, $arg);
+}

+ 9 - 0
sites/all/modules/contrib/admin/log_filter/release_notes/release_notes_7.x-1.0.txt

@@ -0,0 +1,9 @@
+Log Filter 7.x-1.0
+
+
+First release.
+
+
+Install/update notes
+--------------------
+* Clear cache.

+ 14 - 0
sites/all/modules/contrib/admin/log_filter/release_notes/release_notes_7.x-y.z.txt

@@ -0,0 +1,14 @@
+Log Filter 7.x-y.z
+
+
+New features
+------------
+* X
+
+Bug fixes
+---------
+* Y
+
+Install/update notes
+--------------------
+* Z

+ 196 - 0
sites/all/modules/contrib/judy/CHANGELOG.txt

@@ -0,0 +1,196 @@
+judy 7.x-2.x, 2014-04-27
+------------------------
+* Fixed that dialog title couldn't be set as HTML when using later version of jQuery UI (~ jquery_update module support).
+* Fixed that dialog z-index isn't 1000 when using later version of jQuery UI (~ jquery_update module support); which rendered dialog below admin_menu.
+* Fixed that jQuery >=1.9 has no browser property (~ jquery_update module support).
+
+judy 7.x-2.x, 2013-07-21
+------------------------
+* Implemented ajaxcomplete event.
+
+judy 7.x-2.1, 2013-07-04
+--------------------------------------------------
+* Released.
+
+judy 7.x-2.x, 2013-07-04
+------------------------
+* Moved to correctly named development branch.
+
+judy 7.x-2.0.x, 2013-07-04
+--------------------------
+* Added .version property.
+
+judy 7.x-2.0.x, 2013-06-29
+--------------------------
+* Cleanup.
+
+judy 7.x-2.0.x, 2013-06-27
+--------------------------
+* Now adds .keystrokes attribute on keydown/keyup event.
+
+judy 7.x-2.0.x, 2013-06-22
+--------------------------
+* Prevent double disable.
+
+judy 7.x-2.0.x, 2013-05-25
+--------------------------
+* Fixed premature check for jQuery UI dialog support.
+* Implemented contentClass option for Judy.dialog.
+
+judy 7.x-2.0.x, 2013-04-21
+--------------------------
+* Created methods scrollTrap() and scrollTo().
+
+judy 7.x-2.0.x, 2013-03-26
+--------------------------
+* Created multi-element support for enable/disable().
+
+judy 7.x-2.0.x, 2013-03-03
+--------------------------
+* Fixed missing radios support in enable/disable().
+* Made innerWidth/innerHeight/outerWidth/outerHeight() use selector parameter instead of element, and trimmed their algos.
+
+judy 7.x-2.0.x, 2013-03-02
+--------------------------
+* Removed isObject(); use isContainer(o, true) instead.
+* Removed method useragentIE()/useragentIe(); use constant browserIE instead.
+* Removed objectLength(), use Judy.objectKeys(o).length instead.
+* Removed errorHandler(); use inspect.errorHandler() instead.
+* Removed log(); use inspect.console() instead.
+* Removed inspect(); use inspect() directly instead.
+* Removed fieldGet(); use jQuery("[name='" + name + "']").get(0) instead.
+* Made dialog() support all jQuery UI dialog options, events and methods.
+* Fixed dialog()'s autoOpen behaviour.
+* Created overlay().
+* Added stripTags(), setUrlParam(), disable() and enable().
+* Settings page help, and hook_uninstall() implementation.
+
+judy 7.x-2.0.x, 2013-03-01
+--------------------------
+* Removed objectEmpty(); use objectKeys().length instead.
+* Removed checkboxValue(), checklistValue(), radioValue(), selectValue(), textValue(), textareaValue(); use fieldValue() instead.
+* Removed argsToArray(); use toArray() instead (is now IE<9 safe).
+* Methods log(), inspect() and fieldGet() are now deprecated.
+* Created numberToFormat() and numberFromFormat().
+* objectLength() is now deprecated; use objectKeys().length instead.
+
+judy 7.x-2.0.x, 2013-02-28
+--------------------------
+* Eliminated own event model; now uses jQuery events for everything, including key events.
+* Removed eventAdd(), eventRemove().
+* errorHandler() is now deprecated, use inspect.errorHandler() instead.
+* Removed parameter jQueryEvents from method eventList(); all events are now jQuery events.
+* Changed parameter signature for isField(); now only supports element not selector.
+* Removed fieldFocus().
+
+
+judy 7.x-1.3.x, 2013-02-10
+--------------------------
+* Removed initial Inspect dependency; this library should find Inspect (if exists) even if this library gets included before Inspect.
+
+judy 7.x-1.3.x, 2013-02-09
+--------------------------
+* Made judy a library includable via drupal_add_library(), and added admin page.
+
+judy 7.x-1.3.x, 2013-02-02
+--------------------------
+* Fixed midnight bug in .dateFromFormat(), now sets seconds and milliseconds to zero; because 00:00:00 is 'today', whereas 24:00:00 is 'tomorrow', thus a date must start at zero.
+
+judy 7.x-1.3.x, 2013-01-19
+--------------------------
+* Fixed bug in .dialog() - established no element id when falsy selector arg.
+* Fixed bug in .dialog() - failed to get element when called later using #id selector.
+* .dialog() now always returns the id of the dialog box, except for calls using one of the methods.
+
+judy 7.x-1.3.x, 2013-01-05
+--------------------------
+* Fixed bad bug in .selectValue() - setting selectedIndex is seriously unhealthy, may effectively ruin the select.
+
+judy 7.x-1.3.x, 2012-11-18
+--------------------------
+* Added preventDefault parameter to .onKey().
+* Removed keystrokes ctr|meta+alt limitation.
+* Created method .keydown(); full support for data etc.
+
+judy 7.x-1.3.x, 2012-11-10
+--------------------------
+* Added method argsToArray; function arguments are error-prone.
+* Fixed uses of Inspect.
+* Implemented key event adder, that uses jQuery instead of custom event implementation.
+
+judy 7.x-1.3.x, 2012-09-02
+--------------------------
+* eventList() now supports regular and weird structure of jQuery data.
+
+judy 7.x-1.3.x, 2012-07-29
+--------------------------
+* judy data object for events et al now has random name judy_[a-z\d]{20}.
+* Created jQuery.ui.dialog wrapper/factory method.
+
+judy 7.x-1.3.x, 2012-07-26
+--------------------------
+* Return value of selectValue() is now empty string even for multiple select, when none selected or only _none is selected.
+* Added context parameter to isField().
+* Max parameter added to ancestor().
+* checklistValue() done.
+* selectValue() refactored, too messy.
+* Tighter toLeading().
+
+judy 7.x-1.3.x, 2012-07-25
+--------------------------
+* eventRemove() now removes actual element listeners (minor detail ;-).
+* Made containerCopy use Array.concat() when array and shallow copy.
+* Far better isContainer() and isObject(); now checks for all built-in object types, like typeOf().
+* Tuned date formatter.
+* Backend: hook implementation that includes Javascript now implements hook_preprocess_html (instead of hook_init).
+
+judy 7.x-1.3.x, 2012-07-24
+--------------------------
+* Made field methods support element as first argument (not only name), and made the treatment of the type argument more restrictive.
+* Added textValue() and textareaValue().
+* Safer and shorter toArray().
+* Fixed jsdoc comments, for jsdoc parser.
+* objectGet(): better check for bad key arg.
+* Added isNumber().
+* Implemented eventRemove().
+
+judy 7.x-1.3.x, 2012-07-23
+--------------------------
+* Now using Drupal git repository.
+* Moved javascript file inclusion to hook_preprocess() implementation.
+* Code formatting.
+* Started on making field methods accept element, not only name.
+
+judy 7.x-1.2, 2012-03-16
+------------------------
+* Getting value using .selectValue() now returns "" for "_none".
+
+judy 7.x-1.2, 2012-01-19
+------------------------
+* New method toArray
+
+judy 7.x-1.2, 2012-01-12
+------------------------
+* dateFromFormat: check for impossible date, plus more flexible format support.
+* New method isLeapYear
+
+judy 7.x-1.2, 2012-01-11
+------------------------
+* Added toUpperCaseFirst method.
+
+judy 7.x-1.1, 2012-01-11
+------------------------
+* Added isInt method.
+
+judy 7.x-1.0, 2012-01-10
+------------------------
+* Dedicated .innerWidth/Height support for window/document/body.
+* .outerWidth/Height methods.
+
+judy 7.x-1.0, 2012-01-02
+------------------------
+* Construcion and adding of event handler moved to separate function to prevent iteration errors when adding more in one go.
+
+judy 7.x-1.x, 2011-12-26
+------------------------
+* Started

+ 18 - 0
sites/all/modules/contrib/judy/COPYRIGHT.txt

@@ -0,0 +1,18 @@
+
+All code of the Drupal module Judy is Copyright 2012-2014 Jacob Friis Mathiasen.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+This program 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 as the file LICENSE.txt; if not, please see
+http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+
+Drupal is a registered trademark of Dries Buytaert.

+ 339 - 0
sites/all/modules/contrib/judy/LICENSE.txt

@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.

Some files were not shown because too many files changed in this diff