From 3529d05ccc7c13c9ff5c4e0ba5264eda7e3ea8c8 Mon Sep 17 00:00:00 2001
From: Jessica Leveque <leveque@lapp.in2p3.fr>
Date: Wed, 30 Jan 2013 15:43:38 +0100
Subject: [PATCH] tagging CoolRunQuery-00-04-50 (CoolRunQuery-00-04-50)

---
 Database/CoolRunQuery/cmt/requirements        |   35 +
 Database/CoolRunQuery/doc/README              |    5 +
 Database/CoolRunQuery/doc/todo.txt            |   30 +
 .../CoolRunQuery/html/LumiRangeCollection.dtd |   25 +
 .../CoolRunQuery/html/atlas-runquery-help.css |   54 +
 .../html/atlas-runquery-help.html             |   84 +
 .../CoolRunQuery/html/atlas-runquery-lb.css   |   56 +
 .../html/atlas-runquery-maintanancenote.html  |   80 +
 .../html/atlas-runquery-print.css             |   33 +
 .../html/atlas-runquery-relnotes.html         |  121 +
 .../html/atlas-runquery-results.css           |  158 ++
 .../html/atlas-runquery-tabview.css           |   38 +
 Database/CoolRunQuery/html/atlas-runquery.css |  411 +++
 .../CoolRunQuery/html/atlas-runquery.html     |  252 ++
 Database/CoolRunQuery/html/atlas1.ico         |  Bin 0 -> 894 bytes
 .../CoolRunQuery/html/images/1332500.thm.gif  |  Bin 0 -> 398 bytes
 .../CoolRunQuery/html/images/arrow-down.gif   |  Bin 0 -> 852 bytes
 .../CoolRunQuery/html/images/arrow-up.gif     |  Bin 0 -> 851 bytes
 Database/CoolRunQuery/html/images/atlas1.ico  |  Bin 0 -> 894 bytes
 Database/CoolRunQuery/html/images/book.gif    |  Bin 0 -> 361 bytes
 Database/CoolRunQuery/html/images/cclose.jpg  |  Bin 0 -> 741 bytes
 Database/CoolRunQuery/html/images/close.gif   |  Bin 0 -> 381 bytes
 Database/CoolRunQuery/html/images/copen.jpg   |  Bin 0 -> 749 bytes
 Database/CoolRunQuery/html/images/days.gif    |  Bin 0 -> 161 bytes
 .../CoolRunQuery/html/images/download.gif     |  Bin 0 -> 120 bytes
 Database/CoolRunQuery/html/images/i_icon.png  |  Bin 0 -> 4029 bytes
 Database/CoolRunQuery/html/images/info.gif    |  Bin 0 -> 212 bytes
 Database/CoolRunQuery/html/images/minus.gif   |  Bin 0 -> 974 bytes
 .../CoolRunQuery/html/images/newtopic.gif     |  Bin 0 -> 340 bytes
 Database/CoolRunQuery/html/images/open.gif    |  Bin 0 -> 389 bytes
 Database/CoolRunQuery/html/images/plus.gif    |  Bin 0 -> 981 bytes
 Database/CoolRunQuery/html/images/printer.png |  Bin 0 -> 13761 bytes
 .../CoolRunQuery/html/images/printer2.png     |  Bin 0 -> 38049 bytes
 .../CoolRunQuery/html/images/printtopic.gif   |  Bin 0 -> 221 bytes
 .../CoolRunQuery/html/images/question-1.gif   |  Bin 0 -> 214 bytes
 .../CoolRunQuery/html/images/question.gif     |  Bin 0 -> 214 bytes
 .../html/images/recentchanges.gif             |  Bin 0 -> 220 bytes
 .../html/images/rootdrawing-logo.png          |  Bin 0 -> 15051 bytes
 .../CoolRunQuery/html/images/rootlogo.gif     |  Bin 0 -> 19590 bytes
 .../CoolRunQuery/html/images/statistics.gif   |  Bin 0 -> 118 bytes
 .../CoolRunQuery/html/images/tiny_red.gif     |  Bin 0 -> 310 bytes
 .../CoolRunQuery/html/images/tree_icon.gif    |  Bin 0 -> 1891 bytes
 .../CoolRunQuery/html/images/viewtopic.gif    |  Bin 0 -> 77 bytes
 Database/CoolRunQuery/html/images/wip.gif     |  Bin 0 -> 594 bytes
 .../CoolRunQuery/html/images/xml-feed.gif     |  Bin 0 -> 429 bytes
 .../CoolRunQuery/html/images/xml-small.gif    |  Bin 0 -> 121 bytes
 .../CoolRunQuery/html/js/animatedcollapse.js  |  223 ++
 Database/CoolRunQuery/html/js/dw_event.js     |   41 +
 Database/CoolRunQuery/html/js/dw_tooltip.js   |  502 ++++
 .../CoolRunQuery/html/js/dw_tooltip_aux.js    |  178 ++
 Database/CoolRunQuery/html/js/dw_viewport.js  |   61 +
 Database/CoolRunQuery/html/js/jquery.min.js   |   19 +
 .../html/js/jquery.popupWindow.js             |   62 +
 Database/CoolRunQuery/html/js/rq.js           |   48 +
 Database/CoolRunQuery/html/js/rq_examples.js  |  500 ++++
 .../CoolRunQuery/html/js/rq_simplepopups.js   |   75 +
 Database/CoolRunQuery/html/js/switcher.js     |   97 +
 Database/CoolRunQuery/html/js/tabView.js      |   84 +
 .../CoolRunQuery/macros/AtlRunQueryGraphs.C   |    4 +
 Database/CoolRunQuery/macros/colours.C        |   68 +
 Database/CoolRunQuery/macros/style.C          |   39 +
 .../CoolRunQuery/python/AtlRunQueryAMI.py     |  231 ++
 .../CoolRunQuery/python/AtlRunQueryCOMA.py    |  178 ++
 .../CoolRunQuery/python/AtlRunQueryLib.py     |  349 +++
 .../CoolRunQuery/python/AtlRunQueryLookup.py  |    3 +
 .../CoolRunQuery/python/AtlRunQueryOptions.py |  237 ++
 .../CoolRunQuery/python/AtlRunQueryPVSS.py    |   34 +
 .../CoolRunQuery/python/AtlRunQueryParser.py  |  839 +++++++
 .../python/AtlRunQueryQueryConfig.py          |   24 +
 .../CoolRunQuery/python/AtlRunQueryRun.py     | 2209 +++++++++++++++++
 .../CoolRunQuery/python/AtlRunQuerySFO.py     |  438 ++++
 .../python/AtlRunQuerySelectorWorker.py       |  303 +++
 .../CoolRunQuery/python/AtlRunQueryTier0.py   |   54 +
 .../CoolRunQuery/python/AtlRunQueryVersion.py |    3 +
 Database/CoolRunQuery/python/__init__.py      |    7 +
 .../python/html/AtlRunQueryDQSummary.py       |  969 ++++++++
 .../python/html/AtlRunQueryHTML.py            |  377 +++
 .../python/html/AtlRunQueryHtmlUtils.py       |  435 ++++
 .../python/html/AtlRunQueryPageMaker.py       |   50 +
 .../python/html/AtlRunQuerySummary.py         |  651 +++++
 Database/CoolRunQuery/python/html/__init__.py |    2 +
 .../python/output/AtlRunQueryRoot.py          |  975 ++++++++
 .../python/output/AtlRunQuerySave.py          |  152 ++
 .../python/output/AtlRunQueryXML.py           |  277 +++
 .../CoolRunQuery/python/output/__init__.py    |    2 +
 .../selector/AtlRunQuerySelectorBase.py       |  609 +++++
 .../python/selector/AtlRunQuerySelectorDQ.py  |  697 ++++++
 .../selector/AtlRunQuerySelectorEvents.py     |  132 +
 .../selector/AtlRunQuerySelectorLhcOlc.py     |  488 ++++
 .../selector/AtlRunQuerySelectorMisc.py       |  335 +++
 .../selector/AtlRunQuerySelectorRuntime.py    |  133 +
 .../selector/AtlRunQuerySelectorStreams.py    |  303 +++
 .../selector/AtlRunQuerySelectorTrigger.py    |  588 +++++
 .../CoolRunQuery/python/selector/__init__.py  |    2 +
 .../python/utils/AtlRunQueryCache.py          |   89 +
 .../python/utils/AtlRunQueryDQUtils.py        |  221 ++
 .../python/utils/AtlRunQueryFastBlobRead.py   |   21 +
 .../python/utils/AtlRunQueryIOV.py            |  118 +
 .../python/utils/AtlRunQueryLookup.py         |  290 +++
 .../python/utils/AtlRunQueryMemUtil.py        |   45 +
 .../python/utils/AtlRunQueryTimer.py          |  104 +
 .../python/utils/AtlRunQueryTriggerUtils.py   |  285 +++
 .../python/utils/AtlRunQueryUtils.py          |  633 +++++
 .../CoolRunQuery/python/utils/__init__.py     |    2 +
 Database/CoolRunQuery/share/AtlRunQuery.py    |   83 +
 .../CoolRunQuery/share/AtlRunQueryGraphs.py   |  116 +
 .../CoolRunQuery/share/CoolRunQueryWrapper.sh |   47 +
 .../share/CoolRunQueryWrapper47.sh            |   37 +
 Database/CoolRunQuery/share/easycommit        |  124 +
 Database/CoolRunQuery/share/grepfile.py       |   95 +
 Database/CoolRunQuery/share/query.py          |  114 +
 Database/CoolRunQuery/share/subproc.py        |   37 +
 112 files changed, 17930 insertions(+)
 create mode 100644 Database/CoolRunQuery/cmt/requirements
 create mode 100644 Database/CoolRunQuery/doc/README
 create mode 100644 Database/CoolRunQuery/doc/todo.txt
 create mode 100644 Database/CoolRunQuery/html/LumiRangeCollection.dtd
 create mode 100644 Database/CoolRunQuery/html/atlas-runquery-help.css
 create mode 100644 Database/CoolRunQuery/html/atlas-runquery-help.html
 create mode 100644 Database/CoolRunQuery/html/atlas-runquery-lb.css
 create mode 100644 Database/CoolRunQuery/html/atlas-runquery-maintanancenote.html
 create mode 100644 Database/CoolRunQuery/html/atlas-runquery-print.css
 create mode 100644 Database/CoolRunQuery/html/atlas-runquery-relnotes.html
 create mode 100644 Database/CoolRunQuery/html/atlas-runquery-results.css
 create mode 100644 Database/CoolRunQuery/html/atlas-runquery-tabview.css
 create mode 100644 Database/CoolRunQuery/html/atlas-runquery.css
 create mode 100644 Database/CoolRunQuery/html/atlas-runquery.html
 create mode 100644 Database/CoolRunQuery/html/atlas1.ico
 create mode 100644 Database/CoolRunQuery/html/images/1332500.thm.gif
 create mode 100644 Database/CoolRunQuery/html/images/arrow-down.gif
 create mode 100644 Database/CoolRunQuery/html/images/arrow-up.gif
 create mode 100644 Database/CoolRunQuery/html/images/atlas1.ico
 create mode 100644 Database/CoolRunQuery/html/images/book.gif
 create mode 100644 Database/CoolRunQuery/html/images/cclose.jpg
 create mode 100644 Database/CoolRunQuery/html/images/close.gif
 create mode 100644 Database/CoolRunQuery/html/images/copen.jpg
 create mode 100644 Database/CoolRunQuery/html/images/days.gif
 create mode 100644 Database/CoolRunQuery/html/images/download.gif
 create mode 100644 Database/CoolRunQuery/html/images/i_icon.png
 create mode 100644 Database/CoolRunQuery/html/images/info.gif
 create mode 100644 Database/CoolRunQuery/html/images/minus.gif
 create mode 100644 Database/CoolRunQuery/html/images/newtopic.gif
 create mode 100644 Database/CoolRunQuery/html/images/open.gif
 create mode 100644 Database/CoolRunQuery/html/images/plus.gif
 create mode 100644 Database/CoolRunQuery/html/images/printer.png
 create mode 100644 Database/CoolRunQuery/html/images/printer2.png
 create mode 100644 Database/CoolRunQuery/html/images/printtopic.gif
 create mode 100644 Database/CoolRunQuery/html/images/question-1.gif
 create mode 100644 Database/CoolRunQuery/html/images/question.gif
 create mode 100644 Database/CoolRunQuery/html/images/recentchanges.gif
 create mode 100644 Database/CoolRunQuery/html/images/rootdrawing-logo.png
 create mode 100644 Database/CoolRunQuery/html/images/rootlogo.gif
 create mode 100644 Database/CoolRunQuery/html/images/statistics.gif
 create mode 100644 Database/CoolRunQuery/html/images/tiny_red.gif
 create mode 100644 Database/CoolRunQuery/html/images/tree_icon.gif
 create mode 100644 Database/CoolRunQuery/html/images/viewtopic.gif
 create mode 100644 Database/CoolRunQuery/html/images/wip.gif
 create mode 100644 Database/CoolRunQuery/html/images/xml-feed.gif
 create mode 100644 Database/CoolRunQuery/html/images/xml-small.gif
 create mode 100644 Database/CoolRunQuery/html/js/animatedcollapse.js
 create mode 100755 Database/CoolRunQuery/html/js/dw_event.js
 create mode 100755 Database/CoolRunQuery/html/js/dw_tooltip.js
 create mode 100755 Database/CoolRunQuery/html/js/dw_tooltip_aux.js
 create mode 100755 Database/CoolRunQuery/html/js/dw_viewport.js
 create mode 100644 Database/CoolRunQuery/html/js/jquery.min.js
 create mode 100644 Database/CoolRunQuery/html/js/jquery.popupWindow.js
 create mode 100644 Database/CoolRunQuery/html/js/rq.js
 create mode 100644 Database/CoolRunQuery/html/js/rq_examples.js
 create mode 100644 Database/CoolRunQuery/html/js/rq_simplepopups.js
 create mode 100644 Database/CoolRunQuery/html/js/switcher.js
 create mode 100644 Database/CoolRunQuery/html/js/tabView.js
 create mode 100644 Database/CoolRunQuery/macros/AtlRunQueryGraphs.C
 create mode 100644 Database/CoolRunQuery/macros/colours.C
 create mode 100644 Database/CoolRunQuery/macros/style.C
 create mode 100644 Database/CoolRunQuery/python/AtlRunQueryAMI.py
 create mode 100755 Database/CoolRunQuery/python/AtlRunQueryCOMA.py
 create mode 100755 Database/CoolRunQuery/python/AtlRunQueryLib.py
 create mode 100644 Database/CoolRunQuery/python/AtlRunQueryLookup.py
 create mode 100644 Database/CoolRunQuery/python/AtlRunQueryOptions.py
 create mode 100644 Database/CoolRunQuery/python/AtlRunQueryPVSS.py
 create mode 100755 Database/CoolRunQuery/python/AtlRunQueryParser.py
 create mode 100644 Database/CoolRunQuery/python/AtlRunQueryQueryConfig.py
 create mode 100644 Database/CoolRunQuery/python/AtlRunQueryRun.py
 create mode 100644 Database/CoolRunQuery/python/AtlRunQuerySFO.py
 create mode 100644 Database/CoolRunQuery/python/AtlRunQuerySelectorWorker.py
 create mode 100644 Database/CoolRunQuery/python/AtlRunQueryTier0.py
 create mode 100644 Database/CoolRunQuery/python/AtlRunQueryVersion.py
 create mode 100644 Database/CoolRunQuery/python/__init__.py
 create mode 100755 Database/CoolRunQuery/python/html/AtlRunQueryDQSummary.py
 create mode 100644 Database/CoolRunQuery/python/html/AtlRunQueryHTML.py
 create mode 100755 Database/CoolRunQuery/python/html/AtlRunQueryHtmlUtils.py
 create mode 100644 Database/CoolRunQuery/python/html/AtlRunQueryPageMaker.py
 create mode 100644 Database/CoolRunQuery/python/html/AtlRunQuerySummary.py
 create mode 100644 Database/CoolRunQuery/python/html/__init__.py
 create mode 100644 Database/CoolRunQuery/python/output/AtlRunQueryRoot.py
 create mode 100644 Database/CoolRunQuery/python/output/AtlRunQuerySave.py
 create mode 100644 Database/CoolRunQuery/python/output/AtlRunQueryXML.py
 create mode 100644 Database/CoolRunQuery/python/output/__init__.py
 create mode 100644 Database/CoolRunQuery/python/selector/AtlRunQuerySelectorBase.py
 create mode 100644 Database/CoolRunQuery/python/selector/AtlRunQuerySelectorDQ.py
 create mode 100644 Database/CoolRunQuery/python/selector/AtlRunQuerySelectorEvents.py
 create mode 100644 Database/CoolRunQuery/python/selector/AtlRunQuerySelectorLhcOlc.py
 create mode 100644 Database/CoolRunQuery/python/selector/AtlRunQuerySelectorMisc.py
 create mode 100644 Database/CoolRunQuery/python/selector/AtlRunQuerySelectorRuntime.py
 create mode 100644 Database/CoolRunQuery/python/selector/AtlRunQuerySelectorStreams.py
 create mode 100644 Database/CoolRunQuery/python/selector/AtlRunQuerySelectorTrigger.py
 create mode 100644 Database/CoolRunQuery/python/selector/__init__.py
 create mode 100755 Database/CoolRunQuery/python/utils/AtlRunQueryCache.py
 create mode 100644 Database/CoolRunQuery/python/utils/AtlRunQueryDQUtils.py
 create mode 100644 Database/CoolRunQuery/python/utils/AtlRunQueryFastBlobRead.py
 create mode 100644 Database/CoolRunQuery/python/utils/AtlRunQueryIOV.py
 create mode 100644 Database/CoolRunQuery/python/utils/AtlRunQueryLookup.py
 create mode 100644 Database/CoolRunQuery/python/utils/AtlRunQueryMemUtil.py
 create mode 100644 Database/CoolRunQuery/python/utils/AtlRunQueryTimer.py
 create mode 100755 Database/CoolRunQuery/python/utils/AtlRunQueryTriggerUtils.py
 create mode 100644 Database/CoolRunQuery/python/utils/AtlRunQueryUtils.py
 create mode 100644 Database/CoolRunQuery/python/utils/__init__.py
 create mode 100755 Database/CoolRunQuery/share/AtlRunQuery.py
 create mode 100755 Database/CoolRunQuery/share/AtlRunQueryGraphs.py
 create mode 100755 Database/CoolRunQuery/share/CoolRunQueryWrapper.sh
 create mode 100755 Database/CoolRunQuery/share/CoolRunQueryWrapper47.sh
 create mode 100755 Database/CoolRunQuery/share/easycommit
 create mode 100644 Database/CoolRunQuery/share/grepfile.py
 create mode 100644 Database/CoolRunQuery/share/query.py
 create mode 100644 Database/CoolRunQuery/share/subproc.py

diff --git a/Database/CoolRunQuery/cmt/requirements b/Database/CoolRunQuery/cmt/requirements
new file mode 100644
index 00000000000..b7007522dc5
--- /dev/null
+++ b/Database/CoolRunQuery/cmt/requirements
@@ -0,0 +1,35 @@
+# $Id: requirements,v 1.2 2008-11-19 18:56:51 stelzer Exp $
+
+package CoolRunQuery
+
+author Andreas.Hoecker@cern.ch Joerg.Stelzer@cern.ch
+manager Andreas.Hoecker@cern.ch Joerg.Stelzer@cern.ch
+
+use AtlasPolicy *
+
+
+pattern declare_arq_python_modules \
+    apply_pattern generic_declare_for_link kind=python_modules_<dir> files='-s=../python <files>' prefix=python/<package>/<dir> name=arqpy<dir> ; \
+    private ; \
+    macro_append <package>_python_init_dependencies " install_arqpy<dir>python_modules " ; \
+    end_private
+
+
+
+apply_pattern declare_arq_python_modules files="*.py" dir=""
+apply_pattern declare_arq_python_modules files="html/*.py" dir="html"
+apply_pattern declare_arq_python_modules files="selector/*.py" dir="selector"
+apply_pattern declare_arq_python_modules files="utils/*.py" dir="utils"
+apply_pattern declare_arq_python_modules files="output/*.py" dir="output"
+
+apply_pattern declare_scripts files="*.py *.C"
+
+pattern declare_xml \
+    apply_pattern generic_declare_for_link kind=xml files='-s=../html <files>' prefix=XML/<package> name=<name>
+
+pattern declare_html \
+    apply_pattern generic_declare_for_link kind=html files='-s=../html <files>' prefix=html/<package> name=<name>
+
+apply_pattern declare_xml files="*.html *.dtd"
+
+apply_pattern declare_html files="*.html *.dtd *.css"
diff --git a/Database/CoolRunQuery/doc/README b/Database/CoolRunQuery/doc/README
new file mode 100644
index 00000000000..1ff8cb8a114
--- /dev/null
+++ b/Database/CoolRunQuery/doc/README
@@ -0,0 +1,5 @@
+SVN updates
+
+1) svn up and svn ci
+2) tagsvn.sh CoolRunQuery-00-00-14  (was immer du zum taggen benutzt)
+3) auf voatlas24 in /var/www/html/atlas-runquery: . ./switchtag.sh hoecker 00-00-14
diff --git a/Database/CoolRunQuery/doc/todo.txt b/Database/CoolRunQuery/doc/todo.txt
new file mode 100644
index 00000000000..2de2546d3f4
--- /dev/null
+++ b/Database/CoolRunQuery/doc/todo.txt
@@ -0,0 +1,30 @@
+Run Query - todo
+
+Features:
+
+- fix order of output
+- examples sollten gleich bleiben nach ausfuehren des queries (very difficult)
+- Show: add L1 trigger rates (eg, 'show trates')
+- Show atlas runtype
+
+- add new COOL folders from Armin about Tier-0 reconstruction efficiency
+  /afs/cern.ch/atlas/project/tzero/prod1/projects/data09/rfc/RawFileCounter.sh
+- nicify dataset info on CAF
+
+- Payload based query  
+- Query caching: have the web page saved in a cache if one wants to send the query results to someone (Andreas)
+- Add path to CASTOR for datasets (wish from Sylvie)
+- Click on column title of selected runs and sort table accordingly (number of events, LBs, duration, etc)
+
+- Create API for external access
+- Print default settings to web page
+
+- Better error report, maybe popup window
+
+- Be able to query on number of events pasing a certain trigger chain or selecting on prescales/pass through of a trigger (or PSKs) -> see email from Kenneth Johns <kjohns@mail.cern.ch>.
+
+- Add luminosity information 
+
+Bugs:
+
+- this probably does not work yet: showing the same DQ flag from two different folders
diff --git a/Database/CoolRunQuery/html/LumiRangeCollection.dtd b/Database/CoolRunQuery/html/LumiRangeCollection.dtd
new file mode 100644
index 00000000000..2d11b4575ac
--- /dev/null
+++ b/Database/CoolRunQuery/html/LumiRangeCollection.dtd
@@ -0,0 +1,25 @@
+<!ELEMENT LumiRangeCollection (NamedLumiRange*)>
+
+<!ELEMENT NamedLumiRange (Name?, Version?, Metadata*, LumiBlockCollection*)>
+
+<!ELEMENT Metadata (#PCDATA|Stream)*>
+<!ATTLIST Metadata Name CDATA #REQUIRED>
+
+<!ELEMENT Stream EMPTY>
+<!ATTLIST Stream
+    Name CDATA #REQUIRED
+    TotalNumOfEvents CDATA #IMPLIED
+    NumOfSelectedEvents CDATA #IMPLIED
+>
+
+<!ELEMENT LumiBlockCollection (Run, LBRange*)>
+
+<!ELEMENT Name (#PCDATA)>
+<!ELEMENT Version (#PCDATA)>
+<!ELEMENT Run (#PCDATA)>
+<!ATTLIST Run PrescaleRD0 CDATA #IMPLIED>
+<!ATTLIST Run PrescaleRD1 CDATA #IMPLIED>
+<!ELEMENT LBRange EMPTY>
+<!ATTLIST LBRange Start CDATA #REQUIRED> 
+<!ATTLIST LBRange End CDATA #IMPLIED>
+
diff --git a/Database/CoolRunQuery/html/atlas-runquery-help.css b/Database/CoolRunQuery/html/atlas-runquery-help.css
new file mode 100644
index 00000000000..bc459382867
--- /dev/null
+++ b/Database/CoolRunQuery/html/atlas-runquery-help.css
@@ -0,0 +1,54 @@
+table.myhelptable {
+  table-layout: fixed;
+  margin: 0em 0em 0em 0;
+  background: white;
+  border-collapse: collapse;
+}
+table.myhelptable th.coltitle, table.myhelptable th.alltitle, table.myhelptable th.alldescr, table.myhelptable td {
+  border: 2px white solid;
+  padding: 4px;
+  vertical-align: top;
+}
+table.myhelptable th {
+  text-align: left;
+  background: gainsboro;
+  padding: 4px;
+  vertical-align: top;
+}
+table.myhelptable td, td.t1, td.t2 td.out1 td.out2 {
+  font-size: 80%;
+}
+
+table.myhelptable caption {
+  margin-left: inherit;
+  margin-right: inherit;
+}
+
+table.mysmallhelptable {
+  table-layout: fixed;
+  margin: 0em 0em 0em 0;
+  background: white;
+  border-collapse: collapse;
+}
+table.mysmallhelptable th.coltitle, table.mysmallhelptable th.alltitle, table.mysmallhelptable th.alldescr, table.mysmallhelptable td {
+  border: 2px white solid;
+  padding: 4px;
+  vertical-align: top;
+}
+table.mysmallhelptable th {
+  text-align: left;
+  background: gainsboro;
+  padding: 4px;
+  vertical-align: top;
+}
+table.mysmallhelptable td {
+  color: #555555;
+}
+table.mysmallhelptable td, td.t1, td.t2 td.out1 td.out2 {
+  font-size: 80%;
+}
+table.mysmallhelptable caption {
+  margin-left: inherit;
+  margin-right: inherit;
+}
+
diff --git a/Database/CoolRunQuery/html/atlas-runquery-help.html b/Database/CoolRunQuery/html/atlas-runquery-help.html
new file mode 100644
index 00000000000..10a0a8ebee2
--- /dev/null
+++ b/Database/CoolRunQuery/html/atlas-runquery-help.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html xmlns:my>
+<head>
+<title>ATLAS Run Query &minus; Help</title>
+
+<LINK href="atlas-runquery-help.css" rel="stylesheet" type="text/css">
+
+<body style="background-color: #ffffff;">
+
+<table class="mytable"><tr><th class="coltitle" style="font-family: sans-serif; font-size: 100%; background: #6D7B8D; color:white; height: 40px; vertical-align: middle">ATLAS Run Query &minus; Help</th>
+</tr><tr>
+  <td height="10"</td></tr><tr>
+  <td><b>Query format:</b> <br>
+    <ul>
+    <table class="mysmallhelptable">
+      <tr>
+        <th colspan="2"><b>f(ind) [<i>condition1</i> and <i>condition2</i> and ...] / sh(ow) [<i>tag1</i> and <i>tag2</i> and ...] [/ other options]</b> </td>
+      </tr><tr>
+        <td colspan="2" height="3"></td>
+      </tr><tr>
+        <td width="100" valign="top"> <i>find</i> conditions:</td><td> Composed of <i>tag</i> and <i>argument</i>, where any of the tags defined in table below can be used. <br>
+                                 By default is used: "partition ATLAS and ftag data08*".</td>
+      </tr><tr>
+        <td valign="top"> <i>show</i> tags:</td><td> By default: run number, #lumi blocks (LB) and #events are shown for the selected runs.<br>
+                                 More tags (any of the list below) can be added. Note however that adding more tags will require
+                                 more data to be read from the DB, which increases the query delay (the same is true for the <i>find</i> conditions). </td>
+      </tr><tr>
+        <td valign="top">Other options:</td><td>Switch off use of default conditions by adding "/ nodef" to the end of the query.</td>
+      </tr><tr>
+        <td valign="top">Abbreviations:</td><td>Text in paranthesis can be dropped. <br>
+                         For example: "f" is equal to "find", "sh" is equal to "show", "r" is equal to "runs" (cf. tags below), etc.</td>
+      </tr>
+    </table> 
+  </ul>
+  </td>
+</tr><tr>
+  <td height=10 valign="bottom"><b>Available <i>find</i> and <i>show</i> tags:</b></td>
+</tr><tr>
+  <td height=7 valign="bottom"><b></b></td>
+</tr><tr>
+  <td>
+<ul>
+  <table class="myhelptable">
+    <tr>
+      <th width="80"> Tag</th><th>Format examples</th><th>Description</th>
+      </tr><tr>
+      <td class="t1">   r(uns)       </td><td class="t1"> "run 91000", "runs 91000-92000", <br>"runs 91000-(+)"(this run and all before (after)) </td><td class="t1">Run number</td>
+    </tr><tr>
+      <td class="t2">   t(ime)       </td><td class="t2"> "time 10.9.2008-30.9.2008", <br>"time 15.10.2008-(+)" (this date and all before (after)) </td><td class="t2"> Date and time of run range. <br> <font color="red">Note that the time is the CTP (LB1_start -> LBLast_end) time corresponding to the genuine running time where triggers were accepted, and NOT the Run Control time.</font> </td>
+    </tr><tr>
+      <td class="t1">   dur(ation)   </td><td class="t1"> "10d/h/m/s+/-", e.g., "2000s+" (run duration more than 2000 sec), <br> "3h-" (less than 3 hours) </td><td class="t1"> Run duration (see remark on time above)</td>
+    </tr><tr>
+      <td class="t2">   ftag         </td><td class="t2"> "ftag data08_cos,data08_cosmag",<br> "ftag data08_cos*" (wildcard can be * or %)</td><td class="t2">ProjectTag in dataset name (denoted "filenameTag" in COOL) </td>
+    </tr><tr>
+      <td class="t1">   p(artition)  </td><td class="t1"> "partition ATLAS" </td><td class="t1">DAQ partition (ATLAS for combined runs)</td>
+    </tr><tr>
+      <td class="t2">   smk          </td><td class="t2"> "smk 398", "smk 398,399"<br> (format like for run ranges)</td><td class="t2"> Super-master-key labelling trigger menu  </td>
+    </tr><tr>
+      <td class="t1">   trigk(eys)   </td><td class="t1"> "show trigkeys"<br> (attribute for "show" only)</td><td class="t1"> Show super-master-key labelling trigger menu as well as L1 and HLT prescale keys and HLT release </td>
+    </tr><tr>
+      <td class="t2">   tr(igger)   </td><td class="t2"> "trigger EF_e5* and tr L1_EM13I", <br>"sh trigger L2_E*,L2_Cosmic*" (wildcard can be * or %)</td><td class="t2"> Select and show trigger chains ("sh tr" displays all chains for all trigger levels)</td>
+    </tr><tr>
+      <td class="t1">   ev(ents)     </td><td class="t1"> "events 10000+",  "events 10000-", ... (same as for run number)</td><td class="t1"> Number of events (event filter accepts) in run</td>
+    </tr><tr>
+      <td class="t2">   alle(vents)     </td><td class="t2"> "show allevents" <br> (attribute for "show" only)</td><td class="t2"> Show all event numbers, i.e., at EF (default), SFO (from inclusive streaming), L1 and L2 levels </td>
+    </tr><tr>
+      <td class="t1">   m(agnet)     </td><td class="t1"> "magnet s(olenoid)", "magnet t(oroid)", "not magnet t(oroid)", ... </td><td class="t1"> Magnetic field configuration</td>
+    </tr><tr>
+      <td class="t2">   det(ector)   </td><td class="t2"> "detector Pixel B" (for Pixel Barrel), <br>"detector Pixel" (for Pixel B & EC), <br>"all" (for all detectors, probed detector mask is 72551459979255)</td><td class="t2"> Detectors participating in run</td>
+    </tr><tr>        
+      <td class="t1">   dq           </td><td class="t1"> "dq [<i>flag</i>] <i>status</i> [<i>folder</i>]", where the DQ status is "g(reen)", "y(ellow)", "r(ed)", "u(known)", example: dq PIXB y+ (means yellow or green status) </td><td class="t1"> Data quality (DQ) status flags per system</td>
+    </tr><tr>
+      <td class="t2">   st(ream)     </td><td class="t2"> "st physics_*", "st *IDCos*", may also select <i>show</i> fields, such as: "sh st *RPC*" </td><td class="t2"> Raw data stream (incl. physics and calibration)</td>
+    </tr><tr>
+      <td class="t1">   all     </td><td class="t1"> "show all" </td><td class="t1"> Show all available information except for trigger; to also show trigger chains, type "show all and trigger"</td>
+    </tr>
+    </table>
+  </ul>
+</ul><hr>
+<font color="#555555"><font size=-2>
+<i>Contact and support: <a href="mailto:andreas.hoecker@cern.ch"><i>Andreas Hoecker</i></a>, <a href="mailto:joerg.stelzer@cern.ch"><i>Joerg Stelzer</i></a> </font></font></td></tr>
+</table>
+</body>
+</html>
diff --git a/Database/CoolRunQuery/html/atlas-runquery-lb.css b/Database/CoolRunQuery/html/atlas-runquery-lb.css
new file mode 100644
index 00000000000..3aeba800e0b
--- /dev/null
+++ b/Database/CoolRunQuery/html/atlas-runquery-lb.css
@@ -0,0 +1,56 @@
+table.outer
+{ 
+  font-family: sans-serif;
+  font-size: 90%;
+  padding: 5px;
+}
+
+table.outer td
+{ 
+  text-align: left;
+}
+
+table.lb 
+{ 
+  width: auto;
+  border: 0px solid;
+  border-width: 0px; 
+  margin: 0 0 0 0;
+  border-spacing: 0px;
+  border-collapse: separate;
+  padding: 0px;
+  font-size: 90%;
+}
+
+table.lb th {
+  padding-left: 10px;
+  font-family: sans-serif;
+  font-weight: bold;
+  text-align: center;
+  vertical-align: bottom;
+  border-right-width: 20px; border-right-style: solid; border-color: white;
+}
+
+table.lb thead tr.second th {
+  padding-left: 10px;
+  font-family: sans-serif;
+  font-weight: normal;
+  font-size: 80%;
+  text-align: center;
+  vertical-align: bottom;
+  border-right-width: 20px; border-right-style: solid; border-color: white;
+}
+
+
+table.lb td {
+  font-family: sans-serif; text-align: right; font-size: 90%; padding-left: 5px; padding-right: 5px;
+}
+
+
+table.lb td.dt { 
+  font-size: 80%; font-style: italic;
+  border-right-width: 10px; border-right-style: solid; border-color: white;
+}
+
+
+
diff --git a/Database/CoolRunQuery/html/atlas-runquery-maintanancenote.html b/Database/CoolRunQuery/html/atlas-runquery-maintanancenote.html
new file mode 100644
index 00000000000..d404ad3d229
--- /dev/null
+++ b/Database/CoolRunQuery/html/atlas-runquery-maintanancenote.html
@@ -0,0 +1,80 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title>Atlas Runquery Maintenance Note</title>
+    <link rel="stylesheet" type="text/css" href="atlas-runquery.css" media="screen">
+  </head>
+
+  <body>
+
+    <table class="toptable">
+      <tr style="height:45px; vertical-align:top;">
+        <td><font size="+1"><b>ATLAS Run Queries</b></font> </td>
+        <td style="padding-right: 0px;">
+          <table style="border-spacing:6px; margin-left:auto; margin-right:12px">
+            <tr>
+
+              <td class="dontPrint" style="border: 1px white solid; padding: 0.3em; width: 56px; text-align:center; font-size: 100%; vertical-align: middle;">
+                <a href="mailto:andreas.hoecker@cern.ch,joerg.stelzer@cern.ch" title="Contact and support">
+                  Contact
+                </a>
+              </td>
+              <td class="dontPrint" style="border: 1px white solid; padding: 0.3em; width: 35px; text-align:center; font-size: 100%">
+                <a href="javascript:helppopup()" title="Help on Run Query Formatting">
+                  Help
+                </a>
+              </td>
+            </tr>
+          </table>
+        </td>
+      </tr>
+      <tr style="height:20px">
+        <td colspan="2">
+          <table class="toptableLinks">
+            <tr>
+              <td><a href="http://pcatdwww.cern.ch/atlas-point1/wmi/current/Run%20Status_wmi/index.html">Current run</a></td>
+              <td><a href="https://atlas.web.cern.ch/Atlas/GROUPS/DATAPREPARATION/">Run Summaries</a></td>
+              <td><a href="http://trigconf.cern.ch/">Trigger Configuration Query</a></td>
+              <td><a href="http://ami.in2p3.fr:8080/AMI/servlet/net.hep.atlas.Database.Bookkeeping.AMI.Servlet.Command?linkId=512">AMI Data Search</a></td>
+              <td><a href="http://dashb-atlas-data.cern.ch/dashboard/request.py/site">DDM Dashboard</a></td>
+              <td><a href="http://atlas.web.cern.ch/Atlas/tzero/prod1/monitoring/">Tier-0 Monitoring</a></td>
+              <td><a href="http://atlasdqm.web.cern.ch/atlasdqm/">DQ Monitoring</a></td>
+              <td><a href="https://twiki.cern.ch/twiki/bin/view/Atlas/DataPreparation">Data Preparation</a></td>
+              <td><a href="http://pcatdwww.cern.ch/atlas-point1/operation.php">Operations</a></td>
+            </tr>
+          </table>
+        </td>
+      </tr>
+    </table>
+    
+    <table>
+        <tr><td width="40px"><td height="100px">
+            <font style="color: darkblue"><strong>The ATLAS Runquery page is currently being maintained and will be back shortly.</strong></font>
+          </td></tr>
+        <tr height="500px"></tr>
+    </table>
+    <table class="bottomtable">
+      <tr style="height:45px; vertical-align: top;">
+        <td>
+          <i>Contact and support:
+            <a href="http://consult.cern.ch/xwho/people/400557">Andreas Hoecker</a>,
+            <a href="http://consult.cern.ch/xwho/people/652897">J&ouml;rg Stelzer</a>
+            </i>
+          </td>
+          <td><i>Maintenance</i></td>
+          <td style="text-align:right"><i>
+            <script language="JavaScript" type="text/javascript">
+              var date  = document.lastModified.toString();
+              if (date == "") {   // unknown date (or January 1, 1970 GMT)
+              document.writeln("Last Modified: Unknown")
+              } else {
+              document.writeln ("Last modified: " + date); }
+            </script>
+          </i></font>                      
+        </td>    
+      </tr>
+    </table>
+    
+
+  </body>
+</html>
diff --git a/Database/CoolRunQuery/html/atlas-runquery-print.css b/Database/CoolRunQuery/html/atlas-runquery-print.css
new file mode 100644
index 00000000000..bd2d4f970f6
--- /dev/null
+++ b/Database/CoolRunQuery/html/atlas-runquery-print.css
@@ -0,0 +1,33 @@
+
+table.toptableLinks { display:none; }
+
+.TabView, .dontPrint { display:none; }
+
+table.mytable {  
+  table-layout: fixed;
+  margin: 0em 0em 0em 0;
+  margin-left: 4px;
+  border: 0px white solid;
+  padding: 0px; 
+  background: white;
+  border-collapse: collapse;
+}
+
+table.mytable th { text-align: left; }
+
+table.bottomtable
+{
+  position: relative;
+  width: 100%;
+  top: auto;
+  bottom: 0;
+  left: 0;
+  right: auto;
+  margin: 0 0 0 0;
+  padding-top: 0px;
+  padding-left: 12px;
+  padding-right: 20px;
+  color: #000000;
+  background-repeat: no-repeat;
+  font-size: 85%;
+}
diff --git a/Database/CoolRunQuery/html/atlas-runquery-relnotes.html b/Database/CoolRunQuery/html/atlas-runquery-relnotes.html
new file mode 100644
index 00000000000..d474e3bac62
--- /dev/null
+++ b/Database/CoolRunQuery/html/atlas-runquery-relnotes.html
@@ -0,0 +1,121 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html xmlns="my">
+  <head>
+    <title>ATLAS Run Query - Change logs</title>
+    
+    <LINK href="atlas-runquery.css" rel="stylesheet" type="text/css">
+    
+  <body style="background-color: #ffffff;">
+    
+    <table class="relnotetable">
+      <thead>
+        <tr><th class="coltitle" style="font-family: sans-serif; font-size: 100%;">Change Logs &minus; Features and Fixes</th></tr>
+      </thead>
+      <tbody>
+        <tr>
+          <td height=40 valign="bottom"><i>Recent items appended to the top (significant features or bug fixes only):</i></td>
+        </tr>
+        <tr height="20"></tr>
+        <!-- next -->
+        <tr>
+          <td>
+            <i>3-Jan-2009:</i>
+            <ul>
+              <li> Tabbed examples</li>
+              <li> Improved help pages</li>
+          </ul>
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <i>20-Dec-2008:</i>
+            <ul>
+              <li> More involved DQ-flag <i>find</i> queries and <i>show</i> patterns (see also notes from 07-Dec-2008)</li>
+              <li> Significant query speed up</li>
+              <li> Access to SFO database for stream queries, and reliable numbers of events per stream</li>
+              <li> Summary (number od runs, events, etc) for selected runs</li>
+              <li> TH1 plots for all numerical query results (see thumbnails at bottom of page after query)</li>
+          </ul>
+          </td>
+        </tr>
+        <!-- next -->
+        <tr>
+          <td>
+            <i>07-Dec-2008:</i>
+            <ul>
+              <li> Extented dataquality browsing using keyword <i>any</i> </li>
+              <li> Query for runs with unset dataquality using dq flag <i>n.a.</i></li>
+              <li><i>Example: f r 90270-90350 and dq any pix n.a.</i></li>
+          </ul>
+          </td>
+        </tr>
+        <!-- next -->
+        <tr>
+          <td>
+            <i>04-Dec-2008:</i>
+            <ul>
+              <li> ROOT file with TTree for download is created from serialised result dictionary</li>
+            </ul>
+          </td>
+        </tr>
+        <!-- next -->
+        <tr>
+          <td>
+            <i>03-Dec-2008:</i>
+            <ul>
+              <li> Speedup searches (more than 2 times faster)</li>
+              <li> Add possibility to search for runs where no DQ is defined e.g. dq PIXB n.a.</li>
+              <li> Added display of number of lumiblocks</li>
+            </ul>
+          </td>
+        </tr>
+        <!-- next -->
+        <tr>
+          <td>
+            <i>28-Nov-2008:</i>
+            <ul>
+              <li> Added link to serialised ("pickled") version of python dictionary with full result content</li>
+              <li> Bug fixes:
+                <ul>
+                  <li> Fixed mismatch in LB IOV for DQ: LB starts with 1 and not 0</li>
+                </ul>
+              </li>
+            </ul>
+          </td>
+        </tr>
+        <!-- next -->
+        <tr>
+          <td>
+            <i>26-Nov-2008:</i>
+            <ul>
+              <li> Added direct links to ELOG (run-wise search) and to DQ browser in run result table</li>
+              <li> Bug fixes:
+                <ul>
+                  <li> Fixed problem in "show dq [flag] [COOL-folder]" (thanks to Peter Cwetanski for reporting this)
+                  <li> Fixed problem in time-based query (thanks to Alexander Mann for reporting this)
+                </ul>
+            </ul>
+          </td>
+        </tr>
+        <!-- next -->
+        <tr>
+          <td>
+            <i>25-Nov-2008:</i>
+            <ul>
+              <li>First release</li>
+            </ul>
+          </td>
+        </tr>
+        <!-- end -->
+        <tr>
+          <td style="color: #555555; font-size: 60%;">
+            <hr>
+            <i>Contact and support:
+              <a href="mailto:andreas.hoecker@cern.ch"><i>Andreas Hoecker</i></a>,
+              <a href="mailto:joerg.stelzer@cern.ch"><i>Joerg Stelzer</i></a>
+          </td>
+        </tr>
+      </tbody>
+    </table>
+  </body>
+</html>
diff --git a/Database/CoolRunQuery/html/atlas-runquery-results.css b/Database/CoolRunQuery/html/atlas-runquery-results.css
new file mode 100644
index 00000000000..e851584c785
--- /dev/null
+++ b/Database/CoolRunQuery/html/atlas-runquery-results.css
@@ -0,0 +1,158 @@
+table.outer
+{ 
+  font-family: sans-serif;
+  font-size: 90%;
+  padding: 5px;
+}
+
+table.outer td
+{ 
+  text-align: left;
+}
+
+table.resulttable {
+  table-layout: auto;
+  font-family: sans-serif;
+  margin: 0em 0em 0em 0;
+  background: white;
+  border-collapse: collapse;
+  border: 2px white solid;
+  padding: 4px;
+  vertical-align: top;  
+}
+
+table.resulttable th {
+  font-size: 80%;
+  text-align: center;
+  background: #4F81BD;
+  color: white;
+  padding: 4px;
+  border: 2px white solid;
+  vertical-align: top;
+}
+
+table.resulttable th.rowsum {
+  font-size: 80%;
+  text-align: center;
+  background: gainsboro;
+  color: black;
+  padding: 4px;
+  border: 2px white solid;
+  vertical-align: top;
+}
+
+table.resulttable th.colsum {
+  font-size: 65%;
+  text-align: center;
+  background: #4F81BD;
+  color: white;
+  padding: 4px;
+  border: 2px white solid;
+  vertical-align: top;
+}
+
+table.resulttable th.colsumL {
+  font-size: 80%;
+  text-align: center;
+  background: #4F81BD;
+  color: white;
+  padding: 4px;
+  border: 2px white solid;
+  vertical-align: top;
+}
+
+table.resulttable th.emptycorner {
+  font-size: 80%;
+  text-align: left;
+  background: #f0f0f0;
+  color: #777777;
+  padding: 4px;
+  border: 2px white solid;
+  vertical-align: top;
+}
+
+table.resulttable td {
+  border: 2px white solid;
+  text-align: left;
+  padding: 4px;
+  vertical-align: top;
+}
+
+table.resulttable td.tdna     { background: #f2f2f2; color: #bbbbcc; }
+table.resulttable td.tdNA     { background: #cccccc; color: black;   }
+table.resulttable td.tdU      { background: #3090C7; color: white;   }
+table.resulttable td.tdR      { background: #E42217; color: #FFFFFF; }
+table.resulttable td.tdY      { background: #FFF380; color: black;   }
+table.resulttable td.tdG      { background: #8FFB17; color: black;   }
+table.resulttable td.tdB      { background: #444444; color: #FFFFFF; }
+table.resulttable td.td       { text-align: center; }
+table.resulttable td.tdsmallw { min-width: 45px; text-align: left; border-width: 0px; padding: 1px; }
+table.resulttable td.tdsmall  { text-align: left; border-width: 0px; padding: 1px; }
+table.resulttable .tooltip  { cursor: pointer; }
+table.resulttable td.stream   { cursor: pointer; text-decoration: underline; text-align: right; color: rgb(0, 0, 100); }
+table.resulttable td.def      { padding: 2px; height: 100%; }
+
+table.resulttable table.dqdefects  { width: 100%; border-left: medium solid #E42217; border-collapse: collapse; font-size: 80%; text-align:left; height: 100%; }
+table.resulttable table.dqdefects td { border: 0px white solid; color: #888888; padding-right: 5px; padding-left: 3px; padding-top: 0; padding-bottom: 0; font-weight: normal; }
+
+<!-- 
+table.resulttable table.dqdefects td.intolerable { font-weight: bold; color: black;}
+table.resulttable table.dqdefects td.lb { vertical-align: middle; padding: 0; border: 0px white solid; color: blue; font-size: 85%; max-width: 130px;} 
+-->
+ 
+table.resulttable td.intolerable { font-weight: bold; color: black;}
+table.resulttable td.lb { vertical-align: middle; padding: 0; border: 0px white solid; color: blue; font-size: 85%; max-width: 130px;} 
+
+
+table.triggerlinktable { font-size: 85%; border-width: 0px; border-spacing: 0px; border-collapse: collapse; }
+table.triggerlinktable th { padding: 0.2em; font-weight: bold; font-family: roman; border-width: 0px;}
+table.triggerlinktable td { padding: 0.08em; border: 0px white solid; text-align:right; border-width: 0px; font-size: 90%; }
+
+
+table.bcidtable { font-size: 85%; border-width: 0px; border-spacing: 0px; border-collapse: collapse; }
+table.bcidtable th { padding: 0.2em; font-weight: bold; font-family: roman; border-width: 0px; }
+table.bcidtable td { padding: 0.2em; border-top: 0px white solid; border-bottom: 1px #C0C0D0 solid; border-left: 0px white solid;  border-right: 0px white solid; text-align:right; }
+table.bcidtable td.td1 { padding: 0.2em; border-top: 0px #eeeeee solid; border-bottom: 1px #C0C0D0 solid; border-left: 0px white solid;  border-right: 0px white solid; text-align:right; }
+table.bcidtable td.td2 { padding: 0.2em; border-top: 0px #dddddd solid; border-bottom: 1px #C0C0D0 solid; border-left: 0px white solid;  border-right: 0px white solid; text-align:right; }
+table.bcidtable tr.tr0 {  background: #555555; color: white; height: 20px }
+table.bcidtable tr.tr1 {  background: #f3f3f3;  }
+table.bcidtable tr.tr2 {  background: #e3e3e3;  }
+
+
+table.datasettable { font-size: 85%; border-width: 0px; border-spacing: 0px; border-collapse: collapse; }
+table.datasettable th { padding: 0.2em; color: #FFFFFF; font-weight: bold; font-family: roman; background-color: #98AFC7; border-width: 0px; }
+table.datasettable td { padding: 0.2em; border: 0px white solid; text-align:left; border-width: 0px; }
+
+table.ratestable { font-size: 65%; border-width: 0px; border-spacing: 0px; border-collapse: collapse; }
+table.ratestable td { padding: 0.0em; border: 0px white solid; text-align:left; border-width: 0px; }
+
+
+table.resulttabletext 
+{ 
+  font-family: sans-serif;
+  table-layout: fixed;
+  margin: 0em 0em 0em 0;
+  background: white;
+  border-collapse: collapse;
+  border: 2px white solid;
+  padding: 4px;
+  vertical-align: top;
+  text-align: left;
+  font-size: 100%;
+}
+
+table.resulttabletext th 
+{
+  text-align: left;
+  background: white;
+  padding: 4px;
+  vertical-align: top;
+}
+
+table.resulttabletext td 
+{
+  border: 2px white solid;
+  text-align: left;
+  padding: 4px;
+  vertical-align: top;
+}
diff --git a/Database/CoolRunQuery/html/atlas-runquery-tabview.css b/Database/CoolRunQuery/html/atlas-runquery-tabview.css
new file mode 100644
index 00000000000..509769b176f
--- /dev/null
+++ b/Database/CoolRunQuery/html/atlas-runquery-tabview.css
@@ -0,0 +1,38 @@
+
+div.TabView div.Tabs {
+  height: 24px;
+}
+
+div.TabView div.Tabs a {
+  float: left;
+  border-top: #c0c0c0 1px dotted;
+  border-left: #c0c0c0 1px dotted;
+  display: block;
+  text-align: center;
+  height:      24px;
+  line-height: 28px;
+  vertical-align: middle;
+  background: #eeeeee;
+  text-decoration: none;
+  font-weight: 700;
+  font-size: 12px;
+  color: #000080;
+}
+
+div.TabView div.Tabs a:hover, div.TabView div.Tabs a.Active {
+  background: #C6DEFF;
+}
+
+div.TabView div.Pages {
+  clear: both;
+  border: 1px solid #909090;
+}
+
+div.TabView div.Pages div.Page {
+  height: 100%;
+  padding: 0px;
+}
+
+div.TabView div.Pages div.Page div.Pad {
+  padding: 10px 18px;
+}
diff --git a/Database/CoolRunQuery/html/atlas-runquery.css b/Database/CoolRunQuery/html/atlas-runquery.css
new file mode 100644
index 00000000000..d81b2ffb065
--- /dev/null
+++ b/Database/CoolRunQuery/html/atlas-runquery.css
@@ -0,0 +1,411 @@
+body { margin:0 0 0; padding:0; background-color: #ffffff;}
+
+table.bodytable 
+{ 
+  height:100%; 
+  vertical-align:top; 
+  padding: 0px; 
+  margin-left: 7px; 
+  margin-right: 0px;
+  padding-top: 0px;
+  padding-bottom: 0px;
+  width:100% 
+}
+
+td { vertical-align: middle; text-align: left; font-family: sans-serif; font-size: 90%; }
+th { vertical-align: bottom; text-align: center; font-family: sans-serif; font-weight: bold; font-size: 90%; }
+
+td.option { width: 160px; }
+td.array  { width:  50px; }
+td.val    { width: 120px; }
+td.predef { width: 150px; }
+td.info   { width: 320px; }
+
+p.pgm { font-family: sans-serif }
+td.pgm { font-family: sans-serif; color: #222222; vertical-align: top; font-size: 87%; width: 50%; background: white; cursor: pointer }
+td.pgm:hover { text-decoration:underline; }
+td.cmt { font-family: sans-serif; color: #444444; font-size: 80%; vertical-align: top; background: white; }
+td.space { background: white; height: 10px; }
+
+th.alltitle { color: white; background-color: #2B3856; padding: 0 }
+th.alldescr { font-weight: normal; color: #222222; background-color: white; font-size: 80%; }
+th.coltitle { color: black; background-color: #98AFC7; }
+td.helptd { font-weight: normal; color: #000000; background-color: white; font-size: 130%; }
+
+table.toptable
+{
+  position: relative;
+  width: 100%;
+  top: 0;
+  bottom: auto;
+  left: 0;
+  right: auto;
+  margin: 0 0 0 0;
+  padding-top: 0px;
+  color: #ffffff;
+  background-repeat: no-repeat;
+  background-color: #5D6B7D;
+}
+
+table.bottomtable
+{
+  position: relative;
+  width: 100%;
+  top: auto;
+  bottom: 0;
+  left: 0;
+  right: auto;
+  margin: 0 0 0 0;
+  padding-top: 0px;
+  color: #ffffff;
+  background-repeat: no-repeat;
+  background-color: #5D6B7D;
+  font-size: 85%;
+}
+
+#footer {
+  position:absolute;
+  background-color: #eee;
+  color: #000;
+  margin: 0em 0 0 0;
+  padding: .7em;
+  border-top: 1px solid #ddd;
+  border-bottom: 1px solid #ddd;
+  font-size: 80%;
+  height:100%;
+  clear: both;
+}
+
+table.bottomtable td
+{ 
+  padding-left: 12px;
+  padding-right: 15px;
+}
+
+table.bottomtable a 
+{ 
+  color:white;
+  font-style: italic;
+}
+
+table.toptable a 
+{ 
+  color:white;
+  font-size: 75%; 
+}
+
+table.toptable td
+{ 
+  text-align: left;
+  padding-left: 10px;
+}
+
+table.toptableLinks
+{
+  margin-left: auto; 
+  margin-right: 10px;
+  padding-top: 0px;
+  padding-bottom: 0px;
+  padding-left: 0px;
+  padding-right: 0px;
+  color: #ffffff;
+  background-repeat: no-repeat;
+}
+
+table.toptableLinks td 
+{ 
+  text-align: right;
+  border: 0px white solid;
+  padding: 0.4em;
+}
+
+hr.horiline 
+{ 
+  width: auto; 
+  color:red; 
+  background-color: #6D7B8D; 
+  height:1px; 
+  margin-left: 0px;   
+  margin-right: 0px;   
+  border:0;
+}
+
+table.relnotetable {
+  table-layout: fixed;
+  margin: 0em 0em 0em 0;
+  background: white;
+  border-collapse: collapse;
+}
+table.relnotetable td { font-size: 80%; }
+
+table.mytable {  
+  table-layout: fixed;
+  margin: 0em 0em 0em 0;
+  margin-left: 4px;
+  margin-top: 0px;
+  border: 0px white solid;
+  padding: 0px; 
+  background: white;
+  border-collapse: collapse;
+}
+table.mytable th.coltitle, table.mytable th.alltitle, table.mytable th.alldescr, table.mytable td {
+  border: 2px white solid;
+  padding: 0.2em;
+}
+table.mytable th {
+  text-align: left;
+  font-size: 100%;
+}
+table.mytable caption {
+  margin-left: inherit;
+  margin-right: inherit;
+}
+
+
+table.exampletable {
+  width: 100%;
+  table-layout: fixed;
+  margin: 0em 0em 0em 0;
+  background: white;
+  padding: 0px;
+  border-width: 0px;
+  border-color: white;
+  border-style: solid;
+  border-collapse: collapse;
+  font-size: 110%;
+}
+
+table.exampletable a {text-decoration:none; color: #222222}
+table.exampletable a:hover { text-decoration: underline; font-style: normal; color: #222222 }
+
+td.t1 {
+  background: #B0FA91;
+}
+td.t2 {
+  background: #D9FAC9;
+}
+
+tr.outtitlerun {
+  background: gainsboro;
+  font-size: 80%;
+  width: 80px;
+}
+tr.outtitleother {
+  background: lavender;
+  font-size: 80%;
+}
+tr.sum {
+  background: #FFFaa0;
+  font-size: 90%;
+  color: #000000;
+  text-align: right;
+}
+tr.space {
+  background: #ffffff;
+  font-size: 90%;
+}
+
+tr.out2 {  background: #E9EDF4;  font-size: 90%; }
+tr.out1 {  background: #D0D8E8;   font-size: 90%; }
+
+tr.outRed1 {  background: #FFDFDF;  font-size: 90%; }
+tr.outRed2 {  background: #F1C8CE;   font-size: 90%; }
+
+tr.out1LBR {  background: #F0F0F0; font-size: 70%; visibility: collapse; }
+tr.out2LBR {  background: #F5F5F5;  font-size: 70%; visibility: collapse; }
+
+
+tr.showmiss1, td.showmiss1 {
+  background: #E9EDF4;
+  font-size: 90%;
+}
+tr.showmiss2, td.showmiss2 {
+  background: #D0D8E8;
+  font-size: 90%;
+}
+tr.selmiss1, td.selmiss1 {
+  background: lavender;
+  color: red;
+  font-size: 90%;
+}
+tr.selmiss2, td.selmiss2 {
+  background: #B0C4DE;
+  color: red;
+  font-size: 90%;
+}
+
+table.othertable {
+  table-layout: auto;
+  font-family: sans-serif;
+  margin: 0em 0em 0em 0;
+  background: white;
+  border-collapse: collapse;
+  border: 2px white solid;
+  padding: 5px;
+  vertical-align: top;  
+  margin-left: 13px;
+}
+
+table.othertable th {
+  font-size: 80%;
+  text-align: center;
+  background: #4F81BD;
+  color: white;
+  padding: 4px;
+  border: 2px white solid;
+  vertical-align: top;
+}
+
+table.othertable td {
+  border: 2px white solid;
+  text-align: left;
+  padding: 4px;
+  vertical-align: top;
+  background: #E9EDF4;
+  font-size: 80%;
+}
+
+
+a {text-decoration:none}
+:link    { color: rgb(0, 0, 100) }  /* for unvisited links */
+:visited { color: rgb(0, 0, 100) } /* for visited links */
+a:active { color: rgb(0, 0, 100) } /* when link is clicked */
+a:hover { text-decoration: underline; font-style: normal; color: rgb(0, 0, 150) }
+
+a.info{
+  position:relative; /*this is the key*/
+  font-size: 11px;
+  background-color:#ffffff;
+  color:#777777;
+  text-decoration:none;
+  font-weight: lighter
+}
+
+a.info:hover{
+  background-color:#ffffff;
+  color:#aaaaaa;
+  font-weight: lighter
+}
+
+a.info span{
+  display: none
+}
+
+a.info:hover span{ /*the span will display just on :hover state*/
+  display:block;
+  font-size: 12px;
+  position:absolute;
+  top:-5em; left:0em; width:37em;
+  border:1px solid #667295;
+  background-color:#E5E9F5; 
+  color:#000000;
+  text-align: left;
+  font-weight: lighter;
+  padding: 5px
+}
+
+div#tipDiv 
+{
+  color:#000; 
+  font-family: sans-serif; 
+  line-height:1.2;
+  font-size:11px; 
+  background-color:#E1E5F1; 
+  border:1px solid #667295; 
+  padding:5px;
+  text-align: left;
+  font-weight: lighter
+}
+
+div.tooltip 
+{ 
+  font-size:11px; 
+  width:23em;
+}
+
+div.tip2 
+{
+  width:37em; 
+}
+
+table.defaulttable 
+{ 
+  padding: 0;
+  font-size: 120%; 
+  table-layout: fixed;
+}
+
+table.streamtiptable
+{ 
+  height:100%; 
+  vertical-align:top; 
+  padding: 0px; 
+  margin-left: 0px; 
+  margin-right: 0px;
+  padding-top: 0px;
+  padding-bottom: 0px;
+  table-layout: auto;
+}
+
+table.streamtiptable td { vertical-align: middle; text-align: left; font-family: sans-serif; font-size: 100%; }
+table.streamtiptable th { vertical-align: bottom; text-align: center; font-family: sans-serif; font-weight: bold; font-size: 100%; }
+
+table.pileuptable { 
+  width: auto; 
+  border: 0; 
+  border-width: 0px; 
+  margin: 0 0 0 0; 
+  border-spacing: 0px; 
+  border-collapse: separate; 
+  padding: 0px; 
+  font-size: 100% 
+}
+
+table.pileuptable th {  
+  border-width: 0.1em; background: #d9dDe4;; color:#000000; 
+  vertical-align: middle; text-align: center; font-family: sans-serif; font-size: 100%; 
+}
+table.pileuptable td {  
+  border-width: 0.1em; 
+  vertical-align: middle; text-align: center; font-family: sans-serif; font-size: 100%; 
+}
+
+table.eventsperlbstreamtable
+{ 
+  padding: 0;
+  font-size: 120%; 
+  table-layout: auto;
+}
+
+
+table.overlaptable 
+{ 
+  color: #222222; 
+  border-width: 0; 
+  border-spacing: 0; 
+  border-color: #E1E5F1; 
+  background-color: #E1E5F1; 
+  padding: 0; 
+  table-layout: auto;
+  margin: 0em 0em 0em 0;
+  border-collapse: collapse;
+}
+
+table.overlaptable td.tdov1 
+{ 
+  border-width: 0; 
+  padding: 2px; 
+  border-color: #E1E5F1; 
+  background-color:#E1E5F1;
+}
+
+table.overlaptable td.tdov2 
+{ 
+  border-width: 0; 
+  padding: 2px; 
+  border-color: #C1C5E1; 
+  background-color:#C1C5E1;
+}
+
+
+
diff --git a/Database/CoolRunQuery/html/atlas-runquery.html b/Database/CoolRunQuery/html/atlas-runquery.html
new file mode 100644
index 00000000000..1485e4fcc12
--- /dev/null
+++ b/Database/CoolRunQuery/html/atlas-runquery.html
@@ -0,0 +1,252 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+  <head>
+    <title>ATLAS Run Query</title>
+
+    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"></meta>
+    <meta name="ATLAS_Run_Query" content="ATLAS Run Query"></meta>
+    
+    <link rel="stylesheet" type="text/css" href="html/atlas-runquery.css" media="screen"></link>
+    <link rel="stylesheet" type="text/css" href="html/atlas-runquery-results.css" media="screen"></link>
+    <link rel="stylesheet" type="text/css" href="html/atlas-runquery-tabview.css" media="screen"></link>
+    <!--link rel="stylesheet" type="text/css" href="atlas-runquery-print.css" media="print"-->
+    <link rel="shortcut icon" href="html/atlas1.ico"></link>
+
+    <script type="text/javascript" src="js/switcher.js"></script>
+    <script type="text/javascript" src="js/tabView.js"></script>
+
+    <script type="text/javascript" src="js/dw_event.js"></script>
+    <script type="text/javascript" src="js/dw_viewport.js"></script>
+    <script type="text/javascript" src="js/dw_tooltip.js"></script>
+    <script type="text/javascript" src="js/dw_tooltip_aux.js"></script>
+
+    <script type="text/javascript" src="js/rq.js"></script>
+    <script type="text/javascript" src="js/rq_examples.js"></script>
+    <script type="text/javascript" src="js/rq_simplepopups.js"></script>
+
+    <script type="text/javascript" src="js/jquery.min.js"></script>
+    <script type="text/javascript" src="js/jquery.popupWindow.js"></script>
+    <script type="text/javascript">
+      jQuery.fn.ratespopup = function() {
+      window.open(this[0].id,''+this[0].id,
+      'height=800,width=1000,scrollbars=1,menubar=1').focus();
+      }
+
+      $(document).ready(function(){
+      $(".ratespopup").click(function(){$(this).ratespopup();});
+      });
+    </script>
+
+    <script type="text/javascript" src="js/animatedcollapse.js"></script>
+    <script type="text/javascript">
+        animatedcollapse.addDiv('AtlRunQueryCmd', 'fade=1,speed=400')
+        animatedcollapse.ontoggle = function($, divobj, state){ //fires each time a DIV is expanded/contracted
+    }
+    animatedcollapse.init()
+    </script>
+
+  </head>
+
+  <body onload='i=document.getElementById("queryinput");i.focus();i.select();insertExamples()'>
+
+    <table class="toptable">
+      <tr style="height:45px; vertical-align:top;">
+        <td><font size="+1"><b>ATLAS Run Queries</b></font> </td>
+        <td style="padding-right: 0px;">
+          <table style="border-spacing:6px; margin-left:auto; margin-right:12px">
+            <tr>
+              <td class="dontPrint" style="border: 1px white solid; padding: 0.3em; width: 56px; text-align:center; font-size: 100%; vertical-align: middle;">
+                <a href="mailto:andreas.hoecker@cern.ch,joerg.stelzer@cern.ch" title="Contact and support">
+                  Contact
+                </a>
+              </td>
+              <td class="dontPrint" style="border: 1px white solid; padding: 0.3em; width: 35px; text-align:center; font-size: 100%">
+                <a href="javascript:helppopup()" title="Help on Run Query Formatting">
+                  Help
+                </a>
+              </td>
+            </tr>
+          </table>
+        </td>
+      </tr>
+      <tr style="height:20px">
+        <td colspan="2">
+          <table class="toptableLinks">
+            <tr>
+              <td><a href="http://pcatdwww.cern.ch/atlas-point1/wmi/current/Run%20Status_wmi/index.html">Current run</a></td>
+              <td><a href="https://atlas.web.cern.ch/Atlas/GROUPS/DATAPREPARATION/DataSummary/">Data Summary</a></td>
+              <td><a href="http://atlas-trigconf.cern.ch/">Trigger Configuration Query</a></td>
+              <td><a href="http://ami.in2p3.fr:8080/AMI/servlet/net.hep.atlas.Database.Bookkeeping.AMI.Servlet.Command?linkId=512">AMI Data Search</a></td>
+              <td><a href="http://dashb-atlas-data.cern.ch/dashboard/request.py/site">DDM Dashboard</a></td>
+              <td><a href="http://atlas.web.cern.ch/Atlas/tzero/prod1/monitoring/">Tier-0 Monitoring</a></td>
+              <td><a href="http://atlasdqm.web.cern.ch/atlasdqm/">DQ Monitoring</a></td>
+              <td><a href="https://twiki.cern.ch/twiki/bin/view/Atlas/DataPreparation">Data Preparation</a></td>
+              <td><a href="http://pcatdwww.cern.ch/atlas-point1/operation.php">Operations</a></td>
+            </tr>
+          </table>
+        </td>
+      </tr>
+    </table>
+    
+    <table class="mytable" width="95%">
+      <tr>
+        <td style="width:100%;">
+          <table class="mytable" width="100%">
+            <tr>
+              <th height="40" valign="bottom" style="font-size: 14px;width:100%">
+                Run Search &minus;  Insert Your Query:
+                <font style="font-size:12px;font-weight:100">
+                  <!--INSERTLINKCACHE-->
+                </font>
+              </th>
+            </tr>
+            <tr>
+              <td style="background-color:white">
+                <form id="RunQueryInput" action="query.py" method="get" style="margin-bottom:0px">
+                  <input id="queryinput" name="q" size="105%" value="find run last 10 and ready / show all"/>&nbsp;&nbsp;&nbsp;
+                    <input type="submit" value="Show Runs"/>
+                </form>
+              </td>
+            </tr>
+            <tr class="dontPrint">
+              <td colspan="2" style="font-size: 11px; text-align: left;"><div class="showTip LX1" style="display:inline;cursor:pointer">&nbsp;[ <i style="color:rgb(0, 0, 100)">Default query condition</i> ]</div>&nbsp;&nbsp;[ <font color="#666666"><i>Type 'f ... / show <b>all</b>' to see full info (except for DQ and trigger)</i></font> ]</td>
+            </tr>
+          </table>
+          
+        </td>
+      </tr>
+      <tr>
+        <td style="font-size:50%">&nbsp;
+        </td>
+      </tr>
+      <!--START_EXAMPLES-->
+      <tr>
+        <td>
+          <table class="mytable dontPrint" width="100%">
+            <tbody>
+              <tr>
+                <td height="20" valign="top">
+                  <font color="#111133"><i><font size="-1">Examples <font size="-2">(query format inspired by <a href="http://www.slac.stanford.edu/spires/hep/"><font color="#111133">SPIRES</font></a>)</font>:</font></i></font><br/>
+                </td>
+              </tr>
+              <tr>
+                <td>
+                  <div class="TabView" id="TabView">
+                    <!-- *** Tabs ************************************************************** -->
+                    <div class="Tabs">
+                      <a>&nbsp; Run / events &nbsp;&nbsp;</a>
+                      <a>&nbsp; Time &nbsp;&nbsp;</a>
+                      <a>&nbsp; Detectors &nbsp;&nbsp;</a>
+                      <a>&nbsp; Streams &nbsp;&nbsp;</a>
+                      <a>&nbsp; Magnets  &nbsp;&nbsp;</a>
+                      <a>&nbsp; Data quality &nbsp;&nbsp;</a>
+                      <a>&nbsp; Trigger &nbsp;&nbsp;</a>
+                      <a>&nbsp; DAQ &nbsp;</a>
+                      <a>&nbsp; Datasets &nbsp;</a>
+                      <a>&nbsp; Beamspot &nbsp;</a>
+                      <a>&nbsp; LAr &nbsp;</a>
+                      <a>&nbsp; Lumi &nbsp;</a>
+                      <a>&nbsp; LHC &nbsp;</a>
+                      <a style="border-right: #c0c0c0 1px dotted;">&nbsp;&nbsp;<font color="#FF0000">Xtras</font>&nbsp;&nbsp;</a>
+                    </div>
+                    <!-- *** Pages ************************************************************* -->
+                    <div class="Pages" style="width: 855px; height: 220px; text-align: left;">
+                      <div class="Page" id="exampleRunEvt"></div>
+                      <div class="Page" id="exampleTime"></div>
+                      <div class="Page" id="exampleDetectors"></div>
+                      <div class="Page" id="exampleStreams"></div>
+                      <div class="Page" id="exampleMagnets"></div>
+                      <div class="Page" id="exampleDQ"></div>
+                      <div class="Page" id="exampleTrigger"></div>
+                      <div class="Page" id="examplePartition"></div>
+                      <div class="Page" id="exampleDatasets"></div>
+                      <div class="Page" id="exampleBeamSpot"></div>
+                      <div class="Page" id="exampleLAr"></div>
+                      <div class="Page" id="exampleLumi"></div>
+                      <div class="Page" id="exampleLHC"></div>
+                      <div class="Page" id="exampleOther"></div>
+                    </div>
+                    <!-- *** End of Examples ************************************************** -->
+                  </div>
+                </td>
+              </tr>
+              <tr>
+                <td>
+                  <i><font size="-1"><a href="javascript:helppopup()" title="Help on Run Query Formatting">(More formatting help)</a></font></i>
+                </td>
+              </tr>
+            </tbody>
+          </table>
+          <p></p>
+        </td>
+      </tr>
+      <!--END_EXAMPLES-->
+    </table>
+    <p></p>
+
+    <!--INSERTQUERYRESULT-->
+
+    <script language='javascript'>
+      function readAndEcho(pat)
+      {
+      fh = fopen(pat, 0);		// Open the file for reading
+      if(fh!=-1)						// If the file has been successfully opened
+      {
+      length = flength(fh);      // Get the length of the file
+      str = fread(fh, length);   // Read in the entire file
+      fclose(fh);                // Close the file
+
+      // Return the contents of the file
+      return str;
+      }
+      }
+    </script>
+    <table class="bottomtable">
+      <tr style="height:45px; vertical-align: top;">
+        <td>
+          <i>Contact and support:
+            <!--CONTACT_START-->
+            <a href="http://consult.cern.ch/xwho/people/400557">Andreas Hoecker</a>,
+            <a href="http://consult.cern.ch/xwho/people/652897">J&ouml;rg Stelzer</a>
+            <!--CONTACT_END-->
+          </i>
+          </td>
+        <td><i>CoolRunQuery-00-04-50</i></td>
+          <td style="text-align:right"><i>
+            <script language="JavaScript" type="text/javascript">
+              var date  = document.lastModified.toString();
+              if (date == "") {   // unknown date (or January 1, 1970 GMT)
+              document.writeln("Last Modified: Unknown")
+              } else {
+              document.writeln ("Last modified: " + date); }
+            </script>
+          </i></font>
+        </td>
+      </tr>
+    </table>
+
+
+    <script type="text/javascript"> 
+      $('.externalWindow').popupWindow({ 
+      scrollbars:1,
+      width:750 
+      }); 
+    </script>
+
+
+    <script type="text/javascript">
+      if(dw_Tooltip.content_vars==undefined) {
+      dw_Tooltip.content_vars = {};
+      };
+      dw_Tooltip.content_vars["LX1"] = {
+      content: '<table class="defaulttable"><tr><td>By default is added to your query: <font color="red">ptag data09*,data10*,data11*,data12* and part ATLAS</font>.</td></tr><tr><td>To switch this off append <font color="red">/ nodef</font> to query.</td></tr><tr><td> For example: <font color="red">f r 114000-114300 / sh ptag / nodef</font>.</td></tr></table>', klass: 'tip2'
+      };
+    </script>
+
+      <!-- StatCounter has been removed -->
+
+    <script type="text/javascript">
+      tabview_initialize('TabView');
+    </script>
+  </body>
+</html>
diff --git a/Database/CoolRunQuery/html/atlas1.ico b/Database/CoolRunQuery/html/atlas1.ico
new file mode 100644
index 0000000000000000000000000000000000000000..57fa129e4be36c0e6d8022af160d87075aabbabe
GIT binary patch
literal 894
zcmb7DZAep57{1Zph*{AG{V9L+4N(w6DcPT>Fw!7UNDNH;A`Ay=$|Pw&hHZ1EwKZ@$
zGtw>0>1-|C(wfd~?(Wm+bZ$1MXwGfAd3Abs?45#`;*XxoIXve%&->haJ}!psgNH)F
zpg)e~?8mU97>1pL1`>7(T2$Wv%<aVbKS1uOIgapWDO;LX#?2~z_q2qcUEWOP=xDWS
zZj0LMTi9+#2>AlR&z<Tr=BJqR>5p<>RoAr@(HqVt<nTUrOO-f5tZesha<q;j2qoum
zZzdJ2uC0kB0|#R>REA+l+ii|2P=HW;3WIVY@nK%|lS09<xC$muyr+L7KPi`WBsS&r
zrL?QJi|*xD*<Dk6`5~T+piG+Zz~So`ucg*DNXCA9z`XlwK%4dYRa$F)$@@cR(qc~D
zxp3ogAw$4zYIjf1Y_9-5Hy@~cD@n~_+)B#69QUA@UUMZeqqgx&b`dM{`OEmbX-10;
zZ19>uFr@4=Cft8UEoZgMdtT7FwozwzjTCqE`WAu~$AktSPEM!((ip%ETURL%XXKXR
zW}D9Dpm9EE_2x-WbaepxxXbJJ195w1Dqiz|5G&#0%BEIn*PziRR%nRjWe|g*CCku=
z7Pqu@cEJ!<3LS&ZTM36DzouU57<b9~j4F*$H)tV<XvsoodBE)O`TZKL-eehyL?Wy=
z0ysXHVhO&AIu+yY=%$fm#AF`r?oqc$<ddFhuz|Ql5Hh)vU)KyA;F|KXg(9uqK$0XR
z*q!cKuMhN@KVFk<1UH(#|4{MkMNZcQh|%*$NIx`6t7@ull*)S5p(O$oKsdZ=Fpsr%
tDEo0MM8Q4T!lq%~zo_iDGWl&nQMdG4pIo8E&Gx`zaLWc{=l}4(<G<0{XF&h}

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/1332500.thm.gif b/Database/CoolRunQuery/html/images/1332500.thm.gif
new file mode 100644
index 0000000000000000000000000000000000000000..1ff7b67ad492abbfd299f05e7aa4d8c3514e0730
GIT binary patch
literal 398
zcmV;90df9ENk%w1VTS;R0P+9;00000goK2I0RR60goK2~#>W5u{{R30A^8LZ0RaC1
zEC2ui0EYmF000C3Xu90~Fv>}*y*TU5yZ>M)j$~<`XsWJk>%MR-&vb3yc&_h!@BhG{
za7Zi~kI1BQ$!t2G(5Q4uty-_xtai)odcWYXcuX#v&*-#z&2GEj@VI<VuiNkVynfH`
z`~Ow|f`fyA4gd-TiUkCSeuR*TjF5$Q00Wqr1CEOXjhdK_b(fx{oQsT&rkj=n1PTEL
zl#m4q00N?Pq_C2xzP7lnuLiLex4Cn>#23fH0ngCU($LLz%EcAcqprNh!Pc(R;?ml>
z+{@m`a@Wk?+XUnB0p-c(*c9~Z_U-C%r1InP`P-LHShsBM%)tXVO&}b01;GuwH^JeX
ze+<bbtT&NUpFwm8`#sz=t0bX~`UVJC$+D$Omm(jUoGHkV&6_xL>fFh*r_Y~2g9;r=
sw5ZXeNRujE%CxD|r%<Cxol3Q;)vH*uYTe4UtJkk!!-^eCHfaI?JA5Y3LI3~&

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/arrow-down.gif b/Database/CoolRunQuery/html/images/arrow-down.gif
new file mode 100644
index 0000000000000000000000000000000000000000..83e836fc4c70966b7e79ae78d46d77e4acddce93
GIT binary patch
literal 852
zcmZ?wbhEHb6ky<CXlDR{N(P3jk_w+vmB74FVl)IsPzWggWMO7tU}4Y!`5BZa7&r_W
zI5}iIHY_;U%pokqb6~?l=VnG0k2xBJ2M%_KutvCaY+U5TBw=31qws0*$;ld=Y%C1c
E0D#~Z$^ZZW

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/arrow-up.gif b/Database/CoolRunQuery/html/images/arrow-up.gif
new file mode 100644
index 0000000000000000000000000000000000000000..a92773a116e556876408ffd1c942ef1265d37cd4
GIT binary patch
literal 851
zcmZ?wbhEHb6ky<CXlDR{N(P3jk_w+vmB74FVl)IsPzWggWMO7tU}4Y!`5BZa7&r_V
zI5}iIHY_;U%pt7AW8m=c00R??NeGAGq9ZM$x^X5m0w23IF*<e0yxg$l<YZ=MCI)K&
DMlu&N

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/atlas1.ico b/Database/CoolRunQuery/html/images/atlas1.ico
new file mode 100644
index 0000000000000000000000000000000000000000..57fa129e4be36c0e6d8022af160d87075aabbabe
GIT binary patch
literal 894
zcmb7DZAep57{1Zph*{AG{V9L+4N(w6DcPT>Fw!7UNDNH;A`Ay=$|Pw&hHZ1EwKZ@$
zGtw>0>1-|C(wfd~?(Wm+bZ$1MXwGfAd3Abs?45#`;*XxoIXve%&->haJ}!psgNH)F
zpg)e~?8mU97>1pL1`>7(T2$Wv%<aVbKS1uOIgapWDO;LX#?2~z_q2qcUEWOP=xDWS
zZj0LMTi9+#2>AlR&z<Tr=BJqR>5p<>RoAr@(HqVt<nTUrOO-f5tZesha<q;j2qoum
zZzdJ2uC0kB0|#R>REA+l+ii|2P=HW;3WIVY@nK%|lS09<xC$muyr+L7KPi`WBsS&r
zrL?QJi|*xD*<Dk6`5~T+piG+Zz~So`ucg*DNXCA9z`XlwK%4dYRa$F)$@@cR(qc~D
zxp3ogAw$4zYIjf1Y_9-5Hy@~cD@n~_+)B#69QUA@UUMZeqqgx&b`dM{`OEmbX-10;
zZ19>uFr@4=Cft8UEoZgMdtT7FwozwzjTCqE`WAu~$AktSPEM!((ip%ETURL%XXKXR
zW}D9Dpm9EE_2x-WbaepxxXbJJ195w1Dqiz|5G&#0%BEIn*PziRR%nRjWe|g*CCku=
z7Pqu@cEJ!<3LS&ZTM36DzouU57<b9~j4F*$H)tV<XvsoodBE)O`TZKL-eehyL?Wy=
z0ysXHVhO&AIu+yY=%$fm#AF`r?oqc$<ddFhuz|Ql5Hh)vU)KyA;F|KXg(9uqK$0XR
z*q!cKuMhN@KVFk<1UH(#|4{MkMNZcQh|%*$NIx`6t7@ull*)S5p(O$oKsdZ=Fpsr%
tDEo0MM8Q4T!lq%~zo_iDGWl&nQMdG4pIo8E&Gx`zaLWc{=l}4(<G<0{XF&h}

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/book.gif b/Database/CoolRunQuery/html/images/book.gif
new file mode 100644
index 0000000000000000000000000000000000000000..5b88ec6ca2bcd2a4f12c678e3cc0eba9a37d92ba
GIT binary patch
literal 361
zcmZ?wbhEHb6krfwxXQrr|NsBHckgbp-*j*7z55&P|N8Xn-kN(Gtv7D8+4%D0%T0Eh
zHdt*~W3XnO>AKGkK5w+$cz@mfbtdc9o3H<P_v2=V&96?qdUg8MTEn&L&DQS;-*b2M
z-J^L&j~5+3kaXZg*@@p@e*gLYXHUeQ54S%2|M&k;+M(x%p0Cng_3QJm!x@L)UVeMB
z{N%C1V|Q2GeR<;L)#+FN{rR`vV*T!r-LKERet+ZrYQ5DjkH1`_zve{giKTK&Ki&Uy
zefD(*RG|2i1uUQgB0+v)U~4<jP~f4%#du;#P-Tph)8tfR&j1rW$-p8m1s5^?mKMR;
zjLTY1J1Pp;B$!;aY-pKrO{9zAV#L#D3_2F^{J9(wvV39<8e(!hLfq`UDtw|W4MrZE
z=4L!H(*)!jnAtczOr?c2nbkdf_1UbJGpI7NMwfUhGwbQH?bzwfpdfYd(BYGAr(GNw
FtO1!ys_Os%

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/cclose.jpg b/Database/CoolRunQuery/html/images/cclose.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..18bd1764ea28d23794357f5cf74e25802052a0b0
GIT binary patch
literal 741
zcmex=<NpH&0WUXCHwH#VMut#^Fb0PIw;7xnIM~?O*;qN)+1WWcIk<R4czL+Fc_f8|
z`9)-<<mF_gWMmXn^wbrUbd+UeG|V-13=B<7Oyt!qZ7qy!^o&i6K!z}Ka&q!;^GNXW
zN*F21C>oIr{vTiv<X{kB;Adu3Vqg+vWEN!ne}qAvfq{_~=vt72p@5NznT3^&or9B$
z8>nEb00R>vGcywlGb<|#3s7|}P@aKBkX1<0(2-3zFp*uUP{gQl;zAB(r;P_igD!qh
zF-|IK;^Yz&myncFRa4i{)G{$OGq<p`a&~cbbNBG{3JwVk3y+A5N=`{lOV7y6DlRE4
zE3c@mYHn$5YwzgnnlyRJ)M?Xa%$&7o@sg#>maka3YSZQ|TeofBv2)j<!$*!DJAUHi
zsY{oyT)lSv#?4y~A3c8Z^x5+lFJFE9^!dxzZ{L6X`~~tCBLg$UTX3JD`AZP!FD4ci
zW)^mkzZjXyftXp4g;mjzO~^5jJ+V+&$*7S-#A)KfjR!fEje|ajCKX-e5>qjGsQMA)
zHL%Z!^H>vEK7)G<;jdc^Jj{&1$YT~{uxI%4pFuDyyvn}2##YP6xAjYZs*TFWJ-sIm
z-+!w7ae0M!(4OnMTWzDBC0#gQt5UYHf45BF+-A8aZR)Q*AL*JskNlY5{z$<5MvhAL
y&1JUcjax;kKOO%d@}4>KdX$RPvdM*cCwas#d1k9;DouDV^Q$RBe!&9%|2F|FHUygh

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/close.gif b/Database/CoolRunQuery/html/images/close.gif
new file mode 100644
index 0000000000000000000000000000000000000000..791cf8bc366b14e0806e5c41d7c5de50cab66528
GIT binary patch
literal 381
zcmZ?wbhEHblw*)%SZd7x1S~8pY;0^?TwFXnJbZk70s;a;LPBC<Vv>@Q^78Vks;X*g
zYC1YP1_lP^=H?a_7Ot+Y9v&Xv-roNH{^8-_v9YlQ1qFqLg~i3iB_$;d4GqoB&F$^&
zU0q#0Jv|d9Oqe!p+MGFa=FOY8Xwjm@ix)3nzI^@q^&2;C+_GiMjvYI8?%a9!@Zlpz
zjvPC7?8J!^Cr_R{bLPysbLTExxNzyxrK?x3-n@D9*|TRaUcC7J`O*I$cmAUS#h)yU
zTnzRMIv}5b{KUXE%VBPThmKVLi6uoRbFAiH&=6LeES7)t)G@1&xm~PW;TabM;u%=3
z?PBui5N1#~D$1a>^PxlC#y%-drcf)xA_l%N$u@Z>u{IWyK*qKtr?NH`f3r3&7ydTE
z0GT327sWP(K=vYCXT2h3<3RHwS(h?_Fr_>fZid=09!?iICY@vk3ujZ#$`}n*7l~vi
UHJ9cqH*ej(bNAl;AV&sk0N3%GO#lD@

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/copen.jpg b/Database/CoolRunQuery/html/images/copen.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..5d255c9e27675922f149169c1464c8aeb05759c1
GIT binary patch
literal 749
zcmex=<NpH&0WUXCHwH#VMut#^Fb0PIw;7xnIM~?O*;qN)+1WWcIk<R4czL+Fc_f8|
z`9)-<<mF_gWMmXn^wbrUbd+UeG|V-13=B<7Oyt!qZ7qy!^o&i6K!z}Ka&q!;^GNXW
zN*F21C>oIr{vTiv<Y3@q5MX9hVqg+vWEN!ne}qAvfq{_~=vt72p@5NznT3^&or9B$
z8>nEb00R>vGcywlGb<|#3s7|}P@aKBkX1<0(2-3zFp*uUP{gQl;zAB(r;P_igD!qh
zF-|IK;^Yz&myncFRa4i{)G{$OGq<p`a&~cbbNBG{3JwVk3y+A5N=`{lOV7y6DlRE4
zE3c@mYHn$5YwzgnnlyRJ)M?Xa%$&7o@sg#>maka3YSZQ|TeofBv2)j<!$*!DJAUHi
zsY{oyT)lSv#?4y~A3c8Z^x5+lFJFE9^!dxzZ{L6X`~~tCBLg$UTX3JD`AZP!FD4ci
zW)^mkzZjXyftXp4g;mjzO~^5jJ+V+&$*7S-#A)KfjR!fEje|ajCKX-e5>qjGsQMA)
zHL%Z!^H>vEK7)G<;jdc^Jj{&1$YT~{uxEI)g;&bHW5U_>*`NJQdp27|zI>^y5_oJ$
z?-|CQGam2vip}=$Z_mwM^CI}H*sMI|w$J{R+{XfM=zU>-w?W<1JM8MZe}X^XO*~$^
z;Le##N7+72j@~R3>3EQ}sGh5?cV+CKh-ufJMLgPgAvZ1Z)(y+bJXyaG!vl<t&zUV3
I@c+LF0PjHx@Bjb+

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/days.gif b/Database/CoolRunQuery/html/images/days.gif
new file mode 100644
index 0000000000000000000000000000000000000000..eed854ffa69c719b6ea6aaf7d6cb563466b5f3e9
GIT binary patch
literal 161
zcmV;S0ABw`Nk%w1VGsZi0J8u9|NsBp-QAg)nbE?s?z^hYGXULpRnI{Y)?72wP9pWz
z%=qNp;Du(|X+-?-?f?J)A^8LV00000EC2ui01yBW000C|Fvv-(1UPGb1@Pb}0-a!<
z=s*VJh6!rtX7KtsN5NnT@x?3;rT{=3d^MS((7+gwz!pLQc>ZjHMK0llVrQ=?YHW&P
P2I#cf2HsfSln4MjonA%k

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/download.gif b/Database/CoolRunQuery/html/images/download.gif
new file mode 100644
index 0000000000000000000000000000000000000000..73d8ff28e15a00d49364d8ec463630049e3c7eba
GIT binary patch
literal 120
zcmZ?wbhEHb6krfwSj52a|NsBHckinCW?a7gpsauX|1^f*i_$mmJE8cKg#iR~Km<rF
z1GBBft~*=?UO$&<3WrpF?z{WNQBkzOb=ItDTJzSH%emy<Zz>aVe*b?byT5~u5c|Qq
V`JGo7IgV*uoVn6!T@MR`H2_AxFbV(w

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/i_icon.png b/Database/CoolRunQuery/html/images/i_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..8f830865c8a9f0d9535c9f175167b7a77f4a4144
GIT binary patch
literal 4029
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

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/info.gif b/Database/CoolRunQuery/html/images/info.gif
new file mode 100644
index 0000000000000000000000000000000000000000..023f08f2cbbb671600123010365c384526effc31
GIT binary patch
literal 212
zcmZ?wbhEHb6krfwIKseSJd@%7|NnRI-i=&i(09D3aED*eO7)v>&hNRqy7f?+%R<p*
zmnY<J_l{d{*04X}>8E@1&$lnR*z37O`s=UHR&zOj{r!3S?WMc#uKF%h3|OwhfB_VL
zvVg^OKqSac2G+m@3VkV>Y#FOosXy4aL3+!^&j#;xSPUCjI%Rm<3=fp-2|p|pA=BP=
xg#Xi>y&7F!2?4&lI2xUKICryf#4Nn3>gdXKH$1JV;du4q%US(KKRp#0tN~cMR|o(A

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/minus.gif b/Database/CoolRunQuery/html/images/minus.gif
new file mode 100644
index 0000000000000000000000000000000000000000..9b3604b27b91a8065d91eabd0746e7e0e48d443c
GIT binary patch
literal 974
zcmYLIe`phD7=DiCOvTp5BgvwxF6oArQrcQmmzkQhB_wVQ>L1#%8Adb8kfEa+Wewx%
zvTM<86pa#!NU)&<8C{SenaVgq$!;0A!%eyEk1h<Ums=U38`)7A1iyWE6ZZY_e(#Ux
zeR$sY<BPl+_Pr8sMJt{F_C1613wil|C4Wn*{h^26N{c1A@>?ypEOsA^>YEL*R4IHT
zE5E3<x<2($I(@z19f`Gfg<>D%q<f00>6v9ox<@gJvRa$JCgyL+wGG;(RMvE{OuHI`
z;fefBseNx~{#rr4uhus7=sTIl(}q~C6pFI4s`8&_($__AIF`F9<!{SUS+REvs%y3G
zgC`oB4ZW_v)E}MrFqd1F#G+DJtw|+CUDNe?BTWe(syZcnHzSoRVo|QFs&g0fnI&;B
z94p+G1q69aW5;`7wm8rXVEj@`6GLy~e6@~Q20KkZfmj@x1DqM<06#E8{d4O-fGGgV
z3gxkzMbnTz8|eW#0J0y%-AYD5MyLbyHi6ncpa&Re!T^kL6c{nu945W;lw0sGBACQ9
zZ)065oE&!3YHtkNH3%Gd;MZX*>xU2oKaHVbRQ)&>1eK5g;;=C${tRWV;y=kz1&<e=
zsrPn1%db!&v)JqcCxDW=;M%}q3P~RPBnS&~8H5KR;0P88k_7x&w6F{=8*se#dkgJN
z3gBrFO{2Qu;LHI^1YHCIg%eW`98^6$t`m$?!)_B(+>XGH5JoA{>%_ZBv?Sqp0^jjd
zRc(#qj#7By$?14NbC?6q-z^6I49pxggfg~A*s0-|!83+>l_4Am@G%orEL9Dr1}mM0
zal+igl(V=c7_bV4&>`mkeV&1$Vu7P?0X*)<-vjvh5T^GdF>o$`lQW3WyyqW_QAW36
zj6Y#*{t~^9IwzO1!ya~S{OV*peBNOln>Y=1=t46)mhFpw8;Lw`u^&&lb90|Hb+*~x
zcrgAwcI~tHzQ|&(?S=M!?0Emh8*NPJZP)tB3R2G<?#+%f$#Uzi{yhob75Cm|rt6T)
zeI>-E+7Gj~tMR1~w(USqZYbqFd*MzfzMg#(N7%2oIj4U5#Pi*@t-gyb$-ic$OC`qb
V8m@OppITn-h}`gag!4)G{{`}CShD~C

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/newtopic.gif b/Database/CoolRunQuery/html/images/newtopic.gif
new file mode 100644
index 0000000000000000000000000000000000000000..aae4c27f1d3e9a5a36fc1e9fe45e84990890d2e2
GIT binary patch
literal 340
zcmZ?wbhEHb6krfwxXQrr|NsBHckeRHWT>l4`2QcsJ@oYHhKCQ=Uc9*I@81Jw&o21<
zY3H|ZdoEsB^y$;ib7vR)`nmty*@aiHEWLVV$<@nCK7ZcX+M0Fc^3pkT+8#bwd*#Z~
z@89;ccjWx~wQtp`={t9>c=&M5)@@6cEbX5#p=|1u>Yu;%F;EpK{$v50rvoBEeqvxN
zJkU_!p~J;^Vo6Y?43Ca-&vWG!YO`C{ggFSrFgG|R%~?@&wjpgLb7KMLhde2p8wT&5
zt=sxCBIFl$dVC^VYg>kguOzzydmp=^Pl>RQxUiInkkX_?UXJ<mc~#~x3-WVu@e6Xv
TEb&{vevbF%PPc8&jttfS?8SjX

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/open.gif b/Database/CoolRunQuery/html/images/open.gif
new file mode 100644
index 0000000000000000000000000000000000000000..36f3cc0d3bd3da90cb063e75b1b650e4409e0f5c
GIT binary patch
literal 389
zcmZ?wbhEHblw*)%xXJ(m|NsBz<KxlLP)$mV3JmZH3iQ5r>-g>+E4Oc1=I-YB|Hqx*
zU+?_-a{K4!Ti-w4{Py9-k59MWzq<1F#pTz}F1~tt;qkpwS1;~2(AU0nZtsONyH6e4
zcJ}1XMe`@;=ceZ6q?nr-H8qsm+F1Pie&^eVn_u7G`10=hhgVk~-#h)__K90p4?lfy
zcKha~#}9AWwQa?$={*yAo4Y&eR8<spv^CnAt74);#6*RqB*hgK<Rm2}fldWG89^xi
zWMO1ruwu{w34#2?z_!R?Zh?o6RR6BlqLVpR^DnF@@md?T{>GZJ({HQxpAucFB^epW
zbok&Ko3mOsCVD6w$dNd8#kb+cB^Cw-CNn)#CX-m1l12tg{U||SRkH>Lb6@^YPF`QG
zl8N5>3qq8nd<`VMRhV@n%vl2rnG7P;n9K!y1TB~pqIF8Nykr}ga-!r)<g1&6<1Bib
fbmIA@GO;9Zi#HhE^ipJ+bB|l>@w4YqjttfSsQIZ@

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/plus.gif b/Database/CoolRunQuery/html/images/plus.gif
new file mode 100644
index 0000000000000000000000000000000000000000..a706eb249b9a650b7d017bb68f1a7060d51fc0fc
GIT binary patch
literal 981
zcmX9-e`p(J7=Et#(R8yV9!Z-*8L5b1s4mkuTMV_+Eb~X%I@p-FAdMSEMwKd~E#v5}
zmx{H9kwGYR20J7m)=;zrDdUJ;J;IpBR@dt&ZO~HF<QTUZ=8-DIeSUZQ=Xl@mectDJ
zzUSkPyczE7iZ-GVyMSw7Fg~4;Zxu2Nl6FrIy_Xc1mGqog_+9Hb*n9p$Qn_2qUX%4|
zE%|j;%okI0(%^7hx~T+Si?sPd+C#lq(&W2Z_L>sEBFeXlV!pslr84tUFnqS{nNa*n
zHnSl24y4laVqsgaJ)%5fdR~frk`9C;`omgbL(AqA`A%`-QpWXEP<x<Dd8N2b)lVoJ
z#cWQlRcq-vNxE5h`h{NIkkge7P0AN0rcy~t{*&B$j>?ItZ^X01>0me_<`m^l(JkNK
zQ)Ptzz+D7#2_zY}0*s)4CS&=mj5U_lKYX+qv;W-cFb1Os)}#BE-7j)D2n6oK%K!-g
zV_Pczu;5th5^Xm9u<{^>K|s<VB@mXDATxxl5uy+>LZJF!nMA88=KTs-1k9QT>~K3M
z3lxT(#w@_2j$3E2gH;wS^nAaDrV<1e9F;m;Z(D<)fEz)NiXFp(u{-KT6f2C0ALI>A
zn4B&JJJVnd2m%$L1llYC|HQEC11o@%df<70*#vkF+z^Nj<T3~cLckKt67U4vhuCXl
zaM^(4t@7Tg54-@5Hm(TD6*p@tEED($1PUjkpnl*sb%8c!RYi-5$u*(-HiWk+(J4}^
zk}^+Nj)vtqT~@bQ_9)#L-StPiRrliyFXr%9H;x)cdFQuktEwDhM-1A(!5A3>7oTvY
zP*!1j*aWQ1DnSb!FwHr<+6}=pO5Y8uF!M2!pN8LHnHfT<{CE|A3S;+fpG>SBq1m?o
zYc<B`Fh0gVQSVs5$IfS+p^57;Tc5vYJSNrc3pQu2{#G|W-eCJ6xpMq^_;b78vA%Su
zebVj;3_G^GJ>f6hmVrqpUJo}guqNMG*$y>5`P}&}r~myt)9})TN78Y@!dtsovCn(v
z4dF|lb*r;qL9F@Zu{~b?YAD`fKcTM=^?w)lbn+ojzjuQ9-uAAx^kejwPa8Y@gNuj8
hZzPzev6`b|38DV^sZ^!HoV)aE*FfJ)qTP#E{s$QEd*J{8

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/printer.png b/Database/CoolRunQuery/html/images/printer.png
new file mode 100644
index 0000000000000000000000000000000000000000..df629221c2c4668d207a072957dff956a34dce63
GIT binary patch
literal 13761
zcmc(Gg<q6iwDq8<fPjFcAmB(dbazODbT<s$-6hf>2na}bcS(nINSCyLFdzcb4fpVV
z-~AgdKSZ2)<~irtXP>p#TKgETC@+bD_6iLGfnZ2Wi77)MNHFmGHOf=)bDX7E9sGst
zEGn&v0=|4uOv1pwQ5~eToWb=}4}XwiMLuwY7l~ZNHC<Hf&0O4#oJ=9^?(U41cGk{t
zBL`DPdnfbMeg0Pv2suPrOhnZqZ7<!^fw({YphKV$^%1#9z`1WYE^YW1spUkI*NI~k
z-)fn5)9mA&+Dck&Hk&x56S!6uRQDD&w7m7^W%l-EIo)Q9e>%C%h0pm#TkmNK;ttp3
zYsOLz$I*nZ=YLG{AnRhey~BD+ifJA|ghdYdb6#w0RM28RPHrZ6;i{nUVk7Ni*b8`>
z@7_ZF{qUX}qM(JbXXy8``|2&%=w(M?3u$r`&obTs)i;~@np5J{3kl!mU6C^W75{tR
z*6aP2`^0@O6J83~W0b&7Vq)ScJq+U~PFE*8E*fv>u_pD90?AR@K3Aax4!n}mL>4i@
zpnwIE*F43+7s1kcj2cNER`wxC97}9gxC@E`wI(;hMvmq9Kfl~i-u(%Rag$Nh2bO|n
z*ms_oyTQ5e6VWcHIz?O<vPb|q%EYD#`JgOr?>5<>jVG8j{UZ@9L)PRR<2Xs#K?%lp
zsG~exYs{#y-p^HGWkD=Y;|Fo^)S8W=zT4cLxWq{st~q=~PNb016q_YSmAM)=p~y~=
zqxw2x7M2sHNQ10|JEd1&77`?G!X8N8X~W5cqxwx8#I4h+ULrLb*Ol@qYUBWSo|!%s
z`)S;#X_qfKjK!;w<IhlsA$}d1cLubgD?u`*p`KK4>=$OIr}LUP=aJF_o@%yvxkite
zz2hd4puv@Kcda4akx8BAa;1+?N=n+NGkF45F)W7=W9L29%TsZRFkETVn!LnozI?b8
z8F<TKUWt-`;8eUvk|8c9{zPT_=fuN^+K(UQx1)^m=rt$4xiwHXMtIh|@!b6wWE$WB
zHIDjjTn%e<@hyErHtt#Kl0p3#Cs9yJ^XV_%7&=pDr7NA{0lqP5<?!mbm>3h$F4lmF
zk1~G6`ku8m-`<ir+KDOSN*BGmC-D7Tg-#xkvqCP5ciBkX)LFA;s5a_HPEGtLb7%Zs
z@nLop$61pR?W~)f3D0E&&2eL2sf$jxk$}&AF8L_K$Yi+o+i@uTxAN(oj0pCyY{8A9
z=|j?n<ut-16V%0CDi~@%Yjcu#U#`U&ej<YX-z25ZD-Bx<w4kT5=jKp5(bbO+Gatwk
zq%t;rxPtZEtODJnDJ7_<{MjwmAMnHw-l8y7k^V%%B54aqM3tRDqAUdk>|yd*u8I@i
zC17}ex+foEHoYUChsIlRBI2w0G>hs@EFDePf3Kg=OM%zFort^_eXJOiz`u>Gha#?d
zMQ%hCa8>ni>xBPq{lCM2>HPQUBI%+RIEhHxSy1IC;PNa%*khBARok6o^4s21597(E
zLzBtt213ZX<pNTIo|0=}7Y9Z&JWNbDeP67E+-T<`csZ-e*E9~bCJQe65YX{XC8*lC
zWBv;(oL2!}OW~^jKPp)tBc$+7bp9K$XewO_4?LkFnL5eO5row|q_JzQigx*QkZPM^
z`i1zxRbzfIUaS&n0Ce6!5W)uuB}c(5oZ4~XCUG0}9K5;lK}ru2qYER^xF&?FLq0-6
zpq1Te#}2%^iPB5TUB*%KkZGi%XNpFgsj@eI{;^|-<IT;@OI^mKu{8&e5wqH58_q=%
z%+MLDde+jJi0W#VpL=KQ{*R3FyLkEw-lw)JYHBumdwF@87#ka#xVX4@I5;?bWpTsn
z#Dfq(bbqDA6gD+m!o{CQvQR;aAmfm%l|8r0l8TB7S~|LtGY@`KyN1QxQ?Fn!Q;#-%
z@cnyp^SfE?cdL5FpBfq(1fyv@@zF6NOVGcI4P*6ww_bCnyK~l+1|890F1j6l=`k@e
z3i1GDF<-nmKRG=;W$qhYD`*{kyuFpSD&;(r^a+o;Op2`%ztbyqWL8~8Ma4i_S$Xf&
ztMt~dqocJoEg>l>H!lyFF^PV8hBAzXGZmw^x0i;IF_F5Kn9I)N>9c17j~_q&bbEW-
z=(e{oeR1J2_Uo6S0{G&B|HTd1fXF+KKHe$5J*qMe>LomWtjUDZbp^iaIXF1V!L3T^
z=;&Y|rbR_X!hU{!&85;<A=UFXMP+4Trlyn-LpQfs*UO_#4lscA)%Epdz4hF~$K}&`
zoVRe{e`6YHEB6z)?U+l0dkNW)EFM=iH8y%Im#CF$%gV@TmzI|5m8zGE+S)R}@MRxv
zE=@^I{R{&G!@|M>f=I(aM^|-qbyd@A^>DnODb*Nrb$8Ef_BdRp?fc0Bk>p0O?Nm6|
z49FOX^Nw+)$Q3MVYio1P&dj)~tE(q+a&qQmXCpN=HA#DB8Zw9N&Q-$g>@Woc1iofw
zDh&CdLbaIt6qS@dL`0zd{aM}Zv@@AM3zl|ve}CT_Jj?yXge2K(cvRc-UwWgL7R|dY
zsx>m2Q7i-jdu}bh*UhfGoa!1H?wlMPo(l^LimIx0zi&ZYHx}xxCpy4jlKnV(9e%G(
zO-*I}UIdP>mp80*-Q4iY$jB(_>PB^SiGCfqQc#NQ4eaZaVCUpC_VQZr{WD#h{^`>v
z9WQThcfXSfNl7C30TOo)51G_*p%jDGo3gMXkaZd9yR+qsnrdn@E0dG!nhkcZ`AHSJ
zuG7=f#0(4!R2A9S{>0XHuL(Okve<CybRCFe9ioJG6A}`3c6PqcL<xj+tj5H};e1I*
z$Sx~G=c=UbrRL%y(D`QbJp_ZetWY6y-^Rk?=lJ5H_jNy+e=8TX;(kcN(X_6L5RMON
z;7K371-Z4PrK8hg1X#h=?5sLBNp#Q|4;NQxBmvX<&E+xSt5?bl8*VLY$Ctm(uh-76
zV^dQj!FxFk4eqF!A>_s?dU~H~YFN=<ym*U+B8)4Jj)`gP;DALfpC&9XkNJw2xY}xl
z4s52Kg~Aytac^(F*>W9f7gyJEI~yC_<>h7H#ZWT8##k0NtWN8B_6qv9!FWU|<93{>
z2Mbk3-J^YdeS2UD+{+9)1heH&6lsDoGDy>e{7FHcmNZ0hr;lzY5H>8fku#BCz9qq&
zDyI^Yp{1q$4n}zs0j<z&3Ix~dwzx5PEsczhuJ?q$<aS&~j);gDpPmkCZsyfP1d*dy
zSXqgxsJt9a=hHCI*Vp%6>k5v}m5i}7iE2ao#W3pG=RRqc24cnm*|)W{oS&bZbn>>g
zE_FZN8bNi<GiY*pVm_A9n=hM$g%*szxoE@rupl`(kMt|KQYzFFgT(Vv9JomY&hid5
zkB^VHcX!_z7?2ed6y%uZ5A6P1>n<uU@BK4V>UzFWp<Ry#_DPo{neVi|y85>(umrpJ
z|3Zaq%%W}y0?yeyxyAZW=$$qX_9rJNy?Ocg&dasyOPoL&(ZFErt(6}>Ao*OZg#wI7
zS-8%stHT9b9=sEEh8omeZ9kWjsuHgHHex+zW8AnptD*uE3`R&y{4gJ|QF8m?G`OMw
z?V6jL6}7a&M@Qu^eA*iiOgU4ljk=$*b8#(3lL|DK*3{J8p6pCnE2Q(D^1}Z<8NGCn
z5&Vrah+@Rj_v$^>6oSisrL`kJ-*nNoVcD#tw3Mwib7e)JM95FK-adjQ1mw%~+}v9L
z5W+svgV`vNQXEGpvKUFj!HJ3Z(=#(5{?8+ux$>mSzJ0?_Pfu^YYI1UNs<NJAEYqs(
zJ09gb@Tthj$+>JhU$HifYD4~Yo^~8{l`mfk*2oQVo|urZT<>|j)v~y-5Yb@2YIk9!
z>+a4KO(qmQG11#Chb$s&X-R8kZJqo26aX<HDQVyKc9ESWK&zeoZHh24ZvVU1Ej8gj
z!lR=j5C>FHakjS1RMphh)_Wrxy-xo;as>FbF_|w5&`nrUGPFWx91RW4;r{kKx1z#M
zO+-Xwvsk6@k3t&v#H;XcPvg(tBuOm*Shi+O9m!m6^*nxEs!_Sp3?4|u)wMp`_vHM1
zV<7e|SP7jk)F_XJhK3Z?)bP?x-;iL!eSAm|qv>qAtBN#Y*!Z!^fNlnU&oa9kAIFlA
zkWkdoi3|*U^wWm3Ouvnnj?r^C&^fxIf>F280cm7p<Y%MfMh@{+0&`!L-7+tD0-lJ-
z$OC#NCVN4j3x~(>zorm-bJ4o`zg-bOvK%BG9S?68zu8{fczb(Ke6w9d7gzfr3^`~!
z&nWOfd;VMrq{(gIZzDGl%|}QZ=b=wOir|1LiDrMUfY%llnt#7|C#{QzhsW){Pf}1=
znCqECvknqvduQi+g<gxIzCNk@y{D(=#S%g=6y%s!<=nN9d>Xfs@6qo;?Y^It+=wYh
z_s^n<Y5<+7143uZw44<rCHwWR&-QAGK9zv_{_lGAp0u{MHu9)Uo&L}6u9Bi6#L$s!
z=J#)kzW$fQPNE=0R-)O8KTu==6L{q8>>LR#NJ}HBtFO;)XdnP3^m+7Lax&4)SwqLe
zo~t$;PHcR;O$65j7*SGE@>jp|yjC!?@^8BP3axR}ZJhH;(obq#-eD?OpJwo&$<<Kw
zYd*on+1YQ7_jk9EeSE#fpcI9^AnWUmBv3nk4uYhohY>%RH}7a!t%(y+5s><9>f(a?
zZvWtpF?$aciqFQz*8CP$+)7>~6qnuFN<td*jDS&B)8&4bI@2c*?BBmDZ8~$zC^7vX
zpOJb1p5M{EafsV-d$uUp_p`%!G-kWRBF<<Sn}fNJ6S2AJYcyA(_rlH1O&yfJ$5iom
zI}=R0jRD=EFG^Q@Y-;BfRaA0y{Q6_a445;-nE?Et+Dc-1RWI%}^9~4*z5oSpJ@KVD
zwy&>mipI!XxlSn9^zRR8FMr1?{5xB;S0LkY`Ypty-+G|~>CoE0Y*3~vlk%T2x3;z>
z`&nZ;jIaYUTLKlGc%gr-JM{3dpR9E2(nnBLRdxF=^l|6*HVvRox%4MgVR9c?LcV?D
ze5X-HO+__6HI=(?L_<T<2?Xft*MDBdtgRWf-d*jkA8z!o@;m(=@PBmC>vU$FF9&jg
z&F)M?pvrZ3*88CS+OBr>V6Lr=Cc<O4yuo3u>&c8yLNbx-OZ2CXcQ=<$YFV(vsNmI_
zppFLtj102t>Tuk6%BbI3wD8-dNw@KQ#oM((c?*GX{P#<QM8NCh#j_WrHwiQm_d`4#
zc8$uYpK*-D`!sxQrwZP`uv=<$Jn%hV?vGm1eu)<R?`pR)x1+;=qa!bmVxd|dD@ZWU
z+iIp+9l(>rn7}!#QJeu^S=jMpdxEX9?QFsMgYYi{9)w1mo;js70Y3Z(#;;vI_x&4D
zkknh=`%V4hQ)Xa@4;lu(YPHLH+S*n{wHf4L3aFvo+Xn~zOG`^R{HY@$E&I*G<4aDG
z(Inr!58CFg7pyC9oxHrRh(?>P)T$|BRRQk$P{r@8wRxWl)){q&a9p1saIv=py6mV~
zlUqnjhwp#m6v6rfL?^(V5=;yLLq9wGJ1P#faX_K&%zhUd;&<M%D!|9fdsUg{d@7Hi
z_{<J&%8wtpnd-jciI@ZL{5k(S4=-ZlC&Ap9>$s~gDT9Fe@+ITB6qYo=ob2p3Gt%@=
zL^|7juMJJ2Oh6UEB<1Hm1Q8Qr<L172IeIxyq0S|v+z0NP1}01FzU0`i!DYLk>VLi0
zu$w`owEnXio>Jq~vRtJJ3$atDLV<EVdGZA1>BmUkb#bMhRQvYuXJkH#=TYr|Suv-M
zkd9u0z@5$zM^$G!jkd(=At(XAH-ksr&abq2cPvayOw<90?XG!6LeeuBPd!6#!TFYp
zi)%~oFR}=QgrA>aNN6a*`%GN)r-v=8x0vUv{vG=)@%8ofKij<B+d)R$CTQrRisdCt
zTYgQVC>y}-GnlV6A4>wknB7}$nNwuLYV_QE;DeJS`o9i6EEwqmrLdz|8kg;6bY>+a
zB^@vR8G&v2?))w#B?Sxp>2q<Vo7yA;zsslazvhE!dvA=4#4}JY#sTx_Xa(!`{=aqe
z(p%r2$o=~DtKx_=H;G}Cl8ZPNZI2CS_nJeIJ`cb17P^eAEWqMQZ-49AvhSaWxrW4)
zZmwjR+Hg&xZl5D`+dBF!^pdLf^isL(??lbb5u^WQ&_)<VNJt2~WcBkvNa~2htvYfw
z`p-Q#<VQ#|$9v=1@BUrihGZztOiX+*WYz@P-hQ?o$t2I*m$8+`ba@sR^iaU8Ei62;
za&zJLVB4nu+o*il-1E3~ny_hHiZIijH3!(&6bUFH`ueZ$A3gqke}=JVKb*+$H9g%n
zBQ5PFo@>Pej@20{Tb^qK(m<wF|A3&uZu#mGByI|h?-HP&67CIW;>cELI6X&j)@0S(
zGJp%{=;(y6GJ6TT0roPpusB}-`}Yq5|BHsW`ItXF_8C-t9+0S!ph{d%rSrKr<FqBc
zXuK3lHDoUG5?7MRMTsO&BmkJ~xsuN7iU#Ua$eDTVe3khaDJL7-G4<QGZ{I~#m&zt9
z$Tn0#$IyHn4p!RkZM#D-@FdLj6mw=K7)5+FkYh;+;U#(;04c%JFyGXj0<E~@wrCrj
zoSe+m@vrMSxJjnN=*yJSL8+j6_(tESOn{P$jlS1z-SF}+MfC}k+=yusiZJxw8!<wC
zXM2kn_CQ(!z#UzmpPy%H2e+6bgpW}j-MrKLSU?C57R)@@KRY{X0UIxV{NEEwEBC0E
z$g%TjeC~{ETHYWF#{qnQbKK~=g>X{T#57{7=h1qs?lr95C6A<XEyi=G1df>LIDL`8
z>N&zee>yQU6U<>fOSm#?!fFJ{JRu3m&5tH$#3*xLGdCh$;w+oGYvJeod{bp{aj|9b
zt-8~;gjwK#{B%Z91pz2W(b1T5uicjpc_8kumIci~It(9s@VnPHG^{!UrbpDiM};4b
z36wvyE$Y)JhGN%gz`s^jR-(Us`{o-}J(YGm<<;<Mj-u6jEJGl3XM1~KWNb{KG0;j8
zID_+pph|KhP-SJYkZqQm@!q|A_X5a-bfYM}^)#l8G}$NbLB{+6y3h?M+WLn2ddjvA
zS|Op#t11-eb8K;Jz~n+gxdsj|eJt$l&-L59PBW79y>^fTxK3>dN<X<TUY+iqyScbf
z)YH-cHDhR!;T}lN8Y)I61v3ZY2Qayx`^T5xnEPA?g=fT~s;@w~u?4!ew78_?5gbP8
z4{$;DZX8(zCNwEWCwp0|U2b7(Tfe{5<jfTC-fP7@whB5@2Po&l8Hfn=C7dy@pnxj>
zni>VlK~bvEQe2D*?x1t)caPtvxl}k%a%#l!t)aobw6e02)ob;$5)kN$05y-PEWo@X
z0rm%(TPQ(eYV<wUg3pm!u}fRE;~lKMy{}h*^-x$wOLM>2=FN3#iY<m8`!`Vu2pGVJ
z8u0P(Y$FIv8L;r-WqJAe`MDtYC3SV|#R-#Lb`2X9E&G8}JGzPIZ&9F*K7wR`<RwmL
z^;*^EG&RlF*e-rsg!GW4S435TKx@x(v9rTuT_|ty2naTY4enUMYl*E)f#k{`r*?V(
zLrNb1+jR)ki#Q;4&){V|>P_2xY<+TWEp7F6b#>(noyP-l!82C9`^zm8AQzq!FlM#1
z@MX&uQZNKcG0GRdd{Eb5lPFUODt2!=WdmW6)z;RQ&T`f~3qRN_DcjrLwgB1anCFb^
zrKE%nbX%3}B4<=g4BW&7IX*uAYg$^*^fd0)))sjL6fk2kCDq&bqqs{|>p;yNO&C7-
z{{8!RC*t_~!Ff00I2)90)0{XJu<K@LXGb^sW4MsQ=*toTEMfp9L|ge)A5i|!4=$+{
z@TwmSVI<9ek1Kw#rH+82WLaAJV3q)SzToWSltKg#<witO^|C#Nz<+?;(FU-bIy^jF
ztR;@6CC{1BjUV|0<my?uPJ^At#wRW-NSa1sEbsF0Y=z#Uu9g;U-a01<u+0SkS;_+3
z6Hho<yM3Ah#=yu}!3cx>kYRg?T+Iqld0=d;5=k*HkttZESHH4h=-`~mU<4(Q92e03
z3m-uPB_$<FxQ$YON-_)8@2#yw@3s}?KfgfzT)w#V0}C;YiHV7iMEDtj3b_HIfFn3K
zc-j+~@e8yxG{Rb1S{MPMrWr)Sj=<rlUp*+iqYosXj2=V013HEwKwQBJAL0Rg32csM
zsDT5>OLkmo^5!f7;xXH-kE<5<&PZC8<*|XyZ`uD}iQ*=LM{ZSNLw=U2TiexaHM~Iy
z)TDE3(fjAsW>*lF^8-SnUdoXK1ui%1la^)7%rV5P*RSgze~q8aM;W%P*Phbg12G{2
z1{g>xdC2n=KeNc*^?|`b$8iQ8&{#loYk6(g;2m2P1hz<;T%$@VIf`f(7#cWuSswdA
zT3E;^fx@>M;8OG`mKj90GT&#=efW+ZFy*riUc`x2U(KQY_(TkV4sxt?k>}tK!iNeG
z76o0Wz%&&3BJTTN|H2HCR)K>9uCO>YQYz##BJ}ckRZY_Kw;PJmHhw6Ymojjncq$0v
zg@B;2v!@2d{xGe?62S_3r7g(H)&~qz@;LO<V}{o=f-vB)21@a|$TMIx%SeH|!fLwo
zbS&i4qohEA>V%DQyqkog81qQyWySz73zT|Z-TIa|v>x)`#eLYjTjtGoGFV~~*{*NK
zN$BGNzUme6NCR&dIo5I@CFpsU<HLkWw7YU><G^INO+=<2StjSB$ALvj4z$U;enj(M
z(*@YYAn2GQ{XP?ILEsb65?{@%P(=_0Ba7vfcQKa_otc4!XT{MmF&nXxq~C!H5d`eb
zl(ks$bwkcnC4K#9Cf^-d4`47%>7{?|dCi^j{^l^ozvtr%!7xz5Tr`5oYa#$cTCcqO
zQ~B>tY2|t^fq|U6t8tE(^(fegy4)mNM~9lpH~l>QT<wP#ad;xI4{s%-fAtI9IWCML
zG!dT6glW&P66Y5Ad3bmPfmQ-_>lQzf^8LNw?L!x;(P>j=Xq9>~N8Wfdu4F&jJku9{
z_3o@erRE@?71&n5@*9TWi&2?DRDjmeFf%v51!=TXoQ?$gShp@3AIQ~_KYsj3bluI*
z$45^p;N=48Y~|O3FatMH;4{PfGEn;d-&NU)G|Os=lvpT+c6N3SfZ*#A>7^jay_b{I
z%}7lh)?6GK4B^EQ`}R2;F$LT}ASj+ee$X5vL)d^IBmSD2s&kh@89<)rx2;L#7mn;$
z%FM?XxwB)bW|WL1N5<#&w+rYBg7vi2q<1K?Z>Dx7u?8iYtrAOo&0hgvYxKE1(t=D4
z@v|ZLdkFcQH-{43LqkH`625%N%Z|7L`mJi-hSv85;Bm$jtRceW0l;DE$P$sGQkgt&
zQhoFRQUUycvuPEDHY7vMWF~>6Dg@xEUe)dGg7iU~F1#4_1el?&{yTmhLT~*&!*t?-
zDAprLC4@7xvJaZDnl3r|?JaPeoSofu93CE$jy4tj;Cc)}_@uG8{ax`sxHa+d@o}Yk
zVGo8K0FctU3}`6Wh)df)z*a;YQ)&x<ln0irW6UBj?Jh4p!SZjf*cXUv0#5)4@9ze;
ze>9ko2o>q!i45mHz#?Uuotvv19UC*qctsV^y%sRM$=doF0ZjkL05HsW3a6yIpsW$V
zu<Usq2+*Dz0mhwq&0(q?#KFoM2!u`hZK%-A8ajeMOI?Do?0e?jNuj;ne9h(>@UcZh
zyQ}49*d>4`$xj-SZ7ZhK0~QUS+EP1h$Lfp9xt1?<IAY2`c!81<rNfAYvVEnLIFN@D
z=^Rb3QSobpYxRbMJ%?VH3O3p_K-l7Pb8%>X<9C0)u(-%J)Q$sYDUn(Rj0p$cbcdE@
z$6<T|0&3jv*kW`<q@>Y{&xlcw4QuCJ?z7C5gJxD&V?KQN@a`EV$wh#3#k`TZdf7Su
z-Ni;nMP=o|iC0_09O&gWrt~@TrZX>?V1#yqJ2qdn1H+k}kI@n>H9@w(zX3=iNBfJU
zpn~%opoNIufXt;mIXOWW0@7Uw*@01g{z=z*nseXJVqpE=43gdb3oUKaw~w9J(kK}m
z90b_@!K{7Z0~arE#Ldl3V^<9jUAbJwJ0{JrxcAV^x!u#gy-_S=q>YUYma!K+$>S90
zq1_M8*u{hV907VN#(5MTZKxrk`73RVr7ybUXo&v4f79vK0x;*m`PL%M1&|!g9az7n
z3|?oB5uC?WF79!<B#6IoVKu`{)@|_kjX=C5MDK&a8x~pE*m8GEpr47}cgZF(uKh@6
z8@oFex<5YPMtnRRDoqJ<_Df)Ka{xqbta*9Al9P*zx}yMf-Gvue(ymElz`~T5kFH>D
z%E}_&{HUxV&Y2k%?ojHhAJd;}joAojMz>k*4zDD#h}7=Aql*hJ*zIIOSKGPw1f5R=
z7JJarM}6;swUktt;bmnjFE6j7rl#g()g+cCPYsMO*QCs}w4lYkS&pCVOiT*rc=$XG
z3xm$|zAJK<WsFI(a|xm`{f~jdkk#C=!I77f%PK9kzA+cNo_|3_O)a#RwwuChrTl3L
z0>NW_I13=Eq8Y2>CNBskuzI`p!vBH-;bRL3$Ru4F4ZuAbI=V@{J7AoFn%NwjfDuoK
z6CS(2HKq*qJRuobjLzupDHLQVujJ(EJrE<Ez&T<)`@uGLb7>812T}xod-&U)ziI1f
z3M_qs7c1xO=L0Vl_z!_idgfxl!=5bHoNBw~K-k^g-F(#w?9hT}fwwi0s$s&-Il%TG
z9vSHczReFa=Oq-n*XP3z<p3;5uF(DE*!_*r-G<Q0dYS=SjqlRRNmyO<gL7~@3M9=P
zGQ!8#*4B2NLmvvL52*PX^FX}?iN4W;)-3L!1`o{Nl)g710PlSW_yhSz12zq?7XeN?
z`WGc#8!!C)NjRDzzz2<2TatI9Y_|HrlW7*^`!D^#2f>u#b2LZ|amka_=1hI>9>l@J
zQ+%yKK}~Hw-yxj)nZ(`}G)Q!TLLf(ZWM*cjsIHFh?myfMm@-g395*LZ3io3KfJwg|
zy;Ou=Pxyv7jhYj}CCNO0$98zEhg16jboTas_pZCfK#eU~&Y?-yk?HUe7ou!-F&w~s
z>S5QAx>ViZce{q&l=|;BoNyZ(*nU$JiMtChRe)&+99#phtDVA*>(teoEij5y&NZ9M
z!ze^>$&RChO8%n;|LX>SULZL4uCBa7V;z+S$$<m@-H>^!94&_?2iQvIN$XBcQkq($
zG6cCRg0o9Yx<L8%{N=6IgwYDEyj5ub4tflJ$4UN|N&c&IbM7I|r1wK2=;(7_odw4T
z`7Un{{QYlgGjIQfSNiT*3l)`=Sb-L&{_JobsGwVTZD29v6clnB8@cz}3E|)w>F)xl
zSqTLCGgd@K02|NE&7B~U!SSrjXJuy(0?O?W*ogNBWH-N_RYE``v)>-S_syH$qtqli
zFCsWR6!Y~T&zr;k4h{i<+g{L2c@x`IqWm2g)1Wt8!PLLw!f5RxZcKqAa?q2YUWy0S
z8c1!>ag=i`$A8eHb912p2VeNzY>?gm0)_!KL|1m!;~Qmqe%i5g-_Ot&LO1_beXbW*
z?+k%r^jFf=)zt(2!11!I!Mw^!1^3Wv8C%RaLJfS0zz+`Gtz}(k!J<Ia_Wb(w3;0iS
zDyvts4H>Axq69n$X<xrzabuGMC^L+GKTjV@gCwc<-)e8*c%GlGudfdQ>5;dZT39Rp
z0CD?w^fCRl(BOLA&xA?OYUj}-dvkUJ<H3;%(BYk}G{~If9Tel3nVNF`B`I_@;an)6
z{^zNKnr*~Jeq3Gc7iYmPLSo;))%{oL@(6pf|Hi4%yFLXyiwIyzn&QoYOb7OmYfRYK
z*ci3Za*j!=O}czx1@-}01t5Tar4{~W3lV*Tj)7qWglThOA)-_0rdx>L8+5SjARoQ#
zYo&woGV){F%ir|<{FfUexNzXYYjC;Sako1L+BE)egoHX+goMZd_o20Cl)2ULN)4ib
zL1!prUr7XUaC3)MS6AnaWPz&0%)=9Yc<3l6Cx;H2w5>NW_ZKl^q<n5=#9Y_KiA%+#
zF<;X1u^lm3`$9U-+YU}2Uo?#QY_WZMa0M$s(9-oQ-QVl$X8_UktYtal<of*SQ+9Jr
zy`Yt1?x@eU9SdS-Sq)@B)B_lZii)Cul{s)n0lEUJ6&TYHun0p7i|rB6ZfiePxIa<w
zM-LW-L!KfbBRTXDZqT;t@aG$en=EX;fxKhtxH;;5aL;@p_cieT=s(v79scIx;=Ssj
z-AZP)^Jsf+-qABwKyU{48f#7Z$^&n6{I=K3+eO@|wSJs!qyZU00y=dw9Hy)Yl59nk
z?}k_)CqD?2y8yE$8!!uW(7pHf*dEX3^1nOI%zVm>Y4|8pFd_MI7-`Vt;a57xYFt4j
zbw4VW-qI(+q~K%$F=RJ|!x{~cfJk~ex(Lt&LSw*>{KV3iaQ!Py@|?cZo88vfxXTNe
zfVZifwk4Bnj5ZHugOwHQ#SRKo04(qt@M~t(+<=}1HA&L#V8vH1gOQJ86QSV&f^%}T
zIXowyDJXCOs?(h|4K5m_5y=pfi;|=Ar~EEQbDE7~K1JQ<K^a-?H;}gwiTpa1Lix4n
zVio))+^<gpvTDkmgsd)IGw*K@=R2=^WK^Ip=YwLiF#t2$-rIY9yT#RU35OsRMT(2|
zj2yEDNWE0Z=kG4WPMD?tZ8>O1MWv@H*Y+ugivjmiWvf44)n$Iu$rGH=2#zj!1dc<^
z2Lqx;j)K*D@%HIoH$L$AGLCGJ&#N}AG&qw|@rHDkL;Uru(n;#d)IAdxPoW>`f{M$^
zmi{<3xrF}&Sej81Le7fR_ci;CC=jJ;kh%=?R^0F&-XwxeOJvp%t!SdwI9iHw10>7&
z<fNpz9QRHODxtL$@;c^8*og=K6JT&))KG9p_eNAC$|ygMQ$-z?qTG-k7;sWDGBWzK
zVuS+>w;Jr+TTO8L*ReAm#*@w&`3b71^fP3Nr<s<u^D^N4#eVV=+Ae4f_S?sm>GIUN
zj2e$2gHA)ECmz0<5)_F})eMsH%*oiQKb(Mple%QrurE&=Q59y>BNYTXqrgiVLb`}u
za#pg{`jjUFEACR(MU_fSTMw7fZt&#KaP_*bgyBbKGi3n5o7?d1(x?4ZWG_^Jcx<34
zA!;)fHQ6IUG1x>>srqgr7<79i4s1Db^|0q7CdjmthD|F$L-F0;W69FwuS46z%%F=9
zL#_}}ZNnZhxe%QySFoOw1HGL2{1u!(v+1?rByPT+*>UOGI4tWPIrg1s%GK0h>>rw{
z_ho$+T>$Hfc+2n>XX;o%43z0mz-M05$Ai!HNqtF(kN?=(+WHEjPvI9$6y2&Cm_!*r
zNtK<`<#kWwH9Ryoa(Q`49L4`6r~(UTJ}TA^)<+1^fKu?aaEYWgs-%7~Rzgn={}l(4
zBat2xjE1IY>RJ_B1PgunR30liWWo<tIj6G)j=NO-Baso)9y<NPaX+m&Yp!M;W<9tI
ztPBDIg1OytFemw8cr!TBLD;6e?ZO)j5JsM2%}1q7a%@+17)|QXM^jshOwP?e_U0p<
zeU1sRGbY`D5WvebZCD%uKG4sBfdMbT`dU5#ed7rFij=-j1Er{el01Aq2rdjB-qhAp
zRQwD$r#Vv9a1s;!L6$li_12XWij1_jc}2XxVIQIQuMf|@(nQcOFqoz}gBr{X?k%Pi
z)V*d1*l?6HW@Imp@7~T13j%>~f3?#A%>6FV7*IJ%MuEPp)-DHats*q!N5P<V?F%}P
zt>xwK4Wo>loZ{H}K4)ge06hV)P4ME^V^0b^%GYsm@%Tmp=S$9VxZ+@l?Og@GqnF?p
zi-pbMq+qpDb!q3?S|Gzg^pa^Ju*5-w0oc~vpcxvWt)oLcdFVnKI6wt#APht+GZRy#
z5HLl9Mc?eZwRnPaBhR0H)Wt$pS5u=z3k=v>Y^VhiwB2%w3LG90!Mbn~q|u7}@_e@m
zkpTyUFo%ZD02?z@Z3;Xra0x#HmmGuv#!7&dnw)GD#q#6F4_siM&rGU*N5&>@Slk0g
zEr4ZH-VY8EawCBBnYhyx!Rq8808*uq9ECYq?rTblajdBwYw|xJMa7RP!hH`T4RpU1
z(HD2|I{XU2WnsYi0!z`x(xTNT$Qz`@$Hv)6dxtCD$77!6jEjp~2PDF-cLssTQWr3`
z9@6?nX!n?Qx%wz!d`4#H6A?qIcvSEWmRCu7P(S&E?j_+%WF!TlTlS>qa#+axC*$vE
zV}Hg4o!%UeF-1hJ4@lOxDqDD&a`EvEgYJXGTVND9mf|EgW$%OT(<PAQjf^OdQq$9e
zDM*t)QyelUf6Y;j{4Hw<o<;5r2mkR8wu#LL6GS>b$;e1LE`l0Ap-vM!(P}!MlFM?H
zS|Q_v1DsbXxZ(*#uEqiK3G|YW036?e>JlY>RX{;2?W-2onPchXIXJ5}HT}(ZE7?59
zQZ^yU&S;Qt=+lWf?XmHx`3?h90yqT(12$k;Hj5f^c1&PkARQzh^b=btaCfr1mE#rL
zE3j1SqI~qqqh@!R{0<|FT5)!+Bk0S-_(nFwWxSx(9tS&4O@E%Fp$*|&ZK15=Q*d$3
zDTC8Zg1Bg}BXm0>&cvlPe&uiJnGogBNThyHCMrgyZNVx?riw6j@mHQw#udLgO6mww
za<oL-?fmfA%OsCWJ7Ru<)Sk?0Q#2b3sNVuWQJeXtuz15y;N?wDn-TfIU=14(wzY)0
zn<OX86<BDSV6~j+DtZb=>e~K3a#Bud)%}fTQb!i$JPLAVBkdR%IEl$}RC=#ZOKgkt
z2V`)2pKRu_&(8>i<)F;dtCYQKepGa!^VtoY>GA>Rd?I+4P(_7+Z~)8(542(gH=8K=
z?(x%0Cu{!dCS<NYAN6H;(POE#1}5zIF-9DF_IOMv^RqAnCKXvGX^>!PRrD!8Zjun5
zwu~IbBKQ71-lNWmTuBA`1{Q8Y_lZ=xh9m($zWr}rXNB&382Dc{YN(B<g{dS8QQe2=
zGH^4t1>q~vIZjc1z6zI|+Wm>6z9l(u^!32oCm+B6`tc(wlf_MK%n#cC_2#L$XNJp)
zbHe8K*%A9@CQU>$nO>umrWNr{g52)_Bi6y~%Z)&C=20F(_~+2*%yt0{M(3D*wu?dP
zOn&Hd(|oU?{6W>ptRG3wHP2qm!ruBTe9|bWsW2xlKRW#OMDSDM#vt=-?OS*`wXB`j
zzJ|&udX~C815>O<x#^~NA6;pa|D_`%1N{^djOL{lV(3^(CTa5bb!_71L1{fn6NWjk
z@<XTx#$-jX>i!h*BM5w-ZVT_=THanFGR><~LL!6mFAxLwv2vFmxDj%uS|yPFLTGGa
zuH|IS$yhY(SfRA~mp~J{#}}49aU~OQ_V3m6&~CVuQIV6@JpX$aEvxntcGu0==#;9g
zID965+Dfma)3ScqxsR~})QRK9;c^NYN*{LK$IJiR4rh`Uw$+RK;G<`)rOucFz(REj
zZ}{j#TFSKsZK<||wb0R6_Q^*WgZ8TC_vZnPx0;bbr{nKl96o-ASrz7yH(IyNs+#wf
zK@$1pdlg36%P1DhlV%e~st72-+jA5NFz47(OkFB0(x&yQtf)Sx6PeJ3%vRfqSn3(d
zX4qoLFa;HZGe)>{r9@7-$7bEow%)9aPIN&IsTS?j$q>E%o$`}{FDfp2?XaYXlq~cJ
z+t{ct2LuXI+Kcq2goUkk$&}Cy4`x#fsyC;my%CCEc9hMvS##3zCB)INEjJm$zT#p}
z2l@^i|4xr~;@QzlN=ce@$3m#tXRMgkyO!5!?u5rhSjf^dVOxqPsX;$Jc~5;QU5J~M
zQuZY_ROU;Kl+94QwzySuP(D>RC5(7Mf=cB5<<4ux5?UDQ&RwU;khs0)j!Du`scw20
zZJOqzskm5v`(oobRIAuB++A%;;Xf4hsv^Dgg}aa_rCF&uJbDE+sfexN96zd0?P*2i
zUvQK;J*UO+?Dc2~7-EZ2>E87g$T~^v^F`6aP(6F<aj|LhUt)&VLrF($aXp)JDNJ1w
zU@U`ExH%E+F-Ij~#(KLlWwSGy^^p)O4R{icR`0M5T{R}Z-bCW`!JC7}v4g?Zd8HB3
z40^PzO`oSHe>+WKrJAWIA2g?YPSmk^HKO`%q*Kg(VuAt2GgKs78ji=bpp30l*7{W`
zR+q}llwwRHQA1~rp32h%kDej%>w5lU&Cg6a8ajyv;(8~q;5=K0*z^iG;!*q+u)=R;
zhb44xdyk;B(wBkcu;xE_3T8u6vN3gaJ^4^dz4y`r*eM~c?BWIZN`u3FSUOA3pINc$
z{()hlqRK`?k0L0UN5W|JRr4rw0ac`jHp$@{Pkl*93Htp=C4vgu2uX1yK3{e?Wm377
z)ih<rlt&_(h{2I|%5^A$erje&CQy++_e&g9!0seJtVVUXKQ1xFrLLzSwxFqkOBCEe
z%Q*f(QbyrSS4$Q@5huSBeSl`um{n6E>FacgkM^Uuv**GZo?1;FT@l3M#e=d}qsG#7
zvxnFRKPTc6v@=qwpu>?A`KLoBu?f)kYOHiS)kk$=1(a;dmNKX%VK%Wv>*3PYdiFv1
zvg*}G$^yv-lfn5R(?QepsbVSC)hYfmJ2XMLvSKpfl+ZGdolfJ}!Ku6h`j9$&pTeOz
zZp+B%C*|<&ZI)b0MhwfrXS|F!@!BaqErig>jO`<rdY?}xjT1@AtgkjPINsJ%<ipJK
zb_ng4rGgSm!msKy@r{b##Ps0c#ikgppU_(l$<T5L)UeXQASu^MTjH}ExeS(i`tq^g
z$k&w<H412x)FxHSU+!K^;NYoVResq$Of;=@e9P>q#eqGT2<O1VkTj6NCc;Y#X+#${
z(OxVLqb*1ygby=Pb4*gf7=E9#T7_9FiREdiSNGr+3dzW_Yu7~3QYqoW#Z{VlCuZ{S
zcJb(9lbp0{_2_Mjiw1uLRJm}y%-1LgD`QXO$Ym0dlx&k|&zAQ|5M(WP5m=vm9V=})
z%p>FtHA$;7J_K}u*s8gA*LpH6Itra9ETM2l<B8$-+i=Ci$TI4sSW;QJ$!q%Knc4cu
zldV!|TK#s`_utxu(S~jaD<i+DM9AnfCjOW{n#rRWOL{IsFQD|Da^cGl7usHEX;6MB
z0IqHPcp2P$I&w>IVFPndn9<;*%eiDPj&d0aT}TyvzGNZ+5k*3OXh>C~da`DYva||b
z!U-Kgg3Lk=tF~xdP*$9ori-IV0acFpH5T#*A;5DaIwH!9dQoMWtc)Wm$v#QZR{Z#~
z6LI?F(rP$XWBI+Xsb>QJjH$pbwu|h0aj8hOS5Y;_47<^t(<b?GNpah<g+Ej)sVYpc
zcQzC85|#3{EFMj$E=kGA>e5-VgfjL>$$Fr?D~XArM2n=K+8C5+PfrXmv2+ZTf=IDn
zL6ImSsMbWEO`i4aOKA+xdCV{{mYbR$+ZWd;C#t=S#plh(J03EIDGer`a=y$pg`?8H
ztVmh5`dp<B856qa5BT|x=*uw6>_!AE*@A-@F0M6ns%e}<V`h4IkM!i;@DqO5^Azyk
Ptsv6k@?sUDhJpVB+P<}H

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/printer2.png b/Database/CoolRunQuery/html/images/printer2.png
new file mode 100644
index 0000000000000000000000000000000000000000..b788358b399e75cf742ff9103366cd8975960c9b
GIT binary patch
literal 38049
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
W4C6g&EWFDA0000<MNUMnLSTX+0bxM^

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/printtopic.gif b/Database/CoolRunQuery/html/images/printtopic.gif
new file mode 100644
index 0000000000000000000000000000000000000000..63565cfc7ef04a0031bbe2c535c188c5aa80149d
GIT binary patch
literal 221
zcmZ?wbhEHb6krfwIKsg2|NsBHckjl;#4MfHS6No@|NqS|pD!$))B61Ju_g1`e*L=o
z_wV)Jzpg%ia`e})YtNq?`|<7a_ivZKe7e9u98mnp0#>L4B0+XCutp^)^rdJrWvp8D
z{M8~|gEL>|9CKdy{;=$lX4j+{5nmGQuQ)7B(2(g-W?;9B;1_(^=^!DoZ_@h)>%W{V
mcS?T6u+6#uq1@U}{0wU|JJZD*{5LF2P3-jb)!J1Q8LR=98Cci=

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/question-1.gif b/Database/CoolRunQuery/html/images/question-1.gif
new file mode 100644
index 0000000000000000000000000000000000000000..9b1cfe990baed8d24c5fa1bcb0d7b5b145541a16
GIT binary patch
literal 214
zcmZ?wbhEHb6krfwIKsg2KaJu4|NnRI-u>U>@c--k{|gfS7YO{{RR6!(;QyZf|2Oyl
zpBC`{==}dH3;w^k|NqhX|CI_1qyWXAEMVn2AQEIJ18eXCg}xL`wv1J))E_V%GuV@N
zVV9?u$a-CtbxsW%A_SO>8~8aq-o&&YSXj2$QO4s{KbwP$<X){eHx}q-HXmrNt~)A_
YQy3+9f8VoGHS_(i7W*`)C^A?B0A}S)r~m)}

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/question.gif b/Database/CoolRunQuery/html/images/question.gif
new file mode 100644
index 0000000000000000000000000000000000000000..9b1cfe990baed8d24c5fa1bcb0d7b5b145541a16
GIT binary patch
literal 214
zcmZ?wbhEHb6krfwIKsg2KaJu4|NnRI-u>U>@c--k{|gfS7YO{{RR6!(;QyZf|2Oyl
zpBC`{==}dH3;w^k|NqhX|CI_1qyWXAEMVn2AQEIJ18eXCg}xL`wv1J))E_V%GuV@N
zVV9?u$a-CtbxsW%A_SO>8~8aq-o&&YSXj2$QO4s{KbwP$<X){eHx}q-HXmrNt~)A_
YQy3+9f8VoGHS_(i7W*`)C^A?B0A}S)r~m)}

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/recentchanges.gif b/Database/CoolRunQuery/html/images/recentchanges.gif
new file mode 100644
index 0000000000000000000000000000000000000000..d84d7f8f096a549ab867107e0788a354a2ce6852
GIT binary patch
literal 220
zcmZ?wbhEHb6krfwIKsei_wL>Q|NnpcR<vf#6dxa-8#fx>ym|iN!<(Hu`)=Q^J9VmU
z@7|ujfB&poH~HAHZHEtUI(~fn(W6_B9NEl398mnp0#>L4B0+XCutq8<^rdLBWvp8D
z{K38r(p#Kz?;qk}X%_guMed#07FDrc*F|9>8gguH4;KoEa0`hrvTBM5vg^KT&@hvT
kVrsnjqb>AFcFNUUEt$54gMqdSTbSILy?oT#loc7Q0ZC?1P5=M^

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/rootdrawing-logo.png b/Database/CoolRunQuery/html/images/rootdrawing-logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..20ac823f6eec9b3e894eeea35dc5fb2fd30fa13c
GIT binary patch
literal 15051
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

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/rootlogo.gif b/Database/CoolRunQuery/html/images/rootlogo.gif
new file mode 100644
index 0000000000000000000000000000000000000000..75de21ab2ceceb3edd9f758e72c23105c5f7b400
GIT binary patch
literal 19590
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
a2$2v5p>7JT@Cvao3$<_yxe#0e0suP*A5#SY

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/statistics.gif b/Database/CoolRunQuery/html/images/statistics.gif
new file mode 100644
index 0000000000000000000000000000000000000000..c03436a4aaa95eb003c6c490bee28e39bfebd976
GIT binary patch
literal 118
zcmZ?wbhEHb6krfwSj52a|NsBHcke!U@L=Z5nNnH@7+^s0CkvRV10q3c8JMjlcHQAJ
z@cOx|HUGs~(-ll2OpiIbG&)&ddUU*Zo^s&NKKbawul9Vhh~j%1Ea~r-xa_b@oX%AB
LqmHpE3=Gx)O@=A*

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/tiny_red.gif b/Database/CoolRunQuery/html/images/tiny_red.gif
new file mode 100644
index 0000000000000000000000000000000000000000..dba81f5113f127557dfdfad9ad5208bfd694c322
GIT binary patch
literal 310
zcmZ?wbhEHb<YM4rn8?g<=FFM@X=(o%82<nNulS$a&ow02*)hP?NY8+ok%56h@h1x_
z0|PUI4v-Dhz{SA8BtA#Ih^;}2saSoTbz%0bM~53l+^cQ|BB=#w<N#`7VB(r1Y^K!A
z%n&Rff@%~S0~=79XAZl8;EI|>f=ZVnkn}S!FamXRfb`2GSO_27H%%Z}3|T)5P&Y_F
z7fW06NtuTW1agq185!7NwzIS;CkZcfsalC-I12+zHxJMwD|QRAF)({oae<8I1pAa7
SVf&P{#ZrcQ86=8C7_0#!o;rsB

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/tree_icon.gif b/Database/CoolRunQuery/html/images/tree_icon.gif
new file mode 100644
index 0000000000000000000000000000000000000000..8ae8d18f1debe966e61da8820a646ba5676ce5f7
GIT binary patch
literal 1891
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
OEbk!=*T&;;2=D*iWTfl>

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/viewtopic.gif b/Database/CoolRunQuery/html/images/viewtopic.gif
new file mode 100644
index 0000000000000000000000000000000000000000..217afe28b9fcd1032e29d6751d974f0c25163c26
GIT binary patch
literal 77
zcmZ?wbh9u|6krfwIK;s49|UgRy?b}dmYIERMcH6JkkDafU}E56;9+23ma^Do^Wnov
b3H6;4K3cNpq|<9#o)xIgTI4&Mfx#L8r9dLc

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/wip.gif b/Database/CoolRunQuery/html/images/wip.gif
new file mode 100644
index 0000000000000000000000000000000000000000..d1f3b7095d09d9a0c22c8448ad3e6c7eb73f865d
GIT binary patch
literal 594
zcmZ?wbhEHb6krfwcoxKP_wL>Q|NsB__phxZ|Nno-zyJRI`tz@$HKVaL^TTW9_D-On
z0|NuY|NmD1|69zOCja4$^8f!XKfkKJcqsq>uUT7X{)<P7|NlEp>X&2ZVAMC_3=I=}
z@zgLlRPf^)<(adJm^c{j-Ztpy&X0&-N=^}NZIP+0%}GiWX={~<ix>I-&#a{lXo9?>
z8{fZgCb_w6Gp7Shv-b5DxOze7$46ydBhFu6Ro*;TeEq~=Qon3>x9s(s23OAMe0{In
zH=&@rw_x=O<-I%9Hm?``|KD!vw8Cjq_}F+D*|`{>-ZPjqrEuOH#ZPaPGSWm_TctmL
zP&s;3Yu7flJ6C0|z5WXH)L;OLKUo+V7=jpdK#l>$2?P8328O2QmewXVrp``w_O4F0
zCRWDDjLbqp%u^Uyo0z6>iHV4aaZO>GJK593*-e4hTy*kshI!hqiu|U!hAcW8H!~>(
z2Kcx;i1YHX2s3ZykmHu+@s+SPlJsB^;ArCD6x85Rk>T@F*W$iCm)Xx!Q_6-#Pn`SA
z0Y-UcD`{g@9!GDlyW9y*Cxm7A6ZZU2<i4sRZ_DAb!SP6liZ8Q}$_bZFVFs5z2}>b{
NlM_xlHZm|+0{}LTw4VR~

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/xml-feed.gif b/Database/CoolRunQuery/html/images/xml-feed.gif
new file mode 100644
index 0000000000000000000000000000000000000000..ecb09575418861d80c63d143660290732b84678e
GIT binary patch
literal 429
zcmZ?wbhEHbRAJy_xXQqAHG<{il>-lBS^j_f@V`j(!Sbf>FCRROWBHQ8`u60;56P^*
zzP!Ibujv2k;_nYGTqrVrzIWmO#~0^2GXH;e^=XUq|5lU#w+@~QWjUL!{QvF4=bI<K
zSlx6bQRG98$dhutyLl=f4lew0{owx^m1ot)pARkkH7)qVx+X<F#-E#-{$Jemzu)Em
zmZn-`rvJ0T4+XH;OELaGvE)Axq%jZ)6o0aSRqB99ke?XXP95OP@z9a#Ke2eZYPQw<
z3oA@cCHbw7She+L2QP<FsE$*_(WI$rZ)Ex+mxX3%OjAfn>hHE>a}+pdsF%dZ5LD=|
z#BIoD$fL)R)+MjaoZe*E(iZKfn$D=lZj>fa!mKi_xiu;<$&gLPH;q*xU1G(IRRQgO
zEX>S3QX36fl}q%t&s^=V*~_0Uvgj}qhaSUrHfe2bE&ts{vGdtA*2!*S^4s2EsK(`Y
r&xrl1FO#00(U<3bUyZoF{`+ZkFICdR^-y;+hp<-6iGqin3Jlf&%kitR

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/images/xml-small.gif b/Database/CoolRunQuery/html/images/xml-small.gif
new file mode 100644
index 0000000000000000000000000000000000000000..2534c16fe51f0d3582ece04cbb8e2dc2e5a967e3
GIT binary patch
literal 121
zcmZ?wbhEHb<Y(Yy*v!CCYs@s?k@;LG%Y`E2FDb15YgGQXn*5p;{C{=v=R*ts|NqZ`
z3UokRkX{BBJ%PEN+Olmg&X#Mm2=y&mQR`BqvM{LXrpGCl2`k@ZUz_Qtr4yZAA;i*m
LLPbb`k--`Oinu6d

literal 0
HcmV?d00001

diff --git a/Database/CoolRunQuery/html/js/animatedcollapse.js b/Database/CoolRunQuery/html/js/animatedcollapse.js
new file mode 100644
index 00000000000..2e83e4d6371
--- /dev/null
+++ b/Database/CoolRunQuery/html/js/animatedcollapse.js
@@ -0,0 +1,223 @@
+//** Animated Collapsible DIV v2.0- (c) Dynamic Drive DHTML code library: http://www.dynamicdrive.com.
+//** May 24th, 08'- Script rewritten and updated to 2.0.
+//** June 4th, 08'- Version 2.01: Bug fix to work with jquery 1.2.6 (which changed the way attr() behaves).
+//** March 5th, 09'- Version 2.2, which adds the following:
+			//1) ontoggle($, divobj, state) event that fires each time a DIV is expanded/collapsed, including when the page 1st loads
+			//2) Ability to expand a DIV via a URL parameter string, ie: index.htm?expanddiv=jason or index.htm?expanddiv=jason,kelly
+
+//** March 9th, 09'- Version 2.2.1: Optimized ontoggle event handler slightly.
+//** July 3rd, 09'- Version 2.4, which adds the following:
+			//1) You can now insert rel="expand[divid] | collapse[divid] | toggle[divid]" inside arbitrary links to act as DIV togglers
+			//2) For image toggler links, you can insert the attributes "data-openimage" and "data-closedimage" to update its image based on the DIV state
+
+var animatedcollapse={
+divholders: {}, //structure: {div.id, div.attrs, div.$divref, div.$togglerimage}
+divgroups: {}, //structure: {groupname.count, groupname.lastactivedivid}
+lastactiveingroup: {}, //structure: {lastactivediv.id}
+preloadimages: [],
+
+show:function(divids){ //public method
+	if (typeof divids=="object"){
+		for (var i=0; i<divids.length; i++)
+			this.showhide(divids[i], "show")
+	}
+	else
+		this.showhide(divids, "show")
+},
+
+hide:function(divids){ //public method
+	if (typeof divids=="object"){
+		for (var i=0; i<divids.length; i++)
+			this.showhide(divids[i], "hide")
+	}
+	else
+		this.showhide(divids, "hide")
+},
+
+toggle:function(divid){ //public method
+	if (typeof divid=="object")
+		divid=divid[0]
+	this.showhide(divid, "toggle")
+},
+
+addDiv:function(divid, attrstring){ //public function
+	this.divholders[divid]=({id: divid, $divref: null, attrs: attrstring})
+	this.divholders[divid].getAttr=function(name){ //assign getAttr() function to each divholder object
+		var attr=new RegExp(name+"=([^,]+)", "i") //get name/value config pair (ie: width=400px,)
+		return (attr.test(this.attrs) && parseInt(RegExp.$1)!=0)? RegExp.$1 : null //return value portion (string), or 0 (false) if none found
+	}
+	this.currentid=divid //keep track of current div object being manipulated (in the event of chaining)
+	return this
+},
+
+showhide:function(divid, action){
+	var $divref=this.divholders[divid].$divref //reference collapsible DIV
+	if (this.divholders[divid] && $divref.length==1){ //if DIV exists
+		var targetgroup=this.divgroups[$divref.attr('groupname')] //find out which group DIV belongs to (if any)
+		if ($divref.attr('groupname') && targetgroup.count>1 && (action=="show" || action=="toggle" && $divref.css('display')=='none')){ //If current DIV belongs to a group
+			if (targetgroup.lastactivedivid && targetgroup.lastactivedivid!=divid) //if last active DIV is set
+				this.slideengine(targetgroup.lastactivedivid, 'hide') //hide last active DIV within group first
+				this.slideengine(divid, 'show')
+			targetgroup.lastactivedivid=divid //remember last active DIV
+		}
+		else{
+			this.slideengine(divid, action)
+		}
+	}
+},
+
+slideengine:function(divid, action){
+	var $divref=this.divholders[divid].$divref
+	var $togglerimage=this.divholders[divid].$togglerimage
+	if (this.divholders[divid] && $divref.length==1){ //if this DIV exists
+		var animateSetting={height: action}
+		if ($divref.attr('fade'))
+			animateSetting.opacity=action
+		$divref.animate(animateSetting, $divref.attr('speed')? parseInt($divref.attr('speed')) : 500, function(){
+			if ($togglerimage){
+				$togglerimage.attr('src', ($divref.css('display')=="none")? $togglerimage.data('srcs').closed : $togglerimage.data('srcs').open)
+			}
+			if (animatedcollapse.ontoggle){
+				try{
+					animatedcollapse.ontoggle(jQuery, $divref.get(0), $divref.css('display'))
+				}
+				catch(e){
+					alert("An error exists inside your \"ontoggle\" function:\n\n"+e+"\n\nAborting execution of function.")
+				}
+			}
+		})
+		return false
+	}
+},
+
+generatemap:function(){
+	var map={}
+	for (var i=0; i<arguments.length; i++){
+		if (arguments[i][1]!=null){ //do not generate name/value pair if value is null
+			map[arguments[i][0]]=arguments[i][1]
+		}
+	}
+	return map
+},
+
+init:function(){
+	var ac=this
+	jQuery(document).ready(function($){
+		animatedcollapse.ontoggle=animatedcollapse.ontoggle || null
+		var urlparamopenids=animatedcollapse.urlparamselect() //Get div ids that should be expanded based on the url (['div1','div2',etc])
+		var persistopenids=ac.getCookie('acopendivids') //Get list of div ids that should be expanded due to persistence ('div1,div2,etc')
+		var groupswithpersist=ac.getCookie('acgroupswithpersist') //Get list of group names that have 1 or more divs with "persist" attribute defined
+		if (persistopenids!=null) //if cookie isn't null (is null if first time page loads, and cookie hasnt been set yet)
+			persistopenids=(persistopenids=='nada')? [] : persistopenids.split(',') //if no divs are persisted, set to empty array, else, array of div ids
+		groupswithpersist=(groupswithpersist==null || groupswithpersist=='nada')? [] : groupswithpersist.split(',') //Get list of groups with divs that are persisted
+		jQuery.each(ac.divholders, function(){ //loop through each collapsible DIV object
+			this.$divref=$('#'+this.id)
+			if ((this.getAttr('persist') || jQuery.inArray(this.getAttr('group'), groupswithpersist)!=-1) && persistopenids!=null){ //if this div carries a user "persist" setting, or belong to a group with at least one div that does
+				var cssdisplay=(jQuery.inArray(this.id, persistopenids)!=-1)? 'block' : 'none'
+			}
+			else{
+				var cssdisplay=this.getAttr('hide')? 'none' : null
+			}
+			if (urlparamopenids[0]=="all" || jQuery.inArray(this.id, urlparamopenids)!=-1){ //if url parameter string contains the single array element "all", or this div's ID
+				cssdisplay='block' //set div to "block", overriding any other setting
+			}
+			else if (urlparamopenids[0]=="none"){
+				cssdisplay='none' //set div to "none", overriding any other setting
+			}
+			this.$divref.css(ac.generatemap(['height', this.getAttr('height')], ['display', cssdisplay]))
+			this.$divref.attr(ac.generatemap(['groupname', this.getAttr('group')], ['fade', this.getAttr('fade')], ['speed', this.getAttr('speed')]))
+			if (this.getAttr('group')){ //if this DIV has the "group" attr defined
+				var targetgroup=ac.divgroups[this.getAttr('group')] || (ac.divgroups[this.getAttr('group')]={}) //Get settings for this group, or if it no settings exist yet, create blank object to store them in
+				targetgroup.count=(targetgroup.count||0)+1 //count # of DIVs within this group
+				if (jQuery.inArray(this.id, urlparamopenids)!=-1){ //if url parameter string contains this div's ID
+					targetgroup.lastactivedivid=this.id //remember this DIV as the last "active" DIV (this DIV will be expanded). Overrides other settings
+					targetgroup.overridepersist=1 //Indicate to override persisted div that would have been expanded
+				}
+				if (!targetgroup.lastactivedivid && this.$divref.css('display')!='none' || cssdisplay=="block" && typeof targetgroup.overridepersist=="undefined") //if this DIV was open by default or should be open due to persistence								
+					targetgroup.lastactivedivid=this.id //remember this DIV as the last "active" DIV (this DIV will be expanded)
+				this.$divref.css({display:'none'}) //hide any DIV that's part of said group for now
+			}
+		}) //end divholders.each
+		jQuery.each(ac.divgroups, function(){ //loop through each group
+			if (this.lastactivedivid && urlparamopenids[0]!="none") //show last "active" DIV within each group (one that should be expanded), unless url param="none"
+				ac.divholders[this.lastactivedivid].$divref.show()
+		})
+		if (animatedcollapse.ontoggle){
+			jQuery.each(ac.divholders, function(){ //loop through each collapsible DIV object and fire ontoggle event
+				animatedcollapse.ontoggle(jQuery, this.$divref.get(0), this.$divref.css('display'))
+			})
+		}
+ 		//Parse page for links containing rel attribute
+		var $allcontrols=$('a[rel]').filter('[rel^="collapse["], [rel^="expand["], [rel^="toggle["]') //get all elements on page with rel="collapse[]", "expand[]" and "toggle[]"
+		$allcontrols.each(function(){ //loop though each control link
+			this._divids=this.getAttribute('rel').replace(/(^\w+)|(\s+)/g, "").replace(/[\[\]']/g, "") //cache value 'div1,div2,etc' within identifier[div1,div2,etc]
+			if (this.getElementsByTagName('img').length==1 && ac.divholders[this._divids]){ //if control is an image link that toggles a single DIV (must be one to one to update status image)
+				animatedcollapse.preloadimage(this.getAttribute('data-openimage'), this.getAttribute('data-closedimage')) //preload control images (if defined)
+				$togglerimage=$(this).find('img').eq(0).data('srcs', {open:this.getAttribute('data-openimage'), closed:this.getAttribute('data-closedimage')}) //remember open and closed images' paths
+				ac.divholders[this._divids].$togglerimage=$(this).find('img').eq(0) //save reference to toggler image (to be updated inside slideengine()
+				ac.divholders[this._divids].$togglerimage.attr('src', (ac.divholders[this._divids].$divref.css('display')=="none")? $togglerimage.data('srcs').closed : $togglerimage.data('srcs').open)
+			}
+			$(this).click(function(){ //assign click behavior to each control link
+				var relattr=this.getAttribute('rel')
+				var divids=(this._divids=="")? [] : this._divids.split(',') //convert 'div1,div2,etc' to array 
+				if (divids.length>0){
+					animatedcollapse[/expand/i.test(relattr)? 'show' : /collapse/i.test(relattr)? 'hide' : 'toggle'](divids) //call corresponding public function
+					return false
+				}
+			}) //end control.click
+		})// end control.each
+
+		$(window).bind('unload', function(){
+			ac.uninit()
+		})
+	}) //end doc.ready()
+},
+
+uninit:function(){
+	var opendivids='', groupswithpersist=''
+	jQuery.each(this.divholders, function(){
+		if (this.$divref.css('display')!='none'){
+			opendivids+=this.id+',' //store ids of DIVs that are expanded when page unloads: 'div1,div2,etc'
+		}
+		if (this.getAttr('group') && this.getAttr('persist'))
+			groupswithpersist+=this.getAttr('group')+',' //store groups with which at least one DIV has persistance enabled: 'group1,group2,etc'
+	})
+	opendivids=(opendivids=='')? 'nada' : opendivids.replace(/,$/, '')
+	groupswithpersist=(groupswithpersist=='')? 'nada' : groupswithpersist.replace(/,$/, '')
+	this.setCookie('acopendivids', opendivids)
+	this.setCookie('acgroupswithpersist', groupswithpersist)
+},
+
+getCookie:function(Name){ 
+	var re=new RegExp(Name+"=[^;]*", "i"); //construct RE to search for target name/value pair
+	if (document.cookie.match(re)) //if cookie found
+		return document.cookie.match(re)[0].split("=")[1] //return its value
+	return null
+},
+
+setCookie:function(name, value, days){
+	if (typeof days!="undefined"){ //if set persistent cookie
+		var expireDate = new Date()
+		expireDate.setDate(expireDate.getDate()+days)
+		document.cookie = name+"="+value+"; path=/; expires="+expireDate.toGMTString()
+	}
+	else //else if this is a session only cookie
+		document.cookie = name+"="+value+"; path=/"
+},
+
+urlparamselect:function(){
+	window.location.search.match(/expanddiv=([\w\-_,]+)/i) //search for expanddiv=divid or divid1,divid2,etc
+	return (RegExp.$1!="")? RegExp.$1.split(",") : []
+},
+
+preloadimage:function(){
+	var preloadimages=this.preloadimages
+	for (var i=0; i<arguments.length; i++){
+		if (arguments[i] && arguments[i].length>0){
+			preloadimages[preloadimages.length]=new Image()
+			preloadimages[preloadimages.length-1].src=arguments[i]
+		}
+	}
+}
+
+}
\ No newline at end of file
diff --git a/Database/CoolRunQuery/html/js/dw_event.js b/Database/CoolRunQuery/html/js/dw_event.js
new file mode 100755
index 00000000000..f1ad9dfee06
--- /dev/null
+++ b/Database/CoolRunQuery/html/js/dw_event.js
@@ -0,0 +1,41 @@
+//  dw_event.js version date Apr 2008
+//  basic event handling file from dyn-web.com
+
+var dw_Event = {
+  
+    add: function(obj, etype, fp, cap) {
+        cap = cap || false;
+        if (obj.addEventListener) obj.addEventListener(etype, fp, cap);
+        else if (obj.attachEvent) obj.attachEvent("on" + etype, fp);
+    }, 
+
+    remove: function(obj, etype, fp, cap) {
+        cap = cap || false;
+        if (obj.removeEventListener) obj.removeEventListener(etype, fp, cap);
+        else if (obj.detachEvent) obj.detachEvent("on" + etype, fp);
+    }, 
+    
+    DOMit: function(e) { 
+        e = e? e: window.event; // e IS passed when using attachEvent though ...
+        if (!e.target) e.target = e.srcElement;
+        if (!e.preventDefault) e.preventDefault = function () { e.returnValue = false; return false; }
+        if (!e.stopPropagation) e.stopPropagation = function () { e.cancelBubble = true; }
+        return e;
+    },
+    
+    getTarget: function(e) {
+        e = dw_Event.DOMit(e); var tgt = e.target; 
+        if (tgt.nodeType != 1) tgt = tgt.parentNode; // safari...
+        return tgt;
+    }
+    
+}
+
+// Danny Goodman's version (DHTML def ref)
+function addLoadEvent(func) {
+    var oldQueue = window.onload? window.onload: function() {};
+    window.onload = function() {
+        oldQueue();
+        func();
+    }
+}
diff --git a/Database/CoolRunQuery/html/js/dw_tooltip.js b/Database/CoolRunQuery/html/js/dw_tooltip.js
new file mode 100755
index 00000000000..da22a5fbd78
--- /dev/null
+++ b/Database/CoolRunQuery/html/js/dw_tooltip.js
@@ -0,0 +1,502 @@
+/*************************************************************************
+    This code is from Dynamic Web Coding at dyn-web.com
+    Copyright 2003-2008 by Sharon Paine 
+    See Terms of Use at www.dyn-web.com/business/terms.php
+    regarding conditions under which you may use this code.
+    This notice must be retained in the code as is!
+    
+    version date: Aug 2008
+    requires: dw_event.js (april 2008 version) 
+        and dw_viewport.js (march 2008 version)
+*************************************************************************/
+
+var dw_Tooltip = {
+    offX: 12,
+    offY: 12,
+    showDelay: 100,
+    hideDelay: 100,
+    hoverDelay: 500, // for hover tip
+    tipID: "tipDiv",
+    actuatorClass: "showTip",
+    maxLoops: 2, // for actuator check (linked image, etc.)
+    activateOnfocus: true,
+    tip: null, shim:null, timer: 0, hoverTimer: 0,
+    active: false, actuator: null, resetFlag: false, restored: true,
+    on_show: function() {}, on_position: function() {}, on_hide: function() {},
+    
+    init: function() {
+        var _this = dw_Tooltip;
+        if ( document.createElement && document.body && typeof document.body.appendChild != "undefined" ) {
+            var el = document.createElement("div");
+            el.id = _this.tipID; el.style.position = 'absolute';
+            el.style.visibility = 'hidden'; el.style.zIndex = 10000;
+            document.body.appendChild(el);
+            _this.tip = document.getElementById( _this.tipID);
+            _this.setDefaults();
+            if ( _this.checkOverlaySupport() ) { _this.prepOverlay(); }
+            _this.setPosition(0, 0);
+        }
+    },
+    
+    setDefaults: function() { // called when props changed (resetFlag set)
+        if ( !this.defaultProps ) this.defaultProps = {};
+        // prop name, type, default
+        var list = [  ['followMouse', 'boolean', true], ['sticky', 'boolean', false], ['klass', 'string', ''],
+            ['hoverable', 'boolean', false], ['duration', 'number', 0], 
+            ['jumpAbove', 'boolean', true], ['jumpLeft', 'boolean', true],
+            ['Left', 'boolean', false], ['Above', 'boolean', false],
+            ['positionFn', 'function', this.positionRelEvent], 
+            ['wrapFn', 'function', function(str) { return str; } ]  ];
+        
+        for (var i=0; list[i]; i++) {
+            this[ list[i][0] ] = ( typeof this.defaultProps[ list[i][0] ] == list[i][1] )? 
+                this.defaultProps[ list[i][0] ]: list[i][2];
+        }
+        
+        this.tip.className = this.klass;
+        this.coordinateOptions();
+    },
+    
+    activate: function(e, tgt, msg, id) {
+        var _this = dw_Tooltip; if (!_this.tip) return;
+        _this.clearTimer('timer');  _this.clearTimer('hoverTimer');
+        if ( !_this.restored ) _this.handleRestore();
+        _this.actuator = tgt; dw_Viewport.getAll();  
+        _this.getContent(e, tgt, msg, id); _this.restored = false;
+        if ( !_this.tip.innerHTML ) return; _this.active = true;
+        _this.handleOptions(e);  _this.positionFn(e, tgt); _this.adjust();
+        _this.timer = setTimeout(_this.show, _this.showDelay);
+    },
+
+    getContent: function(e, tgt, msg, id) {
+        msg = msg || '';
+        if (id && !msg) {
+            var obj = (id && this.content_vars && this.content_vars[id])? this.content_vars[id]: false;
+            if ( typeof obj == 'string' ) {
+                msg = obj;
+            } else if ( typeof obj == 'object' ) {
+                this.checkForProps( obj );
+                if ( obj['content'] ) { 
+                    msg = obj['content'];
+                } else if ( obj['html_id'] ) { // id of page element
+                    var el = document.getElementById( obj['html_id'] ); 
+                    if (el) msg = el.innerHTML;
+                } else { 
+                    msg = obj;  // wrapFn will obtain props from obj 
+                }
+            }
+        }        
+        this.writeTip(msg);
+    },
+    
+    writeTip: function(msg, bReqFlag) {
+        if ( this.pendingReq && this.respRecd && !bReqFlag ) return;
+        msg = this.wrapFn(msg); this.tip.innerHTML = msg;
+    },
+    
+    positionRelEvent: function(e, tgt) {
+        var _this = dw_Tooltip; 
+        if (typeof e == 'object') { // event 
+            if ( e.type == 'mouseover' || e.type == 'mousemove' ) {
+                _this.evX = _this.getMouseEventX(e);
+                _this.evY = _this.getMouseEventY(e);
+            } else { // focus
+                var pos = dw_getPageOffsets( tgt );
+                _this.evX = pos.x;
+                _this.evY = pos.y;
+            }
+        }
+        
+        var coords = _this.calcPosCoords(e, tgt);
+        _this.setPosition(coords.x, coords.y);
+    },
+    
+    calcPosCoords: function(e, tgt) {
+        var x = this.evX; var y = this.evY; var xXd, yXd;
+        var maxX = this.getMaxX(); var maxY = this.getMaxY(); // tip width/height too
+        
+        var tx = x + this.offX;
+        var altx = x - ( this.width + this.offX );
+        var spL =  x - dw_Viewport.scrollX > dw_Viewport.width/2;
+        
+        if ( typeof e == 'object' && e.type && ( e.type == 'focus' || e.type == 'focusin' ) ) {
+            var tgtWidth = tgt.offsetWidth;
+            if ( tx + tgtWidth  < maxX ) {
+                x = this.evX = x + tgtWidth;
+                tx += tgtWidth; 
+            } else if (tx + 20 < maxX ) {
+                x = this.evX = x + 20;
+                tx += 20
+            }
+            y = this.evY = y + 10;
+        }
+        
+        var ty = y + this.offY;
+        var alty = y - ( this.height + this.offY );
+        var spA =  y - dw_Viewport.scrollY > dw_Viewport.height/2;
+        
+        if ( !this.Left && tx < maxX ) {
+            x = tx;
+        } else if ( ( this.Left && altx >= dw_Viewport.scrollX ) || 
+                ( this.jumpLeft && tx >= maxX && altx >= dw_Viewport.scrollX ) ) {
+            x = altx;
+        } else if ( ( this.Left && altx < dw_Viewport.scrollX ) || 
+                ( !this.Left && this.jumpLeft && altx < dw_Viewport.scrollX && spL ) ) {
+            x = dw_Viewport.scrollX; // place at left edge
+            xXd = 'Left'; // check later whether yXd too
+        } else if ( !this.Left && tx >= maxX && ( !this.jumpLeft || 
+                ( this.jumpLeft && altx < dw_Viewport.scrollX && !spL ) ) ) {
+            x = maxX; xXd = 'Right';
+        }
+        
+        if ( !this.Above && ty < maxY ) {
+            y = ty;
+        } else if ( ( this.Above && alty >= dw_Viewport.scrollY ) || 
+                ( this.jumpAbove && ty >= maxY && alty >= dw_Viewport.scrollY ) ) {
+            y = alty;
+        } else if ( ( this.Above && alty < dw_Viewport.scrollY ) || 
+                ( !this.Above && this.jumpAbove && alty < dw_Viewport.scrollY && spA )  ) {
+            y = dw_Viewport.scrollY; // place at top
+            yXd = 'Above';
+        } else if ( !this.Above && ty >= maxY && ( !this.jumpAbove || 
+                ( this.jumpAbove && alty < dw_Viewport.scrollY && !spA ) ) ) {
+            y = maxY; yXd = 'Below';
+        }
+        
+        if ( xXd && yXd ) { // over link (will flicker) calc least distance to uncover
+            var dx = (xXd == 'Left')? dw_Viewport.scrollX - altx: tx - maxX;
+            var dy = (yXd == 'Above')? dw_Viewport.scrollY - alty: ty - maxY;
+            if ( dx <= dy ) {
+                x = (xXd == 'Left')? altx: tx;
+            } else {
+                y = (yXd == 'Above')? alty: ty;
+            }
+        }
+        return { x: x, y: y }
+    },
+    
+    adjust: function() {
+        var _this = dw_Tooltip;
+        var imgs = _this.tip.getElementsByTagName('img');
+        var img = imgs.length? imgs[imgs.length - 1]: null;
+        checkComplete();
+        
+        function checkComplete() {
+            if ( !_this.active ) return;
+             _this.positionFn();
+            if (img && !img.complete) {
+                setTimeout( checkComplete, 50);
+            }
+        }
+    },
+    
+    setPosition: function(x, y) {
+        this.tip.style.left = x + 'px';
+        this.tip.style.top = y + 'px';
+        this.setOverlay(); this.on_position();
+    },
+
+    show: function() {
+        var _this = dw_Tooltip;
+        _this.tip.style.visibility = 'visible';
+        if ( _this.shim ) _this.shim.style.visibility = 'visible';
+        _this.on_show();
+    },
+
+    deactivate: function(e) {
+        var _this = dw_Tooltip; if (!_this.tip || !_this.active || _this.sticky ) return;
+        e = e? e: window.event;
+        if (e.type && e.type == 'mouseout' && !dw_mouseleave(e, _this.actuator) ) return;
+        _this.clearTimer('timer');  _this.clearTimer('hoverTimer');
+        
+        if ( _this.hoverable ) { // delayed call to hide (time to check if hovered over tip)
+            _this.hoverTimer = setTimeout( _this.hide, _this.hoverDelay );
+            return;
+        }
+        if ( _this.duration ) {
+            _this.timer = setTimeout( _this.hide, _this.duration );
+            return;
+        }
+        _this.timer = setTimeout( _this.hide, _this.hideDelay );
+    },
+    
+    hide: function() {
+        var _this = dw_Tooltip; if (!_this.tip) return;
+        _this.tip.style.visibility = 'hidden';
+        if ( _this.shim ) _this.shim.style.visibility = 'hidden';
+        _this.handleRestore(); _this.on_hide();
+    },
+    
+    handleOptions: function(e) {
+        this.coordinateOptions();
+        if ( this.klass ) { this.tip.className = this.klass; }
+        if ( this.hoverable ) {
+            this.tip.onmouseout = dw_Tooltip.tipOutCheck;
+            this.tip.onmouseover = function() { dw_Tooltip.clearTimer('hoverTimer'); }
+        }
+        if ( this.followMouse && !this.hoverable && !(e.type == 'focus' || e.type == 'focusin') ) {
+            dw_Event.add(document, 'mousemove', this.positionRelEvent);
+        }
+        
+        if ( this.sticky || this.duration ) {
+            dw_Event.add( document, "mouseup", dw_Tooltip.checkDocClick );
+        }
+    },
+    
+    coordinateOptions: function() {
+        if ( this.sticky || this.hoverable || this.duration ) { this.followMouse = false; }
+        if ( this.sticky ) { this.hoverable = false; this.duration = 0; }
+        if ( this.hoverable ) { this.duration = 0; }
+        if ( this.positionFn != this.positionRelEvent ) this.followMouse = false;
+    },
+
+    handleRestore: function() {
+        if ( this.followMouse ) {
+            dw_Event.remove(document, 'mousemove', this.positionRelEvent);
+        }
+        if ( this.sticky || this.duration ) {
+            dw_Event.remove( document, "mouseup",   dw_Tooltip.checkDocClick, false );
+        }
+        this.tip.onmouseover = this.tip.onmouseout = function() {}
+        
+        if ( this.resetFlag ) this.setDefaults(); 
+        this.writeTip('');
+        
+        this.active = false; this.actuator = null;
+        this.tip.style.width = ''; 
+        this.restored = true;
+    },
+    
+    // first class name is actuatorClass, second class would point to content 
+    getTipClass: function(cls) {
+        if (!cls) return ''; var c = '';
+        var classes = cls.split(/\s+/);
+        if ( classes[0] == this.actuatorClass && classes[1] ) {
+            c = classes[1];
+        }
+        return c; // return second class name or ''
+    },
+    
+    checkForProps: function(obj) {
+        var list = ['jumpAbove', 'jumpLeft', 'Above', 'Left', 'sticky', 'duration', 
+                'hoverable', 'followMouse', 'klass', 'positionFn', 'wrapFn'];
+        for (var i=0; list[i]; i++) {
+            if ( typeof obj[ list[i] ] != 'undefined' ) {
+                this[ list[i] ] = obj[ list[i] ];
+                this.resetFlag = true;
+            }
+        }
+    },
+
+    tipOutCheck: function(e) { // hover tip
+        var _this = dw_Tooltip; e = dw_Event.DOMit(e);
+        var tip = this; // assigned to onmouseover property of tip
+        if ( dw_mouseleave(e, tip) ) {
+            _this.timer = setTimeout( _this.hide, _this.hideDelay);
+        }
+    },
+
+    checkEscKey: function(e) { // for sticky, duration, and onfocus activation
+        e = e? e: window.event;  if ( e.keyCode == 27 ) dw_Tooltip.hide();
+    },
+
+    checkDocClick: function(e) { 
+        if ( !dw_Tooltip.active ) return;
+        var tgt = dw_Event.getTarget(e);
+        // hide tooltip if you click anywhere in the document 
+        // except on the tooltip, unless that click is on the tooltip's close box    
+        var tip = document.getElementById(dw_Tooltip.tipID);
+        if ( tgt == tip || dw_contained(tgt, tip) ) {
+            if ( tgt.tagName && tgt.tagName.toLowerCase() == "img" ) tgt = tgt.parentNode; 
+            if ( tgt.tagName.toLowerCase() != "a" || tgt.href.indexOf("dw_Tooltip.hide") != -1 ) return;
+        }
+        // slight delay to avoid crossing onfocus activation and doc click hide 
+        dw_Tooltip.timer = setTimeout( dw_Tooltip.hide, 50);
+    },
+    
+    // check need for and support of iframe shim (for ie win and select lists)
+    checkOverlaySupport: function() {
+        if ( navigator.userAgent.indexOf("Windows") != -1 && 
+            typeof document.body != "undefined" && 
+            typeof document.body.insertAdjacentHTML != "undefined" && 
+            !window.opera && navigator.appVersion.indexOf("MSIE 5.0") == -1 
+            ) return true;
+        return false;
+    }, 
+    
+    prepOverlay: function() {
+        document.body.insertAdjacentHTML("beforeEnd", '<iframe id="tipShim" src="javascript: false" style="position:absolute; left:0; top:0; z-index:500; visibility:hidden" scrolling="no" frameborder="0"></iframe>');
+        this.shim = document.getElementById('tipShim'); 
+        if (this.shim && this.tip) {
+            this.shim.style.width = this.tip.offsetWidth + "px";
+            this.shim.style.height = this.tip.offsetHeight + "px";
+        }
+    },
+    
+    setOverlay: function() { // position and dimensions
+        if ( this.shim ) {
+            this.shim.style.left = this.tip.style.left;
+            this.shim.style.top = this.tip.style.top;
+            this.shim.style.width = this.tip.offsetWidth + "px";
+            this.shim.style.height = this.tip.offsetHeight + "px";
+        }
+    },
+    
+    clearTimer: function(timer) {
+        if ( dw_Tooltip[timer] ) { clearTimeout( dw_Tooltip[timer] ); dw_Tooltip[timer] = 0; }
+    },
+    
+    getWidth: function() { return this.width = this.tip.offsetWidth; },
+    getHeight: function() { return this.height = this.tip.offsetHeight; },
+    getMaxX: function() { return dw_Viewport.width + dw_Viewport.scrollX - this.getWidth() - 1; },
+    getMaxY: function() { return dw_Viewport.height + dw_Viewport.scrollY - this.getHeight() - 1; },
+    getMouseEventX: function(e) { return e.pageX? e.pageX: e.clientX + dw_Viewport.scrollX; },
+    getMouseEventY: function(e) { return e.pageY? e.pageY: e.clientY + dw_Viewport.scrollY; }
+    
+}
+
+// code for event delegation
+dw_Tooltip.initHandlers = function () {
+    dw_Event.add( document, 'mouseover', dw_Tooltip.checkActuatorMouseover);
+    dw_Event.add( document, "keydown", dw_Tooltip.checkEscKey,  true ); // for sticky 
+    dw_Event.add( window, 'blur', dw_Tooltip.deactivate, true ); 
+    dw_Event.add( window, 'unload', dw_Tooltip.deactivate, true ); // firefox needs
+    
+    // see http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
+    if ( dw_Tooltip.activateOnfocus ) {
+        document.onfocusin = dw_Tooltip.checkActuatorFocus; // ie
+        if ( window.addEventListener ) {
+            dw_Event.add(document, 'focus', dw_Tooltip.checkActuatorFocus, true);
+        }
+    }
+}
+
+dw_Tooltip.checkActuatorMouseover = function (e) {
+    var tgt = dw_Event.getTarget(e); var tipAct = null;
+    // limit number of loops 
+    var ctr = 0; var maxCnt = dw_Tooltip.maxLoops; 
+    do {
+        if ( tipAct = dw_Tooltip.getActuatorInfo(tgt) ) {
+            var msg = tipAct.msg; var id = tipAct.id;
+            dw_Tooltip.activate(e, tgt, msg, id);
+            if ( window.attachEvent ) { // avoid multiples for ie (?)
+                dw_Event.remove( tgt, 'mouseout', dw_Tooltip.deactivate); 
+            }
+            dw_Event.add( tgt, 'mouseout', dw_Tooltip.deactivate); 
+            break;
+        }
+        ctr++;
+    } while ( ctr < maxCnt && (tgt = tgt.parentNode) ); 
+
+}
+
+dw_Tooltip.checkActuatorFocus = function (e) {
+    e = e? e: window.event; var tipAct = null;
+    var tgt = dw_Event.getTarget(e);
+    if ( tgt && (tipAct = dw_Tooltip.getActuatorInfo(tgt) ) ) {
+        if ( dw_Tooltip.active && tgt == dw_Tooltip.actuator ) { 
+            return; // if already activated onmouseover
+        }
+        var msg = tipAct.msg; var id = tipAct.id;
+        dw_Tooltip.activate(e, tgt, msg, id);
+        if ( window.attachEvent ) { 
+            tgt.onfocusout = dw_Tooltip.deactivate;
+        } else {
+            dw_Event.add( tgt, 'blur', dw_Tooltip.deactivate, true); 
+        }
+    }
+}
+
+// Check whether the target is an actuator and the content can be located 
+// Either the content itself or the identifier in content_vars will be returned in obj {msg: msg, id: id}
+dw_Tooltip.getActuatorInfo = function (tgt) {
+    var qual = dw_Tooltip.defaultProps['actuatorQual'] || 'actuatorClass';
+    var source = dw_Tooltip.defaultProps['content_source'] || 'content_vars';
+    var msg = '', id = '';
+    dw_Tooltip.resetReqFlags();
+    switch (qual) {
+        case 'actuatorClass' : 
+            var cls = dw_Tooltip.getTipClass(tgt.className);
+            if (!cls) break;
+            if ( source == 'content_vars' ) {
+                id = (dw_Tooltip.content_vars && dw_Tooltip.content_vars[cls])? cls: '';
+            } else if ( source == 'class_id' ) {
+                var el = document.getElementById(cls);
+                if (el) msg = el.innerHTML;
+            }
+            break;
+        case 'queryVal' :
+            var queryVal = dw_Tooltip.defaultProps['queryVal'];
+            var val = queryVal? dw_getValueFromQueryString(queryVal, tgt ): '';
+            id = (val && dw_Tooltip.content_vars && dw_Tooltip.content_vars[val])? val: '';
+            // Even if the content source is ajax, would check content_vars (see below)
+            // dw_updateTooltip should be set up to save results in content_vars
+            if ( val && source == 'ajax' && !id ) {
+                // Something to display in the tooltip while awaiting response. Empty string won't suffice!  
+                msg = 'Retrieving info ...'; 
+                dw_Tooltip.pendingReq = true; 
+                var queryData = encodeURIComponent(queryVal) + '=' + encodeURIComponent(val);
+                dw_TooltipRequest( queryData, val ); // val passed as means to save response
+            }
+            break;
+        case 'id' :
+            id = (tgt.id && dw_Tooltip.content_vars && dw_Tooltip.content_vars[tgt.id])? tgt.id: '';
+            break;
+    }
+    //if ( id && !msg ) { // check content_vars (for previously saved ajax result, or more complex data for ajax request)  }
+    if ( id || msg ) {
+        return {msg: msg, id: id}
+    }
+    return false;
+}
+
+// check so don't overwrite response if already received (localhost speed)
+dw_Tooltip.resetReqFlags = function () {
+    this.respRecd = false;
+    this.pendingReq = false;
+}
+
+/////////////////////////////////////////////////////////////////////
+// Helper functions 
+function dw_mouseleave(e, oNode) {
+    e = dw_Event.DOMit(e);
+    var toEl = e.relatedTarget? e.relatedTarget: e.toElement? e.toElement: null;
+    if ( oNode != toEl && !dw_contained(toEl, oNode) ) {
+        return true;
+    }
+    return false;
+}
+
+function dw_contained(oNode, oCont) {
+    if (!oNode) return; // in case alt-tab away while hovering (prevent error)
+    while ( oNode = oNode.parentNode ) if ( oNode == oCont ) return true;
+    return false;
+}
+
+// Get position of element in page (treacherous cross-browser territory! Don't expect perfect results)
+// can get weird results in ie
+function dw_getPageOffsets(el) {
+	var left = 0, top = 0;
+    do {
+        left += el.offsetLeft;
+        top += el.offsetTop;
+    } while (el = el.offsetParent);
+    return { x:left, y:top };
+}
+
+// obj: link or window.location
+function dw_getValueFromQueryString(name, obj) {
+    obj = obj? obj: window.location; 
+    if (obj.search && obj.search.indexOf(name != -1) ) {
+        var pairs = obj.search.slice(1).split("&"); // name/value pairs
+        var set;
+        for (var i=0; pairs[i]; i++) {
+            set = pairs[i].split("="); // Check each pair for match on name 
+            if ( set[0] == name && set[1] ) {
+                return set[1];
+            }
+        }
+    }
+    return '';
+}
+
diff --git a/Database/CoolRunQuery/html/js/dw_tooltip_aux.js b/Database/CoolRunQuery/html/js/dw_tooltip_aux.js
new file mode 100755
index 00000000000..613b40c7530
--- /dev/null
+++ b/Database/CoolRunQuery/html/js/dw_tooltip_aux.js
@@ -0,0 +1,178 @@
+/*************************************************************************
+    This code is from Dynamic Web Coding at dyn-web.com
+    Copyright 2008 by Sharon Paine 
+    See Terms of Use at www.dyn-web.com/business/terms.php
+    regarding conditions under which you may use this code.
+    This notice must be retained in the code as is!
+    
+    for use with dw_tooltip.js
+    Version date: Aug 2008 (dw_Event.add instead of addLoadEvent for onload )
+*************************************************************************/
+
+
+// Used when the tooltip content is in HTML elements with tipContent class attached 
+dw_Tooltip.writeStyleRule = function() {
+    if ( document.createElement && document.getElementsByTagName &&
+        ( document.addEventListener || document.attachEvent ) ) {
+        document.write('<style type="text/css" media="screen">.tipContent { display:none; }</style>');
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////////
+//  Initialization: init tooltip and set up event delegation
+
+dw_Event.add( window, 'load', dw_Tooltip.init );
+dw_Event.add( window, 'load', dw_Tooltip.initHandlers );
+
+// removed in favor of event delegation
+function dw_initShowTip() {} // empty fn to avoid errors 
+
+// fn's for ajax in head of ajax demo
+function dw_TooltipRequest() {}
+
+/////////////////////////////////////////////////////////////////////
+//  Positioning algorithms 
+
+dw_Tooltip.positionWindowCenter = function() {
+    var x = Math.round( (dw_Viewport.width - dw_Tooltip.tip.offsetWidth)/2 ) + dw_Viewport.scrollX;
+    var y = Math.round( (dw_Viewport.height - dw_Tooltip.tip.offsetHeight)/2 ) + dw_Viewport.scrollY;
+    dw_Tooltip.setPosition(x,y);
+}
+
+// more later or TBA
+
+/////////////////////////////////////////////////////////////////////
+// formatting and display functions 
+
+// for style sheet specs: id for stickyTable,
+// stickyBar class for tr, div classes: stickyTitle, stickyContent (inside td's)
+dw_Tooltip.wrapSticky = function(str, title) {
+    title = title || '';
+    var src = dw_Tooltip.defaultProps['closeBoxImage'];
+    var msg = '<table id="stickyTable" border="0" cellpadding="0" cellspacing="0" width="100%"><tr class="stickyBar">' + 
+        '<td><div class="stickyTitle">' + title + '</div></td>' + 
+        '<td style="text-align:right"><a href="javascript: void dw_Tooltip.hide()">' + 
+        '<img style="float:right" src="' + src + '" border="0" /></a></td></tr>' + 
+        '<tr><td colspan="2"><div class="stickyContent">' + str + '</div></td></tr></table>';
+    return msg;
+}
+
+// optional caption, optional width supported by all these wrapFn's
+
+dw_Tooltip.wrapToWidth = function(obj) {
+    if (!obj) return ''; var str = obj['str']; 
+    var caption = obj['caption'] || '';
+    if ( this.sticky && this.defaultProps['showCloseBox'] ) {
+        str = dw_Tooltip.wrapSticky(str, caption );
+    } else {
+        if (caption) { str = '<div class="caption">' + obj['caption']  + '</div>' + str; }
+    }
+    if ( obj['w'] ) this.setTipWidth( obj['w'] );
+    return str;
+}
+
+// w, h in obj are width and height of image
+dw_Tooltip.wrapImageToWidth = function(obj) {
+    if (!obj) return ''; dw_getImage( obj['img'] );
+    var caption = obj['caption'] || ''; var w = obj['w'];
+    var str = '<img src="' + obj['img'] + '" width="' +w + '" height="' + obj['h'] + '" alt="">';
+    if ( this.sticky && this.defaultProps['showCloseBox'] ) {
+        str = dw_Tooltip.wrapSticky(str, caption );
+        w += 8; // attempt to account for padding etc of inner wrapper
+    } else {
+        if (caption) { str = '<div class="caption">' + obj['caption']  + '</div>' + str; }
+    }
+    if (w) this.setTipWidth(w);
+    return str;
+}
+
+// Image and text side by side
+// w is width to set tipDiv
+dw_Tooltip.wrapTextByImage = function(obj) {
+    if (!obj) return ''; dw_getImage( obj['img'] );
+    var caption = obj['caption'] || '';
+    var str = '<table cellpadding="0" cellspacing="0" border="0"><tr>' + 
+        '<td><div class="txt">' + obj['txt'] + '</div></td>' + 
+         '<td><div class="img"><img src="' + obj['img'] + '" /></div>' + 
+         '</td></tr></table>';
+    
+    if ( this.sticky && this.defaultProps['showCloseBox'] ) {
+        str = dw_Tooltip.wrapSticky(str, caption );
+    } else {
+        if (caption) { str = '<div class="caption">' + obj['caption']  + '</div>' + str; }
+    }
+    if ( obj['w'] ) this.setTipWidth( obj['w'] );
+    return str;
+}
+
+dw_Tooltip.wrapImageOverText = function(obj) {
+    if (!obj) return ''; dw_getImage( obj['img'] );
+    var caption = obj['caption'] || '';
+    var str = '<div class="img"><img src="' + obj['img'] + '" /></div><div class="txt">' + obj['txt'] + '</div>';
+    if ( this.sticky && this.defaultProps['showCloseBox'] ) {
+        str = dw_Tooltip.wrapSticky(str, caption );
+    } else {
+        if (caption) { str = '<div class="caption">' + obj['caption']  + '</div>' + str; }
+    }
+    if ( obj['w'] ) this.setTipWidth( obj['w'] );
+    return str;
+}
+
+dw_Tooltip.wrapTextOverImage = function(obj) {
+    if (!obj) return ''; dw_getImage( obj['img'] );
+    var caption = obj['caption'] || '';
+    var str = '<div class="txt">' + obj['txt'] + '</div><div class="img"><img src="' + obj['img'] + '" /></div>';
+    if ( this.sticky && this.defaultProps['showCloseBox'] ) {
+        str = dw_Tooltip.wrapSticky(str, caption );
+    } else {
+        if (caption) { str = '<div class="caption">' + obj['caption']  + '</div>' + str; }
+    }
+    if ( obj['w'] ) this.setTipWidth( obj['w'] );
+    return str;
+}
+
+// several functions include option of setting width 
+dw_Tooltip.setTipWidth = function(w) {
+    w += dw_backCompatWidth( this.tip ); // in case padding and border set on tipDiv
+    this.tip.style.width = w + "px";
+}
+
+/////////////////////////////////////////////////////////////////////
+//  a few  utility functions 
+
+function dw_getImage(src) {
+    var img = new Image();
+    img.src = src;
+}
+
+// To obtain padding and border for setting width on an element
+function dw_backCompatWidth(el) {
+    var val = 0;
+    if ( el.currentStyle && !window.opera && (document.compatMode == null || document.compatMode == "BackCompat") ) {
+        var p = parseInt( dw_getCurrentStyle(el, 'paddingLeft') ) + parseInt( dw_getCurrentStyle(el, 'paddingRight') );
+        var b = parseInt( dw_getCurrentStyle(el, 'borderLeftWidth') ) + parseInt( dw_getCurrentStyle(el, 'borderRightWidth') )
+        val = p + b;
+    }
+    return val;
+}
+
+// prop must be camelCase (e.g., paddingLeft, borderLeftWidth)
+function dw_getCurrentStyle(el, prop) {
+    var val = '';
+    if (document.defaultView && document.defaultView.getComputedStyle) {
+        val = document.defaultView.getComputedStyle(el, null)[prop];
+    } else if (el.currentStyle) {
+        val = el.currentStyle[prop];
+            // from jquery, dean edwards, see http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+            if ( !/^\d+(px)?$/i.test(val) && /^\d/.test(val) ) {
+				var style = el.style.left;
+				var runtimeStyle = el.runtimeStyle.left;
+				el.runtimeStyle.left = el.currentStyle.left;
+				el.style.left = val || 0;
+				val = el.style.pixelLeft + "px";
+				el.style.left = style;
+				el.runtimeStyle.left = runtimeStyle;
+			}
+    }
+    return val;
+}
diff --git a/Database/CoolRunQuery/html/js/dw_viewport.js b/Database/CoolRunQuery/html/js/dw_viewport.js
new file mode 100755
index 00000000000..e35585e0d7b
--- /dev/null
+++ b/Database/CoolRunQuery/html/js/dw_viewport.js
@@ -0,0 +1,61 @@
+/*************************************************************************
+  dw_viewport.js  
+  free code from dyn-web.com
+  version date: mar 2008
+*************************************************************************/  
+  
+var dw_Viewport = {
+    getWinWidth: function () {
+        this.width = 0;
+        if (window.innerWidth) 
+            this.width = window.innerWidth - 18;
+        else if (document.documentElement && document.documentElement.clientWidth) 
+            this.width = document.documentElement.clientWidth;
+        else if (document.body && document.body.clientWidth) 
+            this.width = document.body.clientWidth;
+        return this.width;
+    },
+  
+    getWinHeight: function () {
+        this.height = 0;
+        if (window.innerHeight) 
+            this.height = window.innerHeight - 18;
+        else if (document.documentElement && document.documentElement.clientHeight) 
+            this.height = document.documentElement.clientHeight;
+        else if (document.body && document.body.clientHeight) 
+            this.height = document.body.clientHeight;
+        return this.height;
+    },
+  
+    getScrollX: function () {
+        this.scrollX = 0;
+        if (typeof window.pageXOffset == "number") 
+            this.scrollX = window.pageXOffset;
+        else if (document.documentElement && document.documentElement.scrollLeft)
+            this.scrollX = document.documentElement.scrollLeft;
+        else if (document.body && document.body.scrollLeft) 
+            this.scrollX = document.body.scrollLeft; 
+        else if (window.scrollX) 
+            this.scrollX = window.scrollX;
+        return this.scrollX;
+    },
+    
+    getScrollY: function () {
+        this.scrollY = 0;    
+        if (typeof window.pageYOffset == "number") 
+            this.scrollY = window.pageYOffset;
+        else if (document.documentElement && document.documentElement.scrollTop)
+            this.scrollY = document.documentElement.scrollTop;
+        else if (document.body && document.body.scrollTop) 
+            this.scrollY = document.body.scrollTop; 
+        else if (window.scrollY) 
+            this.scrollY = window.scrollY;
+        return this.scrollY;
+    },
+    
+    getAll: function () {
+        this.getWinWidth(); this.getWinHeight();
+        this.getScrollX();  this.getScrollY();
+    }
+  
+}
diff --git a/Database/CoolRunQuery/html/js/jquery.min.js b/Database/CoolRunQuery/html/js/jquery.min.js
new file mode 100644
index 00000000000..a0fb8836089
--- /dev/null
+++ b/Database/CoolRunQuery/html/js/jquery.min.js
@@ -0,0 +1,19 @@
+/*
+ * jQuery JavaScript Library v1.3.2
+ * http://jquery.com/
+ *
+ * Copyright (c) 2009 John Resig
+ * Dual licensed under the MIT and GPL licenses.
+ * http://docs.jquery.com/License
+ *
+ * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
+ * Revision: 6246
+ */
+(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F<J;F++){var G=M[F];if(G.selected){K=o(G).val();if(H){return K}L.push(K)}}return L}return(E.value||"").replace(/\r/g,"")}return g}if(typeof K==="number"){K+=""}return this.each(function(){if(this.nodeType!=1){return}if(o.isArray(K)&&/radio|checkbox/.test(this.type)){this.checked=(o.inArray(this.value,K)>=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G<E;G++){L.call(K(this[G],H),this.length>1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H<I;H++){if((G=arguments[H])!=null){for(var F in G){var K=J[F],L=G[F];if(J===L){continue}if(E&&L&&typeof L==="object"&&!L.nodeType){J[F]=o.extend(E,K||(L.length!=null?[]:{}),L)}else{if(L!==g){J[F]=L}}}}}return J};var b=/z-?index|font-?weight|opacity|zoom|line-?height/i,q=document.defaultView||{},s=Object.prototype.toString;o.extend({noConflict:function(E){l.$=p;if(E){l.jQuery=y}return o},isFunction:function(E){return s.call(E)==="[object Function]"},isArray:function(E){return s.call(E)==="[object Array]"},isXMLDoc:function(E){return E.nodeType===9&&E.documentElement.nodeName!=="HTML"||!!E.ownerDocument&&o.isXMLDoc(E.ownerDocument)},globalEval:function(G){if(G&&/\S/.test(G)){var F=document.getElementsByTagName("head")[0]||document.documentElement,E=document.createElement("script");E.type="text/javascript";if(o.support.scriptEval){E.appendChild(document.createTextNode(G))}else{E.text=G}F.insertBefore(E,F.firstChild);F.removeChild(E)}},nodeName:function(F,E){return F.nodeName&&F.nodeName.toUpperCase()==E.toUpperCase()},each:function(G,K,F){var E,H=0,I=G.length;if(F){if(I===g){for(E in G){if(K.apply(G[E],F)===false){break}}}else{for(;H<I;){if(K.apply(G[H++],F)===false){break}}}}else{if(I===g){for(E in G){if(K.call(G[E],E,G[E])===false){break}}}else{for(var J=G[0];H<I&&K.call(J,H,J)!==false;J=G[++H]){}}}return G},prop:function(H,I,G,F,E){if(o.isFunction(I)){I=I.call(H,F)}return typeof I==="number"&&G=="curCSS"&&!b.test(E)?I+"px":I},className:{add:function(E,F){o.each((F||"").split(/\s+/),function(G,H){if(E.nodeType==1&&!o.className.has(E.className,H)){E.className+=(E.className?" ":"")+H}})},remove:function(E,F){if(E.nodeType==1){E.className=F!==g?o.grep(E.className.split(/\s+/),function(G){return !o.className.has(F,G)}).join(" "):""}},has:function(F,E){return F&&o.inArray(E,(F.className||F).toString().split(/\s+/))>-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+"></"+T+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!O.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!O.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!O.indexOf("<td")||!O.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!O.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||!o.support.htmlSerialize&&[1,"div<div>","</div>"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/<tbody/i.test(S),N=!O.indexOf("<table")&&!R?L.firstChild&&L.firstChild.childNodes:Q[1]=="<table>"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E<F;E++){if(H[E]===G){return E}}return -1},merge:function(H,E){var F=0,G,I=H.length;if(!o.support.getAll){while((G=E[F++])!=null){if(G.nodeType!=8){H[I++]=G}}}else{while((G=E[F++])!=null){H[I++]=G}}return H},unique:function(K){var F=[],E={};try{for(var G=0,H=K.length;G<H;G++){var J=o.data(K[G]);if(!E[J]){E[J]=true;F.push(K[G])}}}catch(I){F=K}return F},grep:function(F,J,E){var G=[];for(var H=0,I=F.length;H<I;H++){if(!E!=!J(F[H],H)){G.push(F[H])}}return G},map:function(E,J){var F=[];for(var G=0,H=E.length;G<H;G++){var I=J(E[G],G);if(I!=null){F[F.length]=I}}return F.concat.apply([],F)}});var C=navigator.userAgent.toLowerCase();o.browser={version:(C.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1],safari:/webkit/.test(C),opera:/opera/.test(C),msie:/msie/.test(C)&&!/opera/.test(C),mozilla:/mozilla/.test(C)&&!/(compatible|webkit)/.test(C)};o.each({parent:function(E){return E.parentNode},parents:function(E){return o.dir(E,"parentNode")},next:function(E){return o.nth(E,2,"nextSibling")},prev:function(E){return o.nth(E,2,"previousSibling")},nextAll:function(E){return o.dir(E,"nextSibling")},prevAll:function(E){return o.dir(E,"previousSibling")},siblings:function(E){return o.sibling(E.parentNode.firstChild,E)},children:function(E){return o.sibling(E.firstChild)},contents:function(E){return o.nodeName(E,"iframe")?E.contentDocument||E.contentWindow.document:o.makeArray(E.childNodes)}},function(E,F){o.fn[E]=function(G){var H=o.map(this,F);if(G&&typeof G=="string"){H=o.multiFilter(G,H)}return this.pushStack(o.unique(H),E,G)}});o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(E,F){o.fn[E]=function(G){var J=[],L=o(G);for(var K=0,H=L.length;K<H;K++){var I=(K>0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}});
+/*
+ * Sizzle CSS Selector Engine - v0.9.3
+ *  Copyright 2009, The Dojo Foundation
+ *  Released under the MIT, BSD, and GPL Licenses.
+ *  More information: http://sizzlejs.com/
+ */
+(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa<ab.length;aa++){if(ab[aa]===ab[aa-1]){ab.splice(aa--,1)}}}}}return ab};F.matches=function(T,U){return F(T,null,null,U)};F.find=function(aa,T,ab){var Z,X;if(!aa){return[]}for(var W=0,V=I.order.length;W<V;W++){var Y=I.order[W],X;if((X=I.match[Y].exec(aa))){var U=RegExp.leftContext;if(U.substr(U.length-1)!=="\\"){X[1]=(X[1]||"").replace(/\\/g,"");Z=I.find[Y](X,T,ab);if(Z!=null){aa=aa.replace(I.match[Y],"");break}}}}if(!Z){Z=T.getElementsByTagName("*")}return{set:Z,expr:aa}};F.filter=function(ad,ac,ag,W){var V=ad,ai=[],aa=ac,Y,T,Z=ac&&ac[0]&&Q(ac[0]);while(ad&&ac.length){for(var ab in I.filter){if((Y=I.match[ab].exec(ad))!=null){var U=I.filter[ab],ah,af;T=false;if(aa==ai){ai=[]}if(I.preFilter[ab]){Y=I.preFilter[ab](Y,aa,ag,ai,W,Z);if(!Y){T=ah=true}else{if(Y===true){continue}}}if(Y){for(var X=0;(af=aa[X])!=null;X++){if(af){ah=U(af,Y,X,aa);var ae=W^!!ah;if(ag&&ah!=null){if(ae){T=true}else{aa[X]=false}}else{if(ae){ai.push(af);T=true}}}}}if(ah!==g){if(!ag){aa=ai}ad=ad.replace(I.match[ab],"");if(!T){return[]}break}}}if(ad==V){if(T==null){throw"Syntax error, unrecognized expression: "+ad}else{break}}V=ad}return aa};var I=F.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(T){return T.getAttribute("href")}},relative:{"+":function(aa,T,Z){var X=typeof T==="string",ab=X&&!/\W/.test(T),Y=X&&!ab;if(ab&&!Z){T=T.toUpperCase()}for(var W=0,V=aa.length,U;W<V;W++){if((U=aa[W])){while((U=U.previousSibling)&&U.nodeType!==1){}aa[W]=Y||U&&U.nodeName===T?U||false:U===T}}if(Y){F.filter(T,aa,true)}},">":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){var W=Y.parentNode;Z[V]=W.nodeName===U?W:false}}}else{for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){Z[V]=X?Y.parentNode:Y.parentNode===U}}if(X){F.filter(U,Z,true)}}},"":function(W,U,Y){var V=L++,T=S;if(!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("parentNode",U,V,W,X,Y)},"~":function(W,U,Y){var V=L++,T=S;if(typeof U==="string"&&!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("previousSibling",U,V,W,X,Y)}},find:{ID:function(U,V,W){if(typeof V.getElementById!=="undefined"&&!W){var T=V.getElementById(U[1]);return T?[T]:[]}},NAME:function(V,Y,Z){if(typeof Y.getElementsByName!=="undefined"){var U=[],X=Y.getElementsByName(V[1]);for(var W=0,T=X.length;W<T;W++){if(X[W].getAttribute("name")===V[1]){U.push(X[W])}}return U.length===0?null:U}},TAG:function(T,U){return U.getElementsByTagName(T[1])}},preFilter:{CLASS:function(W,U,V,T,Z,aa){W=" "+W[1].replace(/\\/g,"")+" ";if(aa){return W}for(var X=0,Y;(Y=U[X])!=null;X++){if(Y){if(Z^(Y.className&&(" "+Y.className+" ").indexOf(W)>=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return U<T[3]-0},gt:function(V,U,T){return U>T[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W<T;W++){if(Y[W]===Z){return false}}return true}}}},CHILD:function(T,W){var Z=W[1],U=T;switch(Z){case"only":case"first":while(U=U.previousSibling){if(U.nodeType===1){return false}}if(Z=="first"){return true}U=T;case"last":while(U=U.nextSibling){if(U.nodeType===1){return false}}return true;case"nth":var V=W[2],ac=W[3];if(V==1&&ac==0){return true}var Y=W[0],ab=T.parentNode;if(ab&&(ab.sizcache!==Y||!T.nodeIndex)){var X=0;for(U=ab.firstChild;U;U=U.nextSibling){if(U.nodeType===1){U.nodeIndex=++X}}ab.sizcache=Y}var aa=T.nodeIndex-ac;if(V==0){return aa==0}else{return(aa%V==0&&aa/V>=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V<T;V++){U.push(X[V])}}else{for(var V=0;X[V];V++){U.push(X[V])}}}return U}}var G;if(document.documentElement.compareDocumentPosition){G=function(U,T){var V=U.compareDocumentPosition(T)&4?-1:U===T?0:1;if(V===0){hasDuplicate=true}return V}}else{if("sourceIndex" in document.documentElement){G=function(U,T){var V=U.sourceIndex-T.sourceIndex;if(V===0){hasDuplicate=true}return V}}else{if(document.createRange){G=function(W,U){var V=W.ownerDocument.createRange(),T=U.ownerDocument.createRange();V.selectNode(W);V.collapse(true);T.selectNode(U);T.collapse(true);var X=V.compareBoundaryPoints(Range.START_TO_END,T);if(X===0){hasDuplicate=true}return X}}}}(function(){var U=document.createElement("form"),V="script"+(new Date).getTime();U.innerHTML="<input name='"+V+"'/>";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="<a href='#'></a>";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="<p class='TEST'></p>";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="<div class='test e'></div><div class='test'></div>";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1&&!ac){T.sizcache=Y;T.sizset=W}if(T.nodeName===Z){X=T;break}T=T[U]}ad[W]=X}}}function S(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1){if(!ac){T.sizcache=Y;T.sizset=W}if(typeof Z!=="string"){if(T===Z){X=true;break}}else{if(F.filter(Z,[T]).length>0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z<U;Z++){F(T,V[Z],W)}return F.filter(X,W)};o.find=F;o.filter=F.filter;o.expr=F.selectors;o.expr[":"]=o.expr.filters;F.selectors.filters.hidden=function(T){return T.offsetWidth===0||T.offsetHeight===0};F.selectors.filters.visible=function(T){return T.offsetWidth>0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F<E.length){o.event.proxy(G,E[F++])}return this.click(o.event.proxy(G,function(H){this.lastToggle=(this.lastToggle||0)%F;H.preventDefault();return E[this.lastToggle++].apply(this,arguments)||false}))},hover:function(E,F){return this.mouseenter(E).mouseleave(F)},ready:function(E){B();if(o.isReady){E.call(document,o)}else{o.readyList.push(E)}return this},live:function(G,F){var E=o.event.proxy(F);E.guid+=this.selector+G;o(document).bind(i(G,this.selector),this.selector,E);return this},die:function(F,E){o(document).unbind(i(F,this.selector),E?{guid:E.guid+this.selector+F}:null);return this}});function c(H){var E=RegExp("(^|\\.)"+H.type+"(\\.|$)"),G=true,F=[];o.each(o.data(this,"events").live||[],function(I,J){if(E.test(J.type)){var K=o(H.target).closest(J.data)[0];if(K){F.push({elem:K,fn:J})}}});F.sort(function(J,I){return o.data(J.elem,"closest")-o.data(I.elem,"closest")});o.each(F,function(){if(this.fn.call(this.elem,H,this.fn.data)===false){return(G=false)}});return G}function i(F,E){return["live",F,E.replace(/\./g,"`").replace(/ /g,"|")].join(".")}o.extend({isReady:false,readyList:[],ready:function(){if(!o.isReady){o.isReady=true;if(o.readyList){o.each(o.readyList,function(){this.call(document,o)});o.readyList=null}o(document).triggerHandler("ready")}}});var x=false;function B(){if(x){return}x=true;if(document.addEventListener){document.addEventListener("DOMContentLoaded",function(){document.removeEventListener("DOMContentLoaded",arguments.callee,false);o.ready()},false)}else{if(document.attachEvent){document.attachEvent("onreadystatechange",function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",arguments.callee);o.ready()}});if(document.documentElement.doScroll&&l==l.top){(function(){if(o.isReady){return}try{document.documentElement.doScroll("left")}catch(E){setTimeout(arguments.callee,0);return}o.ready()})()}}}o.event.add(l,"load",o.ready)}o.each(("blur,focus,load,resize,scroll,unload,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,change,select,submit,keydown,keypress,keyup,error").split(","),function(F,E){o.fn[E]=function(G){return G?this.bind(E,G):this.trigger(E)}});o(l).bind("unload",function(){for(var E in o.cache){if(E!=1&&o.cache[E].handle){o.event.remove(o.cache[E].handle.elem)}}});(function(){o.support={};var F=document.documentElement,G=document.createElement("script"),K=document.createElement("div"),J="script"+(new Date).getTime();K.style.display="none";K.innerHTML='   <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';var H=K.getElementsByTagName("*"),E=K.getElementsByTagName("a")[0];if(!H||!H.length||!E){return}o.support={leadingWhitespace:K.firstChild.nodeType==3,tbody:!K.getElementsByTagName("tbody").length,objectAll:!!K.getElementsByTagName("object")[0].getElementsByTagName("*").length,htmlSerialize:!!K.getElementsByTagName("link").length,style:/red/.test(E.getAttribute("style")),hrefNormalized:E.getAttribute("href")==="/a",opacity:E.style.opacity==="0.5",cssFloat:!!E.style.cssFloat,scriptEval:false,noCloneEvent:true,boxModel:null};G.type="text/javascript";try{G.appendChild(document.createTextNode("window."+J+"=1;"))}catch(I){}F.insertBefore(G,F.firstChild);if(l[J]){o.support.scriptEval=true;delete l[J]}F.removeChild(G);if(K.attachEvent&&K.fireEvent){K.attachEvent("onclick",function(){o.support.noCloneEvent=false;K.detachEvent("onclick",arguments.callee)});K.cloneNode(true).fireEvent("onclick")}o(function(){var L=document.createElement("div");L.style.width=L.style.paddingLeft="1px";document.body.appendChild(L);o.boxModel=o.support.boxModel=L.offsetWidth===2;document.body.removeChild(L).style.display="none"})})();var w=o.support.cssFloat?"cssFloat":"styleFloat";o.props={"for":"htmlFor","class":"className","float":w,cssFloat:w,styleFloat:w,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",tabindex:"tabIndex"};o.fn.extend({_load:o.fn.load,load:function(G,J,K){if(typeof G!=="string"){return this._load(G)}var I=G.indexOf(" ");if(I>=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("<div/>").append(M.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H<F;H++){var E=o.data(this[H],"olddisplay");this[H].style.display=E||"";if(o.css(this[H],"display")==="none"){var G=this[H].tagName,K;if(m[G]){K=m[G]}else{var I=o("<"+G+" />").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H<F;H++){this[H].style.display=o.data(this[H],"olddisplay")||""}return this}},hide:function(H,I){if(H){return this.animate(t("hide",3),H,I)}else{for(var G=0,F=this.length;G<F;G++){var E=o.data(this[G],"olddisplay");if(!E&&E!=="none"){o.data(this[G],"olddisplay",o.css(this[G],"display"))}}for(var G=0,F=this.length;G<F;G++){this[G].style.display="none"}return this}},_toggle:o.fn.toggle,toggle:function(G,F){var E=typeof G==="boolean";return o.isFunction(G)&&o.isFunction(F)?this._toggle.apply(this,arguments):G==null||E?this.each(function(){var H=E?G:o(this).is(":hidden");o(this)[H?"show":"hide"]()}):this.animate(t("toggle",3),G,F)},fadeTo:function(E,G,F){return this.animate({opacity:G},E,F)},animate:function(I,F,H,G){var E=o.speed(F,H,G);return this[E.queue===false?"each":"queue"](function(){var K=o.extend({},E),M,L=this.nodeType==1&&o(this).is(":hidden"),J=this;for(M in I){if(I[M]=="hide"&&L||I[M]=="show"&&!L){return K.complete.call(this)}if((M=="height"||M=="width")&&this.style){K.display=o.css(this,"display");K.overflow=this.style.overflow}}if(K.overflow!=null){this.style.overflow="hidden"}K.curAnim=o.extend({},I);o.each(I,function(O,S){var R=new o.fx(J,K,O);if(/toggle|show|hide/.test(S)){R[S=="toggle"?L?"show":"hide":S](I)}else{var Q=S.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),T=R.cur(true)||0;if(Q){var N=parseFloat(Q[2]),P=Q[3]||"px";if(P!="px"){J.style[O]=(N||1)+P;T=((N||1)/R.cur(true))*T;J.style[O]=T+P}if(Q[1]){N=((Q[1]=="-="?-1:1)*N)+T}R.custom(T,N,P)}else{R.custom(T,S,"")}}});return true})},stop:function(F,E){var G=o.timers;if(F){this.queue([])}this.each(function(){for(var H=G.length-1;H>=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J<K.length;J++){if(!K[J]()){K.splice(J--,1)}}if(!K.length){clearInterval(n);n=g}},13)}},show:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.show=true;this.custom(this.prop=="width"||this.prop=="height"?1:0,this.cur());o(this.elem).show()},hide:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(H){var G=e();if(H||G>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})();
diff --git a/Database/CoolRunQuery/html/js/jquery.popupWindow.js b/Database/CoolRunQuery/html/js/jquery.popupWindow.js
new file mode 100644
index 00000000000..3e25dd5f699
--- /dev/null
+++ b/Database/CoolRunQuery/html/js/jquery.popupWindow.js
@@ -0,0 +1,62 @@
+(function($){ 		  
+	$.fn.popupWindow = function(instanceSettings){
+		
+		return this.each(function(){
+		
+		$(this).click(function(){
+		
+		$.fn.popupWindow.defaultSettings = {
+			centerBrowser:0, // center window over browser window? {1 (YES) or 0 (NO)}. overrides top and left
+			centerScreen:0, // center window over entire screen? {1 (YES) or 0 (NO)}. overrides top and left
+			height:500, // sets the height in pixels of the window.
+			left:0, // left position when the window appears.
+			location:0, // determines whether the address bar is displayed {1 (YES) or 0 (NO)}.
+			menubar:0, // determines whether the menu bar is displayed {1 (YES) or 0 (NO)}.
+			resizable:0, // whether the window can be resized {1 (YES) or 0 (NO)}. Can also be overloaded using resizable.
+			scrollbars:0, // determines whether scrollbars appear on the window {1 (YES) or 0 (NO)}.
+			status:0, // whether a status line appears at the bottom of the window {1 (YES) or 0 (NO)}.
+			width:500, // sets the width in pixels of the window.
+			windowName:null, // name of window set from the name attribute of the element that invokes the click
+			windowURL:null, // url used for the popup
+			top:0, // top position when the window appears.
+			toolbar:0 // determines whether a toolbar (includes the forward and back buttons) is displayed {1 (YES) or 0 (NO)}.
+		};
+		
+		settings = $.extend({}, $.fn.popupWindow.defaultSettings, instanceSettings || {});
+		
+		var windowFeatures =    'height=' + settings.height +
+								',width=' + settings.width +
+								',toolbar=' + settings.toolbar +
+								',scrollbars=' + settings.scrollbars +
+								',status=' + settings.status + 
+								',resizable=' + settings.resizable +
+								',location=' + settings.location +
+								',menuBar=' + settings.menubar;
+
+				settings.windowName = this.name || settings.windowName;
+				settings.windowURL = this.href || settings.windowURL;
+				var centeredY,centeredX;
+			
+				if(settings.centerBrowser){
+						
+					if ($.browser.msie) {//hacked together for IE browsers
+						centeredY = (window.screenTop - 120) + ((((document.documentElement.clientHeight + 120)/2) - (settings.height/2)));
+						centeredX = window.screenLeft + ((((document.body.offsetWidth + 20)/2) - (settings.width/2)));
+					}else{
+						centeredY = window.screenY + (((window.outerHeight/2) - (settings.height/2)));
+						centeredX = window.screenX + (((window.outerWidth/2) - (settings.width/2)));
+					}
+					window.open(settings.windowURL, settings.windowName, windowFeatures+',left=' + centeredX +',top=' + centeredY).focus();
+				}else if(settings.centerScreen){
+					centeredY = (screen.height - settings.height)/2;
+					centeredX = (screen.width - settings.width)/2;
+					window.open(settings.windowURL, settings.windowName, windowFeatures+',left=' + centeredX +',top=' + centeredY).focus();
+				}else{
+					window.open(settings.windowURL, settings.windowName, windowFeatures+',left=' + settings.left +',top=' + settings.top).focus();	
+				}
+				return false;
+			});
+			
+		});	
+	};
+})(jQuery);
diff --git a/Database/CoolRunQuery/html/js/rq.js b/Database/CoolRunQuery/html/js/rq.js
new file mode 100644
index 00000000000..462bbd5d526
--- /dev/null
+++ b/Database/CoolRunQuery/html/js/rq.js
@@ -0,0 +1,48 @@
+
+function toggle_dq(div) {
+   var hide = div.innerHTML.match(/hide/);
+   var res_table = document.getElementById('resulttable');
+   var fields = res_table.getElementsByTagName('table');
+   for (var i=0; i<fields.length; i++) {
+      if(fields[i].className != 'dqdefects') continue;
+      var lines = fields[i].getElementsByTagName('tr');
+      for (var l=0; l<lines.length; l++) {
+         var classname = lines[l].className;
+         if(classname.match(/tolerable/)) {
+            if(hide) {
+               lines[l].style.visibility="collapse";
+            } else {
+               lines[l].style.visibility="visible";
+            }
+         }
+      }      
+   }
+   div.innerHTML=hide?"[show tolerable]":"[hide tolerable]";
+}
+
+function switchUTC(span) {
+   if( span.className.match(/TZactive/) ) return;
+   span.className = "TZactive";
+   var other = document.getElementById('TZlocal');
+   other.className = "TZinactive";
+
+   for(var l=0; l<document.styleSheets.length; l++) {
+      if (document.styleSheets[l].cssRules)
+         crossrules=document.styleSheets[l].cssRules;
+      else if (document.styleSheets[l].rules)
+         crossrules=document.styleSheets[l].rules;
+      for(var r=0; r<crossrules.length; r++) {
+         if(crossrules[r].selectorText.match(/TZactive/)) {
+            //alert(crossrules[r].selectorText);
+            //crossrules[r].style.backgroundColor="green";
+         }
+      }
+   }   
+}
+
+function switchLocal(span) {
+   if( span.className.match(/TZactive/) ) return;
+   span.className = "TZactive";
+   var other = document.getElementById('TZutc');
+   other.className = "TZinactive";
+}
diff --git a/Database/CoolRunQuery/html/js/rq_examples.js b/Database/CoolRunQuery/html/js/rq_examples.js
new file mode 100644
index 00000000000..80b2fff1a01
--- /dev/null
+++ b/Database/CoolRunQuery/html/js/rq_examples.js
@@ -0,0 +1,500 @@
+
+
+function insertExamples() {
+    var x = document.getElementById("exampleRunEvt");
+    if(x==null) return;
+    insertExamplesRunEvt();
+    insertExamplesTime();
+    insertExamplesDetectors();
+    insertExamplesStreams();
+    insertExamplesMagnets();
+    insertExamplesDQ();
+    insertExamplesTrigger();
+    insertExamplesPartition();
+    insertExamplesDatasets();
+    insertExamplesBeamSpot();
+    insertExamplesLAr();
+    insertExamplesLumi();
+    insertExamplesLHC();
+    insertExamplesOther();
+}
+
+var newtext = 'blank';
+function addColumn(newtext) {
+  frm = document.forms["RunQueryInput"].q;
+  frm.value = newtext;
+}
+
+
+function insertExamplesRunEvt() {
+   var x = document.getElementById("exampleRunEvt");
+   x.innerHTML = '\
+<div class="Pad">\
+  <table class="exampletable">\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;find run 90270-90350 and events 100000+ / show run and events&quot;);return false">find run 90270-90350 and events 100000+ / show run and events</td>\
+        <td class="cmt"><font color="red">Select</font> runs in given <font color="red">run number range</font> and min. <font color="red">number of events</font>, <br/> and <font color="red">show</font> runs and number of events for selected runs.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 90270-90350 and ev 100k+ / sh r and ev&quot;);return false">f r 90270-90350 and ev 100k+ / sh r and ev</td>\
+        <td class="cmt">Allowed <font color="red">abbreviations</font> &minus; same query as above; <br/> note that the <i>show</i> part could be dropped since same as default.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 90270+ and ev 100k- &quot;);return false">f r 90270+ and ev 100k- </td>\
+        <td class="cmt">Select all runs with run number >= 90270 and &lt; 100k events.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 90270,90275,90380+ and ev 100k-200k&quot;);return false">f r 90270,90275,90380 and ev 100k-200k</td>\
+        <td class="cmt">Select any of the given run numbers if number of events in given range.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r last 10 / show all / nodef &quot;);return false">f r last 10 / show all / nodef </td>\
+        <td class="cmt">Select <font color="red">last 10 runs</font>; same in short: <font color="red">f r l 10 / sh all / nodef</font>.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r data10_7TeV.periodC / sh ready&quot;);return false">f r data10_7TeV.periodC / sh ready </td>\
+        <td class="cmt">Select runs belonging to a given <font color="red">run period</font><br>(giving only "periodC" would use "data11_7TeV" as default)</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 2010.C / sh ready&quot;);return false">f r 2010.C / sh ready </td>\
+        <td class="cmt">Select runs belonging to a given <font color="red">run period</font><br>(giving only "C" would use "2011" as default)</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r periodA-periodC,periodD / sh ready&quot;);return false">f r periodA-periodC,periodD / sh ready </td>\
+        <td class="cmt">Select runs belonging to the given <font color="red">range of run periods</font> (only main letters a considered, so periodA-periodD, means use periods A,B,C,D, but not C1, C2, ...)</td>\
+      </tr>\
+  </table>\
+</div>';
+}
+
+
+function insertExamplesTime() {
+   var x = document.getElementById("exampleTime");
+   x.innerHTML = '\
+<div class="Pad">\
+  <table class="exampletable">\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;find time last 24h / sh r and ev and t / utc&quot;);return false">find time last 24h / sh r and ev and t / utc</td>\
+        <td class="cmt">Select runs that <font color="red">ended within the last 24h</font>; format examples: 5d, 1d = 24h, 5h, ... <br> extra option <font color="red">utc</font>, default is CEST (CERN local time)</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f t 10.9.2008-13.9.2008 / sh r and ev and t&quot;);return false">f t 10.9.2008-13.9.2008 / sh r and ev and t</td>\
+        <td class="cmt">Select runs with start/end dates within given <font color="red">time period</font>; format: DD.MM.YYYY.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f t 13.9.2008+ / sh t&quot;);return false">f t 13.9.2008+ / sh t</td>\
+        <td class="cmt">Select all runs including and <u>after</u> Sep 13, 2008.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f t 13.9.2008- / sh t&quot;);return false">f t 13.9.2008- / sh t</td>\
+        <td class="cmt">Select all runs including and <u>before</u> Sep 13, 2008.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 89465-93000 and duration 2m+ / sh t and dur &quot;);return false">f r 89465-93000 and duration 2m+ / sh t and dur </td>\
+        <td class="cmt">Select runs that had a <font color="red">duration</font> of at least two minutes; <br/>\
+          replace "m" by "h" and "s" for hours and seconds, respectively;<br>note: only integer numbers allowed! </td>\
+      </tr>\
+  </table>\
+</div>';
+}
+
+
+function insertExamplesDetectors() {
+   var x = document.getElementById("exampleDetectors");
+   x.innerHTML = '\
+<div class="Pad">\
+  <table class="exampletable">\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 90270-90350 and det pix / sh r and ev and det&quot;);return false">f r 90270-90350 and det pix / sh r and ev and det</td>\
+        <td class="cmt">Select runs with all Pixel in and show all <font color="red">participating detectors</font>.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 90100-90150 and det any sct / sh r and ev and det&quot;);return false">f r 90100-90150 and det any sct / sh r and ev and det</td>\
+        <td class="cmt">Select runs with at least one SCT in and show all participating detectors.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 90270-90350 and det all / sh r and ev and det&quot;);return false">f r 90270-90350 and det all / sh r and ev and det</td>\
+        <td class="cmt">Select runs with all detectors in; here <i>all</i> means the systems used during the 2008 combined data taking period, ie, not including for example CSC.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;<b><i>Decode detector mask:</i></b> &quot;);return false"><b><i>Decode detector mask:</a></i></b> </td>\
+        <td class="cmt"></td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;detmask 562937068519415&quot;);return false">detmask 562937068519415</td>\
+        <td class="cmt">Interpret <font color="red">detector mask</font>.</td>\
+      </tr>\
+  </table>\
+</div>';
+}
+
+
+function insertExamplesStreams() {
+   var x = document.getElementById("exampleStreams");
+   x.innerHTML = '\
+<div class="Pad">\
+  <table class="exampletable">\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 90270-90350 / sh r and ev and st&quot;);return false">f r 90270-90350 / sh r and ev and st</td>\
+        <td class="cmt">Show <font color="red">all produced streams and events per stream</font> for selected runs.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;</td><td class="&quot;);return false"></td><td class="cmt">\
+          By placing the <font color="red">mouse over</font> the number of events of a stream one can display the <font color="red">stream overlaps</font> &minus; computed relative to the number of events in that stream. </td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 90270-90350 and st *IDCos* 10k+ and st *RPC* / sh st phy*,cal*&quot;);return false">f r 90270-90350 and st *IDCos* 10k+ and st *RPC* / sh st phy*,cal*</td>\
+        <td class="cmt">Select runs where physics_IDCosmic stream has more than 10000 events and the RPC* stream is enabled, shows all physics and calibration streams. </td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 90749-90785 and st *RPC* and st !physics_L1CaloEM / sh st phy*&quot;);return false">f r 90749-90785 and st *RPC* and st !physics_L1CaloEM / sh st phy*</td>\
+        <td class="cmt">Select runs where a RPC stream but <font color="red">no physics_L1CaloEM </font> stream is written.</td>\
+  </table>\
+</div>';
+}
+
+
+
+function insertExamplesMagnets() {
+   var x = document.getElementById("exampleMagnets");
+   x.innerHTML = '\
+<div class="Pad">\
+  <table class="exampletable">\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 90270-90350 and mag s and not mag t / sh r and ev and mag&quot;);return false">f r 90270-90350 and mag s and not mag t / sh r and ev and mag</td>\
+        <td class="cmt">Select runs with <font color="red">solenoid on and toroid off</font>.</td>\
+      </tr>\
+  </table>\
+</div>';
+}
+
+
+
+
+
+function insertExamplesDQ() {
+   var x = document.getElementById("exampleDQ");
+   x.innerHTML = '\
+<div class="Pad">\
+  <table class="exampletable">\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 2012.B6 / sh dqsum&quot;);return false">f r 2012.B6 / sh dqsum</td>\
+        <td class="cmt">Show <font color="red">data quality</font> summary: defects, plots and luminosity losses per system (restricted to LBs with ATLAS READY).</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 2011.C / sh dq&quot;);return false">f r 2011.C / sh dq</td>\
+        <td class="cmt">Show <font color="red">data quality</font> defects (restricted to LBs with ATLAS READY).</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r B / sh dq #DetStatus-v08-pro07&quot;);return false">f r B / sh dq #DetStatus-v08-pro07</td>\
+        <td class="cmt">Show <font color="red">data quality </font> defects with COOL tag DetStatus-v08-pro07.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r A / sh r and dq det&quot;);return false">f r A / sh dq det</td>\
+        <td class="cmt">Show <font color="red">detector defects</font> in period A of current year.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 2010.G1 / sh dq TRIG_&quot;);return false">f r 2010.G1 / sh dq TRIG_</td>\
+        <td class="cmt">Show defects <font color="red">matching pattern</font>. Use &quot;pattern$&quot; for exact match of pattern</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r B1 and dq !CP_TAU #DetStatus-v08-pro07&quot;);return false">f r B1 and dq !CP_TAU #DetStatus-v08-pro07</td>\
+        <td class="cmt">Select all lumiblocks in B1 that have <font color="red">no CP_TAU defect</font>. The specified defect has to match exactly, no wild cards.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 90270-90350 / sh r and dq pix,sct DQMFOFL&quot;);return false">f r 90270-90350 / sh r and dq pix,sct DQMFOFL</td>\
+        <td class="cmt">Same as above for <font color="red">"DQMFOFL" folder</font>; \
+          choices are: "SHIFTOFL", "SHIFTONL", "DQCALCOFL", "DQMFOFL", "DQMFONL", "DQMFONLLB", "DCSOFL", "TISUMM", "LBSUMM" [default: "SHIFTOFL"].</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 135195 / sh r and dq DQMFOFL#DetStatusDQMFOFL-express-pass1&quot;);return false">f r 135195 / sh r and dq DQMFOFL#DetStatusDQMFOFL-express-pass1</td>\
+        <td class="cmt">Specification of a <font color="red">DB tag</font>\
+          [default: "HEAD"].</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 90270-90350 and dq em y+ and dq pixb y+ / sh dq pix,sct,em,til&quot;);return false">f r 90270-90350 and dq em y+ and dq pixb y+ / sh dq pix,sct,em,til</td>\
+        <td class="cmt">Select runs where LAr-EM and Tile DQ flags are at least "Y" and Pixel-B is "G". </td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 90270-91350 and dq lar g / sh dq lar&quot;);return false">f r 90270-91350 and dq lar g / sh dq lar</td>\
+        <td class="cmt">Select runs where all LAr-EM are "green". </td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 90270-91350 and dq any lar g / sh dq lar&quot;);return false">f r 90270-91350 and dq any lar g / sh dq lar</td>\
+        <td class="cmt">Select runs where at least one LAr-EM are "green". </td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 90270-90350 and dq any pix n.a. / sh dq pix&quot;);return false">f r 90270-90350 and dq any pix n.a. / sh dq pix</td>\
+        <td class="cmt">Select runs where at least one Pix qualitity flag is unset. </td>\
+      </tr>\
+  </table>\
+</div>\
+';
+}
+
+
+function insertExamplesProject() {
+   var x = document.getElementById("exampleProject");
+   x.innerHTML = '\
+<div class="Pad">\
+  <table class="exampletable">\
+  </table>\
+</div>\
+';
+}
+
+function insertExamplesTrigger() {
+   var x = document.getElementById("exampleTrigger");
+   x.innerHTML = '\
+<div class="Pad">\
+  <table class="exampletable">\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 90270-90350 and ev 100k+ / sh allev&quot;);return false">f r 90270-90350 and ev 100k+ / sh allev</td>\
+        <td class="cmt">Show <font color="red">all event numbers, i.e., at EF, L2, L1 and SFO (inclusive)</font> levels.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r last 10 / sh trigkeys and rel&quot;);return false">f r last 10 / sh trigkeys and rel</td>\
+        <td class="cmt">Show <font color="red">all trigger keys and HLT release</font> for selected runs.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r last 10 / sh trigrates L1_MBTS_*&quot;);return false">f r last 10 / sh trigrates L1_MBTS_*</td>\
+        <td class="cmt">Show <font color="red">trigger rates</font> (max 50). Currently only Level 1.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 91890-92070 and smk 368,373 / sh trigkeys&quot;);return false">f r 91890-92070 and smk 368,373 / sh trigkeys</td>\
+        <td class="cmt">Select runs with <font color="red">trigger "super-master" key 368 or 373</font>, show keys and <font color="red">release</font>.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 91890-92070 / sh tr L2_E*,L2_Cosmic* &quot;);return false">f r 91890-92070 / sh tr L2_E*,L2_Cosmic* </td>\
+        <td class="cmt">Show <font color="red">show triggers matching patterns L2_E* or L2_Cosmic*</font> [not case sensitive].</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 91890-92070 and tr EF_e5* &quot;);return false">f r 91890-92070 and tr EF_e5* </td>\
+        <td class="cmt">Show <font color="red">runs with triggers matching pattern EF_e5*</font> [not case sensitive].</td>\
+      </tr>\
+  </table>\
+</div>\
+';
+}
+
+
+function insertExamplesPartition() {
+   var x = document.getElementById("examplePartition");
+   x.innerHTML = '\
+<div class="Pad">\
+  <table class="exampletable">\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f t 10.9.2008-13.9.2008 and part ATLAS / sh t and part&quot;);return false">f t 10.9.2008-13.9.2008 and part ATLAS / sh t and part</td>\
+        <td class="cmt">Select runs with <font color="red">DAQ partition</font> "ATLAS".</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r l 10 / sh ready&quot;);return false">f r l 10 / sh ready</td>\
+        <td class="cmt">Show (or similar: select) <font color="red">ReadyForPhysics flag</font> for runs.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f t 10.9.2008-13.9.2008 and ptag data08_1beam* / sh t and ptag&quot;);return false">f t 10.9.2008-13.9.2008 and ptag data08_1beam* / sh t and ptag</td>\
+        <td class="cmt">Select runs with single-beam <font color="red">project tag</font> (note that the project tag is denoted "filenameTag" in COOL).</td>\
+      </tr>\
+      <tr>\
+        <td colspan="2">\
+        <font size="-1">\
+        <table style="border-collapse: collapse;">\
+          <tr style="background-color: #a5a2a2;"><td style="padding: 0px; width: 120px;"><b>Project Tag</b></td><td style="padding: 0px;"><b>Definition</b></td></tr>\
+          <tr><td style="padding: 0px;">dataYY_900GeV</td><td style="padding: 0px;">900 GeV collisions taken during the year 20YY</td></tr>\
+          <tr><td style="padding: 0px;">dataYY_2TeV</td><td style="padding: 0px;">Collisions at 2.X TeV</td></tr>\
+          <tr><td style="padding: 0px;">dataYY_7TeV</td><td style="padding: 0px;">Collisions at 7.X TeV</td></tr>\
+          <tr><td style="padding: 0px;">dataYY_1beam</td><td style="padding: 0px;">Combined data taking with single beam (or 2 non-colliding beams)</td></tr>\
+          <tr><td style="padding: 0px;">dataYY_cos</td><td style="padding: 0px;">Combined cosmic data taking</td></tr>\
+        </table>\
+        </font>\
+        </td>\
+      </tr>\
+  </table>\
+</div>\
+';
+}
+
+function insertExamplesDatasets() {
+   var x = document.getElementById("exampleDatasets");
+   x.innerHTML = '\
+<div class="Pad">\
+  <table class="exampletable">\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f run last 10 / sh time and datasets&quot;);return false">f run last 10 / sh time and datasets</td>\
+        <td class="cmt">Select last 10 runs and show <font color="red">all datasets produced in Tier-0.</font></td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r l 10 / sh t and da&quot;);return false">f r l 10 / sh t and da</td>\
+        <td class="cmt">As above <font color="red">in short.</font></td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r l 10 / sh t and da caf&quot;);return false">f r l 10 / sh t and da caf</td>\
+        <td class="cmt">Also checks if files are <font color="red">available on CAF pool (ATLCAL)</font> (slow query). <br>Note: <b>recent replications (< 24h) may not be included.</b></td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r l 10 / sh t and da *ntup*,*TAG*&quot;);return false">f r l 10 / sh t and da *ntup*,*TAG*</td>\
+        <td class="cmt">As above but selecting <font color="red">dataset name patterns</font> - selection is case insensitive.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r l 10 / sh t and da *ntup*,*TAG* caf&quot;);return false">f r l 10 / sh t and da *ntup*,*TAG* caf</td>\
+        <td class="cmt">As above but including CAF pool availability information.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f run last 10 / sh time and str&quot;);return false">f run last 10 / sh time and str</td>\
+        <td class="cmt">Select last 10 runs and show streams: move mouse over stream info to obtain information on the <font color="red">data types produced in the reconstruction and merging steps of the Tier-0, and their CAF replication status</font>.</td>\
+      </tr>\
+  </table>\
+</div>\
+';
+}
+
+function insertExamplesBeamSpot() {
+   var x = document.getElementById("exampleBeamSpot");
+   x.innerHTML = '\
+<div class="Pad">\
+  <table class="exampletable">\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;find run last 10 / show bs &quot;);return false">find run last 10 / show bs </td>\
+        <td class="cmt">Show <font color="red">offline beam spot parameters</font> for selected runs.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;find run last 10 / show bs &lt;COOL-tag&gt;&quot;);return false">find run last 10 / show bs &lt;COOL-tag&gt;</td>\
+        <td class="cmt">Same as above but assign which <font color="red">COOL tag</font> to use;<br>default tag: "IndetBeampos-ES1-UPD2".</td>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;find run last 10 / show bs online&quot;);return false">find run last 10 / show bs online </td>\
+        <td class="cmt">Show <font color="red">online beam spot parameters</font> for selected runs.</td>\
+      </tr>\
+      </tr>\
+  </table>\
+</div>\
+';
+}
+
+
+function insertExamplesLAr() {
+   var x = document.getElementById("exampleLAr");
+   x.innerHTML = '\
+<div class="Pad">\
+  <table class="exampletable">\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;find run last 10 / show larcond &quot;);return false">find run last 10 / show larcond </td>\
+        <td class="cmt">Show <font color="red">LAr conditions</font> for selected runs.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r l 10 and larc nsamples 7 and larc runtype 1 / sh larc &quot;);return false">f r l 10 and larc nsamples 7 and larc runtype 1 / sh larc </td>\
+        <td class="cmt">As above, in short, and selecting on <font color="red">number of samples and run tupe</font>.</td>\
+      </tr>\
+  </table>\
+</div>\
+';
+}
+
+function insertExamplesLumi() {
+   var x = document.getElementById("exampleLumi");
+   x.innerHTML = '\
+<div class="Pad">\
+  <table class="exampletable">\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;find run 152166 / show lhc &quot;);return false">find run 152166 / show lhc </td>\
+        <td class="cmt">Show LHC information and <font color="red">online luminosity</font> for selected runs.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;find run 152166-152508 and lumi 20ub+ / show lhc &quot;);return false">find run 152166-152508 and lumi 20ub+ / show lhc </td>\
+        <td class="cmt">Find runs within given range with <font color="red">integrated luminosity (online) larger than 20 inverse microbarns</font> (the &quot;+&quot; (&quot;&minus;&quot;) sign indicates &quot;more than&quot; (&quot;less than&quot;)).<br>Allowed units are: b, mb, ub, nb, pb, fb.<br>Note that only luminosity with <b>stable beams</b> is considered (hence: the requirement explicitly selects runs with stable beams).</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;find run 142193 / show lumi &quot;);return false">find run 142193 / show lumi </td>\
+        <td class="cmt">Show <font color="red">offline luminosity</font> for selected runs.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;find run 142193 / show lumi 0 OflLumi-Dec2009-001&quot;);return false">find run 142193 / show lumi 0 OflLumi-Dec2009-001</td>\
+        <td class="cmt">Show offline luminosity for <font color="red">channel 0 and COOL tag OflLumi-Dec2009-001</font>;<br> default channel and tag: 0, OflLumi-Dec2009-001</td>\
+      </tr>\
+  </table>\
+</div>\
+';
+}
+
+function insertExamplesLHC() {
+   var x = document.getElementById("exampleLHC");
+   x.innerHTML = '\
+<div class="Pad">\
+  <table class="exampletable">\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;find run last 10 / show lhc &quot;);return false">find run last 10 / show lhc </td>\
+        <td class="cmt">Show <font color="red">LHC information (stable beams, beam energy and intensities, online luminosity)</font> for selected runs.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;find run last 10 / show lhc all &quot;);return false">find run last 10 / show lhc all</td>\
+        <td class="cmt">Show also: <font color="red">beam mode and buch pattern (BCID mask)</font>.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;find run last 20 and lhc stablebeams true / show lhc&quot;);return false">find run last 20 and lhc stablebeams true / show lhc</td>\
+        <td class="cmt">Select runs with <font color="red">at least one LB with stable-beams</font> (can replace "true" by "t").</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r l 10 and lhc beamenergy 3400+ / sh t and lhc&quot;);return false">f r l 10 and lhc beamenergy 3400+ / sh lhc</td>\
+        <td class="cmt">As above, in short, and selecting on <font color="red">the beam energy</font>.<br>Numbers can be replaced by ranges, eg: 3400+, 3700-, 3400-3700.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r 152772-152876 and lhc fillnumber 1031-1033 / sh lhc&quot;);return false">f r 152772-152876 and lhc fillnumber 1031-1033 / sh lhc</td>\
+        <td class="cmt">Select runs according to <font color="red">LHC fill number</font>.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;find run last 10 / show bpm &quot;);return false">find run last 10 / show bpm </td>\
+        <td class="cmt">Show <font color="red">beam positions measured by Beam Position Monitors (BPM)</font> for selected runs (the closest BPMs are located +-21m from the ATLAS IP).</td>\
+      </tr>\
+  </table>\
+</div>\
+';
+}
+
+function insertExamplesOther() {
+   var x = document.getElementById("exampleOther");
+   x.innerHTML = '\
+<div class="Pad">\
+  <table class="exampletable">\
+      <tr>\
+        <td><b><i>Summary pages:</i></b></td>\
+        <td></td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r A-B / show summary &quot;);return false">f r A-B / show summary </td>\
+        <td class="cmt">Provide <font color="red">summary tables and plots</font> for selected runs.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r A-B / show dqsummary &quot;);return false">f r A-B / show dqsummary </td>\
+        <td class="cmt">Provide <font color="red">summary data quality tables</font> for selected runs.</td>\
+      </tr>\
+      <tr>\
+        <td><b><i>Extra options</i></b> (3rd parameter):</td>\
+        <td></td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r G / show r and ev / nodef &quot;);return false">f r F / show r and ev / nodef </td>\
+        <td class="cmt">Select runs with <font color="red">without default conditions</font>.</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r G / show r and ev / grl grl.xml:runlist &quot;);return false">f r G / show r and ev / grl grl.xml:runlist </td>\
+        <td class="cmt">Produce <font color="red">GRL</font> with optionally give file and runlist name (they defaults to \'MyLBCollection.xml:MyLBCollection\').</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;f r G / show r and ev / root &quot;);return false">f r G / show r and ev / root </td>\
+        <td class="cmt">Produce root files and overview histograms.</td>\
+      </tr>\
+        <td><b><i>Pileup:</i></b></td>\
+        <td></td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;pileup 1.5e28 55 2 100000&quot;);return false">pileup 1.5e28 55 2 100000</td>\
+        <td class="cmt">Compute <font color="red">pileup expectation</font>. The arguments are (in this order): <b>instantaneous luminosity</b>, <b>cross section</b> (unit: mb), <b>number of colliding bunches</b>, [<b>total number of triggered events in sample</b> (optional), default: 1]</td>\
+      </tr>\
+      <tr>\
+        <td class="pgm" onClick="addColumn(&quot;pileup 1e10 17 55 2 1&quot;);return false">pileup 1e10 17 55 2 1</td>\
+        <td class="cmt">Compute <font color="red">pileup expectation</font>. The arguments are (in this order): <b>beam intensity</b> (number of protons), <b>transverse beam size</b> (microns), <b>cross section</b> (mb), <b>number of colliding bunches</b>, [<b>total number of triggered events in sample</b> (optional), default: 1]</td>\
+      </tr>\
+      <tr>\
+  </table>\
+</div>\
+';
+}
diff --git a/Database/CoolRunQuery/html/js/rq_simplepopups.js b/Database/CoolRunQuery/html/js/rq_simplepopups.js
new file mode 100644
index 00000000000..ba8c2cd156e
--- /dev/null
+++ b/Database/CoolRunQuery/html/js/rq_simplepopups.js
@@ -0,0 +1,75 @@
+function helppopup() {
+   helpwin = window.open("atlas-runquery-help.html", "Help for Run Query","location=no,width=950,height=700,scrollbars=yes");
+}
+
+function openWindow(name,text) { 
+   win = window.open("", name, "location=0,left=50,width=720,height=550,scrollbars=1");
+   win.locationbar.visible = false;
+   win.focus();
+   win.document.open();
+   win.document.writeln( text );
+   win.document.close();
+}
+
+function openTextWindow(name,text) { 
+   textwin = window.open("", name, "location=0,width=720,height=750,scrollbars=1");
+   textwin.locationbar.visible = false;
+   textwin.focus();
+   textwin.document.open();
+   textwin.document.writeln( text );
+   textwin.document.close();
+}
+
+function openLumiWindow(name,text) { 
+   lumiwin = window.open("", name, "location=0,width=950,height=310,scrollbars=1,status=0,toolbar=0");
+   lumiwin.locationbar.visible = false;
+   lumiwin.focus();
+   lumiwin.document.open();
+   lumiwin.document.writeln( text );
+   lumiwin.document.close();
+}
+
+function openNemoWindow(name,text) { 
+   lumiwin = window.open("", name, "location=0,width=850,height=710,scrollbars=1,status=0,toolbar=0");
+   lumiwin.locationbar.visible = false;
+   lumiwin.focus();
+   lumiwin.document.open();
+   lumiwin.document.writeln( text );
+   lumiwin.document.close();
+}
+
+function openLargeWindow(name,text) { 
+   largewin = window.open("", name, "location=0,width=830,height=600,scrollbars=1");
+   largewin.locationbar.visible = false;
+   largewin.focus();
+   largewin.document.open();
+   largewin.document.writeln( text );
+   largewin.document.close();
+}
+
+function openPageWindow(link,name) { 
+   pagewin = window.open(link, name, "location=0,width=900,height=650,scrollbars=1"); 
+}
+
+
+function relpopup() {
+   relwin = window.open("atlas-runquery-relnotes.html", "Change logs","location=no,width=645,height=500,scrollbars=yes");
+}
+
+function ShowMessage() {
+   if ((waitDiv=document.getElementById("wait"))!=null) { 
+      if (waitDiv.style){
+         document.getElementById('wait').style.visibility = 'visible'
+            }
+   }
+}
+
+var win=null;
+function NewWindow(mypage,myname,w,h,scroll,pos){
+   if(pos=="random"){LeftPosition=(screen.width)?Math.floor(Math.random()*(screen.width-w)):100;TopPosition=(screen.height)?Math.floor(Math.random()*((screen.height-h)-75)):100;}
+   if(pos=="center"){LeftPosition=(screen.width)?(screen.width-w)/2:100;TopPosition=(screen.height)?(screen.height-h)/2:100;}
+   else if((pos!="center" && pos!="random") || pos==null){LeftPosition=0;TopPosition=20}
+   settings='width='+w+',height='+h+',top='+TopPosition+',left='+LeftPosition+',scrollbars='+scroll+',locationbar=no,directories=no,status=no,menubar=no,toolbar=no,resizable=no';
+   win=window.open(mypage,myname,settings);
+}
+
diff --git a/Database/CoolRunQuery/html/js/switcher.js b/Database/CoolRunQuery/html/js/switcher.js
new file mode 100644
index 00000000000..c027fb5343f
--- /dev/null
+++ b/Database/CoolRunQuery/html/js/switcher.js
@@ -0,0 +1,97 @@
+
+function switcher() {
+   this.runs={};
+   this.headers=[];
+   this.imagesrc=['images/plus.gif','images/minus.gif'];
+}
+
+switcher.prototype.init=function() {
+   var instanceOf=this;
+   this.collectElementbyClass("run")
+   for (var i=0; i<this.headers.length; i++) {
+      var header = this.headers[i]
+      var id = header.id;
+      this.runs[id]=new switchlb(header);
+      this.runs[id].imagesrc=this.imagesrc;
+      this.runs[id].init();
+   }
+   //document.getElementById("expand-all").onclick=function(){instanceOf.toggleAll("doopen")};
+   //document.getElementById("collapse-all").onclick=function(){instanceOf.toggleAll("doclose")};
+   //alert("Test");
+};
+
+switcher.prototype.collectElementbyClass=function(classname) {
+   var classnameRE=new RegExp("(^|\\s+)"+classname+"($|\\s+)", "i");
+   var allelements = document.getElementsByTagName("tr");
+   for (var i=0; i<allelements.length; i++) {
+      var lineEl = allelements[i];
+      //if (lineEl.id!="" && typeof lineEl.className=="string" && lineEl.className.search(classnameRE)!=-1)
+      if (lineEl.id!="" && typeof lineEl.className=="string" && lineEl.className.match("^"+classname))
+         this.headers.push(lineEl);
+   }
+};
+
+switcher.prototype.toggleAll=function(action) {
+   for (var i=0; i<this.headers.length; i++) {
+      var id = this.headers[i].id
+      this.runs[id].toggle(action);
+   }
+}
+   
+function switchlb(header) {
+   this.header = header;
+   this.pmelem = this.header.getElementsByTagName("td")[0];
+   this.status = "open";
+   this.imagesrc=['plus.gif','minus.gif'];
+};
+
+switchlb.prototype.init=function() {
+   var instanceOf=this;
+   this.toggle("doclose")
+   this.pmelem.onclick=function(){instanceOf.toggle()}
+};
+
+switchlb.prototype.toggle=function(action){
+   this.collectLbByClassName(this.header.id);
+   if(action==undefined) {
+      if (this.status=="open") {
+         this.contractcontent();
+      } else {
+         this.expandcontent();
+      }
+   } else if(action=="doclose") {
+      this.contractcontent();
+   } else if(action=="doopen") {
+      this.expandcontent();
+   }
+};
+
+switchlb.prototype.contractcontent=function(){
+   for(var i=0; i<this.lbs.length; i++) {
+      var innercontent=this.lbs[i];
+      innercontent.style.visibility="collapse";
+   }
+   this.pmelem.innerHTML='<img src="'+this.imagesrc[0]+'"/>'
+   this.status="closed";
+};
+
+switchlb.prototype.expandcontent=function(){
+   for(var i=0; i<this.lbs.length; i++) {
+      var innercontent=this.lbs[i];
+      innercontent.style.visibility="visible";
+   }
+   this.pmelem.innerHTML='<img src="'+this.imagesrc[1]+'"/>'
+   this.status="open";
+};
+
+switchlb.prototype.collectLbByClassName=function(classname) {
+   var classnameRE=new RegExp("(^|\\s+)"+classname+"($|\\s+)", "i") //regular expression to screen for classname within element
+   var allLb = document.getElementsByTagName("tr")
+   this.lbs=[]
+   for (var i=0; i<allLb.length; i++) {
+      var lineEl = allLb[i]
+      if (typeof lineEl.className=="string" && lineEl.className.match("^lb-"+classname+"-")) {
+         this.lbs.push(lineEl);
+      }
+   }
+}
diff --git a/Database/CoolRunQuery/html/js/tabView.js b/Database/CoolRunQuery/html/js/tabView.js
new file mode 100644
index 00000000000..4d45fdc7ce1
--- /dev/null
+++ b/Database/CoolRunQuery/html/js/tabView.js
@@ -0,0 +1,84 @@
+/* Copyright (C) 2005 Ilya S. Lyubinskiy. All rights reserved.
+Technical support: http://www.php-development.ru/
+
+YOU MAY NOT
+(1) Remove or modify this copyright notice.
+(2) Distribute this code, any part or any modified version of it.
+    Instead, you can link to the homepage of this code:
+    http://www.php-development.ru/javascripts/tabview.php.
+
+YOU MAY
+(1) Use this code on your website.
+(2) Use this code as a part of another product.
+
+NO WARRANTY
+This code is provided "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. You expressly
+acknowledge and agree that use of this code is at your own risk.
+
+
+If you find my script useful, you can support my site in the following ways:
+1. Vote for the script at HotScripts.com (you can do it on my site)
+2. Link to the homepage of this script or to the homepage of my site:
+   http://www.php-development.ru/javascripts/tabview.php
+   http://www.php-development.ru/
+   You will get 50% commission on all orders made by your referrals.
+   More information can be found here:
+   http://www.php-development.ru/affiliates.php
+*/
+
+// ----- Auxiliary -------------------------------------------------------------
+
+function tabview_aux(TabViewId, id)
+{
+  var TabView = document.getElementById(TabViewId);
+
+  if(TabView==null) return;
+
+  // ----- Tabs -----
+
+  var Tabs = TabView.firstChild;
+  while (Tabs.className != "Tabs" ) Tabs = Tabs.nextSibling;
+
+  var Tab = Tabs.firstChild;
+  var i   = 0;
+
+  do
+  {
+    if (Tab.tagName == "A")
+    {
+      i++;
+      Tab.href      = "javascript:tabview_switch('"+TabViewId+"', "+i+");";
+      Tab.className = (i == id) ? "Active" : "";
+      Tab.blur();
+    }
+  }
+  while (Tab = Tab.nextSibling);
+
+  // ----- Pages -----
+
+  var Pages = TabView.firstChild;
+  while (Pages.className != 'Pages') Pages = Pages.nextSibling;
+
+  var Page = Pages.firstChild;
+  var i    = 0;
+
+  do
+  {
+    if (Page.className == 'Page')
+    {
+      i++;
+      if (Pages.offsetHeight) Page.style.height = (Pages.offsetHeight-2)+"px";
+      Page.style.overflow = "auto";
+      Page.style.display  = (i == id) ? 'block' : 'none';
+    }
+  }
+  while (Page = Page.nextSibling);
+}
+
+// ----- Functions -------------------------------------------------------------
+
+function tabview_switch(TabViewId, id) { tabview_aux(TabViewId, id); }
+
+function tabview_initialize(TabViewId) { tabview_aux(TabViewId,  1); }
diff --git a/Database/CoolRunQuery/macros/AtlRunQueryGraphs.C b/Database/CoolRunQuery/macros/AtlRunQueryGraphs.C
new file mode 100644
index 00000000000..2298acdeb10
--- /dev/null
+++ b/Database/CoolRunQuery/macros/AtlRunQueryGraphs.C
@@ -0,0 +1,4 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
diff --git a/Database/CoolRunQuery/macros/colours.C b/Database/CoolRunQuery/macros/colours.C
new file mode 100644
index 00000000000..ddc496c5dfa
--- /dev/null
+++ b/Database/CoolRunQuery/macros/colours.C
@@ -0,0 +1,68 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// --- user-defined colors
+#include "TROOT.h"
+#include "TColor.h"
+
+#ifndef COLOURS__
+#define COLOURS__
+
+static Int_t c_HiggsGreen    = TColor::GetColor( "#cfff47" );
+static Int_t c_HiggsBlue     = TColor::GetColor( "#A2DAFF" );
+static Int_t c_White         = TColor::GetColor( "#ffffff" );
+static Int_t c_LightYellow   = TColor::GetColor( "#ffff00" );
+static Int_t c_VLightYellow  = TColor::GetColor( "#ffffe0" );
+static Int_t c_DarkYellow    = TColor::GetColor( "#ffd700" );
+static Int_t c_VDarkYellow   = TColor::GetColor( "#ffa500" );
+static Int_t c_LightOrange   = TColor::GetColor( "#ffcc00" );
+static Int_t c_VVLightOrange = TColor::GetColor( "#ffee66" );
+static Int_t c_VLightOrange  = TColor::GetColor( "#ffdd44" );
+static Int_t c_DarkOrange    = TColor::GetColor( "#ff6600" );
+static Int_t c_VDarkOrange   = TColor::GetColor( "#aa4400" );
+static Int_t c_LightGreen    = TColor::GetColor( "#aaff33" );
+static Int_t c_VVLightGreen  = TColor::GetColor( "#cdff88" );
+static Int_t c_VLightGreen   = TColor::GetColor( "#bdff66" );
+static Int_t c_DarkGreen     = TColor::GetColor( "#116600" );
+static Int_t c_VDarkGreen    = TColor::GetColor( "#114400" );
+static Int_t c_NiceGreen     = TColor::GetColor( "#4CC417" );
+static Int_t c_LightBlue     = TColor::GetColor( "#66aaff" );
+static Int_t c_VVLightBlue   = TColor::GetColor( "#aaddff" );
+static Int_t c_VLightBlue    = TColor::GetColor( "#99bbff" );
+static Int_t c_Blue          = TColor::GetColor( "#0000ff" );
+static Int_t c_DarkBlue      = TColor::GetColor( "#0000bb" );
+static Int_t c_LightRed      = TColor::GetColor( "#ff3333" );
+static Int_t c_DarkRed       = TColor::GetColor( "#aa0000" );
+static Int_t c_NovelRed      = TColor::GetColor( "#dd0033" );
+
+static Int_t c_SteelBlue1    = TColor::GetColor( "#ededff" );
+static Int_t c_SteelBlue2    = TColor::GetColor( "#ddffdd" );
+static Int_t c_Violet        = TColor::GetColor( "#aa11aa" );
+
+static Int_t c_BlueT1        = TColor::GetColor( "#2255cc" );
+static Int_t c_BlueT2        = TColor::GetColor( "#4488dd" );
+static Int_t c_BlueT3        = TColor::GetColor( "#99bbff" );
+static Int_t c_BlueT4        = TColor::GetColor( "#99bbff" );
+static Int_t c_BlueT5        = TColor::GetColor( "#aaddff" );
+static Int_t c_NovelBlue     = TColor::GetColor( "#2244a5" );
+
+static Int_t c_DarkBlueT1    = TColor::GetColor( "#0000aa" );
+static Int_t c_DarkBlueT2    = TColor::GetColor( "#1122bb" );
+static Int_t c_DarkBlueT3    = TColor::GetColor( "#2233ee" );
+static Int_t c_DarkBlueT4    = TColor::GetColor( "#0022aa" );
+static Int_t c_DarkBlueT5    = TColor::GetColor( "#001177" );
+
+static Int_t c_VLightGray    = TColor::GetColor( "#eeeeee" );
+static Int_t c_LightGray     = TColor::GetColor( "#cfcfcf" );
+static Int_t c_Gray          = TColor::GetColor( "#888888" );
+static Int_t c_VDarkGray     = TColor::GetColor( "#333333" );
+static Int_t c_DarkGray      = TColor::GetColor( "#555555" );
+static Int_t c_Black         = TColor::GetColor( "#000000" );
+
+static Int_t c_ExclusionCol  = TColor::GetColor( "#999999" );
+static Int_t c_ExclusionColL = TColor::GetColor( "#cccccc" );
+
+static Int_t c_VLightBkg     = TColor::GetColor( "#eeeeee" );
+
+#endif
diff --git a/Database/CoolRunQuery/macros/style.C b/Database/CoolRunQuery/macros/style.C
new file mode 100644
index 00000000000..90c739ea58a
--- /dev/null
+++ b/Database/CoolRunQuery/macros/style.C
@@ -0,0 +1,39 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "TH1.h"
+#include "TStyle.h"
+#include "/Users/andreashoecker/ROOT/colours.C"
+
+#ifndef STYLE__
+#define STYLE__
+
+// set frame styles
+void SetFrameStyle( TH1* frame, Float_t scale = 1.0 )
+{
+   frame->SetLabelOffset( 0.012, "X" );// label offset on x axis
+   frame->SetLabelOffset( 0.012, "Y" );// label offset on x axis
+   frame->GetXaxis()->SetTitleOffset( 1.25 );
+   frame->GetYaxis()->SetTitleOffset( 0.94 );
+   frame->GetXaxis()->SetTitleSize( 0.045*scale );
+   frame->GetYaxis()->SetTitleSize( 0.045*scale );
+   Float_t labelSize = 0.04*scale;
+   frame->GetXaxis()->SetLabelSize( labelSize );
+   frame->GetYaxis()->SetLabelSize( labelSize );
+
+   // global style settings
+   gPad->SetTicks();
+   gPad->SetBottomMargin( 0.120*scale  );
+
+   // some style elements
+   gStyle->SetTitleFillColor( c_VLightGray );
+   gStyle->SetTitleTextColor( c_VDarkGray );
+   gStyle->SetTitleBorderSize( 1 );
+   gStyle->SetTitleH( 0.05 );
+   gStyle->SetTitleX( gPad->GetLeftMargin() );
+   gStyle->SetTitleY( 1 - gPad->GetTopMargin() + gStyle->GetTitleH() );
+   gStyle->SetTitleW( 1 - gPad->GetLeftMargin() - gPad->GetRightMargin() );
+}
+
+#endif
diff --git a/Database/CoolRunQuery/python/AtlRunQueryAMI.py b/Database/CoolRunQuery/python/AtlRunQueryAMI.py
new file mode 100644
index 00000000000..9a834651e44
--- /dev/null
+++ b/Database/CoolRunQuery/python/AtlRunQueryAMI.py
@@ -0,0 +1,231 @@
+#!/bin/env python
+
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+#
+# ----------------------------------------------------------------
+# Script : AtlRunQueryAMI.py
+# Project: AtlRunQuery
+# Purpose: Utility to retrieve information from AMI
+# Authors: Andreas Hoecker (CERN), Joerg Stelzer (DESY)
+# Created: Nov 10, 2009
+# ----------------------------------------------------------------
+#
+
+import re
+
+class ARQ_AMI:
+
+    _amiclient = None
+    store = {}
+    all_periods = None
+
+
+    @classmethod
+    def getAmiClient(cls, amiconf = None, verbose = False):
+        """get ami client
+        param amiconf: name of file with AMI user and pw
+
+        If a valid filename is specified, it tries to read the
+        username and password from there. If that does not succeed or
+        no filename is specified, voms based authentication is tried.
+        """
+        from pyAMI.pyAMI import AMI,pyAMIEndPoint
+        from os import stat,path
+
+        useConfigFile = False
+        if amiconf:
+            if not path.exists(amiconf):
+                if verbose:
+                    print "WARNING: AMI config file", amiconf, "does not exist. Need to rely on valid voms proxy."
+            elif stat(amiconf).st_mode & path.stat.S_IRUSR == 0:
+                if verbose:
+                    print "WARNING: AMI config file", amiconf, "exists but is not readable. Need to rely on valid voms proxy."
+            else:
+                useConfigFile = True
+                
+        if useConfigFile:
+            pyAMIEndPoint.setType("replica")
+            ami=AMI()
+            ami.readConfig(amiconf)
+            if ami.checkAuth():
+                print "... connecting to CERN AMI replica with user+pw"
+                return ami
+            pyAMIEndPoint.setType("main")
+            ami.certAuth()
+            if ami.checkAuth():
+                print "... connecting to AMI main server with user+pw"
+                return ami
+
+            print "WARNING: Authentication in config file",amiconf,"not valid, check format, user, pw. Need to rely on valid voms proxy."
+
+
+        pyAMIEndPoint.setType("replica")
+        ami=AMI()
+        if ami.checkAuth():
+            print "... connecting to CERN replica using voms-proxy"
+            return ami
+
+
+        pyAMIEndPoint.setType("main")
+        ami.certAuth()
+        if ami.checkAuth():
+            print "... connecting to main server using voms-proxy"
+            return ami
+
+
+        if verbose:
+            print "WARNING voms-proxy authentication not valid. No access to AMI."
+        return None
+
+
+    @classmethod
+    def amiclient(cls):
+        if cls._amiclient == None:
+            from os import getenv
+            from utils.AtlRunQueryUtils import runsOnServer
+            if runsOnServer():
+                home = "/data/atrqadm/data/"
+            else:
+                home = getenv('HOME')
+                if not home: home = '~'
+            conffilename = home + "/private/AMIConf.txt"
+            cls._amiclient = cls.getAmiClient(conffilename)
+            if cls._amiclient==None:
+                print "ERROR: voms-proxy authentication not valid and no AMI configuration file",conffilename,"supplied. No access to AMI!"
+                cls._amiclient="No AMI"
+        return cls._amiclient
+
+    @classmethod
+    def OpenAMIConnection(cls):
+        try:
+            from pyAMI.pyAMI import AMI,pyAMIEndPoint
+            #pyAMIEndPoint.setType("replica")
+            amiclient = AMI()
+            amiclient.readConfig("./AMIConf.txt")
+            return amiclient
+        except ImportError:
+            print 'ERROR: could not load pyAMI'
+            return None
+
+
+    @classmethod
+    def amiexec(cls, cmdList):
+        try:
+            result = cls.amiclient().execute(cmdList)
+            return result.getDict()
+        except Exception as ex:
+            print "AMI exception '",type(ex),"' occured"
+            print ex
+        return {}
+
+
+    @classmethod
+    def get_periods_for_run(cls, run):
+        try:    run = int(run)
+        except: return []
+        if not run in cls.store:
+            try:
+                print 'GetDataPeriodsForRun', '-runNumber=%i' % run
+                #result = cls.amiclient().execute(['GetDataPeriodsForRun', '-runNumber=%i' % run])
+                result = cls.amiexec(['GetDataPeriodsForRun', '-runNumber=%i' % run])
+                #cls.store[run] = sorted([ (int(e['periodLevel']),e['period'],e['project']) for e in result.getDict()['Element_Info'].values() ])
+                cls.store[run] = sorted([ (int(e['periodLevel']),e['period'],e['project']) for e in result['Element_Info'].values() ])
+            except:
+                print "Exception"
+                cls.store[run] = []
+        return [x[1] for x in cls.store[run]]
+
+
+    @classmethod
+    def get_periods(cls, year, level):
+        try:
+            cmd = ['ListDataPeriods', '-createdSince=2009-01-01 00:00:00' ]
+            if year>2000:
+                cmd += [ '-projectName=data%02i%%' % (year-2000) ]
+            if level in [1,2,3]:
+                cmd += [ '-periodLevel=%i' % level ]
+            #result = cls.amiclient().execute(cmd)
+            result = cls.amiexec(cmd)
+            #rows = [ (e['period'], e['projectName']) for e in result.getDict()['Element_Info'].values() ]
+            rows = [ (e['period'], e['projectName']) for e in result['Element_Info'].values() ]
+            return sorted(rows)
+        except Exception , e:
+            print e
+            return []
+
+
+    @classmethod
+    def get_all_periods(cls):
+        if cls.all_periods != None: return cls.all_periods
+        cls.all_periods = []
+        p = re.compile("(?P<period>(?P<periodletter>[A-Za-z]+)(?P<periodnumber>\d+)?)$")
+        try:
+            result = cls.get_periods(0, 0)
+            for period, projectName in result:
+                m = p.match(period)
+                if not m: continue
+                year = int(projectName[4:6])
+                period_letter = m.group('periodletter')
+                period_number = int(m.group('periodnumber')) if m.group('periodnumber') else 0
+                if len(period_letter)!=1: pc = 0
+                else: pc = 10000*year + 100*(ord(period_letter.upper())-65) + period_number
+                cls.all_periods += [ ((year, period, pc), projectName+".period" + period) ]
+            cls.all_periods.sort()
+        except Exception, e:
+            print e
+            pass
+        return cls.all_periods
+    
+
+    @classmethod
+    def get_runs(cls, period, year):
+        try:
+            cmd = ['GetRunsForDataPeriod', '-period=%s' % period]
+            if year>2000:
+                cmd += [ '-projectName=data%02i%%' % (year-2000) ]
+            #result = cls.amiclient().execute(cmd)
+            result = cls.amiexec(cmd)
+            #print "amiCommand",' '.join(cmd)        
+            #r = sorted([ int(e['runNumber']) for e in result.getDict()['Element_Info'].values() ])
+            r = sorted([ int(e['runNumber']) for e in result['Element_Info'].values() ])
+            return r
+        except: pass
+
+
+
+# for testing purpose
+if __name__ == "__main__":
+
+    choice = 1
+    while choice != 0:
+        print "\n1 - periods for run"
+        print "2 - runs for period (and year)"
+        print "3 - periods (by year and/or level)"
+        print "4 - all periods (different format)"
+        print "5 - test AMI authentication"
+        print "\n0 - exit\n"
+
+        choice = raw_input("  enter your choice: ")
+        choice = int(choice) if choice.isdigit() else 0
+        if choice==1:
+            run = int(raw_input("  run number: "))
+            print ARQ_AMI.get_periods_for_run( [run] )
+        elif choice==2:
+            period = raw_input("  period           : ")
+            year   = raw_input("  year <RET> = all : ")
+            year   = int(year) if year.isdigit() else 0
+            print ', '.join([str(x) for x in ARQ_AMI.get_runs(period, year)])
+        elif choice==3:
+            year   = raw_input("  year <RET> = all           : ")
+            year   = int(year) if year.isdigit() else 0
+            period = raw_input("  period [1|2|3] <RET> = all : ")
+            period = int(period) if period.isdigit() else 0
+            print ARQ_AMI.get_periods(year, period)
+        elif choice==4:
+            print ARQ_AMI.get_all_periods()
+        elif choice==5:
+            ami = ARQ_AMI.amiclient()
+            if ami!="No AMI":
+                print "Successfully connected to AMI"
+            else:
+                print "Failed to connect to AMI"
diff --git a/Database/CoolRunQuery/python/AtlRunQueryCOMA.py b/Database/CoolRunQuery/python/AtlRunQueryCOMA.py
new file mode 100755
index 00000000000..0d16b1a7b28
--- /dev/null
+++ b/Database/CoolRunQuery/python/AtlRunQueryCOMA.py
@@ -0,0 +1,178 @@
+#!/bin/env python
+
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+#
+# ----------------------------------------------------------------
+# Script : AtlRunQueryAMI.py
+# Project: AtlRunQuery
+# Purpose: Utility to retrieve information from AMI
+# Authors: Andreas Hoecker (CERN), Joerg Stelzer (DESY)
+# Created: Nov 10, 2009
+# ----------------------------------------------------------------
+#
+
+import re
+
+class ARQ_COMA:
+
+    __store = {}
+    all_periods = None
+
+    __cursor = None
+    __schema = "ATLAS_TAGS_METADATA"
+
+    __tables = {
+        'PR'  : 'COMA_V_PERIOD_RUNS',
+        }
+
+    @classmethod
+    def getUsedTables(cls, output, condition):
+        usedtables = set( [o.split('.')[0] for o in output] ) # all tables specified in output fields
+
+        for c in condition:
+            for p in c.split():
+                if '.' in p and not '\'' in p: usedtables.add(p.split('.')[0].lstrip('(')) # all tables specified in conditions
+
+        return ["%s.%s %s" % (cls.__schema,cls.__tables[t],t) for t in usedtables] # prefix schema name to table name
+
+
+    @classmethod
+    def query(cls, output, condition, bindvars, verbose=False):
+        query = 'select distinct %s from %s' % (', '.join(output),
+                                                ', '.join(cls.getUsedTables(output, condition)))
+        if condition:
+            query += ' where ' + ' and '.join(condition)
+        if verbose: print "="*80,"\n",query
+        c = cls.cursor()
+        c.execute(str(query),bindvars)
+        return c.fetchall()
+
+
+    @classmethod
+    def cursor(cls):
+        """get COMA connection
+        any connection to ATLR is fine, we use Trigger DB
+        """
+        if not cls.__cursor:
+            from TrigConfigSvc.TrigConfigSvcUtils import getTriggerDBCursor
+            cls.__cursor = getTriggerDBCursor("TRIGGERDB")[0]
+        return cls.__cursor
+
+
+
+
+
+    @classmethod
+    def get_periods_for_run(cls, run):
+        try:    run = int(run)
+        except: return []
+        if not run in cls.__store:
+
+            print "FRESH Access for run" ,run
+
+            output = ['PR.P_LEVEL', 'PR.P_PERIOD', 'PR.P_PROJECT' ]
+            condition = [ "PR.RUN_INDEX = :run" ]
+            bindvars = { "run": run }
+
+            cls.__store[run] = sorted( cls.query(output, condition, bindvars) )
+
+        return [x[1] for x in cls.__store[run]]
+
+
+    @classmethod
+    def get_periods(cls, year=0, level=0):
+        output = ['PR.P_PERIOD', 'PR.P_PROJECT' ]
+        condition = []
+        bindvars = {}
+
+        if level>0:
+            condition += [ "PR.P_LEVEL=:lvl" ]
+            bindvars["lvl"] = level
+
+        if year>2000:
+            project = 'data%02i%%' % (year-2000)
+            condition += [ "PR.P_PROJECT like :proj" ]
+            bindvars["proj"] = project
+
+        return sorted( cls.query(output, condition, bindvars) )
+
+
+    @classmethod
+    def get_all_periods(cls):
+        if cls.all_periods != None: return cls.all_periods
+        cls.all_periods = []
+        p = re.compile("(?P<period>(?P<periodletter>[A-Za-z]+)(?P<periodnumber>\d+)?)$")
+        try:
+            result = cls.get_periods(0, 0)
+            for period, projectName in result:
+                m = p.match(period)
+                if not m: continue
+                year = int(projectName[4:6])
+                period_letter = m.group('periodletter')
+                period_number = int(m.group('periodnumber')) if m.group('periodnumber') else 0
+                if len(period_letter)!=1: pc = 0
+                else: pc = 10000*year + 100*(ord(period_letter.upper())-65) + period_number
+                cls.all_periods += [ ((year, period, pc), projectName+".period" + period) ]
+            cls.all_periods.sort()
+        except Exception, e:
+            print e
+            pass
+        return cls.all_periods
+    
+
+    @classmethod
+    def get_runs(cls, period, year):
+        output = ['PR.RUN_INDEX', 'PR.P_LEVEL', 'PR.P_PERIOD', 'PR.P_PROJECT' ]
+
+        condition = [ "PR.P_PERIOD=:period" ]
+        bindvars = { "period" : period }
+        if year>2000:
+            project = 'data%02i%%' % (year-2000)
+            condition += [ "PR.P_PROJECT like :proj" ]
+            bindvars["proj"] = project
+        result = cls.query(output, condition, bindvars)
+
+        tmpstore = {}
+
+        for record in result:
+            run = record[0]
+            info = record[1:4]
+            if not run in tmpstore:
+                tmpstore[run] = []
+            tmpstore[run] += [info]
+
+        cls.__store.update(tmpstore)
+        
+        return sorted( [r[0] for r in result] )
+
+
+
+# for testing purpose
+if __name__ == "__main__":
+
+    choice = 1
+    while choice != 0:
+        print "\n1 - periods for run"
+        print "2 - runs for period (and year)"
+        print "3 - periods (by year and/or level)"
+        print "4 - all periods (different format)"
+        print "\n0 - exit\n"
+
+        choice = raw_input("  enter your choice: ")
+        choice = int(choice) if choice.isdigit() else 0
+        if choice==1:
+            run = int(raw_input("  run number: "))
+            print ARQ_COMA.get_periods_for_run( run )
+        elif choice==2:
+            period = raw_input("  period           : ")
+            year   = raw_input("  year <RET> = all : ")
+            year   = int(year) if year.isdigit() else 0
+            print ', '.join([str(x) for x in ARQ_COMA.get_runs(period, year)])
+        elif choice==3:
+            year   = raw_input("  year <RET> = all           : ")
+            year   = int(year) if year.isdigit() else 0
+            level  = raw_input("  level [1|2|3] <RET> = all : ")
+            level  = int(level) if level.isdigit() else 0
+            print ARQ_COMA.get_periods(year, level)
+        elif choice==4:
+            print ARQ_COMA.get_all_periods()
diff --git a/Database/CoolRunQuery/python/AtlRunQueryLib.py b/Database/CoolRunQuery/python/AtlRunQueryLib.py
new file mode 100755
index 00000000000..ef0598d3f20
--- /dev/null
+++ b/Database/CoolRunQuery/python/AtlRunQueryLib.py
@@ -0,0 +1,349 @@
+#!/bin/env python
+
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+#
+# ----------------------------------------------------------------
+# Script : AtlRunQueryLib.py
+# Project: AtlRunQuery
+# Purpose: Library with the actual query classes
+# Authors: Andreas Hoecker (CERN), Joerg Stelzer (DESY)
+# Created: Nov 13, 2008
+# ----------------------------------------------------------------
+#
+
+from __future__ import with_statement
+
+from CoolRunQuery.utils.AtlRunQueryTimer import timer
+
+import CoolRunQuery.utils.AtlRunQueryFastBlobRead
+
+import cx_Oracle
+
+try:
+    Set = set
+except NameError:
+    from sets import Set
+
+import sys, re, os
+from datetime import timedelta,datetime
+from PyCool import cool
+from time import time,strftime,gmtime
+from collections import defaultdict
+from copy import deepcopy
+
+from utils.AtlRunQueryUtils              import coolDbConn, runsOnServer
+
+from selector.AtlRunQuerySelectorRuntime import RunTimeSelector, TimeRunSelector
+from selector.AtlRunQuerySelectorBase    import Selector, DataKey
+
+from CoolRunQuery.AtlRunQueryRun         import Run
+from CoolRunQuery.AtlRunQueryQueryConfig import QC
+
+
+
+
+
+# -----------------------------------------------------------------------------------------
+# class: AtlRunQuery
+# -----------------------------------------------------------------------------------------
+
+class AtlRunQuery:
+
+    def __init__(self, options, readoracle=False, loglevel=1, html="AUTO", origQuery="", datapath='data', parsedstring=""):
+
+        with timer('total'):
+
+            with timer('config'):
+                self.config(options, readoracle, loglevel, html, origQuery, datapath, parsedstring)
+
+            with timer('run all'):
+                runlist = self.run()
+
+            with timer('evaluate all'):
+                (dic, dicsum, xmlhtmlstr, roothtmlstr) = self.evaluate(runlist)
+
+            with timer('output all'):
+                self.output(runlist, dic, dicsum, xmlhtmlstr, roothtmlstr)
+
+            with timer('finalize'):
+                self.finalize()
+
+        from CoolRunQuery.utils.AtlRunQueryTimer import TimerStats as TS
+        TS.printTimeSummary()
+        TS.printTimeFlat()
+
+
+
+    def config(self, options, readoracle, loglevel, html, origQuery, datapath, parsedstring):
+
+        self.cmdlineOptions = options
+        self.origQuery = origQuery
+        self.datapath = datapath
+        Run.Datapath = self.datapath
+        QC.datapath = self.datapath    # TODO: move away from Run.Datapath to QC.datapath 
+        self.parsedstring = parsedstring
+        self.maxNumOfRuns = -1    # in case a maximum number of to be selected runs is given
+        self.makeSummary = 'summary' in options.show  # in case a summary shall be printed
+        self.makeDQSummary = 'dqsummary' in options.show  # in case a DQ efficiency summary shall be printed
+        self.makeDQPlots = 'dqplots' in options.show  # in case only DQ plots shall be printed 
+        self.makeDQeff = 'dqeff' in options.show  # in case a DQ efficiency summary shall be printed
+        self.xmlFileName  = 'MyLBCollection.xml'
+        self.xmlFileLabel = 'MyLBCollection'
+        self.querystart = time()
+        self.selectionOutput = []
+
+        # if no show argument is specified, we use the minimal version
+        if not self.cmdlineOptions.show:
+            self.cmdlineOptions.show = ['run','time']
+
+        if self.cmdlineOptions.xmlfile != None:
+            # format 'file.xml:runlist' or 'runlist:file.xml'
+            str1,str2 = self.cmdlineOptions.xmlfile.strip().split(':',1)
+            if   '.xml' in str1:
+                self.xmlFileName = str1
+                if str2 != '': self.xmlFileLabel = str2
+            elif '.xml' in str2:
+                self.xmlFileName = str2
+                if str1 != '': self.xmlFileLabel = str1            
+                
+        if self.cmdlineOptions.html:
+            self.html = self.cmdlineOptions.html
+        else:
+            if   html=="AUTO": self.html = runsOnServer()
+            elif html=="YES":  self.html = True
+            elif html=="NO":   self.html = False
+            else: raise RuntimeError, "Unknown argument for option 'html': %s" % html
+        Run.writehtml = self.html
+
+        if self.cmdlineOptions.prodgrl != None : # happens only if --nogrl is specified
+            self.prodgrl = self.cmdlineOptions.prodgrl
+        elif self.cmdlineOptions.xmlfile != None :
+            self.prodgrl = True # if an xml file is specified it will be produced
+        else:
+            self.prodgrl = not runsOnServer()
+
+
+        if self.cmdlineOptions.dictroot != None : # happens if --root or --noroot is specified
+            self.dictroot = self.cmdlineOptions.dictroot
+        else:
+            self.dictroot = not runsOnServer()
+            
+
+        if self.cmdlineOptions.database:
+            if self.cmdlineOptions.database.upper()=='MC':     Selector.db = 'OFLP200'
+            elif self.cmdlineOptions.database.upper()=='DATA': Selector.db = 'COMP200'
+            else:                                  Selector.db = self.cmdlineOptions.database
+
+        if self.cmdlineOptions.condtag:
+            Selector.condtag = self.cmdlineOptions.condtag
+
+        QC.localtime = (self.cmdlineOptions.utc==None)
+        QC.settimezone()
+
+        # check which runs currently participate in prompt calibration
+        # we need this for the web display only
+        if self.html:
+            nemo_dir = '/afs/cern.ch/user/a/atlcond/scratch0/nemo/prod/web/'
+            f = open( nemo_dir + 'calibruns.txt' )
+            for line in f:
+                try:
+                    if line: Run.PromptCalibRuns.append( int(line.strip()) )
+                except ValueError:
+                    pass
+            # read list of NEMO tasks
+            # do we need this for each query, or just for the web??
+            fname = os.listdir( nemo_dir + 'tasks' )
+            i = 0
+            for taskname in fname:
+                m = re.match('.*(task_(\d+)_\d+.txt)',taskname)
+                if m:
+                    i+=1
+                    fname, runnr = m.groups()
+                    Run.NemoTasks[int(runnr)] = fname
+
+
+
+    def run(self):
+        # is last run still open ?
+        from CoolRunQuery.AtlRunQuerySFO import GetSFO_lastNruns
+        sfoconnection = coolDbConn.GetSFODBConnection()
+        sfocursor     = sfoconnection.cursor()
+        retlist       = GetSFO_lastNruns( sfocursor, 1 )
+        if 'OPENED' in retlist[0][1]: Run.runnropen = retlist[0][0]
+
+        if self.cmdlineOptions.runlist != None:
+            runlist = self.cmdlineOptions.runlist
+            if any('last' in x for x in self.cmdlineOptions.runlist):
+                for idx in xrange(len(runlist)):
+                    rrange = runlist[idx]
+                    if not 'last' in rrange: continue
+                    rrange = rrange.replace('last','')
+                    self.maxNumOfRuns = int(rrange)
+                    # list of last n runs run numbers, where at least one stream is not calibration
+                    retlist    = GetSFO_lastNruns( sfocursor, 1.1*self.maxNumOfRuns )
+                    runlist[idx] = '%i+' % (retlist[-1][0])
+
+        elif self.cmdlineOptions.timelist != None:
+            # translate time into run-range
+            if 'last' in self.cmdlineOptions.timelist[0]:
+                 # contains 'last'
+                from CoolRunQuery.utils.AtlRunQueryUtils import get_runs_last_dt
+                rlist = get_runs_last_dt(self.cmdlineOptions.timelist[0])
+
+                runlist = ['%i+' % rlist[-1]] if (len(rlist)>0) else ['99999999+']
+
+            else:
+                # translate time into run-range
+                from utils.AtlRunQueryUtils import timeStringToSecondsUTC,secondsToTimeStringUTC,get_run_range2,GetTimeRanges
+                timelist = ','.join(self.cmdlineOptions.timelist)
+                timeranges,timerangesHR = GetTimeRanges(timelist, intRepFnc=timeStringToSecondsUTC, maxval=time())
+                timerangesAsString = [ map(secondsToTimeStringUTC, tr) for tr in timeranges]
+                runranges = [ ( "%s-%s" % get_run_range2(tr[0],tr[1]) ) for tr in timerangesAsString]
+                runlist = [','.join(runranges)]
+
+
+        # the run selector
+        rtSel = RunTimeSelector(name = 'runtime', runlist = runlist)
+
+        # find the begin and end of each interesting run
+        runlist = rtSel.select()
+        self.selectionOutput += ["%s" % rtSel]
+
+
+        from .AtlRunQuerySelectorWorker import SelectorWorker
+
+        # create all selectors that actively select
+        SelectorWorker.parseSelectorOptions(self.cmdlineOptions)
+
+        # parse show option:
+        SelectorWorker.parseShowOption(self.cmdlineOptions)
+
+        # call setApply for all selectors that actively select
+        SelectorWorker.setApplySelection()
+
+        # call setShowOutput for all selectors that show
+        SelectorWorker.setShowOutput()
+
+        SelectorWorker.getRetrieveSelector('trigkey','TrigKeySelector')
+
+        # Selectors can implement an initialize function which runs after any constructor and setShow 
+        for s in SelectorWorker.getOrderedSelectorList():
+            s = s.selector
+            if hasattr(s, 'initialize'):
+                with timer("initializing selector '%s'" % s.name):
+                    s.verbose = True
+                    s.initialize()
+
+        # apply the selectors to initial run list
+        for s in SelectorWorker.selectors():
+            with timer("run selector '%s'" % s.name):
+                s.verbose = True
+                runlist = s.select(runlist)
+                self.selectionOutput += ["%s" % s.__str__()]
+            with timer("run AfterQuery for selector '%s'" % s.name):
+                s.runAfterQuery(runlist)
+            #print [r.runNr for r in runlist]
+
+        # reverse list for presentation: newest run on top
+        runlist.reverse()
+
+        # if "last" option used, the runlist has to be truncated
+        if self.maxNumOfRuns > 0:
+            print 'SELOUT Selecting the %i most recent runs' % self.maxNumOfRuns
+            runlist = runlist[0:self.maxNumOfRuns]
+            self.selectionOutput += ['SELOUT Selecting the %i most recent runs' % self.maxNumOfRuns]
+            
+        return runlist
+
+
+    def evaluate(self, runlist):
+        # provide pickled dictionary of query result
+        with timer('CreateResultDict'):
+            from CoolRunQuery.output.AtlRunQuerySave import CreateResultDict
+            dic, dicsum = CreateResultDict( runlist )
+
+
+        # create XML file (and return pretty html output for print)
+        with timer('CreateXMLFile'):
+            if self.prodgrl:
+                from CoolRunQuery.output.AtlRunQueryXML import CreateXMLFile
+                from .AtlRunQueryVersion import SvnVersion
+                xmlhtmlstr = CreateXMLFile( runlist, self.cmdlineOptions, self.origQuery, self.datapath,
+                                            self.xmlFileName, self.xmlFileLabel, SvnVersion )
+            else:
+                xmlhtmlstr = None
+                print "Creation of GRL disabled"
+
+        with timer('CreateRootFile'):
+            if self.dictroot and len(runlist) > 0:
+                # create root file from dictionary - and make plots
+                from CoolRunQuery.output.AtlRunQueryRoot import CreateRootFile
+                rootfilename, roothtmlstr = CreateRootFile( dic )
+            else:
+                roothtmlstr = None
+                print "Creation of root file disabled"
+
+        return (dic, dicsum, xmlhtmlstr, roothtmlstr)
+        
+
+    def output(self, runlist, dic, dicsum, xmlhtmlstr, roothtmlstr):
+
+        if self.html:
+
+            with timer('GetOKS link info'):
+                from AtlRunQuerySFO import SetOKSLinks
+                SetOKSLinks(runlist)
+
+            # create web page
+            from .html.AtlRunQueryHTML import ResultPageMaker
+            try:
+                pageinfo = { 'datapath'      : self.datapath,
+                             'origQuery'     : self.origQuery,
+                             'fullQuery'     : self.parsedstring,
+                             'runlist'       : runlist,
+                             'dic'           : dic,
+                             'dicsum'        : dicsum,
+                             'makeSummary'   : self.makeSummary,
+                             'makeDQeff'     : self.makeDQeff,
+                             'makeDQSummary' : self.makeDQSummary,
+                             'makeDQPlots'   : self.makeDQPlots,
+                             'roothtmlstr'   : roothtmlstr,
+                             'xmlfilename'   : self.xmlFileName,
+                             'xmlhtmlstr'    : xmlhtmlstr,
+                             'querytime'     : time() - self.querystart,
+                             'selout'        : self.selectionOutput,
+                             }
+                with timer("run page maker"):
+                    ResultPageMaker.makePage(pageinfo)
+            except ImportError, ie:
+                print "Can't import pagemaker, no web page made",ie
+
+        else:
+            print '---------------------------------------------------------------------'
+            print Run.header()
+            runlist.reverse()
+            for r in runlist:
+                print r
+
+            from CoolRunQuery.utils.AtlRunQueryUtils import addKommaToNumber, filesize
+            print 'Summary:'
+            for data_key, summary in dicsum.items():
+                if data_key.Type==DataKey.STREAM:
+                    key = data_key.ResultKey.replace('STR:','')
+                    val = '%s (%s)' % ( addKommaToNumber(summary[0]), filesize(summary[1]) )
+                else:
+                    key = data_key.ResultKey
+                    val = addKommaToNumber(summary)
+                print '%20s : %s' % (key,val)
+            duration = time() - self.querystart
+            print "%20s : %g sec" % ('Total execution time',duration)
+            print '---------------------------------------------------------------------'
+        
+    def finalize(self):
+        coolDbConn.CloseAll()
+            
+if __name__ == '__main__':
+    from CoolRunQuery.AtlRunQueryOptions import AtlRunQueryOptions 
+    (options, args) = AtlRunQueryOptions().parse()    
+    rsq = AtlRunQuery(options)
+
diff --git a/Database/CoolRunQuery/python/AtlRunQueryLookup.py b/Database/CoolRunQuery/python/AtlRunQueryLookup.py
new file mode 100644
index 00000000000..6d3ea110385
--- /dev/null
+++ b/Database/CoolRunQuery/python/AtlRunQueryLookup.py
@@ -0,0 +1,3 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+from utils.AtlRunQueryLookup import DQChannelDict
diff --git a/Database/CoolRunQuery/python/AtlRunQueryOptions.py b/Database/CoolRunQuery/python/AtlRunQueryOptions.py
new file mode 100644
index 00000000000..56556cfb013
--- /dev/null
+++ b/Database/CoolRunQuery/python/AtlRunQueryOptions.py
@@ -0,0 +1,237 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+import sys
+from optparse import OptionParser
+
+class AtlRunQueryOptions:
+    def __init__(self):
+        self.parser = OptionParser(usage="usage: %prog options")
+        self.parser.add_option( "-r",
+                                "--run",
+                                action = 'append',
+                                dest = "runlist",
+                                help = "A list of run ranges 90923,89500-89600,92050-" )
+        
+        self.parser.add_option( "-t",
+                                "--time",
+                                action="append",
+                                dest = "timelist",
+                                help = "A list of time ranges 10.9.2008-30.9.2008,15.10.2008-" )
+
+        self.parser.add_option( "-p",
+                                "--partition",
+                                dest = "partition",
+                                help = "The partition name [default: %DEFAULT]" )
+
+        self.parser.add_option( "--readyforphysics",
+                                dest = "readyforphysics",
+                                help = "ReadyForPhysics flag" )
+
+        self.parser.add_option( "--db",
+                                dest = "database",
+                                default = 'COMP200',
+                                choices = ['COMP200', 'OFLP200', 'DATA', 'MC'],
+                                help = "The detabase [default: %DEFAULT]" )
+        
+        self.parser.add_option( "-c",
+                                "--ctag",
+                                dest = "condtag",
+                                help = "The top conditions tag" )
+        
+        self.parser.add_option( "-l",
+                                "--duration",
+                                dest = "duration",
+                                help = "The duration limit of a run in seconds e.g.: -l 36000 (longer than 10 hours) or -l 300- (less than 5 minutes)" )
+        
+        self.parser.add_option( "-e",
+                                "--events",
+                                dest = "events",
+                                help = "Number of events (EF accepts) in run e.g. 10000-20000" )
+
+        self.parser.add_option( "--allevents",
+                                dest = "allevents",
+                                help = "Shows number of EFA/SFO/L1A/L2A events in selected runs e.g. 10000-20000" )
+
+        self.parser.add_option( "-k",
+                                "--smk",
+                                dest = "smklist",
+                                help = "A list of smks 359,365,372-" )
+        
+        self.parser.add_option( "-b",
+                                "--bfield",
+                                action = "append",
+                                choices = ['on', 'off', 'solenoidon', 'solenoidoff', 'toroidon', 'toroidoff'],
+                                dest = "bfield",
+                                help = "Bfield ['on', 'off', 'solenoidon', 'solenoidoff', 'toroidon', 'toroidoff']" )
+        
+        self.parser.add_option( "-q",
+                                "--dq",
+                                action = "append",
+                                dest = "dqchannels",
+                                help = "Data quality flags, e.g. --dq 'PIXB green SHIFTOFL'" )
+        
+        self.parser.add_option( "--detmaskin",
+                                action = "append",
+                                dest = "detmaskin",
+                                help = "Detector mask, e.g. --detmaskin 0x3123 " )
+
+        self.parser.add_option( "--detmaskout",
+                                action = "append",
+                                dest = "detmaskout",
+                                help = "Detector mask of absent detectors, e.g. --detmaskout 0x2174 " )
+        
+        self.parser.add_option( "--filenametag",
+                                dest = "projecttag",
+                                help = "Filename tag, e.g. --filenametag !data_test " )
+        
+        self.parser.add_option( "--projecttag",
+                                dest = "projecttag",
+                                help = "Project tag, e.g. --projecttag !data_test " )
+
+        self.parser.add_option( "-s",
+                                "--show",
+                                action = "append",
+                                dest = "show",
+                                help = "List of items to query" )
+        
+        self.parser.add_option( "--streams",
+                                action = "append",
+                                dest = "streams",
+                                help = 'Streams, --streams "phy*" ' )
+        
+        self.parser.add_option( "--trigger",
+                                action = "append",
+                                dest = "trigger",
+                                help = 'Triggers, --trigger "EF_Electron*" ' )
+        
+        self.parser.add_option( "--release",
+                                action = "append",
+                                dest = "release",
+                                help = 'Release, --release "14.2.5-14.3.1" ' )
+
+        self.parser.add_option( "--luminosity",
+                                action = "append",
+                                dest = "luminosity",
+                                help = 'Luminosity, --luminosit' )
+
+        self.parser.add_option( "--olclumi",
+                                action = "append",
+                                dest = "olclumi",
+                                help = 'olclumi, --olclumi "1ub+"' )
+
+        self.parser.add_option( "--olcfillparams",
+                                action = "append",
+                                dest = "olcfillparams",
+                                help = 'olcfillparams, --olcfillparams "channel"' )
+
+        self.parser.add_option( "--beamspot",
+                                action = "append",
+                                dest = "beamspot",
+                                help = 'Beamspot, --beamspot' )
+
+        self.parser.add_option( "--bpm",
+                                action = "append",
+                                dest = "bpm",
+                                help = 'BPM, --bpm' )
+
+        self.parser.add_option( "--datasets",
+                                action = "append",
+                                dest = "datasets",
+                                help = 'Datasets, --datasets *NTUP*' )
+
+        self.parser.add_option( "--ami",
+                                action = "append",
+                                dest = "ami",
+                                help = 'Ami, --ami' )
+
+        self.parser.add_option( "--larcond",
+                                action = "append",
+                                dest = "larcond",
+                                help = 'Larcond, --larcond "nsamples 7"' )
+
+        self.parser.add_option( "--lhc",
+                                action = "append",
+                                dest = "lhc",
+                                help = 'LHC information, --lhc "fillnumber 851"' )
+
+        self.parser.add_option( "--summary",
+                                action = "count",
+                                dest = "summary",
+                                help = 'Print summary, --summary ' )
+
+        self.parser.add_option( "--dqeff",
+                                action = "count",
+                                dest = "dqeff",
+                                help = 'Print DQ efficiency summary, --dqeff ' )
+
+        self.parser.add_option( "-v",
+                                "--verbose",
+                                action = "count",
+                                dest = "verbose",
+                                help = "Verbosity level" )
+
+        self.parser.add_option( "--noroot",
+                                action = "store_false",
+                                dest = "dictroot",
+                                help = "Do not create root files and python dict" )
+
+        self.parser.add_option( "--root",
+                                action = "store_true",
+                                dest = "dictroot",
+                                help = "Do create root files and python dict" )
+
+        self.parser.add_option( "--nohtml",
+                                action = "store_false",
+                                dest = "html",
+                                help = "Text output instead of html" )
+
+        self.parser.add_option( "--html",
+                                action = "store_true",
+                                dest = "html",
+                                help = "Text output instead of html" )
+
+        self.parser.add_option( "--selectOnUnknown",
+                                action = "store_true",
+                                dest = "selectonunknown",
+                                default = True,
+                                help = "Select when information is not known (only for #evt and partition name)" )
+
+        self.parser.add_option( "--skipUnknown",
+                                action = "store_false",
+                                dest = "selectonunknown",
+                                help = "Select when information is not known (only for #evt and partition name)" )
+
+        self.parser.add_option( "--xmlfile",
+                                action = "store",
+                                type = "string",
+                                dest = "xmlfile",
+                                help = "Give filename and label (format: filename:label) for XML GoodRunList file" )
+
+        self.parser.add_option( "--nogrl",
+                                action = "store_false",
+                                dest = "prodgrl",
+                                help = "Do not produce a good run list" )
+
+        self.parser.add_option( "--utc",
+                                action = "store_true",
+                                dest = "utc",
+                                help = "Use utc for everything, default is local time (CET/CEST)" )
+
+
+    def splitCmdline(self,argstring):
+        arg = argstring.split()
+        m = zip([x for x in xrange(len(arg)) if arg[x][0]=='"'],[x for x in xrange(len(arg)) if arg[x][-1]=='"'])
+        m.reverse()
+        for p in m:
+            if p[0]==p[1]: arg[p[0]] = arg[p[0]].strip('"')
+            elif p[1]-p[0] == 2:
+                arg[p[0]:p[1]+1]=[("%s %s %s" % (arg[p[0]],arg[p[0]+1],arg[p[1]])).strip('"')]
+            else:
+                arg[p[0]:p[1]+1]=[("%s %s" % (arg[p[0]],arg[p[1]])).strip('"')]
+        return arg
+
+
+    def parse(self,atlqueryarg=None):
+        if atlqueryarg:
+            sys.argv = self.splitCmdline(atlqueryarg)
+        return self.parser.parse_args()
diff --git a/Database/CoolRunQuery/python/AtlRunQueryPVSS.py b/Database/CoolRunQuery/python/AtlRunQueryPVSS.py
new file mode 100644
index 00000000000..df13a2ba798
--- /dev/null
+++ b/Database/CoolRunQuery/python/AtlRunQueryPVSS.py
@@ -0,0 +1,34 @@
+#!/bin/env python
+
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+#
+# ----------------------------------------------------------------
+# Script : AtlRunQueryPVSS.py
+# Project: AtlRunQuery
+# Purpose: Utility to retrieve information from PVSS DB (DCS quantities)
+# Authors: Andreas Hoecker (CERN), Joerg Stelzer (DESY)
+# Created: Mar 27, 2010
+# ----------------------------------------------------------------
+
+import cx_Oracle
+from time import time
+
+def GetPVSS_BPMs( cursor, iovmin, iovmax ):
+
+    # fetch the event history first
+    selcmd = "SELECT 'EVENTHISTORY_'||lpad (archive#,8,'0') from ( select archive#, start_time, end_time from atlas_pvssDCS.arc_archive A where A.group_name = 'EVENT' and (A.end_time > to_date('%s','DD-MM-YYYY HH24:MI:SS') or A.end_time is null) intersect select archive#, start_time, end_time from atlas_pvssDCS.arc_archive A where A.group_name = 'EVENT' and A.start_time < to_date('%s','DD-MM-YYYY HH24:MI:SS') )" % (iovmin, iovmax)
+    cursor.execute( selcmd )
+    eventhistory = cursor.fetchone()[0]
+
+    # perform the actual query
+    res = {}
+    bpmvars = ['ATLGCSLHC:BPMSW_B1_distanceIP.position.horizontal', 'ATLGCSLHC:BPMSW_B1_distanceIP.position.vertical',
+               'ATLGCSLHC:BPMSW_B2_distanceIP.position.horizontal', 'ATLGCSLHC:BPMSW_B2_distanceIP.position.vertical']
+
+    for var in bpmvars:
+        selcmd = "SELECT ROUND(A.VALUE_NUMBER,8), TO_CHAR(A.TS, 'DD-MM-YYYY HH24:MI:SS:FF3') FROM ATLAS_PVSSDCS.%s A,ATLAS_PVSSDCS.ELEMENTS B WHERE A.ELEMENT_ID = B.ELEMENT_ID and  ROWNUM <= 15000 AND  A.ELEMENT_ID = ( SELECT ELEMENT_ID FROM ATLAS_PVSSDCS.ELEMENTS WHERE  ELEMENT_NAME LIKE  '%s') AND TS BETWEEN TO_DATE('%s','DD-MM-YYYY HH24:MI:SS' ) AND TO_DATE('%s','DD-MM-YYYY HH24:MI:SS' ) AND A.VALUE_NUMBER <> 'NaN' AND A.VALUE_NUMBER <> BINARY_FLOAT_INFINITY ORDER BY B.ELEMENT_NAME, A.TS" % (eventhistory, var, iovmin, iovmax)
+        cursor.execute( selcmd )
+        res[var] = cursor.fetchall()
+
+    return res
+
diff --git a/Database/CoolRunQuery/python/AtlRunQueryParser.py b/Database/CoolRunQuery/python/AtlRunQueryParser.py
new file mode 100755
index 00000000000..2efa7672e4a
--- /dev/null
+++ b/Database/CoolRunQuery/python/AtlRunQueryParser.py
@@ -0,0 +1,839 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+#
+# ----------------------------------------------------------------
+# Script : AtlRunQueryParser.py
+# Project: AtlRunQuery
+# Purpose: Utility to translate a parser language (to be used in 
+#          a web browser) into AtlRunQuery arguments
+# Authors: Andreas Hoecker (CERN), Joerg Stelzer (DESY)
+# Created: Nov 13, 2008
+# ----------------------------------------------------------------
+#
+import sys,os,re
+import urllib
+
+from utils.AtlRunQueryLookup import InitDetectorMaskDecoder, DecodeDetectorMask, DQChannels
+
+class ArgumentParser:
+    dqFolderList = [ 'SHIFTOFL', 'DQCALCOFL', 'DQMFOFL', 'DQMFOFLH', 'DCSOFL', 'TISUMM', 'LBSUMM', 'MUONCALIB',
+                     'DQMFONL', 'DQMFONLLB', 'SHIFTONL' ] # these are online folders
+
+    def __init__ ( self ):
+        self.const_arg    = ""
+        self.default_find = ""
+        self.isMCDB = False
+        self.default_show = ["run","events","time"]
+
+        # allowed 'query' arguments
+        # tuple format: ( "short name", "long-name", "interpret function", "show function", "example", "default value" )
+        self.sortedKeys  = [ "run", "time", "duration", "events", "allevents", "projectTag", "partition", "readyforphysics",
+                             "trigkeys", "trigger", "release",
+                             "ami", "magnets", "larcond", "db", "ctag", "lhc", "lumi", "dq",
+                             "streams", "detector", "datasets", "all", "summary", "dqeff" ]
+                           
+        self.queryArgs = { "run":        ("r(uns)",      "run",    self.InterpretPeriods, self.ShowVariable, 
+                                          'r(uns)        [format: "run 91000", "runs 91000-92000", "runs 91000-(+)" (this run and all before (after))]', ""),
+                           "all":        ("all",         "all", self.InterpretString, self.ShowVariable, 
+                                          'all           [format: only available as "show" option]', ""),
+                           "summary":    ("summary",     "summary", self.InterpretString, self.ShowVariable, 
+                                          'summary       [format: only available as "show" option]', ""),
+                           "dqsummary":  ("dqsum(mary)", "dqsummary", self.InterpretString, self.ShowVariable, 
+                                          'dqsum(mary)   [format: only available as "show" option]', ""),
+                           "dqplots":    ("dqpl(ots)",   "dqplots", self.InterpretString, self.ShowVariable, 
+                                          'dqpl(ots)     [format: only available as "show" option]', ""),
+                           "dqeff":      ("dqeff",       "dqeff", self.InterpretString, self.ShowVariable, 
+                                          'dqeff         [format: only available as "show" option]', ""),
+                           "events":     ("ev(ents)",    "events", self.InterpretRange, self.ShowVariable, 
+                                          'ev(ents)      [format: "events 10000+", ... (same as for run number)]', ""),
+                           "allevents":  ("alle(vents)", "allevents", self.InterpretRange, self.ShowVariable, 
+                                          'alle(vents)   [format: only available as "show" option]', ""),
+                           "time":       ("t(ime)",      "time",   self.InterpretRange, self.ShowVariable, 
+                                          't(ime)        [format: "time 10.9.2008-30.9.2008", "time 15.10.2008-(+)" (this date and all before (after))]', ""),
+                           "duration":   ("dur(ation)",  "duration",  self.InterpretDuration, self.ShowVariable, 
+                                          'dur(ation)    [format: "dur 10d/h/m/s+/-", "2000s+" (run duration more than 2000 sec), "dur 3h-" (less than 3 hours)]', ""),
+                           "magnets":    ("m(agnet)",    "bfield", self.InterpretMagnets, self.ShowVariable, 
+                                          'm(agnet)      [format: "magnet s(olenoid)", "magnet t(oroid)", "not magnet t(oroid)", ...]', ""),
+                           "detector":   ("det(ector)",  "detmask", self.InterpretDetectorMask, self.ShowVariable, 
+                                          'det(ector)    [format: "detector Pixel B" (for Pixel Barrel), "detector Pixel" (for Pixel B & EC), "all" (for all detectors, detector mask = 72551459979255)', ""),
+                           "smk":        ("smk",         "smk",    self.InterpretRange, self.ShowVariable, 
+                                          'smk           [format: "smk 398", "smk 398,399 (super-master-key labelling trigger menu, format like for run ranges)]', ""),
+                           "trigkeys":   ("trigk(eys)",  "trigkeys",  self.InterpretRange, self.ShowVariable, 
+                                          'trigk(eys)    [format: "tkeys" (show all trigger keys of run: SMK, L1 and HLT prescale keys)]', ""),
+                           "release":    ("rel(ease)",   "release", self.InterpretString, self.ShowWithArg, 
+                                          'rel(ease)     [format: "release 15.1.*" ',""),
+                           "projectTag": ("ptag",        "projecttag",self.InterpretString, self.ShowVariable, 
+                                          'ptag          [format: "ptag data08_cos,data08_cosmag,data09_cos", "ptag data08_cos*,data09_cos" (note: the projectTag in dataset name / denoted "filenamtTag" in COOL)]',"data08*,data09*,data10*,data11*,data12*,data13*,data14*,data15*,data16*"),
+                           "partition":  ("p(artition)", "partition", self.InterpretString, self.ShowVariable, 
+                                          'p(artition)   [format: "partition ATLAS"]', "ATLAS"),
+                           "readyforphysics":  ("ready(forphysics)", "readyforphysics", self.InterpretString, self.ShowVariable, 
+                                          'ready(forphysics)   [format: "readyforphysics T(rue)"]', ""),
+                           "db":         ("db",          "db", self.InterpretString, self.ShowVariable, 
+                                          'db            [format: "db <DB>, where <DB> is either DATA, MC, COMP200, or OFLP200',""),
+                           "ctag":       ("ctag",        "ctag", self.InterpretString, self.ShowVariable, 
+                                          'ctag          [format: "ctag COMCOND-HLTC-001-00" ',""),
+                           "streams":    ("st(reams)",   "streams", self.InterpretStreams, self.ShowWithArg, 
+                                          'st(reams)     [format: "stream RPCwBeam,TGCwBeam", "stream physics*" ',""),
+                           "dq":         ("dq",          "dq",     self.InterpretDQ, self.ShowDQ, 
+                                          'dq            [format: "dq <FLAG> <status>", where the data quality status is "g(reen)", "y(ellow)", "r(ed)", "u(known)", example: dq PIXB y+ (means yellow or green status)]', ""),
+                           "trigger":    ("tr(igger)",   "trigger", self.InterpretString, self.ShowWithArg, 
+                                          'tr(igger)     [format: "trigger *Electron*" ',""),
+                           "lumi":       ("lu(minosity)","luminosity", self.InterpretWithTwoArgs, self.ShowWithArg, 
+                                          'lu(minosity)  [format: "lumi FOLDER", default: LBLESTOFL]" ',""),
+                           "olc":        ("olc",         "olc", self.InterpretWithTwoArgs, self.ShowWithArg, 
+                                          'olc           [format: "olc" (OLC = Online Luminosity Calculator)]" ',""),
+                           "bs":         ("bs",          "beamspot", self.InterpretString, self.ShowWithArg, 
+                                          'bs            [format: "bs"]" ',""),
+                           "bpm":        ("bpm",         "bpm", self.InterpretString, self.ShowVariable, 
+                                          'bpm           [format: "show bpm"]" ',""),
+                           "datasets":   ("da(tasets)",  "datasets", self.InterpretString, self.ShowWithArg, 
+                                          'da(tasets)    [format: show datasets *NTUP*"]" ',""),
+                           "ami":        ("ami",  "ami", self.InterpretString, self.ShowVariable, 
+                                          'ami           [format: show ami"]" ',""),
+                           "larcond":    ("lar(cond)",   "larcond", self.InterpretWithTwoArgs, self.ShowVariable, 
+                                          'lar(cond)     [format: larcond nsamples 7 / show larcond"]" ',""),
+                           "lhc":        ("lhc",         "lhc", self.InterpretWithTwoArgs, self.ShowVariable, 
+                                          'lhc           [format: lhc fill 7 / show lhc"]" ',""),
+                           "trigrates":  ("trigr(ates)", "trigrates", self.InterpretString, self.ShowWithArg, 
+                                          'trigr(ates)   [format: sh trigrates L1_EM*"]" ',"")
+                           }
+        # allowed 'show' arguments
+
+        # init detector mask
+        (self.dName, self.NotInAll, self.vetoedbits) = InitDetectorMaskDecoder()
+
+    def ParserUsage( self ):
+        print ' '
+        print 'Parser usage: python %s <string_argument>' % sys.argv[0]
+        print ' '
+        print 'A query starts with the keyword "f(ind)", several queries can be combined with "and", "(and) not"'
+        print 'The requested response information is given through the keyword "sh(ow)" (the query must be terminated by a "/")'
+        print ' '
+        print 'Query words:'
+        for key in self.queryArgs:
+            print "   %s " % self.queryArgs[key][4]
+        print ' ' 
+        print 'Parts of a keyword written in paranthesis are optional'
+        print ' ' 
+        print 'Examples: '
+        print ' ' 
+        print '  find run 90272 and runs 90275-91900 and magnet toroid and magnet solenoid / show run and events'
+        print '  f r 90272 and r 90275-91900 and m t and m s / sh r and ev [same as above in short-hand version]'
+        print '  find runs 90275-91900 and not run 90280 and not dq EMEC r and show run and dq EMEC' 
+        print ' '
+
+    def replaceNumbers( self, n ):
+        return n.replace('k','000').replace('m','000000')
+
+    def getPtagAndPeriod( self, name ):
+        ptag   = 'data11_7TeV'
+        if '.' in name: ptag, period = name.split('.')
+        else:           period = name
+        letter = period[period.find('period')+6:][0]
+        return ptag.strip(), period.strip(), letter
+
+    def InterpretPeriods( self, atlqarg, arg, neg ):
+        # format: arg = 'run data10_7TeV.periodA' or 'run periodA' (where 'data11_7TeV' is assumed)
+        #               or 'data10_7TeV.periodA-periodC' or 'data10_7TeV.periodA,data10_7TeV.periodB,...'
+        # This is case sensitive !!
+
+        available_periods = []
+        pfile_extension  = ".runs.list"
+
+
+        def printPeriods(periods):
+            print '\nAvailable periods:\n'
+            for i,x in enumerate(periods):
+                print x[1],"\t",
+                if (i+1)%4==0: print ""
+            sys.exit(0)
+
+
+        def readRunListFromURL( periodname ):
+            wwwpath    = "https://atlas.web.cern.ch/Atlas/GROUPS/DATAPREPARATION/DataPeriods/"
+            webaddress = wwwpath + periodname + pfile_extension
+
+            from utils.AtlRunQueryUtils import checkURL
+            if not checkURL( webaddress ):
+                print 'ERROR: Period "%s" not existing - please check name.' % periodname
+                print '       Note: case sensitivity must be respected for period names!'
+                printPeriods(available_periods)
+            return [line.strip() for line in urllib.urlopen( webaddress )]
+
+        def getDataPeriodsWithinRange(period_range):
+            pshort  = re.compile("(?:(?:\d{2})(?P<year>\d{2})\.)?(?P<period>[a-zA-Z])(?P<subperiod>\d+)?")
+            m1 = pshort.match(period_range[0].upper().replace('PERIOD',''))
+            m2 = pshort.match(period_range[1].upper().replace('PERIOD',''))
+            if m1==None or m2==None:
+                sys.exit(0)
+            p1 = (int(m1.group('year')) if m1.group('year') else 11,m1.group('period'),m1.group('subperiod'))
+            p2 = (int(m2.group('year')) if m2.group('year') else p1[0],m2.group('period'),m2.group('subperiod'))
+            p1c = 10000*p1[0] + 100*(ord(p1[1].upper())-65) + (int(p1[2]) if p1[2] else 0)
+            p2c = 10000*p2[0] + 100*(ord(p2[1].upper())-65) + (int(p2[2]) if p2[2] else 99)
+            #print "P1",p1,p1c
+            #print "P2",p2,p2c
+            if p1c>p2c: sys.exit(0)
+            list_of_periods = []
+            for p,p_name in sorted(available_periods):
+                if p[2]==0: continue # no special VdM or AllYear stuff
+                if p[2]%100==0: continue # no full periods
+                include = (p[2]>=p1c and p[2]<=p2c)
+                if include: list_of_periods += [(p[0],p[1],p_name)]  # 
+                #print p,("--> include" if include else "")
+            return list_of_periods
+
+
+        def getRunsFromPeriods(list_of_periods):
+            """list_of_periods:   periods for which run nr are returned, e.g [('10','B1'),('11','A'),...]"""
+            runlist = []
+            from CoolRunQuery.AtlRunQueryCOMA import ARQ_COMA
+            for year, period, fname in list_of_periods:
+                runlist += ARQ_COMA.get_runs(period, 2000+int(year))
+                    
+            return runlist
+
+        arg = arg.split(None,1)[1]
+
+        pat_last   = re.compile("(?:l|la|las|last) (\d*)$")
+        pat_number = re.compile("\d{5,8}[+-]?$")  # simple number with 5-8 digits, possibly followed by a + or -
+        pat_range  = re.compile("\d{5,8}-\d{5,8}$")  # simple number with 5-8 digits, possibly followed by a + or -
+        pat_short  = re.compile("(?:(?:\d{2})(\d{2})\.)?([a-zA-Z]+\d*)$")
+        pat_full   = re.compile("data(\d{2})_.*\.period([a-zA-Z]+\d*)$")
+
+        # final result in here
+        list_of_runs = []
+                
+        # are their any commas?        
+        for tag in arg.split(','):
+
+            # last X runs pattern
+            m = pat_last.match(arg)
+            if m:
+                list_of_runs += [ "last%s" % m.group(1) ]
+                continue
+            
+            # run numbers
+            if pat_number.match(tag):
+                list_of_runs += [tag]
+                continue
+
+            # run number range
+            if pat_range.match(tag):
+                list_of_runs += [tag]
+                continue
+
+            from CoolRunQuery.AtlRunQueryCOMA import ARQ_COMA
+            available_periods = ARQ_COMA.get_all_periods()
+
+            period_range = tag.split('-')
+            if len(period_range)==2:
+                list_of_periods = getDataPeriodsWithinRange(period_range)
+                list_of_runs += getRunsFromPeriods(list_of_periods)
+                continue
+            
+            m=pat_short.match(tag)
+            if m:
+                year, period = m.groups()
+                if year==None: year="11"
+                period = period.upper().replace('PERIOD','')
+                if 'ALL' in period: period = 'AllYear'
+                list_of_runs += getRunsFromPeriods([(year,period,None)])
+                continue
+
+            # backward compatible form: data10_7TeV.periodA
+            m=pat_full.match(tag)
+            if m:
+                year, period = m.groups()
+                list_of_runs += getRunsFromPeriods([(year,period,tag)])
+                continue
+
+
+        if len(list_of_runs)==0:
+            print "No runs matching pattern"
+            sys.exit(0)
+                    
+        return "--run " + ','.join([str(r) for r in list_of_runs])
+
+
+
+    def InterpretRange( self, atlqarg, arg, neg ):
+        # special possibility to give run ranges
+        rge = self.replaceNumbers(arg.split(None,1)[1])
+        rge = rge.replace('last ','l ').replace('las ','l ').replace('la ','l ').replace('l ','last ')
+        return "--" + atlqarg.strip() + ' "' + rge.strip().replace(' ','') + '"'
+            
+    # range interpretation utilities
+    def InterpretRangeNew( self, atlqarg, arg, neg ):
+        # special possibility to give run ranges
+        rge = self.replaceNumbers(arg.split(None,1)[1])
+        rge = rge.replace('last ','l ').replace('las ','l ').replace('la ','l ').replace('l ','last ')
+        return "--" + atlqarg.strip() + ' "' + rge.strip().replace(' ','') + '"'
+
+    def InterpretString( self, atlqarg, arg, neg ):
+        # '%' is translated into '*' wildcard
+        arg = arg.partition(' ')[2]
+        arg = arg.replace('%','*')
+        arg = arg.strip().replace(' ','')
+        
+        atlqarg = atlqarg.strip()
+        if atlqarg=='db' and (arg=='MC' or arg=='OFLP'):
+            self.isMCDB = True
+
+        # default for ReadyForPhysics flag
+        if atlqarg == 'readyforphysics' and not arg: arg = '1'
+            
+        return '--%s "%s"' % (atlqarg, arg)
+
+    def InterpretWithTwoArgs( self, atlqarg, arg, neg ):
+        # '%' is translated into '*' wildcard
+        cmd,sep,arg = arg.partition(' ')
+        arg = arg.replace('%','*')
+        arg = arg.strip()
+
+        # special case for olc lumi
+        if cmd.lower() == 'olc' and 'lumi' in arg.lower():
+            atlqarg = 'olclumi'
+            a = arg.split()
+            if len(a) == 2:
+                arg = a[1].strip()
+            else:
+                print 'ERROR in argument of command "olc lumi": no argument given' 
+                sys.exit()
+
+        # make equal to 'lumi' (for backward compatibility)
+        if cmd.lower() == 'lumi':
+            atlqarg = 'olclumi'
+            if not arg:
+                print 'ERROR in argument of command "olc lumi": no argument given' 
+                sys.exit()
+
+        # special case for 'lhc'
+        if cmd.lower() == 'lhc':
+            if 'stablebeams' in arg.lower():
+                arg,sep,val = arg.partition(' ')
+                val = val.strip().upper()
+                if   val == '1' or val == 'T': val = 'TRUE'
+                elif val == '0' or val == 'F': val = 'FALSE'
+                elif val != 'TRUE' and val != 'FALSE':
+                    print 'ERROR in argument of command "lhc": "%s". Value must be boolean (true/false or 1/0)' % val
+                    sys.exit()
+                arg += ' ' + val
+        
+        atlqarg = atlqarg.strip()
+        if atlqarg=='db' and (arg=='MC' or arg=='OFLP'):
+            self.isMCDB = True
+            
+        return '--%s "%s"' % (atlqarg, arg)
+
+    def InterpretStreams( self, atlqarg, arg, neg ):
+        # '%' is translated into '*' wildcard
+        arg = arg.split()[1:]
+        retstr = "--" + atlqarg.strip() + ' "' + arg[0].replace('%','*')
+        if len(arg)>1:
+            return retstr + " " + self.replaceNumbers(arg[1]) + '"'
+        else:
+            return retstr + '"'
+
+    def InterpretDuration( self, atlqarg, arg, neg ):
+        # sanity check
+        key, sep, arg = arg.partition(' ')
+        units = {'sec': 1, 's': 1, 'm': 60, 'h': 3600, 'd': 86400 }
+        found = False
+        for u, fac in units.items():
+            if u in arg: 
+                arg = arg.replace(u,'')
+                if '-' in arg: sign = '-'
+                else:          sign = '+'
+                arg = "%i%s" % (int(arg.replace(sign,'').strip())*fac,sign)
+                found = True
+        if not found:
+            self.ParseError( "Unit missing in duration tag: '%s' - should be 's', 'm', 'h', or 'd'" % arg )
+
+        return self.InterpretRange( atlqarg, key + ' ' + arg, neg )
+
+    def InterpretMagnets( self, atlqarg, arg, neg ):        
+        key, s, arg = arg.partition(' ')
+
+        # if 'arg' is empty, intepret directly
+        if arg.strip() == '':
+            self.ParseError( 'Keyword "mag(net)" requires argument' )
+
+        # check if 'not' given
+        arg = arg.strip()[0]
+
+        # now interpret
+        if    arg == "" : newarg = "off"
+        else:
+            if    arg == 's': newarg = "solenoid"
+            elif  arg == 't': newarg = "toroid"
+            else:
+                self.ParseError( "cannot interpret of magnetic field: '%s'" % arg )
+            if    neg: newarg += "off"
+            else:      newarg += "on"
+                
+        return "--" + atlqarg.strip() + ' "' + newarg.strip().replace(' ','') + '"'
+
+    @classmethod
+    def DQGetFolder( cls, args, allowWildCards=False ):
+        """interpret dq show command
+        * args are all arguments after dq codeword
+
+        possible formats for 'dq args':
+        1) dq
+        2) dq D
+        3) dq F
+        4) dq F#
+        5) dq D F
+        6) dq #T
+        7) dq D #T
+        8) dq F#T
+        9) dq D F#T
+
+        where
+        D is a komma-separated list of defects or DQ-flags or *, each optionally proceeded by a ! or followed by a \(defect,defect,defect,...)
+        F an folder name [default DEFECTS]
+        T a cool tag [default HEAD]
+
+        If no folder is specified the new defects folder is used
+        """
+
+
+        d = { 'flag': '', 'folder': '',  'tag': ''}
+        if '#' in args:
+            if allowWildCards:
+                m = re.match('(?P<flag>[!.*\w,\-\$\\\]*?)\s*?(?P<folder>\w*)#(?P<tag>[\w-]*)', args)
+            else:
+                m = re.match('(?P<flag>[!\w,\-\$\\\]*?)\s*?(?P<folder>\w*)#(?P<tag>[\w-]*)', args)
+        else:
+            m = re.match('(?P<flag>[!\w,\-\$\\\]*)\s*(?P<folder>[\w-]*)', args)
+
+        if m: d.update(m.groupdict())
+
+        flag   = d['flag'].lower()
+        folder = d['folder'].upper()
+        tag    = d['tag']
+
+        if flag.upper() in cls.dqFolderList:
+            folder = flag.upper()
+            flag   = ''
+
+        if folder == '': folder = 'DEFECTS'
+        if flag   == '': flag   = '*'
+        if tag    != '':
+            tag    = '#' + tag
+            folder = folder + tag
+
+        return flag, folder, tag
+        
+
+    def ShowDQ( self, atlqarg, short, arg ):
+
+        # check if 'arg' has additional arguments (eg, dq PIXB, ...)
+        args = arg.partition(' ')[2]
+
+        # check/insert COOL folder
+        flags, folder, tag = self.DQGetFolder( args, allowWildCards = True )
+
+        newarg = ""
+
+        if folder.startswith('DEFECTS'):
+            # defects DB
+            if flags == "*": # no additional arguments given --> show all flags
+                return '--show "dq DEFECTS%s" ' % tag
+            else:
+                # assume some defects are given, split by ","
+                return ' '.join(['--show "dq %s DEFECTS%s"' % (fl.upper(), tag) for fl in flags.split(',')])
+
+        # replace 'lar' by appropriate choices
+        flags = flags.replace( 'lar','emba,embc,emeca,emecc,heca,hecc,fcala,fcalc' )
+
+        # replace 'tile' by appropriate choices
+        flags = flags.replace( 'tile','tigb,tilba,tilbc,tieba,tiebc' )
+
+        # replace 'trig' by appropriate choices
+        flags = flags.replace( 'trig','l1cal,l1mub,l1mue,l1ctp,trcal,trbjt,trbph,trcos,trele,trgam,trjet,trmet,trmbi,trmuo,trtau,tridt' )
+
+        dqitems = DQChannels()
+        if flags == "*": # no additional arguments given --> show all flags
+            # query over all DQ channels and add to show
+            for key, dqchan in dqitems:
+                newarg += '--show "dq %s %s" ' % (dqchan, folder)
+        else:
+            # assume some DQ channels are given, split by "," or " "
+            argList = flags.split(',')
+            for a in argList:
+                a = a.strip().lower()
+                if self.isVirtualFlag(a):
+                    newarg += '--show "dq %s %s" ' % (a.upper(), folder)
+                else:
+                    for key, dqchan in dqitems:
+                        dc = dqchan.lower()
+                        if a[0:3]==('trg'): # all trigger dq (tr but not trt)
+                            if dc[0:2]=="tr" and dc[2]!='t':
+                                newarg += '--show "dq %s %s" ' % (dqchan, folder)
+                        else:
+                            if a in dc:
+                                newarg += '--show "dq %s %s" ' % (dqchan, folder)
+
+        return newarg
+
+
+
+    def InterpretDQ( self, atlqarg, args, neg ):
+        # the following formats for dq need to work
+        # dq [any] sys1[,sys2] value[+|-]   // note: a system must be given, if you want all the specify '*' e.g. 'dq * g'
+
+        # split, and remove first word ('dq'), be reminded that a split automatically removes _all_ whitespaces
+        args = args.split()[1:]
+
+        hasColor = len(args)>0 and re.match('(n.a.|u|r|y|g|b)[+-]{0,1}$',args[-1].lower())
+        if hasColor:
+            # last argument must be dq value
+            dqflagVal = args[-1]
+            args = args[:-1]
+        else:
+            dqflagVal = 'x'
+
+
+        # check for the 'any' identifier (any --> OR, otherwise AND)
+        useAny = len(args)>0 and (args[0] == 'any')
+        if useAny: args = args[1:]
+
+        # get the cool folders
+        flags, folder, tag = self.DQGetFolder( ' '.join(args) )
+
+        newarg = ""
+
+        if folder.startswith('DEFECTS'):
+            if flags == "*":
+                newarg = "--dq !ANY " + folder
+            else:
+                # assume some DQ channels are given, split by "," or " "
+                dqchans = flags.upper().split(',')
+                if useAny:
+                    newarg += self.InterpretSingleDQ( atlqarg, (','.join(dqchans), dqflagVal, folder) ) + ' '
+                else:
+                    for dqchan in dqchans:
+                        newarg += self.InterpretSingleDQ( atlqarg, (dqchan, dqflagVal, folder) ) + ' '
+
+        else:
+            if not hasColor:
+                self.ParseError( 'DQ flags need to be assigned a value ("n.a.", "u", "g", "y", "r"), eg, "dq PIXB,TIL yellow+" or "dq g"' )
+
+            # treat some old aliases
+            flags = flags.replace( 'lar','emba,embc,emeca,emecc,heca,hecc,fcala,fcalc' )
+            flags = flags.replace( 'tile','tigb,tilba,tilbc,tieba,tiebc' )
+            flags = flags.replace( 'trig','l1cal,l1mub,l1mue,l1ctp,trcal,trbjt,trbph,trcos,trele,trgam,trjet,trmet,trmbi,trmuo,trtau,tridt' )
+
+            # loop over DQ channels
+            dqitems = DQChannels()
+            if flags == "*": # no additional arguments given --> select on all flags
+                # query over all DQ channels and add to show
+                dqchans = [y for (x,y) in dqitems]
+                if useAny:
+                    newarg += self.InterpretSingleDQ( atlqarg, (','.join(dqchans), dqflagVal, folder) ) + ' '
+                else:
+                    for dqchan in dqchans:
+                        newarg += self.InterpretSingleDQ( atlqarg, (dqchan, dqflagVal, folder) ) + ' '
+
+            else:
+                # assume some DQ channels are given, split by "," or " "
+                dqchans = []
+                for a in flags.upper().split(','):
+                    if self.isVirtualFlag(a):
+                        tmpdqchans = [a]
+                    else:
+                        # wildcard -- DANGEROUS --
+                        tmpdqchans = [dqchan for (k,dqchan) in dqitems if a in dqchan]
+                        if 'LUMI' == a and 'LUMIONL' in tmpdqchans: tmpdqchans.remove('LUMIONL')
+                        if 'IDVX' == a and 'MMUIDVX' in tmpdqchans: tmpdqchans.remove('MMUIDVX')
+                    if len(tmpdqchans)==0: self.ParseError( 'Unknown DQ channel: "%s"' % a )
+                    dqchans += tmpdqchans
+
+                if useAny:
+                    newarg += self.InterpretSingleDQ( atlqarg, (','.join(dqchans), dqflagVal, folder) ) + ' '
+                else:
+                    for dqchan in dqchans:
+                        newarg += self.InterpretSingleDQ( atlqarg, (dqchan, dqflagVal, folder) ) + ' '
+
+
+        return newarg
+
+    def isVirtualFlag(self, flag):
+        return '_' in flag
+
+    def InterpretSingleDQ( self, atlqarg, args ):
+        # expand colours
+        if len(args) != 3:
+            self.ParseError( 'ERROR in DQ argument: "%s" --> need <Flag> AND <Status> (len is: %i)' % (fullarg, len(arg)) )
+        flag, col, folder = args
+
+        flag = flag.upper() # upper case status flags
+
+        col = col.lower() # lower case color status only        
+        trcol = ''
+        if not folder.startswith('DEFECTS'):
+            if   col[0] == 'n': trcol = 'n.a.'
+            elif col[0] == 'u': trcol = 'unknown'
+            elif col[0] == 'g': trcol = 'green'
+            elif col[0] == 'y': trcol = 'yellow'
+            elif col[0] == 'r': trcol = 'red'
+            elif col[0] == 'b': trcol = 'black'
+            else:
+                self.ParseError( 'ERROR in DQ argument: "%s" --> uknown status: %s' % (args, col) )
+            if '+' in col: trcol+= '+'
+            if '-' in col: trcol+= '-'
+        else:
+            if   col[0] == 'n': trcol = 'red'
+            elif col[0] == 'u': trcol = 'red'
+            elif col[0] == 'g': trcol = 'green'
+            elif col[0] == 'y': trcol = 'red'
+            elif col[0] == 'r': trcol = 'red'
+            elif col[0] == 'b': trcol = 'red'
+            elif col[0] == 'x': trcol = 'none'
+            else:
+                self.ParseError( 'ERROR in DQ argument: "%s" --> uknown status: %s' % (fullarg, col) )
+
+
+        return "--" + atlqarg.strip() + ' "' + flag + ' ' + trcol + ' ' + folder + '"'
+        
+    def InterpretDetectorMask( self, atlqarg, arg, neg ):
+        arg = (arg.partition(' ')[2]).lower().strip()
+        anyflag = ''
+        if 'any' in arg:
+            arg = arg.replace('any','').strip()
+            if not neg: anyflag = 'A'
+            
+        # check who's in
+        mask = 0
+        for sarg in arg.split(","):
+            for i in range(0,len(self.dName)):
+                # is vetoed ?
+                if i in self.vetoedbits: continue
+                
+                # sanity
+                d = self.dName[i].lower() + self.NotInAll[i]
+                if not ('unknown' in d or 'removed' in d):
+                    # the actual query
+                    if (sarg == 'all' and not 'NotInAll' in d) or sarg in d:
+                        mask |= 1 << i
+
+        # sanity check
+        if mask == 0:
+            print 'ERROR: could not find detector: "%s" in detector list' % arg
+            print self.dName
+            print 'Note: search is case INSENSITIVE'
+            self.ParseError( '' )
+
+        # decide whether detectors are required IN or OUT of partition
+        atlqarg.strip()
+        if neg: atlqarg += 'out'
+        else: atlqarg += 'in'
+
+        return "--" + atlqarg + ' "%i%s' % (mask,anyflag) + '"'
+        
+    def ParseError( self, errtext, pos = -1 ):
+        print ' '
+        print 'ERROR in argument: "%s"' % self.const_arg
+        print "%s" % errtext
+        print ' '
+        sys.exit(1)
+
+    def MatchingQueryArg(self, arg):
+        arg = arg.split()[0] # first word of arg 'r' in 'r 9000-23100'
+        for key in self.queryArgs:
+            short = self.queryArgs[key][0]  # e.g. 'r(uns)'
+            shortNoPar = short.replace('(','').replace(')','')  # e.g. 'runs'
+            if '(' in short:
+                short = short[:short.find('(')] # e.g. 'r'
+            matchesArg = shortNoPar.startswith(arg.lower()) and arg.lower().startswith(short)
+            if matchesArg: return key
+        return None
+
+    def RetrieveQuery( self, findarg ):
+        # check that find part starts with f and remove the f(ind)
+        if findarg[0] != 'f': 
+            self.ParseError( "Argument must begin with 'f(ind)'", 0 )
+        findarg = findarg[findarg.index(' ')+1:]  # remove first word 'f(ind)'
+
+        
+        argList = [x.strip() for x in findarg.split(" and ")]
+
+        newarg = ""
+        for arg in argList:
+            # check if negation
+            negation = False
+            if 'not' in arg:
+                arg = arg.replace("not","").strip()
+                negation = True
+
+            key = self.MatchingQueryArg(arg)
+            if not key:
+                self.ParseError( "Could not find predefined keyword for arg: '%s' in 'find' block" % (arg) )
+            else:
+                short, atlqarg, function = self.queryArgs[key][0:3]
+                newarg += function( atlqarg, arg, negation ) + ' ' 
+
+        return newarg
+
+    def RetrieveShow( self, showarg ):
+        
+        #self.default_show = ["run","events","time"]
+        arglist = self.default_show + [a.strip() for a in showarg.split(' and ') if a.strip()!=''] # split at 'and'
+
+        # show all        
+        if 'all' in arglist:
+            idx = arglist.index('all')
+            arglist[idx:idx+1] = ['ready', 'lhc', 'trigk', 'rel', 'streams', 'det'] # slice it out
+        # show summary
+        if 'summary' in arglist:
+            arglist += ['dur', 'allev', 'str', 'dq' ]
+        # show lhc ...
+        if any([arg.startswith('lhc') for arg in arglist]):
+            arglist += ['olc']
+        # show dqsum & dqplots
+        tmpArgList = [arg.startswith('dqsum') or arg.startswith('dqpl') for arg in arglist]
+        if any(tmpArgList):
+            idx = tmpArgList.index(True)
+            arglist[idx+1:idx+1] = [ 'ready','lumi', 'lhc stablebeams', 'dq', 'ptag', 'trigrates L1_EM30', 'trigrates L1_EM5']
+
+        # interpret argument list
+        newarg = ""
+        for arg in arglist:
+            key = self.MatchingQueryArg(arg) # check argument validity
+            if key == None:
+                self.ParseError( "Could not find predefined keyword for arg: '%s' in 'show' block" % (arg) )
+
+            # interpret argument and append to string
+            (short, atlqarg, dummy, function) = self.queryArgs[key][0:4]
+            newarg += function( atlqarg, short, arg )
+
+        return newarg
+
+
+    def ShowVariable( self, atlqarg, short, arg ):
+        return '--show ' + atlqarg + ' '
+
+    def ShowWithArg( self, atlqarg, short, arg ):
+        if len(arg.split())==1:
+            if   atlqarg == 'olc'       : return '--show olclumi --show olclbdata --show olcfillparams '
+            elif atlqarg == 'luminosity': return '--show "lhc min" --show "%s 0" ' % (atlqarg)
+            else                        : return '--show %s ' % atlqarg
+        else:
+            if   atlqarg == 'olc':
+                return '--show "olclumi %s" --show olcfillparams --show olclbdata ' % arg.partition(' ')[2]
+            elif atlqarg == 'luminosity':
+                return '--show "lhc min" --show "%s %s" ' % (atlqarg, arg.partition(' ')[2])
+            else:
+                return '--show "%s %s" ' % (atlqarg, arg.partition(' ')[2])
+
+    def PostProcessShowArgs( self, showargs ):
+        
+        # remove special duplicate
+        if len(showargs.split('lhc')) >= 3: showargs = showargs.replace('--show "lhc min"','')
+
+        # remove duplicates in show block
+        duples  = ['--show %s' % d.strip() for d in showargs.split('--show') if d.strip()!='']
+        uniques = reduce(lambda l, x: (x not in l and l.append(x)) or l, duples, [])
+        showargs = ' '.join(uniques)
+
+        return showargs
+        
+
+    def ParseArgument( self, const_arg ):
+        self.const_arg = const_arg
+        arg = const_arg.strip()
+
+        # first separate the three parts ('/' is separator) and strip the spaces around each
+        findarg, showarg, otherarg = [x.strip() for x in (self.const_arg.split('/')+['',''])[0:3]]
+
+        # check that show part starts with sh and remove the sh(ow)
+        if showarg!='':
+            if showarg[0:2] != 'sh': 
+                self.ParseError( "Show block must begin with 'sh(ow)'", 0 )
+            showarg = showarg[showarg.index(' ')+1:]  # remove first word 'sh(ow)'
+            #showarg = ' and ' + showarg # and put ' and ' in front
+        else:
+            if ' sh ' in findarg or ' sho ' in findarg or ' show ' in findarg:
+                self.ParseError( "Show block must be separated by '/' from find condition'", 0 )
+
+        # retrieve the query and show arguments (and check for input errors)
+        queryarg = self.RetrieveQuery( findarg.strip() )
+        shwarg   = self.RetrieveShow ( (showarg).strip() )
+
+        # add 'lhc' to show if 'olclumi' query
+        # necessary because of stable beams information
+        if '--olclumi' in queryarg and not 'stablebeams' in queryarg: queryarg += '--lhc "stablebeams TRUE" '
+
+        shwarg   = self.PostProcessShowArgs( shwarg )
+
+        
+        # interpret other arguments
+        nodef_flag = False
+        oargs = otherarg.split()
+        # always verbose for the time being...
+        #if not 'verbose' in queryarg: queryarg += ' --verbose'
+        extraargs = {'verbose' : '--verbose'}
+        idx = 0
+        while idx < len(oargs):
+            oa = oargs[idx]
+            if oa == 'v':        extraargs['verbose'] = '--verbose'
+            elif oa == 'noroot': extraargs['noroot']  = '--noroot'
+            elif oa == 'root':   extraargs['root']  = '--root'
+            elif oa == 'nohtml': extraargs['nohtml']  = '--nohtml'
+            elif oa == 'html':   extraargs['html']  = '--html'
+            elif oa == 'utc':    extraargs['utc']  = '--utc'
+            elif oa == 'nogrl':  extraargs['nogrl']  = '--nogrl'
+            elif oa == 'grl' or oa == 'xmlfile': extraargs['xmlfile']  = '--xmlfile MyLBCollection.xml:MyLBCollection'
+            elif oa == 'nodef' : nodef_flag = True
+            elif idx>0 and (oargs[idx-1]=='grl' or oargs[idx-1]=='xmlfile'):
+                extraargs['xmlfile']  = '--xmlfile %s' % oa
+            else:
+                print "Extra argument '%s' unknown. Exiting." % oa
+                sys.exit(1)
+            idx+=1
+
+        if 'verbose' in extraargs:
+            print "Parser: '%s'" % self.const_arg
+            print '  find argument: "%s"' % findarg.strip()
+            print '  show argument: "%s"' % showarg.strip()
+            print '  extra argument: "%s"' % otherarg.strip()
+
+        # no defaults for MC
+        if self.isMCDB: nodef_flag = True
+
+        # add default arguments
+        if not nodef_flag:
+            for key, argument, defaultvalue in [ (x[0],x[1][1],x[1][5]) for x in self.queryArgs.items()]:
+                if not argument in queryarg and defaultvalue != "":
+                    queryarg += " --" + argument + ' "' + defaultvalue + '"'
+
+        extraarg = ' '.join(extraargs.values())
+
+        fullarg = '%s %s %s' % (queryarg, shwarg, extraarg)
+
+        return fullarg
+
+
+# command line driver for convenience
+if __name__=='__main__':
+
+    from CoolRunQuery.AtlRunQueryParser import ArgumentParser
+    ap = ArgumentParser()
+
+    if len(sys.argv) <= 1:
+        print 'No query argument given'
+        sys.exit(1)
+
+    if sys.argv[1].lower() == 'detmask':
+        print 'Detector mask %s correspond to:\n%s' % (sys.argv[2], DecodeDetectorMask( int(sys.argv[2] )))
+        sys.exit()
+
+    if sys.argv[1].lower() == 'help':
+        ap.ParserUsage()
+        sys.exit(1)
+ 
+    atlqueryarg = ap.ParseArgument( ' '.join(sys.argv[1:]) )
+    print "\nAtlRunQuery.py %s\n" % atlqueryarg
+
diff --git a/Database/CoolRunQuery/python/AtlRunQueryQueryConfig.py b/Database/CoolRunQuery/python/AtlRunQueryQueryConfig.py
new file mode 100644
index 00000000000..96d41484461
--- /dev/null
+++ b/Database/CoolRunQuery/python/AtlRunQueryQueryConfig.py
@@ -0,0 +1,24 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+from utils.AtlRunQueryUtils import Enumerate
+
+import time
+
+class QC:
+    localtime = True
+    timezone = ('CET','CEST')
+    datapath = ''
+
+    @classmethod
+    def tzdesc(cls):
+        return QC.timezone[1] if QC.localtime else 'UTC'
+
+    @classmethod
+    def settimezone(cls):
+        time.tzname = QC.timezone
+
+    @classmethod
+    def localStr(cls):
+        return "local" if QC.localtime else 'UTC'
+
+
diff --git a/Database/CoolRunQuery/python/AtlRunQueryRun.py b/Database/CoolRunQuery/python/AtlRunQueryRun.py
new file mode 100644
index 00000000000..d2de03b180f
--- /dev/null
+++ b/Database/CoolRunQuery/python/AtlRunQueryRun.py
@@ -0,0 +1,2209 @@
+#!/bin/env python
+
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+#
+# ----------------------------------------------------------------
+# Script : AtlRunQueryRun.py
+# Project: AtlRunQuery
+# Purpose: Library with the Run class
+# Authors: Andreas Hoecker (CERN), Joerg Stelzer (DESY)
+# Created: Feb 10, 2009
+# ----------------------------------------------------------------
+#
+from __future__ import with_statement
+from CoolRunQuery.utils.AtlRunQueryTimer import timer
+
+from utils.AtlRunQueryUtils        import addKommaToNumber, filesize, prettyNumber, coolDbConn, RunPeriods
+from utils.AtlRunQueryLookup       import DecodeDetectorMask
+from utils.AtlRunQueryIOV          import IOVRange,IOVTime
+from utils.AtlRunQueryLookup       import DQChannelDict, LArConfig, isDQ, OLCAlgorithms
+from output.AtlRunQueryRoot        import makeLBPlot, makeLBPlotList, makeTimePlotList, makeLBPlotSummaryForLHC, makeBSPlots, SaveGraphsToFile
+from AtlRunQueryQueryConfig        import QC
+from utils.AtlRunQueryMemUtil      import memory
+from selector.AtlRunQuerySelectorBase import DataKey
+
+import math
+import time, calendar
+import sys
+import re
+import datetime
+import subprocess
+import os.path
+import urllib
+from copy import deepcopy
+from collections import defaultdict
+
+_fW = {'Run' : 12, 'NLB': 5, 'Time': 50, '#Events': 10, 'Stream': 10}
+
+class DataEntry:
+    def __init__(self, iov, value, reject=False):
+        self.iov = iov
+        self.lbrange = (self.iov.startTime.lb, self.iov.endTime.lb) # note that the end lb is not part of the iov
+        self.value = value
+        self.rejected = reject
+
+    def __str__(self):
+        return "[%i-%i) %s %r" % (self.lbrange[0], self.lbrange[1], "r" if self.rejected else "a", self.value)
+
+    def __repr__(self):
+        return "<DataEntry %s>" % self
+
+    def __len__(self):
+        length_L = self.lastlb-self.startlb+1
+        if length_L>0x7FFFFFFF: length_L = 0x7FFFFFFF
+        return int(length_L)
+
+    @property
+    def startlb(self):
+        return self.lbrange[0]
+
+    @property
+    def endlb(self):
+        return self.lbrange[1]
+
+    @property
+    def lastlb(self):
+        return ((0x100000000 + self.endlb)-1) & 0xFFFFFFFF
+
+    def contains(self, lb):
+        return self.lbrange[0]<=lb and lb<self.lbrange[1]
+
+    def intersects(self,lbrange):
+        lbstart, lbend = lbrange
+        return self.contains(lbstart) or self.contains(lbend-1) or (lbstart<=self.lbrange[0] and self.lbrange[1]<lbend)
+
+    def pickled(self):
+        v = self.value.pickled() if hasattr(self.value,'pickled') else self.value
+        return { 'firstlb' : self.startlb, 'lastlb' : self.lastlb, 'value' : v, 'accepted' : not self.rejected }
+
+
+class DataEntryList(list):
+    def __init__(self, key, run):
+        super(DataEntryList,self).__init__()
+        self.key = key
+        self.run = run
+
+    def atLB(self,lb):
+        for e in self:
+            return [x for x in self if x.contains(lb)]
+        return None
+
+    def stops(self):
+        return set([e.startlb for e in self]).union(set([e.lastlb+1 for e in self]))
+
+    @property
+    def lastlb(self):
+        return max([e.lastlb for e in self])
+
+    @property
+    def endlb(self):
+        return max([e.endlb for e in self])
+
+    def pickled(self):
+        return [e.pickled() for e in self]
+            
+
+class RunData:
+
+    # this is a temporary thing to get the DQDefects working, I still want to change the way the selectors work
+    DQKeys = []
+    DQLogic = []
+    DefectSelector = None
+
+    def __init__(self,run):
+        self.__run_o  = run
+        self.run  = run.runNr
+        self.data = {}
+        self.data_current_lb = {}
+        self.current_lb = 0
+        self.stops = []
+
+    def __contains__(self,k):
+        if type(k)==DataKey:
+            return k in self.data or k.ResultKey in self.data
+        return k in self.data
+
+    def __getitem__(self,k):
+        if not k in self:
+            self.data[k] = DataEntryList(key=k, run=self.run)
+            return self.data[k]
+        else:
+            if type(k)==DataKey:
+                return self.data[k] if k in self.data else self.data[k.ResultKey]
+            return self.data[k]
+
+    def __setitem__(self,k,value):
+        self.data[k]=value
+
+    def __iter__(self):
+        self.stops = self._calcStops()
+        for lb in self.stops: # the last stop is the LB after the last
+            if lb>self.__run_o.lastlb: break
+            self._setLB(lb)
+            yield self
+
+    def keys(self):
+        return self.data.keys()
+
+    @property
+    def runNrS(self):
+        return str(self.run)
+
+    @property
+    def lb(self):
+        return self.current_lb
+
+    def lbend(self,lb=None):
+        if lb==None: lb=self.current_lb
+        return self.stops[self.stops.index(lb)+1]-1
+
+    @property
+    def NrLBs(self):
+        return "%i" % max([el.lastlb for el in self.data.values()])
+
+    @property
+    def result(self):
+        return self.data_current_lb
+
+    @property
+    def isRejectedCurrentLB(self):
+        #print "Checking Reject for LB",self.lb,"-",self.lbend()
+        need_dq_check = False
+        for k,s in self.data_current_lb.items():
+            if k in RunData.DQKeys:
+                need_dq_check = True
+                continue # exclude DQ from this, since it gets its own treatment
+            if s==None: continue
+            for e in s:
+                if e.rejected:
+                    return True
+        if need_dq_check:
+            if self.isDQRejected():
+                return True
+        if self.isDQDefectRejected():
+            return True
+        return False
+
+    def isDQRejected(self):
+        for orGroup in RunData.DQLogic:
+            groupAccept = False
+            for k in orGroup:
+                if len(self.data_current_lb[k])==0:
+                    passes = False
+                else:
+                    passes = not self.data_current_lb[k][0].rejected
+                if passes:
+                    groupAccept = True
+                    break
+            if not groupAccept:
+                return True
+        return False
+
+    def isDQDefectRejected(self):
+        if not 'DQ' in self.data_current_lb: return False
+        return not RunData.DefectSelector(self.data_current_lb['DQ'])
+
+
+    @property
+    def isRejected(self):
+        for s in self:
+            if not s.isRejectedCurrentLB: return False
+        return True
+
+
+    def isReady(self,lb=None):
+        if not 'Ready for physics' in self:
+            raise RuntimeError("No ready data available")
+        readydata = [x for x in self.data['Ready for physics'] if x.value=='1']
+        if lb==None:
+            return readydata
+        if type(lb)==int:
+            for x in readydata:
+                if x.contains(lb): return True
+            return False
+        if type(lb)==tuple and len(lb)==2:
+            for x in readydata:
+                if x.intersects(lb): return True
+            return False
+        raise RuntimeError("Can't interpret lb to check isReady(lb=%r)" % lb)
+            
+        
+    def getLBRanges(self,activeOnly=False):
+        last_lb = self.__run_o.nr_lb
+        a = [(int(data.lb),not data.isRejectedCurrentLB) for data in self if data.lb<=last_lb]
+        #a = [(int(data.lb),not data.isRejectedCurrentLB) for data in self]
+        if not a: return []
+        start,state = a[0]
+        ranges = []
+        for x in a[:-1]:
+            if x[1] == state: continue
+            ranges += [(state, start, x[0])]
+            start,state = x
+        last_start,last_state = a[-1]
+        if last_state==state:
+            ranges += [(state, start, last_lb+1)]
+        else:
+            ranges += [(state, start, last_start)]
+            ranges += [(last_state, last_start, last_lb+1)]
+        if activeOnly:
+            return [x for x in ranges if x[0]==True]
+        else:
+            return ranges
+
+    def _setLB(self,lb):
+        self.current_lb = lb
+        self.data_current_lb = dict([(k,entrylist.atLB(lb)) for k,entrylist in self.data.items()])
+
+    def _calcStops(self):
+        stops = set()
+        for entrylist in self.data.values():
+            stops.update(entrylist.stops())
+        return sorted(list(stops))
+
+    def addResult(self, iov, k, value, reject):
+        if not iov:
+            iov = IOVRange(runStart=self.run, lbStart=1, runEnd=self.run+1, lbEnd=0)
+        self[k].append(DataEntry(iov=iov, value=value, reject=reject))
+
+    def astxt(self):
+        s = ""
+        if Run.showrunnr:
+            s += "%*s %*s  " % (4, self.lb, 4, self.lbend())
+        s += ("r" if self.isRejectedCurrentLB else "a")
+        if Run.showtime:        s += "%*s  " % (_fW['Time'],'')
+        if Run.showduration:    s += "            "
+        for k in Run.SortedShowOrder():
+            k = k.ResultKey
+            w = 10
+            if k in _fW: w = _fW[k]
+            v=""
+            if self.data_current_lb[k]:
+                v = [x.value for x in self.data_current_lb[k]][0]
+                if v==None: v=""
+            if k == "#Events" or k[0:4] == "STR:" or k=="TriggerMenu" or k=="TriggerRates" or k=="olc:bcidmask":
+                v = ""
+            s += "%*s  " % (w,v)
+        return s
+
+
+
+
+
+class Run:
+    ShowOrder = []
+    _SortedShowOrder = None
+    DisplayOrder = map(re.compile,['#Events','Ready','lhc:|olc:', 'TriggerMenu|SMK|Release|L1 PSK|HLT PSK|BGS|TriggerRates', 'bs:', 'STR:', 'DQ|SHIFTOFL:|LBSUMM:', 'lar:', 'Detector','.*'])    
+    PromptCalibRuns = []
+    NemoTasks = {}
+    showrunnr = False
+    showtime = False
+    showduration = False
+    writehtml = False
+    bgcolor = "1"
+    totevents = [0, 0]
+    runnropen = -1
+    showCAFLinks = False
+    Datapath = ''
+    Fieldinfo = {}
+    GlobalTooltips = []
+    BeamspotSource = ''
+    runPeriods = RunPeriods()
+    TmpBoxContent = ''
+
+    @classmethod
+    def AddToShowOrder(cls,key):
+        #print "ADDING TO SHOWORDER  %r" % key
+        if not key in cls.ShowOrder:
+            cls.ShowOrder += [ key ]
+
+    @classmethod
+    def addGlobalToolTip(cls, var, content):
+        cls.GlobalTooltips += ['dw_Tooltip.content_vars["%s"] = {content: \'%s\'};' % (var, content.replace("'","&#39;"))]
+    
+    def __init__(self, runNr=0):
+        self.runNr = runNr
+        self.sor = 0
+        self.eor = 0
+        self.lastlb = 0
+        self.selDataIncomplete = False
+        self.showDataIncomplete = False
+        self.xvecStb = []
+        self.hasStableBeamsInfo = False
+        # the results of the query index by query key
+        self.result = {}
+        # the run statistics index by query key (filled in selector.runAfterQuery)
+        self.stats = {}
+        # the start times of all lumiblocks [start_LB1, start_LB2, start_LB3, ..., start_LBN]
+        self.lbtimes = []
+        self.tooltips = []
+        self.data = RunData(run=self)
+        # luminosity unil
+        self.lumiunit    = 1.0 # default unit
+        self.lumiunittxt = 'nb'
+        self.instlumiunittxt = '30'
+        self.givepeakmuinfo = True
+        if self.runNr > 168206 and self.runNr <= 170482:
+            self.lumiunit = 1.0e6 # unit is mbarn for heavy ions
+            self.lumiunittxt = 'mb'
+            self.instlumiunittxt = '24'
+            self.givepeakmuinfo = False
+
+
+    @property
+    def runNrS(self):
+        return "%i" % self.runNr
+
+    @property
+    def data_current_lb(self):
+        return self.data.data_current_lb
+
+    @property
+    def NrLBs(self):
+        return "%i" % self.lastlb
+
+    @property
+    def nr_lb(self):
+        return self.lastlb
+
+    def addToolTip(self, var, content):
+        self.tooltips += ['dw_Tooltip.content_vars["%s\"] = {content: \'%s\'};' % (var, content.replace("'","&#39;"))]
+
+    def getStableBeamsVector(self):
+        if len(self.xvecStb)==0 and 'lhc:stablebeams' in Run.ShowOrder and 'lhc:stablebeams' in self.data:
+            entries = self.data['lhc:stablebeams']
+            for entry in entries:
+                if entry.startlb == 0: continue
+                if 'true' in entry.value.lower():
+                    self.xvecStb += range(entry.startlb,entry.endlb)
+            self.hasStableBeamsInfo = len(self.xvecStb)>0
+        return self.hasStableBeamsInfo, self.xvecStb
+
+    @classmethod
+    def SortedShowOrder(cls):
+        if Run._SortedShowOrder != None:
+            if len(Run._SortedShowOrder) != len(Run.ShowOrder):
+                raise RuntimeError, "Sorting not up-to-date %i %i" % (len(Run._SortedShowOrder), len(Run.ShowOrder) )
+            return Run._SortedShowOrder
+        hk = []
+        for order in Run.DisplayOrder:
+            for x in Run.ShowOrder:
+                if not order.match(x.ResultKey): continue
+                if x in hk: continue
+                hk += [x]
+        Run._SortedShowOrder = hk
+        if len(Run._SortedShowOrder) != len(Run.ShowOrder):
+            raise RuntimeError, "Sorting not up-to-date after creation %i %i" % (len(Run._SortedShowOrder), len(Run.ShowOrder) )
+        return Run._SortedShowOrder
+    
+    @classmethod
+    def headerkeys(cls):
+        hk = []
+        if Run.showrunnr:    hk += ['Run','Links','#LB']
+        if Run.showtime:     hk += ['Start and endtime (%s)' % QC.localStr()]
+        if Run.showduration: hk += ['Duration']
+        for x in cls.SortedShowOrder():
+            x = x.ResultKey
+            if 'L1 PSK' in x or ('olc:' in x and ('beam1bunches' in x or 'beam2bunches' in x or 'collbunches' in x or 'beam1intensity' in x or 'beam2intensity' in x)): continue
+            hk += [x]
+        return hk
+
+
+    @classmethod
+    def header(cls):
+        if Run.writehtml:
+            # flags...
+            hasLAr = False
+            hasLHC = False
+            hasBS  = False
+            ofllumiFlag = False
+            s = '<tr>\n'
+            if Run.showrunnr:    s += '  <th>Run</th><th>Links</th><th>#LB</th>\n'
+            if Run.showtime:
+                s += '  <th>Start and endtime (%s)</th>\n' % QC.localStr()
+            if Run.showduration: s += '  <th>Duration</th>\n'
+            for ik, data_key in enumerate(Run.SortedShowOrder()):
+                k = data_key.ResultKey
+                if k[0:4] == 'STR:':       s += '  <th><font size="-2">%s_<BR>%s</font></th>' % tuple(k[4:].split('_',1))
+                elif k[0:8] == "Detector": s += '  <th>%s</th>' % k
+                elif "SolCurrent" in k:    s += '  <th>Solenoid<br>current&nbsp;(A)</th>'
+                elif "TorCurrent" in k:    s += '  <th>Toroid<br>current&nbsp;(A)</th>'
+                elif 'DQ' == k:
+                    s += '  '
+                    matching_names = dict(Run.Fieldinfo['DQ']['DefMatch'])
+                    first = True
+                    for channelname in Run.Fieldinfo['DQ']['DefChannels']:
+                        tip = "defect_match_%s" % channelname
+                        info = "%s # %s" % (channelname if channelname!="" else "*",data_key._second_internal_key if data_key._second_internal_key!="" else "HEAD")
+                        s += '<th style="align:center; white-space:nowrap; padding-right: 10px; padding-left: 10px; ">'
+                        s += 'Data Quality<br><span class="showTip %s tooltip" style="font-weight:normal; font-size:80%%">(%s)</span>' % (tip, info)
+                        if first:
+                            s += '<div style="font-size: xx-small; cursor: pointer;" onclick="toggle_dq(this)">[show tolerable]</div>'
+                            first = False
+                        s += '</th>'
+                        
+                        a = sorted(matching_names[channelname])
+                        #horizontal
+                        #slices = [slice(x,len(a)+3,4) for x in range(4)]
+                        #zipped = zip(*map((a+4*['']).__getitem__,slices))
+                        #vertical
+                        ncol=4
+                        n = 4*[len(a)/4]
+                        for x in range(len(a)-4*(len(a)/4)):
+                            n[x]+=1
+
+                        cx = 0
+                        slices = []
+                        for x in n:
+                            slices += [slice(cx,cx+x)]
+                            cx+=x
+                        m = map(a.__getitem__,slices)
+                        for x in range(1,len(m)): m[x]+=['']
+                        zipped = zip(*m)
+                        
+                        tts = ''
+                        for z in zipped:
+                            tts += '<tr>%s</tr>' % ''.join(["<td>%s</td>"% x for x in z])
+                        content = '<table style="width:500px; font-size:80%%;">%s</table>' % tts
+                        Run.addGlobalToolTip(tip,content)
+                    
+                elif isDQ(k):
+                    foldertag,flag = k.split(':')
+
+                    if flag in Run.Fieldinfo:
+                        tipname = 'dqvfdesc_%s' % flag
+                        commentbox = '%s' % (Run.Fieldinfo[flag])
+                        Run.addGlobalToolTip(tipname, commentbox)
+                        s += '<th class="showTip %s tooltip" style="cursor:pointer">' % tipname
+                    else:
+                        s += '  <th>'
+
+                    s += '<font size="-1">%s</font><BR><font style="font-weight:normal;font-size:70%%">' % flag
+                    if '#' in foldertag:
+                        s += '(%s #<br>%s)' % tuple(foldertag.split('#',1))
+                    else:
+                        s += '(%s)' % (foldertag)
+                    s += '</font></th>'
+                    
+                elif k == "L1 PSK":        continue
+                elif k == "HLT PSK":       s += '  <th>Prescale keys</th>' 
+                elif k == "Release":       s += '  <th>HLT Release</th>'
+                elif k == "Datasets":      s += '  <th>Tier-0 Datasets</th>'
+                elif k == '#Events (incl. calib.)': s += '  <th>#Events<br><font size="-2">(incl.&nbsp;calib.)</font></th>'
+                elif k == '#Events (streamed)'    : s += '  <th>#Events<br><font size="-2">(streamed)</font></th>'
+                elif 'lar:' in k:
+                    hasLAr = True                   
+                    if   'runtype'        in k: s += '  <th><font size="-2">Run type</font></th>' 
+                    elif 'nsamples'       in k: s += '  <th><font size="-2">#Samples</font></th>' 
+                    elif 'firstsample'    in k: s += '  <th><font size="-2">1st sample</font></th>' 
+                    elif 'format'         in k: s += '  <th><font size="-2">Format</font></th>' 
+                    else:
+                        print 'ERROR: unknown LAr option "%s"' % k
+                        sys.exit(1)
+                elif 'lhc:' in k:
+                    if   'fillnumber'     in k: s += '  <th>  LHC Fill</th>'
+                    elif 'stablebeams'    in k:
+                        s += '  <th>Stable beams</th>'
+                        if 'lhc:beammode' in Run.ShowOrder:   s += '  <th>Beam mode</th>' 
+                        if 'lhc:beamenergy' in Run.ShowOrder:
+                            s += '  <th>Beam&nbsp;energy and&nbsp;intensities</th>'
+                            hasLHC = True
+                            
+                    elif 'beamenergy'     in k: continue # included in 'fillbeams' summary
+                    elif 'nbunch1'        in k: s += '  <th>#Bunches B1 <br><font size="-2"><b>(NOT YET RELIABLE)</b></font></th>' 
+                    elif 'nbunch2'        in k: s += '  <th>#Bunches B2 <br><font size="-2"><b>(NOT YET RELIABLE)</b></font></th>' 
+                    elif 'nbunchcoll'     in k: s += '  <th>#Bunches<br>colliding <br><font size="-2"><b>(NOT YET RELIABLE)</b></font></th>' 
+                    elif 'beamtype1'      in k: s += '  <th>Beam type&nbsp;B1</th>' 
+                    elif 'beamtype2'      in k: s += '  <th>Beam type&nbsp;B2</th>' 
+                    elif 'machinemode'    in k: s += '  <th>LHC mode</th>' 
+                    elif 'beammode'       in k: continue
+                    else:
+                        print 'ERROR: unknown LHC option "%s"' % k
+                        sys.exit(1)
+                elif 'ofllumi:' in k:
+                    if not ofllumiFlag:
+                        s += '  <th>Offline Luminosity<br><font style="font-weight:normal">(%s)</font></font></th>' % k.split(':')[-1]
+                        ofllumiFlag = True
+                elif 'bs:' in k:
+                    hasBS = True
+                    kt = k.replace('bs:','')
+                    if 'bs:Pos' in k or 'bs:Sig' in k:
+                        s += '  <th><font size="-2">%s<br><font style="font-weight:normal">(mm)</font></font></th>' % kt
+                    elif 'bs:Tilt' in k:
+                        s += '  <th><font size="-2">%s<br><font style="font-weight:normal">(rad)</font></font></th>' % kt
+                    else:
+                        s += '  <th><font size="-2">%s</font></th>' % kt
+                elif 'BPM' in k:  s += '  <th>Beam&nbsp;Position Monitors&nbsp;(BPM)</th>' 
+                elif 'olc:' in k:
+                    if 'olc:lumi' in k:                    
+                        tp1, tp2, chan = k.split(':')
+                        try:
+                            chan = float(chan)
+                        except ValueError:
+                            chan = -1
+                        if OLCAlgorithms.has_key(chan): chanstr = OLCAlgorithms[chan]
+                        else:                           chanstr = 'UNKNOWN'
+                        s += '  <th>Online&nbsp;del.&nbsp;Luminosity&nbsp;<font size="-2"><br><font style="font-weight:normal">[%s]</font></font></th>' % chanstr
+                    elif 'beam1bunches' in k:  continue # not used anymore
+                    elif 'beam2bunches' in k:  continue # not used anymore
+                    elif 'collbunches'  in k:  continue # not used anymore
+                    elif 'bcidmask'     in k:  s += '  <th>Bunch&nbsp;structure</th>'
+                    elif 'beam1intensity' in k: continue # included in 'fillbeams' summary
+                    elif 'beam2intensity' in k: continue # included in 'fillbeams' summary
+                    else:
+                        s += '  <th>%s</th>' % k
+
+                elif 'BGS Key' in k: s += '  <th>Bunch group key</th>'
+                        
+                else:
+                    s += '  <th>%s</th>' % k
+                s += '\n'
+            s += '</tr>'
+
+            # generate a second header line
+            secondheader = ''
+            patterns = [ ('lar:',          'LAr configuration'),
+                         ('lhc:|olc:',     'LHC and online luminosity information' if any(['olc:' in x for x in Run.headerkeys()]) else 'LHC information' ),
+                         ('bs:',           'Beam spot parameters (%s)' % Run.BeamspotSource),
+                         ('STR:',          'Data stream statistics'),
+                         ('TriggerMenu|SMK|Release|L1 PSK|HLT PSK|BGS|TriggerRates', 'Trigger information'),
+                         ('SHIFTOFL:',     'Data quality (SHIFTOFL)'),
+                         ('LBSUMM:',       'Data quality (LBSUMM)')
+                         ]
+
+            order = []
+            for (p,hdesc) in patterns:
+                matchedpositions = [idx for (idx,head) in enumerate(Run.headerkeys()) if re.match(p,head)]
+                #print "pattern",p,matchedpositions
+                if matchedpositions: order += [(min(matchedpositions),max(matchedpositions),hdesc)]
+            order.sort()
+
+            mergeempty = True
+            if len(order)>0:
+                current=0
+                for th in order:
+                    if mergeempty:
+                        if th[0]>current:
+                            secondheader += '<th colspan="%s"></th>'  % (th[0]-current)
+                    else:
+                        for x in xrange(th[0]-current): secondheader += '<th></th>'
+                    secondheader += '<th colspan="%s">%s</th>' % (th[1]-th[0]+1,th[2])
+                    current=th[1]+1
+                if len(Run.headerkeys())>current:
+                    if mergeempty:
+                        secondheader += '<th colspan="%s"></th>' % (len(Run.headerkeys())-current)
+                    else:
+                        for x in xrange(len(Run.headerkeys())-current): secondheader += '<th></th>'
+                secondheader = "<tr>%s</tr>" % secondheader
+            
+
+            s = '<thead>' + secondheader + s + '</thead>\n'
+
+            # Global (run independent) tooltips
+
+            # OLC
+            if any([k for k in Run.ShowOrder if "olc:lumi" in k.ResultKey]):
+                boxcontent = '<font color="#AA0000">Click&nbsp;to&nbsp;enlarge&nbsp;figure and&nbsp;to&nbsp;obtain&nbsp;online&nbsp;integrated&nbsp;luminosity&nbsp;versus&nbsp;LB</font>'
+                Run.addGlobalToolTip("OLCLumi", boxcontent)
+
+            # OFLLumi
+            if any([k for k in Run.ShowOrder if "ofllumi" in k.ResultKey]):
+                boxcontent = '<font color="#AA0000">Click to obtain offline integrated luminosity versus LB</font>'
+                Run.addGlobalToolTip("OFLLumi", boxcontent)
+
+            # OFLBS - beamspot
+            if any([k for k in Run.ShowOrder if "bs:" in k.ResultKey]):
+                boxcontent = '<font color="#AA0000">Click to obtain %s beamspot versus LB</font>' % (Run.BeamspotSource.split()[0])
+                Run.addGlobalToolTip("OFLBS", boxcontent)
+
+            # BPM info
+            if any([k for k in Run.ShowOrder if "BPM" == k.ResultKey]):
+                boxcontent = '<font color="#AA0000">Click to enlarge figure</font>'
+                Run.addGlobalToolTip("BPM", boxcontent)
+
+            # LHC Summary
+            if any([k for k in Run.ShowOrder if "lhc:fillnumber" in k.ResultKey]):
+                boxcontent = '<font color="#AA0000">Click to enlarge figure</font>'
+                Run.addGlobalToolTip("LHCSummary", boxcontent)
+
+        else:
+            s = ''
+            for l in [1,2]:
+                if Run.showrunnr:
+                    if l==0: s += '%-*s  %*s  ' % (_fW['Run'],'Run',_fW['NLB'],'#LB')
+                    if l==1: s += '%-*s  %*s  ' % (_fW['Run'],' ',_fW['NLB'],' ')
+                s+=" " # accept/reject flag
+                if Run.showtime:
+                    hstr = 'Start and endtime (%s)' % QC.localStr()
+                    if l==0:
+                        s += '%*s  ' %(_fW['Time'],hstr)
+                    if l==1: s += '%*s  ' %(_fW['Time'],' ')
+                if Run.showduration:
+                    if l==0: s += '%*s  ' % (10,'Duration')
+                    if l==1: s += '%*s  ' % (10,' ')
+                for k in Run.SortedShowOrder():
+                    if k.Type == DataKey.STREAM:
+                        w = max(len(k.Header)-k.Header.find('_'),_fW['Stream'])
+                        if l==0: s += '%*s  ' % (w,k.Header[4:k.Header.find('_')])
+                        if l==1: s += '%*s  ' % (w,k.Header[k.Header.find('_')+1:])
+                    else:
+                        w = 10
+                        if k in _fW: w = _fW[k.ResultKey]
+                        if l==0: s += '%*s  ' % (w,k.Header)
+                        if l==1: s += '%*s  ' % (w,' ')
+                if l==0: s+='\n'
+        return s
+
+    def addResult(self, resDictKey, value, iov=None, reject=False):
+        if resDictKey=='DQ' and value=='n.a.': return
+        #print "Run.addResult:",resDictKey, value, iov,"reject=",reject
+        if not resDictKey in self.result:
+            self.result[resDictKey] = value
+        if iov:
+            if iov.startTime.lb>self.lastlb: return # sometimes there are IOVs completely outside the run e.g. run 165821 DQ SHIFTOFL
+            iov.endTime = min(iov.endTime, IOVTime(self.runNr,self.lastlb+1) ) 
+        self.data.addResult(iov, resDictKey, value, reject)
+
+    def runlinks(self):
+        s = ''
+        # DS
+        if time.gmtime(self.sor/1.E9).tm_year >= 2010:
+            s  += '    <a href="http://atlas.web.cern.ch/Atlas/GROUPS/DATAPREPARATION/DataSummary/%i/run.py?run=%i" target="_blank" title="Data summary information for run %i"><font size="-3">DS</font></a>,&nbsp;\n' % (time.gmtime(self.sor/1.E9).tm_year, self.runNr, self.runNr)
+        # RS
+        s += '    <a href="http://atlas-service-db-runlist.web.cern.ch/atlas-service-db-runlist/php/runDetails.php?run=%i" target="_blank" title="Run summary information for run %i"><font size="-3">RS</font></a>,&nbsp;\n' % (self.runNr, self.runNr)
+        # BS
+        s += '    <a href="https://atlas-beamspot.cern.ch/webapp/jobs/?r=%i" target="_blank" title="Beam spot fit information for run %i"><font size="-3">BS</font></a>,&nbsp;\n' % (self.runNr, self.runNr)        
+        # AMI
+        s += '    <a href="https://ami.in2p3.fr/AMI/servlet/net.hep.atlas.Database.Bookkeeping.AMI.Servlet.Command?Converter=/AMIXmlToAMIProdHtml.xsl&Command=FormBrowseDatasetPerRun+-runNumber=%i" target="_blank" title="AMI reference for run %i"><font size="-3">AMI</font></a>,&nbsp;\n' % (self.runNr, self.runNr)
+        # DQ
+        s += '    <a href="http://atlasdqm.web.cern.ch/atlasdqm/DQBrowser/makeMatrix.php?selection=All&run=%g&runup=&dbinstance=COMP200_SHIFTOFL&tag=HEAD" target="_blank" title="Browse detailed data quality entries for run %i (uses SHIFTOFL folder in COMP200 conditions database)"><font size="-3">DQ</font></a>,<br>\n' % (self.runNr, self.runNr)
+        # ELOG
+        s += '    <a href="https://atlasop.cern.ch/elog/ATLAS/ATLAS/?mode=full&reverse=0&reverse=1&npp=20&ma=1&ya=2008&last=3064&subtext=%i&sall=0" target="_blank" title="Search for ELOG entries on run %i"><font size="-3">ELOG</font></a>,&nbsp;\n' % (self.runNr, self.runNr)
+        # DCS reference, format: http://atlas-dcs.cern.ch/navigation.php?date2=2009-07-26-10-12
+        tbeg = time.strftime("%Y-%m-%d-%H-%M-%S", time.gmtime(self.sor/1.E9))
+        t    = time.gmtime(self.eor/1.E9)
+        tend = "%4i-%02i-%02i-%02i-%02i" % (t[0], t[1], t[2], t[3], t[4])
+        s += '    <a href="http://atlas-dcs.cern.ch/navigation.php?date2=%s" target="_blank" title="DCS status at begin of run %i"><font size="-3">DCS:SoR</font></a>/' % (tbeg, self.runNr)
+        s += '<a href="http://atlas-dcs.cern.ch/navigation.php?date2=%s" target="_blank" title="DCS status at end of run %i"><font size="-3">EoR</font></a>,&nbsp;\n  ' % (tend, self.runNr)
+        # OKS
+        # protect against missing OKS information
+        if self.data['oks']:
+            s += '    <a href="http://cern.ch/atlas-project-tdaq-cc/cgi/getdata.sh?tdaq-03-00-01&oracle://atlas_oks/r&atlas_oks_archive&%i&%i&ATLAS" target="_blank" title="Download online configuration for run %i (slow download!)"><font size="-3">OKS</font></a>\n' % ( self.data['oks'][0].value + (self.runNr,) )
+        # lumi summary
+        # typical address: https://atlas.web.cern.ch/Atlas/GROUPS/DATAPREPARATION/RunSummary/run142308_summary.html
+        # OLD: fname = 'https://atlas.web.cern.ch/Atlas/GROUPS/DATAPREPARATION/RunSummary/run%i_summary.html' % (self.runNr)
+        fname = 'http://atlas.web.cern.ch/Atlas/GROUPS/DATAPREPARATION/DataSummary/runsum.py?run=%i\n' % (self.runNr)
+        fwget = urllib.urlopen(fname)
+
+        wincontent = ''
+        for line in fwget:
+            if '</head>' in line and '<base href' not in wincontent:
+                wincontent += '<base href="http://atlas.web.cern.ch/Atlas/GROUPS/DATAPREPARATION/DataSummary/2010/"></base>'
+            wincontent += line
+        wincontent = wincontent.replace('href="css/atlas-datasummary.css"', 'href="http://atlas.web.cern.ch/Atlas/GROUPS/DATAPREPARATION/DataSummary/css/atlas-datasummary.css"')
+
+        # remove temporarily second plot with integration
+        wincontent = wincontent.replace( '<td>\n<a href="rundata/run%i/run%i_ilumr.png"><img src="rundata/run%i/run%i_ilumr.png" alt="InstLumi" style="width: 200px; "></a></td>' % (self.runNr,self.runNr,self.runNr,self.runNr),'')
+        wincontent = wincontent.replace('"','&quot;')
+        wincontent = wincontent.replace('./RunSummary/figs','https://atlas.web.cern.ch/Atlas/GROUPS/DATAPREPARATION/RunSummary/figs')
+        wincontent = wincontent.replace('<a href','<a target=&quot;_blank&quot; href')
+        wincontent = wincontent.replace('width: 200px','width: 350px')
+        wincontent = wincontent.replace('width: 250px','width: 350px')
+
+
+        openwincmd = 'javascript:openLumiWindow('
+        openwincmd += "'Print','<!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;><html xmlns:&quot;my&quot;><head><title>Luminosity information for run %i</title></head><body style=&quot;background-color:#ffffff&quot;>" % self.runNr
+        openwincmd += wincontent        
+        openwincmd += '</body></html>'
+        openwincmd += "')"
+
+        return s
+
+
+    def timestr(self,format='html',closed=True):
+        """ sor and eor is always in UTC, so sor=0 means the run started 1.1.1970 at 00:00:00"""
+        if QC.localtime:
+            begin = time.localtime(self.sor/1.E9)
+            end   = time.localtime(self.eor/1.E9)
+        else:
+            begin = time.gmtime(self.sor/1.E9)
+            end   = time.gmtime(self.eor/1.E9)
+
+        # begin string
+        beginstr = time.strftime("%a %b %d %Y %X",begin)
+
+        # end format
+        endformat = "%X"
+        if end[0]>begin[0]:                      endformat = "%a %b %d, %Y %X"
+        elif end[1]>begin[1] or end[2]>begin[2]: endformat = "%a %b %d, %X"
+
+        # end string
+        if closed: endstr = time.strftime(endformat,end)
+        else:      endstr = '<font color=#BB0000>ongoing</font>' if format=='html' else 'ongoing'
+
+        # output
+        if format=='html':
+            return '%s&nbsp;&minus;&nbsp;%s' % (beginstr,endstr)
+        elif format=='seconds': #mainly for dictionary
+            return '%12.3f, %12.3f' % (self.sor/1.E9, self.eor/1.E9)
+        elif format=='secondsNum': #mainly for dictionary
+            return self.sor/1.E9, self.eor/1.E9
+        else:
+            return '%s - %s' % (beginstr,endstr)
+
+    def durationstr(self):
+        dt = time.gmtime((self.eor-self.sor)/1.E9)[2:6]
+        if dt[0]>1:
+            return "%id %ih %im %is" % ((dt[0]-1,) + dt[1:])
+        else:
+            return "%ih %im %is" % dt[1:]
+
+    @classmethod
+    def prettyChain(cls,tr,ps):
+        i = len(ps)-1
+        while i>0:
+            if ps[i]==ps[i-1]: ps[i]=' '
+            elif ps[i]<0:      ps[i]='x'
+            else:              ps[i]=str(ps[i])
+            i-=1
+        if ps[0]==None: ps[0]='n.a.'
+        elif ps[0]<0: ps[0]='x'
+        else:       ps[0]=str(ps[0])
+        
+        pss = '-'.join(ps)
+        s = "%s (%s)" % (tr.name,pss)
+        return s
+
+    def splitTriggerChains(self, chainlist):
+        res = { 'L1': [], 'L2': [], 'EF': [] }
+        for tr,pslist in chainlist.items():
+            if not tr.forshow: continue
+            k = tr.name[0:2]
+            res[k] += [Run.prettyChain(tr,pslist)]
+        res['L1'].sort()
+        res['L2'].sort()
+        res['EF'].sort()
+        l1chains = '<br> '.join(res['L1'])
+        l2chains = '<br> '.join(res['L2'])
+        efchains = '<br> '.join(res['EF'])
+        ret = ()
+        if l1chains: ret += (l1chains.replace('.0',''), )
+        if l2chains: ret += (l2chains.replace('.0',''), )
+        if efchains: ret += (efchains.replace('.0',''), )
+        return ret
+
+    def __str__(self):
+        if Run.writehtml:
+            s = ashtml(self)
+            return s
+        else:
+            s = self.astxt()
+            for lbr in self.data:
+                s+= "\n" + lbr.astxt()
+            return s
+
+    def __cmp__(self,other):
+        if isinstance(other,Run):
+            return self.runNr - other.runNr
+        return self.runNr - other
+
+
+    def astxt(self):
+        s = ""
+        if Run.showrunnr:
+            s += "run %*s  %*s  " % (_fW['Run']-4,self.runNrS, _fW['NLB'], self.NrLBs)
+        s += " "
+
+        if Run.showtime:
+            s += "%*s  " % (_fW['Time'],self.timestr('txt'))
+
+        if Run.showduration:
+            dt = time.gmtime((self.eor-self.sor)/1.E9)[2:6]
+            if dt[0]>1: s += "%id %ih %im %is " % ((dt[0]-1,) + dt[1:])
+            else: s += "%2ih %2im %2is " % dt[1:]
+
+        for k in Run.SortedShowOrder():
+            w = 10
+            if k in _fW: w = _fW[k]
+            v = self.result[k.ResultKey]
+            ostr=v
+            if k == "#Events":
+                ostr = addKommaToNumber(v)
+            elif k.Type == DataKey.STREAM:
+                w=max(len(k.Header)-k.Header.find('_'),_fW['Stream'])
+                if isinstance(ostr,tuple):
+                    ostr = ostr[0]
+            elif k=="TriggerMenu":
+                pv = [Run.prettyChain(tr,pslist) for (tr,pslist) in v.items() if tr.forshow]
+                ostr = ", ".join(pv)
+            elif k=="TriggerRates":
+                ostr = "NOT YET"
+            elif k=="olc:bcidmask":
+                ostr = "NOT YET"
+
+            s += "%*s  " % (w,ostr)
+
+        return s
+
+
+
+def ashtml(run):
+    import CoolRunQuery.html.AtlRunQueryHtmlUtils as HU
+
+    with timer("print runnur, runtime, etc"):
+        s = "<!-- Run %s -->\n" % run.runNrS
+
+        # disctionary with results
+        if Run.bgcolor == "1": Run.bgcolor = "2"
+        else: Run.bgcolor = "1"
+        color = Run.bgcolor
+
+        runrowclass = "out"
+        if run.showDataIncomplete: runrowclass="showmiss"
+        if run.selDataIncomplete: runrowclass="selmiss"
+        runrowclass += color   
+
+        s += '<tr class="out%s">\n' % (color)
+
+        if Run.showrunnr: # show columns Run, Links, LB
+            # run number
+            if run.runNr == Run.runnropen: # is the run still ongoing?
+                s += '  <td style="text-align:center" class="%s"><font color="#BB0000">%s<br><font size="-2">(ongoing)</font></font>' % (runrowclass, run.runNrS)
+            else:
+                s += '<td style="text-align:center" class="%s">%s' % (runrowclass, run.runNrS)        
+                p = Run.runPeriods.findPeriod( run.runNr )
+                if p:
+                    # split in the middle
+                    idx=-1
+                    for i in range(p.count(',')/2+1): idx = p.find(',',idx+1)
+                    s += '<br><font color="#488AC7"><font size=-2><nobr>Period: %s<br>%s</nobr></font></font>' % (p[:idx],p[idx+1:])
+
+            # open for prompt calibration?
+            if run.runNr in Run.PromptCalibRuns:
+                s += '<br><font color="#008800"><font size="-2">(in&nbsp;calib&nbsp;loop)</font></font>'
+            s += '</td>'
+
+            # links to other information
+            s += '\n  <td>\n%s</td>' % run.runlinks()
+
+            # luminosity block and average lb duration
+            lbcontent = '%s' % run.NrLBs
+            try:
+                vf = float(run.NrLBs)
+                if vf > 0: lbcontent = '%s<br><font size="-2">(%i&nbsp;s)</font>' % (run.NrLBs, (run.eor-run.sor)/(1.0E9*vf) )
+            except ValueError: pass
+
+            window  = HU.OpenWindow( HU.CreateLBTable(run), extracss=['html/atlas-runquery-lb.css'] )
+
+            # put into html page
+            tip = 'showTip LBStart_%i' % run.runNr
+            s += '\n  <!-- LB Content -->\n'
+            s += '  <td style="text-align: right"><div class="%s tooltip" style="display:inline;cursor:pointer">%s%s</a></div></td>\n' % (tip, window, lbcontent)
+
+
+        if Run.showtime:
+            s += '  <td>%s</td>' % run.timestr('html',run.runNr != Run.runnropen) # is the run still ongoing?
+
+
+        if Run.showduration:
+            if run.runNr == Run.runnropen: s += '  <td><font color="#BB0000">%s<br><font size="-2">(ongoing)</font></font></td>' % run.durationstr()
+            else:                          s += "  <td>%s</td>" % run.durationstr()
+
+        # find maximum output rate in case of streams
+        sumstrnev = 0
+        for k in Run.SortedShowOrder():
+            if k.Type == DataKey.STREAM and k.ResultKey in run.stats and not 'calibration' in k.ResultKey: sumstrnev += run.result[k.ResultKey][0]
+        if sumstrnev == 0: sumstrnev = -1
+
+        # flags...
+        ofllumiFlag = False
+
+
+    # the loop
+    with timer("print keys"):
+        for data_key in Run.SortedShowOrder():
+            k = data_key.ResultKey
+            v = run.result[k]
+
+            with timer("keybuild %s" % k):
+                if any(['olc:beam2intensity' in k,
+                        'olc:beam1intensity' in k,
+                        'lhc:beamenergy' in k,
+                        'beam1bunches' in k,
+                        'beam2bunches' in k,
+                        'collbunches' in k,
+                        'L1 PSK' == k,
+                        ]): continue
+
+
+                
+                s += '\n  '
+
+                # -----------------------------------------------------------------------------------------------------------------------
+
+                if k == "#Events":
+                    # compute approximative output rate in Hz
+                    durInSec = (run.eor-run.sor)/1.0E9                
+                    rate = 'n.a. Hz'
+                    try:
+                        if durInSec > 0: rate = '%.1f Hz' % (float(v)/durInSec)
+                    except ValueError: # if n.a.
+                        pass
+                    s += '  <td style="text-align: right">%s<BR><font size="-2">(%s)</font></td>' % (addKommaToNumber(v),rate)
+                    continue
+
+                # -----------------------------------------------------------------------------------------------------------------------
+
+                if k == "#L1A" or k == '#L2A' or k == '#EFA' or k == '#Events (streamed)' or k == '#Events (incl. calib.)':
+                    s += '  <td style="text-align: right">%s</td>' % addKommaToNumber(v)
+                    continue
+
+                # -----------------------------------------------------------------------------------------------------------------------
+
+                if k == 'DQ': # DEFECT
+                    intolerable = Run.Fieldinfo['DQ']['IntolerableDefects']
+
+                    for channelname in Run.Fieldinfo['DQ']['DefChannels']:
+                        if channelname == '':
+                            matching_dqentries = run.stats[k]["defects"]
+                        elif channelname == 'DET':
+                            matching_dqentries = [dqentry for dqentry in run.stats[k]["defects"] if not '_' in dqentry[0]]
+                        else:
+                            from re import compile
+                            pattern = compile(channelname)
+                            matching_dqentries = [dqentry for dqentry in run.stats[k]["defects"] if pattern.match(dqentry[0])]
+
+
+                        # reduce to LB ranges inside READY
+                        matching_dqentries_ready = []
+                        for (defect, listLBranges) in matching_dqentries: # dqentry is of format ('SCT_GLOBAL_STANDBY', [(1L, 49L), (119L, 123L)])
+                            readyLBRanges = [lbrange for lbrange in listLBranges if run.data.isReady(lbrange)]
+                            if len(readyLBRanges)>0:
+                                matching_dqentries_ready += [ (defect, readyLBRanges) ]
+
+
+                        if len(matching_dqentries_ready)==0:
+                            dq_info = "<table class='dqdefects' style='border-color: limegreen; height=100%'><tr><td>&nbsp;</td></tr></table>\n"
+                        else:
+                            dq_info = "<table class='dqdefects'>\n"
+                            for defect,listLBranges in matching_dqentries_ready:
+                                tip = 'showTip dqdefect_%i_%s tooltip' % (run.runNr, defect)
+                                if defect in intolerable:
+                                    dq_info += "<tr class='%s'><td class='intolerable'>%s</td><td class='lb'>" % (tip, defect)
+                                else:
+                                    dq_info += "<tr class='%s tolerable' style='visibility:collapse;'><td>%s</td><td class='lb'>" % (tip, defect)
+                                dq_info += ", ".join([("%g&minus;%g" % (x[0],x[1]-1) if x[1]-x[0]!=1 else "%g" % x[0]) for x in listLBranges])
+                                dq_info += "</td></tr>\n"
+                            dq_info += '<tr height="100%%"><td height="100%%"></td></tr>\n'
+                            dq_info += "</table>\n"
+                        s += '<td class="def">%s</td>' % dq_info
+
+                    continue
+
+                # -----------------------------------------------------------------------------------------------------------------------
+
+                if isDQ(k): # old, traffic-light DQ
+                    extraDQInfo = ''
+                    tip = ''
+                    dqmax = run.stats[k]["max"]
+                    n     = run.stats[k]["counts"]
+
+                    foundComment = False
+                    for (dq,comment), start, end in run.stats[k]["blocks"]:
+                        dqcss = dq
+                        if dq == 'n.a.': dqcss = 'NA'
+                        elif comment: foundComment = True
+
+                        if n[dq]>0 and dq != dqmax:
+                            if start == end-1:  # only one LB
+                                extraDQInfo += '<tr><td class="td%s" style="min-width: 45px; text-align: left; border-width: 0px; padding:1px;">&nbsp;LB&nbsp;%g:</td><td class="td%s" style="text-align: left; border-width: 0px; padding: 1px; ">%s&nbsp;</td></tr>' % (dqcss,start,dqcss,dq)                  
+                            else:               # range of LBs
+                                extraDQInfo += '<tr><td class="td%s" style="min-width: 45px; text-align: left; border-width: 0px; padding:1px;">&nbsp;LB&nbsp;%g&minus;%g:</td><td class="td%s" style="text-align: left; border-width: 0px; padding: 1px; ">%s&nbsp;</td></tr>' % (dqcss,start,end-1,dqcss,dq)
+
+                    if foundComment: tip = 'showTip dqcomm_%s_%i' % (k, run.runNr)
+                    if extraDQInfo:
+                        extraDQInfo = '<br><img vspace=2 height="1" width="1" src="wdot.jpg"><br><table style="width: 100%; border: 1px solid; border-width: 1px; border-spacing: 0px; border-color: #eeeeee; border-collapse: separate; padding: 0px; font-size: 65%"><tr>' + extraDQInfo + '</table>'
+
+                    if tip: s += '<td class="%s td tooltip td%s">%s%s</td>' % (tip,dqmax,dqmax,extraDQInfo)
+                    else:   s += '<td class="td td%s">%s%s</td>' % (dqmax,dqmax,extraDQInfo)
+
+                    continue
+
+                # -----------------------------------------------------------------------------------------------------------------------
+
+                if "detector systems" in k.lower():
+                    if v!='n.a.':
+                        v = DecodeDetectorMask(int(v),True)
+                    s += '  <td style="min-width:%ipx"><font size="-2">%s<hr color="#aaaaaa" size=1>[<a href="http://sroe.home.cern.ch/sroe/cgi-bin/avgmodule.py?run=%i" target=_blank>SCT HV setting</a>]</font></td>' % (1.1*len(v),v,run.runNr)
+                    continue
+
+                # -----------------------------------------------------------------------------------------------------------------------
+
+                if 'olc:lumi' in k:
+
+                    # find range with stable beams (requires LHC information to be available)
+                    hasStableBeamsInfo, xvecStb = run.getStableBeamsVector()
+
+                    # is pileup information available?
+                    printMu = 'olc:bcidmask' in Run.SortedShowOrder() and run.runNr>=151260 and run.givepeakmuinfo
+
+                    # insert events per LB
+                    xvec       = []
+                    yvec       = []
+                    yvecInt    = []
+                    for entry in run.data[k]:
+                        assert entry.startlb != 0, 'entry should not start at LB=0'
+                        val = entry.value if (entry.value!='n.a.' and entry.value>0) else 0
+                        lastlb = min(entry.lastlb,run.nr_lb)
+                        xvec += xrange(entry.startlb,lastlb+1)
+                        nlb = lastlb - entry.startlb + 1
+                        yvec    += nlb*[val]
+                        yvecInt += nlb*[val]
+
+                    # correct for time span
+                    intlumi, intlumiStb = (0, 0)
+
+                    # for lifetime
+                    lifetime   = 0
+                    lb1        = 0
+                    lb2        = 0
+                    t1         = 0
+                    t2         = 0
+                    y1         = 0
+                    y2         = 0
+                    if len(xvecStb) > 15:
+                        lb1 = xvecStb[3]
+                        lb2 = xvecStb[-1-5]
+
+                    peaklumi = -1
+                    for idx,(lbtime,lbendtime) in enumerate(run.lbtimes):
+                        lb=idx+1                    
+                        dt           = (float(lbendtime)-float(lbtime))/1.E9
+                        yvecInt[idx] *= dt/1000.0*run.lumiunit   # unit of yvec was: ub-1 s-1 -> nb-1
+                        yvec[idx]    *= 1.0*run.lumiunit         # unit of yvec was: ub-1 s-1, transform to: 10^30 cm-2s-1
+                        intlumi      += yvecInt[idx]
+
+                        if yvec[idx] > peaklumi: peaklumi = yvec[idx]
+                        if lb in xvecStb:
+                            intlumiStb += yvecInt[idx]
+                            if   lb == lb1:
+                                t1 = lbtime/1.E9
+                                y1 = yvec[idx]
+                            elif lb == lb2:
+                                t2 = lbtime/1.E9
+                                y2 = yvec[idx]
+
+                    if y1 > 0 and y2 > 0:
+                        lifetime = (t2 - t1)/(3600*math.log(y1/y2))  # unit: hours
+
+                    # line to be printed in column
+                    if hasStableBeamsInfo:
+                        fullprint_ = 'All&nbsp;LBs:&nbsp;%0.4g<br>Stable&nbsp;B:&nbsp;%0.4g' % (intlumi,intlumiStb)
+                        histoText  = 'Integrated luminosity: %.4g %s-1 (all LBs) and %.4g %s-1 (stable beams)' % (intlumi,run.lumiunittxt,intlumiStb,run.lumiunittxt)
+                    else:
+                        fullprint_ = 'All&nbsp;LBs:&nbsp;%0.4g' % (intlumi)
+                        histoText  = 'Integrated luminosity: %.4g %s-1 (all LBs)' % (intlumi,run.lumiunittxt)
+
+                    # find out which channel was used
+                    tp1, tp2, chan = k.split(':')
+                    try:
+                        chan = int(chan)
+                        if OLCAlgorithms.has_key(chan): chanstr = OLCAlgorithms[chan]
+                        else:                           chanstr = 'UNKNOWN'            
+                    except ValueError:
+                        chanstr = chan
+
+                    path = makeLBPlot( xvec, xvecStb, yvec, 'Luminosity block number', 'Online luminosity (10^{%s}cm^{-2}s^{-1})' % run.instlumiunittxt, '',
+                                       'olclumi_vs_lb_run_%i' % (run.runNr),
+                                       'Online lumi [%s] per LB for run %i' % (chanstr, run.runNr),
+                                       Run.Datapath, histoText )
+
+                    # create window and tooltip
+                    wincontent  = '<table class=&quot;outer&quot; style=&quot;padding: 5px&quot;><tr><td>'
+                    wincontent += '<strong><b>Online luminosity [algorithm: %s] per LB for run %i:</b></strong><br><font size=&quot;-1&quot; color=&quot;#888888&quot;>(Begin/end of run: %s)</font>' % (chanstr, run.runNr, run.timestr('html', run.runNr != Run.runnropen))
+                    wincontent += '<hr color=&quot;black&quot; size=1>'
+                    wincontent += '<table style=&quot;padding: 0px&quot;><tr><td>'
+                    wincontent += '<img src=&quot;%s&quot; align=&quot;left&quot;>' % path
+                    wincontent += '</td></tr></table>'
+                    wincontent += '<hr color=&quot;black&quot; size=1>'
+                    wincontent += '<table class=&quot;LB&quot;>'
+                    wincontent += '<tr><th>LB</th><th>Start time<br> (%s)</th><th>Duration<br>(sec)</th><th>Inst. luminosity<br>(1e%s&nbsp;cm<sup>&minus;2</sup>s<sup>&minus;1</sup>)</th>' % (QC.tzdesc(), run.instlumiunittxt)
+                    wincontent += '<th>Int. luminosity<br>(%s<sup>&minus;1</sup>)</th><th>Cumul. luminosity<br>(%s<sup>&minus;1</sup>)</th>' % (run.lumiunittxt, run.lumiunittxt)
+                    if printMu:
+                        wincontent += '<th>&nbsp;&nbsp;&lt;&mu;&gt;&nbsp;&nbsp;</th>'
+                    if hasStableBeamsInfo:
+                        wincontent += '<th>Stable beams</th>'
+                    wincontent += '</tr><tr style=&quot;background:%s&quot;>' % '#eeeeee'
+                    intlumi = 0
+                    mumax = -1
+                    for idx,(lbtime,lbendtime) in enumerate(run.lbtimes):
+                        lb=idx+1                    
+                        intlumi += yvecInt[idx]
+                        stbBeams = '&minus;'
+                        if lb in xvecStb: stbBeams = 'T'
+                        timetuple = time.localtime(lbtime/1.E9) if QC.localtime else time.gmtime(lbtime/1.E9)
+                        wincontent += '<td>%s</td><td>%s</td><td>%.2f</td><td>%.4g</td><td>%.4g</td><td>%.4g</td>' % (lb, time.strftime("%X",timetuple), (float(lbendtime)-float(lbtime))/1.E9, yvec[idx], yvecInt[idx], intlumi)
+                        # pileup <mu> information?
+                        if printMu:
+                            nb = 0
+                            for n,v,lbstart,lbend in run.stats['olc:bcidmask']['blocks']:
+                                if lb >= lbstart and lb <= lbend:
+                                    if v: nb = len(v[2])
+                                    break
+                            # compute expected number of interactions
+                            lumi_mb = yvec[idx]*1000.0
+                            mu = 0
+                            if nb: mu = lumi_mb*71.5/11245.511/nb
+                            wincontent += '<td>%.3g</td>' % mu
+                            if mu > mumax: mumax = mu
+                        if hasStableBeamsInfo:
+                            wincontent += '<td>%s</td>' % stbBeams
+                        if idx%2!=0: col = '#eeeeee'
+                        else:        col = '#ffffff'
+                        wincontent += '</tr><tr style=&quot;background:%s&quot;>' % col
+
+                    printMuInfoToFile = True
+                    if printMuInfoToFile:
+                        mutextfilename = Run.Datapath + '/mu_vs_run_output.txt' 
+                        muout          = open( mutextfilename, 'a' )
+                        muout.write( '%10i   %f\n' % (run.runNr, mumax) )
+                        muout.close()
+
+                    if mumax < 0: mumax = 'n.a.'
+                    else:         mumax = "%0.3g" % mumax
+
+                    if run.runNr == Run.runnropen: # run still ongoing
+                        wincontent += '<tr><td style=&quot;text-align:left&quot;colspan=&quot;3&quot;><i>&nbsp;&nbsp;Run still ongoing ...</i></td></tr>'
+                    wincontent += '</tr></table>'
+
+                    wincontent += """<hr color=&quot;red&quot; size=1><font color=&quot;#777777&quot;><font size=&quot;-1&quot;><i><font size=&quot;-2&quot;>Created by AtlRunQuery on: %s</font></i></font></td></tr></table><script type=&quot;text/javascript&quot;></script></body></html>""" % str(datetime.datetime.now())
+                    wincontent += '</td></tr></table>'
+
+                    openwincmd = '<a href="javascript:openLargeWindow('
+                    openwincmd += "'Print','<!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;><html xmlns:&quot;my&quot;><head><title>Run query result for online luminosity</title><LINK href=&quot;html/atlas-runquery-lb.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot;></head><body><table style=&quot;font-family: sans-serif; font-size: 85%%&quot;>" 
+                    openwincmd += wincontent        
+                    openwincmd += "')\">"
+
+                    # line to be printed in column
+                    fullprint  = '<table class="bcidtable">'
+                    fullprint += '<tr><td colspan="2"><img src="%s" align="left" width="90px"></td></tr>' % path
+                    if hasStableBeamsInfo:
+                        fullprint += '<tr><td style="text-align:left">Entire&nbsp;run:</td><td style="text-align:left">&nbsp;%0.4g&nbsp;%s<sup>&minus;1</sup></td></tr><tr><td style="text-align:left">Stable&nbsp;beams:</td><td style="text-align:left">&nbsp;%0.4g&nbsp;%s<sup>&minus;1</sup></td></tr><tr><td style="text-align:left">Peak&nbsp;lumi:</td><td style="text-align:left">&nbsp;%.2g&nbsp;e%s&nbsp;cm<sup>&minus;2</sup>s<sup>&minus;1</sup></td></tr><tr><td style="text-align:left">Peak&nbsp;&lt;&mu;&gt;:</td><td style="text-align:left">&nbsp;%s</td></tr>' % (intlumi, run.lumiunittxt, intlumiStb, run.lumiunittxt, peaklumi, run.instlumiunittxt, mumax)
+                        if lifetime > 0:
+                            fullprint += '<tr><td style="text-align:left">Approx.&nbsp;lifetime:</td><td style="text-align:left">&nbsp;%0.2g&nbsp;h</td></tr>' % (lifetime)
+                    else:
+                        fullprint += '<td style="text-align:left">All&nbsp;LBs:</td><td style="text-align:left">&nbsp;%0.4g</td></tr>' % (intlumi)
+                    fullprint += '</table>'
+
+                    # put into html page
+                    s += '<td class="showTip OLCLumi stream" style="text-decoration:none; text-align: right">%s%s</a></td>' % (openwincmd, fullprint)
+
+                    continue
+
+                # -----------------------------------------------------------------------------------------------------------------------
+
+                if 'olc:bcidmask' in k:
+
+                    firstGoodRun = 151260
+                    if run.runNr < firstGoodRun: # OLC information not properly filled
+                        s += '<td style="text-align:center;color:#AA0000;font-size:60%%;">BCID information only available for run numbers larger than %i</font></td>' % firstGoodRun
+                        continue
+
+                    # line to be printed in column
+                    fullprint = '<font size=-2><i>Run without stable beams (or, in few cases, missing bunch information in COOL). Click here to obtain bunch crossing information</i>.</font>'
+
+                    wincontent  = '<table class=&quot;outer&quot; style=&quot;padding: 5px&quot;><tr><td>'
+                    wincontent += '<strong><b>Identifiers (BCID) for paired and unpaired bunches for run %i:</b></strong><br><font size=&quot;-1&quot; color=&quot;#888888&quot;>(Begin/end of run: %s)</font>' % (run.runNr, run.timestr('html', run.runNr != Run.runnropen))
+                    wincontent += '<hr color=&quot;black&quot; size=1>'
+                    wincontent += '<table class=&quot;bcidtable&quot; align=&quot;center&quot;><tr class=&quot;tr0&quot;><td style=&quot;text-align:left;font-weight:bold&quot; colspan=&quot;3&quot;>LB&nbsp;range</td><td style=&quot;text-align:right;font-weight:bold&quot;>&nbsp;&nbsp;&nbsp;&nbsp;Stable<br>beams</td><td style=&quot;text-align:right;font-weight:bold&quot;>%s</td><td style=&quot;text-align:right;font-weight:bold&quot;>%s</td><td style=&quot;text-align:right;font-weight:bold&quot;>%s</td></tr>' % ('&nbsp;&nbsp;Crossing&nbsp;(Paired)', '<nobr>&nbsp;&nbsp;Unpaired&nbsp;Beam-1&nbsp;</nobr>', '<nobr>&nbsp;&nbsp;Unpaired&nbsp;Beam-2</nobr>')
+                    ic = 0
+
+                    # retrieve stable beam information
+                    hasStableBeamsInfo, xvecStb = run.getStableBeamsVector()
+
+                    first = True
+                    for n,v,lbstart,lbend in run.stats[k]['blocks']:
+                        ic += 1
+                        cls = 'tr1' if (ic%2==1) else 'tr2'
+
+                        # is this block during stable beams ?
+                        isInStableBeamPeriod = False
+                        stableBeamWord       = '&minus;'
+                        if hasStableBeamsInfo:
+                            if lbstart <= xvecStb[-1] and lbend >= xvecStb[0]:
+                                isInStableBeamPeriod = True
+                                stableBeamWord = '<b>T</b>'
+
+                        wincontent += '<tr class=&quot;%s&quot;><td class=&quot;td1&quot; style=&quot;text-align:right&quot;><b>%s</b></td><td style=&quot;text-align:right&quot;><b>&minus;</b></td><td style=&quot;text-align:right&quot;><b>%s:</b>&nbsp;&nbsp;&nbsp;</td><td>%s&nbsp;&nbsp;&nbsp;&nbsp;</td>' % (cls,str(lbstart),str(lbend-1),stableBeamWord)
+                        if v:
+                            beam1, beam2, beam12 = v
+                            unpaired1 = [b for b in beam1 if b not in beam12]
+                            unpaired2 = [b for b in beam2 if b not in beam12]
+
+                            noBunches = not unpaired1 and not unpaired2 and not beam12  # happens at least in run 152508
+                            if not unpaired1: unpaired1 = ['&minus;']
+                            if not unpaired2: unpaired2 = ['&minus;']
+                            if not beam12:    beam12    = ['&minus;']
+
+                            # analyse bunch train structure
+                            if isInStableBeamPeriod and first and not noBunches:
+                                first = False # don't do that again
+
+                                maxBunchDistanceInTrain = 6                            
+                                if int(run.runNr) > 168665: maxBunchDistanceInTrain = 25 # large (20) bunch distance for Heavy Ion collisions
+                                trains = []
+                                bp = -1
+                                for b in beam12:
+                                    if bp > 0 and b - bp <= maxBunchDistanceInTrain:
+                                        if trains[-1][-1] != bp: trains.append([bp])
+                                        trains[-1].append(b)
+                                    elif len(beam12) > 1 and bp <= 0 and beam12[0] - b <= maxBunchDistanceInTrain:
+                                        trains.append([b])
+                                    bp = b
+
+                                fullprint  = '<table class = "triggerlinktable">'
+                                fullprint += '<tr><td style="text-align:left"><nobr>No. of coll. bunches:&nbsp;&nbsp;</nobr></td><td> <b>%i</b></td></tr>' % len(beam12)
+                                fullprint += '<tr><td style="text-align:left"><nobr>No. of bunch trains:</nobr></td><td><b> %i</b></td></tr>' % len(trains)
+                                if trains:
+                                    Run.TmpBoxContent  = '<strong><b><nobr>Bunch train configuration for run <font color="#AA0000">%i</font></nobr></b></strong>' % run.runNr
+                                    Run.TmpBoxContent += '<hr size=1>' 
+
+                                    # it may be that the BCID=1 is a single pilot bunch only without a train
+                                    # in that case, don't use it to compute bunch distance in train, but print comment
+                                    icoor = 0 
+                                    if len(trains) > 1: icoor = 1
+                                    if len(trains[icoor]) > 1:
+                                        bunchDist = trains[icoor][1] - trains[icoor][0]
+                                        fullprint += '<tr><td style="text-align:left"><nobr>Bunch dist. in trains:</nobr></td><td><nobr><b> %i</b> (%i ns)</nobr></td></tr>' % (bunchDist, bunchDist*25)
+                                    # print the comment in case of single pilot bunch
+                                    if len(trains) > 0:
+                                        if len(trains[0]) == 1:
+                                            fullprint += '<tr><td style="text-align:left;color:#4477EE" colspan=2><i>The first "bunch train" is trivial and consists of only the colliding pilot bunch</td></tr>'
+                                    fullprint += '</table><hr size=1>'                            
+                                    Run.TmpBoxContent += '<table><tr><td>Train</td><td><nobr>No. of bunches</nobr></td><td style="text-align:right">&nbsp;&nbsp;&nbsp;BCID range</td></tr>'
+                                    for it, train in enumerate(trains):
+                                        Run.TmpBoxContent += '<tr><td>&nbsp;&nbsp;%i:&nbsp;&nbsp;</td><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%i</td><td style="text-align:right"><nobr>&nbsp;&nbsp;%i &minus; %i</nobr></td></tr>' % (it+1, len(train), train[0], train[-1])
+                                    Run.TmpBoxContent += '</table><hr size=1>'
+                                else:
+                                    Run.TmpBoxContent = '<nobr>No bunch trains in this run</nobr> <hr size=1>'
+                                    fullprint += '</table><hr size=1>' 
+                                Run.TmpBoxContent += '<p><font color="#AA0000"><b><nobr>Click to obtain full list of BCIDs</nobr></b></font>'
+                                fullprint += '<span style="font-size: xx-small; color: #555555">[ <i>Mouse over for train configuration. Click for full list of BCIDs</i> ]</span>'
+
+                            wincontent += '<td class=&quot;td1&quot; style=&quot;text-align:right&quot;>%s</td><td style=&quot;text-align:right; border-left:1px #C0C0D0 solid;border-right:1px #C0C0D0 solid&quot;>%s</td><td style=&quot;text-align:right&quot;>%s</td>' % (', '.join(map(str,beam12)), ', '.join(map(str,unpaired1)), ', '.join(map(str,unpaired2)) )
+                        else:
+                            wincontent += '<td class=&quot;td1&quot; style=&quot;text-align:right&quot;>%s</td><td style=&quot;text-align:right&quot;>%s</td><td style=&quot;text-align:right&quot;>%s</td>' % ('&minus;','&minus;','&minus;')
+
+                        wincontent += '</tr>'
+
+
+                    wincontent += '</table></td>'
+                    wincontent += '</td></tr></table>'
+
+
+                    openwincmd = HU.OpenWindow(wincontent, title="Run query result for online luminosity", extracss=None, size="large")
+                    #openwincmd = '<a href="javascript:openLargeWindow('
+                    #openwincmd += "'Print','<!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;><html xmlns:&quot;my&quot;><head><title>Run query result for online luminosity</title><LINK href=&quot;html/atlas-runquery-results.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot;></head><body><table style=&quot;font-family: sans-serif; font-size: 85%%&quot;>" 
+                    #openwincmd += wincontent        
+                    #openwincmd += "')\">"
+
+                    s += '<td class="showTip OLCBCID_%i stream" style="text-decoration:none; text-align: left">%s%s</a></td>' % (run.runNr, openwincmd, fullprint)
+
+                    continue
+
+                # -----------------------------------------------------------------------------------------------------------------------
+
+                if k.startswith('bs:Pos') or k.startswith('bs:Sig') or k.startswith('bs:Tilt'):
+
+                    # reference for average
+                    refkey  = 'bs:Sig-X' # must exist !
+                    statkey = 'bs:Status' # must exist !
+
+                    onloffltype = 'Online' if (run.stats['Beamspot']=='online') else 'Offline'
+
+                    # given is beamspot position or width or tilt
+                    xvec       = []
+                    yvec       = []
+                    yvecSt     = []
+                    bsidx      = []
+                    isOK       = False
+                    vave       = 0
+                    eave       = 0
+                    iave       = float(0)
+                    idx        = 0
+
+                    for entry in run.data[k]:
+                        if entry.startlb==0 and entry.lastlb==0: continue
+
+                        val,valerr = entry.value
+                        ref  = run.data[refkey].atLB(entry.startlb)[0].value[0]
+                        stat = run.data[statkey].atLB(entry.startlb)[0].value
+
+                        lastlb = min(entry.lastlb,run.lastlb)
+                        lbs = range(entry.startlb,lastlb+1)
+                        nlb = len(lbs)
+
+                        xvec    += [nlb]
+                        yvec    += [(val,valerr)]# * nlb
+                        yvecSt  += [stat]# * nlb
+                        bsidx   += [idx] * nlb
+                        idx     += 1
+
+                        # compute average if BS has been determined
+                        if ref < 10:
+                            vave += nlb * val
+                            eave += nlb * val**2
+                            iave += nlb
+                            isOK  = True
+
+                    if not isOK:
+                        s += '<td>n.a.</td>'
+                        continue
+
+                    if iave>0:
+                        vave /= float(iave)
+                        rad = eave/iave - vave*vave
+                        if rad>=0: eave = math.sqrt(rad)
+                        else:      eave = 0
+                    else:
+                        vave = -1
+
+                    ymin = vave - 3*eave
+                    ymax = vave + 3*eave
+
+                    if ymin >= ymax:
+                        ymin = ymin*0.9
+                        ymax = ymin*1.1
+                        if ymin >= ymax:
+                            ymin = -0.1
+                            ymax = 0.1
+
+                    if ymin==ymax: delta = 0.1*abs(ymax)
+                    else:          delta = 0.1*(ymax-ymin)
+                    ymin -= delta
+                    ymax += delta
+
+
+                    bstype = 'pos'
+                    if   'Sig'  in k: bstype = 'width'
+                    elif 'Tilt' in k: bstype = 'tilt'
+                    bstype += k[k.find('-'):] 
+
+                    histoText = 'Average beam spot %s: (%.4g +- %.1g) mm' % (bstype, vave, eave)
+
+                    path = makeBSPlots( xvec=xvec, yvec=yvec,
+                                        xtitle = 'Luminosity block number', ytitle = '%s beamspot %s  (mm)' % (onloffltype, bstype),
+                                        histname = '%s_vs_lb_run_%i' % (k.replace(':','_').replace('-','_'), run.runNr),
+                                        histtitle = '%s beamspot %s per LB for run %i' % (onloffltype, bstype, run.runNr),
+                                        datapath = Run.Datapath, ymin = ymin, ymax = ymax, printText = histoText )
+
+
+                    # create window and tooltip
+                    wincontent = '<table class=&quot;outer&quot; style=&quot;padding: 5px&quot;><tr><td>'
+                    wincontent += '<strong><b>%s beamspot %s per LB for run %i:</b></strong><br><font size=&quot;-1&quot;><font color=&quot;#888888&quot;>(Begin/end of run: %s)</font></font><hr color=&quot;black&quot; size=1>' % (onloffltype, bstype, run.runNr, run.timestr('html', run.runNr != Run.runnropen))
+                    wincontent += '<table style=&quot;padding: 0px&quot;><tr><td>'
+                    wincontent += '<img src=&quot;%s&quot; align=&quot;left&quot;>' % (path)
+                    wincontent += '</td></tr></table>'
+                    wincontent += '<hr color=&quot;black&quot; size=1>'
+
+                    wincontent += '<table style=&quot;width: auto; border: 0px solid; border-width: margin: 0 0 0 0; border-spacing: 0px; border-collapse: separate; padding: 0px; font-size: 90%; vertical-align:top; &quot;>'
+                    wincontent += '<tr><th style=&quot;text-align:right&quot;>LB</th><th style=&quot;text-align:right&quot;>&nbsp;&nbsp;&nbsp;Start time<br> (%s)</th><th style=&quot;text-align:right&quot;>&nbsp;&nbsp;&nbsp;Duration<br>(sec)</th><th style=&quot;text-align:right&quot;>&nbsp;&nbsp;&nbsp;Beamspot %s<br>(mm)</th><th style=&quot;text-align:right&quot;>&nbsp;&nbsp;&nbsp;Fit&nbsp;status</th>' % (QC.tzdesc(),bstype)
+                    wincontent += '</tr><tr style=&quot;background:%s&quot;>' % '#eeeeee'
+                    for idx,(lbtime,lbendtime) in enumerate(run.lbtimes):                
+                        lb=idx+1
+                        timetuple = time.localtime(lbtime/1.E9) if QC.localtime else time.gmtime(lbtime/1.E9)
+                        wincontent += '<td style=&quot;text-align:right&quot;>&nbsp;&nbsp;%s</td>' % lb
+                        wincontent += '<td style=&quot;text-align:right&quot;>&nbsp;%s</td>' % time.strftime("%X",timetuple)
+                        wincontent += '<td style=&quot;text-align:right&quot;>%.2f</td>' % ((float(lbendtime)-float(lbtime))/1.E9)
+                        wincontent += '<td style=&quot;text-align:right&quot;>%.4g &plusmn; %.2g</td>' % yvec[bsidx[idx]]
+                        wincontent += '<td style=&quot;text-align:right&quot;>%i</td>' % yvecSt[bsidx[idx]]
+
+                        if idx%2!=0: col = '#eeeeee'
+                        else:        col = '#ffffff'
+                        wincontent += '</tr><tr style=&quot;background:%s&quot;>' % col
+                    if run.runNr == Run.runnropen: # run still ongoing
+                        wincontent += '<tr><td style=&quot;text-align:left&quot;colspan=&quot;3&quot;><i>&nbsp;&nbsp;Run still ongoing ...</i></td></tr>'
+                    wincontent += '</tr></table>'
+
+                    wincontent += """<hr color=&quot;red&quot; size=1><font color=&quot;#777777&quot;><font size=&quot;-1&quot;><i><font size=&quot;-2&quot;>Created by AtlRunQuery on: %s</font></i></font></td></tr></table><script type=&quot;text/javascript&quot;></script></body></html>""" % str(datetime.datetime.now())
+                    wincontent += '</td></tr></table>'
+
+                    openwincmd = '<a href="javascript:openWindow('
+                    openwincmd += "'Print','<!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;>"
+                    openwincmd += "<html><head><title>Run query result for the %s beamspot</title><LINK href=&quot;html/atlas-runquery-lb.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot;></head>" % (onloffltype.lower())
+                    openwincmd += "<body><table style=&quot;font-family: sans-serif; font-size: 85%&quot;>"
+                    openwincmd += wincontent
+                    openwincmd += "</table></body></html>"
+                    openwincmd += "')\">"
+
+                    # plot
+                    fullprint  = '<table class="triggerlinktable">'
+                    fullprint += '<tr><td colspan="2"><img src="%s" align="left" width="90px"></td></tr>' % path
+                    fullprint += '<tr><td colspan="2"></td></tr>' 
+                    if isOK:
+                        fullprint += '<tr><td style="text-align:left">Average&nbsp;%s:</td></tr><tr><td style="text-align:left"><nobr>&nbsp;%0.3g&nbsp;&plusmn;&nbsp;%.2g&nbsp;(RMS)</nobr></td></tr>' % (bstype, vave, eave)
+                    fullprint += '</table>'
+
+                    # put into html page
+                    s += '<td class="showTip OFLBS stream" style="text-decoration:none; text-align: right">%s%s</a></td>' % (openwincmd, fullprint)  
+                    continue
+
+                if "STR:" == k[0:4]:
+                    streamName = k[4:]
+                    if 'n.a.' in v:
+                        s += '<td class="tdna">n.a.</td>'
+                        continue
+
+                    # compute approximative output rate in Hz
+                    durInSec = (run.eor-run.sor)/1.0E9                
+                    rate = 'n.a.&nbsp;Hz'
+                    try:
+                        if durInSec > 0: rate = '%.3f&nbsp;Hz' % (v[0]/durInSec)
+                    except ValueError: pass
+                    strevents = v[0]
+                    strsize = v[1]
+                    # add relative fraction (only if not calibrtion string)
+                    fracstr = ''
+                    if not 'calibration' in k: fracstr = '%.1f%%,' % (float(strevents)/sumstrnev*100)                
+
+
+                    ev = {}
+                    xvec    = []
+                    xvecStb = []
+                    yvecN   = []
+                    yvecR   = []
+                    nevtot = 0
+
+                    # statistics
+                    maxrate    = -1
+                    averate    = 0
+                    nc         = 0
+
+                    # insert events per LB
+                    lbrecinfo = run.stats[k]['LBRecInfo']
+
+                    isPhysicsStream = lbrecinfo!=None and len(lbrecinfo)>0
+                    if isPhysicsStream: # only for physics stream we have LB wise information
+                        ev = dict(lbrecinfo)
+                        for lb in ev: ev[lb]=0
+                        for lb,nev in lbrecinfo: ev[lb] += nev
+                        for idx,(lbtime,lbendtime) in enumerate(run.lbtimes):
+                            lb=idx+1                    
+                            nev = 0
+                            if ev.has_key(lb): nev = ev[lb]
+                            xvec.append(lb)
+                            yvecN.append(nev)                        
+                            yvecR.append(0)
+                            nevtot += nev
+                            try:
+                                if float(lbendtime)-float(lbtime) > 0:
+                                    yvecR[-1] = nev/((float(lbendtime)-float(lbtime))/1.E9)
+                            except ValueError:
+                                pass
+
+                        lbs = ev.keys(); lbs.sort()
+
+                        # find range with stable beams (requires LHC information to be available)
+                        hasStableBeamsInfo, xvecStb = run.getStableBeamsVector()
+
+                        # prepare pop-up window
+                        wincontent  = '<table class=&quot;outer&quot; style=&quot;padding: 5px&quot;>'
+                        wincontent += '<tr><td><b>Number of events and rates per LB for stream %s run %i:</b><br><font size=&quot;-1&quot;><font color=&quot;#888888&quot;>(Begin/end of run: %s)</font></font><hr color=&quot;black&quot; size=1>' % (streamName, run.runNr, run.timestr('html', run.runNr != Run.runnropen))
+
+                        # create plot
+                        pathN = makeLBPlot( xvec, xvecStb, yvecN,  'Luminosity block number', 'Number of events / LB', '',
+                                            'nev_vs_lb_str_%s_run_%i' % (streamName, run.runNr),
+                                            'N events per LB in stream "%s", run %i' % (streamName, run.runNr),
+                                            Run.Datapath, 'Total number of events: %i' % nevtot )
+                        pathR = makeLBPlot( xvec, xvecStb, yvecR, 'Luminosity block numer', 'Event rate [Hz] / LB', '',
+                                            'rate_vs_lb_str_%s_run_%i' % (streamName, run.runNr),
+                                            'Event rate per LB in stream "%s", run %i' % (streamName, run.runNr),
+                                            Run.Datapath )
+                        wincontent += '<table style="padding: 0px">\n<tr><td>'
+                        wincontent += '<img src="%s" width="350">' % pathN.split('/')[-1]
+                        wincontent += '</td><td>'
+                        wincontent += '<img src="%s" width="350">' % pathR.split('/')[-1]
+                        wincontent += '</td></tr></table>\n'
+                        wincontent += '<hr color="black" size=1>\n'
+                        wincontent += '<table class="lb">\n'
+                        wincontent += '<tr><th>LB</th><th>Start time (%s)</th><th>Duration (sec)</th><th>Nevents</th><th>Cumul. Nevents</th><th>Rate [Hz]</th>'  % QC.tzdesc()
+                        if hasStableBeamsInfo:
+                            wincontent += '<th>Stable beams</th>'
+                        wincontent += '</tr>\n<tr style="background:%s">' % '#eeeeee'
+                        sumnev     = 0
+                        for idx,(lbtime,lbendtime) in enumerate(run.lbtimes):
+                            lb=idx+1                    
+                            nev = 0
+                            if ev.has_key(lb): nev = ev[lb]
+                            sumnev += nev
+                            stbBeams = '&minus;'                                
+                            if yvecR[idx] > 0:
+                                averate += yvecR[idx]
+                                if yvecR[idx] > maxrate: maxrate = yvecR[idx]
+                                nc += 1
+                            if lb in xvecStb: 
+                                stbBeams = 'T'
+
+                            timetuple = time.localtime(lbtime/1.E9) if QC.localtime else time.gmtime(lbtime/1.E9)
+                            wincontent += '<td>%s</td><td>%s</td><td>%.2f</td><td>%i</td><td>%i</td><td>%.3g</td>' % (lb, time.strftime("%X",timetuple), (float(lbendtime)-float(lbtime))/1.E9, int(yvecN[idx]), sumnev, yvecR[idx])
+                            if hasStableBeamsInfo:
+                                wincontent += '<td>%s</td>' % stbBeams
+                            if idx%2!=0: col = '#eeeeee'
+                            else:        col = '#ffffff'
+                            wincontent += '</tr>\n<tr style="background:%s">' % col
+
+                        # compute max and averages
+                        if nc>0: averate    /= float(nc)
+
+                        if run.runNr == Run.runnropen: # run still ongoing
+                            wincontent += '<tr><td style="text-align:left"colspan="3"><i>&nbsp;&nbsp;Run still ongoing ...</i></td></tr>\n'
+                        wincontent += '</tr></table>\n'
+                        wincontent += '<hr color="red" size=1><font color="#777777"><font size="-1"><i><font size="-2">Created by AtlRunQuery on: %s</font></i></font></td></tr></table><script type="text/javascript"></script></body></html>' % str(datetime.datetime.now())
+                        wincontent += '</td></tr></table>'
+                    else:
+                        wincontent = ""
+
+                    # the output
+                    tooltipkey = "STROV_%i_%s" % (run.runNr, streamName)
+
+                    physStrOnlyInfo = ""
+                    if isPhysicsStream:
+                        maxrate = 'max:&nbsp;%.2f&nbsp;Hz' % (maxrate)
+                        averate = 'ave:&nbsp;%.2f&nbsp;Hz' % (averate)
+                        physStrOnlyInfo = "%s,<br>%s,<br>%s,&nbsp;" % (maxrate, averate, fracstr)
+                    debugStrLink = ""
+                    if 'debug_' in k:
+                        debugStrLink = '&nbsp;<a href="https://trigmon.web.cern.ch/trigmon/ResultsAnalysis/RESULTS/%i/00%i_%s" target=_blank><font color="#993333">[MON]</font></a>' % (time.gmtime(run.sor/1.E9)[0], run.runNr, k[4:].strip())
+                    evtsize = ',<br>%s/evt' % filesize(float(strsize)/float(strevents)) if (strevents>0) else ""
+                    tdcontent = '%s <BR><font size="-2">(%s%s/run%s%s)' % (addKommaToNumber(strevents), physStrOnlyInfo, filesize(strsize), evtsize, debugStrLink)
+
+                    # wrap content in div with tooltip
+                    tdcontent = '<div class="showTip %s stream" style="display:inline;cursor:pointer">%s</div>' % (tooltipkey, tdcontent)
+
+                    if isPhysicsStream:
+                        # create popup page and wrap content into href
+                        filename = HU.CreatePopupHtmlPage( 'streamov_%i_%s' % (run.runNr, streamName),  HU.WrapIntoHTML(wincontent, title="%s Stream Content" % streamName) )
+                        tdcontent = '<a class="externalWindow" style="text-decoration:none" href="%s">%s</a>' % (filename, tdcontent)
+
+                    s += '<td style="text-decoration:none">%s</td>' % (tdcontent)
+                          
+                    continue
+
+
+
+                if k=="TriggerMenu":
+                    chains = run.splitTriggerChains(v)
+                    if len(chains)==0:   s += '<td></td>' 
+                    elif len(chains)==1: s += '<td style="min-width:300px"><font size="-2">%s</font></td>' % ( chains )
+                    elif len(chains)==2: s += '<td style="min-width:300px"><font size="-2">%s<hr color="gray" size=1>%s</font></td>' % ( chains )
+                    else:                s += '<td style="min-width:300px"><font size="-2">%s<hr color="gray" size=1>%s<hr color="gray" size=1>%s</font></td>' % ( chains )
+                    continue
+
+                if k=="TriggerRates":
+                    if type(v)==str:
+                        s += '<td>%s</td>'%v
+                    else:
+                        tablecontent = ""
+                        triggergroups,imgpaths,openwincmds = HU.createRatePopupWindow(v,run)
+                        for idx,(trgroup,imgpath,openwincmd) in enumerate(zip(triggergroups,imgpaths,openwincmds)):
+                            tooltipkey = "TrRate_Set%i_%i" % (idx,run.runNr)
+                            contentpage = "%s/popupContent_trRates_%i_%i.html" % (Run.Datapath, run.runNr, idx)
+
+                            if idx!=0:
+                                tablecontent += '      <tr><td colspan="2"><hr color="gray"></td></tr>'
+                            imgcontent = '<img src="%s" align="center" width="90px"><br>' % imgpath
+                            imagerow = '<div class="showTip %s ratespopup" id="%s" style="display:inline;cursor:pointer;font-size:80%%;">%s</div>' % (tooltipkey, contentpage, imgcontent)
+                            tablecontent += '      <tr><td  colspan="2" >%s</td></tr>' % imagerow
+                            for tr,avr in trgroup:
+                                tablecontent += '      <tr><td>%s</td><td>: %3.1f Hz</td></tr>' % (tr,avr)
+                        s+="<td><table class='ratestable'>\n%s\n  </table></td>" % tablecontent
+                    continue
+
+                if "Datasets" == k:
+                    # separate datasets into stream types
+                    streamtypes = ['physics_','express_','calibration_','debug_', 'debugrec_']
+                    steptypes   = ['.daq.','.recon.','.merge.','other','Reproc' ]
+                    datatypes   = ['.RAW','.DRAW','.ESD.','.DESD','.AOD.','.TAG.','.TAG_COMM.','.HIST.','.NTUP','other']
+                    vetotypes   = ['_TMP']
+                    shownlist   = []
+
+                    s += '<td>'
+                    s += '<table class="datasettable">'
+                    hrline = ''
+                    allcafdsnames = ''
+                    first = True
+                    for stype in streamtypes:
+                        for step in steptypes:
+                            for dtype in datatypes:
+                                selectedds = {}
+                                for ds in v:                            
+                                    if (stype in ds[0] and step in ds[0] and dtype in ds[0]) or (stype in ds[0] and stype == 'debug_' and step == 'other' and (dtype in ds[0] or dtype == 'other')) and not ds[0] in shownlist:
+                                        vetoed = False
+                                        for veto in vetotypes:
+                                            if veto in ds[0]: 
+                                                vetoed = True
+                                                break
+                                        if not vetoed:
+                                            # number of files, size, events
+                                            st  = ['&nbsp;%s&nbsp;files' % (prettyNumber(ds[4]))]
+                                            st += ['&nbsp;%s'         % (filesize(ds[5]))]
+                                            if ds[6] == 0: st += ['&nbsp;unkn.&nbsp;evts&nbsp;']
+                                            else:          st += ['&nbsp;%s&nbsp;evts&nbsp;'  % (prettyNumber(ds[6]))]
+                                            selectedds[ds[0]] = st
+                                            # replication status
+                                            if 'replicate:done' in ds[2]: selectedds[ds[0]] += [True]
+                                            else:                         selectedds[ds[0]] += [False]
+                                            if ds[3] == 'DONE':           selectedds[ds[0]] += [True]
+                                            else:                         selectedds[ds[0]] += [False]
+                                            selectedds[ds[0]] += [ds[7]] # add dataset creation time
+                                            shownlist.append(ds[0])                                    
+
+                                if not selectedds: continue
+                                dsnames = selectedds.keys()
+                                dsnames.sort()
+                                if not first: s += hrline
+                                first = False
+                                s += '<tr><td colspan="1"><font color="#666666"><i>[&nbsp;Stream&nbsp;type&nbsp;+&nbsp;processing&nbsp;step&nbsp;+&nbsp;data&nbsp;type:&nbsp;<b>%s</b>&nbsp;+&nbsp;<b>%s</b>&nbsp;+&nbsp;<b>%s</b>&nbsp;]</i> </font></td></tr>' % (stype, step, dtype)
+                                for dsname in dsnames:
+                                    # build AMI link to dataset
+                                    dsnspl = dsname.split('.')
+                                    lk = "https://ami.in2p3.fr/AMI/servlet/net.hep.atlas.Database.Bookkeeping.AMI.Servlet.Command?Converter=/AMIXmlToAMIProdHtml.xsl&Command=FormBrowseDatasetPerParameter+-runNumber%3D"
+                                    project = dsnspl[0]
+                                    runNum  = dsnspl[1]
+                                    stream  = dsnspl[2]
+                                    format  = dsnspl[4]                            
+                                    s += '<tr><td>'
+                                    s += '<a href="https://ami.in2p3.fr/AMI/servlet/net.hep.atlas.Database.Bookkeeping.AMI.Servlet.Command?Converter=/AMIXmlToAMIProdHtml.xsl&Command=FormBrowseDatasetPerParameter+-runNumber%3D'
+                                    s += runNum + "+-dataType=" + format + "+-projectName=" + project + "+-streamName=" + stream
+                                    s += '" target="_blank" title="AMI dataset information">'
+                                    s += dsname + '</td>'
+                                    res = selectedds[dsname]
+                                    s += '<td style="text-align:right"><font color="#005500">&nbsp;[</font></td>' 
+                                    for st in res[0:3]:
+                                        s += '<td style="text-align:right"><font color="#005500">%s</font></td>' % st
+                                    s += '<td style="text-align:right"><font color="#005500">]</font></td>'
+                                    if res[3]:
+                                        if Run.showCAFLinks:
+                                            s += '<td><a href="javascript:openPageWindow('
+                                            s += "'data/%s.html','%s')" % (dsname,dsname)
+                                            s += '"title="Check which files of this dataset are available on ATLCAL disk pool">' 
+                                            s += '<font color="#BB0517">&nbsp;[&nbsp;on&nbsp;CAF&nbsp;]</font></a></td>'
+
+                                            # get age of file in hours
+                                            deltat = (datetime.datetime.utcnow() - res[5])
+                                            deltat = deltat.days*24.*3600. + deltat.seconds
+                                            allcafdsnames += dsname + '@' + '%g' % deltat + ','                                    
+                                        else:
+                                            s +='<td><font color="#BB0517">&nbsp;[&nbsp;on&nbsp;CAF&nbsp;]</font></td>'
+                                    else:
+                                        s += '<td></td>'
+                                    if res[4]:
+                                        lk = '<a href="https://ami.in2p3.fr/AMI/servlet/net.hep.atlas.Database.Bookkeeping.AMI.Servlet.Command?Command=FormGetDQ2InfoPerDataset+-logicalDatasetName%3D%22' + dsname + '%22&Converter=%2FAMIXmlToProdFrameHtml.xsl" target="_blank" title="DQ2 information (via AMI) for dataset: ' + dsname + '">'
+                                        s += '<td>%s<font color="#153EBB">&nbsp;[&nbsp;in&nbsp;DDM&nbsp;]</font></a></td>' % lk
+                                    else:
+                                        s += '<td></td>'
+
+                                    s += '</tr>'
+                                if dtype != datatypes[-1]:
+                                    hrline = '<tr><td colspan="8"><hr style="width:100%; background-color: #BBBBBB; height:1px; margin-left:0; border:0"/></td>'
+                                else: hrline = ''
+
+                            if step != steptypes[-1]:
+                                hrline = '<tr><td colspan="8"><hr style="width:100%; background-color: #666666; height:2px; margin-left:0; border:0"/></td>'
+                        if stype != streamtypes[-1]:
+                            hrline = '<tr><td colspan="8"><hr style="width:100%; background-color: #6D7B8D; height:3px; margin-left:0; border:0"/></td>'
+                    # sanity check
+                    s_ = ''
+                    for ds in v:
+                        if not 'TMP.' in ds[0] and not ds[0] in shownlist:
+                            s_ += '<tr><td colspan=8>' + ds[0] + '</td></tr>'
+                    if s_:
+                        s += '<tr><td colspan="8"><hr style="width:100%; background-color: #EE0000; height:3px; margin-left:0; border:0"/></td>'
+                        s += '<tr><td colspan=8><font color="#EE0000"><i>Remaining, unassigned datasets:</i></font></td></tr>'
+                        s += s_
+
+                    # close table
+                    s += '</table>\n'
+                    s += '</td>'
+
+                    # call subprocesses
+                    if allcafdsnames:
+                        subprocess.Popen('python subproc.py caf %s' % (allcafdsnames[:-1]), shell=True)
+
+                    continue
+
+                if 'HLT PSK' == k:
+                    # add another column with links to trigger menu for all SMK and PSKs combinations
+                    links = ''
+                    linklist = run.stats['PSK']['blocks']
+
+                    if linklist:
+                        if len(linklist)<=15: ncol = 1
+                        elif len(linklist)<=30: ncol = 2
+                        else: ncol = 3
+                        if len(linklist)<=15: nrow = len(linklist)
+                        elif len(linklist)<=45: nrow = 15
+                        else: nrow = (len(linklist)+2)/3
+                        
+                        s += '<td align="center"><table class="triggerlinktable" align="center">'
+                        s += '<tr>'
+                        for x in range(ncol):
+                            s += '<td style="text-align:center;font-weight:bold" colspan="3">LB&nbsp;range</td><td style="text-align:center;font-weight:bold">L1&nbsp;&nbsp;&nbsp;HLT</td>'
+                        s += '</tr>'
+
+                        for row in range(nrow):
+                            s += '<tr>'
+                            for col in range(ncol):
+                                entry = row + col*nrow
+                                if entry>=len(linklist): continue
+                                link = linklist[entry]
+                                s += '<td style="padding-left: 0.8em">%s</td><td>&minus;</td><td>%s:&nbsp;</td>' % (str(link[0]),str(link[1]))
+                                l = '<a href="https://atlas-trigconf.cern.ch/run/smkey/%s/l1key/%s/hltkey/%s/" target="_blank" title="L1 \'%s\', HLT \'%s\'. Obtain full trigger menu corresponding to SMK=%s and prescale keys L1=%s, HLT=%s, in independent window">' % (run.result['SMK'],link[2],link[3],link[4],link[5],run.result['SMK'],link[2],link[3])
+                                s += '<td style="border-right: 1px solid gray; padding-right: 0.8em">%s%s&nbsp;|&nbsp;%s</a></td>' % (l, link[2],link[3])
+                            s += '</tr>'
+                        s += '</table>'
+                        s += '<hr style="width:100%; background-color: #AAAABB; height:1px; margin-left:0; border:0"/>'
+                        s += '<a href="https://atlas-trigconf.cern.ch/psevo/%i/" target="_blank" title="Obtain prescale evolution for all L1/L2/EF chains of this run in independent window"><font size="-2"><i>Prescale&nbsp;evolution...</i></font></a>' % run.runNr
+                        s+='</td>'
+                    else:
+                        s += '<td style="text-align:center">n.a.</td>'
+                    continue
+
+                if 'BGS Key' == k:
+                    if v!='n.a.':
+                        if len(run.stats['BGS Key' ]['blocks'])>0:
+                            s += '<td align="center"><table class="triggerlinktable" align="center"><tr><td style="text-align:left;font-weight:bold" colspan="3">LB&nbsp;range</td><td style="text-align:right;font-weight:bold">BGS</td></tr>'
+                            for bgskey, lbbeg, lbend in run.stats['BGS Key' ]['blocks']:
+                                s += '<tr><td style="text-align:right">%i</td><td style="text-align:right">&minus;</td><td style="text-align:right">%i:&nbsp;</td>' % (lbbeg, lbend-1)
+                                l = '&nbsp;<a href="https://atlas-trigconf.cern.ch/bunchgroups?key=%s" target="_blank" title="Obtain bunch group description for BGS Key=%s in independent window">' % (bgskey,bgskey)
+                                s += '<td>%s%s</a></td></tr>' % (l, bgskey)
+                            s += '</table>'
+                            s+='</td>'
+                        else:
+                            s += '<td style="text-align:center">n.a.</td>'
+                    else:
+                        s += '<td class="tdna">n.a.</td>'
+                    continue
+
+                if "SMK" == k:
+                    if v=='n.a.': s += '<td class="tdna">n.a.</td>'
+                    else:
+                        namecomment = '<div style="font-size:80%%;color:#488AC7"><b>%s</b> (v.%i)</div><div style="width:200px;font-size:60%%;color:#777777;text-align:left">%s</div>' % run.stats['SMK']['info']
+                        s += '<td style="text-align: center;">%s<br>%s</td>' % (v,namecomment)
+                    continue
+
+                if 'lar:runtype' in k or 'lar:format' in k:
+                    info = LArConfig(k.replace('lar:',''))
+                    try:
+                        s += '<td style="text-align: center">%s<br><font size="-2">(%s)</font></td>' % (v,info[int(v)])
+                    except ValueError:
+                        if v=='n.a.': s += '<td class="tdna">n.a.</td>'
+                        else:         s += '<td style="text-align: right">%s</td>' % v
+                    continue
+
+                if 'BPM' == k:
+
+                    # compute average and RMS BPMs            
+                    fullprint = '<table class="triggerlinktable" align="center">'
+                    keys      = v.keys()
+                    keys.sort()
+
+                    # time results
+                    xvec    = []
+                    yvec    = []
+                    toffset = int(run.sor/1.E9)
+                    deltat  = int(run.eor/1.E9) - int(run.sor/1.E9)
+
+                    # LB axis
+                    xveclb = []
+                    for idx,(lbtime,lbendtime) in enumerate(run.lbtimes):
+                        lb=idx+1
+                        xveclb.append( [lbtime/1.E9-toffset, (float(lbendtime)-float(lbtime))/1.E9] )
+
+                    ymin    = +1e30
+                    ymax    = -1e30
+                    legend  = []
+                    datemin = '' # run sor
+                    datemax = '' # run eor
+                    for ik,key in enumerate(keys):
+                        y  = 0
+                        y2 = 0                
+                        xvec.append([])
+                        yvec.append([])
+                        for (val,dte) in v[key]:
+                            y  += val
+                            y2 += val*val
+
+                            ts   = time.strptime( dte[:dte.rfind(':')] + '/UTC','%d-%m-%Y %H:%M:%S/%Z' )
+                            tsec = int(calendar.timegm(ts))                                        
+                            xvec[-1].append(tsec - toffset) # time defined with respect to offset
+                            yvec[-1].append(val)
+
+                        ic = len(v[key])
+                        if ic > 0:
+                            y /= float(ic)
+                            arg = y2/float(ic) - y*y
+                            if arg > 0: y2 = math.sqrt(arg)
+                            else:       y2 = 0
+                        ymin = min(ymin,y - 1.5*y2)
+                        ymax = max(ymax,y + 1.5*y2)                
+
+                        # fill table
+                        vname = 'unknown'
+                        if   'B1' in key and 'hori' in key:
+                            vname = 'B1&nbsp;horiz.&nbsp;IP'
+                            lname = 'B1 horizont IP pos.'
+                        elif 'B1' in key and 'vert' in key:
+                            vname = 'B1&nbsp;vert.&nbsp;IP'
+                            lname = 'B1 vertical IP pos.'
+                        elif 'B2' in key and 'hori' in key:
+                            vname = 'B2&nbsp;horiz.&nbsp;IP'
+                            lname = 'B2 horizontal IP pos.'
+                        elif 'B2' in key and 'vert' in key:
+                            vname = 'B2&nbsp;vert.&nbsp;IP'
+                            lname = 'B2 vertical IP pos.'
+                        legend.append( lname )
+                        fullprint += '<tr><td style="text-align:left">%s:&nbsp;</td><td>(</td><td style="text-align:right">&nbsp;%s</td><td style="text-align:left">&nbsp;&#177;&nbsp;</td><td style="text-align:left">%.4g</td><td>)&nbsp;um</td><td>&nbsp;&nbsp;&nbsp;</td>' % (vname, ('%.4g' % y).replace('-','&minus;'), y2)
+
+                        if ik == 0: fullprint += '<td rowspan="4">REPLACEME</td>'
+                        fullprint += '</tr>'
+
+                    # write to file (as text and TGraphs)
+                    bpmrootfilename = Run.Datapath + '/bpm_output_run%i.root' % run.runNr
+                    SaveGraphsToFile( bpmrootfilename, keys, xvec, yvec, "TimeOffset", toffset )
+
+                    bpmtextfilename = Run.Datapath + '/bpm_output_run%i.txt' % run.runNr
+                    bpmout          = open( bpmtextfilename, 'w' )
+
+                    bpmout.write( '# BPM Output for run %i\n' % run.runNr )
+                    bpmout.write( '# Start - end of run: %s [UTC]\n' % run.timestr('txt') )
+                    bpmout.write( '# Time offset applied below in seconds: %i\n' % int(toffset) )
+                    bpmout.write( '#\n' )
+                    bpmout.write( '# ---------------------------------------------------------------------------------\n' )
+                    for ik,key in enumerate(keys):
+                        bpmout.write( '# Output for variable: "%s"\n' % key )
+                        bpmout.write( '# Format: index / timestamp (seconds) wrt. begin of run / BPM position in microns\n' )
+                        bpmout.write( '#\n' )
+                        for i in range(len(xvec[ik])):
+                            bpmout.write( "%4i  %9.2f  %14.6f\n" % (i, xvec[ik][i], yvec[ik][i]) )
+                        bpmout.write( '#\n' )
+                        bpmout.write( '# ---------------------------------------------------------------------------------\n' )
+                    bpmout.close()
+
+                    fullprint += '<tr><td colspan=8><hr style="width:100%; background-color:#999999; height:1px; margin-left:0; border:0"/></td></tr>'
+                    fullprint += '<tr><td colspan=8 style="text-align:left"><a href="%s" target="_blank" title="Tabulated BPM information versus time for run %i"><i>Click here for tabulated BPM values versus time...</i></a></td></tr>' % (bpmtextfilename, run.runNr)
+                    fullprint += '<tr><td colspan=8 style="text-align:left"><a href="%s" target="_blank" title="BPM information versus time for run %i as four TGraph objects in ROOT file"><i>Right-click to download ROOT file with TGraphs...</i></a></td></tr>' % (bpmrootfilename, run.runNr)
+                    fullprint += '</table>' 
+
+                    # make plot
+                    path = makeTimePlotList( xvec, xveclb, yvec, toffset, deltat, ymin, ymax,
+                                             'Time of day (UTC)', 'Beam position (microns)', legend,
+                                             'bp_vs_time_run_%i' % (run.runNr),
+                                             'Beam position versus time of day for run %i' % (run.runNr),
+                                             Run.Datapath, '' )
+
+                    replacetxt = '<img src="%s" align="left" width="70px">' % path
+                    fullprint = fullprint.replace('REPLACEME',replacetxt)
+
+                    # create window and tooltip
+                    wincontent = '<table class=&quot;outer&quot; style=&quot;padding: 5px&quot;><tr><td>'
+                    wincontent += '<strong><b>LHC beam positions at IP verssu time for run %i:</b></strong><br><font size=&quot;-1&quot;><font color=&quot;#888888&quot;>(Begin/end of run: %s)</font></font><hr color=&quot;black&quot; size=1>' % (run.runNr, run.timestr('html', run.runNr != Run.runnropen))
+                    wincontent += '<table style=&quot;padding: 0px&quot;><tr><td>'
+                    wincontent += '<img src=&quot;%s&quot; align=&quot;left&quot;></td>' % path
+                    wincontent += '</td></tr></table>'
+                    wincontent += """<hr color=&quot;red&quot; size=1><font color=&quot;#777777&quot;><font size=&quot;-1&quot;><i><font size=&quot;-2&quot;>Created by AtlRunQuery on: %s</font></i></font></td></tr></table><script type=&quot;text/javascript&quot;></script></body></html>""" % str(datetime.datetime.now())
+                    wincontent += '</td></tr></table>'
+
+
+                    openwincmd = HU.OpenWindow(wincontent,title="Summary of LHC information")
+
+                    # put into html page
+                    s += '<td style="text-decoration:none">%s<div class="showTip BPM stream" style="display:inline;cursor:pointer">%s</div></a></td>' % (tooltipkey, fullprint)
+                    continue
+
+                if 'ofllumi:' in k:
+
+                    if ofllumiFlag: continue
+                    ofllumiFlag = True
+
+                    # find range with stable beams (requires LHC information to be available)
+                    hasStableBeamsInfo, xvecStb = run.getStableBeamsVector()
+
+                    # find all channels that should be printed
+                    kref  = []
+                    chans = []
+                    tags  = []
+                    for kp in Run.ShowOrder:
+                        if 'ofllumi:' in kp.ResultKey:
+                            name, chanstr, tagstr = kp.ResultKey.split(':')
+                            kref.append(kp)
+                            chans.append(chanstr)
+                            tags.append(tagstr)
+
+                    # get the channel names
+                    chanstr = []
+                    for ch in chans:
+                        ich = int(ch)
+                        if OLCAlgorithms.has_key(ich): chanstr.append(OLCAlgorithms[ich])
+                        else:                          chanstr.append('Unknown')
+
+                    # insert events per LB
+                    xvec       = []
+                    yvec       = []
+                    peaklumi   = []
+                    intlumi    = []
+                    intlumiStb = []
+                    for ikp,kp in enumerate(kref):
+                        yvec.append([])
+                        peaklumi.append(-1)
+                        intlumi.append(0)
+                        intlumiStb.append(0)
+                        for entry in run.data[kp]:
+                            if entry.startlb == 0: continue
+                            val = entry.value if entry.value!='n.a.' and entry.value>0 else 0
+                            lastlb = min(entry.lastlb,run.lastlb)
+                            lbs = range(entry.startlb,lastlb+1)
+                            if ikp == 0: xvec += lbs
+                            yvec[-1] += len(lbs)*[float(val)]
+
+
+                    for idx,(lbtime,lbendtime) in enumerate(run.lbtimes):
+                        lb=idx+1                    
+                        dt = (float(lbendtime)-float(lbtime))/1.E9
+                        for ich in range(len(chans)):
+                            tmp = yvec[ich]
+                            intlumi[ich]   += tmp[idx]*dt/1000.0  # unit of yvec was: ub-1 s-1 -> nb-1
+                            if lb in xvecStb: intlumiStb[ich] += yvec[ich][idx]*dt/1000.0
+
+                            yvec[ich][idx] *= 1.0                # unit of yvec was: ub-1 s-1, transform to: 10^30 cm-2s-1
+                            if yvec[ich][idx] > peaklumi[ich]: peaklumi[ich] = yvec[ich][idx]
+
+                    # line to be printed in column
+                    fullprint_ = ''
+                    if hasStableBeamsInfo:
+                        for ich,ch in enumerate(chans):
+                            fullprint_ += 'Integrated&nbsp;(channel:&nbsp;%s):&nbsp;%0.4g<br>Stable&nbsp;B:&nbsp;%0.4g<br>' % (ch,intlumi[ich],intlumiStb[ich])                                
+                        histoText  = 'Integr. lumi (channel: %i): %.4g nb-1 (all LBs) and %.4g nb-1 (stable beams)' % (0, intlumi[0],intlumiStb[0])
+                    else:
+                        for ich,ch in enumerate(chans):
+                            fullprint_ += 'Integrated&nbsp;(channel:&nbsp;%s):&nbsp;%0.4g<br>' % (ch,intlumi[ich])
+                        histoText  = 'Integr. lumi (channel: %i): %.4g nb-1 (all LBs)' % (0, intlumi[0])
+
+                    # make plot
+                    path = makeLBPlotList( xvec, xvecStb, yvec,
+                                           'Luminosity block number', 'Offline luminosity (10^{30}cm^{-2}s^{-1})', chanstr,
+                                           'ofllumi%s_vs_lb_run_%i' % (chans[0],run.runNr),
+                                           'Offline lumi per LB for run %i' % (run.runNr),
+                                           Run.Datapath, histoText )
+
+                    # create window and tooltip
+                    wincontent  = '<table class=&quot;outer&quot; style=&quot;padding: 5px&quot;><tr><td>'
+                    wincontent += '<strong><b>Offline luminosity per LB for run %i:</b></strong><br><font size=&quot;-1&quot; color=&quot;#888888&quot;>(Begin/end of run: %s)</font>' % (run.runNr, run.timestr('html', run.runNr != Run.runnropen))
+                    wincontent += '<hr color=&quot;black&quot; size=1>'
+                    wincontent += '<table style=&quot;padding: 0px&quot;><tr><td>'
+                    wincontent += '<img src=&quot;%s&quot; align=&quot;left&quot;>' % path
+                    wincontent += '</td></tr></table>'
+                    wincontent += '<hr color=&quot;black&quot; size=1>'
+                    wincontent += '<table class=&quot;LB&quot;>'
+                    wincontent += '<tr><th>LB</th><th>Start time<br> (%s)</th><th>Duration<br>(sec)</th>' % QC.tzdesc()
+                    for ch in chanstr: 
+                        wincontent += '<th>Inst. luminosity<br>(1e%s&nbsp;cm<sup>&minus;2</sup>s<sup>&minus;1</sup>)<br>[ %s ]</th>' % (run.instlumiunittxt,ch)
+                    wincontent += '<th>Stable beams</th>'
+                    wincontent += '</tr><tr style=&quot;background:%s&quot;>' % '#eeeeee'
+                    for idx,(lbtime,lbendtime) in enumerate(run.lbtimes):
+                        lb=idx+1                    
+                        stbBeams = '&minus;'
+                        if lb in xvecStb: stbBeams = 'T'
+                        timetuple = time.localtime(lbtime/1.E9) if QC.localtime else time.gmtime(lbtime/1.E9)
+                        wincontent += '<td>%i</td><td>%s</td><td>%.2f</td>' % (lb, time.strftime("%X",timetuple), (float(lbendtime)-float(lbtime))/1.E9)
+                        for ich in range(len(chans)):
+                            wincontent += '<td>%.4g</td>' % (yvec[ich][idx])
+                        wincontent += '<td>%s</td>' % stbBeams
+                        if idx%2!=0: col = '#eeeeee'
+                        else:        col = '#ffffff'
+                        wincontent += '</tr><tr style=&quot;background:%s&quot;>' % col
+                    if run.runNr == Run.runnropen: # run still ongoing
+                        wincontent += '<tr><td style=&quot;text-align:left&quot;colspan=&quot;3&quot;><i>&nbsp;&nbsp;Run still ongoing ...</i></td></tr>'
+                    wincontent += '</tr></table>'
+                    wincontent += """<hr color=&quot;red&quot; size=1><font color=&quot;#777777&quot;><font size=&quot;-1&quot;><i><font size=&quot;-2&quot;>Created by AtlRunQuery on: %s</font></i></font></td></tr></table><script type=&quot;text/javascript&quot;></script></body></html>""" % str(datetime.datetime.now())
+                    wincontent += '</td></tr></table>'
+
+                    openwincmd = HU.OpenWindow(wincontent,title="Run query result for online luminosity")
+
+                    # line to be printed in column
+                    fullprint  = '<table class="bcidtable">'
+                    fullprint += '<tr><td colspan="2"><img src="%s" align="left" width="90px"></td></tr>' % path
+                    if hasStableBeamsInfo:
+                        for ich in range(len(chans)):
+                            fullprint += '<tr><td style="text-align:left">Entire&nbsp;run:</td><td style="text-align:left">&nbsp;%0.4g&nbsp;%s<sup>&minus;1</sup></td></tr><tr><td style="text-align:left">Stable&nbsp;beams:</td><td style="text-align:left">&nbsp;%0.4g&nbsp;%s<sup>&minus;1</sup></td></tr><tr><td style="text-align:left">Peak&nbsp;lumi:</td><td style="text-align:left">&nbsp;%0.2g&nbsp;e%s&nbsp;cm<sup>&minus;2</sup>s<sup>&minus;1</sup></td></tr>' % (intlumi[ich], run.lumiunittxt, intlumiStb[ich], run.lumiunittxt, peaklumi[ich], run.instlumiunittxt)
+                    else:
+                        for ich in range(len(chans)):
+                            fullprint += '<td style="text-align:left">All&nbsp;LBs:</td><td style="text-align:left">&nbsp;%0.4g</td></tr>' % (intlumi[ich])
+                    fullprint += '</table>'
+
+                    # put into html page
+                    s += '<td class="showTip OFLLumi stream" style="text-decoration:none; text-align: right">%s%s</a></td>' % (openwincmd, fullprint)  
+                    continue
+
+                if any( [ ('lhc:' in k and not 'beamenergy' in k),
+                          ('TorCurrent' in k),
+                          ('SolCurrent' in k),
+                          ('bs:' in k),
+                          ('Ready for physics' in k),
+                          ] ):
+                    res  = []
+                    keys = []
+
+                    # search unique ranges            
+                    for entry in run.data[k]:
+                        if entry.startlb == 0: continue
+                        val = entry.value
+
+                        try:
+                            val = float(val)
+                            if not 'bs:' in k and not 'ofllumi:' and not 'beam1intensity' in k and not 'beam2intensity' in k: val = round(val) # no floating points, unless it is 'bs'
+                        except ValueError: pass
+
+                        # special treatment for E-beam = 7864
+                        if 'beamenergy' in k and val>=7864: val = 'ASYNC'
+
+                        if not keys or res[-1] != val:
+                            if keys: keys[-1][1] = entry.startlb
+                            res.append ( val )
+                            keys.append( [entry.startlb, entry.endlb] )
+                        elif res[-1] == val:
+                            keys[-1][1] = entry.endlb
+
+
+                    if len(keys) > 1:
+                        s += '<td><table class="triggerlinktable" align="center">'
+                        for i, c in enumerate(keys):
+                            if int(c[0]) != int(c[1])-1:
+                                s += '<tr><td>LB&nbsp;</td><td style="text-align:right">%i</td><td style="text-align:right">&minus;</td><td style="text-align:right">%i:&nbsp;</td>' % (int(c[0]),int(c[1])-1)
+                            else: 
+                                s += '<tr><td>LB&nbsp;</td><td style="text-align:right">%i</td><td style="text-align:right"></td><td style="text-align:right">:&nbsp;</td>' % (int(c[0]))
+                            try:
+                                val = float(res[i])
+                                if 'bs:' in k or 'beam1intensity' in k or 'beam2intensity' in k:
+                                    vt = '%.4g' % abs(val)
+                                    if val < 0: vt = '&minus;' + vt
+                                    if 'e-' in vt: vt = vt.replace('e-','e&minus;')
+                                    s += '<td style="text-align:right">%s</td></tr>' % vt
+                                elif 'ofllumi:' in k:
+                                    s += '<td style="text-align:right">%g</td></tr>' % val
+                                else:
+                                    s += '<td style="text-align:right">%i</td></tr>' % round(val)
+                            except ValueError:
+                                s += '<td style="text-align:left">%s</td></tr>' % res[i].strip()
+                        s += '</table></td>'            
+
+                    else:
+                        try:
+                            if 'bs:' in k:
+                                vt = '%.4g' % abs(float(v))
+                                if float(v) < 0: v = '&minus;' + vt
+                                else:            v = vt
+                                if 'e-' in v: v = v.replace('e-','e&minus;')
+                            else:
+                                v = round(float(v))
+                                if 'beamenergy' in k and v >= 7864: v = 'ASYNC'
+                                else:                               v = '%i' % v                    
+                        except ValueError: pass
+                        s += '<td style="text-align:center;font-size: 85%%">%s</td>' % v
+
+
+                    if ('lhc:stablebeams' in k and 'lhc:beamenergy' in Run.ShowOrder and not 'lhc:beammode' in Run.ShowOrder) or 'lhc:beammode' in k:
+                        imgpath, xvec, yvec, ymax = HU.makeSummaryPlotForLHC(run)
+                        wincontent = HU.makeSummaryPageForLHC(run, yvec, imgpath)
+                        openwincmd = HU.OpenWindow(wincontent, 'Summary of LHC information')
+                        fullprint  = '<table class="bcidtable">'
+                        fullprint += '<tr><td><img src="%s" align="left" width="90px"></td></tr>' % imgpath
+                        fullprint += '<tr><td style="text-align:left">Maximum&nbsp;intensities:<br>Beam&nbsp;1:&nbsp;%0.3g&nbsp;e11&nbsp;protons<br>Beam&nbsp;2:&nbsp;%0.3g&nbsp;e11&nbsp;protons</td></tr>' % (ymax[0], ymax[1])
+                        fullprint += '<tr><td style="text-align:left">Maximum&nbsp;beam&nbsp;energy:<br>%i&nbsp;GeV</td></tr>' % int(ymax[2])
+                        fullprint += '</table>'
+                        fullprint += '<span style="font-size: xx-small; color: #555555">[ <i>Numbers given for stable beam period (if applies)</i> ]</span>'
+                        # put into html page
+                        s += '<td class="showTip LHCSummary stream" style="text-decoration:none; text-align: left">%s %s </a></td>' % (openwincmd, fullprint)  
+
+                    continue
+
+                # all others
+                if v=='n.a.': s += '<td class="tdna">n.a.</td>'
+                else:         s += '<td style="text-align: right">%s</td>' % v
+
+
+    s += "</tr>\n\n"
+
+    ###
+    ###  TOOLTIPS
+    ###
+
+    # here we start filling the tooltips. there are quite a lot and we should be a bit smarter about them.
+    # For instance, there is no need to define the whole table for each single box
+
+    with timer("Tooltips"):
+        createToolTips(run)
+
+    return s
+
+
+
+def createToolTips(run):
+    import CoolRunQuery.html.AtlRunQueryHtmlUtils as HU
+
+    HU.CreateLBTooltip(run)
+
+    # DQ DEFECTS
+    if 'DQ' in Run.ShowOrder:
+        HU.CreateDQTooltip(run)
+
+    # stream overlaps
+    for k in [k for k in Run.ShowOrder if k.Type==DataKey.STREAM and k.ResultKey in run.stats]:
+        HU.CreateStreamOverlapTooltip(run, k)
+
+    # DQ (old)
+    for data_key in Run.ShowOrder:
+        k = data_key.ResultKey
+        if not isDQ(k): continue
+        if not k in run.stats: continue
+        commentbox = ''
+        for (dq,comment), start, end in run.stats[k]["blocks"]:
+            if dq != 'n.a.':
+                if not comment: comment = 'no comment'
+                col = "#000000"
+                if   dq == 'R': col = "#AA0000"
+                elif dq == 'G': col = "#006600"
+                elif dq == 'Y': col = "#716309"
+                if start == end-1:
+                    commentbox += '<tr style="color:%s"><td style="vertical-align:top;">LB&nbsp;</td><td style="text-align:right;vertical-align:top;">%s</td><td style="text-align:right;vertical-align:top;"></td><td style="text-align:right;vertical-align:top;">&nbsp;(%s)&nbsp;:&nbsp;</td><td style="text-align:left;vertical-align:top;"><i><strong><b>"%s"</b></strong></i></td></tr>' % (col,start,dq,comment)
+                else:    
+                    commentbox += '<tr style="color:%s"><td style="vertical-align:top;">LB&nbsp;</td><td style="text-align:right;vertical-align:top;">%s</td><td style="text-align:right;vertical-align:top;">&minus;</td><td style="text-align:right;vertical-align:top;">%s&nbsp;(%s)&nbsp;:&nbsp;</td><td style="text-align:left;vertical-align:top;"><i><strong><b>"%s"</b></strong></i></td></tr>' % (col,start,end-1,dq,comment)
+            else:
+                if start == end-1:
+                    commentbox += '<tr style="color:#222222"><td style="vertical-align:top;">LB&nbsp;</td><td style="text-align:right;vertical-align:top;">%s</td><td style="text-align:right;vertical-align:top;"></td><td style="text-align:right;vertical-align:top;">&nbsp;(n.a.)&nbsp;</td><td style="text-align:left;vertical-align:top;"></td></tr>' % (start)
+                else:
+                    commentbox += '<tr style="color:#222222"><td style="vertical-align:top;">LB&nbsp;</td><td style="text-align:right;vertical-align:top;">%s</td><td style="text-align:right;vertical-align:top;">&minus;</td><td style="text-align:right;vertical-align:top;">%s&nbsp;(n.a.)&nbsp;</td><td style="text-align:left;vertical-align:top;"></td></tr>' % (start,end-1)
+        if commentbox:
+            sp = k.split(':')
+            commentbox = '<strong><b>Comments&nbsp;for&nbsp;%s&nbsp;DQ&nbsp;channel&nbsp;"%s"&nbsp;in&nbsp;run&nbsp;%s:</b></strong>' % (sp[0],sp[1],run.runNr) + '<table>' + commentbox
+            commentbox += '</table>'
+            run.addToolTip( "dqcomm_%s_%i" % (k, run.runNr), commentbox)
+
+
+    # trigger keys
+    lbtrigtypes = { 'L1 PSK': ['L1&nbsp;PSK', 'L1K'], 'HLT PSK' : ['HLT&nbsp;PSK','HLTK'] }
+    for lbtrigtype, c in lbtrigtypes.iteritems():
+        if lbtrigtype in Run.ShowOrder and run.stats[lbtrigtype].has_key('blocks') and len(run.stats[lbtrigtype]['blocks'])>1:
+            boxcontent = '<strong><b>%s&nbsp;evolved&nbsp;during&nbsp;run:</b></strong><br>' % c[0]
+            boxcontent += '<table style="width: auto; border: 0px solid; border-width: margin: 0 0 0 0; 0px; border-spacing: 0px; border-collapse: separate; padding: 0px; font-size: 100%">'
+            for item, start, stop in run.stats[lbtrigtype]['blocks']:
+                boxcontent += '<tr><td>LB&nbsp;</td><td style="text-align:right">%s</td><td style="text-align:right">&minus;</td><td style="text-align:right">%s</td><td style="text-align:right">:&nbsp;%s</td></tr>' % (start,stop-1,item)
+            boxcontent += '</table>'
+            run.addToolTip("%s_%i" % (c[1], run.runNr), boxcontent)
+
+
+    # OLC BCID
+    if any([k for k in Run.ShowOrder if "olc:bcidmask" in k.ResultKey]):
+        boxcontent = Run.TmpBoxContent
+        if boxcontent:
+            Run.addGlobalToolTip("OLCBCID_%i" % run.runNr, boxcontent)
+
diff --git a/Database/CoolRunQuery/python/AtlRunQuerySFO.py b/Database/CoolRunQuery/python/AtlRunQuerySFO.py
new file mode 100644
index 00000000000..44c660df934
--- /dev/null
+++ b/Database/CoolRunQuery/python/AtlRunQuerySFO.py
@@ -0,0 +1,438 @@
+#!/bin/env python
+
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+#
+# ----------------------------------------------------------------
+# Script : AtlRunQuerySFO.py
+# Project: AtlRunQuery
+# Purpose: Utility to retrieve information from SFO DB
+# Authors: Andreas Hoecker (CERN), Joerg Stelzer (DESY)
+# Created: Nov 13, 2008
+# ----------------------------------------------------------------
+#
+# SFO DB schema:
+# ==============================================
+# 
+# Run Table
+# 
+# "SFOID"        "VARCHAR2(32 Bytes)"
+# "RUNNR"        "NUMBER(10,0)"
+# "STREAMTYPE"   "VARCHAR2(32 Bytes)"
+# "STREAM"       "VARCHAR2(32 Bytes)"
+# "STATE"        "VARCHAR2(32 Bytes)" [OPENED,CLOSED,TRANSFERRED]
+# "TZSTATE"      "VARCHAR2(32 Bytes)" filled by TZ
+# "DSNAME"       "VARCHAR2(256 Bytes)"
+# "T_STAMP"      "TIMESTAMP(0)"  "RUN_SEQNUM"    "NUMBER(10,0)"
+# 
+# Lumiblock Table
+# 
+# "SFOID"        "VARCHAR2(32 Bytes)"
+# "RUNNR"        "NUMBER(10,0)"
+# "LUMIBLOCKNR"  "NUMBER(10,0)"
+# "STREAMTYPE"   "VARCHAR2(32 Bytes)"
+# "STREAM"       "VARCHAR2(32 Bytes)"
+# "STATE"        "VARCHAR2(32 Bytes)" [OPENED,CLOSED,TRANSFERRED]
+# "TZSTATE"      "VARCHAR2(32 Bytes)" filled by TZ
+# "T_STAMP"      "TIMESTAMP(0)"  "LUMIBLOCK_SEQNUM"    "NUMBER(10,0)"
+# 
+# File Table
+# 
+# "LFN"          "VARCHAR2(256 Bytes)" filename
+# "FILENR"       "NUMBER(10,0)"
+# "SFOID"        "VARCHAR2(32 Bytes)"
+# "RUNNR"        "NUMBER(10,0)"
+# "LUMIBLOCKNR"  "NUMBER(10,0)"
+# "STREAMTYPE"   "VARCHAR2(32 Bytes)"
+# "STREAM"       "VARCHAR2(32 Bytes)"
+# "SFOHOST"      "VARCHAR2(64 Bytes)"
+# "TRANSFERSTATE" "VARCHAR2(32 Bytes)" [ONDISK,TRANSFERRED]
+# "FILESTATE"    "VARCHAR2(32 Bytes)" [OPENED,CLOSED,DELETED]
+# "FILEHEALTH"   "VARCHAR2(32 Bytes)" [SANE,TRUNCATED]
+# "TZSTATE"      "VARCHAR2(32 Bytes)" filled by TZ
+# "FILESIZE"     "NUMBER(10,0)"
+# "GUID"         "VARCHAR2(64 Bytes)"
+# "CHECKSUM"     "VARCHAR2(64 Bytes)" Adler-32
+# "PFN"          "VARCHAR2(1024 Bytes)" /path/filename on Castor
+# "SFOPFN"       "VARCHAR2(1024 Bytes)" /path/filename on SFO
+# "NREVENTS"     "NUMBER(10,0)"
+# "T_STAMP"      "TIMESTAMP(0)" "ENDTIME"    "TIMESTAMP(0)" UTC time
+# "FILE_SEQNUM"  "NUMBER(10,0)"
+# 
+# Index Table
+# 
+# "SEQNAME"      "VARCHAR2(64 Bytes)"
+# "SEQINDEX"     "NUMBER(10,0)"
+# "LASTMOD"      "TIMESTAMP(0)"
+#
+# Schema of new OVERLAP table:
+# 
+# "SFOID" 		VARCHAR2(32 BYTE)
+# "RUNNR" 		NUMBER(10,0)
+# "REFERENCE_STREAM" 	VARCHAR2(128 BYTE)
+# "OVERLAP_STREAM" 	VARCHAR2(128 BYTE)
+# "OVERLAP_EVENTS"	NUMBER(10,0)
+# "OVERLAP_RATIO" 	BINARY_FLOAT
+# "TYPE" 			VARCHAR2(32 BYTE) [RAW, FILE]
+# "T_STAMP" 		TIMESTAMP (0)
+# "OVERLAP_SEQNUM" 	NUMBER(10,0)
+# 
+# 
+# Each row provides the overlap for a stream pair (in a given run and
+# SFO). The pair is composed by a reference stream and an overlap stream.
+# We can distinguish between two cases:
+# 
+# a) reference stream = overlap stream
+# The row provides the total number of events in the stream
+# (OVERLAP_EVENTS) and OVERLAP_RATIO is 1
+# 
+# b) reference stream != overlap stream
+# The row provides the overlap between the two streams (OVERLAP_EVENTS).
+# OVERLAP_RATIO is defined as OVERLAP_EVENTS/#(events for reference stream).
+# 
+# The attached screenshot is an example of the expected result (with two
+# streams only).
+# 
+# 
+# The TYPE column is needed to distinguish the source level of the counters:
+# 
+# RAW: raw streams at the input of the SFO
+# FILE: resulting streams after the SFO stream processing
+# (inclusive/exclusive, late, ...)
+#  
+
+from __future__ import with_statement
+from utils.AtlRunQueryTimer import timer
+
+from utils.AtlRunQueryCache import Cache
+from .AtlRunQueryRun import Run
+
+import cx_Oracle
+from time import time
+from collections import defaultdict
+
+@Cache("cache/sfo","%s_run_%i")
+def executeCachedQuery(run,cu,q,cachekey):
+    cu.execute(q, run=run)
+    return cu.fetchall()
+
+def executeQuery(run,cu,q,cachekey):
+    cu.execute(q, run=run)
+    return cu.fetchall()
+
+
+
+##############################################################
+
+# The following 5 methods are used in the stream selector
+
+##############################################################
+
+def GetSFO_streamsAll( cursor, runlist ):
+    res = defaultdict(list)
+    q = "SELECT DISTINCT STREAMTYPE, STREAM FROM SFO_TZ_RUN WHERE RUNNR=:run"
+    cursor.prepare(q)
+
+    for run in runlist:
+        cursor.execute(q,run=run)
+        qr = cursor.fetchall()
+        for e in qr:
+            res[run].append("%s_%s" % (e[0],e[1]))
+
+    return res
+
+
+def GetSFO_filesAll( cursor, runlist ):
+    """returns nfiles, fsize, nevents"""
+    res = defaultdict(dict)
+    q = "SELECT STREAMTYPE, STREAM, COUNT(FILESIZE), SUM(FILESIZE), SUM(NREVENTS) FROM SFO_TZ_File WHERE RUNNR = :run GROUP BY STREAM, STREAMTYPE"
+    cursor.prepare(q)
+
+    for run in runlist:
+        if run==Run.runnropen:
+            qr = executeQuery(run, cursor, q, cachekey=("filesAll",run))
+        else:
+            qr = executeCachedQuery(run, cursor, q, cachekey=("filesAll",run))
+        for e in qr:
+            key = "%s_%s" % (e[0],e[1])
+            res[run][key] = e[2:5] # #files, filesize, nevents
+    return res
+
+
+
+def GetSFO_LBsAll( cursor, runlist ):
+    res = defaultdict(dict)
+    q = "SELECT STREAMTYPE, STREAM, MIN(LUMIBLOCKNR), MAX(LUMIBLOCKNR), COUNT(DISTINCT LUMIBLOCKNR) FROM SFO_TZ_Lumiblock WHERE RUNNR=:run GROUP BY STREAM, STREAMTYPE"
+    cursor.prepare(q)
+
+    for run in runlist:
+        if run==Run.runnropen:
+            qr = executeQuery(run, cursor, q, cachekey=("LBsAll",run))
+        else:
+            qr = executeCachedQuery(run, cursor, q, cachekey=("LBsAll",run))
+        for e in qr:
+            key2 = "%s_%s" % (e[0],e[1])
+            res[run][key2] = e[2:5] # minlb,maxlb,nlb
+    return res
+
+
+
+def GetSFO_NeventsAll( cursor, runlist ):
+    # due to the amount of information oracle access is faster than file access
+    res = {}
+    q = "SELECT STREAMTYPE, STREAM, LUMIBLOCKNR, SUM(NREVENTS) FROM SFO_TZ_File WHERE RUNNR=:run GROUP BY STREAMTYPE, STREAM, LUMIBLOCKNR ORDER BY LUMIBLOCKNR"
+    cursor.prepare(q)
+    
+    for run in runlist:
+        if run==Run.runnropen:
+            qr = executeQuery(run, cursor, q, cachekey=("NeventsAll",run))
+        else:
+            qr = executeCachedQuery(run, cursor, q, cachekey=("NeventsAll",run))
+        res[run] = defaultdict(list)
+        for e in qr:
+            key2 = "%s_%s" % (e[0],e[1])
+            res[run][key2].append(e[2:4]) # lbNr, NrEv
+
+    return res
+
+
+def GetSFO_overlapAll( cursor, runlist ):
+    """returns number of overlap events"""
+    res = {}
+    q = "SELECT REFERENCE_STREAM, OVERLAP_STREAM, SUM(OVERLAP_EVENTS) FROM SFO_TZ_Overlap WHERE TYPE='FILE' and RUNNR=:run GROUP BY REFERENCE_STREAM, OVERLAP_STREAM"
+    cursor.prepare(q)
+
+    for run in runlist:
+        if run==Run.runnropen:
+            qr = executeQuery(run, cursor, q, cachekey=("overlapAll",run))
+        else:
+            qr = executeCachedQuery(run, cursor, q, cachekey=("overlapAll",run))
+            
+        res[run] = defaultdict(dict)
+        for e in qr:
+            res[run][e[0]][e[1]] = e[2] # overlap
+
+    return res
+
+
+
+
+##############################################################
+
+# The following function is used by the XML file maker
+
+# we store only information about physics streams
+
+##############################################################
+
+
+def GetSFO_NeventsAllPhysics( cursor, runlist ):
+    res = {}
+    q = "SELECT STREAM, LUMIBLOCKNR, SUM(NREVENTS) FROM SFO_TZ_File WHERE RUNNR=:run AND STREAMTYPE='physics' GROUP BY STREAM, LUMIBLOCKNR ORDER BY LUMIBLOCKNR"
+    cursor.prepare(q)
+    
+    for run in runlist:
+        if run==Run.runnropen:
+            qr = executeQuery(run, cursor, q, cachekey=("NeventsAllPhysics",run))
+        else:
+            qr = executeCachedQuery(run, cursor, q, cachekey=("NeventsAllPhysics",run))
+        res[run] = defaultdict(list)
+        for e in qr:
+            key2 = "physics_%s" % e[0]
+            res[run][key2].append(e[1:3]) # lbNr, NrEv
+
+    return res
+
+
+
+##############################################################
+
+# The following function is used by the EventSelector
+
+##############################################################
+
+def GetSFO_NphysicseventsAll( cursor, runlist ):
+    res = {}
+    q = "SELECT SUM(OVERLAP_EVENTS) from SFO_TZ_OVERLAP WHERE RUNNR=:run AND TYPE='EVENTCOUNT' AND REFERENCE_STREAM='physics_EventCount'"
+    cursor.prepare(q)
+    for run in runlist:
+        if run==Run.runnropen or 1: # FIXME problem in cache
+            qr = executeQuery(run, cursor, q, cachekey=("SumOverlap",run))
+        else:
+            qr = executeCachedQuery(run, cursor, q, cachekey=("SumOverlap",run))
+        for e in qr:
+            if e[0]!=None: res[run] = e[0]
+    return res
+
+
+
+
+def GetSFO_lastNruns( cursor, nruns ):
+    """returns list of last 'nruns' run numbers, where at least one stream is not calibration"""
+    cursor.execute( "SELECT RUNNR,STATE FROM (SELECT UNIQUE RUNNR,STATE FROM SFO_TZ_RUN WHERE STREAMTYPE!='calibration' AND RUNNR < 999999 ORDER BY RUNNR DESC) SFO_TZ_RUN2 WHERE rownum<=:arg_1", arg_1=nruns )
+    return cursor.fetchall()
+
+def runInfo(runno, streams):
+    if streams==[]:
+        print "No information available for run %i" % runno
+        return
+
+    print 'Output for run number: %i' % runno
+    print '--------------------------------------------------------------------------------'
+    print 'Streams:'
+    print streams
+    print ' '
+    print ' '
+    for s in streams:
+        minlb, maxlb, lbs = GetSFO_LBs( cursor, runno, s )
+        print 'For Stream: %25s: min - max LBs: %i - %i \t(Num: %i)' % (s, minlb, maxlb, lbs)
+
+        result = GetSFO_Nevents( cursor, runno, s )
+        lbold = -1
+        allnev = 0
+        for lb,nev in result:
+            if lb != lbold:
+                if lbold != -1: print s,'\t',lbold,'\t',allnev
+                allnev = nev
+                lbold = lb
+            else:
+                allnev += nev
+            #for lb in range(minlb,maxlb+1):
+            #nev = GetSFO_NeventsPerLB( cursor, runno, s, lb )
+            #print '       - LB: %i has %s events' % (lb,nev)
+
+    print ' '
+    return
+    totnf = totsize = totev = 0
+    for s in streams:
+        nfiles, size, events = GetSFO_files( cursor, runno, s )
+        totnf   += nfiles
+        totsize += size
+        totev   += events
+        print 'Stream %-25s : %i files, %.2f GB, %i events' % (s, nfiles, size/1.0e9, events)
+    
+    print '--------------------------------------------------------------------------------'
+    print 'Total  %-25s : %i files, %.2f GB, %.2f mio events' % (' ', totnf, totsize/1.0e9, totev/1.0e6)
+    print '--------------------------------------------------------------------------------'
+
+    print 'Check overlaps for stream pairs'
+    for i in range(0,len(streams)):
+        nfilesi, sizei, eventsi = GetSFO_files( cursor, runno, streams[i] )
+        for j in range(i,len(streams)):
+            nfilesj, sizej, eventsj = GetSFO_files( cursor, runno, streams[i] )
+            eventsij                = GetSFO_overlap( cursor, runno, streams[i], streams[j] )
+            if eventsij:
+                print '   [ %28s, %28s ] = %g' % (streams[i], streams[j], eventsij)
+            else:
+                print '   [ %28s, %28s ] = None' % (streams[i], streams[j])
+
+
+
+##############################################################
+#
+# The following function is used to get OKS info
+#
+##############################################################
+
+def SetOKSLinks( runlist ):
+    from utils.AtlRunQueryUtils import coolDbConn
+    conn = coolDbConn.GetAtlasRunDBConnection()
+    cursor = conn.cursor()
+    query = "select ConfigSchema,ConfigData from ATLAS_RUN_NUMBER.RunNumber where RunNumber=:run"
+    cursor.prepare(query)
+    for run in runlist:
+        cursor.execute(query, run=run.runNr)
+        re = cursor.fetchall()
+        run.addResult('oks',re[0])
+
+def main():
+    test_oks = True
+    test_sfo = False
+
+    if test_oks:
+        #from os import environ as env
+        #from CoolRunQuery.AtlRunQueryUtils import coolDbConn
+        #coolDbConn.get_auth('oracle://atlr/rn_r') # only in /afs/cern.ch/atlas/project/tdaq/databases/.coral/authentication.xml
+        #print coolDbConn.get_auth('oracle://ATLAS_COOLPROD/ATLAS_COOLOFL_TRIGGER')
+        from CoolRunQuery.AtlRunQuerySFO import SetOKSLinks
+        SetOKSLinks([Run(178211)])
+
+    if test_sfo:
+
+        runno = 122050
+        import sys
+        if len(sys.argv)>1:
+            runno = int(sys.argv[1])
+
+        runno = [140541L, 140571L, 140579L, 140592L, 140616L, 140620L,
+        140622L, 140638L, 140670L, 140682L, 140704L, 140737L, 140747L,
+        140748L, 140754L, 140762L, 140765L, 140769L, 140772L, 140776L,
+        140790L, 140794L, 140822L, 140836L, 140842L, 140929L, 140953L,
+        140955L, 140974L, 140975L, 141046L, 141059L, 141066L, 141079L,
+        141109L, 141150L, 141189L, 141192L, 141194L, 141203L, 141209L,
+        141226L, 141234L, 141236L, 141237L, 141238L, 141266L, 141270L,
+        141359L, 141374L, 141387L, 141398L, 141401L, 141403L, 141461L,
+        141473L, 141474L, 141525L, 141527L, 141529L, 141533L, 141534L,
+        141561L, 141562L, 141563L, 141565L, 141599L, 141624L, 141655L,
+        141667L, 141670L, 141688L, 141689L, 141691L, 141695L, 141700L,
+        141702L, 141704L, 141705L, 141706L, 141707L, 141718L, 141721L,
+        141730L, 141746L, 141748L, 141749L, 141755L, 141769L, 141807L,
+        141811L, 141818L, 141841L, 141915L, 141928L, 141976L, 141979L,
+        141994L, 141998L, 141999L, 142042L, 142065L, 142081L, 142091L,
+        142094L, 142111L, 142123L, 142125L, 142128L, 142133L, 142144L,
+        142149L, 142154L, 142155L, 142157L, 142159L, 142161L, 142165L,
+        142166L, 142171L, 142174L, 142183L, 142185L, 142187L, 142189L,
+        142190L, 142191L, 142192L, 142193L, 142194L, 142195L, 142199L,
+        142203L, 142205L, 142210L, 142214L, 142216L, 142240L, 142258L,
+        142259L, 142265L, 142291L, 142301L, 142308L, 142309L, 142310L,
+        142319L, 142356L, 142368L, 142383L, 142390L, 142391L, 142392L,
+        142394L, 142395L, 142397L, 142400L, 142401L, 142402L, 142403L,
+        142404L, 142405L, 142406L, 143019L, 143023L, 143027L, 143033L,
+        143034L, 143131L, 143136L, 143143L, 143163L, 143169L, 143171L,
+        143178L, 143182L, 143185L, 143190L, 143192L, 143198L, 143203L,
+        143204L, 143205L, 143207L, 143210L, 143218L, 143222L, 143225L,
+        143236L, 143242L]
+
+        #runno = range(141000,143000)
+
+
+        from utils.AtlRunQueryUtils import coolDbConn
+        connection = coolDbConn.GetSFODBConnection()
+        cursor     = connection.cursor()
+
+        # find last N runs
+        if False:
+            n = 10
+            runs = GetSFO_lastNruns( cursor, n )
+            print 'Last %i runs:' % n
+            for r in runs:
+                print '... %i' % r
+            sys.exit()
+
+        # retrieve streams
+        if True:
+            start = time()
+            streams = GetSFO_streamsAll( cursor, runno )
+            print "streams",time()-start
+            start = time()
+            lbs     = GetSFO_LBsAll    ( cursor, runno )
+            print "lbs",time()-start
+            start = time()
+            nev     = GetSFO_NeventsAll( cursor, runno )
+            print "events",time()-start
+            start = time()
+            files   = GetSFO_filesAll  ( cursor, runno )
+            print "files",time()-start
+            start = time()
+            over    = GetSFO_overlapAll( cursor, runno )
+            print "overlap",time()-start
+
+
+        print "Query execution time: %f sec" % (time()-start)
+
+        cursor.close()
+        connection.close()
+
+
+
+if __name__ == '__main__':
+    main()
diff --git a/Database/CoolRunQuery/python/AtlRunQuerySelectorWorker.py b/Database/CoolRunQuery/python/AtlRunQuerySelectorWorker.py
new file mode 100644
index 00000000000..80c1e8cd2a5
--- /dev/null
+++ b/Database/CoolRunQuery/python/AtlRunQuerySelectorWorker.py
@@ -0,0 +1,303 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+
+#import the selectors
+from selector.AtlRunQuerySelectorDQ      import DQSelector
+from selector.AtlRunQuerySelectorTrigger import TrigKeySelector, BGSKeySelector, L1TrigKeySelector, HLTTrigKeySelector, RatesSelector, TriggerSelector
+from selector.AtlRunQuerySelectorMisc    import BPMSelector, LArcondSelector, DatasetsSelector, DetectorSelector, FilenameSelector, PartitionSelector, ReadyForPhysicsSelector, DurationSelector, BFieldCondition, BFieldSelector
+from selector.AtlRunQuerySelectorEvents  import EventSelector, AllEventsSelector, L1EventsSelector
+from selector.AtlRunQuerySelectorStreams import StreamSelector
+from selector.AtlRunQuerySelectorLhcOlc  import LHCSelector, LHCCondition, OLCFillParamsCondition, OLCLBDataCondition, OLCLumiSelector, LuminositySelector, BeamspotSelector
+
+from .AtlRunQueryRun                     import Run
+
+
+class SelectorWorker:
+
+    class SelDescr:
+        def __init__(self,selector, priority, doesSelect, doesShow, executed):
+            self.selector   = selector
+            self.priority   = priority
+            self.doesSelect = doesSelect
+            self.doesShow   = doesShow
+            self.executed   = executed
+
+
+    __selectors = []
+    __executedSelectorsInOrder = []
+    __showSelectorsInOrder = []
+    __selectorDependencies = { 'trigger':['trigkey','l1trigkey','hlttrigkey'],
+                               'dataquality':['readyforphysics']
+                               }
+
+    __creationRules = {
+        'dataquality'     : 'DQSelector',
+        'streams'         : 'StreamSelector',
+        'trigger'         : 'TriggerSelector',
+        'datasets'        : 'DatasetsSelector',
+        'rates'           : 'RatesSelector',
+        'lhc'             : 'LHCSelector',
+        'bfield'          : 'BFieldSelector',
+        'events'          : 'EventSelector',
+        'allevents'       : 'AllEventsSelector',
+        'release'         : 'TrigKeySelector',
+        'trigkey'         : 'TrigKeySelector',
+        'l1trigkey'       : 'L1TrigKeySelector',
+        'hlttrigkey'      : 'HLTTrigKeySelector',
+        'bgskey'          : 'BGSKeySelector',
+        'detmask'         : 'DetectorSelector',
+        'olclumi'         : 'OLCLumiSelector',
+        'olcfillparams'   : 'OLCFillParamsCondition',
+        'olclbdata'       : 'OLCLBDataCondition',
+        'datasets'        : 'DatasetsSelector',
+        'partition'       : 'PartitionSelector',
+        'readyforphysics' : 'ReadyForPhysicsSelector',
+        'larcond'         : 'LArcondSelector',
+        'luminosity'      : 'LuminositySelector',
+        'beamspot'        : 'BeamspotSelector',
+        'bpm'             : 'BPMSelector',
+        'filenametag'     : 'FilenameSelector'
+        }
+
+
+    @classmethod
+    def selectors(cls):
+        for s in SelectorWorker.getOrderedSelectorList():
+            if s.executed: continue
+            needs = cls.getOrderedNeeds(s)
+            for ss in needs:
+                if ss.executed: continue
+                yield ss.selector
+                cls.__executedSelectorsInOrder += [ss]
+                ss.executed=True
+            yield s.selector
+            cls.__executedSelectorsInOrder += [s]
+            s.executed=True
+
+    @classmethod
+    def executedSelectors(cls):
+        for s in cls.__executedSelectorsInOrder:
+            yield s.selector
+
+    @classmethod
+    def getOrderedNeeds(cls, client):
+        needs = []
+        selname = client.selector.name
+        if selname in cls.__selectorDependencies:
+            dependson = cls.__selectorDependencies[selname]
+            for d in dependson:
+                dep = cls.findSelectorDescriptor(d)
+                if dep==None:
+                    raise RuntimeError('Selector %s depends on %s which is not defined' % (selname,d))
+                needs.insert(0, dep)
+        return needs
+
+    
+    @classmethod
+    def addSelector(cls, selector, priority):
+        s = cls.findSelectorDescriptor(selector.name)
+        if s:
+            return s.selector
+        cls.__selectors += [cls.SelDescr(selector=selector,priority=priority,doesSelect=True,doesShow=False,executed=False)]
+        return cls.__selectors[-1].selector
+
+
+    # pure selector search by class name and instance name
+    @classmethod
+    def findSelectorDescriptor(cls, selname, selcls=None):
+        """ returns a SelDescr if name and class match"""
+        for s in cls.__selectors:
+            if s.selector.name == selname and (selcls==None or selcls==s.selector.__class__.__name__):
+                return s
+        return None
+
+    @classmethod
+    def getShowSelector(cls, selname, *args, **kwargs):
+        selcls = SelectorWorker.__creationRules[selname]
+        # see if the selector is already there
+        s = cls.findSelectorDescriptor(selname, selcls)
+        if s:
+            s.doesShow=True
+            cls.__showSelectorsInOrder += [s]
+            try: s.selector.addShowSelector(*args, **kwargs)
+            except: pass
+        else:
+            s = cls.CreateSelector( selname, True, *args, **kwargs)
+            cls.__showSelectorsInOrder += [s]
+            cls.__selectors += [s]
+        return s.selector
+
+    @classmethod
+    def CreateSelector( cls, selname, doesShow, *args, **kwargs):
+        selcls = SelectorWorker.__creationRules[selname]
+        exec('thecls=%s' % selcls)
+        newsel = thecls(name=selname, *args, **kwargs)
+        print "CREATING SELECTOR %s %s('%s')" % (("SHOW" if doesShow else "RETRIEVE"), selcls, selname)
+        s = cls.SelDescr(selector=newsel, priority=0, doesSelect=False, doesShow=True, executed=False)
+        return s
+
+    
+    @classmethod
+    def getRetrieveSelector(cls, selname, selcls=None, *args, **kwargs):
+        s = cls.findSelectorDescriptor(selname, selcls)
+        if s:
+            try: s.selector.addShowSelector()
+            except: pass
+            return s.selector
+        elif selcls!=None:
+            s = cls.CreateSelector( selname, False, *args, **kwargs)
+            cls.__selectors += [s]
+            return s.selector
+        else:
+            return None
+    
+
+    @classmethod
+    def getOrderedSelectorList(cls):
+        # Highes priority first
+        sortedSel = cls.__selectors
+        sortedSel.sort(lambda x,y: y.priority-x.priority)
+        return sortedSel
+
+    @classmethod
+    def setApplySelection(cls):
+        for s in cls.__selectors:
+            s.selector.applySelection = s.doesSelect
+
+    @classmethod
+    def setShowOutput(cls):
+        for s in cls.__showSelectorsInOrder:
+            s.selector.setShowOutput()
+
+        
+    @classmethod
+    def parseSelectorOptions(cls,options):
+
+        if options.events:
+            cls.addSelector( EventSelector(name = 'events', events = options.events), 280 )
+
+        if options.larcond:
+            cls.addSelector( LArcondSelector(name = 'larcond', larcond = options.larcond), 115 )
+
+        if options.datasets:
+            cls.addSelector( DatasetsSelector(name = 'datasets', datasets = options.datasets), 110 )
+
+        if options.duration:
+            cls.addSelector( DurationSelector(name = 'duration', duration = options.duration), 95 )
+
+        if options.streams:
+            cls.addSelector( StreamSelector(name = 'streams', streams = options.streams), 95 )
+
+        if options.smklist:
+            cls.addSelector( TrigKeySelector(name = 'trigkey'), 71 ).setSelectSMK(smks = options.smklist)
+
+        if options.release:
+            cls.addSelector( TrigKeySelector(name = 'trigkey'), 70 ).setSelectRelease(release = options.release)
+
+        if options.detmaskin or options.detmaskout:
+            cls.addSelector( DetectorSelector('detmask', options.detmaskin, options.detmaskout), 60 )
+
+        if options.lhc:
+            cls.addSelector( LHCSelector(name = 'lhc', lhc = options.lhc), 48 )
+
+        if options.beamspot:
+            cls.addSelector( BeamspotSelector(name = 'beamspot', beamspot = options.beamspot), 44 )
+
+        if options.olclumi:
+            cls.addSelector( OLCLumiSelector(name = 'olclumi', olclumi = options.olclumi), 43 )
+
+        if options.bpm:
+            cls.addSelector( BPMSelector(name = 'bpm', release = options.bpm), 40 )
+
+        if options.luminosity:
+            cls.addSelector( LuminositySelector(name = 'luminosity', luminosity = options.luminosity), 40 )
+
+        if options.projecttag:
+            cls.addSelector( FilenameSelector(name = 'filenametag', projecttag = options.projecttag), 40 )
+
+        if options.readyforphysics:
+            cls.addSelector( ReadyForPhysicsSelector(name = 'readyforphysics', readyforphysics = options.readyforphysics), 31 )
+
+        if options.partition:
+            cls.addSelector( PartitionSelector(name = 'partition', partition = options.partition), 30 )
+        
+        if options.trigger:
+            cls.addSelector( TriggerSelector(name = 'trigger', trigger = options.trigger), 25 )
+
+        if options.bfield:
+            cls.addSelector( BFieldSelector(name = 'bfield', bf = options.bfield), 10 )
+
+        if options.dqchannels:
+            cls.addSelector( DQSelector(), 50 ).addSelectionChannel(options.dqchannels)
+
+
+
+
+    @classmethod
+    def parseShowOption(cls,options):
+        if not options.show: return
+
+        for s in options.show:
+
+            if s == 'summary' or s == 'dqeff' or s == 'dqsummary' or s == 'dqplots' : pass # handled outside
+
+            elif s=='run': Run.showrunnr = True
+
+            elif s=='time': Run.showtime = True
+
+            elif s=='duration': Run.showduration = True
+
+            elif s[0:3]=='dq ' or s=='dq':
+                SelectorWorker.getShowSelector('dataquality').addShowChannel(s[3:])
+
+            elif s[0:7] == 'streams':
+                SelectorWorker.getShowSelector('streams').addShowStreamPattern(s[8:])
+
+            elif s[0:7] == 'trigger':
+                SelectorWorker.getShowSelector('trigger').addShowTriggerPattern(s[8:])
+
+            elif s[0:8] == 'datasets':
+                SelectorWorker.getShowSelector('datasets').addShowDatasetPattern(s[9:])
+
+            elif s[0:9] == 'trigrates':
+                SelectorWorker.getShowSelector('rates').addPattern(s[10:])
+
+            elif s[0:3] == 'lhc':
+                arg = ''
+                if   'all' in s: arg = 'all'
+                elif 'min' in s: arg = 'min'
+                selector = SelectorWorker.getShowSelector('lhc',addArg=arg)
+
+            elif 'olclumi' in s:
+                SelectorWorker.getShowSelector(s)
+
+            elif s == 'smk':
+                SelectorWorker.getShowSelector('trigkey').setShow('smk')
+
+            elif s == 'trigkeys' or s == 'smk':
+                SelectorWorker.getShowSelector('trigkey').setShow('smk')
+                SelectorWorker.getShowSelector('l1trigkey')
+                SelectorWorker.getShowSelector('hlttrigkey')
+                SelectorWorker.getShowSelector('bgskey')
+
+            elif s == 'release':
+                SelectorWorker.getShowSelector('trigkey').setShow('release')
+
+            elif s[0:10] == 'luminosity':
+                SelectorWorker.getShowSelector('luminosity').addShowTag(s.split(None,1)[1])
+
+            elif s[0:8] == 'beamspot':
+                SelectorWorker.getShowSelector('beamspot',args=s[8:])
+
+            elif s[0:3] == 'bpm':
+                SelectorWorker.getShowSelector('bpm')
+
+            elif s == 'filenametag' or s == 'projecttag':
+                SelectorWorker.getShowSelector('filenametag')
+
+            elif s in ['bfield', 'events', 'allevents', 'detmask', 'olcfillparams', 'olclbdata', 'datasets', 'partition', 'readyforphysics', 'larcond']:
+                SelectorWorker.getShowSelector(s)
+
+            else:
+                raise RuntimeError("ERROR: option 'show %s' not implemented" %s)
+
diff --git a/Database/CoolRunQuery/python/AtlRunQueryTier0.py b/Database/CoolRunQuery/python/AtlRunQueryTier0.py
new file mode 100644
index 00000000000..8b1dc51803c
--- /dev/null
+++ b/Database/CoolRunQuery/python/AtlRunQueryTier0.py
@@ -0,0 +1,54 @@
+#!/bin/env python
+
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+#
+# ----------------------------------------------------------------
+# Script : AtlRunQueryTier0.py
+# Project: AtlRunQuery
+# Purpose: Utility to retrieve information from Tier0 DB
+# Authors: Andreas Hoecker (CERN), Joerg Stelzer (DESY)
+# Created: Nov 4, 2009
+# ----------------------------------------------------------------
+#
+# Tier-0 Schema (dataset class only)
+# ==============================================
+#
+# http://hoecker.home.cern.ch/hoecker/Tier0DatasetSchema.png
+#
+
+import cx_Oracle
+from time import time
+
+def GetTier0_allDatasets( cursor, runlist, dsnamepattern = [] ):
+    res = {}
+    pos = 0
+    blocksize = 200
+    # build dataset selection string
+    dsselstring = ''
+    for p in dsnamepattern:
+        p = p.replace('*','%')
+        dsselstring += "LOWER(DATASETNAME) like LOWER('%s') OR " % p
+    if dsselstring: dsselstring = 'and (' + dsselstring[:len(dsselstring)-4] + ')'
+
+    # do selection
+    while pos<len(runlist):
+        cursor.execute("SELECT DISTINCT RUNNR,DATASETNAME,TYPE,PSTATES,DDM,NFILES,TOTSIZE,TOTEVENTS,CREATIONTIME FROM dataset WHERE RUNNR in (%s) and TYPE!='LOG' %s and not DATASETNAME like '%%.LOG%%'"% (','.join([str(i) for i in runlist[pos:pos+blocksize]]), dsselstring))
+        r = cursor.fetchall()
+        for e in r:
+            res.setdefault(e[0],[]).append((e[1],e[2],e[3],e[4],e[5],e[6],e[7],e[8]))
+        pos += blocksize
+
+    return res
+
+def GetTier0_datasetsAndTypes( cursor, runlist ):
+    res = {}
+    pos = 0
+    blocksize = 200
+    while pos<len(runlist):
+        cursor.execute("SELECT DISTINCT RUNNR,DATASETNAME,TYPE,PSTATES FROM dataset WHERE RUNNR in (%s) and TYPE!='LOG' and not DATASETNAME like '%%.LOG%%'"% ','.join([str(i) for i in runlist[pos:pos+blocksize]]))
+        r = cursor.fetchall()
+        for e in r:
+            res.setdefault(e[0],[]).append((e[1],e[2],e[3]))
+        pos += blocksize
+
+    return res
diff --git a/Database/CoolRunQuery/python/AtlRunQueryVersion.py b/Database/CoolRunQuery/python/AtlRunQueryVersion.py
new file mode 100644
index 00000000000..1419a28b40f
--- /dev/null
+++ b/Database/CoolRunQuery/python/AtlRunQueryVersion.py
@@ -0,0 +1,3 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+SvnVersion = 'CoolRunQuery-00-04-50'
\ No newline at end of file
diff --git a/Database/CoolRunQuery/python/__init__.py b/Database/CoolRunQuery/python/__init__.py
new file mode 100644
index 00000000000..0216ac564f8
--- /dev/null
+++ b/Database/CoolRunQuery/python/__init__.py
@@ -0,0 +1,7 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+
+
+__author__="Andreas Hoecker, Joerg Stelzer"
+__all__= ["AtlRunQueryLib","RunQueryParser"]
+
diff --git a/Database/CoolRunQuery/python/html/AtlRunQueryDQSummary.py b/Database/CoolRunQuery/python/html/AtlRunQueryDQSummary.py
new file mode 100755
index 00000000000..2ffb8747e46
--- /dev/null
+++ b/Database/CoolRunQuery/python/html/AtlRunQueryDQSummary.py
@@ -0,0 +1,969 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+import sys, time, math
+import operator
+
+from ROOT import *
+from CoolRunQuery.AtlRunQueryQueryConfig import QC
+from CoolRunQuery.selector.AtlRunQuerySelectorBase import DataKey
+from CoolRunQuery.utils.AtlRunQueryUtils import importroot
+importroot()
+
+from CoolRunQuery.output.AtlRunQueryRoot import SetStyle
+from CoolRunQuery.utils.AtlRunQueryUtils import timer
+from CoolRunQuery.AtlRunQueryRun import Run
+from CoolRunQuery.AtlRunQueryCOMA import ARQ_COMA
+
+import xmlrpclib
+global server
+server = xmlrpclib.ServerProxy('http://atlasdqm.cern.ch')
+
+global readylb
+global lumifolder
+global usenb
+global unit
+global livetrigger
+
+########################################################################
+def MapToSystem(defect):
+
+    # Store detectors/cp per "family" for readability
+    global_systems_map = {'LAR':'Calo','TILE':'Calo','CALO':'Calo',
+                          'TAU':'Calo','EGAMMA':'Calo','JET':'Calo','MET':'Calo',
+                          'ALFA':'Trigger & Lumi','LCD':'Trigger & Lumi',
+                          'ZDC':'Trigger & Lumi','BCM':'Trigger & Lumi',
+                          'LUMI':'Trigger & Lumi','TRIG':'Trigger & Lumi',
+                          'GLOBAL':'Trigger & Lumi',
+                          'MS_CSC':'Muon','MS_RPC':'Muon','MS_TGC':'Muon','MS_MDT':'Muon',
+                          'MS':'Muon','MBTS':'Muon','MCP':'Muon',
+                          'PIXEL':'Tracking','SCT':'Tracking','TRT':'Tracking',
+                          'ID':'Tracking','BTAG':'Tracking'}
+    words = defect.split('_')
+    for w in words:
+        for item in global_systems_map:
+            if w in item: return global_systems_map[item]
+    return ' '
+
+########################################################################
+
+def ComputeRunLumi(dic,run,lumiperlb):
+    # consider ATLAS ready only
+    global readylb
+    total = 0.
+    for l in lumiperlb:
+        if l not in readylb: continue
+        total += lumiperlb[l]
+    return total
+
+def GetLBLumi(dic,run):
+    global lumifolder
+    global usenb
+    
+    lumifolder = ''
+    lumiperlb = {}
+    for k,v in dic.items():
+        if not 'ofllumi' in k.ResultKey: continue
+        lumifolder = k.ResultKey
+    if lumifolder == '': return lumiperlb
+    lbdic = dic[DataKey(lumifolder)][run]
+    lbtime = dic[DataKey('#LB')][run][1]
+    for i,item in enumerate(lbdic):
+        for lb in range(int(item.startlb),int(item.endlb)):
+            lumiperlb[lb] = 0.
+            if item.value == "n.a.": continue
+            if (lbtime[lb]-lbtime[lb-1])<0: continue
+            # change unit (pb/nb)
+            scale = 0.001
+            if usenb: scale = 1.
+            lumiperlb[lb] = float(item.value)*(lbtime[lb]-lbtime[lb-1])*0.001*scale # output in nb-1/pb-1
+            #print "DEBUG",run,lb,float(item.value),lbtime[lb]-lbtime[lb-1]
+    return lumiperlb
+
+def GetLBLiveFraction(dic,run):
+    global livetrigger
+    livefraction = {}
+    try:
+        #trigrate = dic[DataKey('TriggerRates')][run][0].value['L1_EM5']
+        trigrate = dic[DataKey('TriggerRates')][run][0].value[livetrigger]
+        for item in trigrate:
+           #print '-----',run,item
+           livefraction[item[0]]= 0.
+           if float(item[1]) != 0: livefraction[item[0]] = float(item[3])/float(item[1])
+    except:
+        print "%s trigger not found - no live fraction computation"%livetrigger
+    return livefraction
+
+def GetLBReady(dic,run):
+    rlb = []
+    for b in dic[DataKey('Ready for physics')][run]:
+        for lb in range(b.startlb,b.endlb):
+            if  b.value == "1" :
+                rlb.append(lb)
+    return rlb
+    
+
+########################################################################
+def MakePlot_SummaryLumiLoss(loss,colors,dicsum,name):
+
+    global usenb
+    global unit
+
+    SetStyle()
+    gStyle.SetTitleX(0.5);
+    gStyle.SetTitleAlign(23);
+
+    ## ATLAS Ready Recorded Lumi
+    TotalLumi = dicsum[DataKey('TotalLumi')][0]
+
+    ## x labels
+    xlabels = [s for s in loss]
+
+    ## runs
+    runs = [item for item in loss[xlabels[0]]]
+    runs.sort()
+
+    ## compute TOTAL lumi per system
+    lumi = {}; max = 0.
+    for sys in loss:
+        lumi[sys] = 0.
+        for r in runs: lumi[sys] += loss[sys][r]
+        if lumi[sys] > max: max=lumi[sys]
+    max = max*1.5
+
+    # if no entry, print no plot
+    if max == 0. : return
+    #print "DEBUG", max
+
+    ## create frame
+    t1 = "       Runs [%i-%i]"%(runs[0],runs[-1])
+    if len(runs) == 1: t1 = "            Run [%i]"%runs[0]
+    t2 = "ATLAS Ready Lumi: %.2f %s^{-1}"%(TotalLumi,unit)
+    h1_frame = TH1F("h1_frame","#splitline{%s}{%s}"%(t1,t2),len(loss),-0.5,len(loss)-0.5)
+    SetXLabel(h1_frame,xlabels)
+    h1_frame.SetMinimum(0.)
+    h1_frame.SetMaximum(max)
+    h1_frame.SetTickLength(0.,"X")
+    h1_frame.GetYaxis().SetTitle("Luminosity Loss during ATLAS Ready [%s^{-1}]"%unit)
+    h1_frame.LabelsOption("a","X") # order X label by alphabetical order
+
+    ## create systems plots 
+    h1_lumi = []; text_lumi = []
+    for sys in loss:
+        h1_lumi.append(TH1F("h1_lumi_%s"%sys,"",len(loss),-0.5,len(loss)-0.5))
+        SetXLabel(h1_lumi[-1],xlabels)
+        h1_lumi[-1].LabelsOption("a","X") # order X label by alphabetical order
+        h1_lumi[-1].SetBarWidth(0.90);
+        h1_lumi[-1].SetTickLength(0.,"X")
+        h1_lumi[-1].SetMinimum(0.)
+        h1_lumi[-1].SetMaximum(max)
+        h1_lumi[-1].SetFillColor(colors[sys])
+        if sys == '_TOTAL': h1_lumi[-1].SetFillStyle(3244)
+        ibin = h1_lumi[-1].GetXaxis().FindBin(sys)
+        #print sys,ibin,colors[sys],lumi[sys]/TotalLumi,h1_lumi[-1].GetName()
+        h1_lumi[-1].SetBinContent(ibin,lumi[sys])
+        if lumi[sys] > 0. :
+            text_lumi.append(TText(lumi[sys]*1.1,ibin-1,"%.2f %%"%(100*lumi[sys]/TotalLumi)))
+        else:
+            text_lumi.append(TText(lumi[sys]*1.1,ibin-1,""))
+
+    
+    ## create png
+    canvas = TCanvas( 'c_SummaryLumiLoss',"Summary Lumi Losses", 200, 10, 600, 700)
+    canvas.Divide(1,1)
+    canvas.cd(1)
+    gPad.SetTopMargin(0.15);
+    h1_frame.Draw("HBAR")
+    subtitle = TText(max,0.,name)
+    subtitle.SetTextSize(0.03)
+    subtitle.SetTextAngle(90)
+    subtitle.SetTextColor(kGray+1)
+    subtitle.Draw()
+    for i,h in enumerate(h1_lumi):
+        h.Draw("HBAR SAME")
+        text_lumi[i].SetTextAlign(12) # Vertical align
+        text_lumi[i].SetTextSize(0.04) # Text Size
+        text_lumi[i].Draw()
+    canvas.Update()
+    from CoolRunQuery.AtlRunQueryQueryConfig import QC
+    pname = QC.datapath+'/'+name+'_lumiloss.png'
+    canvas.Print(pname)
+    return pname
+
+def MakePlot_PerRunLumiLoss(loss,colors,dicsum,name):
+
+    global usenb
+    global unit
+
+    ## get runs list - remove runs with no defect
+    runs = []
+    for r in loss['_TOTAL']:
+        if loss['_TOTAL'][r]>0. : runs.append(r)
+    if len(runs) == 0 : return
+    runs.sort()
+
+    ## ATLAS Ready Recorded Lumi
+    TotalLumi = dicsum[DataKey('TotalLumi')][0]
+
+    ## center histo Title
+    SetStyle()
+    gStyle.SetTitleX(0.5);
+    gStyle.SetTitleAlign(23);
+    
+    ## create stack
+    h_stack = THStack("hs_PerRun","Luminosity Loss during ATLAS Ready [%s^{-1}]"%unit); 
+
+    ## create legends
+    x0=0.17; y0=0.62;
+    nsplits = 4; dx = 0.2; dy = 0.05;
+    leg = TLegend(x0,y0,x0+dx,y0+nsplits*dy)
+    nhists = 0;
+
+    ## settings for BAR histos
+    SHIFT = 0.1
+    WIDTH = 0.4
+    
+    ## create total plot 
+    h1_total = TH1F("h1_total","",len(runs),-0.5,len(runs)-0.5)
+    h1_total.SetMinimum(0.)
+    h1_total.SetFillColor(colors['_TOTAL'])
+    h1_total.SetFillStyle(3244)
+    h1_total.SetBarWidth(WIDTH)
+    h1_total.SetBarOffset(SHIFT+WIDTH)
+
+    for r,run in enumerate(runs):
+        if loss['_TOTAL'][run] > 0: h1_total.Fill(r,loss['_TOTAL'][run])
+    nhists +=1
+    leg.AddEntry(h1_total,'TOTAL',"f")
+                
+    ## create systems plots 
+    h1_lumi = {}; text_lumi = {}; 
+    
+    for i,sys in enumerate(loss):
+            
+        if sys == '_TOTAL': continue
+        
+        h1_lumi[sys] = TH1F("h1_lumi_%s"%sys,"",len(runs),-0.5,len(runs)-0.5)
+        h1_lumi[sys].SetMinimum(0.)
+        h1_lumi[sys].SetFillColor(colors[sys])
+        h1_lumi[sys].SetBarWidth(WIDTH)
+        h1_lumi[sys].SetBarOffset(SHIFT)
+        for r,run in enumerate(runs):
+            if loss[sys][run]> 0.: h1_lumi[sys].Fill(r,loss[sys][run])
+                
+    ## Add to stack
+    for sys in h1_lumi:
+        if h1_lumi[sys].GetEntries() > 0:
+            h_stack.Add(h1_lumi[sys])
+            leg.AddEntry(h1_lumi[sys],sys,"f")
+            nhists +=1
+            
+    ## hmax 
+    hmax = h_stack.GetMaximum()*1.6
+
+    ## create frame
+    t1 = "       Runs [%i-%i]"%(runs[0],runs[-1])
+    if len(runs) == 1: t1 = "            Run [%i]"%runs[0]
+    t2 = "ATLAS Ready Lumi: %.2f %s^{-1}"%(TotalLumi,unit)
+    h1_frame = TH1F("h1_frame_runs","#splitline{%s}{%s}"%(t1,t2),len(runs),-0.5,len(runs)-0.5)
+    SetXLabel(h1_frame,runs)
+    h1_frame.SetLabelSize(0.06,"X")
+    h1_frame.SetMinimum(0.)
+    h1_frame.GetYaxis().SetTitle("Luminosity Loss during ATLAS Ready [%s^{-1}]"%unit) 
+    h1_frame.GetYaxis().SetTitleOffset(1.3)
+
+    ## create png
+    canvas = TCanvas( 'c_PerRunLumiLoss',"Luminosity Losses Per Run", 200, 10, 600, 700)
+    canvas.Divide(1,1)
+    canvas.cd(1)
+    gPad.SetTopMargin(0.15);
+    h1_frame.SetMaximum(hmax)
+    h_stack.SetMaximum(hmax)
+    #h_total.SetBarOffset((shift)
+    
+    h1_frame.Draw("")
+    h_stack.Draw("BARsame")
+    h1_total.Draw("BARsame")
+    ncolumns = int(math.ceil(float(nhists)/float(nsplits)))
+    leg.SetNColumns(ncolumns)
+    leg.Paint() # Draw once to access coordinates
+    leg.SetX2NDC(leg.GetX1NDC()+ncolumns*dx) # Modify legend size w.r.t number of columns
+    nrows = leg.GetNRows()
+    leg.SetY2NDC(leg.GetY1NDC()+nrows*dy) # Modify legend size w.r.t number of rows
+    leg.Draw() # Draw again
+
+    subtitle = TText(len(runs)-0.35,0.,name)
+    subtitle.SetTextSize(0.03)
+    subtitle.SetTextAngle(90)
+    #subtitle.SetTextColor(kGray+1)
+    subtitle.Draw()
+
+    canvas.Update()
+    from CoolRunQuery.AtlRunQueryQueryConfig import QC
+    pname = QC.datapath+'/'+name+'_lumiloss_perrun.png'
+    canvas.Print(pname)
+    return pname
+
+def MakePlot_DefectsPerSystem(sys,intolerable,tolerable,dic,run):
+
+    global readylb
+
+    from CoolRunQuery.AtlRunQueryQueryConfig import QC
+    
+    hname = ['','']
+    h2_DefectVsLB = ['','','']
+
+    ## style
+    SetStyle()
+    gStyle.SetTitleX(0.5);
+    gStyle.SetTitleAlign(23);
+
+    lbrange = readylb[-1]-readylb[0] # can be disconnected !
+    #print run,len(readylb),lbrange
+    
+    ## Intolerable ##
+    if len(intolerable) > 0 :
+        #TCol = TColor.GetColor( "#5D6B7D");
+        TCol = TColor.GetColor( "#354355");
+        hname[0]= "%s_Intolerable_Run%s"%(sys,str(dic[DataKey('Run')][run]))
+        htitle = "%s - Intolerable defects - Run %s"%(sys,str(dic[DataKey('Run')][run]))
+        h2_DefectVsLB[0] = TH2F("h2_defectVsLB_%s"%hname[0],htitle,
+                                lbrange,readylb[0]-0.5,readylb[-1]+0.5,
+                                len(intolerable),0.,len(intolerable))
+        h2_DefectVsLB[0].SetFillColor(TCol)
+        h2_DefectVsLB[0].GetXaxis().SetTitle("Lumiblocks with ATLAS Ready")
+        SetYLabel(h2_DefectVsLB[0],[defect for defect in intolerable])
+        h2_DefectVsLB[0].LabelsOption("a","Y") # order Y label by alphabetical order
+    
+        # Text to store lumi loss number
+        ttext = {}
+        # Fill & Compute lumi losses
+        for i,item in enumerate(intolerable):
+            ibiny = h2_DefectVsLB[0].GetYaxis().FindBin(item)
+            binxmax = h2_DefectVsLB[0].GetXaxis().GetXmax()
+            frac = 100*float(len(intolerable[item]))/float(len(readylb))
+            if frac> 0.: ttext[item] = TText(binxmax,ibiny-0.8,"  %.2f %%"%frac)
+            else: ttext[item] = TText(binxmax,ibiny-0.8,"")
+            ttext[item].SetTextSize(0.03)
+            ttext[item].SetTextColor(TCol)
+            for lb in intolerable[item]:
+                if lb not in readylb: continue
+                ibinx = h2_DefectVsLB[0].GetXaxis().FindBin(lb)
+                h2_DefectVsLB[0].SetBinContent(ibinx,ibiny,1.)
+        
+        # create png
+        canvas = TCanvas( 'c_Int',"Systems Defects - %s"%hname[0], 200, 10, 1000, 800)
+        canvas.Divide(1,1)
+        canvas.cd(1)
+        gPad.SetLeftMargin(0.40);
+        gPad.SetRightMargin(0.1);
+        h2_DefectVsLB[0].Draw("BOX")
+        for item in intolerable: ttext[item].Draw()
+        canvas.Update()
+        hname[0] = QC.datapath+"/"+hname[0]+".png"
+        canvas.Print(hname[0])
+
+    ## Tolerable ##
+    if len(tolerable) > 0 :
+
+        all = dict(tolerable.items() + intolerable.items())
+
+        TCol1 = TColor.GetColor( "#354355");
+        TCol2 = TColor.GetColor("#7B899B");
+        hname[1]= "%s_All_Run%s"%(sys,str(dic[DataKey('Run')][run]))
+        htitle = "%s - All defects - Run %s"%(sys,str(dic[DataKey('Run')][run]))
+        
+        # intolerable
+        h2_DefectVsLB[1] = TH2F("h2_defectVsLB_int_%s"%hname[1],htitle,
+                                lbrange,readylb[0]-0.5,readylb[-1]+0.5,
+                                len(all),0.,len(all))
+        # tolerable
+        h2_DefectVsLB[2] = TH2F("h2_defectVsLB_tol_%s"%hname[1],htitle,
+                                lbrange,readylb[0]-0.5,readylb[-1]+0.5,
+                                len(all),0.,len(all))
+        
+        h2_DefectVsLB[1].SetFillColor(TCol1)
+        h2_DefectVsLB[2].SetFillColor(TCol2)
+        h2_DefectVsLB[1].GetXaxis().SetTitle("Lumiblocks with ATLAS Ready")
+        h2_DefectVsLB[2].GetXaxis().SetTitle("Lumiblocks with ATLAS Ready")
+        SetYLabel(h2_DefectVsLB[1],[defect for defect in all])
+        SetYLabel(h2_DefectVsLB[2],[defect for defect in all])
+        h2_DefectVsLB[1].LabelsOption("a","Y") # order Y label by alphabetical order
+        h2_DefectVsLB[2].LabelsOption("a","Y") # order Y label by alphabetical order
+
+        # Text to store lumi loss number
+        ttext = {}
+        
+        # Fill 
+        for i,item in enumerate(all):
+            ibiny = h2_DefectVsLB[1].GetYaxis().FindBin(item)
+            binxmax = h2_DefectVsLB[1].GetXaxis().GetXmax()
+            frac = 100*float(len(all[item]))/float(len(readylb))
+            if frac >0.: ttext[item] = TText(binxmax,ibiny-0.8,"  %.2f %%"%frac)
+            else: ttext[item] = TText(binxmax,ibiny-0.8,"")
+            ttext[item].SetTextSize(0.03)
+            if item in intolerable:ttext[item].SetTextColor(TCol1)
+            if item in tolerable:ttext[item].SetTextColor(TCol2)      
+            for lb in all[item]:
+                ibinx = h2_DefectVsLB[1].GetXaxis().FindBin(lb)
+                if item in intolerable: h2_DefectVsLB[1].SetBinContent(ibinx,ibiny,1.)
+                if item in tolerable: h2_DefectVsLB[2].SetBinContent(ibinx,ibiny,1.)
+
+        # create png
+        canvas = TCanvas( 'c_Tol',"Systems Defects - %s"%hname[1], 200, 10, 1000, 800)
+        canvas.Divide(1,1)
+        canvas.cd(1)
+        gPad.SetLeftMargin(0.40);
+        gPad.SetRightMargin(0.1);
+        h2_DefectVsLB[2].Draw("BOX")
+        h2_DefectVsLB[1].Draw("BOXSAME")
+        for item in all: ttext[item].Draw()
+        canvas.Update()
+        hname[1] = QC.datapath+"/"+hname[1]+".png"
+        canvas.Print(hname[1])
+
+    return hname
+
+########################################################################
+def SetXLabel(h,list):
+    for i in xrange(len(list)):
+         h.GetXaxis().SetBinLabel(i+1,str(list[i]))
+    return
+
+def SetYLabel(h,list):
+    for i in xrange(len(list)):
+         h.GetYaxis().SetBinLabel(i+1,str(list[i]))
+    return
+
+def listify(l): # compactify lb lists
+    if len(l) == 0 : return ''
+    i = 0; newlist=[]
+    while i < len(l):
+        start=l[i];j=i;
+        while(j+1<len(l) and l[j+1]==l[j]+1): j+=1
+        end=l[j];i=j+1
+        if start==end: newlist.append(start)
+        else: newlist.append(str(start)+'-'+str(end))
+    return  ", ".join([str(x) for x in newlist])
+########################################################################
+
+class DQSummary:
+
+    @classmethod
+    def makeHTML(cls, dic, dicsum, doPickle=True, doDQSummary=True, doDQPlots=True):
+        """ method returns a string (unicode is fine) of html code, with out tag <div>...</div> """
+        
+        #####################################################################
+        # Jessica, your main code goes here                                 #
+        # (note that all methods in the class are 'static' -> @classmethod  #
+        #####################################################################
+
+        ### Global Variables ###
+        with timer("DQSummary"):
+
+            ### loop once over runs to decide between pb/nb###
+            global usenb
+            usenb = False
+            global livetrigger
+            livetrigger ='L1_EM30'
+            for r,run in enumerate(dic[DataKey('Run')]):
+                ptag = dic[DataKey('Project tag')][r][0].value
+                if 'data13' in ptag:
+                    usenb = True
+                    livetrigger = 'L1_EM5'
+            global unit
+            unit = 'pb'
+            if usenb: unit ='nb'
+    
+            ### WARNING messages
+            warning = ''
+
+            ### Total Lumi : 0 = Recorded  1 = Loss (in ATLAS Ready)
+            dicsum[DataKey('TotalLumi')] = [0.,0.]
+
+            ### ATLAS not Ready Total/Per run (in stable Beams)
+            dicsum[DataKey('TotalNotReady')] = 0.
+            dicsum[DataKey('TotalBusy')] = 0.
+            
+            ### Initialize Detectors Variables
+            detectors = ['ALFA','LCD','ZDC','BCM','PIXEL','SCT','TRT','LAR','TILE',
+                         'MS_CSC','MS_RPC','MS_TGC','MS_MDT','MBTS','TRIG','GLOBAL']
+            detectors_color = {'ALFA':kYellow-9,'LCD':kYellow-7,'ZDC':kYellow-4,
+                               'BCM':kOrange+1,'PIXEL':kOrange-3,'SCT':kOrange+7,'TRT':kRed-3,
+                               'LAR':kRed+2,'TILE':kPink-7,
+                               'MS_CSC':kBlue+4,'MS_RPC':kBlue-2,'MS_MDT':kAzure+3,'MS_TGC':kBlue-9,'MBTS':kBlue-6,
+                               'TRIG':kGreen-3,'GLOBAL':kGreen+3,'_TOTAL':TColor.GetColor("#585858")}
+            detectors_lumiloss = {};
+            detectors_affectedLBs = {}
+
+            for d in detectors:
+                detectors_lumiloss[d]={}
+                detectors_affectedLBs[d]={}
+
+            ## Additional field for TOTAL
+            detectors_lumiloss['_TOTAL']={}
+            detectors_affectedLBs['_TOTAL']={}
+                
+            ### Initialize Performances Variables
+            performances = ['LUMI','ID','CALO','TAU','EGAMMA','JET','MET','MCP','BTAG']
+            performances_color = {'LUMI':kYellow-9,'ID':kOrange+7,'CALO':kRed+2,'TAU':kBlue+2,
+                                  'EGAMMA':kGreen-3,'JET':kAzure+3,'MET':kGreen-6,'MCP':kBlue-3,
+                                  'BTAG':kPink,'_TOTAL':TColor.GetColor("#585858")}
+            performances_lumiloss = {}; 
+            performances_affectedLBs = {}
+
+            for p in performances:
+                performances_lumiloss[p]={}
+                performances_affectedLBs[p]={}
+
+            ## Additional field for TOTAL
+            performances_lumiloss['_TOTAL']={}
+            performances_affectedLBs['_TOTAL']={}
+
+            ### Initialize table content // Considered systems ###
+            columns = []; global_systems = [];
+            columns = ['Run Info','ES1','BLK']
+            global_systems = ['Calo','Tracking','Muon','Trigger & Lumi']
+            columns += global_systems 
+            
+        ### create big results table ###
+        summarytable = '<div><table id="resulttable" class="resulttable" style="margin-left: 13px; margin-right: 13px;" >'
+        ### create first title row ###
+        summarytable += '<tr>'
+        summarytable += '<th colspan="1"></th>' # run info column
+
+        #summarytable += '<th colspan="2">Tier0 Reco Status</th>'
+        summarytable += '<th colspan="2">Missing Sign-Off</th>'
+            
+        summarytable += '<th colspan="%i">Defects in ATLAS Ready<br>'%len(global_systems)
+        summarytable += '<div style="font-size: xx-small; cursor: pointer;" onclick="toggle_dq(this)">[show tolerable]</div></th>'
+        summarytable += '</tr>'
+        
+        ### create subtitle row ###
+        summarytable += '<tr>'
+        #for item in columns: summarytable += '<th>%s</th>'%item.split(":")[0]
+        for item in columns: summarytable += '<th>%s</th>'%item
+        summarytable += '</tr>'
+        
+        ### loop over runs ###
+        for r,run in enumerate(dic[DataKey('Run')]):
+
+            ## Get list of ATLAS Ready LBs
+            global readylb
+            readylb = GetLBReady(dic,r)
+
+            ## If no ATLAS ready LB: skip the run
+            if len(readylb) == 0:
+                warning += '<center><font color="red">WARNING! Run %s has 0 ATLAS Ready LB</font></center><br>'%run
+                continue
+
+            ## Get lumi per LB and live fraction for the current run
+            lumiperlb = GetLBLumi(dic,r)
+            livefrac = GetLBLiveFraction(dic,r)
+
+            if len(lumiperlb) == 0:
+                warning += '<center><font color="red">WARNING! Run %s has no offline lumi info</font></center><br>'%run
+                continue
+
+            ## Correct lumi per LB with live fraction
+            #print 'DEBUG',run,len(lumiperlb),len(livefrac),len(readylb)
+            for l in lumiperlb:
+                # IF statement used when len(lumiperlb)!= len(livefrac)
+                if l not in readylb: continue
+                if l not in livefrac:
+                    print "--> Warning: live fraction not available for LB %i. Setting live fraction to 1."%l
+                else:
+                    lumiperlb[l]*=livefrac[l]
+                         
+            ## Initialize columns content for current run            
+            content = {}
+            for i,item in enumerate(columns):content[item]=''
+            
+            ## Retrieve and store run info
+            dp = '?'; ptag = dic[DataKey('Project tag')][r][0].value
+            year = '20'+ptag.split('_')[0][4:]
+            DP = ARQ_COMA.get_periods_for_run(run)
+            if len(DP)>0: dp=DP[0]
+            content['Run Info'] = '<b>%s</b>&nbsp;<font style="font-size:10px;">data period <b>%s</b></font><br>'%(str(run),dp)
+
+            ### In case some systems should be removed
+            tobeignored = ['ALFA','ZDC','LCD']
+            if 'data13' in ptag: tobeignored = []
+
+            ## useful links
+            target='target="blank"'
+            somelinks = '<font style="font-size:10px;color:#0000FF">'
+            somelinks += '<a href="https://atlas-tagservices.cern.ch/tagservices/RunBrowser/runBrowserReport/runBrowserReport.php?runs=%s&pn=%s&fnt=%s" %s>COMA</a>'%(run,dp,ptag,target)
+            somelinks += ', <a href="https://atlasdqm.web.cern.ch/atlasdqm/DQBrowser/makeMatrix.php?selection=All&run=%s&runup=&dbinstance=COMP200_DCS&tag=DEFAULT" %s>DCS</a>'%(run,target)
+            somelinks += ', <a href="https://atlas.web.cern.ch/Atlas/GROUPS/DATAPREPARATION/DataSummary/%s/run.py?run=%s" %s>DS</a>'%(year,run,target)
+            somelinks += ', <a href="https://atlasdqm.cern.ch/defectentry/?run=%s" %s>defects</a>'%(run,target)
+            somelinks += '<br><a href="https://atlasdqm.cern.ch/dqsignoff/%s/" %s>DQlogbook</a>'%(run,target)
+            somelinks += ', <a href="https://atlasdqm.cern.ch/webdisplay/tier0?lowrun=%s&highrun=%s&show_all=on" %s>DQWebDisplay</a>'%(run,run,target)
+            somelinks += '</font><br>'
+
+            content['Run Info'] += somelinks
+            
+            ## Start and End time
+            rundate = dic[DataKey('Start and endtime')][r].split(",")
+            tstart = time.strftime("%a, %d %b %Y %H:%M:%S",time.localtime(float(rundate[0])))
+            tend = time.strftime("%a, %d %b %Y %H:%M:%S",time.localtime(float(rundate[1])))
+            content['Run Info'] += '<font style="font-size:10px;">'
+            content['Run Info'] += '<br>Start:&nbsp;<font style="color:#4C7D7E;">%s</font>'%tstart
+            content['Run Info'] += '<br>End:&nbsp;<font style="color:#4C7D7E;">%s</font>'%tend
+            content['Run Info'] += '</font>'
+
+            #nevents = str(dic[DataKey('#Events')][r][0].value)
+            #content['Run Info'] += 'Recorded events: '+nevents+'<br>'
+            #content['Run Info'] += 'Number of LBs : '+dic[DataKey('#LB')][r][0]+'<br>'
+            #content['Run Info'] += 'LHC Fill : %s<br>'%(dic[DataKey('lhc:fillnumber')][r][0].value)+'<br>'
+
+            ## Add stable Beam / ATLAS Ready info in lhctable
+            lhctable = '<br><font style="font-size:10px;">'
+            lhctable += '<table><tr><td>'
+            lhctable += '<b>Stable&nbsp;Beam</b><br>%s'%'<br>'.join([ '%s-%s:&nbsp<font style="color:#4C7D7E">%s</font>'%(b.startlb,b.endlb,b.value) for b in dic[DataKey('lhc:stablebeams')][r]])
+            lhctable += '</td><td>'
+            lhctable += '<b>ATLAS&nbsp;Ready</b><br>%s'% '<br>'.join([ '%s-%s:&nbsp<font style="color:#4C7D7E">%s</font>'%(b.startlb,b.endlb,b.value) for b in dic[DataKey('Ready for physics')][r]])
+            lhctable += '</td></tr></table>'
+            lhctable += '</font>'
+            content['Run Info'] += lhctable
+
+            ## Add Total Lumi
+            lumitot = ComputeRunLumi(dic,r,lumiperlb)
+            dicsum[DataKey('TotalLumi')][0]+= lumitot
+            content['Run Info'] += '<font style="font-size:10px;">'
+            content['Run Info'] += 'Ready Recorded: <b>%.2f</b> %s<sup>-1</sup>'%(lumitot,unit)
+            content['Run Info'] += '</font><br>'
+                    
+            ## Retrieve DQ defects
+            defects = dic[DataKey('DQ')][r]
+            ## Select only primary flags
+            defects_primary = [d for d in defects if d.value.primary]  
+
+            ## Initialize list of affected LBs per detector/cp
+            ## Initialize lumi losses due to intolerable defects
+            for d in detectors:
+                detectors_lumiloss[d][run]= 0.
+                detectors_affectedLBs[d][run]=[]
+            for p in performances:
+                performances_lumiloss[p][run]=0.
+                performances_affectedLBs[p][run]=[]
+                
+            # Total per run
+            detectors_lumiloss['_TOTAL'][run]= 0.
+            detectors_affectedLBs['_TOTAL'][run]=[]
+            performances_lumiloss['_TOTAL'][run]= 0.
+            performances_affectedLBs['_TOTAL'][run]=[]
+            
+            # And the big sums
+            total_affectedLBs = []
+            GlobalNotReady = []; GlobalBusy = [];
+            
+            ## Store list of defects and affected LBs to print systems table
+            ListOfIntolerableDefects = {}; ListOfTolerableDefects = {};
+             
+            ## Loop over defects
+            for item in defects_primary:
+                defect = item.value.defect
+                comment = item.value.comment
+                user = item.value.user
+                startlb = item.startlb
+                endlb = item.endlb
+                tolerable = item.value.tolerable
+                system = MapToSystem(defect)
+
+                if 'GLOBAL_NOTREADY' in defect:
+                    GlobalNotReady += [ lb for lb in range(startlb,endlb)]
+                                    
+                if 'GLOBAL_BUSY' in defect:
+                    GlobalBusy += [ lb for lb in range(startlb,endlb) if lb in readylb]
+                                    
+                ## Missing Sign-Offs ##
+
+                ## FINAL sign-off
+                if 'UNCHECKED_FINAL' in defect: continue
+                
+                ## BULK sign-off
+                if 'BULK_UNCHECKED' in defect:
+                    short = defect.split('_UNCHECKED')[0]
+                    content['BLK']+='<font style="font-size:8px;font-weight:bold;">%s</font><br>'%short
+                    continue
+                ## ES sign-off
+                if 'UNCHECKED' in defect:
+                    short = defect.split('_UNCHECKED')[0]
+                    content['ES1']+='<font style="font-size:8px;font-weight:bold;">%s</font><br>'%short
+                    continue
+
+                ## Some cross-checks 
+                if system =='':
+                    print 'run %s: this defect is fishy %s '%(run,defect)
+                    continue
+                    
+                ## Some cross-checks 
+                word = defect.split('_'); cpdet = word[0]
+                if word[0]=='MS' :cpdet += "_"+word[1] # MS systems
+                if not cpdet in detectors and not cpdet in performances:
+                    print 'This system is not included: %s (%s)'%(cpdet,defect)
+                    continue
+
+               ## Store intolerable defects if in ATLAS Ready LBs only
+                if not tolerable:
+                    RangeDefect = [ lb for lb in range(startlb,endlb) if lb in readylb ]
+                    if len(RangeDefect)>0:
+                        if not defect in ListOfIntolerableDefects:
+                            ListOfIntolerableDefects[defect]= [[],'']
+                            ListOfIntolerableDefects[defect][0] = RangeDefect
+                            ListOfIntolerableDefects[defect][1] = user+':'+comment
+                        else:
+                            ListOfIntolerableDefects[defect][0]+= RangeDefect
+                            if comment not in ListOfIntolerableDefects[defect][1]:
+                                ListOfIntolerableDefects[defect][1]+= ' '+user+':'+comment
+                        # This is used to compute lumilosses
+                        # Here, we do not include systems "to be ignored"
+                        if cpdet in tobeignored: continue
+                        # Store list of affected LBs per detector/cp group
+                        # we can have a double counting of LBs if defects overlap - fixed later
+                        if cpdet in detectors: detectors_affectedLBs[cpdet][run]+=RangeDefect
+                        if cpdet in performances: performances_affectedLBs[cpdet][run]+=RangeDefect
+                        total_affectedLBs += RangeDefect
+
+                ## Store tolerable defects
+                else:
+                    RangeDefect = [ lb for lb in range(startlb,endlb) if lb in readylb]
+                    if len(RangeDefect)>0:
+                        if not defect in ListOfTolerableDefects:
+                            ListOfTolerableDefects[defect]= [[],'']
+                            ListOfTolerableDefects[defect][0]= RangeDefect
+                            ListOfTolerableDefects[defect][1]= '[%s]:%s '%(user,comment)
+                        else:
+                            ListOfTolerableDefects[defect][0]+= RangeDefect
+                            if comment not in ListOfTolerableDefects[defect][1]:
+                                ListOfTolerableDefects[defect][1] += '[%s]:%s '%(user,comment)
+            ## end of defects loop ##
+            
+            ## Create defects table for each system
+            for item in global_systems:
+                content[item]='<table class="dqdefects">'
+
+            for item in ListOfIntolerableDefects:
+                system = MapToSystem(item)
+                if not system in global_systems: continue
+                lbs = listify(ListOfIntolerableDefects[item][0])
+                tip = ListOfIntolerableDefects[item][1]
+                tipkey = "dqcomment_int_%s_%s"%(item,run)
+                Run.addGlobalToolTip(tipkey,tip)
+                content[system]+='<tr class="showTip %s" >'%(tipkey)
+                content[system]+='<td class="intolerable">%s</td>'%(item)
+                content[system]+='<td class="lb">%s</td>'%(lbs)
+                content[system]+='</tr>'
+
+            for item in ListOfTolerableDefects:
+                system =  MapToSystem(item)
+                if not system in global_systems: continue
+                lbs = listify(ListOfTolerableDefects[item][0])
+                tip = ListOfTolerableDefects[item][1]
+                tipkey = "dqcomment_tol_%s_%s"%(item,run)
+                Run.addGlobalToolTip(tipkey,tip)
+                content[system]+='<tr class="showTip %s tolerable" style="visibility:collapse;">'%(tipkey)
+                content[system]+='<td>%s</td>'%(item)
+                content[system]+='<td class="lb">%s</td>'%(lbs)
+                content[system]+='</tr>'
+
+            ## close systems defects tables
+            for item in global_systems:
+                content[item]+='</table><br>'
+
+            ## Add defects plots in each system column
+            thumbsize = 70
+            imgsize = 600
+            for sys in global_systems:
+                tol = {}; int = {};
+                for defect in ListOfTolerableDefects:
+                    # remove systems to be ignored from the plots
+                    word = defect.split('_'); cpdet = word[0]
+                    if word[0]=='MS' :cpdet += "_"+word[1] # MS systems
+                    if cpdet in tobeignored: continue
+                    if sys==MapToSystem(defect): tol[defect]=ListOfTolerableDefects[defect][0]
+                for defect in ListOfIntolerableDefects:
+                    # remove systems to be ignored from the plots
+                    word = defect.split('_'); cpdet = word[0]
+                    if word[0]=='MS' :cpdet += "_"+word[1] # MS systems
+                    if cpdet in tobeignored: continue
+                    if sys==MapToSystem(defect): int[defect]=ListOfIntolerableDefects[defect][0]
+
+                hname = MakePlot_DefectsPerSystem(sys,int,tol,dic,r)
+                for h in hname:
+                    if len(h)== 0 : continue
+                    title = "Click to zoom"
+                    wincontent = "<img src=&quot;%s&quot; height=%s/>"%(h,imgsize)
+                    openwin = "javascript:openLargeWindow('Print1','"
+                    openwin += "<!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;>"
+                    openwin += "<html xmlns:&quot;my&quot;><head><title>Defects for run %s</title></head>"%run
+                    openwin += "<body style=&quot;background-color:#ffffff&quot;>%s</body></html>"%wincontent
+                    openwin += "')"
+                    content[sys]+='<a title="%s" href="%s" ><img src="%s" height=%s/></a>'%(title,openwin,h,thumbsize)
+
+            ## Compute Global not ready ##
+            l = 0.;
+            for lb in GlobalNotReady: l += lumiperlb[lb]
+            dicsum[DataKey('TotalNotReady')]+= l
+            content['Run Info'] += '<font style="font-size:10px;">'
+            content['Run Info'] += 'Global Not Ready: <b>%.2f</b> %s<sup>-1</sup>'%(l,unit)
+            content['Run Info'] += '</font><br>'
+            
+            ## Compute Global Busy ##
+            l = 0.;
+            for lb in GlobalBusy: l += lumiperlb[lb]
+            dicsum[DataKey('TotalBusy')]+= l
+            content['Run Info'] += '<font style="font-size:10px;">'
+            content['Run Info'] += 'Global Busy: <b>%.2f</b> %s<sup>-1</sup>'%(l,unit)
+            content['Run Info'] += '</font><br>'
+            
+            ## Compute cp/det lumilosses for current run
+            for d in detectors:
+                if len(detectors_affectedLBs[d][run]) == 0: continue
+                # Remove double counting (defects overlap)
+                dll = list(set(detectors_affectedLBs[d][run]))
+                detectors_affectedLBs['_TOTAL'][run]+= dll
+                for lb in dll:
+                    detectors_lumiloss[d][run]+= lumiperlb[lb]
+            for p in performances:
+                if len(performances_affectedLBs[p][run]) == 0: continue
+                # Remove double counting (defects overlap)
+                pll = list(set(performances_affectedLBs[p][run]))
+                performances_affectedLBs['_TOTAL'][run]+= pll
+                for lb in pll:
+                    performances_lumiloss[p][run]+= lumiperlb[lb]
+
+            ## Compute total Lumiloss for this run
+            ## Remove double counting (defects overlap)
+            detectors_affectedLBs['_TOTAL'][run]=list(set(detectors_affectedLBs['_TOTAL'][run]))
+            performances_affectedLBs['_TOTAL'][run]=list(set(performances_affectedLBs['_TOTAL'][run]))
+            total_affectedLBs = list(set(total_affectedLBs))
+            totallossperrun = 0. 
+            # Store the values
+            for lb in total_affectedLBs:
+                totallossperrun += lumiperlb[lb]    
+            dicsum[DataKey('TotalLumi')][1] +=  totallossperrun
+            # Store the values
+            for lb in  detectors_affectedLBs['_TOTAL'][run]:
+                detectors_lumiloss['_TOTAL'][run] +=  lumiperlb[lb]
+            # Store the values
+            for lb in  performances_affectedLBs['_TOTAL'][run]:
+                performances_lumiloss['_TOTAL'][run] += lumiperlb[lb]
+
+            ## Add Total LumiLoss in run info column
+            content['Run Info'] += '<font style="font-size:10px;">'
+            content['Run Info'] += 'DQ Lumi Loss: <b>%.2f</b> %s<sup>-1</sup>'%(totallossperrun,unit) 
+            content['Run Info'] += '</font><br>'
+
+            ### Print run row ###
+            summarytable+='<tr class="out2">'
+            for item in columns: summarytable+='<td>%s</td>'%content[item]
+            summarytable+='</tr>'
+        
+        ### end of run loop ###
+        ### end of results table ###
+        summarytable += '</table></div><br>'            
+            
+        ##########################
+        ## Create Summary Plots ##
+        ##########################
+
+        summaryplot = ''
+
+        from CoolRunQuery.AtlRunQueryQueryConfig import QC
+        
+        plots = []
+
+        plots.append(MakePlot_SummaryLumiLoss(detectors_lumiloss,detectors_color,dicsum,'detectors'))
+        plots.append(MakePlot_SummaryLumiLoss(performances_lumiloss,performances_color,dicsum,'performances'))
+        plots.append(MakePlot_PerRunLumiLoss(detectors_lumiloss,detectors_color,dicsum,'detectors'))
+        plots.append(MakePlot_PerRunLumiLoss(performances_lumiloss,performances_color,dicsum,'performances'))
+    
+        imgsize=500
+        thumbsize=300
+        title = "Click to zoom"
+
+        ## Start plots table at the top of the page
+        summaryplot += '<table align="center" width="90%">'
+        summaryplot += '<th>'
+
+        for p in plots:
+            
+            wincontent = "<img src=&quot;%s&quot; width=%s/>"%(p,imgsize)
+            
+            #openwincmd = "javascript:openLargeWindow('Print%i','"%(r)
+            openwincmd = "javascript:openWindow('Print%i','"%(run)
+            openwincmd += "<!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;>"
+            openwincmd += "<html xmlns:&quot;my&quot;><head><title>DQ Summary Plot - Run %s</title></head>"%(run)
+            openwincmd += "<body style=&quot;background-color:#ffffff&quot;>%s</body></html>"%wincontent
+            openwincmd += "')"
+                
+            summaryplot+='<td><a title="%s" href="%s" ><img src="%s" height=%s/></a></td>'%(title,openwincmd,p,thumbsize)
+
+        ## End plots table
+        summaryplot += '</th></table>'
+
+        ## debug ##
+        #s = "<div>%s</div>" % '<br>'.join([ "%s: %s" % (k.ResultKey,v) for k,v in dicsum.items()])
+        #s = "<div>%s</div>" % '<br>'.join([ "%s: %s" % (k.ResultKey,v) for k,v in dic.items()])
+        #print s
+
+        ###########################
+        ## Print Summary numbers ##
+        ###########################
+        
+        print '+++++++++++++++++++++++++ Summary +++++++++++++++++++'
+        print '  Total Ready Recorded Luminosity: %.2f %s-1'%(dicsum[DataKey('TotalLumi')][0],unit)
+        print '  Total Luminosity Loss (ATLAS Ready) : %.2f %s-1'%(dicsum[DataKey('TotalLumi')][1],unit)
+        print '  Total Global Not Ready (Stable Beams): %.2f %s-1'%(dicsum[DataKey('TotalNotReady')],unit)
+        print '  Total Global Busy (Stable Beams): %.2f %s-1'%(dicsum[DataKey('TotalBusy')],unit)
+        print '+++++++++++++++++++++++++++++++++++++++++++++++++++++'
+
+        global lumifolder
+        
+        summaryinfo = '<table align="center" style="font-size:80%;"><tr>'
+        summaryinfo +='<td> Total Luminosity Loss: <b>%.2f %s<sup>-1</sup></b> (%.2f%%)'%(dicsum[DataKey('TotalLumi')][1],unit,float(dicsum[DataKey('TotalLumi')][1])*100/float(dicsum[DataKey('TotalLumi')][0]))
+        summaryinfo +='<br>Excluded Systems: %s</td></tr>'%tobeignored
+        summaryinfo +='<tr><td style="font-size:70%%">using %s // %s</td></tr>'%(lumifolder.split(':')[2],livetrigger)
+        summaryinfo +='</table>'
+        
+        #############################
+        ## return web page content ##
+        #############################
+        
+        pagecontent = summaryplot +'<br>'
+        pagecontent += summaryinfo +'<br>'
+        if doDQSummary: pagecontent += summarytable
+        pagecontent += warning
+        return pagecontent
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if __name__ == "__main__":
+    # for standalone tests (without querying) just run this and view under test.html
+    
+    import pickle
+    from CoolRunQuery.AtlRunQueryQueryConfig import QC
+    QC.datapath = "data"
+
+    pageinfo = pickle.load(open('%s/dqsum_pi.pickle' % QC.datapath))
+
+    from CoolRunQuery.html.AtlRunQueryHTML import ResultPageMaker as RPM
+    RPM.makePage(pageinfo, doDQPickle=False)
+
+    
diff --git a/Database/CoolRunQuery/python/html/AtlRunQueryHTML.py b/Database/CoolRunQuery/python/html/AtlRunQueryHTML.py
new file mode 100644
index 00000000000..4bea9ae496f
--- /dev/null
+++ b/Database/CoolRunQuery/python/html/AtlRunQueryHTML.py
@@ -0,0 +1,377 @@
+#!/bin/env python
+
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+#
+# ----------------------------------------------------------------
+# Script : AtlRunQueryHTML.py
+# Project: AtlRunQuery
+# Purpose: Library with HTML code creation
+# Authors: Andreas Hoecker (CERN), Joerg Stelzer (DESY)
+# Created: Apr 19, 2010
+# ----------------------------------------------------------------
+#
+from __future__ import with_statement
+
+import sys, re, time, datetime, os
+from random import choice
+
+from CoolRunQuery.AtlRunQueryRun         import Run
+
+from CoolRunQuery.utils.AtlRunQueryUtils import addKommaToNumber, filesize
+from CoolRunQuery.utils.AtlRunQueryTimer import timer
+
+from .AtlRunQueryPageMaker               import PageMaker as PM
+from CoolRunQuery.selector.AtlRunQuerySelectorBase import DataKey
+
+
+class ResultPageMaker:
+
+    @classmethod
+    def makePage(cls, pageinfo, doDQPickle=True):
+
+        # turn dict pageinfo into local variables
+        for x in pageinfo.keys():
+            exec("%s = pageinfo['%s']" % (x,x) )
+
+        # put in link to cache
+        cachelink = datapath[datapath.rfind('arq_'):].rstrip('/')
+        cachelinkline = '[ <a style="font-size:11px;font-weight:100;font-style:normal" href="query.py?q=%s"><i>cached link to this result page</i></a> ]' % cachelink
+
+        extraReplace = [ ('<!--INSERTLINKCACHE-->', cachelinkline) ]
+
+        # START WITH THE PAGE
+        body = u''
+
+        # overall summary output if requested
+        if makeSummary:
+            body += cls._OverallSummary( pageinfo )
+
+        # overall summary output if requested
+        if makeDQSummary or makeDQPlots:
+            body += cls._DQSummaryWrap( pageinfo, doPickle=doDQPickle )
+            extraReplace += [ ('<!--CONTACT_START-->.*<!--CONTACT_END-->', '<a href="http://consult.cern.ch/xwho/people/572921">Jessica Leveque</a>') ]
+            
+        # initial information (query, selection steps, totNEv)
+        pageinfo['selstr'] = cls._makeSelectionSteps( pageinfo )
+        body += cls._InitialSummary( pageinfo )
+
+        if makeDQSummary or makeDQPlots:
+            # only the global tooltips are needed
+            body += cls._defineToolTips( pageinfo, globalOnly=True )
+        else:
+            # horizontal line
+            body += '<hr style="width:95%; background-color: #999999; height:1px; margin-left:14px; border:0">\n<p>\n'
+
+            # results table
+            pageinfo['sumstr'] = cls._makeYellowLine( pageinfo ) # the yellow summary line
+            body += cls._makeResultsTable( pageinfo )
+
+            # tooltips
+            body += cls._defineToolTips( pageinfo )
+
+            # bottom table
+            body += '<p>\n'
+            body += cls._makeBottomTable(pageinfo)
+
+        PM.makePage(body, origQuery, extraReplace=extraReplace, removeExamples=makeDQSummary or makeDQPlots)
+
+
+
+    @classmethod
+    def _makeResultsTable( cls, pageinfo ):
+        for x in pageinfo.keys():
+            exec("%s = pageinfo['%s']" % (x,x) )
+
+        # run results table
+        resultstable = '<table class="resulttable" id="resulttable" style="margin-left: 13px">\n'
+
+        # table head
+        resultstable += Run.header()
+
+        # runs
+        with timer("print the runs"):
+            for r in runlist:
+                with timer("print run %i" % r.runNr):
+                    resultstable += str(r)
+
+        # summary
+        headlist = Run.headerkeys()
+        resultstable += "  <tr class=\"space\"><td style=\"text-align: left;\" colspan=\"%i\"><font size=-2><i>Summary</i>:</font></td></tr>\n" % (len(headlist)-1)
+        resultstable += "  <tr class=\"sum\">" + sumstr + "</tr>\n"
+        resultstable += "</table>\n"
+        return resultstable
+
+
+    @classmethod
+    def _defineToolTips( cls, pageinfo, globalOnly=False ):
+        for x in pageinfo.keys():
+            exec("%s = pageinfo['%s']" % (x,x) )
+        tooltips = u''
+        with timer("print the tooltips"):
+            dw_call  = ['<script type="text/javascript">']
+            dw_call += ["if(dw_Tooltip.content_vars==undefined) {dw_Tooltip.content_vars = {}; };"]
+            dw_call += Run.GlobalTooltips
+            if not globalOnly:
+                for r in runlist:
+                    dw_call += r.tooltips
+            dw_call += ['</script>']
+            for l in dw_call:
+                tooltips += unicode(l) + '\n'
+        return tooltips
+
+
+
+    # makes the bottom table (between yellow line and footer
+    @classmethod
+    def _makeBottomTable( cls, pageinfo ):
+        for x in pageinfo.keys():
+            exec("%s = pageinfo['%s']" % (x,x) )
+
+        bottomTable = '<table cellspacing="0" style="color: #777777; font-size: 80%; margin-left: 13px">\n'
+        bottomTable += '<tr>\n<td valign="top">\n'
+        bottomTable += cls._Description()
+        bottomTable += '<tr><td colspan="2"><p><hr style="width:40%; color:#999999; background-color: #999999; height:1px; margin-left:0; border:0"/>\n<p>\n</td></tr>'        
+
+        # XML output (official format for input to good-run lists)
+        bottomTable += cls._XMLFormat(datapath, xmlfilename, xmlhtmlstr)
+
+        # pickled output
+        bottomTable += cls._PickledOutput(datapath)
+
+        # ROOT output
+        bottomTable += cls._RootOutput(roothtmlstr, datapath)
+
+        # end of bottom table
+        bottomTable += '<tr><td colspan="2"><p>\n<p>\n</td></tr>'
+        bottomTable += '</table>'
+        return bottomTable
+        
+
+    # create DQ efficiency summary
+    @classmethod
+    def _makeDQeff( cls, pageinfo ):
+        for x in ["dicsum", "dic", "datapath", "makeDQeff"]:
+            exec("%s = pageinfo['%s']" % (x,x) )
+
+        if dicsum and makeDQeff:
+            with timer("make the DQ efficiency summary"):
+                from CoolRunQuery.utils.AtlRunQueryDQUtils import MakeDQeffHtml
+                return MakeDQeffHtml( dic, dicsum, datapath )
+        else:
+            return ''
+
+    # build the yellow summary line
+    @classmethod
+    def _makeYellowLine( cls, pageinfo ):
+        for x in ["dicsum"]:
+            exec("%s = pageinfo['%s']" % (x,x) )
+        with timer("make the yellow summary line"):
+            sumdic = {}
+            for key, summary in dicsum.items():
+                if key.Type == DataKey.STREAM:
+                    s = addKommaToNumber(summary[0])+' <BR><font size="-2">(%s)</font>' % filesize(summary[1])
+                elif key=='Run':
+                    s = addKommaToNumber(summary) + "&nbsp;runs"
+                else:
+                    s = addKommaToNumber(summary)
+                sumdic[key.ResultKey] = s.strip()
+        sumstr = ''
+        headlist = Run.headerkeys()
+        for title in headlist:
+            sumstr += '<td style="text-align:right;">%s</td>' % (sumdic[title] if title in sumdic else '')
+        return sumstr
+
+
+    # selection steps
+    @classmethod
+    def _makeSelectionSteps( cls, pageinfo ):
+        for x in ["selout"]:
+            exec("%s = pageinfo['%s']" % (x,x) )
+        selstr = '<table style="color: #777777; font-size: 100%" cellpadding="0" cellspacing="0">'
+        for sel in selout:
+            if 'SELOUT' == sel[0:6]:
+                selout = sel[7:].split('==>')
+                if len(selout)==1:
+                    selstr += '<tr><td width="400" style="vertical-align:top">%s</td></tr>' % selout[0]
+                else:
+                    selstr += '<tr><td width="400" style="vertical-align:top">%s</td><td width="20" style="vertical-align:top">:</td><td style="vertical-align:top">%s</td></tr>' % tuple(selout[0:2])
+        selstr += '</table>'
+        return selstr
+
+
+
+
+    @classmethod
+    def _prettyNumber( cls, n, width=-1, delim=',',decimal='.' ):
+        """Converts a float to a string with appropriately placed commas"""
+        if width >= 0: s = "%.*f" % (width, n)
+        else: s = str(n)
+        dec = s.find(decimal)
+        if dec == -1: dec = len(s)
+        threes = int((dec-1)/3) 
+        for i in xrange(threes):
+            loc = dec-3*(i+1)
+            s = s[:loc] + delim + s[loc:]
+        return s
+
+
+    @classmethod
+    def _OverallSummary( cls, pageinfo ):
+        for x in pageinfo.keys():
+            exec("%s = pageinfo['%s']" % (x,x) )
+        with timer("make the summary"):
+            from CoolRunQuery.html.AtlRunQuerySummary import MakeSummaryHtml
+            overallsummarystr = MakeSummaryHtml( dic, dicsum, datapath )
+        if overallsummarystr == '': return ''
+        s = '''<table width="95%" cellpadding="5" style="margin-left: 13px">
+        <tr><td colspan=2 bgcolor=gainsboro><font size=+1><b>Search Result Summary</b></font></td></tr>
+        </table>'''
+        s += '<p></p>'
+        s += overallsummarystr
+        s += '<p></p>'
+        return s
+
+
+    @classmethod
+    def _DQSummaryWrap( cls, pageinfo, doPickle=True ):
+        from CoolRunQuery.utils.AtlRunQueryUtils import runsOnServer
+        if not runsOnServer() and doPickle:
+            import pickle
+            from CoolRunQuery.AtlRunQueryQueryConfig import QC
+            f = open('%s/dqsum_pi.pickle' % QC.datapath, "w")
+            pickle.dump(pageinfo, f)
+            f.close()
+        for x in pageinfo.keys():
+            exec("%s = pageinfo['%s']" % (x,x) )
+        with timer("make the DQ summary"):
+            from CoolRunQuery.html.AtlRunQueryDQSummary import DQSummary
+            dqsummary = DQSummary.makeHTML( dic, dicsum, doDQSummary=makeDQSummary, doDQPlots=makeDQPlots )
+        if dqsummary == '': return ''
+        s = '''<table width="95%" cellpadding="5" style="margin-left: 13px">
+        <tr><td colspan=2 bgcolor=gainsboro><font size=+1><b>Data Quality Summary</b></font></td></tr>
+        </table>'''
+        s += '<p></p>'
+        s += dqsummary
+        s += '<p></p>'
+        return s
+
+
+    @classmethod
+    def _InitialSummary(cls, pageinfo):
+        for x in pageinfo.keys():
+            exec("%s = pageinfo['%s']" % (x,x) )
+        error = False
+        totEv,naEv = Run.totevents[0:2]
+        s_table = '''<table width="95%" cellpadding="5" style="margin-left: 13px">
+        <tr><td colspan=2 bgcolor=gainsboro><font size=+1><b>Search Result</b></font></td></tr>
+        </table>'''
+        s_table += '<table width="95%" cellpadding="0" cellspacing="3" style="font-size: 90%; margin-left: 13px">\n'
+        s_table += '<tr height="10"></tr>\n'
+        s_table += '<tr><td height="10" width="130" style="vertical-align:top"><i>Selection&nbsp;rule:</i></td><td width=10></td><td valign=top>%s</td></tr>\n' % origQuery
+        if 'erbose' in fullQuery:
+            s_table += '<tr><td height="10" style="vertical-align: top; color: #777777"><i>Query&nbsp;command:</i></td><td width=10 style="color: #777777"></td><td style="color: #777777">'
+            s_table += """<a href="javascript:animatedcollapse.toggle('AtlRunQueryCmd')">"""
+            s_table += '<font color="#777777">[ Click to expand/collapse command... ]</font></a>'
+            s_table += '<div id="AtlRunQueryCmd" style="width: 100%; background: #FFFFFF; color: #777777; display:none">'
+            s_table += '%s' % (fullQuery)
+            s_table += '</div></td></tr>\n'
+            s_table += '<tr><td height="10" style="vertical-align: top; color: #777777"><i>Selection&nbsp;sequence:</i></td><td width=10 style="color: #777777"></td><td style="vertical-align: top">%s</td></tr>\n' % (selstr)
+        if not error:
+            s_table += '<tr><td height="10" style="vertical-align: top"><i>No.&nbsp;of&nbsp;runs&nbsp;selected:</i></td><td></td><td valign="top">%s</td></tr>\n' % len(runlist)
+            if totEv >= 0:
+                if naEv >= 0:
+                    sr = 'run'
+                    if naEv > 1: sr += 's'
+                    if naEv == 0:
+                        s_table += '<tr><td height="10" valign="top"><i>Total&nbsp;no.&nbsp;of&nbsp;events:</i></td><td></td><td valign="top">%s</td></tr>\n' % (cls._prettyNumber(totEv))
+                    else:
+                        s_table += '<tr><td height="10" valign="top"><i>Total&nbsp;no.&nbsp;of&nbsp;events:</i></td><td></td><td valign="top">%s (excluding %i %s without available "#Events" information)</td></tr>\n' % (cls._prettyNumber(totEv), naEv, sr)
+                else:
+                    s_table += '<tr><td height="10" valign="top"><i>Total&nbsp;no.&nbsp;of&nbsp;events:</i></td><td></td><td valign="top">%s</td></tr>\n' % (cls._prettyNumber(totEv))
+            s_table += '<tr><td height="10" valign="top"><i>Execution&nbsp;time:</i></td><td></td><td valign="top">%.1f sec</td></tr>\n' % round(querytime,1)
+            s_table += '<tr><td height=5 valign=top></td></tr>\n'
+        s_table += '</table>'
+        return s_table
+
+
+    @classmethod
+    def _PickledOutput(cls, datapath):
+        return '''<tr><td style="vertical-align: top"><img vspace=0 src="images/download.gif">&nbsp;&nbsp;</td><td>
+        <a href="./%s/atlrunquery.pickle" target=_blank title="Query results as serialised python dictionary">
+        Result table as pickled <b>python dictionary</b> (right-click link to download)</a> 
+        <br>
+        use as follows:<br>
+        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&minus;
+        open file (f) in python and deserialise ("unpickle")
+        via: dico = pickle.load(f)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&minus; the dictionary keys are equal to the column titles,
+        the lines are stored as list entries for each key
+        </td></tr>''' % datapath
+
+
+    @classmethod
+    def _RootOutput(cls, roothtmlstr, datapath):
+        if roothtmlstr!=None:
+            return '''
+            <tr><td style="vertical-align: top"><img vspace=0 width="17" src="images/tree_icon.gif">&nbsp;&nbsp;</td><td>
+            <a href="./%s/atlrunquery.root" title="Query results as ROOT TTree">Result table as <b>TTree</b> in ROOT file (right-click link to download)</a></td></tr>
+            <tr><td style="vertical-align: top"><img vspace=0 src="images/statistics.gif">&nbsp;&nbsp;</td><td style="vertical-align: top">
+            <font color="#333333"><b>Graphs</b> of table columns versus run numbers:</font>
+            </td></tr>
+            <tr><td style="vertical-align: top"></td><td style="vertical-align: top">%s
+            </td></tr>''' % (datapath, roothtmlstr)
+        else:
+            return '''
+            <tr><td style="vertical-align: top"><img vspace=0 width="17" src="images/tree_icon.gif">&nbsp;&nbsp;</td><td style="color: #000064;">
+            Not available. <font color="#333333">The creation of a ROOT file with the results has been disabled by default. Please use option <b><i>root</i></b> as shown in the examples under <font style="color:red">Xtras</font></font></td></tr>
+            <tr><td style="vertical-align: top"><img vspace=0 src="images/statistics.gif">&nbsp;&nbsp;</td><td style="vertical-align: top">
+            <font color="#333333">The creation of <b>Graphs</b> has been disabled by default. Please use option <b><i>root</i></b> as shown in the examples under <font style="color:red">Xtras</font></font>
+            </td></tr>'''
+
+
+    @classmethod
+    def _Description(cls):
+        return '''<tr style="line-height: 6.5"><td colspan="2"></td></tr>
+        <tr><td style="vertical-align: top"><img vspace=0 src="images/info.gif">&nbsp;&nbsp;</td><td height="55"><i>n.a.</i>
+        in the table stands for <i>not available</i>:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&minus;
+        in case of <i>#Events</i> this mostly indicates unproperly closed runs<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&minus;
+        in case of <i>data quality flags</i> it indicates that the corresponding flag was not set<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&minus;
+        <i><font color="red">runs in red</font></i> indicate that their selection is questionable due to n.a. information
+        (n.a. fields pass the corresponding selection query)
+        </td></tr>'''
+
+
+    @classmethod
+    def _PrintFormat(cls, s_table, resstr):
+        s  = '<tr><td><img vspace=0 src="images/printtopic.gif">&nbsp;&nbsp;</td>\n'
+        s += '<td><a href="javascript:openWindow('
+        s += "'Print','<!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;><html xmlns:&quot;my&quot;><head><title>Run query result</title><LINK href=&quot;atlas-runquery.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot;><body><table style=&quot;font-family: sans-serif; font-size: 85%%&quot;>"
+        s += '<tr><td>%s</td></tr>' % s_table.replace('"','&quot;')
+        s += '<tr><td>' + resstr.replace('resulttable','resulttabletext').replace('"','quot;') + '</td></tr>'
+        s += '<tr><td><hr color=&quot;red&quot; size=1></td></tr><tr><td><font color=&quot;#777777&quot;><font size=&quot;-1&quot;><i><font size=&quot;-2&quot;>Created by AtlRunQuery on: %s</font></i></font></td></tr></table><script type=&quot;text/javascript&quot;></script></body></html>' % str(datetime.datetime.now())
+        s += "')"
+        s += '" title="Query results in text format for easy printing">Print version of results</a>'
+        s += '</td></tr>'
+        return s
+
+
+    @classmethod
+    def _XMLFormat(cls, datapath, xmlfilename, xmlhtmlstr):
+        if xmlhtmlstr!=None:
+            s = '''<tr><td style="vertical-align: top"><img vspace=0 src="images/xml-small.gif">&nbsp;&nbsp;</td><td>
+            <a href="./%s/%s" target="_blank" title="Query result as LB collection in standard XML good-run-list format">Query result as standard <b>Good Run-LB List in XML format</b> (right-click link to download)</a> /
+            <a href="./LumiRangeCollection.dtd" target="_blank" title="Corresponding DTD file">DTD file</a>
+            </td></tr>''' % (datapath, xmlfilename)
+            s += '<tr><td style="vertical-align: top"></td><td>'
+            s += '<a href="javascript:openTextWindow('
+            s += "'Print','<!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;><html xmlns:&quot;my&quot;><head><title>Run query result</title><LINK href=&quot;atlas-runquery.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot;><body><table style=&quot;padding: 10px;font-family: sans-serif; font-size: 95%%&quot;>" 
+            s += '<tr><td>%s</td></tr>' % xmlhtmlstr
+            s += '</table></body></html>'
+            s += "')"
+            s += '" title="Query result in text format">Query result as standard <b>Good Run-LB List in pretty-text format</b> for visual inspection (click for pop-up)</a>'    
+            s += '</td></tr>'
+            return s
+        else:
+            return '''<tr><td style="vertical-align: top;"><img vspace=0 src="images/xml-small.gif">&nbsp;&nbsp;</td><td style="color: #000064;">
+            Not available. <font color="#333333">The creation of <b>GRLs</b> based on the query result has been disabled by default. Please use option <b><i>grl</i></b> as shown in the examples under <font style="color:red">Xtras</font></font></td></tr>'''
+
+
diff --git a/Database/CoolRunQuery/python/html/AtlRunQueryHtmlUtils.py b/Database/CoolRunQuery/python/html/AtlRunQueryHtmlUtils.py
new file mode 100755
index 00000000000..1debfac41c0
--- /dev/null
+++ b/Database/CoolRunQuery/python/html/AtlRunQueryHtmlUtils.py
@@ -0,0 +1,435 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+import time, datetime
+
+from CoolRunQuery.AtlRunQueryRun import Run
+from CoolRunQuery.AtlRunQueryQueryConfig import QC
+
+def WrapIntoHTML(content, title="Run query result", extracss=None):
+    wrap  = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">'
+    wrap += '<html xmlns:"my"><head><title>%s</title>' % title
+    wrap += '<LINK href="atlas-runquery-lb.css" rel="stylesheet" type="text/css">'
+    if extracss:
+        for css in extracss:
+            wrap += '<LINK href="%s" rel="stylesheet" type="text/css">' % css
+    wrap += '</head>'
+    wrap += '<body>%s</body></html>' % content
+    return wrap
+
+
+def OpenWindow(content, title="Run query result", extracss=None, size="normal"):
+    wrap = WrapIntoHTML(content, title, extracss)
+    openWindowCmd = 'openWindow'
+    if size=='large': openWindowCmd = 'openLargeWindow'
+    return "<a href=\"javascript:%s('Print', '%s')\">" % ( openWindowCmd, wrap.replace('"','&quot') )
+
+
+def CreatePopupHtmlPage(name,wincontent):
+    filename = 'popupContent_%s.html' % name
+    outfn = '%s/%s' % (Run.Datapath, filename) 
+    fh = open(outfn,"w")
+    if type(wincontent)==list:
+        for l in wincontent:
+            print >> fh, l
+    else:
+        print >> fh, wincontent
+    fh.close()
+    return outfn
+
+
+
+def CreateLBTable(run):
+    body  = '<table class="outer">'
+    body += '<tr><td><b>LB start times (%s) and durations for run %i:</b><br>' % (QC.tzdesc(),run.runNr)
+    body += '<font size="-1" color="#888888">(Begin/end of run: %s)</font>' % run.timestr('html', run.runNr != Run.runnropen)
+    body += '<hr color="black" size=1>'
+    body += '<table class="lb">'
+    body += '<tr><th>LB</th><th>Start time (%s)</th><th>Duration (sec)</th></tr>' % QC.tzdesc()
+    body += '<tr>'
+    for idx,(lbtime,lbendtime) in enumerate(run.lbtimes):
+        lb=idx+1
+        timetuple = time.localtime(lbtime/1.E9) if QC.localtime else time.gmtime(lbtime/1.E9)
+        body += '<tr><td>%s</td><td>%s</td><td>%.2f</td></tr>' % (lb, time.strftime('%X',timetuple), (float(lbendtime)-float(lbtime))/1.E9)
+    if run.runNr == Run.runnropen: # run still ongoing
+        body += '<tr><td style="text-align:left"colspan="3"><i>&nbsp;&nbsp;Run still ongoing ...</i></td></tr>'
+    body += '</tr></table>'
+    body += '<hr color="red" size=1><font color="#777777"><font size="-1"><i><font size="-2">Created by AtlRunQuery on: %s</font></i></font></td></tr></table>' % str(datetime.datetime.now())
+    body += '</td></tr></table>'
+    return body.replace('"','&quot')
+
+
+
+def CreateLBTooltip(run):
+    if len(run.lbtimes)==0: return
+    
+    content = '<strong><b>LB start times (%s) and durations for run %i:</b></strong><br>Begin/end of run: %s' % (QC.tzdesc(), run.runNr, run.timestr('html', run.runNr != Run.runnropen))
+    content += '<hr style="width:100%; background-color: #BBBBBB; height:1px; margin-left:0; border:0"/>'
+    content += '<table style="width: auto; border: 0px solid; border-width: margin: 0 0 0 0; 0px; border-spacing: 0px; border-collapse: separate; padding: 0px; font-size: 90%">'
+    content += '<tr>'
+    if len(run.lbtimes) > 150:
+        content += '<td><i>Too many LBs to show ... (click instead!)</i></td>'
+    else:
+        for idx,(lbstart, lbend) in enumerate(run.lbtimes):
+            lb=idx+1
+            timetuple = time.localtime(lbstart/1.E9) if QC.localtime else time.gmtime(lbstart/1.E9)
+            content += '<td style="text-align:right">&nbsp;&nbsp;%s:&nbsp;%s&nbsp;</td><td style="text-align:right">(%.1f&nbsp;sec)</td>' % (lb, time.strftime("%X",timetuple), (float(lbend)-float(lbstart))/1.E9)
+            if lb%6==0:
+                content += '</tr><tr>'
+    content += '</tr></table>'
+    content += '<hr style="width:100%; background-color: #BBBBBB; height:1px; margin-left:0; border:0"/>'
+    content += '<font color="#AA0000">Click to obtain full list in independent window!</font>'
+    run.addToolTip( 'LBStart_%i' % run.runNr, content )
+
+
+
+def CreateDQTooltip(run):
+    if not 'DQ' in Run.ShowOrder: return
+
+    def_with_primaries = run.stats['DQ']["primaries"]
+    condensed = True
+    if not condensed:
+        for x in sorted(def_with_primaries.keys()):
+            l_ready = [y for y in def_with_primaries[x] if run.data.isReady( (y.since,y.until) )]
+            if len(l_ready)==0: continue
+            content  = '<strong><b>%s: comments for run %i:</b></strong><br><span style="font-size: 80%%">ATLAS READY in LBs %s</span>' % (x,run.runNr,', '.join(["%i&minus;%i" % (r.startlb, r.endlb-1) for r in run.data.isReady()]))
+            content += '<hr width="100%%">'
+            content += '<table style="width: auto; white-space: nowrap; border: 0px solid; margin: 0 0 0 0; border-spacing: 0px; border-collapse: separate; padding: 0px;">'
+            for y in l_ready:
+                s = "%i&minus;%i" % (y.since,y.until-1) if y.until-y.since!=1 else "%i" % (y.since)
+                content += '<tr><td style="color:blue; padding-right: 5px;">LB %s</td>' % s # the LB info
+                content += '<td style="font-weight:bold; padding-right: 5px;">%s</td><td><i>%s</i></td></tr>' % (y.description.split("->")[-1], y.comment)  # the primary and the comment
+            content += '</table>'
+            run.addToolTip("dqdefect_%i_%s" % (run.runNr,x), content)
+    else:
+        from itertools import groupby
+        from operator import attrgetter
+        gr = {}
+        for k in def_with_primaries:
+            d = {}
+            for p,v in groupby(sorted(def_with_primaries[k]), key=attrgetter('description', 'comment')):
+                d[p] = [(e.since, e.until) for e in v]
+            gr[k] = d
+
+        for x in sorted(gr):
+            content  = '<strong><b>%s: comments for run %i:</b></strong><br><span style="font-size: 80%%">ATLAS READY in LBs %s</span>' % (x,run.runNr,', '.join(["%i&minus;%i" % (r.startlb, r.endlb-1) for r in run.data.isReady()]))
+            content += '<hr width="100%%">'
+            content += '<table style="width: auto; white-space: nowrap; border: 0px solid; margin: 0 0 0 0; border-spacing: 0px; border-collapse: separate; padding: 0px;">'
+            for pdef in sorted(gr[x]):
+                l_ready = [y for y in gr[x][pdef] if run.data.isReady( y )]
+                if len(l_ready)==0: continue
+                s = ", ".join(["%i&minus;%i" % y if y[1]-y[0]!=1 else "%i" % (y[0]) for y in l_ready])
+                content += '<tr><td colspan="2" style="color:blue; padding-right: 5px; max-width: 130;">LB %s</td></tr>' % s # the LB info
+                content += '<tr><td style="font-weight:bold; padding-right: 5px;">%s</td><td><i>%s</i></td></tr>' % (pdef[0].split("->")[-1], pdef[1])  # the primary and the comment
+            content += '</table>'
+            run.addToolTip("dqdefect_%i_%s" % (run.runNr,x), content)
+
+
+def CreateStreamOverlapTooltip(run,k):
+    if not run.stats[k.ResultKey]['StrOverlap']:
+        ovstr = '<tr><td width="200"><b><i>None (or not available for this run)</i></b></td></tr>'
+    else:
+        ovstr = ''
+        nacc=0
+        for stream, fraction in run.stats[k.ResultKey]['StrOverlap']:
+            nacc+=1
+            tdstr = '<td class="tdov%i">' % (nacc%2+1)
+            fs = "%.2g" % fraction
+            if fraction==100: fs = "100"
+            ovstr += '<tr>%s%s</td>%s&nbsp;=&nbsp;</td>%s%s%%</td></tr>' % (tdstr, stream, tdstr, tdstr, fs)
+            strpairs = [('STR:physics_MuonswBeam',   'physics_L1Calo'),
+                        ('STR:physics_MinBias', 'physics_L1Calo'),
+                        ('STR:physics_Muons',   'physics_Egamma'),
+                        ('STR:physics_Muons',   'physics_JetTauEtmiss'),
+                        ('STR:physics_Egamma',  'physics_JetTauEtmiss'),
+                        ('STR:physics_MinBias', 'physics_JetTauEtmiss')]
+            for st in strpairs:
+                if k==st[0] and stream==st[1]:
+                    s1 = st[0].replace('STR:','')
+                    fname = 'data_' + s1.strip() + '_' + st[1].strip() + '.txt'
+                    f = open(Run.Datapath + '/' + fname,'a')
+                    f.write('%i   %f\n' % (run.runNr,fraction))
+                    f.close()
+                    break
+
+    boxcontent = '<table class="streamtiptable"><tr><td>'
+    boxcontent += '<strong><b>Info&nbsp;for&nbsp;stream:&nbsp;<font color="#AA0000">%s</font></b></strong>' % k.Header[4:]
+    boxcontent += '</td></tr><tr><td>'
+    boxcontent += '<hr style="width:100%; background-color: #999999; height:1px; margin-left:0; border:0"/>'
+    boxcontent += '</td></tr>'
+    boxcontent += '<tr><td>'
+    boxcontent += '<strong><b>Stream&nbsp;overlaps</b></strong>&nbsp;(nonzero&nbsp;overlaps&nbsp;only):'
+    boxcontent += '</td></tr><tr><td>'
+    boxcontent += '<table class="overlaptable">%s</table><strong>' % ovstr
+    boxcontent += '</td></tr>'
+
+    # Tier-0 output            
+    prodsteps = ['StrTier0TypesRAW', 'StrTier0TypesESD' ]
+    allt0text = ''
+    for p in prodsteps:
+        if run.stats[k.ResultKey].has_key(p):
+            typelist = run.stats[k.ResultKey][p].keys()
+            if not typelist: continue
+
+            typelist.sort()
+            t0text = ''
+            for i, t0out in enumerate(typelist):
+                if not 'TMP' in t0out: # don't show temporary output
+                    if i%4==0 and i>0: t0text += '<br>'                            
+                    if t0out == 'NTUP': t0outtxt = 'NTUP_... <font size="-2">(types as above)</font>' # stands for all NTUP types in merge step
+                    else:               t0outtxt = t0out
+                    if run.stats[k.ResultKey][p][t0out]: # output on CAF
+                        t0text += '<font color="#BB0000">%s</font>, ' % t0outtxt
+                    else:
+                        t0text += '%s, ' % t0outtxt
+
+            if t0text != '':
+                allt0text += '<strong><b><i>'
+                if 'RAW' in p:
+                    allt0text += 'Produced&nbsp;by&nbsp;reconstruction&nbsp;step'
+                    if run.stats[k.ResultKey].has_key('StrTier0AMI') and run.stats[k.ResultKey]['StrTier0AMI']:
+                        if run.stats[k.ResultKey]['StrTier0AMI'].has_key(p):
+                            allt0text += '&nbsp;(AMI&nbsp;tag:&nbsp;%s)' % run.stats[k.ResultKey]['StrTier0AMI'][p]
+                        else:
+                            allt0text += '&nbsp;(AMI&nbsp;tag:&nbsp;%s)' % 'UNKNOWN'
+                else:
+                    allt0text += 'Produced&nbsp;by&nbsp;merge&nbsp;step'
+
+                allt0text += ':</i></b></strong>'
+
+                allt0text += '<table class="overlaptable"><tr><td style="padding-left:10px">' + t0text[:len(t0text)-2] + '</td></tr></table>'
+                if p != prodsteps[-1]: allt0text += ''
+
+    if allt0text != '':
+        boxcontent += '<tr><td>'
+        boxcontent += '<hr style="width:100%; background-color:#999999; height:1px; margin-left:0; border:0"/>'
+        boxcontent += '</td></tr><tr><td>'
+        boxcontent += '<strong><b>Tier-0 output types for this stream:</b></strong><br>(Datasets in <font color="#BB000"><strong><b>red</b></strong></font> are <font color="#BB000">replicated to CAF</font>'
+        boxcontent += '</td></tr><tr><td>'
+        boxcontent += '<table class="overlaptable" style="color:#222222"><tr><td>%s</td></tr></table>' % allt0text
+        boxcontent += '</td></tr>'
+
+    # events-per-LB information
+    lbrecinfo = run.stats[k.ResultKey]['LBRecInfo']
+    if not lbrecinfo:
+        lbrecinfo = '<tr><td style="font-size:75%"><i>No LB information in SFO DB. <br> Probably because files for this stream <br>were not closed at LB boundaries by SFO.</i></td></tr>'
+    else:
+        ev = dict(lbrecinfo)
+        for lb in ev: ev[lb]=0
+        for lb,nev in lbrecinfo: ev[lb] += nev
+        lbs = ev.keys(); lbs.sort()
+        output = '<tr>'
+        idx = 0
+        while idx <len(lbs):
+            output += '<td style="font-size:75%%;text-align:right">%i&nbsp;(%s)</td>' % (lbs[idx],ev[lbs[idx]])
+            if len(lbs)>50 and idx==23:
+                output += '</tr><tr><td style="font-size:75%; text-align:left" colspan="8">&nbsp;... <i>too many LBs ... show begin and end of run only...</i></td></tr>'
+                idx = len(lbs) - 23
+            elif (idx+1)%8==0: output += '</tr><tr>' # newline every 10
+            idx += 1
+        output += '</tr>'
+        lbrecinfo = output
+
+    boxcontent += '<tr><td>'
+    boxcontent += '<hr style="width:100%; background-color:#999999; height:1px; margin-left:0; border:0"/>'
+    boxcontent += '<strong><b>Recorded LB (#Events)</b></strong></strong>:'
+    boxcontent += '</td></tr><tr><td>'
+    boxcontent += '<table class="eventsperlbstreamtable" style="color:#222222">%s</table>' % lbrecinfo
+    boxcontent += '</td></tr></table>'
+    if not 'No LB information' in lbrecinfo:
+        boxcontent += '<font color="#AA0000"><strong><b>Click to obtain the full LB list and plots in independent window!</b></strong></font>'
+
+    run.addToolTip("STROV_%i_%s" % (run.runNr, k.ResultKey[4:]), boxcontent)
+
+
+
+
+
+def createRatePopupWindow(v,run):
+    from CoolRunQuery.output.AtlRunQueryRoot import makeRatePlot
+    histoText = '' # upper left on above the histogramm
+
+    lbduration = [(idx+1,lbtime,(lbendtime-lbtime)/1e9) for idx,(lbtime,lbendtime) in enumerate(run.lbtimes) ]
+
+    duration = (run.lbtimes[-1][1] - run.lbtimes[0][0])/1e9
+    averrate = []
+    for tr in v:
+        averrate.append((tr, sum([int(co[3]) for co in v[tr]])/duration))
+    averrate.sort(lambda x,y: cmp(y[1],x[1]))
+
+    paths = []
+    wincmds = []
+    triggergroups = []
+    loopcntr = 0
+    plotstart = 0
+    plotrange = 8
+    triggers_in_range = averrate[plotstart:plotstart+plotrange]
+    while len(triggers_in_range)>0:
+        path  = makeRatePlot( v, lbduration, triggers_in_range, averrate, 'Luminosity block number', 'Rate [Hz]',
+                              'trigcounts%i_vs_lb_run_%i' % (loopcntr,run.runNr),
+                              'Trigger Rates for run %i' % (run.runNr),
+                              Run.Datapath, histoText )
+        paths += [path]
+
+        wincmd = createRateWinContent(loopcntr, v, lbduration, triggers_in_range, run, path)
+        wincmds += [wincmd]
+
+        triggergroups += [triggers_in_range]
+
+        loopcntr += 1
+        plotstart += plotrange
+        triggers_in_range = averrate[plotstart:plotstart+plotrange]
+
+    return triggergroups,paths,wincmds
+
+
+
+
+def createRateWinContent(loopcntr, v, lbduration, triggers_in_range, run, path):
+
+    triggers = [tr[0] for tr in triggers_in_range]
+
+    # create window and tooltip
+    wincontent  = ['<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">']
+    wincontent += ['<html xmlns:"my">']
+    wincontent += ['  <head>']
+    wincontent += ['    <title>Run query result for trigger rates</title>']
+    wincontent += ['    <LINK href="atlas-runquery-lb.css" rel="stylesheet" type="text/css">']
+    wincontent += ['  </head>']
+    wincontent += ['  <body>']
+    wincontent += ['    <table class="outer" style="padding: 5px">']
+    wincontent += ['      <tr><td><strong><b>Trigger rates for run %s:</b></strong><br><font size="-1" color="#888888">(Begin/end of run: %s)</font></td></tr>' % (run.runNr, run.timestr('html', run.runNr != Run.runnropen))]
+    wincontent += ['      <tr><td colspan="2"><hr color="black" size=1></td></tr>']
+    wincontent += ['      <tr><td><img src="%s" align="left"></td>' % path.rsplit('/')[-1]]
+    wincontent += ['      <td><img src="%s" align="left"></td></tr>' % path.rsplit('/')[-1].replace('.png','_log.png')]
+    wincontent += ['      <tr><td colspan="2"><hr color="black" size=1></td></tr>']
+    wincontent += ['      <tr><td colspan="2" style="font-size:70%; height:30px; text-align: right;  vertical-align: middle;"><b>TBP</b> - <i>trigger before prescale</i>,<b>TAV</b> - <i>trigger after veto</i>, <b>DTF</b> - <i>dead time fraction</i></td></tr>']
+    wincontent += ['      <tr><td colspan="2">']
+    wincontent += ['        <table class="LB">']
+    header = '<th>LB</th><th>Start time</th><th>Duration</th>'
+    header2 = '<th></th><th>(%s)</th><th>(s)</th>' % QC.tzdesc()
+    for tr in triggers:
+        if "UNPAIRED" in tr or "EMPTY" in tr or "FILLED" in tr:
+            header += '<th colspan="3">%s<BR>_%s</th>' % tuple(tr.rsplit('_',1))
+        else:
+            header += '<th colspan="3">%s</th>' % tr
+        header2 += '<th>TBP</th><th>TAV</th><th>DTF</th>'
+    wincontent += ['          <thead>']
+    wincontent += ['            <tr>%s</tr>' % header]
+    wincontent += ['            <tr class="second">%s</tr>' % header2]
+    wincontent += ['          </thead>']
+    wincontent += ['          <tbody>']
+    for lb, lbstart, dt in lbduration:
+        timetuple = time.localtime(lbstart/1.E9) if QC.localtime else time.gmtime(lbstart/1.E9)
+        linecontent = '<td>%i</td><td>%s</td><td class="dt">%3.1f</td>' % (lb,time.strftime("%X",timetuple),dt)
+        for tr in triggers:
+            _lb,bp,ap,av = v[tr][lb-1]
+            try: avr=float(av)/dt
+            except: avr=0
+            try: bpr=float(bp)/dt
+            except: bpr=0
+            try: apr=float(ap)/dt
+            except: apr=0
+            deadtime=0
+            bg = ""
+            if apr>0:
+                deadtime = ( apr - avr ) / apr
+                if deadtime>0.90:   bg=' style="background-color: #ff0000;"'
+                elif deadtime>0.30: bg=' style="background-color: #ff3333;"'
+                elif deadtime>0.10: bg=' style="background-color: #ff6666;"'
+                elif deadtime>0.05: bg=' style="background-color: #ff9999;"'
+                elif deadtime>0.01: bg=' style="background-color: #ffcccc;"'
+            linecontent += '<td>%3.1f</td><td>%3.1f</td><td%s class="dt">(%2.1f%%)</td>' % (bpr,avr,bg,100*deadtime)
+        if lb%2!=0: col = '#eeeeee'
+        else:       col = '#ffffff'
+        wincontent += ['            <tr style="background:%s">%s</tr>' % (col,linecontent)]
+
+    if run.runNr == Run.runnropen: # run still ongoing
+        wincontent += ['            <tr><td style="text-align:left"colspan="%i"><i>&nbsp;&nbsp;Run still ongoing ...</i></td></tr>' % (len(triggers)+1)]
+    wincontent += ['          </tbody>']
+    wincontent += ['        </table>']
+    wincontent += ['      </td></tr>']
+    wincontent += ['      <tr><td colspan="2"><hr color="red" size=1></td></tr>']
+    wincontent += ['      <tr><td colspan="2">']
+    wincontent += ['        <font color="#777777" size="-1"><i><font size="-2">Created by AtlRunQuery on: %s</font></i></font>' % str(datetime.datetime.now())]
+    wincontent += ['      </td></tr>']
+    wincontent += ['    </table>']
+    wincontent += ['  </body>']
+    wincontent += ['</html>']
+
+    CreatePopupHtmlPage('trRates_%i_%i' % (run.runNr, loopcntr), wincontent)
+    return ''
+
+
+
+
+
+def makeSummaryPlotForLHC(run):
+    from CoolRunQuery.output.AtlRunQueryRoot import makeLBPlotSummaryForLHC
+    # make summary of all LHC information
+    # requires: beam intensities, beam energy, stable beams
+    # keys = [ 'olc:beam1intensity', 'olc:beam2intensity', 'lhc:beamenergy', 'olc:lumi:0' ]
+    xvec    = []
+    yvec    = [[],[],[]]  # note that this is not the same as 3*[[]]
+    ymax    = 3*[-1]
+
+    # stable beams
+    hasStableBeamsInfo, xvecStb = run.getStableBeamsVector()
+    for ik,k in enumerate( [ 'olc:beam1intensity', 'olc:beam2intensity', 'lhc:beamenergy' ] ):
+        if not k in Run.ShowOrder: continue
+        for entry in run.data[k]:
+            if entry.startlb == 0: continue
+
+            val = float(entry.value) if (entry.value!='n.a.' and entry.value>0) else 0
+
+            if ik==0 or ik==1:
+                if val > 1e30: val = 0
+                val *= 1.0 # beam intensities in 10^11 protons
+            elif ik==2:
+                if val >= 7864: val = -1
+
+            lastlb = min(entry.lastlb,run.lastlb)
+
+            if ik==0:
+                xvec += range(entry.startlb,lastlb+1)
+
+            yvec[ik] += (lastlb-entry.startlb+1) * [val]
+
+            for ilb in xrange(entry.startlb,lastlb+1):
+                if val > ymax[ik]:
+                    if not hasStableBeamsInfo or ilb in xvecStb: ymax[ik] = val # find max                
+
+    histoText = ''
+    path = makeLBPlotSummaryForLHC( xvec, xvecStb, yvec, run.runNr, Run.Datapath, histoText )
+
+    return path, xvec, yvec, ymax
+
+
+def makeSummaryPageForLHC(run, yvec, path):
+    # create window and tooltip
+    wincontent  = '<table class=&quot;outer&quot; style=&quot;padding: 5px; font-family: sans-serif; font-size: 85%&quot;><tr><td>'
+    wincontent += '<strong><b>LHC beam energy and intensities during run %i:</b></strong><br><font size=&quot;-1&quot;><font color=&quot;#888888&quot;>(Begin/end of run: %s)</font></font><hr color=&quot;black&quot; size=1>' % (run.runNr, run.timestr('html', run.runNr != Run.runnropen))
+    wincontent += '<table style=&quot;padding: 0px&quot;><tr><td>'
+    wincontent += '<img src=&quot;%s&quot; align=&quot;left&quot;></td>' % path
+    wincontent += '</td></tr></table>'
+    wincontent += '<hr color=&quot;black&quot; size=1>'
+    wincontent += '<table class=&quot;lb&quot;>'
+    wincontent += '<tr><th style=&quot;text-align:right&quot;>LB</th><th style=&quot;text-align:right&quot;>&nbsp;&nbsp;&nbsp;Start time<br> (%s)</th><th style=&quot;text-align:right&quot;>&nbsp;&nbsp;&nbsp;Duration<br>(sec)</th><th style=&quot;text-align:right&quot;>&nbsp;&nbsp;&nbsp;Beam energy<br>(GeV)</th><th style=&quot;text-align:right&quot;>&nbsp;&nbsp;&nbsp;Intensity Beam-1<br>(1e11&nbsp;protons)</th><th style=&quot;text-align:right&quot;>&nbsp;&nbsp;&nbsp;Intensity Beam-2<br>(1e11&nbsp;protons)</th>' % QC.tzdesc()
+    wincontent += '</tr><tr style=&quot;background:%s&quot;>' % '#eeeeee'
+    nbeam1intensity = len(yvec[0])
+    nbeam2intensity = len(yvec[1])
+    nbeamenergy     = len(yvec[2])
+    for idx,(lbtime,lbendtime) in enumerate(run.lbtimes):
+        lb=idx+1
+        timetuple = time.localtime(lbtime/1.E9) if QC.localtime else time.gmtime(lbtime/1.E9)
+        beam1intensity = yvec[0][idx] if idx<nbeam1intensity else 0
+        beam2intensity = yvec[1][idx] if idx<nbeam2intensity else 0
+        beamenergy     = yvec[2][idx] if idx<nbeamenergy else 0
+        wincontent += '<td>%i</td><td>%s</td><td>%.2f</td><td>%i</td><td>%.4g</td><td>%.4g</td>' % (lb, time.strftime("%X",timetuple), (float(lbendtime)-float(lbtime))/1.E9, beamenergy, beam1intensity, beam2intensity)
+        if idx%2!=0: col = '#eeeeee'
+        else:        col = '#ffffff'
+        wincontent += '</tr><tr style=&quot;background:%s&quot;>' % col
+    if run.runNr == Run.runnropen: # run still ongoing
+        wincontent += '<tr><td style=&quot;text-align:left&quot;colspan=&quot;4&quot;><i>&nbsp;&nbsp;Run still ongoing ...</i></td></tr>'
+    wincontent += '</tr></table>'
+    wincontent += """<hr color=&quot;red&quot; size=1><font color=&quot;#777777&quot;><font size=&quot;-1&quot;><i><font size=&quot;-2&quot;>Created by AtlRunQuery on: %s</font></i></font></td></tr></table>""" % str(datetime.datetime.now())
+    return wincontent
diff --git a/Database/CoolRunQuery/python/html/AtlRunQueryPageMaker.py b/Database/CoolRunQuery/python/html/AtlRunQueryPageMaker.py
new file mode 100644
index 00000000000..7421e7ed9ad
--- /dev/null
+++ b/Database/CoolRunQuery/python/html/AtlRunQueryPageMaker.py
@@ -0,0 +1,50 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+
+import os, re
+
+class PageMaker:
+
+    @classmethod
+    def makePage(cls, body, origQuery=None, extraReplace=None, removeExamples=False):
+        from CoolRunQuery.AtlRunQueryQueryConfig import QC
+        
+        (top, bottom) = cls.getBlankPage(removeExamples=removeExamples)
+        # put in the original query
+        if origQuery != None:
+            top = top.replace('name="q"','name="q" value="%s"' % origQuery)
+
+        # extra replacements
+        if extraReplace != None:
+            for pat,repl in extraReplace:
+                p = re.compile(pat,re.S)
+                top = p.sub(repl, top)
+                bottom = p.sub(repl, bottom)
+        
+        fh = open("%s/index.html" % QC.datapath, "w")
+        print >> fh, top
+        print >> fh, body.encode("utf-8")
+        print >> fh, bottom
+        fh.close()
+
+        cls._copySomeFilesToCache()
+
+
+    @classmethod
+    def getBlankPage(cls, removeExamples=False):
+        if '/var/vhost' in os.path.dirname(__file__):
+            page = open("%s/index.html" % os.path.dirname(__file__).replace('CoolRunQuery/html',''))
+        else:
+            page = open("%s/atlas-runquery.html" % os.path.dirname(__file__).replace('python/CoolRunQuery/html','html/CoolRunQuery'))
+        s = page.read()
+        top, bottom = re.match("(.*)<!--INSERTQUERYRESULT-->(.*)", s, re.S|re.M).group(1,2)
+        if removeExamples:
+            top = "".join(re.match("(.*)<!--START_EXAMPLES-->.*<!--END_EXAMPLES-->(.*)", top, re.S|re.M).group(1,2))
+        return (top,bottom)
+    
+
+    @classmethod
+    def _copySomeFilesToCache(cls):
+        from commands import getoutput
+        from CoolRunQuery.AtlRunQueryQueryConfig import QC
+        getoutput("cp html/atlas-runquery-lb.css %s" % QC.datapath)
diff --git a/Database/CoolRunQuery/python/html/AtlRunQuerySummary.py b/Database/CoolRunQuery/python/html/AtlRunQuerySummary.py
new file mode 100644
index 00000000000..58e38a4e81a
--- /dev/null
+++ b/Database/CoolRunQuery/python/html/AtlRunQuerySummary.py
@@ -0,0 +1,651 @@
+#!/bin/env python
+
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+#
+# ----------------------------------------------------------------
+# Script : AtlRunQuerySummary.py
+# Project: AtlRunQuery
+# Purpose: Library with the Summary maker
+# Authors: Andreas Hoecker (CERN), Joerg Stelzer (DESY)
+# Created: Oct 6, 2009
+# ----------------------------------------------------------------
+#
+import sys, time
+from array import array                
+from CoolRunQuery.utils.AtlRunQueryUtils  import prettyNumber, durationInSeconds, filesize, importroot
+from CoolRunQuery.utils.AtlRunQueryLookup import DQChannelDict, DQSuperGroupsDict, DQGroupDict, DQChannels
+from CoolRunQuery.output.AtlRunQueryRoot   import SetStyle, MakeHtml
+from CoolRunQuery.selector.AtlRunQuerySelectorBase       import DataKey
+importroot()
+from ROOT import TCanvas, gPad, gStyle, TGraph, TColor, TGaxis, gROOT, TH1F, TLegend, TText, TLine, Double
+
+# custom ROOT colours
+c_White         = TColor.GetColor( "#ffffff" )
+c_NovelBlue     = TColor.GetColor( "#2244a5" )
+c_DarkOrange    = TColor.GetColor( "#ff6600" )
+c_NovelRed      = TColor.GetColor( "#dd0033" )
+c_DarkGreen     = TColor.GetColor( "#116600" )
+c_Violet        = TColor.GetColor( "#aa11aa" )
+c_LightBlue     = TColor.GetColor( "#66aaff" )
+c_VDarkYellow   = TColor.GetColor( "#ffa500" )
+c_Gray          = TColor.GetColor( "#888888" )
+c_VLightGray    = TColor.GetColor( "#eeeeee" )
+c_VDarkGray     = TColor.GetColor( "#333333" )
+
+def MakeSummaryTableHtml( cornerstr, colstr, rowkeys, table, tablewidth ):
+
+    # dimensions
+    ncol = len(colstr)
+    nrow = len(rowkeys)
+    
+    s = '<table class="resulttable" width="%i" style="margin-left: 14px">\n' % tablewidth
+    # headline    
+    s += '<tr>\n'
+    if cornerstr != '': s += '   <th style="text-align:left">%s</th>  ' % cornerstr
+    else:               s += '   <th class="emptycorner">&minus;</th>'
+    for ic in range(0,ncol):
+        s += '<th>%s</th>' % colstr[ic]
+    s += '</tr>\n'
+    for ir in range(0,nrow):
+        if ir%2 == 0: color = 1
+        else:         color = 2
+        if  'debug_' in rowkeys[ir][1]: s += '<tr class="outRed%s">\n' % color   # special colours for debug stream
+        else:                           s += '<tr class="out%s">\n' % color
+        s += '   <th class="rowsum" style="text-align:left">%s&nbsp;</th>  ' % rowkeys[ir][1]
+        for ic in range(ncol):
+            if ic in rowkeys[ir][4]: # exclude from printing
+                s += '<td style="text-align:center">&minus;</td'
+                continue
+            s += '<td style="text-align:right">'
+            if isinstance(table[ir][ic],str):
+                s += "%s" % table[ir][ic] # example filesize
+            elif rowkeys[ir][3] == 'pretty-int':
+                s += "%s" % prettyNumber(int(table[ir][ic])) # example '#Event'
+            else:
+                s += (rowkeys[ir][3] % table[ir][ic]) # format
+            s += '%s</td>' % rowkeys[ir][2] # unit
+
+        s += '</tr>\n'
+    s += '</table>'
+
+    return s
+
+def MakeDQSummaryTableHtml( cornerstr, title, colstr, colchans, rowstr, rowstrNames, dic, nruns, labeloffset ):
+
+    if nruns <= 0: return ''    
+
+    # dimensions
+    ncol = len(colstr) # flag types
+    nrow = len(rowstr) # DQ channels
+
+    # overlay pictures
+    dw_call = '<script type="text/javascript">\n'
+    dw_call += """if(dw_Tooltip.content_vars==undefined) {dw_Tooltip.content_vars = {}; };\n"""
+    for ir in range(0,nrow):
+        for ic in range(0,ncol):
+            if dic[colchans[ic]][rowstr[ir]][0] > 0:
+                var = 'var_%i_%i' % (ir,ic+labeloffset)
+                dw_call += 'dw_Tooltip.content_vars["%s"] = {' % var
+                dw_call += "content: '<strong><b>Corresponding&nbsp;run(s)&nbsp;[#&nbsp;=&nbsp;%i]:</b></strong><br> " % dic[colchans[ic]][rowstr[ir]][0]
+                icc = 0
+                for r in dic[colchans[ic]][rowstr[ir]][1]:
+                    dw_call += '%s, ' % r
+                    icc += 1
+                    if icc%8 == 0: dw_call += '<br>'
+                if dw_call[-1-3:] == '<br>': dw_call = dw_call[0:-1-3] # remove ', <br>'
+                else:                        dw_call = dw_call[0:-1-1] # remove ', '
+                dw_call += """ ' };\n"""
+    dw_call += '</script>\n\n'
+
+    s = '<table class="resulttable" width="auto" style="margin-left: 14px">\n'
+    # headline    
+    s += '<tr>\n'
+    if cornerstr != '': s += '   <th class="rowsum" style="text-align:left" rowspan="2">%s</th>  ' % cornerstr
+    else:               s += '   <th class="emptycorner" rowspan="2">&minus;</th>'
+    s += '<th class="colsumL" colspan="%i">%s</th></tr><tr>' % (ncol, title)
+    for ic in range(0,ncol):
+        s += '<th class="colsum">%s</th>' % colstr[ic]
+    s += '</tr>\n'
+    for ir in range(0,nrow):
+        if ir%2 == 0: color = 1
+        else:         color = 2
+        s += '<tr class="out%s">\n' % color
+        s += '   <th class="rowsum" style="text-align:left">%s</th>  ' % rowstrNames[ir]
+        for ic in range(0,ncol):            
+            dqk = rowstr[ir]
+            dqk_tdtype = dqk
+            if dqk == 'n.a.': dqk_tdtype = 'NA'
+            s += '<td class="td%s" style="text-align:center">' % dqk_tdtype
+            if dic[colchans[ic]][rowstr[ir]][0] > 0: s += '<div class="showTip var_%i_%i" style="display:inline;cursor:pointer">' % (ir,ic+labeloffset)
+            if dic[colchans[ic]][dqk][0]>0: s += '%i' % (dic[colchans[ic]][dqk][0])
+            if dic[colchans[ic]][rowstr[ir]][0] > 0: s += '</div>'
+            s += '</td>'
+
+        s += '</tr>\n'
+    s += '</table>\n\n'
+    s += dw_call
+    s += '\n'
+
+    return s
+
+def ComputeStats( vlist ):
+    if len(vlist) == 0: return [0,0,0,0,0]
+    tot = 0
+    mn = +sys.maxint
+    mx = -sys.maxint
+    for v in vlist:
+        tot += v
+        mn = min(mn,v)
+        mx = max(mx,v)
+    mean = float(tot)/len(vlist)
+    return [tot,mean,mn,mx,len(vlist)]
+
+def DecodeStr( s, tpe ):
+    if 'Duration' == tpe:
+        return durationInSeconds(s)/float(3600)
+    elif 'STR:physics_*' == tpe:
+        s = s[0].value
+        if len(s) <= 1:
+            print 'Big troubles... in function "AtlRunQuerySummary::DecodeStr": invalid length for "%s"' % tpe
+            sys.exit(1)
+        if s[0] <= 0: return 0
+        else:         return float(s[1])/s[0]/1.0e6
+
+    # otherwise
+    return int(s[0].value)
+
+def DrawGraph( graph, col, width, style, legend, title,
+               drawNumber=False, unit='M', text=TText() ):
+    hist = graph.GetHistogram()
+    hist.SetLineColor( col )
+    graph.SetLineColor( col )
+    hist.SetLineWidth( width )
+    graph.SetLineWidth( width )
+    hist.SetLineStyle( style )
+    graph.SetLineStyle( style )
+    graph.Draw("lsame")
+    legend.AddEntry( hist, title, "L" )
+
+    # draw max number
+    if drawNumber:
+        N = graph.GetN()
+        minunit_ = Double(0)
+        maxunit_ = Double(0)
+        minnev_  = Double(0)
+        maxnev_  = Double(0)
+        x        = Double(0)
+        y        = Double(0)
+        graph.GetPoint( 0,   minunit_, minnev_ )
+        graph.GetPoint( N-1, maxunit_, maxnev_ )
+        dist    = maxunit_ - minunit_
+        graph.GetPoint( N-1,x,y )
+
+        text.SetTextAlign( 12 )
+        text.SetTextSize( 0.030 )
+        text.SetTextColor( c_NovelBlue )
+        if y >= 100: yt = '%.0f'  % y
+        else:        yt = '%#.3g' % y
+        text.DrawText( x+0.015*dist, y, '%s %s' % (yt, unit) )
+
+def SetFrameStyle( frame, scale = 1.0 ):
+
+    c_VLightGray = TColor.GetColor( "#eeeeee" )
+    c_VDarkGray  = TColor.GetColor( "#333333" )
+
+    frame.SetLabelOffset( 0.012, "X" )
+    frame.SetLabelOffset( 0.012, "Y" )
+    frame.GetXaxis().SetTitleOffset( 1.25 )
+    frame.GetYaxis().SetTitleOffset( 0.94 )
+    frame.GetXaxis().SetTitleSize( 0.045*scale )
+    frame.GetYaxis().SetTitleSize( 0.045*scale )
+    labelSize = 0.04*scale
+    frame.GetXaxis().SetLabelSize( labelSize )
+    frame.GetYaxis().SetLabelSize( labelSize )
+    gPad.SetTicks()
+    gPad.SetBottomMargin( 0.120*scale  )
+    gStyle.SetTitleFillColor( c_VLightGray )
+    gStyle.SetTitleTextColor( c_VDarkGray )
+    gStyle.SetTitleBorderSize( 1 )
+    gStyle.SetTitleH( 0.06 )
+    gStyle.SetTitleX( gPad.GetLeftMargin() )
+    gStyle.SetTitleY( 1 - gPad.GetTopMargin() + gStyle.GetTitleH() )
+    gStyle.SetTitleW( 1 - gPad.GetLeftMargin() - gPad.GetRightMargin() )
+
+def CreateCanvasAndFrame( runmin, runmax, tminS, tmaxS, maxnev, type, unit ):
+    # plots the graphs
+    title = "ATLAS integrated numnber of events in run range %i - %i" % (runmin, runmax)
+    c = TCanvas( "c", title, 0, 0, 800, 550 )
+    c.GetPad(0).SetRightMargin(0.08)
+    c.GetPad(0).SetLeftMargin(0.10)
+    c.GetPad(0).SetTopMargin(0.07)
+    htitle = "Events recorded by ATLAS between %s and %s" % (time.strftime('%b %d',tminS),
+                                                             time.strftime('%b %d, %Y',tmaxS))
+
+    frame = TH1F( "frame", htitle.strip(), 10000, runmin, runmax )
+
+    SetFrameStyle( frame )
+    TGaxis.SetMaxDigits(6)
+    frame.GetYaxis().SetTitleOffset( 1.0 )
+    frame.SetMinimum( 0 )
+    frame.SetMaximum( maxnev*1.1 )
+    frame.SetYTitle( "Number of events (in %s)" % unit )
+    frame.SetXTitle( "Run number"  )
+    frame.Draw()
+
+    # legend for plot
+    dx = 0.04
+    dy = -0.05
+    legend = TLegend( c.GetLeftMargin() + dx, 1 - c.GetTopMargin() + dy,
+                      c.GetLeftMargin() + 0.48 + dx, 1 - c.GetTopMargin() - 0.38 + dy)
+    legend.SetFillStyle( 1001 )
+    legend.SetFillColor( c_VLightGray )
+    legend.SetBorderSize(1)
+    legend.SetMargin( 0.2 )
+    legend.SetTextColor( c_VDarkGray )
+    legend.Draw("same")
+
+    return c, frame, legend
+
+def MakeRootPlots( rootstreamdic, datapath ):
+
+    # suppress output
+    gROOT.SetBatch( 1 )
+
+    # common style, and a few corrections
+    SetStyle()
+
+    colours = [ c_NovelRed, 4, c_DarkOrange, c_DarkGreen, c_Violet, c_LightBlue, 3, c_VDarkYellow, c_Gray,
+                1, 2, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 ]
+    
+    # run ranges (note: reverse order!)
+    run_and_time = sorted(rootstreamdic[DataKey('Start and endtime')])
+    runs = [x[0] for x in run_and_time]
+    runmin = min(runs)
+    runmax = max(runs)
+
+    tmin = min([x[1][0] for x in run_and_time])
+    tmax = max([x[1][1] for x in run_and_time])
+
+    # time structs
+    tminS  = time.gmtime(tmin)
+    tmaxS  = time.gmtime(tmax)    
+
+    # html references
+    htmlstr = []
+    
+    # create graphs
+    graphs = []
+    sortdic = {}
+    maxnev = { 'all_':-1, 'debug_':-1,'calibration_':-1 }
+    for key, content in rootstreamdic.iteritems():
+        if type(key)==DataKey: key = key.ResultKey
+        if not 'Start and endtime' in key:
+            graphs.append( TGraph( len(content) ) )
+            graphs[-1].SetName( key.strip().replace(' ','_') )
+            graphs[-1].SetTitle( key.strip() )
+            cumulsum = 0
+            for i in range(len(content)):
+                j = len(content)-1-i # reverse order
+                scale = 1.e6
+                if 'debug_' in key: scale = 1.e3
+                cumulsum += content[j][1]/scale
+                graphs[-1].SetPoint( i, content[j][0], cumulsum ) # number of events in million
+            for stype in maxnev.keys():
+                if stype in key:
+                    if cumulsum > maxnev[stype]: maxnev[stype] = cumulsum 
+            if not 'debug_' in key and cumulsum > maxnev['all_']: maxnev['all_'] = cumulsum
+            sortdic[len(graphs)-1] = cumulsum
+
+    # sort dictionary into list
+    sortedlist = sorted(sortdic, key=sortdic.__getitem__, reverse=True)
+
+    # individual physics streams
+    ic = 0
+    for i in sortedlist:
+        g = graphs[i]
+        name = g.GetTitle()
+        if 'physics_' in name or 'express_' in name:
+            x = Double(0)
+            y = Double(0)
+            g.GetPoint( g.GetN()-1, x, y )
+            c, frame, legend = CreateCanvasAndFrame( runmin, runmax, tminS, tmaxS, y*1.1, '', 'million' )
+            legend.SetX2( legend.GetX2() - 0.2 );
+            legend.SetY1( legend.GetY2() - 0.05 );
+            DrawGraph( g, colours[ic], 2, 1, legend, name.replace('physics_','').replace('express_','').replace('express','Express'), True, 'M', TText() )
+            ic += 1
+
+            # redraw axes and update
+            frame.Draw("sameaxis")   
+            c.Update()
+            
+            # make plot
+            fname = '%s/atlrunquery_%s.png' % (datapath, name)
+            c.Print( fname )
+            del frame
+            
+            # reference in html
+            htmlstr.append( MakeHtml( ['Events in streams %s versus run' % name], [fname], True, 60, 5 ) )
+
+    # physics streams only ------------------------------------------------------------
+    c, frame, legend = CreateCanvasAndFrame( runmin, runmax, tminS, tmaxS, maxnev['all_'], '', 'million' )
+    ic = 0
+    for i in sortedlist:
+        g = graphs[i]
+        name = g.GetTitle()
+        if '#Events (streamed)' in name: 
+            DrawGraph( g, c_NovelBlue, 2, 2, legend, "Total number of streamed events" )
+        elif '#Events' == name:            
+            DrawGraph( g, c_NovelBlue, 5, 1, legend, "Total number of triggered events (excl. calib)", True, 'M', TText() )
+        elif 'physics_' in name or 'express_' in name:
+            DrawGraph( g, colours[ic], 2, 1, legend, name.replace('physics_','').replace('express_','').replace('express','Express') )
+            ic += 1
+
+    # redraw axes and update canvas
+    frame.Draw("sameaxis")   
+    c.Update()
+
+    # make plot
+    fname = '%s/atlrunquery_physicsstreams.png' % datapath
+    c.Print( fname )
+    del frame
+
+    # reference in html
+    htmlstr.append( MakeHtml( ['Events in physics streams versus run'], [fname], True, 60, 5 ) )
+
+    # the other types can be 
+    #             stream_type  nice text  unit
+    plottypes = { 'debug_' :       [ 'Debug',        'thousand', 'k' ],
+                  'calibration_' : [ 'Calibration', 'million',  'M' ] }
+
+    # debug and calibration streams ----------------------------------------------------
+    for key, cprop in plottypes.iteritems():
+                 
+        c, frame, legend = CreateCanvasAndFrame( runmin, runmax, tminS, tmaxS, maxnev[key], cprop[0], cprop[1] )
+        legend.SetY1( legend.GetY1() + 0.15 );
+        legend.SetX2( legend.GetX2() - 0.15 );
+        ic = 0
+        for i in sortedlist:
+            g = graphs[i]
+            name = g.GetTitle()
+            if key in name:
+                DrawGraph( g, colours[ic], 2, 1, legend, name, ic == 0, cprop[2], TText() )            
+                ic += 1
+
+        # redraw axes and update canvas
+        frame.Draw("sameaxis")   
+        c.Update()
+
+        # make plot
+        fname = '%s/atlrunquery_%sstreams.png' % (datapath, cprop[0].lower())
+        c.Print( fname )
+        del frame
+        
+        # reference in html
+        htmlstr.append( MakeHtml( ['Events in %s streams versus run' % cprop[0].lower()], [fname], True, 60, 5 ) )
+
+    # html code ---------------------------------------------------------------------------
+    retstr    = '<table width="900" style="margin-left: 14px; background-color: #f0f0f0; border: 2px white solid; border-collapse: collapse;"><tr>'
+    for i,s in enumerate(htmlstr):
+        retstr += '<td style="padding: 4px">%s</td>' % s
+        if (i+1)%5 == 0: retstr += '</tr><tr>'
+    retstr += '</tr></table>'
+
+    return retstr
+            
+def MakeSummaryHtml( dic, dicsum, datapath ):
+    # run and time ranges
+    runs   = dic[DataKey('Run')]
+    nruns  = len(runs)
+    times  = dic[DataKey('Start and endtime')]
+
+    starttime = float(times[-1].partition(',')[0])
+    endtime   = float(times[0].partition(',')[2])
+
+    s = '<table style="color: #777777; font-size: 85%; margin-left: 14px" cellpadding="0" cellspacing="3">\n'
+    # runs in reverse order
+    s += '<tr><td><i>Number of runs selected:</i></td><td>&nbsp;&nbsp;%g</td><td></td></tr>\n' % (len(runs))
+    s += '<tr><td><i>First run selected:</i></td><td>&nbsp;&nbsp;%s</td><td>&nbsp;&nbsp;(%s)</td></tr>\n' % (runs[-1], time.strftime("%a %b %d, %Y, %X",time.gmtime(starttime)))
+    s += '<tr><td><i>Last run selected:</i></td><td>&nbsp;&nbsp;%s</td><td>&nbsp;&nbsp;(%s)</td></tr>\n'  % (runs[0], time.strftime("%a %b %d, %Y, %X",time.gmtime(endtime)))
+    s += '</table>\n'
+    
+    # --------------------------------------------------------------------------------------
+    # run summary table    
+    s += '<p></p>\n'
+    s += '<table style="margin-left: 14px">\n'
+    s += '<tr><td><b>Run / Event Summary</b></td></tr>\n'
+    s += '</table>\n'
+
+    table  = []
+    # format     Title in dico    Title in table     unit   format        which columns in table to exclude
+    keys   = [ [ 'Duration',           'Run duration',    ' h',  '%.2f',       [] ],
+               [ '#Events',            '#Events (excl.)', '',    'pretty-int', [] ],
+               [ '#Events (streamed)', '#Events (incl.)', '',    'pretty-int', [] ],
+               [ 'STR:physics_*',      'Event size <font size="-2">(RAW)</font>',' MB', '%.2f', [0] ]     # with wildcard
+               ]
+    for k in keys:
+        v = []
+        for dk, c in dic.iteritems():
+            # exact check?
+            Found = False
+            if ('*' in k[0] and k[0].replace('*','') in dk.ResultKey) or (not '*' in k[0] and k[0] == dk.ResultKey):            
+                for x in c:
+                    try:
+                        v.append( DecodeStr( x, k[0] ) )
+                    except ValueError: # if n.a.
+                        pass
+        # sanity check
+
+        ### what if just n.a. in one column
+        ###if len(v) == 0:
+        ###    print 'Big troubles... in function "AtlRunQuerySummary::MakeSummaryHtml": did not find key "%s" in dictionary' % k[0]
+        ###    sys.exit(1)
+        table.append( ComputeStats( v ) )
+                
+    s += MakeSummaryTableHtml( '', ['Total', 'Average', 'Min', 'Max'], keys, table, 500 )
+
+    # --------------------------------------------------------------------------------------
+    # stream summary table    
+    s += '<p></p>\n'
+    s += '<table style="margin-left: 14px">\n'
+    s += '<tr><td><b>Streams / Events Summary</b> <font size=-2> [ Straight averages given, not weighted by number of events in run ]</font></td></tr>\n'
+    s += '</table>\n'
+
+    streamdic     = {}    
+    streamsizedic = {}    
+    streamfracdic = {}    
+    streamratedic = {}    
+    rootstreamdic = {}    
+    v = []    
+    for dk, c in dic.iteritems():
+        # for root
+        if '#Events' in dk.ResultKey:
+            rootstreamdic[dk] = []
+            for run,dataentries in zip(runs,c):
+            #for i in range(len(c)):
+                run = int(run)
+                data = dataentries[0].value  # for events and time info there is only one entry in the list per run
+                try:
+                    rootstreamdic[dk].append([run, int(data)])
+                except ValueError:
+                    if data != 'n.a.': rootstreamdic[dk].append([run, data])
+            
+        if 'Start and endtime' in dk.ResultKey:
+            rootstreamdic[dk] = []
+            for run,data in zip(runs,c):
+                if data != 'n.a.': rootstreamdic[dk].append([int(run), map(float,data.split(','))])
+            
+        # collect streams
+        if 'STR:' in dk.ResultKey:
+            # loop over runs
+            sname = dk.ResultKey.replace('STR:','')
+            streamdic[sname]     = []
+            streamsizedic[sname] = 0
+            streamfracdic[sname] = []
+            streamratedic[sname] = []
+            rootstreamdic[sname] = []
+            #for i in range(len(c)):
+            for run,t,dataentries in zip(runs,times,c):
+                run = int(run)
+                data = dataentries[0].value  # for stream data there is only one entry in the list per run
+                if not isinstance(data, str): # not 'n.a.'
+                    streamdic[sname].append(data[0])
+                    streamfracdic[sname].append(data[0])
+                    tmin_   = float(t.partition(',')[0])
+                    tmax_   = float(t.partition(',')[2])
+                    deltat = tmax_ - tmin_
+                    if (deltat > 0): streamratedic[sname].append(data[0]/deltat)
+                    else           : streamratedic[sname].append(-1)
+                    streamsizedic[sname] += data[1]
+                    try:
+                        rootstreamdic[sname].append([run, data[0]])
+                    except ValueError:
+                        pass
+                else: streamfracdic[sname].append('na')
+
+    # sort (physics, debug, calibration)
+    streamtypes = ['physics', 'express', 'debug', 'calibration']
+    sortedstreams = []
+    for stype in streamtypes:
+        keys = {}
+        for key, c in streamdic.iteritems():
+            if stype in key: keys[key] = sum(c)    
+        sortedstreams += sorted(keys, key=keys.__getitem__, reverse=True)
+    
+    # fill table
+    keys = []
+    table  = []
+    newstreamfracdic = {}
+    for stream in sortedstreams:        
+        stats = ComputeStats( streamdic[stream] )
+        table.append( stats[0:4] )
+
+        # compute event fractions (not for calibration streams)
+        if not 'calibration_' in stream: 
+            v = []
+            for i, evrun in enumerate(streamfracdic[stream]):
+                if evrun != 'na':
+                    evsum = float(0)
+                    for stream2 in sortedstreams:
+                        if not 'calibration_' in stream2:
+                            if streamfracdic[stream2][i] != 'na': evsum += streamfracdic[stream2][i]
+                    if evsum > 0: v.append( float(evrun)/evsum*100 ) # fraction in percent
+
+            table[-1] += ['%.3g' % ComputeStats( v )[1]]
+        else:
+            table[-1] += ['&minus']
+
+        # average rate
+        table[-1] += ['%.3g' % ComputeStats( streamratedic[stream] )[1]]
+
+        # put here #runs where the stream was produced
+        table[-1] += [stats[4]]
+
+        # event sizes
+        if table[-1][0] > 0: table[-1] += [filesize(streamsizedic[stream]),
+                                           filesize(float(streamsizedic[stream])/table[-1][0])] 
+        else:                table[-1] += [filesize(streamsizedic[stream]),'&minus']
+
+        prettystr = stream
+        if 'debug' in stream: prettystr = '<font color="#C11B17">' + stream + '</font>'
+        # format     Title in dico    Title in table     unit   format        which columns in table to exclude
+        keys.append( [stream,         prettystr,         '',    'pretty-int', []] )
+
+    s += MakeSummaryTableHtml( 'Stream',
+                               ['Total', 'Average', 'Min', 'Max',
+                                'Average<br>fraction&nbsp;(%)',
+                                'Average<br>rate&nbsp;(Hz)',
+                                '#Runs<br><font size="-2">(out&nbsp;of&nbsp;%i)</font>' % nruns,
+                                'Total&nbsp;file<br>size&nbsp;<font size="-2">(RAW)</font>',
+                                'Average&nbsp;event<br>size&nbsp;<font size="-2">(RAW)</font>'], keys, table, 900 )
+
+    # make integrated events plots
+    htmlstr = MakeRootPlots( rootstreamdic, datapath )
+    s += htmlstr    
+
+    return s
+
+    # DQ summary not operational anymore since defects ?
+    
+    # --------------------------------------------------------------------------------------
+    # DQ summary table
+    s += '<p></p>\n'
+    s += '<table style="margin-left: 14px">\n'
+    s += '<tr><td><b>Data Quality Summary - SHIFTOFL (number of runs)</b> <font size=-2> [ No number signifies zero. Move mouse over number to see corresponding runs. ]</font></td></tr>\n'
+    s += '</table>\n'
+
+    dqflags      = ['G','Y','R','B','U','n.a.']
+    dqflagsNames = ['Green', 'Yellow', 'Red', 'Black', 'Unknown', 'Not&nbsp;assigned&nbsp;']
+    dqitems      = DQChannels()
+
+    # DQ flags are grouped together according to their channel numbers
+    # all groups with equal first two digits belong together
+
+    UseGroups = False
+    if UseGroups:
+        ndq = {}
+        for chan, dqgroup in DQGroupDict.items():
+            ndq[chan] = {}
+            for dqflag in dqflags:
+                ndq[chan][dqflag] = 0
+
+        for chan, dqchan in dqitems:
+            if dic.has_key( dqchan ):
+                grchan = int(chan/10)*10
+                if grchan == 430: grchan = 420 # 'ad hoc' correction for TAU trigger
+                for dqflag in dic[dqchan]:
+                    ndq[grchan][dqflag] += 1
+
+        colstr = []
+        colchans = []
+        for chan, dqgroup in DQChannelDict.items():
+            colstr.append( dqgroup )
+            colchans.append( chan )
+
+    # here per channel
+    colstr = []
+    colchans = []
+    ndq = {}
+    for chan, dqchan in dqitems:
+        dqchan = "SHIFTOFL_%s" % (dqchan)
+        colstr.append( dqchan )
+        colchans.append( chan )
+
+        ndq[chan] = {}
+        for dqflag in dqflags:
+            ndq[chan][dqflag] = [0, []]
+
+        if dic.has_key( dqchan ):
+            for i, dqflag in enumerate(dic[dqchan]):
+                ndq[chan][dqflag][0] += 1
+                ndq[chan][dqflag][1].append(runs[i])
+
+
+    # create summary table
+    # break table after 'nc' entries
+    nc = 15
+    colstr_ = []
+    colchans_ = []
+    for i in range(len(colchans)):
+        if (i+1)%nc == 0:
+            labeloffset = i # required to avoid double-labels for tool-tips
+            colstr_ = []
+            colchans_ = []            
+        else:
+            colstr_.append(colstr[i])
+            colchans_.append(colchans[i])
+
+    # groups
+    labeloffset = 0
+    for dqgroup, content in DQSuperGroupsDict.iteritems():
+        colstr_   = []
+        colchans_ = []
+        title     = content[0]
+        for dqchan in content[1]:                        
+            colstr_.append(dqchan)
+            colchans_.append(DQChannelDict[dqchan])
+        s += MakeDQSummaryTableHtml( '', title, colstr_, colchans_, dqflags, dqflagsNames, ndq, nruns, labeloffset )
+        labeloffset += 1 # required to avoid double-labels for tool-tips
+        s += '<p></p>'            
+
+    # return full page string
+    return s
diff --git a/Database/CoolRunQuery/python/html/__init__.py b/Database/CoolRunQuery/python/html/__init__.py
new file mode 100644
index 00000000000..74583d364ec
--- /dev/null
+++ b/Database/CoolRunQuery/python/html/__init__.py
@@ -0,0 +1,2 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
diff --git a/Database/CoolRunQuery/python/output/AtlRunQueryRoot.py b/Database/CoolRunQuery/python/output/AtlRunQueryRoot.py
new file mode 100644
index 00000000000..e1e8058e6dc
--- /dev/null
+++ b/Database/CoolRunQuery/python/output/AtlRunQueryRoot.py
@@ -0,0 +1,975 @@
+#!/bin/env python
+
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+#
+# ----------------------------------------------------------------
+# Script : AtlRunQueryRoot.py
+# Project: AtlRunQuery
+# Purpose: ROOT interactions
+# Authors: Andreas Hoecker (CERN), Joerg Stelzer (DESY)
+# Created: Dec 13, 2008
+# ----------------------------------------------------------------
+#
+# ---------------------------------------------------------------------------------------------------
+# ROOT TTree making and plotting
+# ---------------------------------------------------------------------------------------------------
+
+import datetime, sys, os
+from array import array
+from CoolRunQuery.utils.AtlRunQueryUtils  import importroot
+importroot() # needed before any root import to switch to batch mode
+from ROOT import TFile, TTree, gDirectory, TCanvas, gPad, TGraph, TColor, TStyle, TGaxis, gROOT, gStyle, TText, TH1F, TLegend, TDatime, TF1
+
+# ---------------------------------------------------------------------------------------------------
+# Creation of ROOT output file
+# ---------------------------------------------------------------------------------------------------
+
+# general style
+def SetStyle( whiteCanvas = False ):
+
+    # colors
+    c_Canvas = TColor.GetColor( "#f0f0f0" ) # TColor.GetColor( "#e9e6da" )
+    if whiteCanvas: c_Canvas = TColor.GetColor( 10 )
+    c_FrameFill      = 10 
+    c_TitleBox       = TColor.GetColor( "#dae1e6" )
+    c_SignalLine     = TColor.GetColor( "#0000ee" )
+    c_SignalFill     = TColor.GetColor( "#7d99d1" )
+    c_BackgroundLine = TColor.GetColor( "#ff0000" )
+    c_BackgroundFill = TColor.GetColor( "#ff0000" )
+
+    myStyle = TStyle( gROOT.GetStyle("Plain") )
+    myStyle.SetName("myStyle")
+    			
+    myStyle.SetLineStyleString( 5, "[52 12]" )
+    myStyle.SetLineStyleString( 6, "[22 12]" )
+    myStyle.SetLineStyleString( 7, "[22 10 7 10]" )
+
+    # pretty colors
+    myStyle.SetPalette(1)
+
+    # use plain black on white colors
+    myStyle.SetFrameBorderMode(0)
+    myStyle.SetCanvasBorderMode(0)
+    myStyle.SetPadBorderMode(0)
+    myStyle.SetPadColor(0)
+    myStyle.SetFillStyle(0)
+
+    myStyle.SetLegendBorderSize(0)
+
+    myStyle.SetTitleFillColor( c_TitleBox )
+    myStyle.SetFrameFillColor( c_FrameFill )
+    myStyle.SetCanvasColor( c_Canvas )
+
+    # set the paper & margin sizes
+    myStyle.SetPaperSize(20,26)
+    myStyle.SetPadTopMargin(0.11)
+    myStyle.SetPadRightMargin(0.05)
+    myStyle.SetPadBottomMargin(0.11)
+    myStyle.SetPadLeftMargin(0.12)
+    
+    # use bold lines and markers
+    myStyle.SetMarkerStyle(21)
+    myStyle.SetMarkerSize(0.3)
+    myStyle.SetHistLineWidth(2)
+    myStyle.SetLineStyleString(2,"[12 12]") # postscript dashes
+    
+    # do not display any of the standard histogram decorations
+    myStyle.SetOptTitle(1)
+    myStyle.SetTitleH(0.052)
+
+    myStyle.SetOptStat(0)
+    myStyle.SetOptFit(0)
+    
+    # put tick marks on top and RHS of plots
+    myStyle.SetPadTickX(1)
+    myStyle.SetPadTickY(1)
+
+    # use this style
+    gROOT.GetListOfStyles().Add(myStyle)
+    gROOT.SetStyle("myStyle")
+
+def SaveGraphsToFile( filename, varnames, xvecs, yvecs, addparamName = None, addparamVal = None ):
+    f = TFile.Open( filename, 'RECREATE' )
+    if len(xvecs) != len(yvecs) or len(varnames) != len(xvecs):
+        print 'ERROR: wrong dimensions in "AtlRunQueryRoot.SaveGraphsToFile"'
+        return
+    for ik in range(len(xvecs)):
+        xv = xvecs[ik]
+        yv = yvecs[ik]
+        g = TGraph( len(xv) )
+        g.SetName ( "graph%i" % (ik+1) )
+        g.SetTitle( varnames[ik] )
+        for i in range(len(xv)):
+            g.SetPoint( i, xv[i], yv[i] )
+        g.Write()
+
+    # save additional parameter
+    if addparamName != None:
+        addparam = TF1( addparamName, "[0]", 0, 1 )
+        addparam.SetParameter( 0, addparamVal )
+        addparam.Write()
+        
+    f.Close()
+
+def MakePlots( tree, datapath ):
+
+    # batch mode -> no windows
+
+    gROOT.SetBatch( 1 )
+    if tree == None:
+        print 'ERROR: input tree is None'
+        return
+
+    # style --------------------------------------------
+    steelBlue  = TColor.GetColor( "#4863A0" )
+    slateBlue  = TColor.GetColor( "#574EC7" )
+    dogerBlue  = TColor.GetColor( "#1569C7" )
+    dogerBlue3 = TColor.GetColor( "#1569C7" )
+    graphCol  = dogerBlue
+    markerCol = dogerBlue3
+
+    SetStyle()
+    # --------------------------------------------------
+
+    # reference 
+    reflist = [ 'Run' ]
+
+    # types that can be plotted
+    validtypes = [ 'int', 'float', 'double', 'short', 'long' ]
+
+    # get list of leaves for plotting
+    leafList = tree.GetListOfLeaves()
+    varlist = []
+    
+    for leaf in leafList:
+        if leaf != None:
+            # check type, only values are plotted
+            typename = leaf.GetTypeName().lower()
+            valid = False
+            for vt in validtypes:
+                if vt in typename: valid = True
+            if valid: varlist.append( leaf.GetName() )
+
+    # plot
+    TGaxis.SetMaxDigits(6)
+    c = []
+    g = []
+    fnames = []
+    hnames = []
+    for ref in reflist:
+        # sanity check
+        if not ref in varlist:
+            print 'Big troubles in "MakePlots" --> reference variable "%s" not in TTree' % ref
+            sys.exit(1)
+
+        for var in varlist:
+            if var == ref: continue
+
+            vreg = var.replace('-','_')
+            rreg = ref.replace('-','_')
+            
+            hname = "h_%s_%s" % (ref, var)
+            c.append( TCanvas( "c_%s" % hname, "ATLAS Run Query: %s vs. %s" % (var, ref), 0, 0, 600, 500 ) )
+            tree.Draw( "%s:%s" % (vreg, rreg), "", "goff" )
+            g.append( TGraph( tree.GetSelectedRows(), tree.GetV2(), tree.GetV1() ) )
+            g[-1].SetTitle( "ATLAS Run Query: %s vs. %s" % (var, ref) )
+            g[-1].SetMarkerStyle( 20 )
+            g[-1].SetMarkerColor( markerCol )
+            g[-1].SetMarkerSize( 1.2 )
+            g[-1].SetLineWidth( 2 )
+            g[-1].SetLineColor( graphCol )
+            g[-1].GetXaxis().SetTitleOffset( 1.25 )
+            g[-1].GetYaxis().SetTitleOffset( 1.75 )
+            g[-1].GetXaxis().SetTitle( ref )
+            g[-1].GetYaxis().SetTitle( var )
+            g[-1].GetXaxis().SetLabelOffset( 0.012 )
+            g[-1].GetYaxis().SetLabelOffset( 0.012 )
+            g[-1].GetXaxis().SetNdivisions( 506 )
+
+            # some global style settings
+            scale = 1
+            gPad.SetTicks()
+            gPad.SetLeftMargin  ( 0.138*scale )
+            gPad.SetRightMargin ( 0.050*scale )
+            gPad.SetBottomMargin( 0.120*scale  )
+            
+            g[-1].Draw("alp")
+                      
+            c[-1].Update()
+            fnames.append( '%s/atlrunquery_%s.png' % (datapath, hname) )
+            hnames.append( '%s versus %s' % (var, ref ) )            
+            c[-1].Print( fnames[-1] )
+
+    return hnames, fnames
+    
+# ---------------------------------------------------------------------------------------------------
+# Creation of ROOT output file
+# ---------------------------------------------------------------------------------------------------
+
+def makeLBPlotSummaryForLHC( xvec, xvecStb, yvec, runNr, datapath, printText = '' ):
+
+    # sanity check
+    if not xvec or len(yvec)==0 or not yvec[0]: return "None"
+
+    ylegend = ['Intensity Beam-1', 'Intensity Beam-2', 'Beam energy', 'Online inst. luminosity' ]
+
+    SetStyle()    
+    name  = 'LHCsummary_vs_lb_run_%i' % (runNr)
+    #print "Attempt printing", name
+    title = 'LHC summary vs. LB for run_%i' % (runNr)
+    szescale = 1.2
+    c = TCanvas( name, title, 0, 0, int(530*szescale), int(400*szescale) )
+    c.GetPad(0).SetTopMargin(0.13)
+    c.GetPad(0).SetLeftMargin(0.09)
+    c.GetPad(0).SetRightMargin(1.3)
+    # c.GetPad(0).SetGrid()
+    x1 = xvec[0]
+    x2 = xvec[-1]
+
+    h  = TH1F( name, title, x2 - x1 + 1, x1, x2 + 1 ) # for stable beams
+    hg = []
+    for iy in range(len(yvec)):
+        hg.append( TH1F( name + 'g%i' % iy, title, x2 - x1 + 1, x1, x2 + 1 ) )
+    h.GetXaxis().SetTitle( 'Luminosity block number' )
+    h.GetXaxis().SetTitleOffset( 1.3 )
+    h.GetYaxis().SetTitle( 'Beam intensity (10^{11} protons)' )
+    h.GetYaxis().SetTitleOffset( 1.0 )
+    h.SetTitle( title )    
+
+    for i in range(len(xvec)):
+        for iy,y in enumerate(yvec):
+            hg[iy].SetBinContent( xvec[i], y[i] )
+    
+    # first draw histogram        
+    ymax = max(hg[0].GetMaximum(),hg[1].GetMaximum())
+    y2 = ymax*1.3
+    if y2 <= 0: y2 = 1
+    y1 = 0
+    h.SetMinimum(0)
+    h.SetMaximum(y2) 
+    h.Draw("0")
+    gPad.SetTicks(1, 0)
+
+    # beam energy (rescale)
+    ebcol = TColor.GetColor( "#306754" )
+    heb = hg[2]
+    heb.Scale( 1./1000.0 ) # in TeV
+    if heb.GetMaximum()==0:  heb.SetMaximum(1)
+    ebmax = heb.GetMaximum()*1.3
+
+    # one more sanity check
+    if ebmax == 0:
+        return "None"
+    
+    heb.SetLineColor( ebcol )
+    heb.SetLineWidth( 1 )
+    scale = h.GetMaximum()/ebmax
+    # heb.SetFillColor( TColor.GetColor("#CCFB5D") )
+    heb.SetFillColor( TColor.GetColor("#C3FDB8") )
+    heb.Scale( scale )    
+    heb.Draw("same")
+
+    if xvecStb:
+        for i in range(len(xvec)):
+            if xvec[i] in xvecStb: h.SetBinContent( xvec[i], yvec[2][i]*scale/1000.0 ) # draw for beam energy (in TeV)
+        h.SetFillColor( TColor.GetColor( "#63bD58" ) )
+        h.SetFillStyle( 3007 )
+        h.SetLineColor( TColor.GetColor( "#C3FDB8" ) )
+        h.SetLineWidth( 1 )
+        h.SetLineStyle( 1 )
+        h.Draw("same")
+        hebp = TH1F( heb )
+        hebp.SetFillColor( 0 )
+        hebp.Draw("same")
+        
+
+    colorList = [TColor.GetColor( "#255EC7" ), TColor.GetColor( "#E42217" ), TColor.GetColor( "#2212EE" ), TColor.GetColor( "#22EE33" )]
+
+    for ig in range(2):
+        col = 1
+        if ig < len(colorList): hg[ig].SetLineColor( colorList[ig] )
+        hg[ig].SetLineWidth( 2 )
+        hg[ig].Draw("same")
+
+    # logo
+    now = str(datetime.datetime.today())
+    t = TText( h.GetXaxis().GetXmax(), y2*1.01, 'ATLAS Run Query %s' % now[:now.find('.')] )
+    t.SetTextAlign( 31 )
+    t.SetTextSize( 0.035 )
+    t.SetTextSize( 0.030 )
+    t.SetTextColor( TColor.GetColor( "#888888" ) )
+    t.Draw()
+
+    drawLegend = False
+    dx = 1 - c.GetRightMargin() - c.GetLeftMargin() - 0.05
+    dy = 0.1
+    legend = TLegend( 1 - c.GetRightMargin() - dx, 1 - c.GetTopMargin() - dy - 0.035,
+                      1 - c.GetRightMargin(), 1 - c.GetTopMargin() - 0.035)
+    # legend.SetFillStyle( 1001 )
+    # legend.SetFillColor( TColor.GetColor( "#FFFFFF" ) )
+    legend.SetNColumns(2)
+    legend.SetBorderSize( 1 )
+    legend.SetMargin( 0.15 )
+    legend.SetLineColor( 0 )
+    legend.SetTextColor( 1 )
+    for ig,hgg in enumerate(hg):
+        if ylegend[ig]:
+            opt = "l"
+            if ig == 2: opt = "FL"
+            legend.AddEntry( hgg, ylegend[ig], opt )
+            drawLegend = True
+        
+    if xvecStb:
+        legend.AddEntry( h,  "LBs with stable beams","F" )
+        drawLegend = True
+    if drawLegend: legend.Draw("same")
+
+    # redraw axis
+    h.Draw( "sameaxis" )
+    
+    # draw beam energy axis on the right side
+    if h.GetMaximum() > 0:
+        axis = TGaxis( x2 + 1, 0, x2 + 1, h.GetMaximum(), 0, ebmax, 510, "+L" )
+        axis.SetLabelOffset( 0.007 )
+        axis.SetTitleOffset( 1.2 )
+        axis.SetTitleSize( h.GetXaxis().GetTitleSize() )
+        axis.SetLabelSize( 0.04 )
+        axis.SetLineColor( ebcol )
+        axis.SetTitleColor( ebcol )
+        axis.SetLabelColor( ebcol )
+        axis.SetTitle( "Beam energy (TeV)" )
+        axis.Draw()
+
+    c.Update()
+    fnames = '%s/atlrunquery_%s.png' % (datapath, name) 
+    c.Print( fnames )
+    #print "Printing",fnames
+    
+    return fnames
+
+def makeTimePlotList( xvec, xveclb, yvec, toffset, dt, ymin, ymax,
+                      xtit, ytit, ylegend, name, title, datapath, printText = '' ):
+
+    # sanity check
+    if not xvec or len(yvec)==0 or not yvec[0]: return "None"
+
+    SetStyle()
+
+    gStyle.SetPadTickX(0)
+    gStyle.SetPadTickY(1)
+    
+    c = TCanvas( name, title, 0, 0, 530, 430 )
+    c.GetPad(0).SetTopMargin(0.22)
+    c.GetPad(0).SetGrid()
+
+    # create the graphs
+    graphs = []
+    y1 = 1e30
+    y2 = -1e30
+    for ig in range(len(yvec)):
+        n = len(yvec[ig])
+        g = TGraph( n )
+        for i in range(n):
+            g.SetPoint( i, xvec[ig][i], yvec[ig][i] )        
+            if ymin == ymax:
+                y1 = min(y1,yvec[ig][i])
+                y2 = max(y2,yvec[ig][i])
+        graphs.append( g )
+
+    if ymin != ymax:
+        y1 = ymin
+        y2 = ymax
+
+    # create the frame
+    frame  = TH1F( name, title, int(dt/2), 0, dt )
+
+    # x-axis is time format
+    frame.GetXaxis().SetTimeDisplay(1)   
+    # use rather default: frame.GetXaxis().SetTimeFormat("%d-%Hh")
+
+    # =================================
+    # toffset += 7*3600 # BUG in ROOT ???
+    # =================================
+
+    frame.GetXaxis().SetTimeOffset(long(toffset), "gmt") # assumes time given was local
+
+    frame.GetXaxis().SetTitle( xtit )
+    frame.GetXaxis().SetTitleOffset( 1.3 )
+    frame.GetYaxis().SetTitle( ytit )
+    frame.GetYaxis().SetTitleOffset( 1.4 )
+    frame.SetTitle( title )    
+    frame.SetMinimum(y1 - (y2-y1)*0.1)
+    frame.SetMaximum(y2 + (y2-y1)*0.3)
+    frame.Draw()
+    
+    colorList = [TColor.GetColor( "#154EB7" ), TColor.GetColor( "#82CAFF" ), TColor.GetColor( "#D11B17" ), TColor.GetColor( "#FF9A4D" )]
+    styleList = [1,1,1,1]
+
+    for ig,g in enumerate(graphs):
+        if ig < len(colorList):
+            g.SetLineColor( colorList[ig] )
+            g.SetLineStyle( styleList[ig] )
+        g.SetLineWidth( 2 )
+        g.Draw("same")
+
+    if printText:
+        t = TText( frame.GetXaxis().GetXmax(), y2*1.01, printText )
+        t.SetTextAlign( 31 )
+        t.SetTextSize( 0.035 )
+        t.Draw()
+
+    # logo
+    now = str(datetime.datetime.today())
+    tlogo = TText( frame.GetXaxis().GetXmax()*1.025 - frame.GetXaxis().GetXmin()*0.025, y1,
+                   'ATLAS Run Query %s' % now[:now.find('.')] )
+    tlogo.SetTextSize( 0.030 )
+    tlogo.SetTextColor( TColor.GetColor( "#aaaaaa" ) )
+    tlogo.SetTextAngle(90)
+    tlogo.Draw()
+
+    # axis for LBs
+    lbcol = TColor.GetColor( "#777777" )
+    axis = TGaxis( frame.GetXaxis().GetXmin(), frame.GetMaximum(),
+                   frame.GetXaxis().GetXmax(), frame.GetMaximum(),
+                   1, len(xveclb), 505, "-L" )
+    axis.SetLabelOffset( frame.GetXaxis().GetLabelOffset() )
+    axis.SetTitleOffset( 1.4 )
+    axis.SetTitleSize( frame.GetXaxis().GetTitleSize() )
+    axis.SetLabelSize( frame.GetXaxis().GetLabelSize() )
+    axis.SetLineColor( lbcol )
+    axis.SetTitleColor( lbcol )
+    axis.SetLabelColor( lbcol )
+    axis.SetTitle( "Luminosity block number (indicative)" )
+    axis.Draw()
+
+    # legend
+    drawLegend = False
+    dx = 1 - c.GetRightMargin() - c.GetLeftMargin() - 0.05
+    dy = 0.1
+    legend = TLegend( 1 - c.GetRightMargin() - dx, 1 - c.GetTopMargin() - dy - 0.035,
+                      1 - c.GetRightMargin(), 1 - c.GetTopMargin() - 0.035)
+    # legend.SetFillStyle( 1001 )
+    # legend.SetFillColor( TColor.GetColor( "#FFFFFF" ) )
+    legend.SetNColumns(2)
+    legend.SetBorderSize( 1 )
+    legend.SetMargin( 0.15 )
+    legend.SetLineColor( 0 )
+    legend.SetTextColor( 1 )
+    legend.SetTextSize( 0.037 )
+    for ig,g in enumerate(graphs):
+        if ylegend[ig]:
+            h = g.GetHistogram()
+            h.SetLineColor( colorList[ig] )
+            h.SetLineStyle( styleList[ig] )
+            h.SetLineWidth( 2 )
+            legend.AddEntry( h, ylegend[ig], "l" )
+            drawLegend = True        
+    if drawLegend: legend.Draw("same")
+
+    # redraw axis
+    frame.Draw( "sameaxis" )
+
+    c.Update()
+    fnames = '%s/atlrunquery_%s.png' % (datapath, name) 
+    c.Print( fnames )
+    
+    return fnames
+
+
+def makeLBPlotList( xvec, xvecStb, yvec, xtitle, ytitle, ylegend, histname, histtitle, datapath, printText = '', ymin = None , ymax = None ): 
+
+    # sanity check
+    if not xvec or len(yvec)==0 or not yvec[0]: return "None"
+
+    SetStyle()    
+    c = TCanvas( histname, histtitle, 0, 0, 530, 400 )
+    c.GetPad(0).SetTopMargin(0.13)
+    c.GetPad(0).SetGrid()
+    x1 = xvec[0]
+    x2 = xvec[-1]
+
+    h  = TH1F( histname, histtitle, x2 - x1 + 1, x1, x2 + 1 ) # for stable beams
+    hg = []
+    for iy in range(len(yvec)):
+        hg.append( TH1F( histname + 'g%i' % iy, histtitle, x2 - x1 + 1, x1, x2 + 1 ) )
+    h.GetXaxis().SetTitle( xtitle )
+    h.GetXaxis().SetTitleOffset( 1.3 )
+    h.GetYaxis().SetTitle( ytitle )
+    h.GetYaxis().SetTitleOffset( 1.4 )
+    h.SetTitle( histtitle )
+
+
+    for i in range(len(xvec)):
+        for iy,y in enumerate(yvec):
+            if type(y[i]) == tuple:
+                val,valerr = y[i]
+            else:
+                val,valerr = y[i],0
+            hg[iy].SetBinContent( xvec[i], val )
+            hg[iy].SetBinError( xvec[i], valerr )
+        if xvec[i] in xvecStb: h.SetBinContent( xvec[i], yvec[0][i] )
+
+    if not ymax:
+        ymax = max([h.GetMaximum() for h in hg])
+        if ymax <= 0: ymax = 1
+        ymax *= 1.2
+
+    if not ymin:
+        ymin=0
+
+    # first draw histogram
+    h.SetMinimum(ymin)
+    h.SetMaximum(ymax)
+    if xvecStb:
+        h.SetFillColor( TColor.GetColor( "#98AFC7" ) )
+        h.SetLineColor( TColor.GetColor( "#788FA7" ) )
+        h.SetLineWidth( 1 )
+        h.SetLineStyle( 1 )
+        h.Draw("")
+    else:
+        h.Draw("0")
+
+    colorList = [TColor.GetColor( "#255EC7" ), TColor.GetColor( "#E42217" ), TColor.GetColor( "#2212EE" ), TColor.GetColor( "#22EE33" )]
+
+    for ig,hgg in enumerate(hg):
+        if ig < len(colorList): hgg.SetLineColor( colorList[ig] )
+        hgg.SetLineWidth( 2 )
+        hgg.Draw("e2same")
+
+    if printText:
+        t = TText( h.GetXaxis().GetXmax(), (ymax-ymin)*1.01 + ymin, printText )
+        t.SetTextAlign( 31 )
+        t.SetTextSize( 0.035 )
+        t.Draw()
+
+    # logo
+    now = str(datetime.datetime.today())
+    tlogo = TText( h.GetXaxis().GetXmax()*1.025, (ymax-ymin)*0.0+ymin, 'ATLAS Run Query %s' % now[:now.find('.')] )
+    tlogo.SetTextSize( 0.030 )
+    tlogo.SetTextColor( TColor.GetColor( "#888888" ) )
+    tlogo.SetTextAngle(90)
+    tlogo.Draw()
+
+    drawLegend = False
+    dx = 0.4
+    dy = 0.10 + 0.03*(len(hg)-1)
+    legend = TLegend( 1 - c.GetRightMargin() - dx, 1 - c.GetTopMargin() - dy - 0.015,
+                      1 - c.GetRightMargin(), 1 - c.GetTopMargin() - 0.015)
+    # legend.SetFillStyle( 1001 )
+    # legend.SetFillColor( TColor.GetColor( "#FFFFFF" ) )
+    legend.SetBorderSize( 1 )
+    legend.SetMargin( 0.15 )
+    legend.SetLineColor( 0 )
+    legend.SetTextColor( 1 )
+    for ig,hgg in enumerate(hg):
+        if ylegend[ig]:
+            legend.AddEntry( hgg, ylegend[ig], "l" )
+            drawLegend = True
+        
+    if xvecStb:
+        legend.AddEntry( h,  "LBs with stable beams","F" )
+        drawLegend = True
+    if drawLegend: legend.Draw("same")
+
+    # redraw axis
+    h.Draw( "sameaxis" )
+
+    c.Update()
+    fnames = '%s/atlrunquery_%s.png' % (datapath, histname) 
+    c.Print( fnames )
+    
+    return fnames
+
+
+def makeBSPlots( xvec, yvec, xtitle, ytitle, histname, histtitle, datapath, ymin, ymax, printText = '' ): 
+
+    # sanity check
+    if not xvec or len(yvec)==0 or not yvec[0]:
+        return None
+
+    ROOT = importroot()
+
+    SetStyle()
+    c = TCanvas( histname, histtitle, 0, 0, 530, 400 )
+    c.GetPad(0).SetTopMargin(0.13)
+    c.GetPad(0).SetGrid()
+    xlower = 1
+    xupper = sum(xvec)
+
+    bounds = [1]
+    for nlb in xvec: bounds += [bounds[-1]+nlb]
+
+    from array import array
+    h = TH1F( histname + 'g', histtitle, len(bounds)-1, array('f',bounds) )
+    h.GetXaxis().SetTitle( xtitle )
+    h.GetXaxis().SetTitleOffset( 1.3 )
+    h.GetYaxis().SetTitle( ytitle )
+    h.GetYaxis().SetTitleOffset( 1.4 )
+    h.SetTitle( histtitle )
+    h.SetMinimum(ymin)
+    h.SetMaximum(ymax)
+    h.SetFillColor( TColor.GetColor( "#56A5EC" ) )
+    for bin,y in enumerate(yvec):
+        val,valerr = y
+        h.SetBinContent( bin+1, val )
+        h.SetBinError  ( bin+1, valerr )
+    h.Draw("e2")
+
+    hc = h.Clone()
+    hc.SetLineColor( ROOT.kBlack )
+    hc.SetLineWidth(2)
+    hc.Draw("e0same")
+
+    if printText:
+        t = TText( h.GetXaxis().GetXmax(), (ymax-ymin)*1.01 + ymin, printText )
+        t.SetTextAlign( 31 )
+        t.SetTextSize( 0.035 )
+        t.Draw()
+
+    # logo
+    now = str(datetime.datetime.today())
+    tlogo = TText( h.GetXaxis().GetXmax()*1.025, (ymax-ymin)*0.0+ymin, 'ATLAS Run Query %s' % now[:now.find('.')] )
+    tlogo.SetTextSize( 0.030 )
+    tlogo.SetTextColor( TColor.GetColor( "#888888" ) )
+    tlogo.SetTextAngle(90)
+    tlogo.Draw()
+
+    c.Update()
+    fnames = '%s/atlrunquery_%s.png' % (datapath, histname) 
+    c.Print( fnames )
+    
+    return fnames
+
+
+def makeLBPlot( xvec, xvecStb, yvecScalar,
+                xtitle, ytitle, ylegendScalar,
+                histname, histtitle,
+                datapath, printText = '', ymin = None, ymax = None ):
+    yvec    = [yvecScalar]
+    ylegend = [ylegendScalar]
+    return makeLBPlotList( xvec, xvecStb, yvec, xtitle, ytitle, ylegend, histname, histtitle, datapath, printText, ymin, ymax )
+
+def InttypeTrf( tree, var, vlist, value, kcoord ):
+    # initialisation
+    if kcoord < 0:
+        vlist.append( array( 'i', [ 0 ] ) )
+        vreg = var.replace('-','_')
+        tree.Branch( vreg, vlist[-1], "%s/I" % vreg )
+        return
+    # fill tree
+    try:    vlist[kcoord][0] = int(value)
+    except: vlist[kcoord][0] = -1
+        
+def FloattypeTrf( tree, var, vlist, value, kcoord ):
+    # initialisation
+    if kcoord < 0:
+        vlist.append( array( 'f', [ 0 ] ) )
+        vreg = var.replace('-','_')
+        tree.Branch( vreg, vlist[-1], "%s/F" % vreg )
+        return
+    # fill tree
+    try:     vlist[kcoord][0] = float(value)
+    except:  vlist[kcoord][0] = -1
+
+def StringtypeTrf( tree, var, vlist, value, kcoord ):
+    # initialisation
+    if kcoord < 0:
+        vlist.append( array( 'c', 'ab\0' ) )
+        tree.Branch( var, vlist[-1], "%s/C" % var )
+        return
+    # fill tree
+    try:
+        vlist[kcoord] = array( 'c', value + '\0' ) 
+        tree.SetBranchAddress( var, vlist[kcoord] )
+    except:                    
+        vlist[kcoord] = array( 'c', 'unknown\0' ) 
+        tree.SetBranchAddress( var, vlist[kcoord] )
+
+def TimetypeTrf( tree, var, vlist, value, kcoord ):
+    return StringtypeTrf( tree, var, vlist, value, kcoord )
+
+def DurationtypeTrf( tree, var, vlist, value, kcoord ):
+    # original format: '[2d] 13h 15m 45s' --> transform in seconds
+    if kcoord >= 0:
+        try:
+            dur = value.split()
+            if len(dur) == 3:
+                h, m, s = dur
+                d = '0d'
+            elif len(dur) == 4:
+                d, h, m, s = dur
+            else:
+                print 'Unknown format in "DurationtypeTrf:"'
+                print dur
+                sys.exit(1)
+                
+            value = str( ( (int(d.replace('d','').strip())*24 + int(h.replace('h','').strip()))*60 + 
+                           int(m.replace('m','').strip()) )*60 + int(s.replace('s','').strip()) )
+        except:
+            print value
+            sys.exit(1)
+            value = 0
+    InttypeTrf( tree, var, vlist, value, kcoord )            
+
+
+def MakeHtml( hnames, fnames, uselarge = False, iconwidth = 70, nbreakline = 10 ):
+    windowstyle = 'openWindow'
+    if uselarge:
+        windowstyle = 'openLargeWindow'
+        iconwidth   = 120
+    s = ''
+    s += '<table><tr>'
+    for i in range(0,len(fnames)):
+        f = fnames[i]
+        h = hnames[i]
+        s += """<td valign="top"><a STYLE="text-decoration: none" href=" """
+        s += """javascript:%s('Plot','<!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;><html xmlns:my><head><title>%s</title><LINK href=&quot;atlas-runquery.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot;><body><table style=&quot;font-family: sans-serif; font-size: 85%%&quot;><tr><td valign=&quot;top&quot;>""" % (windowstyle,h)
+        s += """<img src=&quot;%s&quot;>""" % f
+        s += """<hr color=&quot;red&quot; size=1><font color=&quot;#777777&quot;><font size=&quot;-1&quot;><i><font size=&quot;-2&quot;>Created by AtlRunQuery on: %s</font></i></font></td></tr></table><script type=&quot;text/javascript&quot;></script></body></html>""" % str(datetime.datetime.now())
+        s += """')"""
+        s += """ "><img vspace=0 src="%s" title="Plot showing query result for %s" width="%i"></a><br><font size="-2">%s</font></td>""" % (f,h,iconwidth,h)
+        s += """<td>&nbsp;</td>"""
+        if (i+1)%nbreakline == 0: s += '</tr><tr>'
+
+    s += '</tr></table>'
+    return s
+
+def GetActions():
+    # define all actions (choose small letters)
+    # format: 'column header' 'include' 'type' '...'
+    actions = { "run":               ( True,  InttypeTrf      ),
+                "links":             ( False, StringtypeTrf   ),
+                "#lb":               ( True,  InttypeTrf      ),
+                "#events":           ( True,  InttypeTrf      ),
+                "smk":               ( True,  InttypeTrf      ),
+                "start and endtime": ( True,  TimetypeTrf     ),
+                "duration":          ( True,  DurationtypeTrf ),
+                "torcurrent":        ( True,  FloattypeTrf    ), 
+                "solcurrent":        ( True,  FloattypeTrf    ), 
+                "detector systems":  ( False, StringtypeTrf   ),
+                "stream":            ( True,  InttypeTrf      ),
+                "lumi":              ( True,  FloattypeTrf    ),
+                "other":             ( True,  StringtypeTrf   )
+                }
+    return actions
+
+def CreateRootFile( dic ):
+
+    from CoolRunQuery.selector.AtlRunQuerySelectorBase import DataKey
+
+    from CoolRunQuery.AtlRunQueryQueryConfig import QC
+    datapath = QC.datapath
+
+    actions = GetActions()
+
+    if not 'data' in os.listdir('.'):
+        os.mkdir('data')
+
+    f = open( '%s/dummyroot.txt' % datapath, 'w' )
+
+    froot = TFile( '%s/atlrunquery.root' % datapath,  'RECREATE' )
+
+    tree = TTree( 'RunQuery', 'ATLAS Run Query' )
+
+    varlist  = []
+
+    # create branches
+    r_1 = -1
+    keylist = []
+    for data_key in dic:
+
+        #print "DATA_KEY",type(data_key),data_key
+        f.write( 'key: %s \n' % (data_key.ResultKey))
+
+        # the actual variable name used in the tree
+        var = data_key.ResultKey.replace('#',' ').strip().replace(' ','_').replace('STR:','').replace('-','_').replace(':','_')
+
+        k = data_key.ResultKey.lower()
+        if data_key.Type==DataKey.STREAM:        k = 'stream'
+        elif 'olc_' == data_key.ResultKey[0:4]:  k = 'lumi'
+
+        # is key included in 'actions' dictionary ?
+        if not k in actions: k = 'other'
+
+        useit, function = actions[k]
+        if useit:
+            function( tree, var, varlist, -1, -1 )  # create branch
+            keylist.append( (data_key,var, function) )
+
+    # loop over runs
+    for ev in range(len(dic[DataKey('Run')])):
+
+        for k,(data_key,var,function) in enumerate(keylist):
+
+            val = dic[data_key][ev]
+            if data_key.Type==DataKey.STREAM:
+                val = val[0]
+
+            function( tree, var, varlist, val, k )
+            
+        tree.Fill()
+
+    # make plots ?
+    hnames, fnames = MakePlots( tree, datapath )
+    htmlstr        = MakeHtml( hnames, fnames )
+
+    f.close()
+    tree.Write()
+    froot.Close()
+
+    return froot.GetName(), htmlstr
+
+
+
+def makeRatePlot( v, lbduration, plottriggers, averrate, xtit, ytit, name, title, datapath, printText = '' ):
+
+    ## # pickle input
+    ## import pickle
+    ## store = (v, lbduration, plottriggers, averrate, xtit, ytit, name, title, datapath, printText)
+    ## 
+    ## pf = open( '%s/rates.pickle' % datapath, 'w' )
+    ## try: pickle.dump(store, pf)
+    ## except:
+    ##     print 'ERROR: could not pickle rates'
+    ##     sys.exit(1)
+    ## pf.close()
+    
+    ROOT = importroot()
+    
+    SetStyle()
+    c = TCanvas( name, title, 0, 0, 530, 400 )
+    c.GetPad(0).SetTopMargin(0.13)
+    c.GetPad(0).SetGrid()
+
+    firstlb = min([lbinfo[0][0] for lbinfo in v.values()])
+    lastlb = max([lbinfo[-1][0] for lbinfo in v.values()])
+
+    frame = TH1F( name, title, lastlb-firstlb+1, firstlb, lastlb+1 )
+    frame.GetXaxis().SetTitle( xtit )
+    frame.GetXaxis().SetTitleOffset( 1.3 )
+    frame.GetYaxis().SetTitle( ytit )
+    frame.GetYaxis().SetTitleOffset( 1.4 )
+
+
+    hTAP = {} # trigger after prescale (not realy, it contains (tap+tav)/2 with and error of (tap-tav)/2)
+    hTAV = {} # trigger after veto
+    ymax = -1
+
+    # see http://root.cern.ch/root/html526/TColorWheel.html
+    colorList = [ (ROOT.kBlue,ROOT.kAzure+1),
+                  (ROOT.kGreen+2,ROOT.kGreen+2),
+                  (ROOT.kRed+1,ROOT.kRed),
+                  (ROOT.kTeal-1,ROOT.kTeal),
+                  (ROOT.kOrange+8,ROOT.kOrange),
+                  (ROOT.kYellow+1,ROOT.kYellow),
+                  (ROOT.kOrange+3,ROOT.kOrange+5),
+                  (ROOT.kPink+8,ROOT.kPink+9) ]
+
+    clrIdx = 0
+    for trname,avrate in plottriggers:
+        hTAP[trname] = TH1F( '%s_ap_%s' % (name,trname), title, lastlb-firstlb+1, firstlb, lastlb+1 )
+        hTAV[trname] = TH1F( '%s_av_%s' % (name,trname), title, lastlb-firstlb+1, firstlb, lastlb+1 )
+        hap = hTAP[trname]
+        hav = hTAV[trname]
+        hav.SetLineWidth( 2 )
+        if clrIdx < len(colorList):
+            dark,bright = colorList[clrIdx]
+            hav.SetLineColor( dark )
+            hap.SetFillColor( bright )
+            hap.SetMarkerColor( bright )
+            clrIdx += 1
+
+        counts = v[trname]
+        for (lb,bp,ap,av),(lb2,lbstart,dt) in zip(counts,lbduration):
+            _apr = float(ap)/dt
+            _avr = float(av)/dt
+            hap.SetBinContent( lb-firstlb+1, (_apr+_avr)/2 )
+            hap.SetBinError( lb-firstlb+1, (_apr-_avr)/2 )
+            hav.SetBinContent( lb-firstlb+1, _avr )
+            ymax = max(ymax,_apr)
+
+
+    if ymax <= 0: ymax = 1
+    
+    # first draw histogram        
+    y2 = ymax*1.2
+    y1 = 0.01
+    frame.SetMinimum(y1)
+    frame.SetMaximum(y2)
+    frame.Draw("0")    
+
+    for h in hTAP.values():
+        h.Draw("same e2")
+    for h in hTAV.values():
+        h.Draw("same")
+
+    if printText:
+        t = TText( frame.GetXaxis().GetXmax(), y2*1.01, printText )
+        t.SetTextAlign( 31 )
+        t.SetTextSize( 0.035 )
+        t.Draw()
+
+    # logo
+    now = str(datetime.datetime.today())
+    tlogo = TText( frame.GetXaxis().GetXmax()*1.025, y1, 'ATLAS Run QUERY %s' % now[:now.find('.')] )
+    tlogo.SetTextSize( 0.030 )
+    tlogo.SetTextColor( TColor.GetColor( "#888888" ) )
+    tlogo.SetTextAngle(90)
+    tlogo.Draw()
+
+    dx = 0.4
+    dy = 0.10 + 0.01*(len(hTAV)-1)
+    legend = TLegend( 1 - c.GetRightMargin() - dx, 1 - c.GetTopMargin() - dy - 0.015,
+                      1 - c.GetRightMargin(), 1 - c.GetTopMargin() - 0.015)
+    legend.SetNColumns(2)
+    legend.SetBorderSize( 0 )
+    legend.SetMargin( 0.15 )
+    legend.SetLineColor( 0 )
+    legend.SetTextColor( 1 )
+    # fill legend - highest average rate first
+    for trname,avtrrate in averrate:
+        if not trname in hTAV: continue
+        legend.AddEntry( hTAV[trname], trname, "l" )
+    legend.Draw("same")
+
+    # redraw axis
+    frame.Draw( "sameaxis" )
+
+    c.Update()
+    fnames = '%s/atlrunquery_%s.png' % (datapath, name) 
+    c.Print( fnames )
+    frame.SetMaximum(ymax*5)
+    c.SetLogy(1)
+    c.Update()
+    fnames2 = '%s/atlrunquery_%s_log.png' % (datapath, name) 
+    c.Print( fnames2 )
+
+    return fnames
+    
+
+
+
+
+# command line driver for convenience
+if __name__=='__main__':
+
+    import pickle
+    datapath = '/afs/cern.ch/user/s/stelzer/runsummary/data'
+    pf = open( '%s/rates.pickle' % datapath, 'r' )
+    try: store = pickle.load(pf)
+    except:
+        print 'ERROR: could not load rates'
+        sys.exit(1)
+    pf.close()
+
+    (v, lbduration, plottriggers, averrate, xtit, ytit, name, title, datapath, printText) = store
+
+    datapath = '/afs/cern.ch/user/s/stelzer/runsummary/data'
+    makeRatePlot(v, lbduration, plottriggers, averrate, xtit, ytit, name, title, datapath, printText)
+
+    #froot = TFile.Open( 'atlrunquery.root', 'READ' )
+    #tree = gDirectory.Get( 'RunQuery' )
+    #
+    #hnames, fnames = MakePlots( tree )
+    #htmlstr = MakeHtml( hnames, fnames )
+    #print htmlstr
diff --git a/Database/CoolRunQuery/python/output/AtlRunQuerySave.py b/Database/CoolRunQuery/python/output/AtlRunQuerySave.py
new file mode 100644
index 00000000000..5f20251e2b8
--- /dev/null
+++ b/Database/CoolRunQuery/python/output/AtlRunQuerySave.py
@@ -0,0 +1,152 @@
+#!/usr/env python
+
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+#
+# ----------------------------------------------------------------
+# Script : AtlRunQuerySave.py
+# Project: AtlRunQuery
+# Purpose: Utility to save pickled dictionary 
+# Authors: Andreas Hoecker (CERN), Joerg Stelzer (DESY)
+# Created: Dec 2, 2008
+# ----------------------------------------------------------------
+#
+# ---------------------------------------------------------------------------------------------------
+# Creation of Pickled dictionary for output
+# ---------------------------------------------------------------------------------------------------
+from __future__ import with_statement
+from CoolRunQuery.utils.AtlRunQueryTimer import timer
+from CoolRunQuery.AtlRunQueryQueryConfig import QC
+from CoolRunQuery.selector.AtlRunQuerySelectorBase import DataKey
+
+import pickle,sys,os
+from CoolRunQuery.AtlRunQueryRun import Run
+
+def CreateResultDict( runlist ):
+
+    if len(runlist)==0: return {}, {}
+
+    # output directory
+    if not 'data' in os.listdir('.'):
+        os.mkdir('data')
+
+    # define the header
+    header = []
+    excludelist = []
+    if Run.showrunnr:    header += [DataKey(x) for x in ['Run', 'Links', '#LB']]
+    if Run.showtime:     header += [DataKey('Start and endtime')]
+    if Run.showduration: header += [DataKey('Duration')]
+    header += [k for k in Run.ShowOrder if k not in excludelist]
+
+    AddUpEvents(runlist)
+
+    SaveResultTxt(runlist, header)
+
+    dic = CreateDic(runlist, header)
+
+    dic_basic = CreateDicBasicTypes(dic)
+
+    SaveTypelessPickleResult(dic_basic)
+
+    summary = CreateSummary(dic)
+
+    return dic, summary
+
+
+def AddUpEvents(runlist):
+    # Sum up total event numbers
+    for run in runlist:
+        try:
+            Run.totevents[0] += int(run.result["#Events"])
+        except:
+            Run.totevents[1] += 1
+
+
+
+def SaveResultTxt(runlist, header):
+        # write header to text file
+    f = open( '%s/QueryResult.txt' % QC.datapath, 'w' )
+    print >> f, "data keys:", ', '.join([h.ResultKey for h in header])
+    print >> f, 'number of runs: %i' % len(runlist)
+
+    # now get the values for each run and write to file
+    for r in runlist:
+        line = []
+        if Run.showrunnr:        line += ["%i" % r.runNr, "", "%i" % r.lastlb]
+        if Run.showtime:         line += ["%s" % r.timestr('seconds')]
+        if Run.showduration:     line += ["%s" % r.durationstr()]
+        for k in Run.ShowOrder:  line += [r.data[k.ResultKey]]
+        for head,item in zip(header,line):
+            if isinstance(item,tuple): item = '|'.join([str(x) for x in item])
+            print >> f, '%40s: %s' % (head.ResultKey, item)
+        print >> f, '\n'
+    f.close()
+
+
+
+
+def SaveTypelessPickleResult(pdic, filename = 'atlrunquery.pickle'):
+    # write pickle output
+    pf = open( '%s/atlrunquery.pickle' % QC.datapath, 'w' )
+    try: pickle.dump(pdic, pf)
+    except Exception, e:
+        print 'ERROR: could not pickle results dictionary: "%r"' % e
+        sys.exit(1)
+    pf.close()
+
+
+
+def CreateDic(runlist, header):
+    # create keys for pickle dictionary
+    dic = {}
+    for r in runlist:
+        for k in header:
+            if   k == 'Run':               scontent = r.runNr
+            elif k == 'Links':             scontent = ""
+            elif k == '#LB':               scontent = (r.lastlb, [(lbtime[0]-r.lbtimes[0][0])*1e-9 for lbtime in r.lbtimes] + [ (r.lbtimes[-1][1]-r.lbtimes[0][0])*1e-9 ] )
+            elif k == 'Start and endtime': scontent = r.timestr('seconds')
+            elif k == 'Duration':          scontent = r.durationstr()
+            else:                          scontent = r.data[k.ResultKey]
+            dic.setdefault(k,[]).append(scontent)
+    return dic
+
+
+def basic(v):
+    if hasattr(v,'pickled'): return v.pickled()
+    return v
+
+def CreateDicBasicTypes(dic):
+    dic_basic = {'Run':dic[DataKey('Run')]}
+
+    for i,r in enumerate(dic_basic['Run']):
+        dic_basic[r] = dict([ ( k.pickled(), basic(v[i]) ) for k,v in dic.items()])
+
+    return dic_basic
+    
+
+
+
+    
+def CreateSummary(dic):
+    # create summary
+    dicsum = {}
+    for key, results in dic.items():
+        if key.ResultKey in ['SMK','HLT PSK','L1 PSK','TorCurrent','SolCurrent','BGS Key','#LB']: continue
+        if key.Type==DataKey.DETECTOR: continue
+        for r in results:
+            if key=='Run':
+                dicsum.setdefault(key,0)
+                dicsum[key] += 1
+            elif key.Type == DataKey.STREAM:
+                entry = r[0]
+                if entry == None or entry.value == 'n.a.': continue
+                dicsum.setdefault(key,[0,0])
+                dicsum[key][0] += entry.value[0]
+                dicsum[key][1] += entry.value[1]
+            else:
+                try:            
+                    ir = int(r)
+                    if not key in dicsum: dicsum[key] = 0
+                    dicsum[key] += ir
+                except:
+                    pass
+    return dicsum
diff --git a/Database/CoolRunQuery/python/output/AtlRunQueryXML.py b/Database/CoolRunQuery/python/output/AtlRunQueryXML.py
new file mode 100644
index 00000000000..390a4e24d6f
--- /dev/null
+++ b/Database/CoolRunQuery/python/output/AtlRunQueryXML.py
@@ -0,0 +1,277 @@
+#!/usr/env python
+
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+#
+# ----------------------------------------------------------------
+# Script : AtlRunQueryXML.py
+# Project: AtlRunQuery
+# Purpose: XML file output of good run lists
+# Authors: Andreas Hoecker (CERN), Joerg Stelzer (DESY)
+# Created: May 6, 2009
+# ----------------------------------------------------------------
+#
+# ---------------------------------------------------------------------------------------------------
+# XML making
+# ---------------------------------------------------------------------------------------------------
+
+from __future__ import with_statement
+from CoolRunQuery.utils.AtlRunQueryTimer import timer
+
+import datetime, sys, os
+from xml.dom.minidom import Document, DocumentType, Comment, Text, Element
+from CoolRunQuery.AtlRunQueryRun   import Run
+from CoolRunQuery.utils.AtlRunQueryUtils import prettyNumber
+
+# ---------------------------------------------------------------------------------------------------
+# Creation of XML output file
+# ---------------------------------------------------------------------------------------------------
+
+# This is an Element, but does not print sub-elements. It is designed
+# to hold attributes and CharacterData, and prints everything in one
+# line (unlike Element.writexml(), which always adds a 'newline'
+class TextElement(Element):
+    def __init__(self,name,data,doc):
+        Element.__init__(self,name)
+        if not isinstance(data, str):
+            raise TypeError, "node contents must be a string"
+        self.tagName = name
+        self.data = data
+        self.ownerDocument = doc
+        self.attOrder = []
+        
+    def setAttribute(self, attname, value):
+        if not attname in self.attOrder:
+            self.attOrder += [attname]
+        Element.setAttribute(self, attname, value)
+        
+    def writexml(self, writer, indent="", addindent="", newl=""):
+        attrs = self._get_attributes()
+        atstr = ''
+        for a_name in self.attOrder:
+            atstr += ' %s="%s"' % (a_name, attrs[a_name].value)
+
+        if self.data:
+            writer.write("%s<%s%s>%s</%s>%s" % (indent, self.tagName, atstr, self.data, self.tagName, newl ) )
+        else:
+            writer.write("%s<%s%s/>%s" % (indent, self.tagName, atstr, newl ) )
+
+def CreateRunStreamAndNeventsList( runlist ):
+
+    # open SFO DB connection
+    from CoolRunQuery.utils.AtlRunQueryUtils import coolDbConn
+    from CoolRunQuery.AtlRunQuerySFO   import GetSFO_NeventsAllPhysics
+
+    cursor = coolDbConn.GetSFODBConnection().cursor()
+    cursor.arraysize=1000
+
+    # find streams
+    runnrlist = [r.runNr for r in runlist]
+    runstreamevents = GetSFO_NeventsAllPhysics( cursor, runnrlist )  # { runnr: { stream: [(LUMIBLOCKNR, NREVENTS)] } }
+    return runstreamevents, ",".join(['%i' % r for r in runnrlist])
+
+def CreateXMLFile( runlist, options, origQuery, datapath, xmlfname, xmllabel, svnversion='Unknown'  ):
+
+    # show number of events per stream per run ?
+    ShowNumberOfEventsPerStreamPerRun  = False
+    ShowNumberOfEventsPerStreamSummary = True
+
+
+    # find streams
+    runstreamevents, runnrliststr = CreateRunStreamAndNeventsList( runlist ) # { runnr: { stream: [(LUMIBLOCKNR, NREVENTS)] } }
+
+
+
+
+    ####################################
+
+    ## create XML file of GRL
+
+    ####################################    
+    
+    doc = Document()
+
+    docType = DocumentType('LumiRangeCollection')
+    docType.systemId = 'http://atlas-runquery.cern.ch/LumiRangeCollection.dtd'
+    doc.appendChild(docType)
+
+    # number of comments
+    txt = ' Good-runs-list created by %s on %s ' % (sys.argv[0].split('/')[-1], str(datetime.datetime.now()))
+    doc.appendChild( doc.createComment( txt ) )
+
+    # root element
+    lrc = doc.createElement('LumiRangeCollection')
+    doc.appendChild(lrc)
+
+    # NamedLumiRange
+    namedLR = doc.createElement('NamedLumiRange')
+    lrc.appendChild(namedLR)
+
+    # name of NamedLumiRange
+    namedLR.appendChild(TextElement('Name',xmllabel,doc))
+
+    # version of NamedLumiRange
+    namedLR.appendChild(TextElement('Version','2.1',doc))
+
+    # metadata of NamedLumiRange
+    metadata = {
+        'Query'      : origQuery.split('/')[0],
+        'RQTSVNVersion' : svnversion,
+        'RunList'    : runnrliststr
+        }
+
+    for md in metadata:
+        mdelm = TextElement('Metadata', metadata[md], doc)
+        mdelm.setAttribute('Name', md)
+        namedLR.appendChild(mdelm)
+
+    if ShowNumberOfEventsPerStreamSummary:        
+        strsummdelm = doc.createElement('Metadata')
+        strsummdelm.setAttribute('Name','StreamListInfo')
+        namedLR.appendChild(strsummdelm)
+
+
+    # lumiblock collections of NamedLumiRange
+    streams_sum = {}
+    streams_byrun = {}
+    for run in runlist:
+        lbc = doc.createElement('LumiBlockCollection')
+        # run number
+        runnrelm = TextElement('Run',str(run.runNr),doc)
+        (rd0,rd1) = run.stats['SMK']['random']
+        # protect against missing information
+        if rd0 == 'n.a.': rd0 = 0
+        if rd1 == 'n.a.': rd1 = 0
+        runnrelm.setAttribute('PrescaleRD0',0x1<<(3+rd0))
+        runnrelm.setAttribute('PrescaleRD1',0x1<<(3+rd1))
+        lbc.appendChild(runnrelm)
+
+        # streams (initialisation)
+        streams = {}
+        streams_byrun[run.runNr] = streams
+        if runstreamevents.has_key(run.runNr): # protection in case the run does not have any stream
+            for stream in runstreamevents[run.runNr].keys():
+                if 'physics_' == stream[:8]:
+                    streams[stream] = [0,0] # only for physics streams
+                    if not streams_sum.has_key(stream): streams_sum[stream] = [0,0]
+                    # total number of events in stream
+                    for (nlb,nev) in runstreamevents[run.runNr][stream]: streams[stream][0] += nev 
+
+        # lumiblock ranges
+        
+        for lbrange in run.data.getLBRanges(activeOnly=True):
+            lbrelm = TextElement('LBRange','',doc)
+            lbrelm.setAttribute('Start',lbrange[1])
+            lbrelm.setAttribute('End',lbrange[2]-1)
+            lbc.appendChild(lbrelm)
+            # count nevents in streams
+            if runstreamevents.has_key(run.runNr): # protection in case the run does not have any stream
+                for stream, lbnevts in runstreamevents[run.runNr].items():
+                    if 'physics_' == stream[:8]:
+                        for (nlb,nev) in lbnevts:
+                            if nlb>=lbrange[1] and nlb<lbrange[2]: streams[stream][1] += nev
+
+        # append stream element
+        s = streams.keys()        
+        s.sort()
+        strselm = doc.createElement('StreamsInRun')
+
+        for stream in s:
+            nevts  = streams[stream]
+            if ShowNumberOfEventsPerStreamPerRun:
+                strelm = TextElement('Stream','',doc)
+                strelm.setAttribute('Name', stream)
+                strelm.setAttribute('TotalNumOfEvents',    nevts[0])
+                strelm.setAttribute('NumOfSelectedEvents', nevts[1])
+                strselm.appendChild(strelm)
+            eff = 0
+            if nevts[0] > 0: eff = nevts[1]/float(nevts[0])*100.0
+
+            # collect total number of events
+            streams_sum[stream][0] += nevts[0]
+            streams_sum[stream][1] += nevts[1]
+
+        # append streams
+        if ShowNumberOfEventsPerStreamPerRun: lbc.appendChild(strselm)
+
+        # append LumiBlickCollection
+        namedLR.appendChild(lbc)
+
+    for stream in sorted(streams_sum.keys()):
+        nevts  = streams_sum[stream]
+        if ShowNumberOfEventsPerStreamSummary: 
+            strelm = TextElement('Stream','',doc)
+            strelm.setAttribute('Name', stream)
+            strelm.setAttribute('TotalNumOfEvents',    nevts[0])
+            strelm.setAttribute('NumOfSelectedEvents', nevts[1])
+            strsummdelm.appendChild(strelm)    
+
+
+    filename = '%s/%s' % (datapath, xmlfname)
+    #print "Writing",filename
+    xmlfile = open( filename, mode="w" )         
+    xmlfile.write( doc.toprettyxml('   ') )
+    xmlfile.close()
+
+
+
+
+    ####################################
+
+    ## create HTML
+
+    ####################################    
+
+
+    # provide also pretty html text output
+    htmltext = ''
+    hspace   = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'
+    htmltext += '<table style=&quot;width: auto; border: 0px solid; border-width: margin: 0 0 0 0; 0px; border-spacing: 0px; border-collapse: separate; padding: 0px;&quot; font-family: sans-serif; font-size: 85%%&quot;>\n'
+    htmltext += '<tr><td colspan=&quot;2&quot;><b><font color=&quot;#999999&quot;>' + txt.strip() + '</font></b></td></tr>\n'
+    htmltext += '<tr><td style=&quot;vertical-align:top&quot;>SVN&nbsp;Version: </td><td> ' + svnversion + '</td></tr>\n'    
+    htmltext += '<tr><td style=&quot;vertical-align:top&quot;>Query&nbsp;string:</td><td><b>' + origQuery.split('/')[0] + '</b></td></tr>\n'    
+    htmltext += '<tr><td style=&quot;vertical-align:top&quot;>Run list:</td><td>' + runnrliststr + '</td></tr>\n'    
+    htmltext += '</table>'
+    htmltext += '<hr color=&quot;#000000&quot; size=1><font color=&quot;#777777&quot;>\n'
+    htmltext += '<table style=&quot;width: auto; border: 0px solid; border-width: margin: 0 0 0 0; 0px; border-spacing: 0px; border-collapse: separate; padding: 0px;&quot; font-family: sans-serif; font-size: 90%%&quot;>\n'
+
+
+    # lumiblock collections of NamedLumiRange
+    for run in runlist:
+        # run number
+        htmltext += '<tr><td style=&quot;text-align:left;height:25px;vertical-align:bottom&quot;>Run <b>%i</b>:</td><td></td></tr>\n' % run.runNr
+
+        # lumiblock ranges
+
+        for lbrange in run.data.getLBRanges(activeOnly=True):
+            htmltext += '<tr><td></td><td style=&quot;text-align:left&quot;>LB range: [%5i-%5i]</td></tr>\n' % (lbrange[1],lbrange[2]-1)
+
+        # append stream element
+        htmltext += '<tr><td></td><td style=&quot;text-align:left&quot;></td></tr>'
+        htmltext += '<tr><td></td><td style=&quot;text-align:left&quot;><table style=&quot;width: auto; border: 0px solid; border-width: margin: 0 0 0 0; 0px; border-spacing: 0px; border-collapse: separate; padding: 0px;font-family: sans-serif; font-size: 90%&quot;><tr><td>Stream name</td><td>#Events total</td><td>&nbsp;&nbsp;&nbsp;#Events selected</td><td>&nbsp;&nbsp;&nbsp;Sel. fraction (%)</td></tr>\n'
+
+        streams = streams_byrun[run.runNr]
+        for stream in sorted(streams.keys()):
+            nevts  = streams[stream]
+            eff    = (nevts[1]/float(nevts[0])*100.0) if (nevts[0] > 0) else 0
+            htmltext += '<tr><td style=&quot;text-align:left&quot;><i>%s</i></td><td style=&quot;text-align:right&quot;>%s</td><td style=&quot;text-align:right&quot;>%s</td><td style=&quot;text-align:right&quot;>%.4g</td></tr>\n' % (stream, prettyNumber(nevts[0]),prettyNumber(nevts[1]),eff)
+
+        htmltext += '</table></td></tr>\n'
+
+
+    # append stream element
+    htmltext += '</table>'
+    htmltext += '<hr color=&quot;#000000&quot; size=1><font color=&quot;#777777&quot;>\n'
+    htmltext += '<b>Stream summary for all selected runs:</b><br>\n'
+    htmltext += '<table style=&quot;width: auto; border: 0px solid; border-width: margin: 0 0 0 0; 0px; border-spacing: 0px; border-collapse: separate; padding: 0px;font-family: sans-serif; font-size: 95%&quot;><tr><td>Stream name</td><td>#Events total</td><td>&nbsp;&nbsp;&nbsp;#Events selected</td><td>&nbsp;&nbsp;&nbsp;Sel. fraction (%)</td></tr>\n'
+    for stream in sorted(streams_sum.keys()):
+        nevts  = streams_sum[stream]
+        eff = 0
+        if nevts[0] > 0: eff = nevts[1]/float(nevts[0])*100.0
+        htmltext += '<tr><td style=&quot;text-align:left&quot;><i>%s</i></td><td style=&quot;text-align:right&quot;>%s</td><td style=&quot;text-align:right&quot;>%s</td><td style=&quot;text-align:right&quot;>%.4g</td></tr>\n' % (stream, prettyNumber(nevts[0]),prettyNumber(nevts[1]),eff)
+    htmltext += '</table>\n'
+
+
+
+
+    # provide also text output
+    return htmltext
diff --git a/Database/CoolRunQuery/python/output/__init__.py b/Database/CoolRunQuery/python/output/__init__.py
new file mode 100644
index 00000000000..74583d364ec
--- /dev/null
+++ b/Database/CoolRunQuery/python/output/__init__.py
@@ -0,0 +1,2 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
diff --git a/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorBase.py b/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorBase.py
new file mode 100644
index 00000000000..bd841eb6461
--- /dev/null
+++ b/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorBase.py
@@ -0,0 +1,609 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+
+from PyCool import cool
+from copy import deepcopy
+
+from CoolRunQuery.utils.AtlRunQueryUtils  import coolDbConn, MergeRanges, SmartRangeCalulator  #, runsOnServer, GetRanges
+from CoolRunQuery.utils.AtlRunQueryIOV    import IOVTime, IOVRange
+
+import sys
+from time import time,strftime,gmtime
+from collections import namedtuple, defaultdict
+
+from itertools import groupby
+from operator import itemgetter
+
+
+O = namedtuple('O', 'channel payload iovrange isvf')
+def coolgen(coolobjs):
+    while coolobjs.goToNext():
+        obj=coolobjs.currentRef()
+        yield O(obj.channelId(),obj.payloadValue, IOVRange(obj), False)
+
+ChDesc = namedtuple('ChDesc','CoolPayloadKey,CoolChannel,ResultKey,Header,SelectShowRetrieve')
+
+class DataKey(object):
+    SELECT   = 0x1
+    SHOW     = 0x2
+    RETRIEVE = 0x4
+
+    UNDEFINED = 0
+    STREAM = 1
+    DETECTOR = 2
+    DQDEFECTS = 3
+
+    def __init__(self, x, keytype=UNDEFINED, selecttype = SELECT):
+        if isinstance(x,str):
+            self._cool_channel = 0
+            self._cool_attr = ''
+            self._internal_key = x.strip()
+            self._second_internal_key = ''
+            self._table_header = x.strip()
+        else:
+            self._cool_channel = x[0]
+            self._cool_attr = x[2]
+            self._internal_key = x[1].strip()
+            self._second_internal_key = ''
+            self._table_header = x[1] if len(x)<4 else x[3]
+        self._type = keytype
+        self._select_show_retrieve = selecttype # 0-retrieve only, 1-select, 2-show, 3-select&show
+
+    @property
+    def _seltype(self):
+        if self._select_show_retrieve == DataKey.SELECT: return "SELECT"
+        if self._select_show_retrieve == DataKey.SHOW: return "SHOW"
+        if self._select_show_retrieve == DataKey.RETRIEVE: return "RETRIEVE"
+        return ""
+
+    def __repr__(self):
+        return "<DataKey '%s' type %i %s>" % (self._internal_key, self._type, self._seltype)
+
+    def __eq__(self,other):
+        if isinstance(other,DataKey):
+            #print "Compare (%s) with (%s) ==> %r" % (self._internal_key,other._internal_key, self._internal_key==other._internal_key)
+            eq = self._internal_key==other._internal_key and self._second_internal_key==other._second_internal_key
+            return eq
+        else:
+            #print "Compare (%s) with '%s' ==> %r" % (self._internal_key, other, self._internal_key==other)
+            eq = self._internal_key==other
+            return eq
+
+    def __cmp__(self,other):
+        if isinstance(other,DataKey):
+            if self._internal_key==other._internal_key and self._second_internal_key==other._second_internal_key:
+                return 0
+            if self._internal_key==other._internal_key:
+                return self._second_internal_key.__cmp__(other._second_internal_key)
+            return self._internal_key.__cmp__(other._internal_key)
+        else:
+            #print "Compare (%s) with '%s' ==> %r" % (self._internal_key, other, self._internal_key==other)
+            return self._internal_key==other
+
+    def __hash__(self):
+        return hash( (self._internal_key,self._second_internal_key) )
+
+    def pickled(self):
+        if self._second_internal_key != '':
+            return (self._internal_key,self._second_internal_key)
+        return self._internal_key
+    
+    
+    @property
+    def CoolPayloadKey(self):
+        return self._cool_attr
+        
+    @property
+    def CoolChannel(self):
+        return self._cool_channel
+    
+    @property
+    def ResultKey(self):
+        return self._internal_key
+
+    @property
+    def Header(self):
+        return self._table_header
+
+    @property
+    def SelectShowRetrieve(self):
+        return self._select_show_retrieve
+
+    @property
+    def Type(self):
+        return self._type
+
+
+
+
+class Selector(object):
+    db = "COMP200"
+    condtag = ""
+    def __init__(self, name):
+        self.name = name
+        self.priority = 50
+        self.verbose = False
+        self.applySelection = True
+        self.mcenabled = False
+    def select(self, runlist): return runlist
+    def prettyValue(self, value, key): return value
+    def ApplySelection(self,key): return self.applySelection
+    def runAfterQuery(self,runlist): pass
+
+
+class Condition(Selector):
+    def __init__(self, name, dbfolderkey, channelKeys):
+        super(Condition,self).__init__(name)
+        self.selDataMissing = False
+        self.setSchemaFolderTag(dbfolderkey)
+        self.setChannelKeys(channelKeys)
+
+    def setSchemaFolderTag(self,dbfoldertag):
+        # setting schema, folder, and tag
+        self.schema, foldertag = dbfoldertag.split('::')
+        self.folder, self.tagname = (foldertag.split('#')+[''])[0:2]
+        if self.tagname=="": self.tagname = self.condtag
+        
+        
+    def setChannelKeys(self,channelKeys,ssr=None):
+        self.data_keys = [DataKey(x) for x in channelKeys]
+        if ssr:
+            assert len(ssr)==len(self.data_keys)
+            for (x,_ssr) in zip(self.data_keys,ssr):
+                x._select_show_retrieve = _ssr
+        
+        self._channelKeys    = channelKeys
+        self._coolpayloadkey = [x[2] for x in channelKeys]
+        self._coolchannel    = [x[0] for x in channelKeys]
+        self._resultKey      = [x[1] for x in channelKeys]
+        self._headerKey      = [x[1] for x in channelKeys]
+        if not ssr:
+            self._doSelectShowRetrieve = len(channelKeys)*[1] # 0-retrieve only, 1-select, 2-show, 3-select&show
+        else:
+            self._doSelectShowRetrieve = ssr
+        self._channeldesc = self.data_keys
+
+    def _getFolder(self):
+        f = coolDbConn.GetDBConn(schema = self.schema,db=self.db).getFolder(self.folder)
+        if f.versioningMode()==0: self.tagname=""
+        if self.tagname not in ["HEAD", ""]:
+            self.tagname = f.resolveTag(self.tagname)
+        return f
+
+    def addChannelKey(self,channelKey,ssr=None):
+        """
+        channelKey: (0,'SMK','MasterConfigurationKey')
+        ssr: 0-retrieve only, 1-select, 2-show, 3-select&show
+        """
+        
+        if DataKey(channelKey) in self.data_keys:
+            # key already exists
+            return
+        
+        self.data_keys += [ DataKey(channelKey) ]
+        if ssr:
+            self.data_keys[-1]._select_show_retrieve = ssr
+        
+        self._channelKeys    += [ channelKey ]
+        self._coolpayloadkey += [ channelKey[2] ]
+        self._coolchannel    += [ channelKey[0] ]
+        self._resultKey      += [ channelKey[1] ]
+        self._headerKey      += [ channelKey[1] ]
+        if ssr:
+            self._doSelectShowRetrieve += [ ssr ]
+        else:
+            self._doSelectShowRetrieve += [ 1 ] 
+        self._channeldesc = self.data_keys
+
+        
+
+    def ResultKey(self):
+        return self._resultKey
+
+    def ChannelKeys(self):
+        return self._channelKeys
+
+    def CoolChannels(self):
+        return self._coolchannel
+
+    def HeaderKeys(self):
+        return self._headerKey
+
+    def DoSelectShowRetrieve(self):
+        return self._doSelectShowRetrieve
+
+    def ChannelDesc(self):
+        return self._channeldesc
+
+    def setShowOutput(self, listofchans=None ):
+        for cd in self.ChannelDesc():
+            if listofchans and not cd.ResultKey in listofchans: continue
+            cd._select_show_retrieve |= 2 
+        self._doSelectShowRetrieve = [cd.SelectShowRetrieve for cd in self._channeldesc]
+        self.updateShowOrder()
+        
+    def updateShowOrder(self):
+        from CoolRunQuery.AtlRunQueryRun import Run
+        for cd in self.ChannelDesc():
+            if cd.SelectShowRetrieve<2: continue
+            Run.AddToShowOrder(cd)
+
+
+class RunLBBasedCondition(Condition):
+    def __init__(self, name, dbfolderkey, channelKeys=None):
+        super(RunLBBasedCondition,self).__init__(name, dbfolderkey, channelKeys)
+
+    def _retrieve(self, iovmin, iovmax, f, sortedRanges):
+        chansel = None
+        for ch1,ch2 in sortedRanges:
+            if chansel==None: chansel = cool.ChannelSelection(ch1,ch2,cool.ChannelSelection.sinceBeforeChannel)
+            else:             chansel.addRange(ch1,ch2)
+        print self.name,"browsing objects with tag",self.tagname
+        return coolgen(f.browseObjects( iovmin, iovmax, chansel, self.tagname))
+
+    def findPayload(self, runNr, iovpllist):
+        """
+        iovpllist is a list [(IOV,payload),(IOV,payload),..,(IOV,payload)]
+        """
+        for x in iovpllist:
+            if IOVTime(runNr,1).inRange(x[0]): return x[1]
+        return 'n.a.'
+
+    def getSortedAndCompletedPayloadDict(self, iovpllist, runlist, key):
+        # reduce to data in the run 'runNr' and sort by iov start time
+
+        pld = defaultdict(list)
+        if not iovpllist: return pld
+        if not runlist: return pld
+        
+        runnrlist = [r.runNr for r in runlist]
+        nlb = dict([(r.runNr,r.lastlb) for r in runlist])
+
+        # first and last run of the runlist
+        firstrun = runnrlist[0]
+        lastrun  = runnrlist[-1]
+
+        for iov, pl in iovpllist:
+            first = max(firstrun,iov.startTime.run)
+            last =  min(lastrun,(iov.endTime-1).run)
+            for r in xrange(first,last+1):
+                if r in runnrlist:
+                    pld[r].append((deepcopy(iov),pl))
+
+        # adjustments of IOV
+        for runnr, iovplbyrun in pld.items():
+            # adjust lb 0 to lb 1
+            if iovplbyrun[0][0].startTime.lb==0: iovplbyrun[0][0].startTime.lb=1
+
+            # truncate first IOV to a single run
+            iovplbyrun[0][0].truncateToSingleRun(runnr)
+
+            # sometimes and IOV has [RunLB1 - RunLB2), where RunLB2 has LB==1
+            # -> that gets truncated to [RunLB2 - RunLB2), which is obviously not valid
+            # -> so we slice that right out
+            if iovplbyrun[0][0].startTime == iovplbyrun[0][0].endTime:
+                iovplbyrun[:1] = []
+
+            # truncate last IOV to a single run
+            lastiov = iovplbyrun[-1][0]
+            lastiov.truncateToSingleRun(runnr)
+
+            # insert IOVs for missing ranges (value n.a.)
+            idx=0
+            curTime = IOVTime(runnr,1)
+            while curTime<lastiov.startTime:
+                iov = iovplbyrun[idx][0]
+                if curTime < iov.startTime:
+                    # insert n.a. for missing iov
+                    missingIOV = IOVRange(starttime=curTime, endtime=iov.startTime)
+                    iovplbyrun.insert( idx, (missingIOV, "n.a.") )
+                curTime = IOVTime(iov.endTime)
+                idx += 1
+
+            # also check if IOV at the end is missing 
+            runEndTime = IOVTime(runnr,nlb[runnr]+1) # last lb + 1
+            if  lastiov.endTime<runEndTime:
+                missingIOV = IOVRange(starttime=lastiov.endTime, endtime=runEndTime)
+                iovplbyrun.append( (missingIOV, "n.a.") )
+
+        return pld
+
+
+
+    def readCondData(self, runranges, f, sortedRanges):
+        # get the data from cool
+        condData = defaultdict(list)
+
+        keys = dict([(ch,set(k)) for ch, k in groupby(sorted(self.ChannelKeys(), key=itemgetter(0)), itemgetter(0))])
+
+        for rr in runranges:
+            iovmin=(rr[0] << 32)+0
+            iovmax=((rr[1]+1) << 32)-1
+
+            objs = self._retrieve(iovmin, iovmax, f, sortedRanges)
+
+            for obj in objs:
+                #if 'DQDEFECT' in keys:
+                #    print '\n YYYYYYY ',obj
+                ch  = obj.channel
+                for chtmp, internalKey, payloadKey in keys[ch]:
+                    if type(payloadKey)==tuple:
+                        if obj.isvf: payload = obj.payload
+                        else:        payload = tuple(map(obj.payload, payloadKey))
+                    else:
+                        payload = obj.payload(payloadKey)
+
+                    #if 'DQDEFECT' in keys:
+                    #    print '\n YYYYYYY ', payload
+
+                    condData[internalKey].append( (IOVRange(obj.iovrange), payload) )
+        return condData
+
+
+
+
+    def select(self, runlist):
+        print self,
+        sys.stdout.flush()
+        start = time()
+        newrunlist = []
+
+        sortedChannel = sorted( list( set( self.CoolChannels() ) ) )
+        sortedRanges = MergeRanges([(x,x) for x in sortedChannel])
+        
+        runranges = SmartRangeCalulator(runlist)
+
+        f = self._getFolder()
+
+        condData = self.readCondData(runranges, f, sortedRanges)
+
+        # for each key sort the data by IOV start time
+        for k in self.ResultKey():
+            condData[k].sort()
+            #if k.startswith('ofllumi'):
+            #    for x in condData[k]:
+            #        print k,x
+
+        condDataDict = {}
+        runnrlist = [r.runNr for r in runlist]
+        for k in self.ResultKey():
+            condDataDict[k] = self.getSortedAndCompletedPayloadDict(condData[k],runlist,k)
+
+        for run in runlist: # go through old runlist and see
+
+            rejectSomething = False
+            for k in self.ResultKey():
+                if not run.runNr in condDataDict[k]:
+                    if self.ApplySelection(k):
+                        rejectSomething = True
+                    run.addResult(k, "n.a.")
+                    continue
+
+                datavec = condDataDict[k][run.runNr]
+
+                if not datavec or len(datavec)==0:
+                    run.addResult(k, "n.a.")
+                    continue
+
+                if 'n.a.' in datavec: run.showDataIncomplete = True
+
+                anyDataSelected = False
+                for iov, data in datavec:
+                    #if k=="DQ":
+                    #    print "CCCCCCCCCCCC",k,data
+                    self.selDataMissing = False
+                    if self.ApplySelection(k) and not self.passes(data,k):
+                        run.addResult(k, self.prettyValue(data,k), iov, reject=True)
+                        rejectSomething = True
+                    else:
+                        run.addResult(k, self.prettyValue(data,k), iov)
+                        if self.selDataMissing: run.selDataIncomplete = True
+
+            if not (rejectSomething and self.rejectRun(run)):
+                newrunlist += [run.runNr]
+                        
+        runlist = [r for r in runlist if r.runNr in newrunlist]
+
+        duration = time() - start
+
+        if self.applySelection:  print " ==> %i runs found (%.2f sec)" % (len(runlist),duration)
+        else:                    print " ==> Done (%g sec)" % duration
+
+        return runlist
+
+
+    def rejectRun(self,run):
+        return run.data.isRejected
+
+
+class TimeBasedCondition(Condition):
+    def __init__(self, name, dbfolderkey, channelKeys=None):
+        super(TimeBasedCondition,self).__init__(name, dbfolderkey, channelKeys)
+
+
+    def getSortedAndCompletedPayloadDict(self, iovpllist, runlist,key):
+        # reduce to data in the run 'runNr' and sort by iov start time
+        
+        pld = {}
+        if not iovpllist or not runlist: return pld
+
+        startiovindex = 0
+        for run in runlist:
+            pld[run.runNr] = []
+
+            if startiovindex<-1:
+                continue
+
+            # find the first iov that overlaps
+            iovindex = startiovindex
+            while True:
+                try:
+                    iov      = iovpllist[iovindex][0]
+                    iovstart = iov.startTime.time
+                    iovend   = iov.endTime.time
+
+                    if iovend>run.sor:
+                        startiovindex = iovindex
+                        break
+
+                    if iovstart>run.eor:
+                        startiovindex = -1
+                        break
+
+                    if iovend<run.sor and iovindex==len(iovpllist)-1:
+                        startiovindex = -2
+                        break
+
+                    iovindex += 1
+                except IndexError:
+                    startiovindex = -1
+
+            if startiovindex<0:
+                continue
+
+            # find the last iov that overlaps
+            iovindex = startiovindex
+            while True:
+                iov      = iovpllist[iovindex][0]
+                iovstart = iov.startTime.time
+                iovend   = iov.endTime.time
+
+                if iovend>=run.eor or iovindex==len(iovpllist)-1:
+                    endiovindex = iovindex
+                    break
+
+                iovindex += 1
+
+            # now we have the first and last iov that overlap with that run: startiovindex, endiovindex
+            lbindex = 0
+            for iovindex in range(startiovindex, endiovindex+1):
+                iov,pl   = iovpllist[iovindex]
+                iovstart = iov.startTime.time
+                iovend   = iov.endTime.time
+                endrun   = run.runNr
+
+                while lbindex<len(run.lbtimes) and run.lbtimes[lbindex][0]<iovstart:
+                    lbindex += 1
+                startlb = lbindex+1
+
+                while lbindex<len(run.lbtimes) and run.lbtimes[lbindex][0]<iovend:
+                    lbindex += 1
+                lbindex -= 1
+
+                # now lbindex points to the last lb that starts within the iov or to one after the last lb
+                if lbindex==len(run.lbtimes)-1:
+                    endlb   = 0
+                    endrun += 1
+                else:
+                    endlb = lbindex+2 # +1 for lb-index->lb-number, +1 for closed interval
+
+                # append info of this IOV
+                lastIOV,lastpl=None,None
+                if len(pld[run.runNr])>0:
+                    lastIOV,lastpl = pld[run.runNr][-1]
+                if lastpl==pl:
+                    lastIOV.endTime.run = endrun
+                    lastIOV.endTime.lb = endlb
+                else:
+                    pld[run.runNr] += [(IOVRange(runStart=run.runNr, lbStart=startlb, runEnd=endrun, lbEnd=endlb), pl)]
+
+
+            # for the next run we start looking at:
+            startiovindex = endiovindex
+
+        return pld
+
+
+    def select(self, runlist):
+        print self,
+        sys.stdout.flush()
+        start = time()
+        newrunlist = []
+        f = coolDbConn.GetDBConn(schema=self.schema, db=self.db).getFolder(self.folder)
+        
+        sortedChannel = sorted( list( set( self.CoolChannels() ) ) )
+        chansel = None
+        for ch in sortedChannel:
+            if chansel==None: chansel = cool.ChannelSelection(ch,ch,cool.ChannelSelection.sinceBeforeChannel)
+            else:             chansel.addChannel(ch)
+
+        runranges = SmartRangeCalulator(runlist,True)
+        condData = defaultdict(list)
+
+            
+
+        for rr in runranges:
+            firstrun = runlist[runlist.index(rr[0])]
+            lastrun = runlist[runlist.index(rr[1])]
+            iovmin=firstrun.sor
+            iovmax=lastrun.eor
+
+            objs = f.browseObjects( iovmin, iovmax, chansel)
+            while objs.goToNext():
+                obj= objs.currentRef()
+                ch = obj.channelId()
+                for chKey in self.ChannelKeys():
+                    (channelNumber, resultKey, payloadKey) = chKey
+                    if channelNumber != ch: continue
+                    isBlob = (resultKey == 'olc:bcidmask')
+
+                    if isBlob:
+                        payloadvalue = obj.payload()[chKey[2]].read()
+                    else:
+                        payloadvalue = obj.payloadValue(chKey[2])
+
+                    condData[resultKey].append( (IOVRange(obj=obj, timebased=True), payloadvalue) )
+
+
+        # for each key sort the data by IOV start time
+        for k in self.ResultKey(): condData[k].sort()
+        
+        condDataDict = {}
+        for k in self.ResultKey():
+            condDataDict[k] = self.getSortedAndCompletedPayloadDict(condData[k],runlist,k)
+
+        for run in runlist:
+
+            rejectSomething = False
+            for k in self.ResultKey():
+
+                if not run.runNr in condDataDict[k]:
+                    run.addResult(k, "n.a.")
+                    continue
+
+                datavec = condDataDict[k][run.runNr]
+
+                if not datavec or len(datavec)==0:
+                    run.addResult(k, "n.a.")
+                    continue
+
+                if 'n.a.' in datavec: run.showDataIncomplete=True
+
+                anyDataSelected = False
+                for iov, data in datavec:
+                    self.selDataMissing = False
+                    if self.ApplySelection(k) and not self.passes(data,k):
+                        run.addResult(k, self.prettyValue(data,k), iov, reject=True)
+                        rejectSomething = True
+                        continue
+
+                    run.addResult(k, self.prettyValue(data,k), iov)
+
+                    if self.selDataMissing: run.selDataIncomplete = True
+
+            if not (rejectSomething and self.rejectRun(run)):
+                newrunlist += [run.runNr]
+
+
+        runlist = [r for r in runlist if r.runNr in newrunlist]
+
+        duration = time() - start
+
+        if self.applySelection: print " ==> %i runs found (%.2f sec)" % (len(runlist),duration)
+        else:                   print " ==> Done (%g sec)" % duration
+
+        return runlist
+
+    def rejectRun(self,run):
+        return run.data.isRejected
+
diff --git a/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorDQ.py b/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorDQ.py
new file mode 100644
index 00000000000..82fdba08ce2
--- /dev/null
+++ b/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorDQ.py
@@ -0,0 +1,697 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+
+from .AtlRunQuerySelectorBase import Selector, RunLBBasedCondition, O
+from CoolRunQuery.utils.AtlRunQueryIOV    import IOVRange
+from CoolRunQuery.utils.AtlRunQueryUtils  import coolDbConn
+from CoolRunQuery.utils.AtlRunQueryLookup import DQChannel
+
+from collections import defaultdict, namedtuple
+
+DQDefectPayload = namedtuple("DQDefectPayload", "defect comment user ignore primary tolerable recoverable")
+DQDefectPayload.pickled = DQDefectPayload._asdict
+
+DD = namedtuple("DD","description comment since until")
+
+def vfgen(vfobjs):
+    for obj in vfobjs:
+        yield O(obj.channel, (str(obj.Code),obj.Comment), IOVRange(starttime=obj.since, endtime=obj.until), True)
+
+class DQSelector(Selector):
+    def __init__(self, name='dataquality'):
+        super(DQSelector,self).__init__(name)
+        self.selectors = {}
+
+        from CoolRunQuery.AtlRunQuerySelectorWorker import SelectorWorker
+        SelectorWorker.getRetrieveSelector('readyforphysics','ReadyForPhysicsSelector')
+
+
+    def __getChannelAndFolder(self, chanAndfolder):
+        cf = chanAndfolder.split()
+        if len(cf)==1:
+            channel=''
+            folder=cf[0]
+        else:
+            channel, folder = cf
+        return (channel,folder)
+
+    def __getCondition(self, folder):
+        if folder in self.selectors:
+            return self.selectors[folder]
+        if folder.startswith('DEFECTS'):
+            self.selectors[folder] = DQDefectCondition(self.name+"DEFECTS", folder)
+        else:
+            self.selectors[folder] = DQCondition(self.name+folder, folder, [])
+        return self.selectors[folder]
+
+    def addSelectionChannel(self, dq=[]):
+        """
+        dq can be e.g. ['EMBA yellow SHIFTOFL', 'FCALA green+ DQMFOFL', 'EMBA,EMBC,EMECA,EMECC yellow+ SHIFTOFL']
+        this example should be translated into two selectors, one for each of the folders 'SHIFTOFL' and 'DQMFOFL'
+        """
+        folderCriteria = defaultdict(list)
+        for x in dq:
+            s = x.split()
+            folderCriteria[s[-1]].append(s[:-1])
+        for f in folderCriteria.keys():
+            if f.startswith('DEFECTS'):
+                self.selectors[f] = DQDefectCondition(self.name+"DEFECTS", f )
+                self.selectors[f].addSelectionChannels(folderCriteria[f])
+            else:
+                self.selectors[f] = DQCondition(self.name+f, f, folderCriteria[f])
+
+
+    def addShowChannel(self, chanAndfolder):
+        (channel,folder) = self.__getChannelAndFolder(chanAndfolder)
+        condition = self.__getCondition(folder)
+        condition.addShowChannel(folder, channel, 'HEAD')
+
+    def setShowOutput(self):
+        for sel in self.selectors.values():
+            sel.setShowOutput()
+
+
+    def __str__(self):
+        s = ""
+        for sel in self.selectors.values():
+            s += "\n%s" % sel
+        return s
+
+
+    def select(self, runlist):
+        # garbage collector
+        # import gc
+        # gcod = gc.get_objects()
+        # print "GC objects",len(gcod)
+        # print "GC object count",gc.get_count()
+        
+        for sel in self.selectors.values(): runlist = sel.select(runlist)
+        return runlist
+
+    def runAfterQuery(self,runlist):
+        for sel in self.selectors.values(): sel.runAfterQuery(runlist)
+        
+
+
+class DQCondition(RunLBBasedCondition):
+
+    code  = {'unknown': 0, 'red': 1, 'yellow': 2, 'green': 3, 'black': -1}
+    color = {'n.a.': 'n.a.', '0': 'U', '1': 'R', '2': 'Y', '3': 'G', '-1': 'B'}
+    invert = {'n.a.': -2, 'B': -1, 'U': 0, 'R': 1, 'Y': 2, 'G': 3 }
+    
+    def __init__(self, name, foldername, dq):
+
+        self.foldername = foldername
+        self.channelNames = []
+        self.channelNamesFlat = []
+        self.channels = []
+        self.channelsflat = []
+        self.flags = []
+        self.useVirtualFlags = False
+
+        dbname = 'COOLOFL_GLOBAL'
+        if 'ONL' in self.foldername: dbname = 'COOLONL_GLOBAL'
+
+        # set up virtual flag logic folder and expand wild cards for VF in dq
+        self.GetVirtualFlagsExpanded(dq, Selector.db, dbname)
+
+        for x in dq:
+            ch = x[0].split(',')
+            self.channelNames     += [["%s:%s" % (self.foldername,chn) for chn in ch]]
+            self.channels         += [[self.DQChannel(chn) for chn in ch]]
+            self.flags            += [(x+[''])[1]]
+
+        for chN in self.channelNames: self.channelNamesFlat += chN
+        for ch in self.channels: self.channelsflat += ch
+
+        self.channelCommentsFlat = [n+"_m" for n in self.channelNamesFlat]
+
+        # choose DB based on foldername
+
+        # out of 'SHIFTOFL', 'DQCALCOFL', 'DQMFOFL', 'DQMFOFLH', 'DCSOFL', 'TISUMM', 'LBSUMM', 'MUONCALIB', 'DQMFONL', 'SHIFTONL'
+        # these ones have a comment field
+
+        self.folderHasComment = ( (self.foldername == "SHIFTOFL") or (self.foldername.startswith("SHIFTOFL#")) or
+                                  (self.foldername == "LBSUMM")   or (self.foldername.startswith("LBSUMM#")) or
+                                  (self.foldername == "DQCALCOFL")   or (self.foldername.startswith("DQCALCOFL#")) or
+                                  (self.foldername.startswith("MUONCALIB#")) )
+
+        # channel keys:
+        # [Code (Int32) : 1], [deadFrac (Float) : 0], [Thrust (Float) : 0], [Comment (String255) : "warm start"]
+        if self.folderHasComment:
+            channelKeys  = zip(self.channelsflat, self.channelNamesFlat, len(self.channelsflat)*[('Code','Comment')])
+        else:
+            channelKeys  = zip(self.channelsflat, self.channelNamesFlat, len(self.channelsflat)*['Code'])
+                                         
+        super(DQCondition,self).__init__(name=name,
+                                         dbfolderkey='%s::/GLOBAL/DETSTATUS/%s' % (dbname, self.foldername),
+                                         channelKeys = channelKeys)
+
+        self.flagInterpreter = {}
+        for flag in self.flags:
+            self.flagInterpreter[flag] = {}
+            d = self.flagInterpreter[flag]
+            d['refVal']      = None
+            d['passFnc']     = None
+            d['passFncName'] = ''
+
+            if flag=='n.a.':
+                d['passFnc']     = lambda x: x==-2
+                d['passFncName'] = "x=='n.a.'"
+            elif flag[-1] in '+-':
+                cd = self.code[flag[:-1].lower()]
+                d['refVal'] = cd
+                if flag[-1]=='+':
+                    if cd == -1: d['passFnc'] = lambda x: int(x)>=-1
+                    elif cd == 0:d['passFnc'] = lambda x: int(x)>=0
+                    elif cd == 1:d['passFnc'] = lambda x: int(x)>=1
+                    elif cd == 2:d['passFnc'] = lambda x: int(x)>=2
+                    elif cd == 3:d['passFnc'] = lambda x: int(x)>=3
+                    d['passFncName'] = "x>='%i'" % d['refVal']
+                else:
+                    if cd == -1: d['passFnc'] = lambda x: int(x)<=-1
+                    elif cd == 0:d['passFnc'] = lambda x: int(x)<=0
+                    elif cd == 1:d['passFnc'] = lambda x: int(x)<=1
+                    elif cd == 2:d['passFnc'] = lambda x: int(x)<=2
+                    elif cd == 3:d['passFnc'] = lambda x: int(x)<=3
+                    d['passFncName'] = "x<='%i'" % d['refVal']
+            else:
+                cd = self.code[flag.lower()]
+                d['refVal'] = cd
+                if cd == -1: d['passFnc'] = lambda x: int(x)==-1
+                elif cd == 0:d['passFnc'] = lambda x: int(x)==0
+                elif cd == 1:d['passFnc'] = lambda x: int(x)==1
+                elif cd == 2:d['passFnc'] = lambda x: int(x)==2
+                elif cd == 3:d['passFnc'] = lambda x: int(x)==3
+                d['passFncName'] = "x=='%i'" % d['refVal']
+                
+        self.passSpecs = {}
+        for chgrp, flag in zip(self.channelNames,self.flags):
+            for ch in chgrp:
+                self.passSpecs[ch] = self.flagInterpreter[flag]
+
+    def _getFolder(self):
+        from CoolRunQuery.AtlRunQueryRun import RunData
+        RunData.DQLogic = self.channelNames
+        RunData.DQKeys = self.channelNamesFlat
+
+        f = coolDbConn.GetDBConn(schema = self.schema,db=self.db).getFolder(self.folder)
+        if self.useVirtualFlags:
+            f = self.VirtualFlagFolder(f)
+        else:
+            if f.versioningMode()==0: self.tagname=""
+            if self.tagname not in ["HEAD", ""]:
+                self.tagname = f.resolveTag(self.tagname)
+        return f
+
+    def _retrieve(self, iovmin, iovmax, f, sortedRanges):
+        if self.useVirtualFlags:
+            channels = [x.lower().split(':')[-1] for x in self.channelNamesFlat]
+            objs = vfgen(f.browseObjects( iovmin, iovmax, channels, self.tagname ))
+        else:
+            objs = super(DQCondition,self)._retrieve(iovmin, iovmax, f, sortedRanges)
+        return objs
+
+    def DQChannel(self,dqfullname):
+        dqname = dqfullname.split(':')[-1].split('#')[0]
+        if self.useVirtualFlags and dqname in self.vfl.get_logic_list().keys():
+            try:
+                return self.vfl.get_logic_list()[dqname].record.channel
+            except:
+                return self.vfl.get_logic_list()[dqname].channel
+        return DQChannel(dqname)
+
+    def GetVirtualFlagsExpanded(self, dqlist, db, schema):
+        for i in xrange(len(dqlist)):
+            dqs = dqlist[i][0].split(',')
+            newdqs = []
+            for c in dqs:
+                if '_' in c:
+                    newdqs += self.ExpandVFlag(c,db,schema)
+                else:
+                    newdqs.append(c)
+            dqlist[i][0] = ','.join(newdqs)
+
+    def ExpandVFlag(self, cpflag, db, schema):
+        vfl = self.GetVirtualFlagLogic(db, schema)
+        vflags = vfl.get_logic_list().keys()
+
+        useprimaries = cpflag[-1]=='+'
+        cpflag=cpflag.rstrip('+')
+
+        expflags = []
+
+        if cpflag in vflags:
+            self.AddVFHeaderData(cpflag)
+            expflags += [cpflag]
+            if useprimaries: expflags += self.getVFDef(cpflag)
+        else:
+            for vf in vflags:
+                if vf.startswith(cpflag):
+                    self.AddVFHeaderData(vf)
+                    expflags += [vf]
+                    if useprimaries: expflags += self.getVFDef(vf)
+                    
+        if len(expflags)==0:
+            raise RuntimeError("Virtual Flag pattern %s does not match any virtual flag: %r" % (cpflag, vfl.get_logic_list().keys()))
+
+        return expflags
+
+
+    def GetVirtualFlagLogic(self, db, schema):
+        if self.useVirtualFlags: return self.vfl
+        try: # import
+            from VirtualFlags import VirtualFlagLogicFolder, VirtualFlagFolder
+        except ImportError:
+            print "Can't import virtual flags"
+            import traceback
+            traceback.print_exc()
+
+        self.VirtualFlagFolder = VirtualFlagFolder
+        self.vfl               = VirtualFlagLogicFolder(coolDbConn.GetDBConn(schema=schema, db=db))
+        self.logics            = self.vfl.get_logic_list()
+        self.useVirtualFlags   = True
+        return self.vfl
+
+    def AddVFHeaderData(self,cpflag):
+        from CoolRunQuery.AtlRunQueryRun import Run
+        if cpflag in Run.Fieldinfo: return
+        Run.Fieldinfo[cpflag] = '<strong><b>%s</b></strong><br><table width="300"><tr><td>%s</td></tr></div>' % \
+                                (self.vfl.get_logic_list()[cpflag].comment,
+                                 ", ".join(self.getVFDef(cpflag)) )
+
+    def getVFDef(self,cpflag):
+        return self.vfl.resolve_primary_flags(self.vfl.resolve_dependancies([cpflag]))
+    
+    
+        
+    def ApplySelection(self,key):
+        if key in self.passSpecs: return True
+        return False
+
+    def addShowChannel(self, folder, channelname, tag):
+        tmplist = [[channelname,'']]
+        self.GetVirtualFlagsExpanded(tmplist, Selector.db, self.schema)
+
+        for shch in tmplist[0][0].split(','):
+            self.addSingleShowChannel(folder+':'+shch)
+        
+    def addSingleShowChannel(self, channelname):
+        ch = self.DQChannel(channelname)
+        ssr = self.DoSelectShowRetrieve()
+        if ch in self.channelsflat: # channel exists already, just need to set showoutput to true
+            idx = self.channelsflat.index(ch) # location of the channel in the flat list
+            self.channelNamesFlat[idx] = channelname
+            ssr[idx] += 2
+        else:
+            self.channelNamesFlat += [channelname]
+            self.channelsflat += [self.DQChannel(channelname)]
+            ssr += [2]
+        # re-assign
+        self.channels = self.channelsflat
+        
+        if self.folderHasComment:
+            channelKeys = zip(self.channelsflat, self.channelNamesFlat, len(self.channelsflat)*[('Code','Comment')])
+        else:
+            channelKeys = zip(self.channelsflat, self.channelNamesFlat, len(self.channelsflat)*['Code'])
+
+        self.setChannelKeys(channelKeys,ssr)
+
+    def __str__(self):
+        if self.applySelection:
+            s = "SELOUT Checking in the DQ folder %s" % self.foldername
+            flagCh = defaultdict(list)
+            for flag,ch in zip(self.flags,self.channelNames):
+                flagCh[flag].append('(' + ' or '.join(ch) + ')')
+            for flag in flagCh:
+                chlist = ' and '.join(flagCh[flag])
+                s += "\nSELOUT %s is %r" % (chlist, flag)
+            return s
+        else:
+            return "Retrieving DQ for channels %r from folder %s" % (self.channelNamesFlat, self.foldername)
+
+    def passes(self,values, key):
+        passfnc = self.passSpecs[key]['passFnc']
+        if isinstance(values,tuple):  v = values[0]
+        else:                         v = values
+        if v=='n.a.': v=-2
+        try:
+            if passfnc(v):  # passed this DQ flag in the OR group?
+                return True
+        except ValueError:
+            # happens when comparing 'n.a.' with 0,1,2,3 (for 'U','R','Y','G') ... and the black flag? (AH)
+            # should never set pass=True
+            pass
+        
+        return False
+
+    def rejectRun(self,run):
+        for k in self.ResultKey():
+            passfnc = self.passSpecs[k]['passFnc']
+            for entry in run.data[k]:
+                v = entry.value
+                dqres = v[0] if type(v)==tuple else v
+                dqcode = self.invert[dqres]
+                entry.rejected = not passfnc( dqcode )
+        return super(DQCondition,self).rejectRun(run)
+
+
+
+    def prettyValue(self, value, key):
+        if type(value)==tuple:
+            return (self.color[value[0]], value[1])
+        else:
+            return self.color[value]
+                
+    def runAfterQuery(self,runlist):
+        dqs = ['G','Y','R','B','U','n.a.']
+        for run in runlist:
+            for k in self.ResultKey():
+                n={}
+                run.stats[k] = {}
+                for dq in dqs: n[dq] = 0
+                blocks = []
+                for entry in run.data[k]:
+                    if self.folderHasComment:
+                        if entry.value == 'n.a.':
+                            dq, dqcomment = ('n.a.','')
+                        else:
+                            dq, dqcomment = entry.value
+                    else:
+                        dq, dqcomment = (entry.value,None)
+                    
+                    n[dq] += len(entry)
+                    if entry.startlb == 0: n[dq] -= 1 # CAUTION: problem with LB-1 = 0 ==> needs to be corrected
+                    if len(blocks) > 0 and blocks[-1][0]==(dq,dqcomment) and blocks[-1][2]==entry.startlb:
+                        blocks[-1][2] = entry.endlb
+                    else:
+                        blocks += [ [(dq, dqcomment), entry.startlb, entry.endlb] ]
+
+                maxn = max(n.values())
+                # find maximum DQ flag
+                dqmax = dqs[0]
+                for dq in dqs:
+                    if n[dq]==maxn:
+                        dqmax=dq
+                run.result[k]=dqmax
+                run.stats[k] = { "counts" : n, "max": dqmax, "blocks": blocks }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class DQDefectCondition(RunLBBasedCondition):
+
+    def __init__(self, name, folder):
+        self.foldername   = folder # DEFECTS#<TAG>
+        self.primaries    = {} # self.primaries[runnr] is the list of primary defects that are set in each run
+        self.channelNames = []
+        self.selectionChannelNames = []
+        self.global_ignore = set() # set of all primary defects that should be ignored in all defects
+        super(DQDefectCondition,self).__init__(name=name,
+                                               dbfolderkey = 'COOLOFL_GLOBAL::%s' % self.foldername, # folder name handled internally by DQDefects
+                                               channelKeys = [('DQDEFECT', 'DQ',('Code','Comment'))])
+
+        self.data_keys[0]._second_internal_key = self.tagname
+
+    def _getFolder(self):
+        from CoolRunQuery.AtlRunQueryRun import RunData
+        RunData.DefectSelector = self._pass
+        self.__db = coolDbConn.GetDBConn('DEFECTS',self.tagname)
+        return self.__db # return the DB, not the folder
+
+    def _pass(self,data):
+        these_defects = []
+        if data!=None:
+            for x in data:
+                if x.value.ignore==None: # no ignore
+                    these_defects += [x.value.defect]
+                else:
+                    these_defects += [x.value.defect+'\\'+x.value.ignore]
+        for orGroup in self.selectionChannelNames:
+            any_passes = False
+            for k in orGroup:
+                if k[0]=='\\': continue # "\Defect" are modifiers not requirements so we ignore it in the check
+                if k[0]=='!':  # !DEFECT
+                    kk = k[1:]
+                    passes = not kk in these_defects
+                else:
+                    passes = k in these_defects
+                if passes:
+                    any_passes = True
+                    break
+            if not any_passes: # none pass in the OR-group
+                return False
+        return True
+
+    def _fix_channel_names(self, db):
+        newl = []
+        for litem in self.selectionChannelNames:
+            newlitem = []
+            for k in litem:
+                if k[0]=='\\':
+                    newlitem.append(k)
+                elif k[0] == '!':
+                    newlitem.append('!' + db.normalize_defect_names(k[1:]))
+                else:
+                    newlitem.append(db.normalize_defect_names(k))
+            newl.append(newlitem)
+        self.selectionChannelNames = newl
+        self.global_ignore = set(db.normalize_defect_names(self.global_ignore))
+
+
+    def __getChannels(self, db, channel_name_patterns):
+        """ based on the patterns in the list channel_name_patterns create a
+        list of pairs of patterns and matching defects ( pattern, set(matching defects) )
+        and attach it to the global Run.FieldInfo dictionary under 'DQ'
+        """
+        from re import compile
+        from CoolRunQuery.AtlRunQueryRun import Run
+        if not 'DQ' in Run.Fieldinfo: Run.Fieldinfo['DQ'] = {}
+        if not 'DefMatch' in Run.Fieldinfo['DQ']: Run.Fieldinfo['DQ']['DefMatch'] = []
+        Run.Fieldinfo['DQ']['IntolerableDefects'] = db.get_intolerable_defects(old_primary_only=False)
+        matches = set()
+        for pattern in channel_name_patterns:
+            if pattern.upper() != 'DET':
+                cpattern = compile(pattern)
+                channelnames = set(filter(cpattern.match,db.defect_names))
+                channelnames.update(filter(cpattern.match,db.virtual_defect_names))
+            else:
+                channelnames = set([d for d in db.defect_names if not '_' in d])
+                channelnames.update([d for d in db.virtual_defect_names if not '_' in d])
+            matches.update(channelnames)
+            Run.Fieldinfo['DQ']['DefMatch'] += [(pattern,channelnames)]
+        return matches
+
+
+    def _retrieve(self, iovmin, iovmax, db, sortedRanges):
+        runmin = iovmin>>32
+        runmax = iovmax>>32
+        since  = (runmin,iovmin&0xFFFFFFFF)
+        until  = (runmax,iovmax&0xFFFFFFFF)
+
+        # add the channels for showing (those can be wildcarded, so call __getChannels to get exact matches)
+        channels = self.__getChannels(db,self.channelNames)
+
+        # Rewrite defect names to get cases to be correct
+        self._fix_channel_names(db)
+
+        # add the channels for selection (those have to match exactly, they are simply added)  
+        channels_with_ignore = {} # unique
+        for selChans in self.selectionChannelNames:
+            channels.update([x.lstrip('!') for x in selChans if not '\\' in x])
+            for x in selChans: # for the defects with ignore condition
+                if not '\\' in x: continue
+                channel, ignore_str = self.sort_uniq_ignores(x).split('\\',1)
+                if not ignore_str in channels_with_ignore: channels_with_ignore[ignore_str] = []
+                channels_with_ignore[ignore_str] += [channel.lstrip('!')]
+
+        #print "CHANNELS",channels
+        if len(channels) + len(channels_with_ignore)==0: return []
+
+        # we need to remove the special case ANY from the set
+        if 'ANY' in channels: channels.remove('ANY')
+
+        res = [] if len(channels)==0 else [ (db.retrieve(since=since, until=until, channels=channels, ignore=self.global_ignore, with_primary_dependencies=True).trim_iovs, None) ]
+
+        # and also treat the defects with 'ignore' condition
+        for _ignore_str, _channels in channels_with_ignore.items():
+            ignore = set(_ignore_str.split('\\'))
+            ignore.update(self.global_ignore)
+            ## https://svnweb.cern.ch/trac/atlasoff/browser/DataQuality/DQDefects/tags/DQDefects-00-00-24/python/db.py#L154
+            res += [ (db.retrieve(since=since, until=until, channels=_channels, ignore=ignore, with_primary_dependencies=True).trim_iovs, _ignore_str) ]
+
+        return self.defgen(db, res, channels, channels_with_ignore)
+
+    
+
+    def defgen(self, db, defects_with_ignore, channels, channels_with_ignore):
+        """
+        defects: list of defects returned by query
+        channels: explicit list of channels that matched the pattern
+        """
+        intolerableDefects = db.get_intolerable_defects(old_primary_only=False)
+        for defects, ignore in defects_with_ignore:
+            chanlist = channels if ignore==None else channels_with_ignore[ignore]
+            for d in defects:
+                if not d.present: continue
+                isVirtual = (d.user == 'sys:virtual') # db.defect_is_virtual(d.channel)
+                if not isVirtual:
+                    run = d.since.run
+                    # fill list of primaries defects for this run (this is needed for the comments, but not for the selection)
+                    if not run in self.primaries: self.primaries[run] = []
+                    self.primaries[run] += [d]
+                if not d.channel in chanlist: continue
+
+                defPayload = DQDefectPayload(defect = d.channel, comment = d.comment,
+                                             user = d.user, primary = not isVirtual,
+                                             ignore = ignore,
+                                             tolerable = (not d.channel in intolerableDefects),
+                                             recoverable = d.recoverable)
+                # note that the comment is either the user's comment,
+                # a comment that the defect is auto-generated, or the
+                # list of source defects in case of virtual defects
+                
+                #o = O("DQDEFECT", (d.channel, d.comment, ignore), IOVRange(starttime=d.since.real, endtime=d.until.real), True)
+                o = O("DQDEFECT", defPayload, IOVRange(starttime=d.since.real, endtime=d.until.real), True)
+                yield o
+
+
+        
+    def ApplySelection(self,key):
+        return key=='DQ' and len(self.selectionChannelNames)!=0
+
+
+    def sort_uniq_ignores(self,requirement):
+        if not '\\' in requirement: return requirement
+        x = requirement.split('\\')
+        new_req = x[0] + '\\' + '\\'.join(sorted(list(set(x[1:]))))
+        return new_req
+    
+
+    def addSelectionChannels(self, dq):
+        for channels,flag in dq:
+            a = []
+            prefix = '!' if flag == 'green' else ''
+            for x in channels.split(','):
+                if x[0]=='\\':
+                    self.global_ignore.update( x.lstrip('\\').split('\\') ) # "\Defect" are modifiers not a selection requirement
+                else:
+                    a += [ prefix+self.sort_uniq_ignores(x) ]
+            if len(a)>0:
+                self.selectionChannelNames += [ a ]
+
+        
+    def addShowChannel(self, folder, channelname, tag):
+        self.channelNames += [channelname]
+        from CoolRunQuery.AtlRunQueryRun import Run
+        if not 'DQ' in Run.Fieldinfo: Run.Fieldinfo['DQ'] = {}
+        if not 'DefChannels' in Run.Fieldinfo['DQ']: Run.Fieldinfo['DQ']['DefChannels'] = []
+        Run.Fieldinfo['DQ']['DefChannels'] += [channelname]
+
+    
+    def __str__(self):
+        if self.applySelection:
+            return "SELOUT Checking the DQ defects %s" % ', '.join([', '.join(cn) for cn in self.selectionChannelNames])
+        else:
+            return "Retrieving DQ defects %s" % ', '.join([', '.join(cn) for cn in self.selectionChannelNames])
+
+    def passes(self,values, key):
+        return True
+
+    def rejectRun(self,run):
+        return super(DQDefectCondition,self).rejectRun(run)
+
+    def mergeRanges(self,it):
+        """ two adjacent defect entries are merged into one"""
+        doMerge = False
+        if doMerge:
+            mergedByDefect = []
+            x = it.next()
+            (openedat,openuntil) = (x.startlb,x.endlb)
+            for x in it:
+                if x.startlb == openuntil:
+                    openuntil = x.endlb
+                else:
+                    mergedByDefect += [(openedat, openuntil)]
+                    openedat,openuntil = x.startlb,x.endlb
+            mergedByDefect += [(openedat, openuntil)]
+            return mergedByDefect
+        else:
+            return [(x.startlb,x.endlb) for x in it]
+
+
+
+    def runAfterQuery(self,runlist):
+        """
+        collects, sorts, and groups defects with LBs and comments
+        """
+
+
+        from itertools import groupby
+        from operator import itemgetter, attrgetter
+
+        for run in runlist:
+
+            for k in self.ResultKey():
+                # format of run.data[k] is
+                # [ <DataEntry with value = (defect_name, defect_comment or defect_composition)>, ...]
+
+                #for x in run.data[k]:
+                #    print "               %r" % (x,)
+                if not k in run.data.keys():
+                    run.result[k] = {}
+                run.stats[k] = {}
+
+                all_defects = sorted(list(set([x.value[0] for x in run.data[k]])))
+                
+                grouped_defects = groupby(sorted(run.data[k],key=lambda x: x.value[0]),key = lambda x: x.value[0]) # first sort by defect name, then group by defect name
+
+                desired_defects = [ (defect_name, self.mergeRanges(lblist)) for defect_name, lblist in grouped_defects ]
+
+                run.stats[k] = { "defects": desired_defects,
+                                 "primaries": {} }
+
+                primaries = {}  # defect : list of primaries with lb-range
+                if run.runNr in self.primaries:
+                    primgroups = groupby(sorted([p for p in self.primaries[run.runNr]],key=attrgetter('channel')),key=attrgetter('channel'))
+                    primaries = dict([(p,list(l)) for p,l in primgroups])
+                    
+                for defect in all_defects:
+                    if self.__db.defect_is_virtual(defect):
+                        reps = []
+                        self.find_primaries(DD, self.__db.virtual_defect_logics[defect], primaries, defect, reps)
+                        run.stats[k]["primaries"][defect] = reps
+                    elif defect in primaries:
+                        run.stats[k]["primaries"][defect] = [ DD("->%s" % def_obj.channel, def_obj.comment, def_obj.since.lumi, def_obj.until.lumi) for def_obj in primaries[defect] ]
+
+
+                #import pickle
+                #f = open("dev.pickle","w")
+                #pickle.dump(run.stats[k]["primaries"],f)
+                #f.close()
+
+                #for x,l in run.stats[k]["primaries"].items():
+                #    print x
+                #    for y in sorted(l):
+                #        print "    ",y
+
+
+    def find_primaries(self, DD, defect_logic, primaries, curpath, reps):
+        for pdef in defect_logic.primary_defects:
+            if not pdef in primaries: continue
+            pdefects = primaries[pdef]
+            for pdeflb in pdefects:
+                reps += [  DD("%s->%s" % (curpath, pdeflb.channel), pdeflb.comment, pdeflb.since.lumi, pdeflb.until.lumi) ]
+        for dep in defect_logic.dependencies:
+            self.find_primaries(DD, dep, primaries, curpath+"->"+dep.name, reps)
+
diff --git a/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorEvents.py b/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorEvents.py
new file mode 100644
index 00000000000..0279adf7b25
--- /dev/null
+++ b/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorEvents.py
@@ -0,0 +1,132 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+
+from time import time
+import sys
+
+from CoolRunQuery.utils.AtlRunQueryIOV   import IOVTime, IOVRange
+from CoolRunQuery.utils.AtlRunQueryTimer import timer
+from CoolRunQuery.utils.AtlRunQueryUtils import coolDbConn, runsOnServer, GetRanges, SmartRangeCalulator
+
+from .AtlRunQuerySelectorBase import Selector, Condition, RunLBBasedCondition, TimeBasedCondition, DataKey
+
+class EventSelector(RunLBBasedCondition):
+    def __init__(self, name, events=None):
+        self.events = events
+        super(EventSelector,self).__init__(name=name,
+                                           dbfolderkey='oracle::SFO-based',
+                                           channelKeys = [(0,'#Events','EFEvents')])
+        if events: self.cutRange = GetRanges(events)        
+        
+
+
+    def __str__(self):
+        if self.applySelection: return "SELOUT Checking if number of events matches %s" % self.events
+        else: return "Retrieving event numbers"
+
+    def select(self, runlist):
+
+        # some preparation: compile the show patterns
+        start = time()
+
+        print self,
+        sys.stdout.flush()
+        newrunlist = []
+        connection = coolDbConn.GetSFODBConnection()
+        cursor     = connection.cursor()
+        cursor.arraysize = 1000
+        
+        runnrlist = [r.runNr for r in runlist]
+
+        from CoolRunQuery.AtlRunQuerySFO import GetSFO_NphysicseventsAll
+        with timer("GetSFO_NphysicseventsAll"):
+            events = GetSFO_NphysicseventsAll( cursor, runnrlist )  # { runnr: nPhysEvents }
+
+        for run in runlist:
+
+            iov = IOVRange(runStart=run.runNr, lbStart=1, runEnd=run.runNr+1, lbEnd=0)
+
+            for k in self.ResultKey():
+                if not run.runNr in events:
+                    # the OVERLAP_EVENTS information is not yet available in the SFO (before Nov 15, 2009)
+                    # use the inclusive number instead
+                    run.addResult(k, "n.a.", iov, reject=False)
+                    run.showDataIncomplete=True
+                    continue
+
+                nev = events[run.runNr]
+                
+                if self.ApplySelection(k) and not self.passes(nev,k):
+                    run.addResult(k, self.prettyValue(nev,k), iov, reject=True)
+                    continue
+
+                run.addResult(k, self.prettyValue(nev,k), iov)
+
+            rej = self.rejectRun(run)
+
+            if not rej:
+                newrunlist += [run.runNr]
+
+        runlist = [r for r in runlist if r.runNr in newrunlist]
+        
+        duration = time() - start
+        if self.applySelection: print " ==> %i runs found (%.2f sec)" % (len(runlist),duration)
+        else:                   print " ==> Done (%g sec)" % duration
+        return runlist
+
+    def passes(self,values,key):
+        try:
+            val = int(values)
+        except ValueError: # if n.a.
+            self.selDataMissing = True
+            return True
+        for cr in self.cutRange:
+            if val>=cr[0] and val<=cr[1]:
+                return True
+        return False
+
+
+class AllEventsSelector(RunLBBasedCondition):
+    def __init__(self, name, events=None):
+        self.events = events
+        self.showAllevents = False
+        super(AllEventsSelector,self).__init__(name=name,
+                                               dbfolderkey='COOLONL_TDAQ::/TDAQ/RunCtrl/EventCounters',
+                                               channelKeys = [(0,'#Events (incl. calib.)','EFEvents'),
+                                                              (0,'#Events (streamed)','RecordedEvents'),
+                                                              (0,'#L2A','L2Events')])
+        if events: self.cutRange = GetRanges(events)        
+
+    def __str__(self):
+        if self.applySelection: return "SELOUT Checking if number of events matches %s" % self.events
+        else:                   return "Retrieving event numbers"
+
+    def passes(self,values,key):
+        try:
+            val = int(values)
+        except ValueError: # if n.a.
+            self.selDataMissing = True
+            return True
+        for cr in self.cutRange:
+            if val>=cr[0] and val<=cr[1]:
+                return True
+        return False
+
+class L1EventsSelector(RunLBBasedCondition):
+    def __init__(self, name, events=None):
+        self.events = events
+        self.showL1events = False
+        super(L1EventsSelector,self).__init__(name=name,
+                                              dbfolderkey='COOLONL_TRIGGER::/TRIGGER/LVL1/CTPCORELBDATA',
+                                              channelKeys = [(0,'#L1A','GlobalL1AcceptCounter')])
+    def setShowL1events(self):
+        self.showL1events  = True
+        super(L1EventsSelector,self).setShowOutput()
+        
+    def __str__(self):
+        if self.applySelection: return "SELOUT Checking if number of L1A events matches %s" % self.events
+        else:                   return "Retrieving L1A numbers"
+
+    def passes(self,values,key):
+        return True
+
diff --git a/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorLhcOlc.py b/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorLhcOlc.py
new file mode 100644
index 00000000000..c1d6d93f2bc
--- /dev/null
+++ b/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorLhcOlc.py
@@ -0,0 +1,488 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+
+from CoolRunQuery.utils.AtlRunQueryIOV   import IOVTime, IOVRange
+from CoolRunQuery.utils.AtlRunQueryTimer import timer
+from CoolRunQuery.utils.AtlRunQueryUtils import coolDbConn, runsOnServer, GetRanges, SmartRangeCalulator
+
+from .AtlRunQuerySelectorBase import Selector, Condition, RunLBBasedCondition, TimeBasedCondition, DataKey
+
+class LHCSelector(Selector):
+    def __init__(self, name, lhc=[], addArg=''):
+        super(LHCSelector,self).__init__(name)
+        self.condition = LHCCondition( 'lhc', lhc, addArg = addArg )
+        self.showarg=addArg
+        if not lhc:
+            self.condition.applySelection = False
+
+    def __str__(self):
+        return "\n%s" % self.condition
+
+    def addShowSelector(self, addArg=''):
+        self.showarg=addArg
+        
+    def setShowOutput(self):
+        self.condition.setShowOutput(self.showarg)
+        
+    def select(self, runlist):
+        runlist = self.condition.select(runlist)
+        return runlist
+
+class LHCCondition(TimeBasedCondition):
+    def __init__(self, name, condition=[], channel=0, addArg=''):
+        ck = [(1,'lhc:fillnumber',  'FillNumber'),
+              (1,'lhc:stablebeams', 'StableBeams'),
+              (1,'lhc:beamenergy',  'BeamEnergyGeV')]
+        if   addArg == 'all': ck += [(1,'lhc:beammode',    'BeamMode')]
+        elif addArg == 'min': ck = [(1,'lhc:stablebeams', 'StableBeams')]
+        super(LHCCondition,self).__init__(name=name,
+                                          dbfolderkey='COOLOFL_DCS::/LHC/DCS/FILLSTATE',
+                                          channelKeys = ck)
+    
+        # define arguments (after initialising base class!)
+        self.lhc = {}
+        for c in condition:
+            # format: 'fillnumber 891' or 'stablebeams 1', etc
+            lhcargs = c.split()
+            if len(lhcargs) == 2:
+                key = 'lhc:' + lhcargs[0].strip().lower()
+                # does it exist?
+                if not key in self.ResultKey():
+                    print 'ERROR: unknown LHC variable "%s"' % key
+                    sys.exit(1)                
+
+                cond = lhcargs[1].strip()
+                if cond:
+                    try:
+                        isnum = float(cond[0])
+                        self.lhc[key] = GetRanges( cond )
+                    except ValueError:
+                        self.lhc[key] = [[cond]]
+                        pass
+            else:
+                print 'ERROR: unknown condition format for LHC: "%s" -> need two arguments separated by blank' % lhcargs
+                sys.exit(1)                                    
+
+
+
+    def setShowOutput(self, addArg ):
+        ck = ['lhc:fillnumber', 'lhc:stablebeams', 'lhc:beamenergy']
+        if   addArg == 'all': ck += ['lhc:beammode']
+        elif addArg == 'min': ck = ['lhc:stablebeams']
+        super(LHCCondition,self).setShowOutput()
+                    
+    def __str__(self):
+        if self.applySelection: return "SELOUT Checking if LHC fill state information %s" % self.lhc
+        else: return "Retrieving LHC fill state information"
+
+    def passes(self, value, k):
+        if not k in self.lhc:  return True
+        if 'n.a.' in value:    return True
+        try:
+            v = float(value)
+            # special treatment for E-beam = 7864 --> value for ASYNC
+            if v >= 7864: return False
+            
+            # iterate over conditions
+            for cr in self.lhc[k]:
+                if v >= cr[0] and v <= cr[1]: return True            
+        except ValueError:
+            # value is a string
+            # note that it still can happen that the reference of the string is a number. For example, the
+            # beam energy can be returned as "ASYNC", when the two beams were in asynchronous mode. Need
+            # to cover such a case.
+            try:
+                cmin = float(self.lhc[k][0][0])
+                return False # comparing number to string -> don't pass
+            except ValueError:
+                if value ==  self.lhc[k][0][0]:  return True
+                pass
+            pass
+        return False
+    
+class OLCFillParamsCondition(TimeBasedCondition):
+    def __init__(self, name, condition=[], channel=0):
+        super(OLCFillParamsCondition,self).__init__(name=name,
+                                                    dbfolderkey='COOLONL_TDAQ::/TDAQ/OLC/LHC/FILLPARAMS',
+                                                    channelKeys = [(0,'olc:beam1bunches', 'Beam1Bunches'),
+                                                                   (0,'olc:beam2bunches', 'Beam2Bunches'),
+                                                                   (0,'olc:collbunches',  'LuminousBunches'),
+                                                                   (0,'olc:bcidmask',     'BCIDmasks')])
+        self.onl = {}
+
+    def __str__(self):
+        if self.applySelection: return "SELOUT Checking if online lumi is %s" % self.olc
+        else: return "Retrieving online lumi information /TDAQ/OLC/LHC/FILLPARAMS"
+
+    def passes(self,values,k):
+        if not k in self.onl:      return True
+        if 'n.a.' in values:       return True
+        if values ==  self.onl[k]: return True
+        return False
+    
+    def runAfterQuery(self,runlist):
+        for k in self.ResultKey():
+            with timer("olc afterquery blocks prepare for: %s" % k):
+                for run in runlist:
+                    run.stats[k] = {}
+                    if not k in run.data: continue
+                    blocks = []
+                    for entry in run.data[k]:
+                        v = entry.value
+                        if k!='olc:bcidmask':
+                            v = int(v)
+                        if len(blocks) > 0 and blocks[-1][0]==v and blocks[-1][2]==entry.startlb:
+                            blocks[-1][2] = entry.endlb
+                        else:
+                            blocks += [ [v, entry.startlb, entry.endlb] ]
+                    run.stats[k] = { "blocks" : blocks, "first" : run.data[k][0].value }
+
+
+        with timer("olc afterquery rest"):
+            from CoolRunQuery.utils.AtlRunQueryUtils import UnpackBCID
+            for run in runlist:
+
+                if run.runNr < 151260: continue # OLC information was not in COOL before this run
+
+                # these contain the number of bunches for each IOV [(nb,lbstart,lbend)(...)...]
+                xb1 = run.stats['olc:beam1bunches']['blocks']
+                xb2 = run.stats['olc:beam2bunches']['blocks']
+                xbc = run.stats['olc:collbunches']['blocks']
+                
+                # loop over BCID mask
+                bcidmask = run.stats['olc:bcidmask']['blocks']
+                for i in xrange(len(bcidmask)):
+                    (v,lbstart,lbend) = bcidmask[i]
+                    
+                    # number of bunches
+                    for nb1, b, e in xb1:
+                        if lbstart>=b and lbstart<e: break
+                    for nb2, b, e in xb2:
+                        if lbstart>=b and lbstart<e: break
+                    for nbc, b, e in xbc:
+                        if lbstart>=b and lbstart<e: break
+
+                    # unpack BCID mask
+                    if len(v) == 2 * (nb1 + nb2 + nbc):
+                        beam1, beam2, beam12 = UnpackBCID( v, nb1, nb2, nbc )
+                    else:
+                        print "WARNING, bcidMask inconsistent",nb1, nb2, nbc,"should add up to half of",len(v)
+                        beam1, beam2, beam12 = ([],[],[])
+
+                    # refill run stats
+                    bcidmask[i] = ((nb1, nb2, nbc), (beam1, beam2, beam12), lbstart, lbend)
+
+class OLCLBDataCondition(TimeBasedCondition):
+    def __init__(self, name, condition=[]):
+        super(OLCLBDataCondition,self).__init__(name=name,
+                                                dbfolderkey='COOLONL_TDAQ::/TDAQ/OLC/LHC/LBDATA',
+                                                channelKeys = [(1,'olc:beam1intensity', 'Beam1Intensity'),
+                                                               (1,'olc:beam2intensity', 'Beam2Intensity')])
+                                                               #(1,'olc:beam1intensitybct', 'Beam1IntensityAll'),
+                                                               #(1,'olc:beam2intensitybct', 'Beam2IntensityAll')])
+                                                               #(0,'olc:invlivetime', 'Beam1InvLifetime')])
+                                                               #(0,'olc:invlivetime', 'Beam2InvLifetime')])
+        self.onl = {}
+
+    def __str__(self):
+        if self.applySelection: return "SELOUT Checking if online lumi is %s" % self.olc
+        else: return "Retrieving online lumi information /TDAQ/OLC/LHC/LBDATA"
+
+    def passes(self,values,k):
+        if not k in self.onl:      return True
+        if 'n.a.' in values:       return True
+        if values ==  self.onl[k]: return True
+        return False
+    
+    def runAfterQuery(self,runlist):
+        for k in self.ResultKey():
+            for run in runlist:
+                blocks = []
+                first = 0
+                if len(run.data[k])>0:
+                    for entry in run.data[k]:
+                        v = entry.value
+                        if len(blocks) > 0 and blocks[-1][0]==v and blocks[-1][2]==entry.startlb:
+                            blocks[-1][2] = entry.endlb
+                        else:
+                            blocks += [ [v, entry.startlb, entry.endlb] ]
+                    first = run.data[k][0].value
+                run.stats[k] = { "blocks" : blocks, "first" : first }
+
+# moved from LUMINOSITY timestamp-based to LB-based folder
+#... class OLCLumiCondition(TimeBasedCondition):
+class OLCLumiCondition(RunLBBasedCondition):
+    def __init__(self, name, condition=[], channel=0):        
+
+        self.condition = condition
+        name, sep, channel = name.partition(' ')
+        try:
+            channel = int(channel)
+        except ValueError:
+            channel = 0
+            pass
+
+        # the key
+        # interpret condition: reference luminosity: ub-1, default: ub-1
+        # format: 1ub, 100nb, 1mb+, 1pb-, etc
+        units   = [ 'mb', 'ub', 'nb', 'pb', 'fb', 'ab', 'b' ]
+        factoub = [ 1e-3, 1,   1e3,  1e6,  1e9,  1e12, 1e-6 ]
+        self.complumi = -1
+        self.compsign = +1
+        f             = 1
+        if self.condition:
+            c = self.condition[0].strip()
+            for iu,u in enumerate(units):
+                if u in c:
+                    f = factoub[iu]
+                    c = c.replace(u,'')
+                    break
+            
+            try:
+                if '+' in c:
+                    c = c.replace('+','').strip()
+                    self.complumi = float(c)
+                elif '-' in c:
+                    self.compsign = -1
+                    c = c.replace('-','').strip()
+                    self.complumi = float(c)
+            except ValueError:
+                print "ERROR: in 'olc' condition: %s" % self.condition
+                sys.exit(1)
+        self.complumi *= f # in ub-1
+
+        super(OLCLumiCondition,self).__init__(name=name,
+                                              dbfolderkey='COOLONL_TRIGGER::/TRIGGER/LUMI/LBLESTONL',
+                                              channelKeys = [(channel,'olc:lumi:%i' % (channel), 'LBAvInstLumi')])
+        # -----------------------------------------------------------------------------------------------------------
+        # old, timestamp based folder
+        # super(OLCLumiCondition,self).__init__(name=name,
+        #                                       dbfolderkey='COOLONL_TDAQ::/TDAQ/OLC/LUMINOSITY',
+        #                                       channelKeys = [(channel,'olc:lumi:%i' % channel, 'LBAvInstLumPhys')])
+        # -----------------------------------------------------------------------------------------------------------
+        self.olc = {}
+                    
+    def __str__(self):
+        if self.applySelection: return "SELOUT Checking if online lumi is %s" % self.condition
+        else: return "Retrieving online lumi information /TRIGGER/LUMI/LBLESTONL"
+
+    def passes(self,values,k):
+        return True
+        if not k in self.olc:      return True
+        if 'n.a.' in values:       return True
+
+        if values ==  self.olc[k]: return True
+        return False
+
+    def runAfterQuery(self, runlist):
+
+        # correct "old" runs for uncalibrated luminosity
+        k   = self.ResultKey()[0]  # lumi
+        kst = 'lhc:stablebeams'
+        for ir,run in enumerate(runlist):
+            for entry in run.data[k]:
+                if entry.startlb == 0: continue
+                if entry.value != 'n.a.':
+                    if run.runNr <= 158632: entry.value *= 1.13
+
+        if not self.condition: return
+        
+        # compute integrated luminosity
+        # given is the delivered luminosity in units of 10^30 cm-2 = 1 ub-1
+        # insert events per LB
+        vetolist = []
+        for ir,run in enumerate(runlist):
+            yvecInt = [] # olc per lb in 10^27 cm-2s-1
+            xvecStb = []
+            for entry in run.data[k]:
+                assert entry.startlb != 0, 'entry should not start at LB=0'
+                val = 0
+                if entry.value != 'n.a.':
+                    val = max(0,entry.value) * 1.e3 # unit of val was: 10^30 cm-2 s-1, transform to: 10^27 cm-2s-1
+                lbs = range(entry.startlb,entry.endlb)
+                yvecInt += len(lbs)*[val]
+                    
+                # check LBs with stable beam
+                print run.data[kst].atLB(entry.startlb)
+                stable_beam = run.data[kst].atLB(entry.startlb)[0].value
+                if 'true' in stable_beam.lower():
+                    xvecStb += lbs
+                            
+            # correct for time span
+            intlumi    = 0
+            for idx,(lbtime,lbendtime) in enumerate(run.lbtimes):
+                lb=idx+1                    
+                if lb in xvecStb:
+                    # unit of yvec was: 10^27 cm-2 s-1 -> 10^30 cm-2 = ub-1 
+                    yvecInt[idx] *= (float(lbendtime)-float(lbtime))/1.E9/1000. 
+                    intlumi      += yvecInt[idx]            
+
+            if not (intlumi > self.compsign*self.complumi or -1*intlumi > self.compsign*self.complumi):
+                vetolist.append(ir)
+
+        # remove vetoed runs
+        ic = 0
+        vetolist.sort()
+        for ir in vetolist:
+            del runlist[ir-ic]
+            ic += 1
+    
+    def prettyValue(self, value, key):
+        if value=='n.a.': return value
+        return float(value) # unit is ub-1 s-1
+    
+class OLCLumiSelector(Selector):
+    def __init__(self, name, olclumi=[]):
+        super(OLCLumiSelector,self).__init__(name)
+        self.condition = OLCLumiCondition( 'olclumi', olclumi )
+        if not olclumi:
+            self.condition.applySelection = False
+
+    def setShowOutput(self):
+        self.condition.setShowOutput()
+        
+    def runAfterQuery(self, runlist):
+        self.condition.runAfterQuery( runlist )
+
+    def select(self, runlist):
+        runlist = self.condition.select(runlist)
+        return runlist
+
+class LuminositySelector(RunLBBasedCondition):
+    def __init__(self, name, lumi=None):
+        
+        name, tag = (name.split(None,1) + [""])[:2]
+
+        channel, condtag = self.__interpretTag(tag)
+
+        self._dbfolderkey='COOLOFL_TRIGGER::/TRIGGER/OFLLUMI/LBLESTOFL'
+        if condtag: self._dbfolderkey += "#" + condtag
+
+        self._channelKeys = [(channel,'ofllumi:%i:%s' % (channel,condtag), 'LBAvInstLumi')]
+
+
+        super(LuminositySelector,self).__init__(name=name,
+                                                dbfolderkey = self._dbfolderkey,
+                                                channelKeys = self._channelKeys)
+
+        if lumi:
+            self.cutRange = GetRanges(lumi)        
+            self.applySelection = True
+
+    def addShowTag(self, tag):
+        channel, condtag = self.__interpretTag(tag)
+        self._dbfolderkey='COOLOFL_TRIGGER::/TRIGGER/OFLLUMI/LBLESTOFL'
+        if condtag: self._dbfolderkey += "#" + condtag
+        self._channelKeys = [(channel,'ofllumi:%i:%s' % (channel,condtag), 'LBAvInstLumi')]
+
+    def initialize(self):
+        print "Setting channelkeys",self._channelKeys
+        self.setSchemaFolderTag(self._dbfolderkey)
+        self.setChannelKeys(self._channelKeys)
+
+    def __interpretTag(self, tag):
+        # default settings
+        channel = 0  # 'ATLAS_PREFERRED' algorithm
+#        condtag = "OflLumi-8TeV-002" # uses vdM scan calibration
+        condtag = "OflLumi-UPD2-004" # temporary
+        l = tag.split()
+        if len(l) == 1:
+            # format: "luminosity <channel_number>" OR "luminosity <COOL tag>"
+            try: channel = int(l[0])
+            except ValueError: condtag = l[0]
+        elif len(l) == 2: 
+            # format: "luminosity <channel_number> <COOL tag>"
+            try: channel = int(l[0])
+            except ValueError: channel = 0
+            condtag = l[1]
+        return channel, condtag
+
+
+
+            
+    def __str__(self):
+        if self.applySelection: return "SELOUT Checking if number of events matches %r" % self.cutRange
+        else:                   return "Retrieving lumi numbers"
+
+    def passes(self,values,key):
+        try:
+            val = int(values)
+        except ValueError: # if n.a.
+            self.selDataMissing = True
+            return True
+        for cr in self.cutRange:
+            if val>=cr[0] and val<=cr[1]:
+                return True
+        return False
+
+class BeamspotSelector(RunLBBasedCondition):
+    def __init__(self, name, bs=None, args=""):
+        self.bs = bs
+        args = args.split()
+        
+        # defaults
+        folder       = 'COOLOFL_INDET::/Indet/Beampos'
+        # self.condtag = 'IndetBeampos-ES1-UPD2'
+        self.condtag = 'IndetBeampos-ES1-UPD2-02' # new default tag (operational since rel 17, run 188902, 7 Sep)
+        self.isOffline = True
+
+        if args: # more information: online and/or COOL tag
+            # check if online
+            if args[0].lower().startswith('onl'):
+                # online format: "online MyTag" or "online"
+                self.isOffline = False
+                folder = 'COOLONL_INDET::/Indet/Onl/Beampos'
+                self.condtag = 'IndetBeamposOnl-HLT-UPD1-001-00' # default tag
+                if len(args)>1:
+                    if args[1]=='live':
+                        self.condtag = 'IndetBeamposOnl-LiveMon-001-00'
+                    else:
+                        self.condtag = args[1]
+            else:
+                # assume second entry is COOL tag
+                self.condtag = args[0]
+            
+        super(BeamspotSelector,self).__init__(name        = name,
+                                              dbfolderkey = folder,
+                                              channelKeys = [
+                                                  (0,'bs:Status','status'),
+                                                  (0,'bs:Pos-X', ('posX','posXErr')),
+                                                  (0,'bs:Pos-Y', ('posY','posYErr')),
+                                                  (0,'bs:Pos-Z', ('posZ','posZErr')),
+                                                  (0,'bs:Sig-X', ('sigmaX','sigmaXErr')),
+                                                  (0,'bs:Sig-Y', ('sigmaY','sigmaYErr')),
+                                                  (0,'bs:Sig-Z', ('sigmaZ','sigmaZErr')),
+                                                  (0,'bs:Sig-XY',('sigmaXY','sigmaXYErr')),
+                                                  (0,'bs:Tilt-X',('tiltX','tiltXErr')),
+                                                  (0,'bs:Tilt-Y',('tiltY','tiltYErr'))
+                                                  ])
+
+        if bs: self.cutRange = GetRanges(bs)
+
+    def __str__(self):
+        if self.applySelection: return "SELOUT Checking if %s beamspot information matches %s" % ("offline" if self.isOffline else "online", self.bs)
+        else:                   return "Retrieving %s beamspot information" % ("offline" if self.isOffline else "online",)
+
+    def prettyValue(self, value, key):
+        if type(value)==tuple:
+            return tuple(map(float,value))
+        return float(value)
+
+
+    def passes(self,values,key):
+        try:
+            val = int(values)
+        except ValueError: # if n.a.
+            self.selDataMissing = True
+            return True
+        for cr in self.cutRange:
+            if val>=cr[0] and val<=cr[1]:
+                return True
+        return False
+
+    def runAfterQuery(self,runlist):
+        whatitis = 'offline' if self.isOffline else 'online'
+        from CoolRunQuery.AtlRunQueryRun import Run
+        Run.BeamspotSource = '%s, COOL tag: %s' % (whatitis, self.condtag)
+        for run in runlist:
+            run.stats['Beamspot'] = whatitis
diff --git a/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorMisc.py b/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorMisc.py
new file mode 100644
index 00000000000..481077cd95e
--- /dev/null
+++ b/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorMisc.py
@@ -0,0 +1,335 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+
+import re,sys
+
+from CoolRunQuery.AtlRunQueryRun   import Run
+from CoolRunQuery.utils.AtlRunQueryIOV   import IOVTime, IOVRange
+from CoolRunQuery.utils.AtlRunQueryTimer import timer
+from CoolRunQuery.utils.AtlRunQueryUtils import coolDbConn, runsOnServer, GetRanges, SmartRangeCalulator
+
+from .AtlRunQuerySelectorBase import Selector, Condition, RunLBBasedCondition, TimeBasedCondition, DataKey
+
+
+class FilenameSelector(RunLBBasedCondition):
+    def __init__(self, name, projecttag=None):
+        self.filenametag = projecttag
+        self.fntpatterns = None
+        if projecttag:
+            self.fntpatterns = [re.compile(pt.strip().replace('*','.*').replace('?','.'),re.I) for pt in projecttag.split(',')]
+        super(FilenameSelector,self).__init__(name=name,
+                                              dbfolderkey='COOLONL_TDAQ::/TDAQ/RunCtrl/SOR_Params',
+                                              channelKeys = [(0, 'Project tag','FilenameTag')])
+    def __str__(self):
+        if self.applySelection: return 'SELOUT Checking if the filename tag matches "%s"' % self.filenametag
+        else: return "Retrieving filenametag"
+    def passes(self,value,key):
+        for p in self.fntpatterns:
+            if p.match(value): return True
+        return False
+
+class PartitionSelector(RunLBBasedCondition):
+    def __init__(self, name, partition=None):
+        self.partition = partition
+        super(PartitionSelector,self).__init__(name=name,
+                                               dbfolderkey='COOLONL_TDAQ::/TDAQ/RunCtrl/EventCounters',
+                                               channelKeys = [(0,'Partition','PartitionName')])
+
+    def __str__(self):
+        if self.applySelection: return 'SELOUT Checking if partition name matches "%s"' % self.partition
+        else: return "Retrieving partition name"
+
+    def passes(self,value,key):
+        if value=='n.a.':
+            self.selDataMissing = True
+            return True
+        return value==self.partition
+
+class ReadyForPhysicsSelector(RunLBBasedCondition):
+    def __init__(self, name, readyforphysics=None):
+        self.readyforphysics = readyforphysics
+        super(ReadyForPhysicsSelector,self).__init__(name=name,
+                                                     dbfolderkey='COOLONL_TDAQ::/TDAQ/RunCtrl/DataTakingMode',
+                                                     channelKeys = [(0,'Ready for physics','ReadyForPhysics')])
+
+    def __str__(self):
+        if self.applySelection: return 'SELOUT Checking if ReadyForPhysics flag matches "%s"' % self.readyforphysics
+        else: return "Retrieving ReadyForPhysics flag"
+
+    def passes(self,value,key):
+        if value=='n.a.':
+            self.selDataMissing = True
+            return True
+        return value==self.readyforphysics
+
+
+class DurationSelector(Selector):
+    def __init__(self,name,duration):
+        self.geReq = (duration[-1]!='-')
+        self.duration = int(duration.rstrip('+-'))
+        super(DurationSelector,self).__init__(name)
+    def __str__(self):
+        return "SELOUT Checking if duration of run is %s than %i seconds" % ("more" if self.geReq else "less",self.duration)
+    def select(self, runlist):
+        print self,
+        sys.stdout.flush()
+        if self.geReq:
+            rmlist = [r for r in runlist if (r.eor-r.sor)/1E9<self.duration]
+        else:
+            rmlist = [r for r in runlist if (r.eor-r.sor)/1E9>self.duration]
+        for r in rmlist: runlist.remove(r)
+        if self.applySelection: print " ==> %i runs selected" % len(runlist)
+        return runlist
+
+
+class DetectorSelector(RunLBBasedCondition):
+    def __init__(self, name, dmin=None, dmout=None):
+        self.bm = self.bp = self.bmany = 0
+        if not dmin: dmin = []
+        if not dmout: dmout = []
+        for m in dmin+dmout:
+            if 'A' in m: continue
+            self.bm |= int(m)
+        for m in dmin:
+            if 'A' in m: continue
+            self.bp |= int(m)
+        for m in dmin:
+            if not 'A' in m: continue
+            self.bmany |= int(m.rstrip('A'))
+
+        super(DetectorSelector,self).__init__(name=name,
+                                              dbfolderkey='COOLONL_TDAQ::/TDAQ/RunCtrl/SOR_Params',
+                                              channelKeys = [(0, 'Detector systems', 'DetectorMask')])
+
+        self.data_keys[0]._type = DataKey.DETECTOR
+
+
+
+    def __str__(self):
+        if self.applySelection:
+            if self.bm!=0 and self.bmany!=0:
+                return "SELOUT Checking if [detector mask & %i] matches %i and [detector mask & %i] is greater 0" % (self.bm,self.bp,self.bmany)
+            elif self.bm==0:
+                return "SELOUT Checking if [detector mask & %i] is greater 0" % self.bmany
+            else:
+                return "SELOUT Checking if [detector mask & %i] matches %i" % (self.bm,self.bp)
+        else: return "Retrieving detector mask"
+
+    def passes(self,values,key):
+        try:
+            val = int(values)
+        except ValueError:
+            self.selDataMissing = True
+            return True
+        retval = True
+        if self.bm!=0:    retval &= ((val & self.bm) == self.bp)
+        if self.bmany!=0: retval &= ((val & self.bmany) != 0)
+        return retval
+
+    def prettyValue(self, value, key):
+        return  value
+
+
+
+
+class BFieldCondition(TimeBasedCondition):
+    def __init__(self, name, condition=None, channel=0, resDictKey=''):
+        super(BFieldCondition,self).__init__(name,
+                                             dbfolderkey='COOLOFL_DCS::/EXT/DCS/MAGNETS/SENSORDATA',
+                                             channelKeys = [(channel,resDictKey,'value')])
+        if condition:
+            self.cutRange = GetRanges(condition)
+    def __str__(self):
+        if self.applySelection:
+            if self.cutRange[0][1] > 1000000: txt = '[%.0f,+inf]' % (self.cutRange[0][0])
+            else:                             txt = '[%.0f,%0.f]' % (self.cutRange[0][0],self.cutRange[0][1])
+            return "SELOUT Checking if the %s is within %s" % (', '.join(self.ResultKey()), txt)
+        else: return "Retrieving magnet currents %s" % self.ResultKey()
+
+    def passes(self,values,key):
+        try:
+            val = abs(float(values))
+        except ValueError:
+            self.selDataMissing = True
+            return True            
+        for cr in self.cutRange:
+            if val>=cr[0] and val<=cr[1]: return True
+        return False
+    
+    def prettyValue(self, value, key):
+        if value=='n.a.': return value
+        return round(float(value),2)
+
+
+class BFieldSelector(Selector):
+    def __init__(self, name, bf=None):
+        super(BFieldSelector,self).__init__(name)
+        self.conditions = []
+        if bf:
+            if 'solenoidon' in bf or 'solenoidoff' in bf:
+                tmp = []
+                if   'solenoidon'  in bf: tmp += ['7700+']
+                elif 'solenoidoff' in bf: tmp += ['10-']
+                self.conditions += [ BFieldCondition('csolcur', ','.join(tmp), channel = 1, resDictKey = 'SolCurrent') ]
+            if 'toroidon' in bf or 'toroidoff' in bf:
+                tmp = []
+                if   'toroidon'  in bf: tmp += ['20000+']
+                elif 'toroidoff' in bf: tmp += ['10-']
+                self.conditions += [ BFieldCondition('ctorcur', ','.join(tmp), channel = 3, resDictKey = 'TorCurrent') ]
+        else:
+            self.conditions += [ BFieldCondition('csolcur', channel = 1, resDictKey = 'SolCurrent') ]
+            self.conditions += [ BFieldCondition('ctorcur', channel = 3, resDictKey = 'TorCurrent') ]
+            for sel in self.conditions:
+                sel.setShowOutput()
+                sel.applySelection = False
+
+    def __str__(self):
+        s = ""
+        for sel in self.conditions:
+            s += "\n%s" % sel
+        return s
+
+    def setShowOutput(self):
+        for cond in self.conditions:
+            cond.setShowOutput()
+
+    def addShowSelector(self):
+        sol = tor = None
+        for s in self.conditions:
+            if s.name == 'csolcur': sol = s
+            if s.name == 'ctorcur': tor = s
+        if not sol:
+            sol = BFieldCondition('csolcur', channel = 1, resDictKey = 'SolCurrent')
+            sol.applySelection = False
+            self.conditions += [ sol ]
+        if not tor:
+            tor = BFieldCondition('ctorcur', channel = 3, resDictKey = 'TorCurrent')
+            tor.applySelection = False
+            self.conditions += [ tor ]
+        sol.setShowOutput()
+        tor.setShowOutput()
+            
+    def select(self, runlist):
+        for sel in self.conditions:
+            runlist = sel.select(runlist)
+        return runlist
+
+
+class BPMSelector(Selector):
+    def __init__(self, name, events=None):
+        self.name = name
+        self.selpattern = []
+        super(BPMSelector,self).__init__(name)
+
+    def __str__(self): return "Retrieving Beam Position Monitor values from PVSS archive"
+    def passes(self,values,key): return True
+    def setShowOutput(self): pass
+    def select(self, runlist): return runlist
+    
+    def runAfterQuery(self,runlist):
+        # do show selection here
+        from CoolRunQuery.AtlRunQueryPVSS import GetPVSS_BPMs
+        pvssdb = coolDbConn.GetPVSSDBConnection()
+        cursor = pvssdb.cursor()
+        cursor.arraysize = 1000
+
+        pvssretdico = {}
+        for r in runlist:
+            t = gmtime(r.sor/1.E9)
+            sor = "%02i-%02i-%4i %02i:%02i:%02i" % (t[2], t[1], t[0], t[3], t[4], t[5])
+            t = gmtime(r.eor/1.E9)
+            eor = "%02i-%02i-%4i %02i:%02i:%02i" % (t[2], t[1], t[0], t[3], t[4], t[5])
+            
+            # retrieve values
+            res = GetPVSS_BPMs( cursor, sor, eor )
+            r.addResult('BPM', res )
+
+        Run.AddToShowOrder(DataKey('BPM'))
+
+
+
+class DatasetsSelector(Selector):
+    def __init__(self, name, events=None):
+        self.name = name
+        self.selpattern = []
+        self.showCAFLinks = False
+        super(DatasetsSelector,self).__init__(name)
+
+    def __str__(self): return "Retrieving datasets from Tier-0 DB"
+    def passes(self,values,key): return True
+    def setShowOutput(self): pass
+    def select(self, runlist): return runlist
+    def addShowDatasetPattern(self, pattern = ''):
+        # format: '*NTUP*,*dESD*,... [caf]'
+        if pattern.lower() == 'caf':
+            self.showCAFLinks = True
+        elif pattern:
+            # first check if 'caf'
+            sp = pattern.split()
+            if len(sp)>1:
+                if 'caf' == sp[0].lower():
+                    self.showCAFLinks = True
+                    pattern = sp[1]
+                elif 'caf' == sp[1].lower():
+                    self.showCAFLinks = True
+                    pattern = sp[0]
+                # sanity check
+                if len(sp) != 2 or not self.showCAFLinks:
+                    print 'ERROR: wrong format in "show dataset". Usage: "show dataset [pattern] [caf]"'
+                    sys.exit(1)
+                                       
+            self.selpattern = pattern.split(',')
+    
+    def runAfterQuery(self,runlist):
+        # do show selection here
+        from CoolRunQuery.AtlRunQueryTier0 import GetTier0_allDatasets
+        runnrlist = [r.runNr for r in runlist]
+        tier0connection  = coolDbConn.GetTier0DBConnection()
+        tier0retdico     = GetTier0_allDatasets( tier0connection.cursor(), runnrlist, self.selpattern )
+
+        for run in runlist: # go through old runlist and see
+            if tier0retdico.has_key( run.runNr ):
+                run.addResult('Datasets', tier0retdico[run.runNr])
+            else:
+                run.addResult('Datasets', {})
+
+        Run.AddToShowOrder(DataKey('Datasets'))
+        Run.showCAFLinks  = self.showCAFLinks
+
+
+
+class LArcondSelector(RunLBBasedCondition):
+    def __init__(self, name, larcond=[]):
+        super(LArcondSelector,self).__init__(name=name,
+                                             dbfolderkey='COOLONL_LAR::/LAR/Configuration/RunLog',
+                                             channelKeys = [(0,'lar:runtype',  'runType'),
+                                                            (0,'lar:nsamples', 'nbOfSamples'),
+                                                            (0,'lar:format',   'format')])
+        # define arguments (after initialising bas class!)
+        self.larcond = {}
+        if larcond:
+            for c in larcond:
+                # format: 'nsamples 7' or 'runtype 1', etc
+                larcondargs = c.split()
+                if len(larcondargs) == 2:
+                    key = 'lar:' + larcondargs[0].strip().lower()
+                    # does it exist?
+                    if not key in self.ResultKey():
+                        print 'ERROR: unknown larcond variable "%s"' % key
+                        sys.exit(1)                
+                    self.larcond[key] = larcondargs[1].strip()
+                else:
+                    print 'ERROR: unknown condition format for larcond: "%s" -> need two arguments separated by blank' % larcondargs
+                    sys.exit(1)                
+                    
+                    
+    def __str__(self):
+        if self.applySelection: return "SELOUT Checking if LAr condition matches %s" % self.larcond
+        else: return "Retrieving LAr run conditions"
+
+    def passes(self,values,key):
+        if self.larcond.has_key(key.lower().strip()):
+            if values.strip() ==  self.larcond[key.lower().strip()]: return True
+            else:                                                    return False
+        return True
+
diff --git a/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorRuntime.py b/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorRuntime.py
new file mode 100644
index 00000000000..86e273b52bd
--- /dev/null
+++ b/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorRuntime.py
@@ -0,0 +1,133 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+
+from time import time
+import sys
+
+from PyCool import cool
+
+from CoolRunQuery.utils.AtlRunQueryIOV   import IOVTime, IOVRange
+from CoolRunQuery.utils.AtlRunQueryTimer import timer
+from CoolRunQuery.utils.AtlRunQueryUtils import coolDbConn, runsOnServer, GetRanges, SmartRangeCalulator
+
+from .AtlRunQuerySelectorBase import Selector, Condition, RunLBBasedCondition, TimeBasedCondition, DataKey
+
+from CoolRunQuery.AtlRunQueryRun         import Run
+
+class RunTimeSelector(Selector):
+    def __init__(self, name, runlist):
+        super(RunTimeSelector,self).__init__(name)
+        if not runlist: runlist = ['-']
+        runlist = ','.join(runlist).split(',')
+        runlist = [rr for rr in runlist if not rr.startswith('last')]
+        self.runranges = GetRanges(','.join(runlist))
+
+    def __str__(self):
+        rr = []
+        for r in self.runranges:
+            if r[0]==r[1]: rr += [ str(r[0]) ]
+            elif r[0]==r[1]-1: rr += [ '%i, %i' % tuple(r) ]
+            else: rr += [ '%i-%i' % tuple(r) ]
+        return "SELOUT Checking for runs in %s" % ', '.join(rr)
+
+
+    def select(self):
+        runlist = []
+        
+        start = time()
+        folder = coolDbConn.GetDBConn(schema="COOLONL_TRIGGER",db=self.db).getFolder('/TRIGGER/LUMI/LBLB')
+        print self,
+        sys.stdout.flush()
+        currentRun = None
+        for rr in self.runranges:
+            objs = folder.browseObjects( rr[0] << 32, ((rr[1]+1) << 32)-1, cool.ChannelSelection(0))
+            while objs.goToNext():
+                obj=objs.currentRef()
+                payload=obj.payload()
+                runNr,lbNr = RunTimeSelector.runlb(obj.since())
+                if lbNr==0: lbNr=1 # this is an aweful hack to make MC work (there only one LB exists in LBLB and it is nr 0) need to rethink this
+                if not currentRun or runNr > currentRun.runNr:
+                    if currentRun:
+                        currentRun.eor = currentEOR
+                        runlist.append(currentRun)
+                    currentRun = Run(runNr)
+                    currentRun.sor = payload['StartTime']
+                currentRun.lbtimes.extend([(0,0)]*(lbNr-len(currentRun.lbtimes)))
+                currentRun.lbtimes[lbNr-1] = ( payload['StartTime'], payload['EndTime'] )
+                currentRun.lastlb = lbNr
+                currentEOR = payload['EndTime']
+        if currentRun:
+            currentRun.eor = currentEOR
+            runlist.append(currentRun)
+        runlist.sort()
+
+        duration = time() - start
+        print " ==> %i runs found (%.2f sec)" % (len(runlist),duration)
+        return runlist
+
+    @staticmethod
+    def runlb(time):
+        run = time>>32
+        lb = time&0xFFFFFFFF
+        return (run,lb)
+
+    def runNrFromTime(self,timeiov):
+        listOfCoveredRuns = []
+        runlist = self.runTimes.keys()
+        runlist.sort()
+        lastEOR = 0
+        for rt in runlist:
+            x = self.runTimes[rt]
+            if timeiov[0]>=x[0] and timeiov[1]<x[1] or timeiov[0]<x[0] and timeiov[1]>x[0]:
+                listOfCoveredRuns += [rt]
+                lastEOR = x[1]
+        return (listOfCoveredRuns,lastEOR)
+
+        
+class TimeRunSelector(Selector):
+    def __init__(self, name, timelist):
+        super(TimeRunSelector,self).__init__(name)
+        self.timelist = ','.join(timelist)
+        
+    def select(self):
+        start = time()
+        runlist = []
+        folder = coolDbConn.GetDBConn(schema="COOLONL_TRIGGER", db=self.db).getFolder('/TRIGGER/LUMI/LBTIME')
+        print 'SELOUT Checking for runs in time range "%s"' % self.timelist,
+        sys.stdout.flush()
+        ranges = GetRanges(self.timelist, maxval=long(time()*1E09))
+        currentRun = None
+        for rr in ranges:
+            objs = folder.browseObjects( rr[0], rr[1]+86400000000000L, cool.ChannelSelection(0))
+            while objs.goToNext():
+                obj=objs.currentRef()
+                payload=obj.payload()
+                runNr = int(payload['Run'])
+                if runNr==0: continue # mistakenly runnr=0 was stored 
+                
+                if runNr>1<<30:
+                    # there is a problem with runs between
+                    # usetimes 2009-04-14:00:00:00 2009-04-16:13:00:00
+                    # there the runnumbers are off the chart (> 1<<30)
+                    continue
+
+                if not currentRun or runNr != currentRun.runNr:
+                    if currentRun:
+                        currentRun.eor = currentEOR
+                        runlist.append(currentRun)
+                    currentRun = Run(runNr)
+                    currentRun.sor = obj.since()
+                lbNr = int(payload['LumiBlock'])
+                currentRun.lbtimes.extend([(0,0)]*(lbNr-len(currentRun.lbtimes)))
+                currentRun.lbtimes[lbNr-1] = ( obj.since(), obj.until() )
+                currentRun.lastlb = lbNr
+                currentEOR = obj.until()
+        if currentRun:
+            currentRun.eor = currentEOR
+            runlist.append(currentRun)
+
+        runlist.sort()
+        duration = time() - start
+        print " ==> %i runs selected (%g sec)" % (len(runlist), duration)
+        return runlist
+
diff --git a/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorStreams.py b/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorStreams.py
new file mode 100644
index 00000000000..abeb32bc51d
--- /dev/null
+++ b/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorStreams.py
@@ -0,0 +1,303 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+
+import re, sys
+try:
+    Set = set
+except NameError:
+    from sets import Set
+from time import time
+
+from CoolRunQuery.utils.AtlRunQueryIOV   import IOVTime, IOVRange
+from CoolRunQuery.utils.AtlRunQueryTimer import timer
+from CoolRunQuery.utils.AtlRunQueryUtils import coolDbConn, runsOnServer, GetRanges, SmartRangeCalulator
+
+from .AtlRunQuerySelectorBase import Selector, Condition, RunLBBasedCondition, TimeBasedCondition, DataKey
+
+from CoolRunQuery.AtlRunQueryRun         import Run
+
+
+class StreamSelector(Selector):
+    def __init__(self, name, streams=[]):
+        # streams can be ["*RPC*", "phy* 10k", "deb*,cal* 100k"]
+        #    will select runs that satiesfy an 'and' of all patterns in the list
+        # a pattern without number are checked for existence
+        # a pattern with number will be checked against the sum of the events in all matching streams
+
+        self.streams = ' and '.join(streams)
+        self.selstreamspatterns = []
+        self.showstreampatterns = []
+
+        # selstreampatterns is a list of (pattern,nevents) tuples
+        for s in streams:
+            pattern = s.split()[0].replace(',','|').replace('*','.*').replace('%','.*').replace('?','.')
+            negate  = pattern[0]=='!'
+            pattern = pattern.lstrip('!')
+            p = re.compile(pattern)
+            nevt = (s.split()+[None])[1]
+            self.selstreamspatterns += [(p,nevt,negate,pattern)]
+        
+        super(StreamSelector,self).__init__(name)
+
+    def setShowOutput(self):
+        pass
+
+    def addShowStreamPattern(self, streampattern="*"):
+        self.showstreampatterns += streampattern.replace('*','.*').replace('%','.*').replace('?','.').split(',')
+
+    def __str__(self):
+        if len(self.streams)!=0: return 'SELOUT Checking if the stream name matches "%s"' % self.streams
+        else: return "Retrieving stream names that match '%s'" % ','.join(self.showstreampatterns)
+
+    def select(self, runlist):
+
+        # some preparation: compile the show patterns
+        start = time()
+
+        if '.*' in self.showstreampatterns:
+            compiledShowPatterns = [re.compile('.*')]
+        else:
+            compiledShowPatterns = [re.compile(p) for p in self.showstreampatterns]
+
+        # we disable the access to everything that is not needed if we only select
+        ShowStreams = False
+        useTier0    = False
+        if len(compiledShowPatterns)>0:
+            ShowStreams = True
+            useTier0 = True
+        
+
+        print self,
+        sys.stdout.flush()
+        newrunlist = []
+        allStreams = Set()  # list of all the streams that are in the selected runs
+        connection = coolDbConn.GetSFODBConnection()
+        cursor     = connection.cursor()
+        cursor.arraysize = 1000
+
+        runnrlist = [r.runNr for r in runlist]
+
+        from CoolRunQuery.AtlRunQuerySFO import GetSFO_streamsAll,GetSFO_filesAll
+        with timer('GetSFO_streamsAll'):
+            streamsall = GetSFO_streamsAll( cursor, runnrlist )  # { runnr: [streams] }
+        with timer('GetSFO_filesAll'):
+            filesall   = GetSFO_filesAll( cursor, runnrlist )    # [(COUNT(FILESIZE), SUM(FILESIZE), SUM(NREVENTS))]
+
+        if ShowStreams:
+            from CoolRunQuery.AtlRunQuerySFO import GetSFO_LBsAll,GetSFO_NeventsAll,GetSFO_overlapAll
+            with timer('GetSFO_LBsAll'):
+                lbinfoall  = GetSFO_LBsAll( cursor, runnrlist )      # [(MIN(LUMIBLOCKNR), MAX(LUMIBLOCKNR), #LUMIBLOCKS)]
+            with timer('GetSFO_overlapAll'):
+                overlapall = GetSFO_overlapAll( cursor, runnrlist )  # [(SUM(OVERLAP_EVENTS))]
+            smallrunnrlist=[]
+            for r in runnrlist: # go through old runlist and see
+                if not r in streamsall: continue
+                for s in streamsall[r]:
+                    if r in lbinfoall and s in lbinfoall[r] and lbinfoall[r][s][1]>0:
+                        smallrunnrlist += [r]
+                        break
+            with timer('GetSFO_NeventsAll'):
+                neventsall = GetSFO_NeventsAll( cursor, smallrunnrlist )  # [(LUMIBLOCKNR, NREVENTS)]
+
+
+        
+        for run in runlist: # go through old runlist and see
+            
+            streams   = []  # names of all streams in this run
+            strsize   = []  # size of streams in this run
+            strevents = []  # nr of events in this run
+            if run.runNr in streamsall:
+                streams   = streamsall[run.runNr]
+            for s in streams:
+                try: nfiles, size, events = filesall[run.runNr][s]
+                except: nfiles, size, events = (0,0,0)
+                strsize   += [size]
+                strevents += [events]
+
+
+
+            if ShowStreams:
+                from CoolRunQuery.utils.AtlRunQueryUtils import Matrix
+
+                nst       = len(streams)
+                stovmat   = Matrix(nst,nst)  # overlap matrix
+                for i,s in enumerate(streams):
+                    run.stats['STR:'+s] = {}
+
+                    # fill overlaps into matrix
+                    for j,s2 in enumerate(streams):
+                        try: eventsij = overlapall[run.runNr][s][s2]
+                        except KeyError:
+                            eventsij = 0
+                            if i==j and events:
+                                eventsij = events
+                        stovmat.setitem(i,j,float(eventsij))
+                        stovmat.setitem(j,i,float(eventsij)) # symmetrise matrix
+
+
+                    # read number of events per LB
+                    minlb, maxlb, lbs = (0,0,1)
+                    try: minlb, maxlb, lbs = lbinfoall[run.runNr][s]
+                    except KeyError: pass
+
+                    # if minlb==maxlb==0 -> no file closure at LB boundary
+                    if minlb == 0 and maxlb == 0:
+                        run.stats['STR:'+s]['LBRecInfo'] = None;
+                        continue
+                    else:
+                        lbevcount = '<tr>'
+                        result = neventsall[run.runNr][s] #[ (lb,nev),... ]
+                        lbold = -1
+                        allnev = 0
+                        ic = 0
+                        ice = 0
+                        allic = 0
+                        lastElement = False
+                        firstcall = True
+
+                        for ice,(lb,nev) in enumerate(result):
+                            if ice == len(result):
+                                lastElement = True
+                                allnev += nev
+                            if lb != lbold or lastElement:
+                                if lbold != -1:
+                                    ic += 1
+                                    allic += 1
+                                    if allic < 101:
+                                        if ic == 9:
+                                            ic = 1
+                                            lbevcount += '</tr><tr>'
+                                        lbevcount += '<td style="font-size:75%%">%i&nbsp;(%s)</td>' % (lbold,allnev)
+                                    else:
+                                        if firstcall:
+                                            lbevcount += '</tr><tr>'
+                                            lbevcount += '<td style="font-size:75%%" colspan="8">... <i>too many LBs (> 100) to show</i></td>'
+                                            firstcall = False                                        
+                                allnev = nev
+                                lbold = lb
+                            else:
+                                allnev += nev
+                        lbevcount += '</tr>'
+                        run.stats['STR:'+s]['LBRecInfo'] = lbevcount
+                        run.stats['STR:'+s]['LBRecInfo'] = result
+
+                # add overlap information to the run stats
+                for i in xrange(nst):
+                    statkey = 'STR:'+streams[i]
+                    run.stats[statkey]['StrOverlap'] = []
+                    denom = stovmat.getitem(i,i)
+                    if denom==0: continue
+                    for j in xrange(nst):
+                        if i == j or stovmat.getitem(i,j) == 0: continue
+                        fraction = 100
+                        if stovmat.getitem(i,j) != denom:
+                            fraction = float(stovmat.getitem(i,j))/float(denom)*100.0
+                        run.stats[statkey]['StrOverlap'] += [(streams[j], fraction)]
+
+
+
+            # selection...
+            if not self.passes(zip(streams,strevents),0): continue
+            newrunlist += [run.runNr]
+            allStreams.update(streams)
+            for k,v,s in zip(streams,strevents,strsize):
+                run.addResult('STR:'+k, (v,s))
+
+
+
+
+        allStreams = ['STR:'+s for s in allStreams]
+        allStreams.sort(lambda x,y: 2*cmp(y[4],x[4]) + cmp(x[5:],y[5:]))
+
+        # fill the gaps
+        for run in runlist:
+            for s in allStreams:
+                if not s in run.result:
+                    run.addResult(s, 'n.a.')
+
+        runlist = [r for r in runlist if r.runNr in newrunlist]
+
+        # check if the streams in 'allStreams' match the show patterns
+        for s in allStreams:
+            if any( [p.match(s[4:])!=None for p in compiledShowPatterns] ):
+                Run.AddToShowOrder(DataKey(s, keytype=DataKey.STREAM))
+
+
+
+
+        if useTier0:
+
+            # retrieve Tier-0 information
+            from CoolRunQuery.AtlRunQueryTier0 import GetTier0_datasetsAndTypes
+            tier0connection  = coolDbConn.GetTier0DBConnection()
+            cursor = tier0connection.cursor()
+            cursor.arraysize = 1000
+            tier0retdico     = GetTier0_datasetsAndTypes( cursor, runnrlist )
+
+            # add Tier0 information
+            for run in runlist:
+                for s in allStreams:
+                    if run.result[s]=='n.a.': continue
+                    run.stats[s]['StrTier0TypesRAW'] = {}
+                    run.stats[s]['StrTier0TypesESD'] = {}
+                    run.stats[s]['StrTier0AMI'] = {}
+                    if run.runNr in tier0retdico.keys(): 
+                        for dsname,t,pstates in tier0retdico[run.runNr]:
+                            if s.replace('STR:','') in dsname:                                    
+                                if '.RAW' in dsname:
+                                    if '.merge' in dsname:
+                                        prodstep = 'StrTier0TypesESD'
+                                        t        = '(RAW)'
+                                    else:
+                                        prodstep = 'StrTier0TypesRAW'
+                                        t        = '(RAW)'
+                                else:
+                                    if '.recon.' in dsname:
+                                        prodstep = 'StrTier0TypesRAW'
+                                    else:
+                                        prodstep = 'StrTier0TypesESD'
+                                    if not run.stats[s]['StrTier0AMI'].has_key( prodstep ):
+                                        dsnamesplit = dsname.split('.')
+                                        if len(dsnamesplit)>5:
+                                            amitag = dsnamesplit[5]
+                                            run.stats[s]['StrTier0AMI'][prodstep] = amitag
+                                        else:
+                                            amitag = ''
+                                # check if on CAF
+                                oncaf = False
+                                if pstates and 'replicate:done' in pstates: oncaf = True
+
+                                # fill the run stats
+                                if not run.stats[s][prodstep].has_key(t): run.stats[s][prodstep][t] = oncaf
+
+
+        # Done
+        duration = time() - start
+        if len(self.streams)!=0: print " ==> %i runs found (%.2f sec)" % (len(runlist),duration)
+        else:                    print " ==> Done (%g sec)" % duration
+        return runlist
+
+    def passes(self,streamevents,key):
+        # streamevents is  [('physics_L1Calo', 87274, False), ('physics_RPCwBeam', 1075460, True), ('debug_hlterror', 151, False),...]
+        for streampattern, neventreq, negate, pattern in self.selstreamspatterns:
+            nevents = 0
+            foundmatchingStream = False
+            for se in streamevents:
+                if streampattern.match(se[0]):
+                    nevents += se[1]
+                    foundmatchingStream = True
+            if neventreq:
+                if neventreq[-1] in '+-':
+                    if neventreq[-1] == '-': passreq = nevents<int(req[1][:-1])
+                    else: passreq = nevents>int(neventreq[:-1])
+                else:
+                    passreq = nevents>int(neventreq)
+            else:
+                if negate:
+                    passreq = not foundmatchingStream
+                else:
+                    passreq = foundmatchingStream
+            if not passreq:
+                return False
+        return True
+
diff --git a/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorTrigger.py b/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorTrigger.py
new file mode 100644
index 00000000000..28e53b85fb6
--- /dev/null
+++ b/Database/CoolRunQuery/python/selector/AtlRunQuerySelectorTrigger.py
@@ -0,0 +1,588 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+"""Provides Trigger related selectors:
+
+TriggerSelector      Trigger menu from TriggerDB
+TrigKeySelector      SMK
+BGSKeySelector       BGK
+L1TrigKeySelector    L1PSK
+HLTTrigKeySelector   HLTPSK
+RatesSelector        L1 rates from COOL
+
+"""
+
+import re,sys
+
+from time import time,strftime,gmtime
+from collections import defaultdict
+
+from PyCool import cool
+
+from CoolRunQuery.selector.AtlRunQuerySelectorBase    import Selector, RunLBBasedCondition
+from CoolRunQuery.utils.AtlRunQueryUtils           import coolDbConn, GetRanges, SmartRangeCalulator
+
+
+class TrigKeySelector(RunLBBasedCondition):
+    def __init__(self, name):
+        self.showRelease  = False
+        self.showTrigKeys = False
+        self.smkCutRange  = None
+        self.relCutRange  = None
+        self.trigkeys     = None
+        self.release      = None
+        super(TrigKeySelector,self).__init__(name=name,
+                                             dbfolderkey='COOLONL_TRIGGER::/TRIGGER/HLT/HltConfigKeys',
+                                             channelKeys = [(0,'SMK','MasterConfigurationKey'),
+                                                            (0,'Release','ConfigSource')])
+        self.applySelection = False
+
+    def setSelectSMK(self,smks):
+        self.trigkeys = smks
+        if self.trigkeys:
+            self.smkCutRange = GetRanges(self.trigkeys)
+            self.applySelection = True
+
+    def setSelectRelease(self,release):
+        self.release = release
+        if self.release:
+            self.relCutRange = GetRanges(','.join(self.release), intRepFnc=self.relStringToInt)
+            self.applySelection = True
+
+    def setShow(self, what):
+        if what == 'smk':
+            super(TrigKeySelector,self).setShowOutput('SMK')
+        if what == 'release':
+            super(TrigKeySelector,self).setShowOutput('Release')
+
+    def relStringToInt(self, r):
+        major, minor, sub, patch = ([int(x) for x in r.split('.')] + [0,0,0,0])[0:4]
+        if sub<10: sub*=10;
+        return 1000000*major+10000*minor+100*sub+patch
+    
+    def __str__(self):
+        if self.applySelection:
+            if self.trigkeys and self.release:
+                return 'SELOUT Checking if SMK matches "%s" and release matches "%s"' % (self.trigkeys,self.release)
+            elif self.trigkeys:
+                return 'SELOUT Checking if SMK matches "%s"' % self.trigkeys
+            else:
+                return 'SELOUT Checking if release matches "%s"' % (self.release)
+        else:
+            if self.showTrigKeys and self.showRelease:
+                return "Retrieving SMK and release version"
+            elif self.showTrigKeys:
+                return "Retrieving SMK"
+            else:
+                return "Retrieving release version"
+
+    def passes(self,values,key):
+        if self.smkCutRange:
+            smkPass = False
+            try: val = int(values)
+            except ValueError:
+                self.selDataMissing = True
+                smkPass = True
+            else:
+                for cr in self.smkCutRange:
+                    if val>=cr[0] and val<=cr[1]: smkPass= True
+            if not smkPass: return False
+        if self.relCutRange:
+            relPass = False
+            val = values[1]
+            if val=='n.a.':
+                self.selDataMissing = True
+                relPass = True
+            else:
+                val = val.split(',')
+                if len(val)>1:
+                    val = self.relStringToInt(val[1])
+                    for cr in self.relCutRange:
+                        if val>=cr[0] and val<=cr[1]: relPass= True
+                else:
+                    self.selDataMissing = True
+                    relPass = True
+            if not relPass: return False
+        return True
+
+    def prettyValue(self, value, key):
+        if key=='Release' and value!="n.a." and ',' in value:
+            return value.split(',')[1]
+        return value
+
+    def runAfterQuery(self,runlist):
+        for k in self.ResultKey():
+            if k != 'SMK': continue
+            smks = set()
+            for run in runlist:
+                smk = run.result['SMK']
+                if not str.isdigit(smk): continue
+                smks.add(int(smk))
+
+            from CoolRunQuery.utils.AtlRunQueryTriggerUtils import getSmkNames, getRandom
+            smknames = getSmkNames(smks)
+
+            for run in runlist:
+                smk = run.result['SMK']
+                info = list(smknames[int(smk)] if str.isdigit(smk) else ("","",""))
+                if info[2]=="" or info[2]=="~": info[2]="no comment"
+                run.stats[k] = { "info" : tuple(info),
+                                 "random" : getRandom(smk) }
+
+
+class BGSKeySelector(RunLBBasedCondition):
+    def __init__(self, name):
+        self.showBGKeys = False
+        super(BGSKeySelector,self).__init__(name=name,
+                                            dbfolderkey='COOLONL_TRIGGER::/TRIGGER/LVL1/BunchGroupKey',
+                                            channelKeys = [(0,'BGS Key','Lvl1BunchGroupConfigurationKey')])
+    def __str__(self):
+        return "Retrieving Bunch group set key"
+
+    def passes(self,values,key):
+        return True
+
+    def prettyValue(self, value, key):
+        if not str.isdigit(value): return None
+        return int(value)
+
+    def runAfterQuery(self,runlist):
+        for k in self.ResultKey():
+            for run in runlist:
+                run.stats[k] = { "blocks" : [], "first" : 0 }
+                entries = run.data[k]
+                if len(entries)==0: continue
+                blocks = []
+                for entry in entries:
+                    v = entry.value
+                    if len(blocks) > 0 and blocks[-1][0]==v and blocks[-1][2]==entry.startlb:
+                        blocks[-1][2] = entry.endlb
+                    else:
+                        blocks += [ [v, entry.startlb, entry.endlb] ]
+                run.stats[k] = { "blocks" : blocks, "first" : entries[0].value }
+
+
+class L1TrigKeySelector(RunLBBasedCondition):
+    def __init__(self, name):
+        self.showTrigKeys = False
+        super(L1TrigKeySelector,self).__init__(name=name,
+                                               dbfolderkey='COOLONL_TRIGGER::/TRIGGER/LVL1/Lvl1ConfigKey',
+                                               channelKeys = [(0,'L1 PSK','Lvl1PrescaleConfigurationKey')])
+
+
+    def __str__(self):
+        return "Retrieving L1 PSK"
+
+    def passes(self,values,key):
+        return True
+
+    def prettyValue(self, value, key):
+        return int(value) if str.isdigit(value) else None
+
+    def runAfterQuery(self,runlist):
+        for k in self.ResultKey():
+            for run in runlist:
+                run.stats[k] = { "blocks" : [], "first" : 0 }
+                entries = run.data[k]
+                print "OOOOOOOO",entries
+                if len(entries)==0: continue
+                blocks = []
+                for entry in entries:
+                    v = entry.value
+                    if v == "n.a.": v = None
+                    if len(blocks) > 0 and blocks[-1][0]==v and blocks[-1][2]==entry.startlb:
+                        blocks[-1][2] = entry.endlb
+                    else:
+                        blocks += [ [v, entry.startlb, entry.endlb] ]
+                run.stats[k] = { "blocks" : blocks, "first" : entries[0].value }
+        HLTTrigKeySelector.combineHltL1Keys(runlist)
+
+
+
+        
+class HLTTrigKeySelector(RunLBBasedCondition):
+    def __init__(self, name):
+        self.showTrigKeys = False
+        if Selector.db == 'OFLP200':
+            super(HLTTrigKeySelector,self).__init__(name=name,
+                                                    dbfolderkey='COOLONL_TRIGGER::/TRIGGER/HLT/HltConfigKeys',
+                                                    channelKeys = [(0,'HLT PSK','HltPrescaleConfigurationKey')])
+        else:
+            super(HLTTrigKeySelector,self).__init__(name=name,
+                                                    dbfolderkey='COOLONL_TRIGGER::/TRIGGER/HLT/PrescaleKey',
+                                                    channelKeys = [(0,'HLT PSK','HltPrescaleKey')])
+
+    def __str__(self):
+        return "Retrieving HLT PSK"
+
+    def passes(self,values,key):
+        return True
+
+    def prettyValue(self, value, key):
+        if not str.isdigit(value): return None
+        return int(value)
+
+    def runAfterQuery(self,runlist):
+        for k in self.ResultKey():
+            for run in runlist:
+                blocks = []
+                run.stats[k] = {}
+                for entry in run.data[k]:
+                    v = entry.value
+                    if v == "n.a.": v = None
+                    if len(blocks) > 0 and blocks[-1][0]==v and blocks[-1][2]==entry.startlb:
+                        blocks[-1][2] = entry.endlb
+                    else:
+                        blocks += [ [v, entry.startlb, entry.endlb] ]
+                run.stats[k] = { "blocks" : blocks, "first" : run.data[k][0].value }
+
+        HLTTrigKeySelector.combineHltL1Keys(runlist)
+
+    @classmethod
+    def combineHltL1Keys(cls, runlist):
+        l1keys = set()
+        hltkeys = set()
+        for run in runlist:
+            if 'L1 PSK' in run.stats:
+                l1keys.update( [x[0] for x in run.stats['L1 PSK']['blocks']] )
+            if 'HLT PSK' in run.stats:
+                hltkeys.update( [x[0] for x in run.stats['HLT PSK']['blocks']] )
+
+        from CoolRunQuery.utils.AtlRunQueryTriggerUtils import getL1PskNames, getHLTPskNames
+        if len(l1keys)>0 and len(hltkeys)>0:
+            l1names = getL1PskNames(l1keys)
+            hltnames = getHLTPskNames(hltkeys)
+
+        for run in runlist:
+            if not ('L1 PSK' in run.stats and 'HLT PSK' in run.stats): continue
+            ic = 0
+            blocks = set()
+            for l1key, l1beg, l1end in run.stats['L1 PSK' ]['blocks']:
+                for hltkey, hltbeg, hltend in run.stats['HLT PSK' ]['blocks']:
+                    lbmin = max(ic,min(l1beg,hltbeg))
+                    lbmax = min(l1end-1,hltend-1)
+                    if lbmin > lbmax or lbmin == 0 or lbmax == 0: continue
+                    ic = lbmax + 1
+                    # accept if new
+                    l1name = l1names[l1key] if l1key else ""
+                    hltname = hltnames[hltkey] if hltkey else ""
+                    elm = (lbmin, lbmax, l1key, hltkey, l1name, hltname)
+                    blocks.update([elm])
+            run.stats['PSK' ] = {'blocks' : sorted(list(blocks)) }
+            
+
+
+class RatesSelector(RunLBBasedCondition):
+    def __init__(self, name, trigger=[]):
+        # trigger can be ["*Electron*", "L1_*"]
+        # rate will be printed for all triggers matching the pattern
+
+        super(RatesSelector,self).__init__(name=name,
+                                           dbfolderkey='COOLONL_TRIGGER::/TRIGGER/LUMI/LVL1COUNTERS',
+                                           channelKeys = [(-1,'TriggerRates','TriggerName')])
+
+        self.trigger=trigger
+        from CoolRunQuery.AtlRunQuerySelectorWorker import SelectorWorker
+        self.trigSel = SelectorWorker.getRetrieveSelector('trigger','TriggerSelector')
+        if len(trigger)>0:
+            self.trigSel.addShowTriggerPattern(','.join(trigger))
+
+    def addPattern(self,pattern):
+        if pattern=="" or pattern=="L1":
+            pattern="L1_EM5,L1_TAU5,L1_XE10,L1_J5,L1_MBTS_4_4,L1_MU6"
+        self.trigSel.addShowTriggerPattern(pattern)
+        self.trigger += pattern.split(',')
+
+
+    def __str__(self):
+        return "Retrieving trigger rates for %r" % ','.join(self.trigger)
+
+    def select(self, runlist):
+        start = time()
+        print self,
+        sys.stdout.flush()
+
+        fL1R = coolDbConn.GetDBConn(self.schema,db=self.db).getFolder(self.folder)
+
+        for r in runlist:
+            menu = r.result['TriggerMenu']
+
+            namelookup = 256*['']
+            channellist = []
+            #print menu
+            for tr in menu:
+                if not tr.name.startswith("L1_"): continue
+                ch = tr.counter
+                namelookup[ch] = tr.name
+                channellist.append(ch)
+
+            if len(channellist)>50:
+                r.addResult(self.ResultKey()[0], "Too many L1 triggers requested (%i), maximum is 50" % len(channellist))
+                continue
+
+            if len(channellist)==0:
+                r.addResult(self.ResultKey()[0], "No match")
+                continue
+
+            channellist.sort()
+            ch = channellist[0]
+            chanselL1 = cool.ChannelSelection(ch,ch,cool.ChannelSelection.sinceBeforeChannel)
+            for ch in channellist[1:]:
+                chanselL1.addChannel(ch)
+
+            iovmin=(r.runNr << 32)+0
+            iovmax=((r.runNr+1) << 32)-1
+
+            countsholder = defaultdict(list)
+
+            # the hlt part
+            objs = fL1R.browseObjects( iovmin, iovmax, chanselL1)
+            while objs.goToNext():
+                obj=objs.currentRef()
+                ch  = obj.channelId()
+                countsholder[namelookup[ch]].append((obj.since()&0xFFFFFFFF,
+                                                     obj.payloadValue('BeforePrescale'),
+                                                     obj.payloadValue('AfterPrescale'),
+                                                     obj.payloadValue('L1Accept')))
+
+            r.addResult(self.ResultKey()[0], countsholder)
+
+        duration = time() - start
+
+        if self.applySelection: print " ==> %i runs found (%.2f sec)" % (len(runlist),duration)
+        else:                   print " ==> Done (%g sec)" % duration
+
+        return runlist
+
+class TriggerSelector(RunLBBasedCondition):
+
+    def __init__(self, name, trigger=[]):
+        # trigger can be ["*Electron*", "L1_*"]
+        #    will select runs that satiesfy an 'or' of all patterns in the list
+        # a pattern without number are checked for existence
+        # a pattern with number will be checked against the sum of the events in all matching triggers
+        from CoolRunQuery.AtlRunQuerySelectorWorker import SelectorWorker
+        SelectorWorker.getRetrieveSelector('trigkey','TrigKeySelector')
+        SelectorWorker.getRetrieveSelector('l1trigkey','L1TrigKeySelector')
+        SelectorWorker.getRetrieveSelector('hlttrigkey','HLTTrigKeySelector')
+
+        super(TriggerSelector,self).__init__(name=name,
+                                             dbfolderkey='COOLONL_TRIGGER::/TRIGGER/HLT/Menu',
+                                             channelKeys = [(-1,'TriggerMenu','ChainName')])
+
+        self.triggers = ' or '.join(trigger)
+        self.applySelection = (len(trigger)>0)
+        self.seltriggerpatterns = []
+        self.showtriggerpatterns = []
+
+        for s in trigger:
+            s += "$"
+            p = re.compile(s.split()[0].replace(',','|').replace('*','.*').replace('?','.').replace('%','.*'), re.I)
+            self.seltriggerpatterns += [p]
+        
+
+    def addShowTriggerPattern(self, triggerpattern):
+        if triggerpattern=="": triggerpattern = "*"
+        self.showtriggerpatterns += triggerpattern.split(',')
+
+    def __str__(self):
+        if self.applySelection: return 'SELOUT Checking if the trigger name matches "%s"' % self.triggers
+        else: return "Retrieving trigger names [%s]" % ','.join(self.showtriggerpatterns)
+
+
+    def getL1Prescales(self, l1psks):
+        from CoolRunQuery.utils.AtlRunQueryTriggerUtils import getL1Prescales
+        l1pscache    = dict()
+        for l1psk in l1psks:
+            l1pscache[l1psk] = getL1Prescales(l1psk)
+        return l1pscache
+
+    def getHLTPrescales(self, hltpsks):
+        from CoolRunQuery.utils.AtlRunQueryTriggerUtils import getHLTPrescales
+
+        l2pscache   = dict()
+        efpscache   = dict()
+
+        for hltpsk in hltpsks:
+            l2pscache[hltpsk], efpscache[hltpsk] = getHLTPrescales(hltpsk)
+
+        return l2pscache, efpscache
+
+
+    def getMenuFromRun(self, smks):
+        from CoolRunQuery.utils.AtlRunQueryTriggerUtils import getL1Menu, getHLTMenu
+
+        l1menucache  = dict()
+        l2menucache  = defaultdict(dict)
+        efmenucache  = defaultdict(dict)
+
+        # fill the menu and prescale caches
+        for smk in smks:
+
+            # the l1 menu
+            l1items = getL1Menu(smk)
+            l1menucache[smk] = l1items
+
+            # the hlt menu
+            l2chains, efchains = getHLTMenu(smk)
+            d2 = l2menucache[smk] = dict([(c.counter,c) for c in l2chains])
+            d3 = efmenucache[smk] = dict([(c.counter,c) for c in efchains])
+
+            # connect the levels (assign lower counter)
+            for chain in efchains:
+                lowername = chain.lowername
+                if chain.lowername=="": continue
+                cc = chain.counter
+                if (cc in d2) and (chain.lowername == d2[cc].name):
+                    chain.lower = d2[cc]
+                    chain.lowercounter = cc
+                    continue
+                for l2ch in l2chains:
+                    if chain.lowername == l2ch.name:
+                        chain.lower = l2ch
+                        chain.lowercounter = l2ch.counter
+                        break
+
+            for chain in l2chains:
+                if chain.lowername == "": continue
+                for l1item in l1items:
+                    if l1item and chain.lowername == l1item.name:
+                        chain.lower = l1item
+                        chain.lowercounter = l1item.counter
+                        break
+
+            # set display flag
+            for item in l1items + l2chains + efchains:
+                if item:
+                    item.forshow = self.matchShowPattern(item.name)
+
+            # set 'selected' flag
+            if self.applySelection:
+                for item in l1items + l2chains + efchains:
+                    if item:
+                        item.forselect = self.matchSelectPattern(item.name)
+
+        return l1menucache, l2menucache, efmenucache
+    
+
+    def select(self, runlist):
+        start = time()
+        # some preparation: compile the show patterns
+        self.compiledShowPatterns = []
+        if '*' in self.showtriggerpatterns:
+            self.compiledShowPatterns = ['all']
+        else:
+            for p in self.showtriggerpatterns:
+                p += "$"
+                self.compiledShowPatterns += [re.compile(p.replace('*','.*').replace('?','.').replace('%','.*'),re.I)]
+
+        print self,
+        sys.stdout.flush()
+        newrunlist = []
+
+        runranges = SmartRangeCalulator(runlist)
+
+        smks = [r.result['SMK'] for r in runlist]
+        l1psks = set()
+        hltpsks = set()
+        for r in runlist:
+            l1psks.update( [l1psk for (l1psk,firstlb,lastlb) in r.stats['L1 PSK']['blocks']] )
+            hltpsks.update( [hltpsk for (hltpsk,firstlb,lastlb) in r.stats['HLT PSK']['blocks']] )
+
+        l1menucache, l2menucache, efmenucache = self.getMenuFromRun(smks)
+
+        l1pscache = self.getL1Prescales(l1psks)
+
+        l2pscache, efpscache = self.getHLTPrescales(hltpsks)
+
+        for run in runlist: # go through old runlist and see
+
+            smk  = run.result['SMK']
+            psks = [(x[2],x[3]) for x in run.stats['PSK']['blocks']]
+
+            l1items  = [it for it in l1menucache[smk] if it and (it.forshow or it.forselect)]
+            l2chains = [ch for ch in l2menucache[smk].values() if (ch.forshow or ch.forselect) and not ch.multiseeded]
+            efchains = [ch for ch in efmenucache[smk].values() if (ch.forshow or ch.forselect) and not ch.multiseeded and ch.lower and not ch.lower.multiseeded]
+
+            value = defaultdict(list)
+            
+            for item in l1items:
+                for l1psk,hltpsk in psks:
+                    if not l1psk:
+                        value[item].append(None)
+                        continue
+                    itemps = l1pscache[l1psk][item.counter]
+                    value[item].append(itemps if itemps>=0 else -1)
+
+            for l2chain in l2chains:
+                for l1psk,hltpsk in psks:
+                    if not l1psk or not hltpsk:
+                        value[l2chain].append(None)
+                        continue
+                    chainps,chainpt = l2pscache[hltpsk][l2chain.counter]
+                    if chainps<0:
+                        value[l2chain].append(-1)
+                        continue
+                    chainps *= l1pscache[l1psk][l2chain.lowercounter]
+                    value[l2chain].append(chainps if chainps>=0 else -1)
+
+            for efchain in efchains:
+                l2chain = efchain.lower
+                for l1psk,hltpsk in psks:
+                    if not l1psk or not hltpsk:
+                        value[efchain].append(None)
+                        continue
+                    chainps,chainpt = efpscache[hltpsk][efchain.counter]
+                    if chainps<0:
+                        value[efchain].append(-1)
+                        continue
+                    l2chainps,l2chainpt = l2pscache[hltpsk][l2chain.counter]
+                    chainps *= l2chainps
+                    if chainps<0:
+                        value[efchain].append(-1)
+                        continue
+                    chainps *= l1pscache[l1psk][l2chain.lowercounter]
+                    value[efchain].append(chainps if chainps>=0 else -1)
+
+                # remove all the disabled triggers
+                for tr,pslist in value.items():
+                    if not any([ps==None or ps>=0 for ps in pslist]):
+                        value.pop(tr)
+
+            if self.applySelection and not self.passes(value): continue
+            newrunlist += [run.runNr]
+
+            run.addResult(self.ResultKey()[0], value)
+
+        runlist = [r for r in runlist if r.runNr in newrunlist]
+
+        duration = time() - start
+
+        if self.applySelection: print " ==> %i runs found (%.2f sec)" % (len(runlist),duration)
+        else:                   print " ==> Done (%g sec)" % duration
+
+        return runlist
+
+    def matchShowPattern(self,name):
+        if len(self.compiledShowPatterns)==0 or self.compiledShowPatterns[0]=='all':
+            return True
+        else:
+            return any([p.match(name) for p in self.compiledShowPatterns])
+        
+        
+    def matchSelectPattern(self,name):
+        return any([p.match(name) for p in self.seltriggerpatterns])
+
+    def prettyValue(self, value):
+        form = []
+        for v in value:
+            if len(v)==2:
+                form += ["%s (%s)" % (v[0],','.join(v[1]))]
+            else:
+                form += ["%s (%s|%s)" % v]
+        return ', '.join(form)
+
+
+    def passes(self,triggers):
+        for chain in triggers:
+            if chain.forselect: return True
+        return False
diff --git a/Database/CoolRunQuery/python/selector/__init__.py b/Database/CoolRunQuery/python/selector/__init__.py
new file mode 100644
index 00000000000..74583d364ec
--- /dev/null
+++ b/Database/CoolRunQuery/python/selector/__init__.py
@@ -0,0 +1,2 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
diff --git a/Database/CoolRunQuery/python/utils/AtlRunQueryCache.py b/Database/CoolRunQuery/python/utils/AtlRunQueryCache.py
new file mode 100755
index 00000000000..b95d259d474
--- /dev/null
+++ b/Database/CoolRunQuery/python/utils/AtlRunQueryCache.py
@@ -0,0 +1,89 @@
+#!/bin/env python
+
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+from time import sleep
+import pickle
+import os
+
+DEBUG=False
+
+class Cache(object):
+    def __init__(self,cachedir,form):
+        self._cache = {}
+        self.cachedir = cachedir.rstrip('/') if os.path.exists(cachedir) else None
+        self.form = form
+        if self.cachedir:
+            print "Initializing the cache at",cachedir.rstrip('/')
+            
+
+    def __call__(self, f, *args, **kwds):
+        if not self.cachedir:
+            return f  # caching is automatically disabled if no cache directory exists
+
+        print "Providing cache functionality for function '%s()'" % f.func_name
+        def newf(*args, **kwds):
+            key = kwds['cachekey']
+            if not self.__is_cached(key):
+                self.__write_to_cache(key,f(*args, **kwds))
+            else:
+                if DEBUG:
+                    print "DEBUG: returning cached value for '%s'" % (self.form % key)
+                pass
+            return self._cache[key]
+        return newf
+
+    def __name_pickle_cache(self,key):
+        filename = self.form % key
+        return '%s/%s.pickle' % (self.cachedir, filename)
+
+
+    def __write_to_cache(self,key, value):
+        # put into transient cache
+        self._cache[key] = value
+
+        # store pickled version
+        pfname = self.__name_pickle_cache(key)
+        pf = open( pfname, 'w' )
+        try:
+            pickle.dump(value, pf)
+        except:
+            print 'ERROR: could not write to cache: ' + pfname
+            sys.exit(1)
+        pf.close()
+        
+    def __is_cached(self,key):
+        # check transient cache
+        if key in self._cache:
+            return True
+
+        # check for pickled version
+        pfname = self.__name_pickle_cache(key)
+        try:
+            pf = open( pfname, 'r' )
+        except:
+            if DEBUG:
+                print 'DEBUG: could not read from cache: ' + pfname
+            return False
+        try:
+            self._cache[key] = pickle.load(pf)
+        except:
+            print "ERROR: could not unpickle '%s'" % pfname
+            sys.exit(1)
+        pf.close()
+        return True
+
+
+
+
+
+if __name__ == "__main__":
+    @Cache("/afs/cern.ch/user/s/stelzer/runsummary/cache/","simple_%i_second%i")
+    def aFunction(x,y,cachekey):
+        print "expensive"
+        return (3*x,y*y,x+y)
+
+    x=13
+    print aFunction(x,y=2,cachekey=(x,2))
+    print aFunction(x,1,cachekey=(x,1))
+
diff --git a/Database/CoolRunQuery/python/utils/AtlRunQueryDQUtils.py b/Database/CoolRunQuery/python/utils/AtlRunQueryDQUtils.py
new file mode 100644
index 00000000000..71b15eaff73
--- /dev/null
+++ b/Database/CoolRunQuery/python/utils/AtlRunQueryDQUtils.py
@@ -0,0 +1,221 @@
+#!/bin/env python
+
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+#
+# ----------------------------------------------------------------
+# Script : AtlRunQueryDQUtils.py
+# Project: AtlRunQuery
+# Purpose: Utility functions for AtlRunQuery
+# Authors: Peter Onyisi (Chicago U)
+# Created: May 6, 2010
+# ----------------------------------------------------------------
+#
+from __future__ import division
+
+import sys, time
+import xml.etree.cElementTree as et
+import xmlrpclib
+from PyCool import cool
+dbSvc = cool.DatabaseSvcFactory.databaseService()
+
+from .AtlRunQuerySelectorBase import DataKey
+
+THIRTYTWOMASK=int(2**32-1)
+SERVER='http://atlasdqm.cern.ch:8080'
+
+FLAGS_WE_CARE_ABOUT = ['PIXB', 'PIX0', 'PIXEA', 'PIXEC',
+                       'SCTB', 'SCTEA', 'SCTEC',
+                       'TRTB', 'TRTEA', 'TRTEC','TRTTR'
+                       'IDGL', 'IDAL',
+                       'EMBA', 'EMBC', 'EMECA', 'EMECC', 'HECA', 'HECC',
+                       'FCALA', 'FCALC',
+                       'TILBA', 'TILBC', 'TIEBA', 'TIEBC',
+                       'MBTSA', 'MBTSC',
+                       'MDTBA', 'MDTBC', 'MDTEA', 'MDTEC',
+                       'RPCBA', 'RPCBC',
+                       'TGCEA', 'TGCEC',
+                       'CSCEA', 'CSCEC',
+                       'LCD',
+                       #'L1CAL',
+                       #'L1MUB', 'L1MUE',
+                       #'L1CTP',
+                       #'TRCAL', 'TRBJT', 'TRBPH', 'TRCOS',
+                       #'TRELE', 'TRGAM', 'TRJET', 'TRMET',
+                       #'TRMBI', 'TRMUO', 'TRTAU', 'TRIDT',
+#                       'EIDB', 'EIDCR', 'EIDE', 'PIDB', 'PIDCR', 'PIDE',
+#                       'JETB', 'JETEA', 'JETEC',
+#                       'MET', 'METCALO', 'METMUON',
+#                       'TAUB', 'TAUCR', 'TAUE',
+                       ]
+
+FLAGGROUPS = {
+    'PIX': ['PIXB', 'PIX0', 'PIXEA', 'PIXEC'],
+    'SCT': ['SCTB', 'SCTEA', 'SCTEC'],
+    'TRT': ['TRTB', 'TRTEA', 'TRTEC', 'TRTTR'],
+    'LAR': ['EMBA', 'EMBC', 'EMECA', 'EMECC',
+            'HECA', 'HECC', 'FCALA', 'FCALC'],
+    'EM': ['EMBA', 'EMBC', 'EMECA', 'EMECC'],
+    'HEC': ['HECA', 'HECC'],
+    'FCAL': ['FCALA', 'FCALC'],
+    'TILE': ['TILBA', 'TILBC', 'TIEBA', 'TIEBC'],
+    'MDT': ['MDTBA', 'MDTBC', 'MDTEA', 'MDTEC'],
+    'RPC': ['RPCBA', 'RPCBC'],
+    'TGC': ['TGCEA', 'TGCEC'],
+    'CSC': ['CSCEA', 'CSCEC'],
+    'MBTS': ['MBTSA', 'MBTSC'],
+    'LUCID': ['LCD']
+    }
+
+def _intersect(lbr1, lbr2):
+    def normalize(lbr):
+        return (max(1, lbr[0]), lbr[1] if lbr[1] != -1 else THIRTYTWOMASK)
+    tlbr1 = normalize(lbr1)
+    tlbr2 = normalize(lbr2)
+    rv = (max(tlbr1[0],tlbr2[0]), min(tlbr1[1],tlbr2[1]))
+    if rv[1] <= rv[0]:
+        return None
+    else:
+        return rv
+
+lumicache = {}
+
+def lumi(run, lbr):
+    if tuple(lbr) in lumicache:
+        return lumicache[tuple(lbr)]
+
+    lblbdb = dbSvc.openDatabase('COOLONL_TRIGGER/COMP200', True)
+    lblb = lblbdb.getFolder('/TRIGGER/LUMI/LBLB')
+    lblestonl = lblbdb.getFolder('/TRIGGER/LUMI/LBLESTONL')
+
+    lbs = lblb.browseObjects((run<<32)+lbr[0],
+                             (run<<32)+lbr[1]-1,
+                             cool.ChannelSelection(0))
+    inf = {}
+    for obj in lbs:
+        lbpy = obj.payload()
+        #print (lbpy['EndTime']-lbpy['StartTime'])/1e9
+        inf[(run, obj.since() & 0xFFFFFFFF)] = (lbpy['EndTime']-lbpy['StartTime'])/1e9
+    if obj.since() & 0xFFFFFFFF == lbr[1]:
+        print 'Oops: this should not happen, appears to be off-by-one error'
+    lbls = lblestonl = lblestonl.browseObjects((run<<32)+lbr[0],
+                                               (run<<32)+lbr[1]-1,
+                                               cool.ChannelSelection(0))
+    infl = {}
+    for obj in lbls:
+        lblpy = obj.payload()
+        infl[(run, obj.since() & 0xFFFFFFFF)] = lblpy['LBAvInstLumi']
+
+    #print sorted(infl.keys())
+    totlum = 0
+    for lb in inf:
+        if lb in infl:
+            totlum += inf[lb]*infl[lb]
+        else:
+            print 'Missing run %d, LB %d' % lb
+    lumicache[tuple(lbr)] = totlum
+    return totlum
+
+def GetDQEfficiency( rundict ):
+
+    runset = set()
+    for runnum in rundict.keys(): runset.add(runnum)
+
+    s = xmlrpclib.ServerProxy(SERVER)
+    flaginfo = s.get_dqmf_summary_flags_lb({'run_list': list(runset)}, FLAGS_WE_CARE_ABOUT, 'SHIFTOFL')
+    #print flaginfo
+    record = {}
+    for flag in FLAGS_WE_CARE_ABOUT:
+        record[flag] = []
+    for run in runset:
+        if `run` not in flaginfo:
+            print '%s not in flaginfo' % run
+            del rundict[run]
+            continue
+        for sublb in rundict[run]:
+            for flag, periods in flaginfo[`run`].items():
+                for period in periods:
+                    ip = _intersect(period, sublb)
+                    if ip is not None:
+                        #print run, flag, ip, period[2]
+                        #print lumi(run, ip)
+                        record[flag].append((ip[1]-ip[0], period[2], lumi(run, ip)))
+
+
+    totallum = 0
+    for run in rundict:
+        for pair in rundict[run]:
+            totallum += lumi(run, pair)
+    print 'Total lumi:', totallum
+
+    flagsum = {}
+
+    for flag in FLAGS_WE_CARE_ABOUT:
+        flagsum[flag] = {}
+        lr = record[flag]
+        cols = set([x[1] for x in lr])
+        accounted = 0
+        for col in cols:
+            llum = sum([x[2] for x in lr if x[1] == col])
+            accounted += llum
+            print flag, col, llum, '%.2f%%' % (llum/totallum*100)
+            flagsum[flag][col] = (llum/totallum*100)
+        if abs(accounted-totallum) > 1e-8:
+            print flag, 'n.a.', totallum-accounted, '%.2f%%' % ((1-accounted/totallum)*100)
+            flagsum[flag]['n.a.'] = ((1-accounted/totallum)*100)
+
+    def _sum(d1, d2):
+        rv = {}
+        for key in set(d1.keys() + d2.keys()):
+            rv[key] = d1.get(key, 0) + d2.get(key, 0)
+        #print rv
+        return rv
+
+    for flagtop, flaggroup in FLAGGROUPS.items():
+        vals = reduce(_sum, [flagsum[f] for f in flaggroup], {})
+        print flagtop
+        for typ in vals:
+            print '  %s: %.2f%%' % (typ, vals[typ]/len(flaggroup))
+
+def MakeDQeffHtml( dic, dicsum, datapath ):
+    s = ''
+
+    
+    # run and time ranges
+    runs   = dic[DataKey('Run')]
+    nruns  = len(runs)
+    times  = dic[DataKey('Start and endtime')]
+
+    starttime = float(times[-1].partition(',')[0])
+    endtime   = float(times[0].partition(',')[2])
+
+    s = '<table style="color: #777777; font-size: 85%; margin-left: 14px" cellpadding="0" cellspacing="3">\n'
+    # runs in reverse order
+    s += '<tr><td><i>Number of runs selected:</i></td><td>&nbsp;&nbsp;%g</td><td></td></tr>\n' % (len(runs))
+    s += '<tr><td><i>First run selected:</i></td><td>&nbsp;&nbsp;%s</td><td>&nbsp;&nbsp;(%s)</td></tr>\n' % (runs[-1], time.strftime("%a %b %d, %Y, %X",time.gmtime(starttime)))
+    s += '<tr><td><i>Last run selected:</i></td><td>&nbsp;&nbsp;%s</td><td>&nbsp;&nbsp;(%s)</td></tr>\n'  % (runs[0], time.strftime("%a %b %d, %Y, %X",time.gmtime(endtime)))
+    s += '</table>\n'
+    
+    # --------------------------------------------------------------------------------------
+    # run summary table    
+    s += '<p></p>\n'
+    s += '<table style="margin-left: 14px">\n'
+    s += '<tr><td><b>Run / Event Summary</b></td></tr>\n'
+    s += '</table>\n'
+
+    return s
+
+if __name__ == '__main__':
+
+    p = et.parse(sys.argv[1])
+
+    rundict = {}
+    for lbc in p.getiterator('LumiBlockCollection'):
+        runnum = int(lbc.find('Run').text)
+        #print 'Run', runnum
+        runset.add(runnum)
+        rundict[runnum] = []
+        for lbr in lbc.findall('LBRange'):
+            rundict[runnum].append([int(lbr.get('Start')),
+                                    int(lbr.get('End'))+1])
+            #print '  LBs %s-%s' % (lbr.get('Start'), lbr.get('End'))
+
diff --git a/Database/CoolRunQuery/python/utils/AtlRunQueryFastBlobRead.py b/Database/CoolRunQuery/python/utils/AtlRunQueryFastBlobRead.py
new file mode 100644
index 00000000000..2d05efa3705
--- /dev/null
+++ b/Database/CoolRunQuery/python/utils/AtlRunQueryFastBlobRead.py
@@ -0,0 +1,21 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+
+import PyCool # need to import this, so that later imports don't override blob_read
+import PyCintex
+PyCintex.gbl.cool.IDatabase # force the load of the dictionary (to stay on the safe side)
+from PyCintex import gbl, getAllClasses
+
+def blob_read(self, size = -1):
+    if size < 0:
+        endpos = self.size()
+    else:
+        endpos = self.pos + size
+    beginpos = self.pos
+    self.pos = endpos
+    buf = self.startingAddress()
+    buf.SetSize(self.size())
+    return buf[beginpos:endpos]
+
+# add the new functions
+getattr(gbl,"coral::Blob").read = blob_read
diff --git a/Database/CoolRunQuery/python/utils/AtlRunQueryIOV.py b/Database/CoolRunQuery/python/utils/AtlRunQueryIOV.py
new file mode 100644
index 00000000000..59b1e9a778e
--- /dev/null
+++ b/Database/CoolRunQuery/python/utils/AtlRunQueryIOV.py
@@ -0,0 +1,118 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+
+import sys,os,copy, time
+
+from PyCool import cool
+
+class IOVTime:
+    def __init__(self, run=None, lb=None, timerunlb=None,timebased=False):
+        if isinstance(run,IOVTime):
+            self.timebased = run.timebased
+            self.run = run.run
+            self.lb = run.lb
+            self.time = run.time
+        else:
+            self.timebased=timebased
+            self.run = self.lb = self.time = None
+            if timebased:
+                self.time=timerunlb
+            else:
+                if timerunlb!=None:
+                    self.run = timerunlb>>32
+                    self.lb = timerunlb&0xFFFFFFFF
+                else:
+                    self.run = run
+                    self.lb  = lb 
+
+    def __str__(self):
+            if self.timebased:
+                try:
+                    return "%s" % time.strftime("%a %b %d %Y %X",time.gmtime(self.time/1E9))
+                except:
+                    return "infinity" 
+            else:              return "%i/%i" % (self.run,self.lb)
+
+    def __lt__(self, other):
+        if self.timebased: return self.time<other.time
+        else: return self.run<other.run or self.run==other.run and self.lb<other.lb
+
+    def __cmp__(self, other):
+        if self.timebased:
+            return cmp(self.time,other.time)
+        else:
+            if self.run==other.run: return cmp(self.lb,other.lb)
+            else: return cmp(self.run,other.run)
+
+    def __eq__(self, other):
+        if self.timebased: return self.time==other.time
+        else: return self.run==other.run and self.lb==other.lb
+
+    def __le__(self, other):
+        return self<other or self==other    
+
+    def __sub__(self, other):
+        if isinstance(other, int):
+            return IOVTime(timerunlb=self.timerunlb()-1)
+        elif isinstance(other, IOVTime):
+            return self.timerunlb()-other.timerunlb()
+        
+
+    def timerunlb(self):
+        if self.timebased:
+            return self.time
+        res = long(self.run)<<32
+        res += self.lb
+        return res
+
+    def inRange(self,iovrange):
+        return iovrange.isInRange(self)
+
+class IOVRange:
+    def __init__(self, obj=None, starttime=None, endtime=None, runStart=None, lbStart=None, runEnd=None, lbEnd=None, timebased=False):
+        if isinstance(obj, cool.IObject):
+            self.startTime = IOVTime(timerunlb=obj.since(), timebased=timebased)
+            self.endTime = IOVTime(timerunlb=obj.until(), timebased=timebased)
+        elif isinstance(obj, IOVRange):
+            self.startTime = obj.startTime
+            self.endTime = obj.endTime
+        elif isinstance(starttime, IOVTime) and isinstance(endtime, IOVTime):
+            self.startTime = starttime
+            self.endTime = endtime
+        elif isinstance(starttime,long) and isinstance(endtime,long):
+            self.startTime = IOVTime(timerunlb=starttime,timebased=timebased)
+            self.endTime = IOVTime(timerunlb=endtime,timebased=timebased)
+        elif runStart!=None and lbStart!=None and runEnd!=None and lbEnd!=None:
+            self.startTime = IOVTime(runStart, lbStart, timebased=False)
+            self.endTime = IOVTime(runEnd, lbEnd, timebased=False)
+        else:
+            print "IOVRange.__init__: Can't interpret arguments"
+
+    def truncateToSingleRun(self,runnr):
+        if self.startTime.run<runnr:
+            self.startTime.run=runnr
+            self.startTime.lb=1
+        if self.endTime.run>runnr:
+            self.endTime.run=runnr+1
+            self.endTime.lb=0
+            
+    def __str__(self):
+        return "[%s, %s)" % (self.startTime,self.endTime)
+    def __repr__(self):
+        return str(self)
+
+    def __cmp__(self, other):
+        return cmp(self.startTime,other.startTime)
+
+    def length(self):
+        return "%2.1f" % ((self.endTime-self.startTime)/1.E9)
+
+    def isInRange(self, iovtime):
+        return self.startTime<=iovtime and iovtime<self.endTime
+
+    def overlaps(self, o):
+        if o.startTime>=self.endTime or o.endTime<=self.startTime:
+            return False
+        return True
+
+
diff --git a/Database/CoolRunQuery/python/utils/AtlRunQueryLookup.py b/Database/CoolRunQuery/python/utils/AtlRunQueryLookup.py
new file mode 100644
index 00000000000..f09977ea688
--- /dev/null
+++ b/Database/CoolRunQuery/python/utils/AtlRunQueryLookup.py
@@ -0,0 +1,290 @@
+#!/bin/env python
+
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+#
+# ----------------------------------------------------------------
+# Script : AtlRunQueryLookup.py
+# Project: AtlRunQuery
+# Purpose: Library with references for DQ flags and detector mask
+# Authors: Andreas Hoecker (CERN), Joerg Stelzer (DESY)
+# Created: Nov 13, 2008
+# ----------------------------------------------------------------
+#
+# See: DetectorDescription/DetDescrCond/DetectorStatus/doc/mainpage.h
+# Decription:
+#   http://alxr.usatlas.bnl.gov/lxr/source/atlas/DetectorDescription/DetDescrCond/DetectorStatus/doc/mainpage.h
+# Implementation:
+#   http://alxr.usatlas.bnl.gov/lxr/source/atlas/DetectorDescription/DetDescrCond/DetectorStatus/python/DetStatusLib.py
+
+DQChannelDict = {'PIXB':101,'PIX0':102,'PIXEA':104,'PIXEC':105,
+                 'SCTB':111,'SCTEA':114,'SCTEC':115,
+                 'TRTB':121,'TRTEA':124,'TRTEC':125,'TRTTR':126,
+                 'IDGL':130, # Obsolete: 'IDGB OBSOLETE':131,'IDGEA OBSOLETE':134,'IDGEC OBSOLETE':135,
+                 'IDAL':140, # Obsolete: 'IDAB OBSOLETE':141,'IDAEA OBSOLETE':144,'IDAEC OBSOLETE':145,
+                 'IDBS':150,
+                 'IDVX':161,
+                 'IDBCM':170,
+                 'EMBA':202,'EMBC':203,'EMECA':204,'EMECC':205,
+                 'HECA':214,'HECC':215,
+                 'FCALA':224,'FCALC':225,
+                 'TIGB':230,
+                 'TILBA':232,'TILBC':233,'TIEBA':234,'TIEBC':235,
+                 'MBTSA':244,'MBTSC':245,
+                 'CALBA':251,'CALEA':254,'CALEC':255,
+                 'MDTBA':302,'MDTBC':303,'MDTEA':304,'MDTEC':305,
+                 'RPCBA':312,'RPCBC':313,
+                 'TGCEA':324,'TGCEC':325,
+                 'CSCEA':334,'CSCEC':335,
+                  'LCDA':353,'LCDC':354,
+                 'ALFA':360,'ZDC':370,
+                 'L1CAL':401,'L1MUB':402,'L1MUE':403,'L1CTP':404,
+                 'TRCAL':411,
+                 'TRBJT':421,'TRBPH':422,'TRCOS':423,'TRELE':424,
+                 'TRGAM':425,'TRJET':426,'TRMET':427,'TRMBI':428,
+                 'TRMUO':429,'TRTAU':430,'TRIDT':431,
+                 'LUMI':450, 'LUMIONL':451,
+                 'RUNCLT':460,
+                 'RCOPS':461,
+                 'ATLGL':480,'ATLSOL':481,'ATLTOR':482,
+                 'EIDB':501,'EIDCR':502,'EIDE':503,
+                 'PIDB':505,'PIDCR':506,'PIDE':507,
+                 'EIDF':508,'EIDSOFT':509,
+                 'MSTACO':510,'MMUIDCB':511,'MMUIDVX':512,
+                 'MMUGIRL':513,'MMUBOY':514,'MMUIDSA':515,
+                 'MMUTAG':516,'MMTIMO':517,'MCMUTAG':518,
+                 'MCALLHR':519,
+                 'JETB':521,'JETEA':524,'JETEC':525,
+                 'JETFA':526,'JETFC':527,
+                 'METCALO':531,'METMUON':532,
+                 'BTGLIFE':541,'BTGSOFTE':544,'BTGSOFTM':545,
+                 'TAUB':551,'TAUCR':552,'TAUE':553}
+
+DQSuperGroupsDict = {1 : ['Inner detector',       ['PIXB','PIX0','PIXEA','PIXEC','SCTB','SCTEA','SCTEC','TRTB','TRTEA','TRTEC','TRTTR',
+                                                   'IDGL','IDAL','IDBS','IDVX']], 
+                     2 : ['Calorimeter',          ['EMBA','EMBC','EMECA','EMECC','HECA','HECC','FCALA','FCALC',
+                                                   'TIGB','TILBA','TILBC','TIEBA','TIEBC','CALBA','CALEA','CALEC']],
+                     3 : ['Muon systems',         ['MDTBA','MDTBC','MDTEA','MDTEC','RPCBA','RPCBC','TGCEA','TGCEC','CSCEA','CSCEC']],
+                     4 : ['Forward detectors and luminosity', ['MBTSA','MBTSC','IDBCM','LCDA','LCDC','ALFA','ZDC','LUMI']],
+                     5 : ['Global, Magnets, DAQ and Trigger',['ATLGL','ATLSOL','ATLTOR','RUNCLT','RCOPS',
+                                                   'L1CAL','L1MUB','L1MUE','L1CTP',
+                                                   'TRCAL','TRBJT','TRBPH','TRCOS','TRELE','TRGAM','TRJET','TRMET','TRMBI','TRMUO','TRTAU','TRIDT']],
+                     6 : ['Combined performance', ['EIDB','EIDCR','EIDE',
+                                                   'PIDB','PIDCR','PIDE',
+                                                   'EIDF','EIDSOFT',
+                                                   'MSTACO','MMUIDCB','MMUIDVX',
+                                                   'MMUGIRL','MMUBOY','MMUIDSA',
+                                                   'MMUTAG','MMTIMO','MCMUTAG',
+                                                   'MCALLHR',
+                                                   'JETB','JETEA','JETEC','JETFA','JETFC',
+                                                   'METCALO','METMUON',
+                                                   'BTGLIFE','BTGSOFTE','BTGSOFTM',
+                                                   'TAUB','TAUCR','TAUE']]}
+
+DQGroupDict =  { 100:'PIX',
+                 110:'SCT',
+                 120:'TRT',
+                 130:'IDGL',
+                 140:'IDAL',
+                 150:'IDBS',
+                 160:'IDVX',
+                 170:'IDBCM',
+                 200:'LArEM',
+                 210:'HEC',
+                 220:'FCAL',
+                 230:'TILE',
+                 240:'MBTS',
+                 250:'CAL',
+                 300:'MDT',
+                 310:'RPC',
+                 320:'TGC',
+                 330:'CSC',
+                 350:'LCD',
+                 360:'ALFA',
+                 370:'ZDC',
+                 400:'L1',
+                 410:'TRIG',
+                 420:'TRBJT',
+                 450:'LUMI',
+                 460:'RUNCLT',
+                 500:'EGAMCP',
+                 510:'MUONCP',
+                 520:'JETCP',
+                 530:'METCP',
+                 540:'BTAGCP',
+                 550:'TAUCP'}
+
+def DQChannels():
+    # sort disctionary
+    dqitems = DQChannelDict.items()
+    dqitems = [(v, k) for (k, v) in dqitems]
+    dqitems.sort()
+    return dqitems
+
+def DQChannel(name):
+    name = name.upper()
+    if ':' in name: name = name[name.index(':')+1:]
+    # OLD: if name.startswith('CP_'): return -1
+    if '_' in name: return -1
+    return DQChannelDict[name]
+
+
+def isDQ(name):
+    name = (name.split(':')[-1].split('#')[0]).upper()
+    if name.startswith("CP_") or name.startswith("PHYS_") or name.startswith("TRIG_") or name.startswith("LUM_") or name.startswith("GLOBAL_"): return True
+    return name in DQChannelDict
+
+
+OLCAlgorithms = { 0:     'ATLAS_PREFERRED',
+                  1:     'LHC',
+                  101:	 'LUCID_ZEROS_OR',
+                  102:	 'LUCID_ZEROS_AND',
+                  103:	 'LUCID_HITS_OR',
+                  104:	 'LUCID_HITS_AND',
+                  151:	 'LUCID_AND',
+                  201:	 'BCM_H_ZEROS_AND',
+                  202:	 'BCM_H_EVENTS_AND',
+                  203:	 'BCM_H_EVENTS_XORA',
+                  204:	 'BCM_H_EVENTS_XORC',
+                  205:	 'BCM_V_ZEROS_AND',
+                  206:	 'BCM_V_EVENTS_AND',
+                  207:	 'BCM_V_EVENTS_XORA',
+                  208:	 'BCM_V_EVENTS_XORC',
+                  301:	 'MBTS_ZEROS_AND',
+                  302:	 'MBTS_ZEROS_OR',
+                  303:	 'MBTS_HITS_AND',
+                  304:	 'MBTS_HITS_OR',
+                  401:	 'ZDC',
+                  501:	 'FCAL',
+                  601:	 'HLT',
+                  901:	 'OffLumi_LArTime_Events',
+                  998:	 'OflLumi_Fake0',
+                  999:	 'OflLumi_Fake1' }
+
+def InitDetectorMaskDecoder():
+
+    # taken from:
+    #   http://alxr.usatlas.bnl.gov/lxr/source/tdaq-common/eformat/src/DetectorMask.cxx
+    #
+    # note that these here are obsolete:
+    #   https://svnweb.cern.ch/trac/atlastdaq/browser/DAQ/online/RCUtils/trunk/src/get_detectormask.cc
+    #   http://isscvs.cern.ch/cgi-bin/viewcvs-all.cgi/DAQ/online/RunControl/src/get_detectormask.cc?root=atlastdaq&view=markup
+
+    dName = ['unknown']*64
+
+    dName[0]  = "Pix Barrel"
+    dName[1]  = "Pix Disks"
+    dName[2]  = "Pix B-Layer"
+    dName[3]  = "REMOVED"
+
+    dName[4]  = "SCT BA"
+    dName[5]  = "SCT BC"
+    dName[6]  = "SCT EA"
+    dName[7]  = "SCT EC"
+
+    dName[8]  = "TRT BA"
+    dName[9]  = "TRT BC"
+    dName[10] = "TRT EA"
+    dName[11] = "TRT EC"
+
+    dName[12] = "LAr EMBA"
+    dName[13] = "LAr EMBC"
+    dName[14] = "LAr EMECA"
+    dName[15] = "LAr EMECC"
+    dName[16] = "LAr HECA"
+    dName[17] = "LAr HECC"
+    dName[18] = "LAr FCALA"
+    dName[19] = "LAr FCALC"
+
+    dName[20] = "Tile BA"
+    dName[21] = "Tile BC"
+    dName[22] = "Tile EA"
+    dName[23] = "Tile EC"
+
+    dName[24] = "MDT BA"
+    dName[25] = "MDT BC"
+    dName[26] = "MDT EA"
+    dName[27] = "MDT EC"
+    dName[28] = "RPC BA"
+    dName[29] = "RPC BC"
+    dName[30] = "TGC EA"
+    dName[31] = "TGC EC"
+
+    dName[32] = "CSC EA"
+    dName[33] = "CSC EC"
+
+    dName[34] = "L1Calo preprocessor"
+    dName[35] = "L1Calo cluster DAQ"
+    dName[36] = "L1Calo cluster RoI"
+    dName[37] = "L1Calo Jet/E DAQ"
+    dName[38] = "L1Calo Jet/E RoI"
+    dName[39] = "MUCTPI"
+    dName[40] = "CTP"
+    dName[41] = "L2SV"
+    dName[42] = "SFI"
+    dName[43] = "SFO"
+    dName[44] = "LVL2"
+    dName[45] = "EF"
+
+    dName[46] = "BCM"
+    dName[47] = "Lucid"
+    dName[48] = "ZDC"
+    dName[49] = "Alfa"
+
+    dName[50] = "TRT_ANCILLARY_CRATE"
+    dName[51] = "TILECAL_LASER_CRATE"
+    dName[52] = "MUON_ANCILLARY_CRATE"
+    dName[53] = "TDAQ_BEAM_CRATE"
+
+    # list of detector NOT part of 'all' tag (means, they can be in, but are not required)
+    notInAll = ['CSC', 'L2SV', 'SFI', 'SFO', 'LVL2', 'EF', 'Lucid', 'ZDC', 'Alfa',
+                'TRT_ANCILLARY_CRATE','TILECAL_LASER_CRATE','MUON_ANCILLARY_CRATE','TDAQ_BEAM_CRATE'  ]
+
+    NotInAll = ['']*64
+    for i in range(0,len(dName)): 
+        for n in notInAll:
+            if dName[i] == n: NotInAll[i] = ' NotInAll'
+
+    vetoedbits = [3, 50, 51, 52, 53] + [x for x in range(54,64)]
+
+    return (dName, NotInAll, vetoedbits)
+
+def DecodeDetectorMask( mask, smart=False ):
+    dName, NotInAll, vetoedbits = InitDetectorMaskDecoder()
+    col = '#000000'
+    if smart: col = '#106734'
+    res = '<b>Detector mask = %i, corresponding to the systems:</b><br><font color="%s">' % (mask,col)
+    ic = 0
+    found = False
+    for i in range(64):
+        if (mask & (1 << i)):
+            found = True
+            res += dName[i] + ", "
+            ic += 1
+    if smart:
+        # check if it is more interesting to give the missing systems
+        if ic > 30:
+            res = '<b>Detector mask = %i.<br> <font color="#aa0000">The following systems are NOT in partition:</b><br>' % mask
+            for i in range(64):
+                if i not in vetoedbits and not (mask & (1 << i)):
+                    found = True
+                    res += dName[i] + ", "
+        
+    # chop off last comma-space
+    if found:
+        if len(res)>1: res = res[:-2]
+        res += '</font>'
+    else:
+        res += '???'
+
+    return res
+
+def LArConfig(type):
+    # runtype, format
+    if 'runtype' in type.lower():
+        return {0:'RawData', 1:'RawDataResult', 2:'Result'}
+    elif 'format' in type.lower():
+        return {0:'Transparent', 1:'Format 1', 2:'Format 2'}
+    else:
+        print 'ERROR in LArconfig: unknown type %s' % type
+        sys.exit()
+             
diff --git a/Database/CoolRunQuery/python/utils/AtlRunQueryMemUtil.py b/Database/CoolRunQuery/python/utils/AtlRunQueryMemUtil.py
new file mode 100644
index 00000000000..f7da298fc68
--- /dev/null
+++ b/Database/CoolRunQuery/python/utils/AtlRunQueryMemUtil.py
@@ -0,0 +1,45 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+import os
+
+_proc_status = '/proc/%d/status' % os.getpid()
+
+_scale = {'kB': 1024.0, 'mB': 1024.0*1024.0,
+          'KB': 1024.0, 'MB': 1024.0*1024.0}
+
+def _VmB(VmKey):
+    '''Private.
+    '''
+    global _proc_status, _scale
+     # get pseudo file  /proc/<pid>/status
+    try:
+        t = open(_proc_status)
+        v = t.read()
+        t.close()
+    except:
+        return 0.0  # non-Linux?
+     # get VmKey line e.g. 'VmRSS:  9999  kB\n ...'
+    i = v.index(VmKey)
+    v = v[i:].split(None, 3)  # whitespace
+    if len(v) < 3:
+        return 0.0  # invalid format?
+     # convert Vm value to bytes
+    return float(v[1]) * _scale[v[2]]
+
+
+def memory(since=0.0):
+    '''Return memory usage in bytes.
+    '''
+    return _VmB('VmSize:') - since
+
+
+def resident(since=0.0):
+    '''Return resident memory usage in bytes.
+    '''
+    return _VmB('VmRSS:') - since
+
+
+def stacksize(since=0.0):
+    '''Return stack size in bytes.
+    '''
+    return _VmB('VmStk:') - since
diff --git a/Database/CoolRunQuery/python/utils/AtlRunQueryTimer.py b/Database/CoolRunQuery/python/utils/AtlRunQueryTimer.py
new file mode 100644
index 00000000000..b91ebcedaa8
--- /dev/null
+++ b/Database/CoolRunQuery/python/utils/AtlRunQueryTimer.py
@@ -0,0 +1,104 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+
+from contextlib import contextmanager
+
+from time import time
+from os import environ
+
+class TimeCount:
+    def __init__(self, name):
+        self.name = name
+        self.totaltime = 0
+        self.subcounts = []
+
+    def __repr__(self):
+        return "%s: %f" % (self.name, self.totaltime)
+
+    def __str__(self):
+        return "%s: %f" % (self.name, self.totaltime)
+
+    def printRecursive(self, lvl):
+        from operator import attrgetter
+        # print myself
+        if self.subcounts:
+            # sum up sub counts
+            ts = sum([x.totaltime for x in self.subcounts])
+            print "%s%-70s : %f (sub sum %f)" % (5*lvl*" ", self.name, self.totaltime, ts)
+        else:
+            print "%s%-70s : %f" % (5*lvl*" ", self.name, self.totaltime)
+        # sort sub counters
+        sortedByTime = sorted(self.subcounts,key=attrgetter('totaltime'),reverse=True)
+        # call print for sub counters
+        for subtc in sortedByTime:
+            subtc.printRecursive(lvl+1)
+
+    def __cmp__(l, r):
+        return cmp(l.name,r)
+        
+
+class TimerStats:
+    level=0
+    total = TimeCount('total')
+    totalFlat = {}
+    context = []
+
+    @classmethod
+    def saveTimeFlat(cls, exectime):
+        n = cls.context[-1]
+        if not n in cls.totalFlat: cls.totalFlat[n] = [0,0]
+        cls.totalFlat[n][0] += exectime
+        cls.totalFlat[n][1] += 1
+
+
+    @classmethod
+    def saveTime(cls, exectime):
+        cur = cls.total # a TimeCount instance
+        for n in cls.context:
+            if n=='total':
+                cur = cls.total
+                continue
+            try:
+                idx = cur.subcounts.index(n)
+                cur = cur.subcounts[idx]
+            except:
+                cur.subcounts += [TimeCount(n)]
+                cur = cur.subcounts[-1]
+        cur.totaltime += exectime
+        cls.saveTimeFlat(exectime)
+
+    @classmethod
+    def printTimeSummary(cls):
+        #import pickle
+        #f = open("timecount.pickle","w")
+        #pickle.dump(cls.total,f)
+        #f.close()
+        cls.total.printRecursive(0)
+
+    @classmethod
+    def printTimeFlat(cls):
+        for name, [time, callcount] in sorted(cls.totalFlat.items(),key=lambda x: x[1][0]):
+            print "%-70s : %f (%i)" % (name, time, callcount)
+
+
+@contextmanager
+def timer(name):
+    "A context manager which spits out how long the block took to execute"
+    if False: #not environ.has_key("ARQDEBUG"):
+        yield
+        return
+
+    from CoolRunQuery.utils.AtlRunQueryTimer import TimerStats as TS
+
+    start = time()
+    TS.level += 1
+    TS.context.append(name)
+    try:
+        yield
+    finally:
+        end = time()
+        execTime = end - start
+        TS.saveTime(execTime)
+        TS.level -= 1
+        TS.context.pop()
+        print "%*s took %.2f sec to %s" % (5*TS.level, "...", execTime, name)
diff --git a/Database/CoolRunQuery/python/utils/AtlRunQueryTriggerUtils.py b/Database/CoolRunQuery/python/utils/AtlRunQueryTriggerUtils.py
new file mode 100755
index 00000000000..9df11eed5dc
--- /dev/null
+++ b/Database/CoolRunQuery/python/utils/AtlRunQueryTriggerUtils.py
@@ -0,0 +1,285 @@
+#!/bin/env python
+
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+#
+# ----------------------------------------------------------------
+# Script : AtlRunQueryTriggerUtils.py
+# Project: AtlRunQuery
+# Purpose: Trigger Utility functions for AtlRunQuery
+# Authors: Andreas Hoecker (CERN), Joerg Stelzer (DESY)
+# Created: Oct 27, 2010
+# ----------------------------------------------------------------
+
+try:
+    set
+except NameError:
+    from sets import Set
+    set = Set
+
+from TrigConfigSvc.TrigConfigSvcUtils import getTriggerDBCursor
+
+__cursor=None
+__schema = ""
+
+class TriggerChain:
+    def __init__(self, name, counter, lowername="", lowercounter=-1, forshow=False, forselect=False, level=0):
+        self.name         = name     
+        self.counter      = counter       
+        self.lowername    = "" if lowername=="~" else lowername
+        self.lowercounter = lowercounter  
+        self.forshow      = forshow  
+        self.forselect    = forselect
+        self.multiseeded  = (self.lowername=="") or (',' in self.lowername)
+        self.level        = level
+        self.lower        = None
+        
+    def __repr__(self):
+        return "TC:"+self.name
+
+
+
+
+def getUsedTables(output, condition, schemaname, tables):
+    schemaname = schemaname.rstrip('.')+'.'
+    usedtables = set()
+    for o in output:
+        usedtables.add(o.split('.')[0])
+    for c in condition:
+        for p in c.split():
+            if '.' in p and not '\'' in p: usedtables.add(p.split('.')[0])
+    return ["%s%s %s" % (schemaname,tables[t],t) for t in usedtables]
+
+
+def executeQuery(cursor, output, condition, schemaname, tables, bindvars=()):
+    query = 'select distinct %s from %s where %s' % \
+            (', '.join(output),
+             ', '.join(getUsedTables(output, condition, schemaname, tables)),
+             ' and '.join(condition))
+    if len(bindvars)==0:
+        cursor.execute(str(query))
+    else:
+        cursor.execute(str(query),bindvars)
+
+    return cursor.fetchall()
+
+
+def getL1PskNames(psk):
+    global __cursor, __schema
+    if not __cursor:
+        __cursor,__schema = getTriggerDBCursor("TRIGGERDB")
+
+    if type(psk) == set: psk = list(psk)
+    if type(psk) != list: psk = [psk]
+
+    keyslist = ','.join([str(k) for k in psk if k])
+
+    if keyslist=="":
+        return {}
+
+    tables = { 'L' : 'L1_PRESCALE_SET' }
+
+    output = [ 'L.L1PS_ID', 'L.L1PS_NAME' ]
+
+    condition = [ "L.L1PS_ID in (%s)" % keyslist ]
+
+    res = executeQuery(__cursor, output, condition, __schema, tables)
+
+    return dict(res)
+
+
+
+def getHLTPskNames(psk):
+    global __cursor, __schema
+    if not __cursor:
+        __cursor,__schema = getTriggerDBCursor("TRIGGERDB")
+
+    if type(psk) == set: psk = list(psk)
+    if type(psk) != list: psk = [psk]
+
+    if len(psk)==0:
+        return {}
+    
+    tables = { 'L' : 'HLT_PRESCALE_SET' }
+
+    output = ['L.HPS_ID', 'L.HPS_NAME']
+
+    prescales = [str(k) for k in psk if k]
+
+    if len(prescales)==0: return {}
+
+    condition = [ "L.HPS_ID in (%s)" % ','.join(prescales) ]
+
+    res = executeQuery(__cursor, output, condition, __schema, tables)
+
+    return dict(res)
+
+
+def getSmkNames(smk):
+    global __cursor, __schema
+    if not __cursor:
+        __cursor,__schema = getTriggerDBCursor("TRIGGERDB")
+
+    if type(smk) == set: smk = list(smk)
+    if type(smk) != list: smk = [smk]
+
+    if len(smk)==0:
+        return {}
+    
+    tables = { 'S' : 'SUPER_MASTER_TABLE' }
+
+    output = ['S.SMT_ID', 'S.SMT_NAME', 'S.SMT_VERSION', 'S.SMT_COMMENT']
+
+    condition = [ "S.SMT_ID in (%s)" % ','.join([str(k) for k in smk]) ]
+
+    res = executeQuery(__cursor, output, condition, __schema, tables)
+
+    return dict([ (r[0],(r[1],r[2],r[3])) for r in res])
+
+def getHLTMenu(smk):
+    global __cursor, __schema
+    if not __cursor:
+        __cursor,__schema = getTriggerDBCursor("TRIGGERDB")
+
+    output = ['TC.HTC_NAME', 'TC.HTC_CHAIN_COUNTER', 'TC.HTC_LOWER_CHAIN_NAME', 'TC.HTC_L2_OR_EF' ]
+    
+    tables = {}
+    tables['SM']    = 'SUPER_MASTER_TABLE'
+    tables['HM']    = 'HLT_MASTER_TABLE'
+    tables['M2C']   = 'HLT_TM_TO_TC'
+    tables['TC']    = 'HLT_TRIGGER_CHAIN'
+
+    
+    condition = [ "SM.SMT_ID = :smk",
+                  'SM.SMT_HLT_MASTER_TABLE_ID = HM.HMT_ID',
+                  'HM.HMT_TRIGGER_MENU_ID = M2C.HTM2TC_TRIGGER_MENU_ID',
+                  'M2C.HTM2TC_TRIGGER_CHAIN_ID = TC.HTC_ID' ]
+    
+    bindvars = { "smk": smk }
+    
+    res = executeQuery(__cursor, output, condition, __schema, tables, bindvars)
+
+    l2chains = []
+    efchains = []
+
+    for r in res:
+        if r[3]=='L2':
+            l2chains += [TriggerChain(r[0],r[1],r[2], level=2)]
+        elif r[3]=='EF':
+            efchains += [TriggerChain(r[0],r[1],r[2], level=3)]
+
+    return l2chains, efchains
+
+def getL1Menu(smk):
+    global __cursor, __schema
+    if not __cursor:
+        __cursor,__schema = getTriggerDBCursor("TRIGGERDB")
+
+    output = ['TI.L1TI_NAME', 'TI.L1TI_CTP_ID' ]
+    
+    tables = {}
+    tables['SM']    = 'SUPER_MASTER_TABLE'
+    tables['M']     = 'L1_MASTER_TABLE'
+    tables['M2I']   = 'L1_TM_TO_TI'
+    tables['TI']    = 'L1_TRIGGER_ITEM'
+
+    
+    condition = [ "SM.SMT_ID = :smk",
+                  'SM.SMT_L1_MASTER_TABLE_ID = M.L1MT_ID',
+                  'M.L1MT_TRIGGER_MENU_ID = M2I.L1TM2TI_TRIGGER_MENU_ID',
+                  'M2I.L1TM2TI_TRIGGER_ITEM_ID = TI.L1TI_ID' ]
+
+    bindvars = { "smk": smk }
+    
+    res = executeQuery(__cursor, output, condition, __schema, tables, bindvars)
+
+    items = 256*[None]
+
+    for r in res:
+        items[r[1]] = TriggerChain(r[0],r[1])
+    return items
+
+def getL1Prescales(l1prescalekey):
+    global __cursor, __schema
+    if not __cursor:
+        __cursor,__schema = getTriggerDBCursor("TRIGGERDB")
+    
+    tables = { 'L' : 'L1_PRESCALE_SET' }
+    
+    output = ['L.L1PS_VAL%i' % i for i in xrange(1,257)]
+    
+    condition = [ "L.L1PS_ID = :psk" ]
+    
+    bindvars = { "psk": l1prescalekey }
+
+    res = executeQuery(__cursor, output, condition, __schema, tables, bindvars)
+    
+    return res[0][0:256]
+
+
+def getHLTPrescales(hltprescalekey):
+    global __cursor, __schema
+    if not __cursor:
+        __cursor,__schema = getTriggerDBCursor("TRIGGERDB")
+    
+    tables = { 'H' : 'HLT_PRESCALE_SET',
+               'P' : 'HLT_PRESCALE'
+               }
+    
+    output = [ 'P.HPR_L2_OR_EF', 'P.HPR_CHAIN_COUNTER', 'P.HPR_PRESCALE', 'P.HPR_PASS_THROUGH_RATE' ]
+    
+    condition = [ "P.HPR_PRESCALE_SET_ID = :psk", "P.HPR_L2_OR_EF not like 'express'" ]
+    
+    bindvars = { "psk": hltprescalekey }
+
+    res = executeQuery(__cursor, output, condition, __schema, tables, bindvars)
+
+    l2ps = {}
+    efps = {}
+    for r in res:
+        if r[0]=='L2':   l2ps[r[1]] = ( float(r[2]), float(r[3]) )
+        elif r[0]=='EF': efps[r[1]] = ( float(r[2]), float(r[3]) )
+
+    return l2ps, efps
+
+
+def getRandom(smk):
+    global __cursor, __schema
+    if not __cursor:
+        __cursor,__schema = getTriggerDBCursor("TRIGGERDB")
+
+    if smk=='n.a.':
+        return ('n.a.','n.a.')
+
+    tables = { 'S' : 'SUPER_MASTER_TABLE',
+               'M' : 'L1_MASTER_TABLE',
+               'R' : 'L1_RANDOM'
+               }
+    
+    output = [ 'R.L1R_RATE1', 'R.L1R_RATE2' ]
+    
+    condition = [ "S.SMT_ID=:smk", "S.SMT_L1_MASTER_TABLE_ID=M.L1MT_ID", "M.L1MT_RANDOM_ID=R.L1R_ID" ]
+    
+    bindvars = { "smk": smk }
+
+    res = executeQuery(__cursor, output, condition, __schema, tables, bindvars)
+
+    return res[0]
+
+
+
+if __name__=="__main__":
+    #print getL1PskNames([2517, 2518, 2284, 2536])
+
+    #print getHLTPskNames([2517, 2530, 2537, 2491])
+    
+    #print getSmkNames([931, 932, 933])
+
+    #print getL1Menu(931)
+
+    #print getHLTMenu(931)
+
+    #print getL1Prescales(2517)
+
+    #print getHLTPrescales(2530)
+
+    print getRandom(1038)
diff --git a/Database/CoolRunQuery/python/utils/AtlRunQueryUtils.py b/Database/CoolRunQuery/python/utils/AtlRunQueryUtils.py
new file mode 100644
index 00000000000..8160a3fa187
--- /dev/null
+++ b/Database/CoolRunQuery/python/utils/AtlRunQueryUtils.py
@@ -0,0 +1,633 @@
+#!/bin/env
+
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+#
+# ----------------------------------------------------------------
+# Script : AtlRunQueryUtils.py
+# Project: AtlRunQuery
+# Purpose: Utility functions for AtlRunQuery
+# Authors: Andreas Hoecker (CERN), Joerg Stelzer (DESY)
+# Created: Jan 20, 2009
+# ----------------------------------------------------------------
+#
+
+from __future__ import with_statement
+from .AtlRunQueryTimer import timer
+
+from collections import namedtuple, defaultdict
+import sys, os, time, re, calendar
+from math import exp,sqrt,pi
+from PyCool import cool
+from copy import copy, deepcopy
+import cx_Oracle
+import struct
+import urllib
+
+from httplib import HTTP
+from urlparse import urlparse
+
+import DQDefects
+
+def checkURL(url):
+    p = urlparse(url)
+    h = HTTP(p[1])
+    h.putrequest('HEAD', p[2])
+    h.endheaders()
+    if h.getreply()[0] == 200: return 1
+    else: return 0
+
+class RunPeriods():
+    def findPeriod( self, runno ):
+        from CoolRunQuery.AtlRunQueryCOMA import ARQ_COMA
+        s = ",".join( ARQ_COMA.get_periods_for_run(runno) )
+        return s
+
+class Enumerate(object):
+    def __init__(self, names):
+        for number, name in enumerate(names.split()):
+            setattr(self, name, number)
+
+def runsOnServer():
+    hostname = os.getenv('HOSTNAME')
+    return re.match('voatlas(197|218|262).cern.ch',hostname)
+
+def importroot(batch=True):
+    import sys
+    cmdline_args = sys.argv
+    sys.argv[1:]=[]
+    if batch:
+        sys.argv += ['-b']
+    import ROOT
+    ROOT.gROOT.SetBatch(batch)
+    if batch:
+        del sys.argv[1]
+    # import PyCintex
+    # PyCintex.Cintex.Enable()
+    ROOT.gErrorIgnoreLevel = 2000 # to avoid printout when creating images
+    sys.argv=cmdline_args
+    return ROOT
+
+
+def prettyNumber( n, width=-1, delim=',',decimal='.' ):
+    """Converts a float to a string with appropriately placed commas"""
+    if width >= 0: s = "%.*f" % (width, n)
+    else: s = str(n)
+    dec = s.find(decimal)
+    if dec == -1: dec = len(s)
+    threes = int((dec-1)/3) 
+    for i in xrange(threes):
+        loc = dec-3*(i+1)
+        s = s[:loc] + delim + s[loc:]
+    return s
+
+def durationInSeconds( duration_string ):
+    lst = duration_string.split()
+    sec = 0
+    for l in lst:
+        if   's' in l: sec += int(l.replace('s',''))
+        elif 'm' in l: sec += int(l.replace('m',''))*60
+        elif 'h' in l: sec += int(l.replace('h',''))*3600
+        elif 'd' in l: sec += int(l.replace('d',''))*3600*24
+        elif 'w' in l: sec += int(l.replace('w',''))*3600*24*7
+        elif 'y' in l: sec += int(l.replace('y',''))*3600*24*365
+        else:
+            print 'Big troubles... in function "AtlRunQueryUtils::durationInSeconds": cannot decode string "%s"' % l
+            sys.exit(1)
+    return sec
+
+class DBConnectionController:
+    def __init__(self):
+        self.openConn = {}
+        self.pw = {}
+
+    def GetDBConn(self, schema, db):
+        """for example schema=COOLONL_TRIGGER', db='COMP200"""
+        if (schema,db) in self.openConn:
+            return self.openConn[(schema,db)]
+        try:
+            if schema=="DEFECTS":
+                #from AthenaCommon.Logging import logging # this is needed because of some problem in DQUtils logger
+                # the logger there, if called first makes the athena logger crash
+                defdb = DQDefects.DefectsDB("COOLOFL_GLOBAL/COMP200",tag=db)
+                defdb.closeDatabase = lambda: None
+                self.openConn[(schema,db)] = defdb
+            else:
+                readoracle=False # Richard: Tools which expect to read from the real
+                                 # data conditions database have to be
+                                 # setup in such a way as to ignore SQLite
+                                 # replicas have to use 'indirectOpen' with
+                                 # the oracle=True argument
+                logging=False
+                from CoolConvUtilities.AtlCoolLib  import indirectOpen
+                self.openConn[(schema,db)] = indirectOpen("%s/%s"%(schema,db),True,readoracle, logging)
+        except Exception, e:
+            print e
+            sys.exit(-1)
+        return self.openConn[(schema,db)]
+
+    def get_auth(self,key):
+        if key not in self.pw:
+            from os import environ as env
+            #lookup = XMLReader(env['CORAL_DBLOOKUP_PATH']+"/dblookup.xml")
+            #for s in lookup.servicelist.logicalservices:
+            #    print "Service",s['name']
+            #    for p in s.services:
+            #        print "   name",p['name']
+            auth = XMLReader(env['CORAL_AUTH_PATH']+"/authentication.xml")
+            for c in auth.connectionlist.connections:
+                if key!=c['name']: continue
+                self.pw[key] = dict([(p['name'],p['value']) for p in c.parameters])
+                break
+            if key not in self.pw:
+                print "Can not authenticate DB",key
+                sys.exit(0)
+        return self.pw[key]
+
+
+    def GetAtlasRunDBConnection(self):
+        if not 'run' in self.openConn:
+            auth = self.get_auth('oracle://ATLAS_COOLPROD/ATLAS_COOLOFL_TRIGGER')
+            self.openConn['run'] = cx_Oracle.connect("%s/%s@ATLAS_COOLPROD" % (auth['user'],auth['password']))
+        return self.openConn['run']
+
+    def GetSFODBConnection(self):
+        if not 'sfo' in self.openConn:
+            #auth = self.get_auth('oracle://ATLAS_CONFIG/ATLAS_SFO_T0')
+            #self.openConn['sfo'] = cx_Oracle.connect("%s/%s@ATLAS_CONFIG" % (auth['user'],auth['password']))
+            self.openConn['sfo'] = cx_Oracle.connect("ATLAS_SFO_T0_R/readmesfotz2008@ATLAS_CONFIG")
+        return self.openConn['sfo']
+
+    def GetTier0DBConnection(self):
+        if not 'tier0' in self.openConn:
+            #auth = self.get_auth('oracle://ATLAS_T0/ATLAS_T0')
+            #self.openConn['tier0'] = cx_Oracle.connect("%s/%s@ATLAS_T0" % (auth['user'],auth['password']))
+            self.openConn['tier0'] = cx_Oracle.connect("ATLAS_T0_R1/titft0ra@ATLAS_T0")
+        return self.openConn['tier0']
+
+    def GetPVSSDBConnection(self):
+        if not 'pvss' in self.openConn:
+            #auth = self.get_auth('oracle://ATLAS_PVSSPROD/ATLAS_PVSS_READER')
+            #self.openConn['pvss'] = cx_Oracle.connect("%s/%s@ATLAS_PVSSPROD" % (auth['user'],auth['password']))
+            self.openConn['pvss'] = cx_Oracle.connect("ATLAS_PVSS_READER/PVSSRED4PRO@ATLAS_PVSSPROD")
+        return self.openConn['pvss']
+
+    def CloseAll(self):
+        for (dbname,dbconn) in self.openConn.items():
+            if isinstance(dbconn,cx_Oracle.Connection):
+                dbconn.close()
+            else:
+                dbconn.closeDatabase()
+
+
+coolDbConn = DBConnectionController()
+
+def addKommaToNumber(no):
+    gr = [str(no)]
+    if not gr[0].isdigit(): return gr[0]
+    while gr[0]:
+        gr[0:1]=[gr[0][:-3],gr[0][-3:]]
+    return ','.join(gr[1:])
+
+def filesize(no):
+    if no == None: return "n.a."
+    if no>0x4000000000000: return "%1.1f&nbsp;PB" % (no*1.0/0x4000000000000)
+    if no>0x10000000000:   return "%1.1f&nbsp;TB" % (no*1.0/0x10000000000)
+    if no>0x40000000:      return "%1.1f&nbsp;GB" % (no*1.0/0x40000000)
+    if no>0x100000:        return "%1.1f&nbsp;MB" % (no*1.0/0x100000)
+    if no>0x400:           return "%1.1f&nbsp;kB" % (no*1.0/0x400)
+    return "%i&nbsp;B" % no
+
+
+# a helper function to decode range lists and merge the intervals
+# par: listOfRanges: [(b1,e1),(b2,e2),....,(bn,en)]  ->   [(b1,e2),....,(bn,en)] if b2-1<=e1
+def MergeRanges(listOfRanges):
+    listOfRanges.sort()
+    newRR=[]
+    for rr in listOfRanges:
+        if len(newRR)==0 or rr[0]-1>newRR[-1][1]:
+            newRR.append(copy(rr))
+        else:
+            newRR[-1] = [newRR[-1][0], max(rr[1],newRR[-1][1]) ]
+    return newRR
+
+# a helper function to decode range lists and merge the intervals (like above)
+# par: listOfRanges: [(b1,e1],(b2,e2],....,(bn,en]]  ->   [(b1,e2],....,(bn,en]] if b2<=e1
+def MergeLBRanges(listOfRanges):
+    listOfRanges.sort()
+    newRR=[]
+    for rr in listOfRanges:
+        if len(newRR)==0 or rr[0]>newRR[-1][1]:
+            newRR.append(copy(rr))
+        else:
+            newRR[-1] = (newRR[-1][0], max(rr[1],newRR[-1][1]) )
+    return newRR
+
+class Matrix(object):
+
+    def __init__(self, cols, rows):
+        self.cols = cols
+        self.rows = rows
+        # initialize matrix and fill with zeroes
+        self.matrix = []
+        for i in range(rows):
+            ea_row = []
+            for j in range(cols):
+                ea_row.append(0)
+            self.matrix.append(ea_row)
+
+    def setitem(self, col, row, v):
+        self.matrix[col-1][row-1] = v
+
+    def getitem(self, col, row):
+        return self.matrix[col-1][row-1]
+
+    def __repr__(self):
+        outStr = ""
+        for i in range(self.rows):
+            outStr += 'Row %s = %s\n' % (i+1, self.matrix[i])
+        return outStr
+
+    def __iter__(self):
+        for row in range(self.rows):
+            for col in range(self.cols):
+                yield (self.matrix, row, col)  
+
+def stringToIntOrTime(s):
+    if re.match("^\d+$",s): return int(s)
+    # convert the string into seconds since epoch
+
+    # string is meant to be UTC time (hence we need calendar.timegm
+    # and not time.mktime to convert the tuple into seconds)
+    t = int(1E9*calendar.timegm(time.strptime(s,"%d.%m.%Y")))
+    #print "turning",s,"into time",t
+    #print "cross-check:",time.strftime("%d.%m.%Y %H:%M:%S",time.gmtime(t/1E9))
+    return t
+
+def timeStringToSecondsUTC(t):
+    """ convert string into seconds since epoch
+
+    string is meant to be UTC time (hence we need calendar.timegm
+    and not time.mktime to convert the tuple into seconds)
+
+    format can be '1.5.2010_14:23:10', '1.5.2010 14:23:10', or '1.5.2010'
+    """
+    try:
+        t = time.strptime(t,"%d.%m.%Y")
+    except ValueError:
+        try:
+            t = time.strptime(t,"%d.%m.%Y %H:%M:%S")
+        except:
+            t = time.strptime(t,"%d.%m.%Y_%H:%M:%S")
+
+    return int(calendar.timegm(t))
+
+def timeStringToSecondsLocalTime(t):
+    """ convert string into seconds since epoch
+
+    string is meant to be in local time (hence we use time.mktime
+    and not calender.timegm to convert the tuple into seconds)
+
+    format can be '1.5.2010_14:23:10', '1.5.2010 14:23:10', or '1.5.2010'
+    """
+    try:
+        t = time.strptime(t,"%d.%m.%Y")
+    except ValueError:
+        try:
+            t = time.strptime(t,"%d.%m.%Y %H:%M:%S")
+        except:
+            t = time.strptime(t,"%d.%m.%Y_%H:%M:%S")
+
+    return int(time.mktime(t))
+
+def secondsToTimeStringUTC(s):
+    # convert seconds since epoch into utc
+    return time.strftime("%d.%m.%Y %H:%M:%S",time.gmtime(s))
+
+
+def secondsToTimeStringLocaltime(s):
+    # convert seconds since epoch into localtime
+    return time.strftime("%d.%m.%Y %H:%M:%S",time.localtime(s))
+
+
+
+def GetRanges(rangestr, intRepFnc=stringToIntOrTime, maxval=1<<30):
+    if type(rangestr)==list:
+        ranges = rangestr
+    else:
+        if rangestr[:4]=='STR:':
+            return [ [rangestr[4:], rangestr[4:]] ]
+        ranges = rangestr.split(',')
+    listOfRanges = []
+    for r in ranges:
+        if r == '-':
+            listOfRanges += [[0,maxval]]
+        elif not ('-' in r or '+' in r):
+            # single value
+            x = intRepFnc(r)
+            listOfRanges += [[x,x]]
+        elif r[-1] == '+':
+            listOfRanges += [[intRepFnc(r[:-1]),maxval]]
+        elif r[-1] == '-':
+            listOfRanges += [[0,intRepFnc(r[:-1])]]
+        else:
+            startend = r.split('-')
+            if len(startend)!=2:
+                raise RuntimeError, "Range format error '%s'" % r
+            listOfRanges += [[intRepFnc(x) for x in startend]]
+    return MergeRanges(listOfRanges)
+
+
+
+
+def full_time_string(s,startofday):
+    try:
+        time.strptime(s,"%d.%m.")
+        year=str(time.gmtime().tm_year)
+        return s+year+"_00:00:00" if startofday else s+year+"_23:59:59"
+    except:
+        try:
+            time.strptime(s,"%d.%m.%Y")
+            return s+"_00:00:00" if startofday else s+"_23:59:59"
+        except:
+            return s
+
+def GetTimeRanges(timeranges, intRepFnc=timeStringToSecondsUTC, maxval=1<<30):
+    if type(timeranges)==list:
+        timeranges = ','.join(timeranges)
+
+    timeranges = timeranges.split(',')
+    listOfRanges = []
+    listOfRangesHR = []
+
+    for r in timeranges:
+        start = 0
+        end = 'inf'
+        if r == '-':
+            listOfRangesHR += [['0','inf']]
+        elif not ('-' in r or '+' in r):
+            # single value
+            start = full_time_string( r, startofday=True )
+            end   = full_time_string( r, startofday=False )
+        elif r[-1] == '+':
+            start = full_time_string( r[:-1], startofday=True )
+        elif r[-1] == '-':
+            end   = full_time_string( r[:-1], startofday=False )
+        else:
+            try:
+                start,end = r.split('-')
+            except:
+                raise RuntimeError, "Time format '%s' wrong, should be 'from-until'" % r
+            start = full_time_string( start, startofday=True )
+            end   = full_time_string( end, startofday=False )
+
+        listOfRangesHR += [[start,end]]
+        start = 0 if start==0 else intRepFnc(start)
+        end   = maxval if end=='inf' else intRepFnc(end)
+        listOfRanges += [[start,end]]
+
+    return MergeRanges(listOfRanges),listOfRangesHR
+
+
+def SmartRangeCalulator(runlist,singleRuns=False):
+    if len(runlist) == 0:
+        return []
+    if type(runlist[0]) == type([]):
+        return runlist
+    if singleRuns:
+        rr = [[r.runNr,r.runNr] for r in runlist]
+    else:
+        rr = [[runlist[0].runNr,runlist[-1].runNr]]
+    return rr
+
+
+def UnpackBCID(blob, nb1, nb2, nbc):
+    size = nb1+nb2+nbc
+    a = struct.unpack( size*'H', blob[:2*size])  
+    return a[0:nb1], a[nb1:nb1+nb2], a[nb1+nb2:] # beam1, beam2, coll
+
+
+def Poisson( n, mu ):
+    # only valid for small mu and integer n
+    if   n < 0 : return 0
+    else:
+        p = exp(-mu)
+        for i in xrange(n):
+            p *= mu
+            p /= float(i+1)
+        return p
+
+def ComputePileup( lumi_mb, sigma, nbunch, fOrbit ):
+    # sanity
+    if nbunch <= 0: return 0
+
+    # compute first probability of interaction    
+    nint = lumi_mb*sigma/fOrbit/nbunch
+    if nint > 100: return nint
+
+    # small 'nint', compute poisson probabilities
+    p = []
+    for n in xrange(40):
+        p.append(Poisson(n,nint))
+        if n > 20 and p[-1] < 1e40: break
+    return nint, p
+
+def Pileup( args ):
+    # orbit revolution frequency
+    fOrbit = 11245.511 # [Hz] given by: 40.0790e6 Hz (bunch frequency) / 3564 (nbunches)
+
+    if len(args) < 3:
+        return '<font color="red">ERROR: need at least 3 arguments for pileup calculation: inst.-lumi cross-section-in-mb nbunch [nevents]</font>'
+    try:    
+        fstarg = float(args[0])
+        if fstarg < 1e20:
+            # input expects first two arguments to be number of protons and transverse beam size
+            nprotons = fstarg
+            sigtrans = float(args[1]) # given in microns
+            sigtrans *= 1e-4          # transform to cm
+            
+            sigma    = float(args[2])
+            nbunch   = float(args[3])
+            lumi     = nprotons**2 * fOrbit * nbunch / (4.0 * pi * sigtrans**2)
+            nevents  = 1
+            if len(args) == 5: nevents = float(args[4])
+        else:
+            # input expects first argument to be luminosity in cm-2s-1
+            lumi     = float(args[0])
+            sigma    = float(args[1])
+            nbunch   = float(args[2])
+            nevents  = 1
+            if len(args) == 4: nevents = float(args[3])
+
+        # compute pileup
+        lumi_mb = lumi/1.e27  # luminosity in mb-1s-1
+        pint, plist = ComputePileup( lumi_mb, sigma, nbunch, fOrbit )
+
+        # create output string        
+        s = ' '
+        s += '<table class="datasettable" style="font-size: 140%">'
+        s += '<tr><td>Instantaneous luminosity :</td><td> %g cm&minus;2s&minus;1 (= %g mb&minus;1s&minus;1)</td></tr>' % (lumi, lumi_mb)
+        s += '<tr><td>Inelastic cross section :</td><td> %g mb</td></tr>' % sigma
+        s += '<tr><td>Number of colliding bunches :</td><td> %g</td></tr>' % nbunch
+        s += '<tr><td colspan="2"><hr style="width:100%; #999999; background-color: #999999; height:1px; margin-left:0px; border:0"></td></tr>'
+        s += '<tr><td>Inelastic interaction rate:</td><td>%g Hz</td></tr>' % (lumi_mb*sigma)
+        s += '<tr><td>Average number of interactions per crossing:&nbsp;&nbsp;</td><td> %g</td></tr>' % pint
+        s += '</table>'
+        s += '<hr style="width:100%; #999999; background-color: #999999; height:0px; border:0">\n<p>\n'
+        if not plist:        
+            p = plist[0]
+            s += 'Very large pileup probability (assume Gaussian distribution): %g +- %g' % (p, sqrt(p))
+        else:
+            s += '<table class="pileuptable">'
+            s += '<tr><th>Num. of interactions per filled bunch crossing</th><th>Probability per filled bunch crossing</th><th>Probability per triggered minimum bias event*</th>'
+            if nevents>1:
+                s += '<th>Expected number of events in sample*</th>'
+            s += '</tr>'
+
+            pref = 1.0-plist[0] # probability for a zero bias trigger to have triggered an event
+            psum = 0
+            for i,p in enumerate(plist):
+                if i>=1:
+                    s += '<tr><td>&gt;= %i</td><td>%g</td><td>%g</td>' % (i,1.0-psum,(1.0-psum)/pref)
+                    if nevents > 1:
+                        nevexp = (1.0-psum)/pref*nevents
+                        s += '<td> %g</td>' % (nevexp)
+                    s += '</tr>'
+                if p < 1e-15: break
+                psum += p                
+            s += '</table><p></p>'
+            s += '<font size=-2>*assuming 100% trigger efficiency for inelastic events</font><br>'
+
+        return s
+
+    except ValueError:
+        return '<font color="red">ERROR: only numerical arguments allowed</font>'
+
+
+def get_run_range(start,end=None):
+    runs = get_runs(start,end)
+    if len(runs) == 0: return None
+    if len(runs) == 1: return (runlist[0],runlist[0])
+    return (runs[0],runs[-1])
+
+def get_runs_last_dt(last):
+    lt = last.replace('last','').strip()
+    nsec = durationInSeconds( lt )
+    start = time.gmtime( time.mktime(time.gmtime()) - nsec  )
+    return get_runs(time.strftime("%d.%m.%Y_%H:%M:%S",start))
+
+def get_runs(start,end=None):
+    """start and end are given in the format '1.5.2010_14:23:10', '1.5.2010 14:23:10', or '1.5.2010'"""
+
+    co = coolDbConn.GetAtlasRunDBConnection()
+    cu = co.cursor()
+
+    #available:
+    # NAME,RUNNUMBER,STARTAT,DURATION,CREATEDBY,HOST,PARTITIONNAME,CONFIGSCHEMA,CONFIGDATA,COMMENTS
+    records = 'RUNNUMBER'
+
+    t = time.gmtime( timeStringToSecondsUTC(start) )
+    starttime = time.strftime("%Y%m%dT%H%M%S",t)
+
+    if not end:
+        q = "SELECT %s FROM ATLAS_RUN_NUMBER.RUNNUMBER WHERE STARTAT>'%s' ORDER BY RUNNUMBER desc" % (records,starttime)
+    else:
+        t = time.gmtime( timeStringToSecondsUTC(end) )
+        endtime = time.strftime("%Y%m%dT%H%M%S",t)
+        q = "SELECT %s FROM ATLAS_RUN_NUMBER.RUNNUMBER WHERE STARTAT>'%s' and STARTAT<'%s' ORDER BY RUNNUMBER" % (records,starttime,endtime)
+
+    cu.arraysize=100
+    cu.execute(q)
+
+    res = cu.fetchall()
+    return [r[0] for r in res]
+
+
+def get_run_range2(start,end=None):
+    """start and end are given in the format '1.5.2010_14:23:10', '1.5.2010 14:23:10', or '1.5.2010'"""
+
+    co = coolDbConn.GetAtlasRunDBConnection()
+    cu = co.cursor()
+
+    #available:
+    # NAME,RUNNUMBER,STARTAT,DURATION,CREATEDBY,HOST,PARTITIONNAME,CONFIGSCHEMA,CONFIGDATA,COMMENTS
+
+    t = time.gmtime( timeStringToSecondsUTC(start) )
+    sstart = time.strftime("%Y%m%dT%H%M%S",t)
+
+    # last run that started before the begin of the range
+    subq = "SELECT MAX(RUNNUMBER) FROM ATLAS_RUN_NUMBER.RUNNUMBER WHERE STARTAT<'%s'" % sstart
+    q = "select RUNNUMBER,STARTAT,DURATION from ATLAS_RUN_NUMBER.RUNNUMBER where RUNNUMBER=(%s)" % subq
+    cu.execute(q)
+    try:
+        run1,startat,duration = cu.fetchone()
+        # note that duration is not exact, but always a bit larger than the length of the run
+    
+        endat = calendar.timegm( time.strptime(startat,"%Y%m%dT%H%M%S") ) + duration
+        if end < timeStringToSecondsUTC(start):
+            q = "SELECT MIN(RUNNUMBER) FROM ATLAS_RUN_NUMBER.RUNNUMBER WHERE STARTAT>'%s'" % sstart
+            cu.execute(q)
+            try:
+                run1 = cu.fetchone()[0]
+            except:
+                run1 = None
+    except:
+        run1 = None
+
+    run2 = None
+    if end != None:
+        # last run that started before the end of the range
+        t = time.gmtime( timeStringToSecondsUTC(end) )
+        endtime = time.strftime("%Y%m%dT%H%M%S",t)
+        q = "SELECT MAX(RUNNUMBER) FROM ATLAS_RUN_NUMBER.RUNNUMBER WHERE STARTAT<'%s'" % endtime
+        cu.execute(q)
+        run2 = cu.fetchone()[0]
+
+    return (run1,run2)
+
+
+
+class XMLReader(object):
+    class XMLElement:
+        def __init__(self,element):
+            self.element = element
+            self.tag = element.tag
+            self.attributes = dict(element.items())
+            self.children = element.getchildren()
+            self.readchildren()
+
+        def items(self):
+            return self.attributes.items()
+        def __str__(self):
+            return "<%s %s>" % (self.tag, " ".join(['%s="%s"' % x for x in self.items()]))
+        def __repr__(self):
+            return self.tag
+        def __getitem__(self,k):
+            if not k in self.attributes:
+                raise KeyError, "'%s'. XML element '%s' has attributes %s" % (k,self.tag, self.attributes.keys())
+            return self.attributes[k]
+
+        def readchildren(self):
+            self.childtags = []
+            self._childtagdict = {}
+            for c in self.children:
+                self._childtagdict.setdefault(c.tag,[]).append(XMLReader.XMLElement(c))
+                if not c.tag in self.childtags: self.childtags += [c.tag]
+            for t in self.childtags:
+                self.__dict__['%ss'%t] = self._childtagdict[t]
+                if len(self._childtagdict[t])==1:
+                    self.__dict__['%s'%t] = self._childtagdict[t][0]
+
+        def __getattr__(self,name):
+            raise AttributeError, "'%s'. XML element '%s' has tags %s" % (name,self.tag, ["%ss" % t for t in self.childtags])
+
+
+    def __init__(self,filename):
+        import xml.etree.cElementTree as ET
+        self.doc = ET.parse(filename)
+        root = XMLReader.XMLElement(self.doc.getroot())
+        self.__filename = filename
+        self.__root = root
+        self.__dict__[root.tag] = root
+
+    def __getattr__(self,name):
+        raise AttributeError, "'%s'. XML document '%s' has root tag '%s'" % (name,self.__filename, self.__root.tag)
diff --git a/Database/CoolRunQuery/python/utils/__init__.py b/Database/CoolRunQuery/python/utils/__init__.py
new file mode 100644
index 00000000000..74583d364ec
--- /dev/null
+++ b/Database/CoolRunQuery/python/utils/__init__.py
@@ -0,0 +1,2 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
diff --git a/Database/CoolRunQuery/share/AtlRunQuery.py b/Database/CoolRunQuery/share/AtlRunQuery.py
new file mode 100755
index 00000000000..e8aa05f57a8
--- /dev/null
+++ b/Database/CoolRunQuery/share/AtlRunQuery.py
@@ -0,0 +1,83 @@
+#!/bin/env python
+#
+# ----------------------------------------------------------------
+# Script : AtlRunQuery.py
+# Project: AtlRunQuery
+# Purpose: Main
+# Authors: Andreas Hoecker (CERN), Joerg Stelzer (DESY)
+# Created: Nov 13, 2008
+# ----------------------------------------------------------------
+#
+
+import sys, getopt, os
+
+def main():
+    arguments = sys.argv
+
+    if len(arguments) <= 1:
+        print 'No query argument given'
+        return 1
+
+    fileindex = None
+
+    if arguments[1] == 'fileindex':
+        installpath = '/'.join(os.path.dirname(__file__).split('/')[:-1])
+        fileindex = arguments[2]
+        datapath = 'data/arq_%s/arq_%s' % (fileindex[:6],fileindex)
+        queryfile = '%s/%s/query.txt' % (installpath,datapath)
+        fh = open(queryfile,"r")
+        origQuery = fh.readline().strip()
+        fh.close()
+        arguments[1:] = origQuery.split()
+    else:
+        datapath='data'
+        origQuery = ' '.join(arguments[1:])
+    
+    ignoreParser = origQuery.startswith('--')
+
+    from CoolRunQuery.AtlRunQueryOptions import AtlRunQueryOptions
+    if ignoreParser:
+
+        (options, args) = AtlRunQueryOptions().parse()
+        atlqueryarg = origQuery
+
+    else:
+        
+        from CoolRunQuery.AtlRunQueryParser import ArgumentParser
+        ap = ArgumentParser()
+
+        # special treatment of some extra tools: pileup calc, det mask decoding, help(not implemented)
+        firstarg = arguments[1].lower()
+        if firstarg in ['pileup','detmask','help']:
+            tabletemplate = '<table class="othertable" style="width:60%%"><tr><th>Query result:</th></tr><tr><td>\n%s</td></tr></table><p></p><br><p></p>'
+            if firstarg == 'pileup':
+                from CoolRunQuery.AtlRunQueryUtils import Pileup
+                body = tabletemplate % (Pileup(arguments[2:]))
+            elif firstarg == 'detmask':
+                from CoolRunQuery.AtlRunQueryLookup import DecodeDetectorMask
+                body = tabletemplate % (DecodeDetectorMask( int(arguments[2] )))
+            else:
+                body = ''
+
+            # return a default page
+            from CoolRunQuery.AtlRunQueryPageMaker import PageMaker
+            PageMaker.makeDefaultPage(datapath, body, origQuery)
+            return 0
+
+        atlqueryarg = arguments[0].rsplit('/',1)[-1] + " " + ap.ParseArgument( ' '.join(arguments[1:]) )
+
+        if '--verbose' in atlqueryarg:
+            print atlqueryarg
+
+        (options, args) = AtlRunQueryOptions().parse(atlqueryarg)
+
+
+    from CoolRunQuery.AtlRunQueryLib import AtlRunQuery
+    AtlRunQuery(options, html="AUTO", origQuery=origQuery, datapath=datapath, parsedstring=atlqueryarg)  # html can be "YES", "NO", "AUTO"
+    return 0
+
+if __name__ == '__main__':
+    #import cProfile
+    #cProfile.run('main()','prof')
+    import sys
+    sys.exit(main())
diff --git a/Database/CoolRunQuery/share/AtlRunQueryGraphs.py b/Database/CoolRunQuery/share/AtlRunQueryGraphs.py
new file mode 100755
index 00000000000..9bc234a1398
--- /dev/null
+++ b/Database/CoolRunQuery/share/AtlRunQueryGraphs.py
@@ -0,0 +1,116 @@
+#!/usr/bin/env python
+
+import sys,os
+from CoolRunQuery.AtlRunQueryLookup import InitDetectorMaskDecoder, DQChannels
+from ROOT import TFile, TGraph, TH1I
+
+def execute( fname ):
+    file = open( fname, 'r' )
+
+    # first count number of lines in file and find run numbers
+    ic = -1
+    minRun = 1e20
+    maxRun = -1
+    for line in file:
+        if '--------------------' in line:
+            if ic<0: 
+                ic = 0
+                continue
+            else: break
+        if ic >= 0: 
+            # get run number
+            r, sep, line = line.partition(':')
+            runno = int(r.strip('run').strip())
+            if runno > maxRun: maxRun = runno
+            if runno < minRun: minRun = runno
+            ic += 1       
+
+    print 'Found: %i runs in file; run range: [%i, %i]' % (ic,minRun, maxRun)
+    maxRun += 1
+    minRun -= 1
+
+    # --- read detectors ----
+
+    print ' '
+    print 'Reading detectors and DQ flags'
+    (dName, NotInAll) = InitDetectorMaskDecoder()
+    dqchans           = DQChannels()
+
+    # create graphs and histograms
+    rootfile = TFile.Open( "queryresults.root", "RECREATE" )        
+    detgraphs = {}
+    dethists  = {}
+    for det in dName:
+        detc = det.strip().replace(' ','_')        
+        if 'unknown' in detc: continue
+
+        detgraphs[det] = TGraph( ic )
+        detgraphs[det].SetName( 'Det_%s_vs_run_graph' % detc )
+        dethists[det] = TH1I( 'Det_%s_vs_run_hist' % detc, 'Det_%s_vs_run_hist' % detc, maxRun-minRun+1, minRun, maxRun )
+
+    dqhists   = {}
+    for key, dq in dqchans.items():
+        dqhists[dq] = TH1I( 'DQ_%s_vs_run_hist' % dq, 'DQ_%s_vs_run_hist' % dq, maxRun-minRun+1, minRun, maxRun )
+
+    # read lines
+    ip = -1
+    file.seek(0)
+    for line in file:
+        # search for start of output block
+        if '--------------------' in line:
+            for line in file:
+                if '--------------------' in line: break
+                # get run number
+                r, sep, line = line.partition(':')
+                ip += 1
+                runno = int(r.strip('run').strip())
+
+                # check detector
+                for det in dName:
+                    if 'unknown' in det: continue
+                    if det in line: v = 2
+                    else:           v = 1
+                    detgraphs[det].SetPoint( ip, runno, v )
+                    dethists[det].SetBinContent( runno - minRun + 1, v )
+
+                # check DQ flag
+                for key, dq in dqchans.items():
+                    if not dq in line: v = -1
+                    else:           
+                        word = line[line.find( dq ):line.find( dq )+len(dq)+2]
+                        if '=' in word:
+                            w, sep, status = word.partition('=')
+                            status = status.strip().lower()
+                            if   status == 'u': v = 0
+                            elif status == 'g': v = 3
+                            elif status == 'y': v = 2
+                            elif status == 'r': v = 1
+                            else:
+                                print 'ERROR: unknown DQ status: "%s" --> abort' % status
+                                sys.exit(1)
+                            
+                            dqhists[dq].SetBinContent( runno - minRun + 1, v )
+                        else:
+                            print 'ERROR: format error on DQ parsing: "%s" --> abort' % word
+                            sys.exit(1)
+                            
+
+    print 'End of file reading. Found: %i runs' % (ip+1)
+
+    # write all graphs, and finish
+    for key, g in detgraphs.items(): g.Write()
+    for key, h in dethists.items() : h.Write()
+    for key, h in dqhists.items()  : h.Write()
+
+    print 'Wrote root file: %s' % rootfile.GetName()
+    rootfile.Close()
+
+
+# command line driver for convenience
+if __name__=='__main__':
+
+    if len(sys.argv) <= 1:
+        print 'ERROR: Need to give input filename as argument --> abort'
+        sys.exit(0)
+
+    execute( sys.argv[1] )
diff --git a/Database/CoolRunQuery/share/CoolRunQueryWrapper.sh b/Database/CoolRunQuery/share/CoolRunQueryWrapper.sh
new file mode 100755
index 00000000000..035b70230f9
--- /dev/null
+++ b/Database/CoolRunQuery/share/CoolRunQueryWrapper.sh
@@ -0,0 +1,47 @@
+export PATH=\
+/cvmfs/atlas.cern.ch/repo/sw/software/17.0.5/sw/lcg/external/Python/2.6.5/i686-slc5-gcc43-opt/bin:\
+$PATH
+
+export ROOTSYS=/cvmfs/atlas.cern.ch/repo/sw/software/17.0.5/sw/lcg/app/releases/ROOT/5.28.00g/i686-slc5-gcc43-opt/root
+
+export PYTHONPATH=`pwd`:\
+/cvmfs/atlas.cern.ch/repo/sw/software/17.0.5/AtlasProduction/17.0.5.6/InstallArea/python:\
+/cvmfs/atlas.cern.ch/repo/sw/software/17.0.5/AtlasConditions/17.0.5/InstallArea/python:\
+/cvmfs/atlas.cern.ch/repo/sw/software/17.0.5/AtlasCore/17.0.5/InstallArea/i686-slc5-gcc43-opt/lib/python2.6:\
+/cvmfs/atlas.cern.ch/repo/sw/software/17.0.5/AtlasCore/17.0.5/InstallArea/python:\
+/cvmfs/atlas.cern.ch/repo/sw/software/17.0.5/AtlasTrigger/17.0.5/InstallArea/python:\
+/cvmfs/atlas.cern.ch/repo/sw/software/17.0.5/external/ZSI/2.1-a1/lib/python:\
+/cvmfs/atlas.cern.ch/repo/sw/software/17.0.5/sw/lcg/app/releases/COOL/COOL_2_8_10b/i686-slc5-gcc43-opt/python:\
+$ROOTSYS/lib:\
+/cvmfs/atlas.cern.ch/repo/sw/software/17.0.5/sw/lcg/external/pygraphics/1.1p1_python2.6/i686-slc5-gcc43-opt/lib/python2.6/site-packages:\
+/cvmfs/atlas.cern.ch/repo/sw/software/17.0.5/sw/lcg/external/pytools/1.4_python2.6/i686-slc5-gcc43-opt/lib/python2.6/site-packages
+
+export LD_LIBRARY_PATH=\
+/cvmfs/atlas.cern.ch/repo/sw/software/17.0.5/AtlasConditions/17.0.5/InstallArea/i686-slc5-gcc43-opt/lib:\
+/cvmfs/atlas.cern.ch/repo/sw/software/17.0.5/DetCommon/17.0.5/InstallArea/i686-slc5-gcc43-opt/lib:\
+/cvmfs/atlas.cern.ch/repo/sw/software/17.0.5/LCGCMT/LCGCMT_60d/InstallArea/i686-slc5-gcc43-opt/lib:\
+/cvmfs/atlas.cern.ch/repo/sw/software/17.0.5/sw/lcg/external/Python/2.6.5/i686-slc5-gcc43-opt/lib:\
+/afs/cern.ch/sw/lcg/external/gcc/4.3.2/x86_64-slc5/lib:\
+/usr/lib
+
+# for the dbreplica.config file
+export DATAPATH=\
+/cvmfs/atlas.cern.ch/repo/sw/software/17.0.5/AtlasCore/17.0.5/InstallArea/share
+
+export CORAL_DBLOOKUP_PATH=/data/atrqadm/authentication
+export CORAL_AUTH_PATH=/data/atrqadm/authentication
+
+export TNS_ADMIN=/cvmfs/atlas.cern.ch/repo/sw/software/17.0.5/DBRelease/current/oracle-admin
+
+export HOSTNAME=$HOSTNAME
+
+export NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1
+
+export COOL_DISABLE_CORALCONNECTIONPOOLCLEANUP=YES
+
+unset HOME
+
+printenv
+
+`pwd`/share/AtlRunQuery.py $*
+
diff --git a/Database/CoolRunQuery/share/CoolRunQueryWrapper47.sh b/Database/CoolRunQuery/share/CoolRunQueryWrapper47.sh
new file mode 100755
index 00000000000..614c56b845d
--- /dev/null
+++ b/Database/CoolRunQuery/share/CoolRunQueryWrapper47.sh
@@ -0,0 +1,37 @@
+export PATH=\
+/afs/cern.ch/sw/lcg/external/Python/2.6.5/i686-slc5-gcc43-opt/bin:\
+$PATH
+
+export ROOTSYS=/data/atrqadm/sw/root
+
+export PYTHONPATH=`pwd`:\
+/data/atrqadm/sw/InstallArea/python:\
+/afs/cern.ch/atlas/software/builds/AtlasConditions/16.0.1/InstallArea/python:\
+/afs/cern.ch/atlas/software/builds/AtlasCore/16.0.1/InstallArea/i686-slc5-gcc43-opt/lib/python2.6:\
+/afs/cern.ch/atlas/software/builds/AtlasCore/16.0.1/InstallArea/python:\
+/afs/cern.ch/atlas/software/builds/AtlasTrigger/16.0.1/InstallArea/python:\
+/afs/cern.ch/atlas/offline/external/ZSI/2.1-a1/lib/python:\
+/afs/cern.ch/sw/lcg/app/releases/COOL/COOL_2_8_7/i686-slc5-gcc43-opt/python:\
+$ROOTSYS/lib:\
+/afs/cern.ch/sw/lcg/external/pytools/1.2_python2.6/i686-slc5-gcc43-opt/lib/python2.6/site-packages
+
+export LD_LIBRARY_PATH=\
+/data/atrqadm/sw/InstallArea/i686-slc5-gcc43-opt/lib:\
+/afs/cern.ch/atlas/software/builds/DetCommon/16.0.1/InstallArea/i686-slc5-gcc43-opt/lib:\
+/afs/cern.ch/atlas/offline/external/LCGCMT/LCGCMT_59a/InstallArea/i686-slc5-gcc43-opt/lib:\
+/afs/cern.ch/sw/lcg/external/Python/2.6.5/i686-slc5-gcc43-opt/lib:\
+/afs/cern.ch/sw/lcg/external/gcc/4.3.2/x86_64-slc5/lib:\
+/usr/lib
+
+export CORAL_DBLOOKUP_PATH=/data/atrqadm/authentication
+export CORAL_AUTH_PATH=/data/atrqadm/authentication
+
+export TNS_ADMIN=/afs/cern.ch/sw/lcg/external/oracle/11.2.0.1.0p2/admin
+export HOSTNAME=$HOSTNAME
+
+export NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1
+
+export COOL_DISABLE_CORALCONNECTIONPOOLCLEANUP=YES
+
+`pwd`/share/AtlRunQuery.py $*
+
diff --git a/Database/CoolRunQuery/share/easycommit b/Database/CoolRunQuery/share/easycommit
new file mode 100755
index 00000000000..bd9b35b235d
--- /dev/null
+++ b/Database/CoolRunQuery/share/easycommit
@@ -0,0 +1,124 @@
+#!/usr/bin/env python
+
+#from subprocess import Popen, PIPE
+from commands import getstatusoutput,getoutput
+import sys,re
+
+def updateSNVTagInFile(newtag):
+
+    print "updating html/atlas-runquery.html to tag",newtag
+    p = re.compile("(^.*)CoolRunQuery-\d\d-\d\d-\d\d(.*$)",re.DOTALL)
+    out = []
+    f = open("html/atlas-runquery.html",'r')
+    for line in f:
+        m = p.match(line)
+        if m:
+            out += [m.group(1)+newtag+m.group(2)]
+        else:
+            out += [line]
+    f.close()
+
+    f = open("html/atlas-runquery.html",'w')
+    for l in out: f.write(l)
+    f.close()
+
+    print "updating python/AtlRunQueryVersion.py to tag",newtag
+    f = open("python/AtlRunQueryVersion.py",'w')
+    f.write("SvnVersion = '%s'" % newtag)
+    f.close()
+
+
+
+# get package URL
+#info = Popen("svn info".split(),stdout=PIPE).communicate()[0].splitlines()
+url = getoutput("svn info | grep '^URL'").splitlines()[0]
+p  = re.compile("URL: (.*)/(trunk)/?()(.*)")
+p2 = re.compile("URL: (.*)/(tags)/([^/]+)/{0,1}(.*)")
+p3 = re.compile("URL: (.*)/(branches)/([^/]+)/{0,1}(.*)")
+pkgurl = None
+
+m=p.match(url)
+if not m: m=p2.match(url)
+if not m: m=p3.match(url)
+
+if not m:
+    print "Must be in the package directory"
+    sys.exit(1)
+
+pkgurl, what, tag, subdir = m.groups()
+
+if subdir:
+    print "Must be in the package directory and not in a sub-directory"
+    sys.exit(1)
+
+if what=='tags':
+    print "Must be in the trunk or a branch"
+    sys.exit(1)
+    
+# find the last
+if what=='branches':
+    branchbase = tag[:tag.rfind('-')]
+    cmd = "svn list %s/tags | grep %s" % (pkgurl, branchbase)
+else:
+    cmd = "svn list %s/tags" % pkgurl
+    
+tags = getoutput(cmd).splitlines()
+if what=='branches': print "Last five branch tags are"
+else: print "Last five tags are"
+for l in tags[-5:]:
+    print "  "+ l.rstrip('/')
+
+last = tags[-1].rstrip('/')
+
+# new tag suggestion
+if what=='branches' and last.count('-')==3:
+    newtag = branchbase+'-01'
+else:
+    newtag = ''
+    ls = last.split('-')
+    nti = int(''.join(ls[1:]))+1
+    for x in range(len(ls)-1):
+        nti % 100
+        newtag = ("-%02i" % (nti%100)) + newtag
+        nti /= 100
+    newtag = ls[0] + newtag
+
+# extract comment from Changelog
+FH=open("ChangeLog")
+FH.readline()
+comment=FH.readline().strip().strip('*').strip()
+comment.replace("'","")
+FH.close()
+
+# edit
+updateSNVTagInFile(newtag)
+
+print "Comment: '%s'" % comment
+answer = raw_input("Would you like to edit html, commit and tag as %s? [Y/n]> " % newtag)
+
+cmdci = "svn ci -m '%s'" % comment
+
+if what=='trunk':
+    cmdtag = "svn cp -m '%s' %s/trunk %s/tags/%s" % (comment,pkgurl,pkgurl,newtag)
+else:
+    cmdtag = "svn cp -m '%s' %s/branches/%s %s/tags/%s" % (comment,pkgurl,tag,pkgurl,newtag)
+
+
+if answer.lower() in 'y':
+
+    # commit to head or branch
+    print "commiting ..."
+    status,output = getstatusoutput(cmdci)
+    print output
+    if status==0:
+        # copy to tag
+        print "tagging ..."
+        print getoutput(cmdtag)
+        print "Package tagged as '%s'" % newtag
+    else:
+        print "error during commit, will not tag"
+else:
+    print "here some help:"
+    print cmdci
+    print cmdtag
+
diff --git a/Database/CoolRunQuery/share/grepfile.py b/Database/CoolRunQuery/share/grepfile.py
new file mode 100644
index 00000000000..f964e039539
--- /dev/null
+++ b/Database/CoolRunQuery/share/grepfile.py
@@ -0,0 +1,95 @@
+#!/bin/env python2.5
+#
+# ----------------------------------------------------------------
+# Script : subproc.py
+# Project: AtlRunQuery
+# Purpose: Grep lines in file and paste into shtml
+# Authors: Andreas Hoecker (CERN), Joerg Stelzer (DESY)
+# Created: Nov 13, 2009
+# ----------------------------------------------------------------
+#
+import os
+import sys
+import datetime
+import time
+
+def durationstr(sec):
+    dt = time.gmtime(sec)[2:6]
+    if dt[0]>1:
+        return "%id %ih %im %is" % ((dt[0]-1,) + dt[1:])
+    else:
+        return "%ih %im %is" % dt[1:]
+
+if __name__ == '__main__':
+
+    # note, it is assumed that the file exist and that exactly 2 argumentds are given
+    d, searchstr, age, reffile = sys.argv
+
+    # search for dataset pattern
+    os.system('grep %s %s > data/%s.tmp.txt' % (searchstr, reffile, searchstr))
+
+    # read file and insert
+    fr = open( 'data/%s.tmp.txt' % searchstr, "r" )
+    ic = 0
+    filenames = []
+    paths     = []
+    for line in fr:
+        ic += 1
+        filename, sep, info = str(line).partition(' ')
+        # remove path - caution, different for RAW files
+        if '.RAW' in filename:
+            path = filename[:filename.index(searchstr)]
+            if not path in paths: paths.append(path)        
+            if len(paths) == 1:
+                filenames.append( [path, filename[filename.index(searchstr):]] )
+            else:
+                filenames.append( [path, filename] )
+        else:
+            path = filename[:filename.index(searchstr)+len(searchstr)+1]
+            if not path in paths: paths.append(path)        
+            if len(paths) == 1:
+                filenames.append( [path, filename[filename.index(searchstr)+len(searchstr)+1:]] )
+            else:
+                filenames.append( [path, filename] )
+    fr.close()    
+
+    content = ''
+    if ic>0:
+        refpath = paths[0]
+        for path, filename in filenames:        
+            if path == refpath:
+                content += '<tr><td style="padding-top:5px;padding-bottom:5px;">%s<br>\n' % filename
+            else:
+                content += '<tr><td style="padding-top:5px;padding-bottom:5px;"><font color="#CC0000"><i>The path for the following file differs from the above default. Full path + filename is thus given:</i></font><br>\n' 
+                content += '%s<br>\n' % filename
+            content += '<font color="#999999"><font size="1px">%s</font></font><br></td></tr>\n'  % info
+
+    # page header
+    s = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html xmlns:"my"><head><head><title>ATLCAL results for dataset: %s' % searchstr
+    s +=  '</title><LINK href="atlas-runquery.css" rel="stylesheet" type="text/css"></head><body>\n\n'
+    s += '<table style="font-family:sans-serif;padding:4px;font-size:80%;width:100%">'
+
+    # body
+    s += '<tr><td style="font-size:110%%"><b>ATLCAL disk pool &minus; files belonging to dataset: <font color="#CC0000">%s</font><br><hr color="gray" size=1></td></tr>\n' % searchstr
+    try:
+        s += '<tr><td>Age of dataset: <b>%s</b></td></tr>' % durationstr(float(age))
+    except ValueError:
+        s += '<tr><td>Age of dataset: <b>%s</b></td></tr>' % 'unknown'
+        pass
+    if ic == 0: s += '<tr><td><b>No files found on ATLCAL.</b><br>&nbsp;<br>Note that the accounting of newly replicated datasets may take up to 24h (which adds to the production and replication delay). </td></tr>' 
+    else:       s += '<tr><td>Number of files found: <b>%i</b></td></tr>' % ic
+    
+    if ic>0:
+        if len(paths)==1:
+            s += '<tr><td>Common path for all files:<br> <font color="#AA0000">%s</font><br><hr color="gray" size=1></td></tr>' % refpath
+        else:
+            s += '<tr><td>Common path for the following files if not indicated otherwise:<br> <font color="#AA0000">%s</font><br><hr color="gray" size=1></td></tr>' % refpath
+
+        # add the content
+        s += content
+
+    # end of page
+    s += '<tr><td><hr color="red" size=1><font color="#777777"><font size="-1"><i><font size="-2">Created by AtlRunQuery on: %s</font></i></font></td></tr>' % str(datetime.datetime.now())
+    s += '</table></body></html>'
+
+    os.system("echo '%s' > data/%s.html" % (s, searchstr))
diff --git a/Database/CoolRunQuery/share/query.py b/Database/CoolRunQuery/share/query.py
new file mode 100644
index 00000000000..ef51a03f225
--- /dev/null
+++ b/Database/CoolRunQuery/share/query.py
@@ -0,0 +1,114 @@
+#!/bin/env python2.5
+#$Name: not supported by cvs2svn $
+
+""" Publisher example """
+import sys, re, time, datetime, os
+from random import choice
+
+def index(q=''):
+
+    if q.startswith('arq_'):
+        (page, fullpath) = _cache_request(q)
+    else:
+        (page, fullpath) = _new_request(q)
+
+    _touch(fullpath)
+
+    return page
+
+def _new_request(q=''):
+    installpath = os.path.dirname(__file__)
+
+    timeofrequest = time.gmtime()
+
+    # data stream uses current time 
+    queryday = time.strftime("%y%m%d",timeofrequest)
+    queryid = time.strftime("%y%m%d%H%M%S",timeofrequest)
+
+    # add random string to avoid conflict from coincident query
+    queryid += "".join([choice('abcdefghijklmnopqrstyz') for x in xrange(4)])
+
+    # the query datapath
+    datapath = 'data/arq_%s/arq_%s' % (queryday,queryid)
+    
+    # where to store the result
+    fulldatapath = '%s/%s' % (installpath,datapath)
+    os.makedirs(fulldatapath)
+
+    # the query that should be run
+    queryfile = '%s/query.txt' % fulldatapath
+    fh = open(queryfile,"w")
+    print >> fh, "%s" % q
+    fh.close()
+
+    # global log file
+    logfile = '%s/data/log.txt' % installpath
+    fh = open(logfile,"a")
+    print >> fh, "%s / [id %s] - received query: %s" % (timeofrequest, queryid, q if q else "none" )
+    fh.close()
+    
+    com = "cd %s; ./CoolRunQueryWrapper.sh fileindex %s" % (installpath,queryid)
+
+    # run the query
+    from commands import getoutput
+    log = getoutput(com)
+    logfile = '%s/log.txt' % fulldatapath
+    fh = open(logfile,"w")
+    print >> fh, log
+    fh.close()
+
+
+    # forward file
+    outputfile = '%s/index.html' % fulldatapath
+    try:
+        fh = open(outputfile,"r")
+        page = fh.read()
+        fh.close()
+        if not page.rstrip().endswith("</html>"):
+            page = _error_page(datapath)
+    except IOError:
+        page = "<html><body>No web page created! Here the log file:<pre><br><br><br>%s</pre></body></html>" % (log.replace("<","&lt;").replace(">","&gt;")) 
+
+    return (page,fulldatapath)
+
+
+
+def _error_page(datapath):
+    
+    s = """<html>
+    <head><title>Error</title></head>
+    <body>
+    Found incomplete web page! Would you like to see the
+    <a target="_blank" href="query.py?q=%s">web page fragment</a> or the
+    <a target="_blank" href="%s/log.txt">log file</a> ?
+    </body>
+    </html>
+    """ % (datapath.split('/')[-1], datapath)
+    return s
+
+
+
+def _cache_request(q):
+    installpath = os.path.dirname(__file__)
+    fulldatapath = '%s/data/%s/%s' % (installpath,q[:10],q)
+    try:
+        # open cache
+        fh = open('%s/index.html' % fulldatapath,"r")
+        page = fh.read()
+        fh.close()
+        return (page,fulldatapath)
+    except IOError:
+        return ("Could not find cache %s" % q, None)
+
+def _touch(fullpath):
+    if fullpath==None: return
+    installpath = os.path.dirname(__file__)
+    try:
+        # open cache
+        fh = open('%s/access.log' % fullpath,"a")
+        timeofaccess = time.gmtime()
+        querytime = time.strftime("%y%m%d",timeofaccess)
+        print >> fh, querytime
+        fh.close()
+    except IOError:
+        pass
diff --git a/Database/CoolRunQuery/share/subproc.py b/Database/CoolRunQuery/share/subproc.py
new file mode 100644
index 00000000000..927c4220b1a
--- /dev/null
+++ b/Database/CoolRunQuery/share/subproc.py
@@ -0,0 +1,37 @@
+#!/bin/env python2.5
+#
+# ----------------------------------------------------------------
+# Script : subproc.py
+# Project: AtlRunQuery
+# Purpose: Executable for python subprocesses
+# Authors: Andreas Hoecker (CERN), Joerg Stelzer (DESY)
+# Created: Nov 12, 2009
+# ----------------------------------------------------------------
+#
+
+import subprocess
+import time
+import sys
+import os.path
+
+if __name__ == '__main__':
+
+    subtype = 'caf'
+    argstr  = ''
+    if len(sys.argv)>1: subtype = sys.argv[1]
+    if len(sys.argv)>2: argstr  = sys.argv[2]
+
+    # start python subprocess to find files on CAF ---------
+    # first check age of reference file, reload if older than 1d
+    if subtype == 'caf':
+        reffile = 'data/atlas.atlcal.last'
+        if not os.path.isfile(reffile) or (time.time()-os.path.getmtime(reffile))/3600.>24.:
+            subprocess.Popen('wget -o data/wget.log http://castor.web.cern.ch/castor/DiskPoolDump/atlas.atlcal.last -O %s' % (reffile), shell=True).wait()
+                                    
+        dsnamesAndAge = argstr.split(',')
+        agrs = []
+        for dsnameAndAge in dsnamesAndAge:
+            # format is: '<dsname>@<age_in_sec>'
+            dsname, sep, age = dsnameAndAge.partition('@')
+            subprocess.Popen('python2.5 grepfile.py %s %s %s' % (dsname, age, reffile), shell=True)
+
-- 
GitLab