<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://daq00.triumf.ca/MidasWiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Zaher</id>
	<title>MidasWiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://daq00.triumf.ca/MidasWiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Zaher"/>
	<link rel="alternate" type="text/html" href="https://daq00.triumf.ca/MidasWiki/index.php/Special:Contributions/Zaher"/>
	<updated>2026-04-13T21:43:23Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.6</generator>
	<entry>
		<id>https://daq00.triumf.ca/MidasWiki/index.php?title=Custom_Page&amp;diff=3534</id>
		<title>Custom Page</title>
		<link rel="alternate" type="text/html" href="https://daq00.triumf.ca/MidasWiki/index.php?title=Custom_Page&amp;diff=3534"/>
		<updated>2025-05-21T14:27:26Z</updated>

		<summary type="html">&lt;p&gt;Zaher: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Pagelinks}}&lt;br /&gt;
&lt;br /&gt;
= Links =&lt;br /&gt;
{{mhttpdpages3|[[Custom Page Features]]|[[/Custom ODB tree]]|[[Mhttpd.js|MIDAS Javascript library]]}}&lt;br /&gt;
&lt;br /&gt;
= Purpose =&lt;br /&gt;
A user-created [[mhttpd]] Custom Web Page accessible from the side menu allows the user additional flexibility. For example, a custom page may present the essential parameters of the controlled experiment in a more compact way. A custom page may even replace the default [[Status Page]].&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
Custom web pages provide the user with a means of creating secondary user-created web page(s) activated within the standard MIDAS web interface. These custom pages usually display ODB parameters or data to the user. They can contain specific links to the ODB so the user may also input information relevant to the experiment. Users create Custom Pages when the standard pages do not meet their requirements completely.&lt;br /&gt;
&lt;br /&gt;
We note that MIDAS has provided a number of different ways of providing custom pages over the years.  A new scheme of custom pages making use of modern HTML5 techniques has been introduced in 2017. This page will mostly only be providing documentation for the new scheme of custom pages.&lt;br /&gt;
&lt;br /&gt;
= Examples of Custom Pages =&lt;br /&gt;
&lt;br /&gt;
Click on the thumbnails to enlarge.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| [[File:Capture_sgas.png|thumb|left|Figure 1: MEG Gas System]] || &#039;&#039;&#039;Example 1&#039;&#039;&#039;&lt;br /&gt;
This page (Figure 1) from the MEG experiment at PSI shows a complex gas system. This shows the use of &amp;quot;fills&amp;quot; and &amp;quot;labels&amp;quot;. Open valves are represented as green circles, closed valves as red circles. If, for example, an open valve is clicked, the valve closes, and the circle turns red (provided the user successfully supplied the correct password).&lt;br /&gt;
|-&lt;br /&gt;
| [[File:custom_ROOT_analyzer_page.png|thumb|left|Figure 2: ROOT Analyzer (MEG Experiment)]] || &#039;&#039;&#039;Example 2&#039;&#039;&#039;&lt;br /&gt;
Many MIDAS experiments work with ROOT based analyzers today. One problem is that the graphical output of the root analyzer can only be seen through the X server and not through the web. At the MEG experiment, this problem was solved in an elegant way: The ROOT analyzer runs in the background, using a &amp;quot;virtual&amp;quot; X server called Xvfb. It plots its output (several panels) normally using this X server, then saves this panels every ten seconds into GIF files. These GIF files are then served through mhttpd using a custom page. The output is shown in Figure 2.&lt;br /&gt;
&lt;br /&gt;
The buttons on the left sides are actually HTML buttons on that custom page overlaid to the GIF image, which in this case shows one of the 800 PMT channels digitized at 1.6 GSPS. With these buttons one can cycle through the different GIF images, which then automatically update ever ten seconds. Of course it is not possible to feed interaction back to the analyzer (i.e. the waveform cannot be fitted interactively) but for monitoring an experiment in production mode this tool is extremely helpful, since it is seamlessly integrated into mhttpd. All the magic is done with JavaScript, and the buttons are overlaid on the graphics using CSS with absolute positioning. The analysis ratio on the top right is also done with JavaScript accessing the required information from the ODB. &lt;br /&gt;
&lt;br /&gt;
For details using Xvfb server, please contact Ryu Sawada &amp;lt;sawada@icepp.s.u-tokyo.ac.jp&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| [[File:deap_custom_scb.png|thumb|left|Figure 3: SCB Setup (Deap Experiment)]] || &#039;&#039;&#039;Example 3&#039;&#039;&#039;&lt;br /&gt;
This custom page from the Deap Experiment (Figure 3) allows the users to easily set individual channels, or a group of channels, or all channels of the SCB modules to a particular value.   &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Access a Custom Page from the Regular MIDAS pages =&lt;br /&gt;
Access to a Custom Page is set up through the [[/Custom ODB tree]] (see [[/Custom ODB tree#Keys in the /Custom tree|custom-link]]). This associates a custom page file on the disk with a menu item on the left navigation bar. Clicking on the resulting link will display that custom page.&lt;br /&gt;
&lt;br /&gt;
Often a custom page requires resources such as *.css (stylesheets) or *.js (javascript) files. It is convenient to store all such files with the custom page file (*.html) in&lt;br /&gt;
a particular directory, e.g. /home/expt/online/custom. By creating an ODB key /Custom/Path, all the custom page files and resources can be served easily from this directory.&lt;br /&gt;
See [[Custom Page Features#Resource files]] for more information.&lt;br /&gt;
&lt;br /&gt;
If the key  {{Odbpath|path=/Custom/myPage&amp;amp;}}  (see Note) is created, e.g.&lt;br /&gt;
 odbedit&amp;gt; ls /Custom&lt;br /&gt;
    Path                              /home/expt/online/custom&lt;br /&gt;
    myPage&amp;amp;                           mypage.html&lt;br /&gt;
&lt;br /&gt;
the custom link on the left navigation bar will be &amp;lt;code&amp;gt;myPage&amp;lt;/code&amp;gt; and the URL for the resulting custom page will be of the form &amp;lt;code&amp;gt;http://myhost.mydomain:myport/cmd=?Custom&amp;amp;page=myPage&amp;lt;/code&amp;gt; (see also [[mhttpd#usage]]).  &lt;br /&gt;
Clicking on &amp;lt;code&amp;gt;myPage&amp;lt;/code&amp;gt; will display the custom page in the same window.&lt;br /&gt;
&lt;br /&gt;
;Note&lt;br /&gt;
: With the &amp;quot;&amp;amp;&amp;quot; symbol in the key name, the page would appear in a new tab/window. See [[/Custom ODB tree#Key names|Key names]] for more information.&lt;br /&gt;
&lt;br /&gt;
If an experiment used many custom pages, the menu on the left side can get pretty long. To avoid that, custom pages can be structured in submenus. Simply put a custom page in an ODB subdirectory, and it will appear in a separate submenu, e.g.&lt;br /&gt;
&lt;br /&gt;
 odbedit&amp;gt; ls -r /Custom&lt;br /&gt;
    Path                              /home/expt/online/custom&lt;br /&gt;
    myPage&amp;amp;                           mypage.html&lt;br /&gt;
    Calorimeter&lt;br /&gt;
        HV                            hv.html&lt;br /&gt;
        Rates                         rates.html&lt;br /&gt;
    Baeam&lt;br /&gt;
        Beamline                      beamline.html&lt;br /&gt;
        Accelerator                   accel.html&lt;br /&gt;
&lt;br /&gt;
The pages then include the subdirectory in the URL, like &lt;br /&gt;
&lt;br /&gt;
 http://localhost:8080?cmd=custom&amp;amp;page=beam/Beamline&lt;br /&gt;
&lt;br /&gt;
Subdirectories can contain nested subdirectories. Please make sure that you specify the full path in your mhttpd_init() call, such as&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body class=&amp;quot;mcss&amp;quot; onload=&amp;quot;mhttpd_init(&#039;Calorimeter/HV&#039;);&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in order to keep the submenu open after you select the custom page.&lt;br /&gt;
&lt;br /&gt;
To enable clicks on a menu item that result in an onclick event (no html refresh), one can create and ODB key in the /Custom (or its subdirectories) whose value is a string that does not end with a valid extension (txt|jpg|jpeg|png|gif|pdf|csv|html|js|css). In this case, the string will be encapsulated into and onclick event. For example,&lt;br /&gt;
odbedit&amp;gt; ls -r /Custom&lt;br /&gt;
    Path                              /home/expt/online/custom&lt;br /&gt;
    Click                             alert(1)&lt;br /&gt;
&lt;br /&gt;
Clicking on the menu item &amp;quot;Click&amp;quot; will result in an alert window.&lt;br /&gt;
&lt;br /&gt;
= How to write a custom page =&lt;br /&gt;
A custom page is usually written in a combination of HTML and Javascript. It can contain any of the features described below. A [[Mjsonrpc | Javascript MjsonRPC Library]] has been written to provide access to the ODB and other functions.&lt;br /&gt;
&lt;br /&gt;
In what follows, we describe a scheme for writing custom pages with the set of modb* javascript functions.  The advantages of using these modb* javascript functions are&lt;br /&gt;
&lt;br /&gt;
* modb* functions hide details about the underlying MjsonRPC calls, which should allow a user to write pretty and sophisticated custom pages quickly and cleanly.&lt;br /&gt;
* modb* functions ensure that all the periodic updates of the ODB value (and other MIDAS information) are done in a single MjsonRPC batch call, which should ensure optimal page loading speed.&lt;br /&gt;
* modb* functions encapsulate the underlying communication. Should the communication change in the future, the custom pages do not have to be changed.&lt;br /&gt;
&lt;br /&gt;
It is also possible for users to write their custom pages using only the underlying [[Mjsonrpc | MjsonRPC library]] calls, but they then need to ensure on their own that the page loading remains efficient.  In particular, if you combine the standard MIDAS navigation bars (described in next section) with your own periodic MjsonRPC calls then you will probably need at least two separate periodic RPC calls to populate the custom page (instead of one call).  It will also require more coding to implement the custom page with only MjsonRPC calls.&lt;br /&gt;
&lt;br /&gt;
== How to use the standard MIDAS navigation bars on your custom page == &lt;br /&gt;
&lt;br /&gt;
If you want to have your custom page use the same header and navigation bars as the standard MIDAS pages, you need to use the following syntax &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
   &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;midas.css&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;script src=&amp;quot;controls.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
   &amp;lt;script src=&amp;quot;midas.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
   &amp;lt;script src=&amp;quot;mhttpd.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
   &amp;lt;title&amp;gt;myPage&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;body class=&amp;quot;mcss&amp;quot; onload=&amp;quot;mhttpd_init(&#039;myPage&#039;);&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- header and side navigation will be filled in mhttpd_start --&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;mheader&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;msidenav&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;mmain&amp;quot;&amp;gt;&lt;br /&gt;
 ADD YOUR HTML/JS  CODE here...&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The call &amp;lt;code&amp;gt;mhttpd_init(&#039;myPage&#039;)&amp;lt;/code&amp;gt; is executed when the page is loaded, and  &amp;lt;code&amp;gt;myPage&amp;lt;/code&amp;gt; is the name of the page shown on the left menu bar. This corresponds to an ODB entry /Custom/myPage.&lt;br /&gt;
This pattern will allow you to use the standard MIDAS navigation whether you are using the modb* functions or the underlying [[Mjsonrpc | javascript libraries]].&lt;br /&gt;
&lt;br /&gt;
= modb* Javascript scheme = &lt;br /&gt;
&lt;br /&gt;
The general scheme of the custom page scheme is to write &amp;lt;code&amp;gt;&amp;amp;lt;div class=&amp;quot;modb...&amp;quot;&amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;&amp;amp;lt;span class=&amp;quot;modb...&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;&amp;lt;/code&amp;gt; tags with special class names, most of them starting with &amp;quot;modb...&amp;quot; (&amp;quot;MIDAS-ODB&amp;quot;). Use a &amp;lt;code&amp;gt;&amp;amp;lt;div&amp;amp;gt;&amp;lt;/code&amp;gt; tag if you want the element to appear in a separate line, and use the &amp;lt;code&amp;gt;&amp;amp;lt;span&amp;amp;gt;&amp;lt;/code&amp;gt; tag if you want to display the element in-line. The following description uses only &amp;lt;code&amp;gt;&amp;amp;lt;div&amp;amp;gt;&amp;lt;/code&amp;gt; tags, but all of them can be changed to &amp;lt;code&amp;gt;&amp;amp;lt;span&amp;amp;gt;&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
All HTML tags with &amp;quot;modb...&amp;quot; names are scanned by the &amp;lt;code&amp;gt;mhttp_init(&#039;name&#039;)&amp;lt;/code&amp;gt; function upon page load, and their inner contents are replaced by the requested ODB value or some graphics. The contents are then updated regularly. Updates are once per second by default. This can be changed by passing a second argument to &amp;lt;code&amp;gt;mhttpd_init(&#039;name&#039;, interval)&amp;lt;/code&amp;gt; where &amp;quot;interval&amp;quot; is in milliseconds. You can add or remove &amp;quot;modb...&amp;quot; elements at any time using javascript, and the new elements will be &amp;quot;discovered&amp;quot; automatically during the next update.&lt;br /&gt;
&lt;br /&gt;
== modbset(path, value) ==&lt;br /&gt;
&lt;br /&gt;
To set values in the ODB, the midas JavaScript function mjsonrpc_db_paste() is usually called. This function is implemented as a JavaScript promise, which lets you chain several request in order to change values inside the ODB in a certain order. If that functionality is not required, the simplified modbset() function can be called, which also implements standard error handling. Two versions of this function exist, one which accepts a single ODB path and a single value, and one which accepts an array of ODB paths and values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
modbset(&amp;quot;odb path&amp;quot;, value)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
modbset([&amp;quot;odb path1&amp;quot;, &amp;quot;odb path2&amp;quot;, ...], [value1, value2, ...])&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These functions are typically used by custom JavaScript code, like when some value in an experiment exceeds some limit and some action has to be taken like to close a valve. If the call fails (like if mhttpd is dead), a window with an error description is shown.&lt;br /&gt;
&lt;br /&gt;
== modb ==&lt;br /&gt;
&lt;br /&gt;
This special HTML div tag (abbreviation stands for Midas ODB) &amp;lt;code&amp;gt;&amp;amp;lt;div class=&amp;quot;modb&amp;quot; data-odb-path=&amp;quot;/Some/Path&amp;quot; onchange=&amp;quot;func()&amp;quot;&amp;amp;gt;&amp;lt;/code&amp;gt; can be used to call a user-defined function func() if a value in the ODB changes. This function must be defined inline or in a separate &amp;amp;lt;script&amp;amp;gt;...&amp;amp;lt;/script&amp;amp;gt; section, and can execute any operation, such as opening a dialog box, hiding/unhiding parts of the custom page, or changing colors and styles of page elements.&lt;br /&gt;
&lt;br /&gt;
The current value of the ODB entry is available inside the &amp;quot;onchange&amp;quot; function as &#039;&#039;&#039;this.value&#039;&#039;&#039;. Following tag will call a function which logs the current run number in the JavaScript console window:&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;div class=&amp;quot;modb&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; onchange=&amp;quot;func(this.value)&amp;quot;&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;amp;lt;script&amp;amp;gt;function func(value) {&lt;br /&gt;
console.log(value);&lt;br /&gt;
}&amp;amp;lt;/script&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
If the ODB path does not point to an individual value but to a subdirectory, the whole subdirectory is mapped to &#039;&#039;&#039;this.value&#039;&#039;&#039; as a JavaSctipt object such as&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;div class=&amp;quot;modb&amp;quot; data-odb-path=&amp;quot;/Runinfo&amp;quot; onchange=&amp;quot;func(this.value)&amp;quot;&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;amp;lt;script&amp;amp;gt;function func(value) {&lt;br /&gt;
console.log(value[&amp;quot;run number&amp;quot;]);&lt;br /&gt;
}&amp;amp;lt;/script&amp;amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Note that ODB entries are mapped to JavaScript objects without change. So if an ODB entry name contains a blank, it must be accessed via the JS square bracket &#039;&#039;&#039;value[&amp;quot;run number&amp;quot;]&#039;&#039;&#039; as shown in the above example. Otherwise, the entry can be accessed via the dot notation, such as &#039;&#039;&#039;value.state&#039;&#039;&#039; for /Runinfo/State for example.&lt;br /&gt;
&lt;br /&gt;
== modbvalue ==&lt;br /&gt;
&lt;br /&gt;
This special HTML div tag (abbreviation stands for &amp;quot;Midas ODB VALUE&amp;quot;) &lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;div class=&amp;quot;modbvalue&amp;quot; data-odb-path=&amp;quot;/Some/Path&amp;quot;&amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&amp;lt;/code&amp;gt; &lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
is now automatically replaced by the value in the ODB found at the given path and updated regularly as described above Following options are valid for this tag:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Table 1: List of valid options for modbvalue tag&lt;br /&gt;
|-&lt;br /&gt;
! Option !! Example !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| data-name || class=&amp;quot;modbvalue&amp;quot; || Tells the framework to replace this tag with an ODB value&lt;br /&gt;
|-&lt;br /&gt;
| data-odb-path || data-odb-path = &amp;quot;/Runinfo/Run number&amp;quot; || Path to the value in the ODB. If omitted, the value must be set via [[Custom_Page#Changing_values_of_indicators_programmatically | set_value]].&lt;br /&gt;
|-&lt;br /&gt;
| data-odb-editable || data-odb-editable=&amp;quot;1&amp;quot; || If set, the value is not only shown, but is also clickable for in-line editing. Hitting return send the new value to the ODB.&lt;br /&gt;
|-&lt;br /&gt;
| data-format || data-format=&amp;quot;f3&amp;quot; || Specify format of data shown. See Table 2 below for options.&lt;br /&gt;
|-&lt;br /&gt;
| data-size || data-size=&amp;quot;8&amp;quot; || Specify size (in chars) of edit box if one modifies the value. Default is 10.&lt;br /&gt;
|-&lt;br /&gt;
| data-formula || data-formula=&amp;quot;2*x+3&amp;quot; || Specify an optional formula to process with the current ODB value stored in x&lt;br /&gt;
|-&lt;br /&gt;
| data-validate || data-validate=&amp;quot;func&amp;quot; || Specify an optional validation function which gets called before submitting data (see below)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Validation ===&lt;br /&gt;
&lt;br /&gt;
Before a modified value is submitted to the ODB, an optional validation function can be called via the &amp;lt;code&amp;gt;data-validate&amp;lt;/code&amp;gt; option. The function&lt;br /&gt;
will be called with the current value and a reference to the current modbvalue element. If the function returns &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;, then the value&lt;br /&gt;
is not sent to the ODB.&lt;br /&gt;
&lt;br /&gt;
Following example shows a function which just rejects the submission of values above 1000:&lt;br /&gt;
&lt;br /&gt;
  &amp;amp;lt;div class=&amp;quot;modbvalue&amp;quot; ... data-odb-editable=&amp;quot;1&amp;quot; data-validate=&amp;quot;my_validate&amp;quot;&amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;amp;lt;script src=&amp;quot;controls.js&amp;quot;&amp;amp;gt;&amp;amp;lt;/script&amp;amp;gt; &amp;amp;lt;!-- needed of dlgAlert() --&amp;amp;gt;&lt;br /&gt;
  &amp;amp;lt;script&amp;amp;gt;&lt;br /&gt;
  function my_validate(value, element) {&lt;br /&gt;
     if (value &amp;gt; 1000) {&lt;br /&gt;
        dlgAlert(&amp;quot;Value cannot be above 1000&amp;quot;);&lt;br /&gt;
        return false;&lt;br /&gt;
     }&lt;br /&gt;
     return true;&lt;br /&gt;
  }&lt;br /&gt;
  &amp;amp;lt;/script&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
Following function corrects the return value to 1000 if it&#039;s above 1000:&lt;br /&gt;
&lt;br /&gt;
  &amp;amp;lt;script&amp;amp;gt;&lt;br /&gt;
  function my_validate2(value, element) {&lt;br /&gt;
     if (value &amp;gt; 1000) {&lt;br /&gt;
        element.childNodes[0].value = 1000;&lt;br /&gt;
     return true;&lt;br /&gt;
  }&lt;br /&gt;
  &amp;amp;lt;/script&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Confirmation ===&lt;br /&gt;
&lt;br /&gt;
Before a modified value is submitted to the ODB, a confirmation dialog box can be displayed to let the user confirm the change before it is actually written to the ODB. &lt;br /&gt;
This is done with the option &amp;lt;code&amp;gt;data-confirm=&amp;amp;lt;string&amp;amp;gt;&amp;lt;/code&amp;gt;. A dialog box is then shown with the &amp;lt;code&amp;gt;&amp;amp;lt;string&amp;amp;gt;&amp;lt;/code&amp;gt; as the main text and two buttons with &amp;quot;OK&amp;quot; and &amp;quot;Cancel&amp;quot;.&lt;br /&gt;
Hitting &amp;quot;OK&amp;quot; finally writes the value to the ODB, hitting &amp;quot;Cancel&amp;quot; keeps the old value.&lt;br /&gt;
&lt;br /&gt;
Following example shows an example:&lt;br /&gt;
&lt;br /&gt;
  &amp;amp;lt;div class=&amp;quot;modbvalue&amp;quot; ... data-odb-editable=&amp;quot;1&amp;quot; data-confirm=&amp;quot;Are you sure to change the value?&amp;quot;&amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
Following dialog box is then showed:&lt;br /&gt;
&lt;br /&gt;
[[File:Confirm.png|frame|left|Optional confirm dialog]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br clear=all&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Formatting ===&lt;br /&gt;
&lt;br /&gt;
Table 2 below lists the format specifiers supported with a modbvalue tag &amp;lt;code&amp;gt;data-format=&amp;quot;...&amp;quot;&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Table 2: Format specifiers for modbvalue tag &amp;lt;code&amp;gt;data-format=&amp;quot;...&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
! Option !! Valid for* !! Example !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| %d || int || 1234 || Shows a number in decimal encoding&lt;br /&gt;
|-&lt;br /&gt;
| %t || int, float || 1,234,567 || Shows a number in decimal encoding with commas as thousands separator&lt;br /&gt;
|-&lt;br /&gt;
| %x || int || 0x4D2 || Shows a number in hexadecimal encoding&lt;br /&gt;
|-&lt;br /&gt;
| %b || int || 10011010010b|| Shows a number in binary encoding. Options t, d, x, b can be combined, like &amp;lt;code&amp;gt;data-format=&amp;quot;%d / %x&amp;quot;&amp;lt;/code&amp;gt; to produce &amp;lt;code&amp;gt;1234 / 0x4D2&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| %f&amp;amp;lt;x&amp;amp;gt; || float || 1.234 || Shows a floating point number with &amp;amp;lt;x&amp;amp;gt; digits after the decimal. A value of f0 shows only the integer part.&lt;br /&gt;
|-&lt;br /&gt;
| %p&amp;amp;lt;x&amp;amp;gt; || float || 1.23 || Shows a floating point number with &amp;amp;lt;x&amp;amp;gt; significant digits of precision, independent of the decimal. For example a value of p2 can render a number to 12000 or 0.0012&lt;br /&gt;
|-&lt;br /&gt;
| %e&amp;amp;lt;x&amp;amp;gt; || float || 1.23e-05 || Shows a floating point number with &amp;amp;lt;x&amp;amp;gt; digits after the decimal in exponential format. Useful for small number such as pressures.&lt;br /&gt;
|-&lt;br /&gt;
| T= %f1 C || float || T= 25.4 C || Combination of text and float value is possible.&lt;br /&gt;
|-&lt;br /&gt;
| %d / %x / %b || int || 17 / 0x11 / 10001b|| Same integer value in different formats&lt;br /&gt;
|-&lt;br /&gt;
| [col1,col2] || bool || [red,var(--mgreen)] || Generates a color box filled with col1 (false, &amp;lt;span style=&amp;quot;display: inline-block; width: 1em; height: 1em; border: 1px solid black; background-color: red&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;) or col2 (true, &amp;lt;span style=&amp;quot;display: inline-block; width: 1em; height: 1em; border: 1px solid black; background-color: #a0ffb8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* Note that valid for &amp;quot;int&amp;quot; means all integral ODB types (regardless of size or signed/unsigned) and valid for &amp;quot;float&amp;quot; means both float and double.&lt;br /&gt;
&lt;br /&gt;
== modbbutton ==&lt;br /&gt;
&lt;br /&gt;
This tag generates a push-button which can set a certain ODB entry to a specific value. To set the &amp;quot;Run number&amp;quot; to 100, one can use the following tag:&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;button class=&amp;quot;modbbutton mbutton&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-odb-value=&amp;quot;100&amp;quot; data-validate=&amp;quot;my_validate&amp;quot;&amp;amp;gt;[Button Text]&amp;amp;lt;/button&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The optional &amp;lt;code&amp;gt;data-validate&amp;lt;/code&amp;gt; function can be used to prevent pressing the button under certain circumstances. If the validate function returns false, the value is not written to the ODB, similarly than for modbvalue tag.&lt;br /&gt;
&lt;br /&gt;
== modbbox ==&lt;br /&gt;
&lt;br /&gt;
This tag generates a rectangular box which changes color according to a value in the ODB. If the value is nonzero or true (for booleans), the &#039;&#039;&#039;data-color&#039;&#039;&#039; is used, otherwise the &#039;&#039;&#039;data-background-color&#039;&#039;&#039; is used&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;div class=&amp;quot;modbbox&amp;quot; data-odb-path=&amp;quot;/Logger/Write Data&amp;quot; data-formula=&amp;quot;x &amp;gt; 0&amp;quot; style=&amp;quot;width: 30px; height: 30px; border: 1px solid black&amp;quot; data-color=&amp;quot;lightgreen&amp;quot; data-background-color=&amp;quot;red&amp;quot;&amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Optionally, a &amp;lt;code&amp;gt;data-formula&amp;lt;/code&amp;gt; can be specified. The formula sees the ODB value in the variable &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt;, and can do any boolean operation. If the result of this is true, then the box gets the &amp;lt;code&amp;gt;data-color&amp;lt;/code&amp;gt;, otherwise the &amp;lt;code&amp;gt;data-background-color&amp;lt;/code&amp;gt;.&lt;br /&gt;
Examples for these formulas are &amp;lt;code&amp;gt;x &amp;gt; 10&amp;lt;/code&amp;gt; for a comparison or &amp;lt;code&amp;gt;x &amp;amp; 1&amp;lt;/code&amp;gt; which will do a bitwise AND operation and is true only for odd numbers.&lt;br /&gt;
&lt;br /&gt;
== modbcheckbox ==&lt;br /&gt;
&lt;br /&gt;
This tag generates a check box which can set a certain ODB entry to true or false. To set the &amp;quot;Write data&amp;quot; flag for the logger true or false, one can use the following tag:&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;input type=&amp;quot;checkbox&amp;quot; class=&amp;quot;modbcheckbox&amp;quot; data-odb-path=&amp;quot;/Logger/Write data&amp;quot; data-validate=&amp;quot;my_validate&amp;quot; /&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
If the ODB value changed by this control is of type integer, its value will be set to 1 or 0. The optional &amp;lt;code&amp;gt;data-validate&amp;lt;/code&amp;gt; function can be used to prevent changing a value under certain circumstances. If the validate function returns false, the value is not written to the ODB, similarly than for &amp;lt;code&amp;gt;modbvalue&amp;lt;/code&amp;gt; tag.&lt;br /&gt;
&lt;br /&gt;
== modbselect ==&lt;br /&gt;
&lt;br /&gt;
This tag generates a drop down box with certain valued which can be sent to a value in the ODB. Following example shows a drop-down box with three different values. When selected, they are sent to the ODB under &amp;lt;code&amp;gt;/Runinfo/Run number&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
  &amp;amp;lt;select class=&amp;quot;modbselect&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot;&amp;amp;gt;&lt;br /&gt;
    &amp;amp;lt;option value=&amp;quot;1&amp;quot;&amp;amp;gt;1&amp;amp;lt;/option&amp;amp;gt;&lt;br /&gt;
    &amp;amp;lt;option value=&amp;quot;5&amp;quot;&amp;amp;gt;5&amp;amp;lt;/option&amp;amp;gt;&lt;br /&gt;
    &amp;amp;lt;option value=&amp;quot;10&amp;quot;&amp;amp;gt;10&amp;amp;lt;/option&amp;amp;gt;&lt;br /&gt;
  &amp;amp;lt;/select&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
Instead of specifying the valid options in the javascript code, you can also specify them in the ODB, and populate the drop-down with those values. Specify &amp;lt;code&amp;gt;data-auto-options=&amp;quot;1&amp;quot;&amp;lt;/code&amp;gt; to enable this behaviour. For ODB key &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt;, you will need to create an ODB entry called &amp;lt;code&amp;gt;Options x&amp;lt;/code&amp;gt; in the same directory; this &amp;quot;options&amp;quot; key should be a list, with each element in the list being an allowable option.&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;!-- Will read options from &amp;quot;/Equipment/Example/Settings/Options Something&amp;quot; in this case --&amp;gt;&lt;br /&gt;
  &amp;amp;lt;select class=&amp;quot;modbselect&amp;quot; data-odb-path=&amp;quot;/Equipment/Example/Settings/Something&amp;quot; data-auto-options=&amp;quot;1&amp;quot;&amp;amp;gt;&lt;br /&gt;
  &amp;amp;lt;/select&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The benefit of the &amp;lt;code&amp;gt;data-auto-options=&amp;quot;1&amp;quot;&amp;lt;/code&amp;gt; approach is that the same options will be shown on the regular ODB browser webpage. &lt;br /&gt;
&lt;br /&gt;
Note that these options are only a convenience for the user interface - there is no strict enforcement in the ODB itself! Power-users are able to set other values via C++/Python/Javascript/odbedit etc.&lt;br /&gt;
&lt;br /&gt;
== modbhbar ==&lt;br /&gt;
&lt;br /&gt;
The following tag:&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;div class=&amp;quot;modbhbar&amp;quot; style=&amp;quot;width: 500px; height: 18px; color: lightgreen;&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-max-value=&amp;quot;10&amp;quot; &amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
shows a horizontal bar with a total length of 500px. Depending on the ODB value {{Odbpath|path=Run number}}. If {{Odbpath|path=Run number}} is 10, then the bar is filled all the way to the right, if {{Odbpath|path=Run number}} is 5, the bar is only filled halfway. Following options are possible:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Setting !! Meaning !! Required&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;width: 500px&amp;quot; || Total width of the horizontal bar || Yes&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;height: 18px&amp;quot; || Height of the horizontal bar || Yes&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;color: red&amp;quot; || Color of horizontal bar || Transparent if not present&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;background-color: red&amp;quot; || Background color of horizontal bar || Transparent if not present&lt;br /&gt;
|-&lt;br /&gt;
| data-odb-path || ODB path of value being displayed. If omitted, the value must be set via [[Custom_Page#Changing_values_of_indicators_programmatically | set_value]]. || No&lt;br /&gt;
|-&lt;br /&gt;
| data-min-value || Left limit of bar range || 0 if not present&lt;br /&gt;
|-&lt;br /&gt;
| data-max-value || Right limit of bar range || 1 if not present&lt;br /&gt;
|-&lt;br /&gt;
| data-log || Logarithmic display || No&lt;br /&gt;
|-&lt;br /&gt;
| data-print-value || If &amp;quot;1&amp;quot;, data value is shown as text overlay || No&lt;br /&gt;
|-&lt;br /&gt;
| data-format || Specify format of data shown. See Table 2 above for options || No&lt;br /&gt;
|-&lt;br /&gt;
| data-formula || Specify an optional formula to process with the current ODB value stored in x || No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== mhaxis ==&lt;br /&gt;
&lt;br /&gt;
A horizontal bar can be combined with an axis with tick marks and labels. The axis can be above or below the bar.&lt;br /&gt;
&lt;br /&gt;
The following tag:&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;div class=&amp;quot;mhaxis&amp;quot; style=&amp;quot;width: 500px; height: 22px;&amp;quot; data-min-value=&amp;quot;0&amp;quot; data-max-value=&amp;quot;10&amp;quot; &amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
shows a horizontal axis next to the bar. Following options are possible:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Setting !! Meaning !! Required&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;width: 500px&amp;quot; || Total width of the axis, must match the width of the horizontal bar || Yes&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;height: 18px&amp;quot; || Height of the axis, must be enough to display labels  || Yes&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align: top&amp;quot; || Must be &amp;quot;top&amp;quot; if the axis is below the bar || &amp;quot;bottom&amp;quot; if not given&lt;br /&gt;
|-&lt;br /&gt;
| data-min-value || Left limit of axis range || Yes&lt;br /&gt;
|-&lt;br /&gt;
| data-max-value || Right limit of axis range || Yes&lt;br /&gt;
|-&lt;br /&gt;
| data-log || Logarithmic display || No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== modbvbar ==&lt;br /&gt;
&lt;br /&gt;
Same as &amp;lt;code&amp;gt;modbhbar&amp;lt;/code&amp;gt;, except the bar grows vertically instead of horizontally.&lt;br /&gt;
&lt;br /&gt;
== mvaxis ==&lt;br /&gt;
&lt;br /&gt;
Same as &amp;lt;code&amp;gt;mhaxis&amp;lt;/code&amp;gt;, except the axis is shown vertically instead of horizontally.&lt;br /&gt;
&lt;br /&gt;
== modbthermo ==&lt;br /&gt;
&lt;br /&gt;
The following tag:&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;div class=&amp;quot;modbthermo&amp;quot; style=&amp;quot;width: 30px; height: 100px;&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-min-value=&amp;quot;-10&amp;quot; data-max-value=&amp;quot;30&amp;quot; data-color=&amp;quot;blue&amp;quot; data-print-value=&amp;quot;1&amp;quot; &amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
shows a vertical thermometer ranging from -10 to 30. Depending on the ODB value {{Odbpath|path=Run number}}. The run number was chosen instead of a real temperature since this ODB variable exists in all midas installations by default, so it&#039;s good for testing. Following options are possible:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Setting !! Meaning !! Required&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;width: 30px&amp;quot; || Width of the thermometer || Yes&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;height: 100px&amp;quot; || Total height of the thermometer || Yes&lt;br /&gt;
|-&lt;br /&gt;
| data-odb-path || ODB path of value being displayed. If omitted, the value must be set via [[Custom_Page#Changing_values_of_indicators_programmatically | set_value]]. || No&lt;br /&gt;
|-&lt;br /&gt;
| data-max-value || Upper range || Yes&lt;br /&gt;
|-&lt;br /&gt;
| data-min-value || Lower range || 0 if not present&lt;br /&gt;
|-&lt;br /&gt;
| data-color || Color of thermometer || Black if not present&lt;br /&gt;
|-&lt;br /&gt;
| data-background-color || Color of thermometer background || Transparent if not present&lt;br /&gt;
|-&lt;br /&gt;
| data-print-value || If &amp;quot;1&amp;quot;, data value is shown below the thermometer || No&lt;br /&gt;
|-&lt;br /&gt;
| data-scale || If &amp;quot;1&amp;quot;, the min and max values of the range are shown next to the thermometer || No&lt;br /&gt;
|-&lt;br /&gt;
| data-format || Specifies format of temperature shown below gauge. See Table 2 for options. || No&lt;br /&gt;
|-&lt;br /&gt;
| data-formula || Specify an optional formula to process with the current ODB value stored in x || No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== modbgauge ==&lt;br /&gt;
&lt;br /&gt;
The following tag:&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;div class=&amp;quot;modbgauge&amp;quot; style=&amp;quot;width: 100px; height: 50px;&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-min-value=&amp;quot;0&amp;quot; data-max-value=&amp;quot;10&amp;quot; data-color=&amp;quot;darkgreen&amp;quot;&amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
shows a circular gauge ranging from 0 to 10. Depending on the ODB value &amp;quot;Run number&amp;quot;. Following options are possible:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Setting !! Meaning !! Required&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;width: 100px&amp;quot; || Width of the gauge || Yes&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;height: 50px&amp;quot; || Total height of the gauge || Yes&lt;br /&gt;
|-&lt;br /&gt;
| data-odb-path || ODB path of value being displayed. If omitted, the value must be set via [[Custom_Page#Changing_values_of_indicators_programmatically | set_value]]. || No&lt;br /&gt;
|-&lt;br /&gt;
| data-max-value || Upper range || Yes&lt;br /&gt;
|-&lt;br /&gt;
| data-min-value || Lower range || 0 if not present&lt;br /&gt;
|-&lt;br /&gt;
| data-color || Color of gauge || Black if not present&lt;br /&gt;
|-&lt;br /&gt;
| data-background-color || Color of gauge background || Transparent if not present&lt;br /&gt;
|-&lt;br /&gt;
| data-print-value || If &amp;quot;1&amp;quot;, data value is shown below the gauge || No&lt;br /&gt;
|-&lt;br /&gt;
| data-format || Specifies format of temperature shown below gauge. See Table 2 for options. || No&lt;br /&gt;
|-&lt;br /&gt;
| data-scale || If &amp;quot;1&amp;quot;, the min and max values of the range are shown below the gauge || No&lt;br /&gt;
|-&lt;br /&gt;
| data-formula || Specify an optional formula to process with the current ODB value stored in x || No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If the gauge scale is not shown, the gauge height should be half the gauge width. If the scale is shown, 15px must be added to the height.&lt;br /&gt;
&lt;br /&gt;
== Changing properties of controls dynamically ==&lt;br /&gt;
&lt;br /&gt;
All custom controls can be configured to call a user&#039;s function when the control is first set up, or when the value changes. This is done by specifying the &#039;&#039;&#039;onload&#039;&#039;&#039; and/or &#039;&#039;&#039;onchange&#039;&#039;&#039; functions.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;onload&#039;&#039;&#039; is called only once, when the control&#039;s value is first read from the ODB.&lt;br /&gt;
* &#039;&#039;&#039;onchange&#039;&#039;&#039; is called each time the value in the ODB changes.&lt;br /&gt;
&lt;br /&gt;
The onload/onchange functions have access to the current value and can change any of the parameters of the control. The following callback for example changes the color of a thermometer to red if the value is above 30 and to blue if it is below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;onchange=&amp;quot;this.dataset.color=this.value &amp;gt; 30?&#039;red&#039;:&#039;blue&#039;;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
onchange can call any arbitrary javascript function. Rather than specifying the logic in the tag itself, the above example could also be implemented like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
function check_therm(elem) {&lt;br /&gt;
  if (elem.value &amp;gt; 30) {&lt;br /&gt;
    elem.dataset.color = &amp;quot;red&amp;quot;;&lt;br /&gt;
  } else {&lt;br /&gt;
    elem.dataset.color = &amp;quot;blue&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;modbthermo&amp;quot; style=&amp;quot;width: 30px; height: 100px;&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-min-value=&amp;quot;-10&amp;quot; data-max-value=&amp;quot;30&amp;quot; data-color=&amp;quot;blue&amp;quot; data-print-value=&amp;quot;1&amp;quot; onchange=&amp;quot;check_therm(this)&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Other example use cases include showing/hiding other elements on a webpage based on whether an modbcheckbox is checked or not, or temporarily changing the background color of an element to highlight that a value has changed.&lt;br /&gt;
&lt;br /&gt;
If you want the same function to be called for both onload and onchange, you could set &amp;lt;code&amp;gt;onload=&amp;quot;onchange()&amp;quot;&amp;lt;/code&amp;gt; and have the &amp;quot;real&amp;quot; function in onchange.&lt;br /&gt;
&lt;br /&gt;
== Dynamic ODB paths ==&lt;br /&gt;
&lt;br /&gt;
The path of a custom control is static, meaning it has to be written directly inside the control via &amp;lt;code&amp;gt;data-odb-path=&amp;quot;/Some/Path&amp;quot;&amp;lt;/code&amp;gt;. There can be however cases where the path is only known at runtime. For these cases, the path can be a user function which gets called during each update of the control and has to return the current ODB path. This can be useful for equipment values with names. The standard scheme of MIDAS is to have slow control variables under &amp;lt;code&amp;gt;/Equipment/&amp;lt;name&amp;gt;/Variables&amp;lt;/code&amp;gt; and the names of these variables under &amp;lt;code&amp;gt;/Equipment/&amp;lt;name&amp;gt;/Settings/Names&amp;lt;/code&amp;gt;. If there are several different arrays under &amp;lt;code&amp;gt;Variables&amp;lt;/code&amp;gt;, you might also have something like &amp;lt;code&amp;gt;/Equipment/&amp;lt;name&amp;gt;/Settings/Names XXX&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;XXX&amp;lt;/code&amp;gt; is the name of the key under &amp;lt;code&amp;gt;Variables&amp;lt;/code&amp;gt;. If one wants to use a name of a variable rather than its index, the dynamic path function can be uses like in the following example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
   let names;&lt;br /&gt;
&lt;br /&gt;
   function getNames() {&lt;br /&gt;
      mjsonrpc_db_get_value(&amp;quot;/Equipment/.../Settings/Names&amp;quot;).then(function (rpc) {&lt;br /&gt;
         names = rpc.result.data[0];&lt;br /&gt;
         mhttpd_init(&#039;Custom Page Example&#039;);&lt;br /&gt;
      });&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   function getpath(p) {&lt;br /&gt;
      if (mscbNames)&lt;br /&gt;
         return `/Equipment/.../Variables/MSCB[${names.indexOf(p)}]`;&lt;br /&gt;
   }&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;body class=&amp;quot;mcss&amp;quot; onload=&amp;quot;getNames();&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- header and side navigation will be filled in mhttpd_init --&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;mheader&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;msidenav&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;mmain&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;div class=&amp;quot;modbvalue&amp;quot; data-odb-path=&amp;quot;getpath(&#039;ADC1&#039;)&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When the page is initialized, the function &amp;lt;code&amp;gt;getNames()&amp;lt;/code&amp;gt; is called, which obtains the &amp;lt;code&amp;gt;Names&amp;lt;/code&amp;gt; array from the ODB and stores it into an array. After the names have been received, the function calls the usual &amp;lt;code&amp;gt;mhttpd_init()&amp;lt;/code&amp;gt; function. The &amp;quot;modbvalue&amp;quot; path is now set to &amp;lt;code&amp;gt;data-odb-path=&amp;quot;getpath(&#039;ADC1&#039;)&amp;quot;&amp;lt;/code&amp;gt;. This function does a lookup in the &amp;lt;code&amp;gt;names&amp;lt;/code&amp;gt; array and returns the proper index, which is then used to access the corresponding value in the variables array. This method has the advantage that if the indices of an array change (e.g. by adding new variables at the front), the code does not have to update any index since the indices are calculated dynamically.&lt;br /&gt;
&lt;br /&gt;
== Changing values of indicators programmatically ==&lt;br /&gt;
&lt;br /&gt;
Usually, custom controls are directly linked to values in the ODB. Sometimes it is however necessary to combine several ODB values into a single indicator, like if you want to show the difference of two ODB values. &lt;br /&gt;
&lt;br /&gt;
For such cases, the &amp;lt;code&amp;gt;data-odb-path&amp;lt;/code&amp;gt; attribute can be removed and the the display value can be changed via JavaScript code like following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;mythermo&amp;quot; class=&amp;quot;modbthermo&amp;quot; data-min-value=&amp;quot;-10&amp;quot; data-max-value=&amp;quot;30&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
  let t = document.getElementById(&amp;quot;mythermo&amp;quot;);&lt;br /&gt;
  t.setValue(15);&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= mjshistory =&lt;br /&gt;
&lt;br /&gt;
Custom pages can contain one or more specific history panels usually shown on the &amp;quot;History&amp;quot; page. This makes it easy to combine current readings of values together with the history of these values.&lt;br /&gt;
&lt;br /&gt;
To enable interactive history panels, following lines have to be added to your custom page:&lt;br /&gt;
&lt;br /&gt;
Inisde the &amp;lt;head&amp;gt; tag:&lt;br /&gt;
&lt;br /&gt;
   &amp;lt;script src=&amp;quot;mhistory.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Inside the &amp;lt;body&amp;gt; tag:&lt;br /&gt;
&lt;br /&gt;
   &amp;lt;body ... onload=&amp;quot;mhistory_init();&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following tag:&lt;br /&gt;
&lt;br /&gt;
   &amp;amp;lt;div class=&amp;quot;mjshistory&amp;quot; data-group=&amp;quot;&amp;lt;group&amp;gt;&amp;quot; data-panel=&amp;quot;&amp;lt;panel&amp;gt;&amp;quot; style=&amp;quot;width: 320px; height: 200px;&amp;quot; &amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
shows a history panel defined in the ODB under /History/Display/&amp;amp;lt;group&amp;amp;gt;/&amp;amp;lt;panel&amp;amp;gt; (replace &amp;amp;lt;group&amp;amp;gt;/&amp;amp;lt;panel&amp;amp;gt; with groups and panels from your experiment).&lt;br /&gt;
&lt;br /&gt;
Following options are possible:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Setting !! Meaning !! Required&lt;br /&gt;
|-&lt;br /&gt;
| data-group || ODB group of history. Has to match a group under /History/Display || Yes&lt;br /&gt;
|-&lt;br /&gt;
| data-panel || ODB panel name of history. Has to match a panel name under /History/Display/&amp;amp;lt;group&amp;amp;gt;/ || Yes&lt;br /&gt;
|-&lt;br /&gt;
| data-scale || Time scale of history plot. Use 10m for 10 minutes and 5h for 5 hours. If not specified, the value from the ODB under /History/Display/&amp;amp;lt;group&amp;amp;gt;/&amp;amp;lt;panel&amp;amp;gt;/Timescale is used. || No&lt;br /&gt;
|-&lt;br /&gt;
| data-show-title || Flag to show or hide the title. Default is &amp;quot;1&amp;quot;. || No&lt;br /&gt;
|-&lt;br /&gt;
| data-show-values || Flag to show or hide the variable labels with their current value. Default is &amp;quot;1&amp;quot;. || No&lt;br /&gt;
|-&lt;br /&gt;
| data-show-axis || Flag to show or hide the X/Y axis. Default is &amp;quot;1&amp;quot;. || No&lt;br /&gt;
|-&lt;br /&gt;
| data-show-menu-buttons || Flag to show or hide the menu buttons. Default is &amp;quot;1&amp;quot;. || No&lt;br /&gt;
|-&lt;br /&gt;
| data-show-menu-buttons || Flag to show or hide the zoom buttons. Default is &amp;quot;1&amp;quot;. || No&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;width: 320px&amp;quot; || Width of the history panel || No&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;height: 200px&amp;quot; || Height of the history panel || No&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border: 1px solid black&amp;quot; || Border around the history panel || No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If width and height are omitted, the default values of 320px and 200px are used. History panels are automatically updated every second.&lt;br /&gt;
&lt;br /&gt;
In addition, it is possible to show a floating dialog box with a history panel. That might be useful if you show a single value on a custom page, and want to give users &lt;br /&gt;
the possibility to show the history of that variable. Just put a button next to the value and call &#039;&#039;&#039;mhistory_dialog(&amp;amp;lt;group&amp;amp;gt;, &amp;amp;lt;panel&amp;amp;gt;)&#039;&#039;&#039; from that button like:&lt;br /&gt;
&lt;br /&gt;
   &amp;amp;lt;span class=&amp;quot;modbvalue&amp;quot; data-odb-path=&amp;quot;/Some/Path&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;&lt;br /&gt;
   &amp;lt;button onclick=&amp;quot;mhistory_dialog(&#039;group&#039;,&#039;panel&#039;)&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;icons/activity.svg&amp;quot;&amp;gt;&amp;lt;/button&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The history panel will then be opened when the user clicks the button:&lt;br /&gt;
&lt;br /&gt;
[[File:History dialog.png|frame|left|Floating history dialog]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br clear=all&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If one wants to avoid the definition of a history panel in the ODB, a &amp;quot;direct variable plot&amp;quot; can be done with the function &#039;&#039;&#039;mhistory_dialog_var(&amp;amp;lt;variable&amp;amp;gt;)&#039;&#039;&#039; where &amp;amp;lt;variable&amp;amp;gt; has the format like the variable definition in the ODB (e.g. &amp;quot;System:Trigger per sec.&amp;quot;). Such a plot has some default parameters for the timescale etc., which can be overwritten by passing a parameter object to the function such as &#039;&#039;&#039;mhistory_dialog_var(&amp;quot;System:Trigger per sec.&amp;quot;, {&amp;quot;Timescale&amp;quot;: &amp;quot;24h&amp;quot;});&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A full example of a custom page with a history panel is shown below.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
  &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;midas.css&amp;quot; type=&amp;quot;text/css&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;script src=&amp;quot;midas.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;script src=&amp;quot;mhttpd.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;script src=&amp;quot;controls.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;script src=&amp;quot;mhistory.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body onload=&amp;quot;mhttpd_init(&#039;history_example&#039;); mhistory_init();&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;mheader&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;msidenav&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;  &lt;br /&gt;
  &amp;lt;div id=&amp;quot;mmain&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;mjshistory&amp;quot; data-group=&amp;quot;EPICS&amp;quot; data-panel=&amp;quot;Logging&amp;quot; style=&amp;quot;width: 500px; height: 300px;&amp;quot; &amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= mplot =&lt;br /&gt;
&lt;br /&gt;
Custom pages may contain scatter plots, histograms and other graphics. The syntax is described on the dedicated [[Custom plots with mplot]] page.&lt;br /&gt;
&lt;br /&gt;
= Dialog, popup and modal boxes =&lt;br /&gt;
&lt;br /&gt;
You can spawn a dialog box to either show a message to the user, ask for input, or require confirmation of an action. You can call all these functions from your own javascript code.&lt;br /&gt;
&lt;br /&gt;
== Showing a message ==&lt;br /&gt;
&lt;br /&gt;
The dlgMessage, dlgAlert and dlgWait functions show a message to the user. The dialog box contains an &amp;quot;Ok&amp;quot; button that the user may click to dismiss the message.&lt;br /&gt;
&lt;br /&gt;
=== dlgMessage ===&lt;br /&gt;
&lt;br /&gt;
dlgMessage is the most customisable of the 3 functions. The signature is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dlgMessage(title, message, modal, error, callback, param)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter !! Type !! Meaning !! Required&lt;br /&gt;
|-&lt;br /&gt;
| title || string || Title of the dialog box || Yes&lt;br /&gt;
|-&lt;br /&gt;
| message || string (can be arbitrary HTML) || Main message content || Yes&lt;br /&gt;
|-&lt;br /&gt;
| modal || boolean || If true, will grey out the rest of the page and require the user to dismiss the alert box before they can continue interacting with the page. || No. Defaults to false&lt;br /&gt;
|-&lt;br /&gt;
| error || boolean || If true, will use a red background for the title || No. Defaults to false&lt;br /&gt;
|-&lt;br /&gt;
| callback || function || Function to be called with the user clicks the &amp;quot;Ok&amp;quot; button. The callback function will be called with just a single paramter. || No. Defaults to not calling a callback function.&lt;br /&gt;
|-&lt;br /&gt;
| param || anything || Parameter that will be passed to the `callback` function || No. Defaults to undefined.&lt;br /&gt;
|}&lt;br /&gt;
 &lt;br /&gt;
Some example invocations are:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dlgMessage(&amp;quot;Message title&amp;quot;, &amp;quot;Message text&amp;quot;);&lt;br /&gt;
dlgMessage(&amp;quot;It&#039;s an error!&amp;quot;, &amp;quot;&amp;lt;b&amp;gt;Something is wrong!!!&amp;lt;/b&amp;gt;&amp;quot;, true, true);&lt;br /&gt;
dlgMessage(&amp;quot;Callback example&amp;quot;, &amp;quot;Testing&amp;quot;, true, false, my_message_cb, &amp;quot;some_param&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
function my_message_cb(param) {&lt;br /&gt;
   alert(&amp;quot;Message dismissed! The param was &amp;quot; + param);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== dlgAlert ===&lt;br /&gt;
&lt;br /&gt;
dlgAlert is a convenience function for making it easier to show a warning message to the user. The signature is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dlgAlert(message, callback)&lt;br /&gt;
&lt;br /&gt;
// The above is equivalent to:&lt;br /&gt;
dlgMessage(&amp;quot;Message&amp;quot;, message, true, true, callback)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== dlgWait ===&lt;br /&gt;
&lt;br /&gt;
dlgWait shows a message for a certain amount of time and then automatically closes itself. The signature is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dlgWait(time_in_seconds, message)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Asking for input ==&lt;br /&gt;
&lt;br /&gt;
=== dlgQuery ===&lt;br /&gt;
&lt;br /&gt;
dlgQuery asks the user to respond to a question. The dialog shows a message, an input field for the user to type in, and Ok/Cancel buttons. The user&#039;s response is sent to a callback function that you must implement yourself. The signature is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dlgQuery(message, value, callback, param)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter !! Type !! Meaning !! Required&lt;br /&gt;
|-&lt;br /&gt;
| message || string (can be arbitrary HTML) || The question to show the user || Yes&lt;br /&gt;
|-&lt;br /&gt;
| value || string || Default value to pre-populate the answer field with || Yes (but can be empty string)&lt;br /&gt;
|-&lt;br /&gt;
| callback || function || Function to be called when the user finishes with the dialog. The first parameter will be false if the user clicked the &amp;quot;Cancel&amp;quot; button, or their answer if they clicked the &amp;quot;Ok&amp;quot; button. || Yes&lt;br /&gt;
|-&lt;br /&gt;
| param || anything || Parameter that will be passed to the `callback` function as the 2nd parameter || No. Defaults to undefined.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example usage is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dlgQuery(&amp;quot;Enter a value:&amp;quot;, &amp;quot;my default value&amp;quot;, my_query_cb, &amp;quot;some_other_param&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
function my_query_cb(value, param) {&lt;br /&gt;
   if (value === false) {&lt;br /&gt;
      // User clicked the Cancel button&lt;br /&gt;
   } else {&lt;br /&gt;
      alert(&#039;Value is &#039; + value + &#039;, param is &#039; + param);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// where &#039;param&#039; can also be ommitted.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== dlgConfirm ===&lt;br /&gt;
&lt;br /&gt;
dlgConfirm is like dlgQuery, but just shows the Ok and Cancel buttons without an extra input field. The signature is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dlgConfirm(message, callback, param)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter !! Type !! Meaning !! Required&lt;br /&gt;
|-&lt;br /&gt;
| message || string (can be arbitrary HTML) || The question to show the user || Yes&lt;br /&gt;
|-&lt;br /&gt;
| callback || function || Function to be called when the user finishes with the dialog. The first parameter will be false if the user clicked the &amp;quot;Cancel&amp;quot; button, or true if they clicked the &amp;quot;Ok&amp;quot; button. || Yes&lt;br /&gt;
|-&lt;br /&gt;
| param || anything || Parameter that will be passed to the `callback` function as the 2nd parameter || No. Defaults to undefined.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example usage is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dlgConfirm(&amp;quot;Are you sure you wish to do that?&amp;quot;, my_confirm_cb, &amp;quot;some_other_param&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
function my_confirm_cb(value, param) {&lt;br /&gt;
   if (value === false) {&lt;br /&gt;
      alert(&amp;quot;User clicked Cancel! Param was &amp;quot; + param);&lt;br /&gt;
   } else {&lt;br /&gt;
      alert(&amp;quot;User clicked Ok! Param was &amp;quot; + param);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// where &#039;param&#039; can also be ommitted.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Implementing SVGs =&lt;br /&gt;
&lt;br /&gt;
An SVG file loaded on a custom page can be interactively modified using JavaScript.&lt;br /&gt;
This is useful for graphically displaying ODB values in complex service or detector systems.&lt;br /&gt;
&lt;br /&gt;
An SVG file can be embedded like this:&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
&amp;lt;object id=&amp;quot;svgObject&amp;quot; type=&amp;quot;image/svg+xml&amp;quot; data=&amp;quot;Midas_helium_example.svg&amp;quot;&amp;gt;&amp;lt;/object&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Objects within the SVG can be modified—for example, by changing their fill color as shown below:&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
const svgDoc = document.getElementById(&#039;svgObject&#039;).contentDocument; &lt;br /&gt;
const obj_Valve = svgDoc.getElementById(valveID); &lt;br /&gt;
obj_Valve.style.fill = &amp;quot;#00FF00&amp;quot;; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
SVG images are stored in XML format. In Inkscape, object properties can be interactively edited using the XML Editor.&lt;br /&gt;
A full example is given below in [[SVGs on Custom Pages]]&lt;br /&gt;
&lt;br /&gt;
= Complete Example =&lt;br /&gt;
&lt;br /&gt;
The following code shows an example page (contained in {{Filepath|path=resources/a_example.html}} in the MIDAS distribution) of a custom page implementing most of the new features. You activate this page by putting in the ODB:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/Custom&lt;br /&gt;
  Path     /midas/resources&lt;br /&gt;
  Test     a_example.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
The file &#039;&#039;&#039;a_example.html&#039;&#039;&#039; contains the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html class=&amp;quot;mcss&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
   &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;midas.css&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;script src=&amp;quot;controls.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
   &amp;lt;script src=&amp;quot;midas.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
   &amp;lt;script src=&amp;quot;mhttpd.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
   &amp;lt;title&amp;gt;Example&amp;lt;/title&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   &amp;lt;style&amp;gt;&lt;br /&gt;
      .mtable td { padding: 10px; }&lt;br /&gt;
   &amp;lt;/style&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;body class=&amp;quot;mcss&amp;quot; onload=&amp;quot;mhttpd_init(&#039;Example&#039;);&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- header and side navigation will be filled in mhttpd_init --&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;mheader&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;msidenav&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;mmain&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;table class=&amp;quot;mtable&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;th colspan=&amp;quot;2&amp;quot; class=&amp;quot;mtableheader&amp;quot;&amp;gt;Status&amp;lt;/th&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td style=&amp;quot;width: 200px;&amp;quot;&amp;gt;&lt;br /&gt;
            Run number:&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbvalue&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-odb-editable=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            Last run start:&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbvalue&amp;quot; data-odb-path=&amp;quot;/Runinfo/Start time&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            Last run stop:&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbvalue&amp;quot; data-odb-path=&amp;quot;/Runinfo/Stop time&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            Check box:&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            &amp;lt;!-- checkbox changes /Logger/Write data, fire dialog box on change (even if changed by odbedit) --&amp;gt;&lt;br /&gt;
            &amp;lt;input type=&amp;quot;checkbox&amp;quot; class=&amp;quot;modbcheckbox&amp;quot; data-odb-path=&amp;quot;/Logger/Write data&amp;quot;&amp;gt;&amp;lt;/input&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modb&amp;quot; data-odb-path=&amp;quot;/Logger/Write data&amp;quot; onchange=&amp;quot;dlgAlert(&#039;Flag has changed&#039;);&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            Color box:&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            &amp;lt;!-- box changes color according to /Logger/Write data --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbbox&amp;quot; style=&amp;quot;width: 30px; height: 30px;&amp;quot; data-odb-path=&amp;quot;/Logger/Write data&amp;quot;&lt;br /&gt;
                 data-color=&amp;quot;lightgreen&amp;quot; data-background-color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            Horizontal bars:&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbhbar&amp;quot; style=&amp;quot;width:300px;height:20px;color:orange;&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot;&lt;br /&gt;
                 data-max-value=&amp;quot;10&amp;quot; data-print-value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;div class=&amp;quot;mhaxis&amp;quot; style=&amp;quot;width:500px;height:22px;&amp;quot; data-min-value=&amp;quot;0&amp;quot; data-max-value=&amp;quot;10&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbhbar&amp;quot; style=&amp;quot;width: 500px; height: 18px;color:lightblue&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot;&lt;br /&gt;
                 data-max-value=&amp;quot;10&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbhbar&amp;quot; style=&amp;quot;width: 200px; height: 10px;color:lightgreen;background-color:white&amp;quot;&lt;br /&gt;
                 data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-min-value=&amp;quot;0.1&amp;quot; data-max-value=&amp;quot;10&amp;quot; data-log=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;mhaxis&amp;quot; style=&amp;quot;width:200px;height:22px;vertical-align:top;&amp;quot; data-min-value=&amp;quot;0.1&amp;quot;&lt;br /&gt;
                 data-max-value=&amp;quot;10&amp;quot; data-line=&amp;quot;0&amp;quot; data-log=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            Vertical bars:&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            &amp;lt;span class=&amp;quot;mvaxis&amp;quot; style=&amp;quot;width:100px;height:200px;text-align:right;&amp;quot; data-min-value=&amp;quot;0&amp;quot; data-max-value=&amp;quot;20&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;modbvbar&amp;quot;&lt;br /&gt;
                  style=&amp;quot;width:20px;height:200px;color:yellow;&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot;&lt;br /&gt;
                  data-min-value=&amp;quot;0&amp;quot; data-max-value=&amp;quot;20&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
            &amp;lt;span class=&amp;quot;modbvbar&amp;quot; style=&amp;quot;width:10px;height:200px;vertical-align:top;color:red&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-min-value=&amp;quot;0.1&amp;quot;&lt;br /&gt;
                  data-max-value=&amp;quot;10&amp;quot; data-log=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;mvaxis&amp;quot; style=&amp;quot;width:100px;height:200px;text-align:left;&amp;quot; data-min-value=&amp;quot;0.1&amp;quot;&lt;br /&gt;
                                                                data-max-value=&amp;quot;10&amp;quot; data-log=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            Thermometer:&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbthermo&amp;quot; style=&amp;quot;width:30px;height:100px;&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-min-value=&amp;quot;-10&amp;quot; data-max-value=&amp;quot;30&amp;quot;&lt;br /&gt;
                 data-color=&amp;quot;darkgreen&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbthermo&amp;quot; style=&amp;quot;width:60px;height:100px;&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-min-value=&amp;quot;-10&amp;quot; data-max-value=&amp;quot;30&amp;quot;&lt;br /&gt;
                 data-color=&amp;quot;blue&amp;quot; data-scale=&amp;quot;1&amp;quot;&lt;br /&gt;
                 onchange=&amp;quot;this.dataset.color=this.value &amp;gt; 9?&#039;red&#039;:&#039;blue&#039;;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbthermo&amp;quot; style=&amp;quot;width:30px;height:100px;&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-min-value=&amp;quot;-10&amp;quot; data-max-value=&amp;quot;30&amp;quot;&lt;br /&gt;
                 data-color=&amp;quot;blue&amp;quot; data-background-color=&amp;quot;white&amp;quot; data-value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            Gauges:&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbgauge&amp;quot; style=&amp;quot;width:100px;height:50px;&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-min-value=&amp;quot;0&amp;quot; data-max-value=&amp;quot;10&amp;quot;&lt;br /&gt;
                 data-color=&amp;quot;darkgreen&amp;quot; data-background-color=&amp;quot;lightgrey&amp;quot; &amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbgauge&amp;quot; style=&amp;quot;width:100px;height:65px;&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-min-value=&amp;quot;0&amp;quot; data-max-value=&amp;quot;10&amp;quot;&lt;br /&gt;
                 data-color=&amp;quot;red&amp;quot; data-value=&amp;quot;1&amp;quot; data-scale=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td colspan=&amp;quot;2&amp;quot; style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- div around image with &amp;quot;relative&amp;quot; position as anchor for labels and bars --&amp;gt;&lt;br /&gt;
            &amp;lt;div style=&amp;quot;position:relative;width:300px;margin:auto&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
               &amp;lt;img src=&amp;quot;tank.gif&amp;quot;&amp;gt; &amp;lt;!-- background image of tank --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
               &amp;lt;!-- label next to valve --&amp;gt;&lt;br /&gt;
               &amp;lt;div class=&amp;quot;modbvalue&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-odb-editable=&amp;quot;1&amp;quot;&lt;br /&gt;
                    style=&amp;quot;position:absolute;top:157px;left:288px;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
               &amp;lt;!-- vertical bar inside tank, render red if value &amp;gt; 9 --&amp;gt;&lt;br /&gt;
               &amp;lt;div class=&amp;quot;modbvbar&amp;quot; style=&amp;quot;position:absolute;top:80px;left:10px;width:104px;height:170px;&amp;quot;&lt;br /&gt;
                    data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-max-value=&amp;quot;11&amp;quot; data-color=&amp;quot;green&amp;quot;&lt;br /&gt;
                    onchange=&amp;quot;this.firstChild.style.backgroundColor=(this.value &amp;gt; 9)?&#039;red&#039;:&#039;green&#039;;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
               &amp;lt;!-- thermometer inside tank --&amp;gt;&lt;br /&gt;
               &amp;lt;div class=&amp;quot;modbthermo&amp;quot; style=&amp;quot;position:absolute;top:140px;left:20px;width:20px;height:100px;&amp;quot;&lt;br /&gt;
                    data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-min-value=&amp;quot;-10&amp;quot; data-max-value=&amp;quot;30&amp;quot;&lt;br /&gt;
                    data-color=&amp;quot;blue&amp;quot; data-value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td colspan=&amp;quot;2&amp;quot; style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- three buttons to change an ODB entry (run number in this example) --&amp;gt;&lt;br /&gt;
            &amp;lt;button class=&amp;quot;modbbutton&amp;quot; class=&amp;quot;mbutton&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-odb-value=&amp;quot;1&amp;quot;&amp;gt;Set run&lt;br /&gt;
               number to 1&lt;br /&gt;
            &amp;lt;/button&amp;gt;&lt;br /&gt;
            &amp;lt;button class=&amp;quot;modbbutton&amp;quot; class=&amp;quot;mbutton&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-odb-value=&amp;quot;5&amp;quot;&amp;gt;Set run&lt;br /&gt;
               number to 5&lt;br /&gt;
            &amp;lt;/button&amp;gt;&lt;br /&gt;
            &amp;lt;button class=&amp;quot;modbbutton&amp;quot; class=&amp;quot;mbutton&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-odb-value=&amp;quot;10&amp;quot;&amp;gt;Set run&lt;br /&gt;
               number to 10&lt;br /&gt;
            &amp;lt;/button&amp;gt;&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
   &amp;lt;/table&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
which results in the page shown in Figure 1 below:&lt;br /&gt;
&lt;br /&gt;
[[File:Custom17.png|frame|left|Figure 1  Example custom page using most features]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt; &amp;lt;!-- clear wraparound after thumbnail --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Old custom page feature =&lt;br /&gt;
&lt;br /&gt;
There are a number of deprecated custom page features, which can be seen here: [[Old Custom Page Features]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:mhttpd Pages]] [[Category:Custom]]&lt;/div&gt;</summary>
		<author><name>Zaher</name></author>
	</entry>
	<entry>
		<id>https://daq00.triumf.ca/MidasWiki/index.php?title=/Custom_ODB_tree&amp;diff=3478</id>
		<title>/Custom ODB tree</title>
		<link rel="alternate" type="text/html" href="https://daq00.triumf.ca/MidasWiki/index.php?title=/Custom_ODB_tree&amp;diff=3478"/>
		<updated>2025-03-17T17:04:22Z</updated>

		<summary type="html">&lt;p&gt;Zaher: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Pagelinks}}&lt;br /&gt;
&lt;br /&gt;
= Links =&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* [[mhttpd |MIDAS web server (mhttpd)]] &lt;br /&gt;
* mhttpd [[Custom Page]]&lt;br /&gt;
* [[Custom Page Features]]&lt;br /&gt;
* mhttpd [[Status Page]]&lt;br /&gt;
* [[Mhttpd.js|MIDAS Javascript Library]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Purpose =&lt;br /&gt;
The {{Odbpath|path=/Custom}} ODB tree is required if the user wishes to create [[mhttpd]] custom pages. It contains essential data needed for [[mhttpd]] to display a custom page. The {{Odbpath|path=/images}} subtree is required if an imagefile (*.gif) is to be displayed on the custom page. Optionally, labels, bars and fills can be superimposed on the image.&lt;br /&gt;
&lt;br /&gt;
= Creating the &amp;lt;span style=&amp;quot;color:purple; font-style:italic;&amp;quot;&amp;gt;/Custom&amp;lt;/span&amp;gt;  tree =&lt;br /&gt;
The {{Odbpath|path=/Custom}} ODB tree is an optional tree that may be [[ODB#Creating ODB keys|created by the user]]. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Custom-Button&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div id=&amp;quot;Custom-Link&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
= Keys in the /Custom tree =&lt;br /&gt;
The optional ODB {{Odbpath|path=/Custom}} tree may contain any of the following :&lt;br /&gt;
&lt;br /&gt;
*  keys pointing to &#039;&#039;&#039;local&#039;&#039;&#039; external files containing custom web pages (html/javascript files)&lt;br /&gt;
*  keys pointing to &#039;&#039;&#039;local&#039;&#039;&#039; external files containing resources for custom web pages (e.g. .css style files, .js javascript file, images).&lt;br /&gt;
** Note: files that are have a &#039;.&#039; in the Key name are assumed to be resource files and are treated differently. See also the [[#Path key|Path key]] notes below.&lt;br /&gt;
** Note: .css, .js, .pdf, .jpg, .gif, .png, .svg, .ps, .eps, .xls, .doc, .txt, .asc, .zip files should get served up with the correct MIME types&lt;br /&gt;
*  keys containing the html code for [[Internal Custom Page#How to create an Internal Custom Page|internal custom webpages]] &lt;br /&gt;
*  &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Path&amp;lt;/span&amp;gt; variable, used to indicate where to look on host machine for external files.&lt;br /&gt;
*  &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/pwd&amp;lt;/span&amp;gt; subtree used to contain custom password keys&lt;br /&gt;
*  &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/images&amp;lt;/span&amp;gt; subtree used to specify images for custom pages&lt;br /&gt;
&lt;br /&gt;
Keys defined in this tree pointing to custom web pages of any kind are called &#039;&#039;&#039;&#039;&#039;custom-links&#039;&#039;&#039;&#039;&#039;.  &lt;br /&gt;
* External &#039;&#039;custom-links&#039;&#039; contain the path and filename of the external custom page file (or may be a symbolic link to a custom-link) &lt;br /&gt;
* Internal &#039;&#039;custom-links&#039;&#039; contain the code for an [[Internal Custom Page]]. &lt;br /&gt;
&lt;br /&gt;
If &#039;&#039;custom-links&#039;&#039; are defined in this tree, except where [[#Key names|noted below]], the &#039;&#039;custom-links&#039;&#039; will appear as &#039;&#039;&#039;&#039;&#039;custom-buttons&#039;&#039;&#039;&#039;&#039;  on the [[mhttpd]] [[Status Page]]. By clicking on one of these &#039;&#039;custom-buttons&#039;&#039;, the custom page will be visible in a new frame (see also [[#Key names|Key names]]). &lt;br /&gt;
&lt;br /&gt;
We will note some of the subtleties of how the Custom tree keys are used in the following sub-sections. &lt;br /&gt;
&lt;br /&gt;
== Key names ==&lt;br /&gt;
The user chooses the names of any keys in the &amp;lt;span style=&amp;quot;color:purple; font-style:italic;&amp;quot;&amp;gt;/Custom&amp;lt;/span&amp;gt; ODB tree except for&lt;br /&gt;
* the key name &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Status&amp;lt;/span&amp;gt; is reserved (see [[Custom Page#Custom Status page|Custom Status Page]]). &lt;br /&gt;
* the key name &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;pwd&amp;lt;/span&amp;gt; is reserved (see optional  [[#Pwd subtree|Pwd subtree]] for custom passwords)&lt;br /&gt;
* the key name &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Path&amp;lt;/span&amp;gt; is reserved (see optional  [[#Path key|Path key] for details)&lt;br /&gt;
* keys in the  &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/images&amp;lt;/span&amp;gt; subtree have defined names except for the user-defined [[#&amp;lt;Image-name&amp;gt; subtree|&amp;lt;Image-name&amp;gt; subtree]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There are two characters that have &#039;&#039;&#039;special meaning&#039;&#039;&#039; if they are the last character of a &#039;&#039;custom-link&#039;&#039; in the {{Odbpath|path=/Custom}} tree :&lt;br /&gt;
*    The character &amp;quot;&#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;&amp;quot; forces the page to be opened in a new tab/window when the &#039;&#039;custom-button&#039;&#039; is pressed. If this character is omitted, the page will be opened in the current frame. The &amp;quot;&amp;amp;&amp;quot; character is omitted from the name of the button.&lt;br /&gt;
*    The character &amp;quot;&#039;&#039;&#039;!&#039;&#039;&#039;&amp;quot; suppresses the &#039;&#039;custom-button&#039;&#039; from appearing on the [[Status Page]], forming a &#039;&#039;hidden-link&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;hidden-link&#039;&#039; feature can be used to provide external webpages hidden from the user, such as a stylesheet or a file of Javascript functions needed by other custom pages. If the value does not end with a file extention, e.g. console.log(&amp;quot;this goes into onclick&amp;quot;), then no link is produced. Instead an &#039;&#039;onclick&#039;&#039; call is formed.&lt;br /&gt;
&lt;br /&gt;
The {{Odbpath|path=/Custom}} tree in the [[#Example|example]] below would produce one &#039;&#039;custom-button&#039;&#039;, i.e.{{Button|name=ppg&amp;amp;nbsp;cycle}}.&lt;br /&gt;
&lt;br /&gt;
;NOTE&lt;br /&gt;
: To avoid confusion, do not use custom-links that only differ by the special characters &amp;quot;&amp;amp;&amp;quot; and &amp;quot;!&amp;quot; (e.g. &amp;quot;test&amp;quot;, &amp;quot;test&amp;amp;&amp;quot; and &amp;quot;test!&amp;quot;) in the same ODB.&lt;br /&gt;
&lt;br /&gt;
= Path key =&lt;br /&gt;
&lt;br /&gt;
When creating custom external web pages you will usually want to use other resource files, like CSS style sheets or images.  &lt;br /&gt;
&lt;br /&gt;
One way to do that is to specify each of the files that you need to use in the  {{Odbpath|path=/Custom}} tree.  For instance, suppose you had a HTML file called  {{File|name=control.html}} that used an image called  {{File|name=valve.png}}.  You could &lt;br /&gt;
&lt;br /&gt;
 Key name                        Type    #Val  Size  Last Opn Mode Value&lt;br /&gt;
 ---------------------------------------------------------------------------&lt;br /&gt;
 Control                         STRING  1     256   1h   0   RWD  /home/expt/online/custom/control.html&lt;br /&gt;
 valve.png!                      STRING  1     256   1h   0   RWD  /home/expt/online/custom/valve.png&lt;br /&gt;
&lt;br /&gt;
You would then be able to refer to that png normally in your HTML&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 &amp;lt;img src=&amp;quot;valve.png!&amp;quot;&amp;gt;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
This approach can get tedious however, if you have a large number of resource files to add.&lt;br /&gt;
&lt;br /&gt;
An alternative is given by the {{Odbpath|path=Path}} ODB key.  This key can be used to specify a directory on the server file system where files should be searched for.  So, for instance, if the {{Odbpath|path=/Custom}} tree is set to &lt;br /&gt;
&lt;br /&gt;
 Key name                        Type    #Val  Size  Last Opn Mode Value&lt;br /&gt;
 ---------------------------------------------------------------------------&lt;br /&gt;
 Path                            STRING  1     256   1h   0   RWD  /home/expt/online/custom/&lt;br /&gt;
 Control                         STRING  1     256   1h   0   RWD  control.html&lt;br /&gt;
&lt;br /&gt;
you can instruct  {{Utility|name=mhttpd}} to look in the directory  {{Filepath|path=/home/expt/online/custom/}} and then map the custom page &#039;Control&#039; to &lt;br /&gt;
 {{Filepath|path=/home/expt/online/custom/control.html}}.   &lt;br /&gt;
&lt;br /&gt;
One very important point: when the key {{Odbpath|path=/Custom/Path}} is defined, mhttpd will treat differently how it serves up resources, depending on whether there is a &#039;.&#039; in the resource web address.  So, for instance, for the custom page described above &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     https://myhost:8443/?cmd=custom&amp;amp;page=Control   &lt;br /&gt;
 or  http://myhost:8081/CS/Control   (very old MIDAS versions )&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
you will need to have a ODB key called  {{Odbpath|path=/Custom/Control}}, as described above.  &lt;br /&gt;
&lt;br /&gt;
However, if you have the ODB key  {{Odbpath|path=/Custom/Path}} and you access content like&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   https://myhost:8443/?cmd=custom&amp;amp;page=valve.png&lt;br /&gt;
or http://myhost:8081/CS/valve.png (very old MIDAS versions )&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
then  {{Utility|name=mhttpd}} will automatically figure out that it should use the file&lt;br /&gt;
&lt;br /&gt;
 Value of &amp;quot;/Custom/Path&amp;quot; + valve.png&lt;br /&gt;
 i.e. /home/expt/online/custom/valve.png&lt;br /&gt;
&lt;br /&gt;
So the benefit is that with the   {{Odbpath|path=/Custom/Path}} key set, you can just place all your resource files in the directory pointed to by /Custom/Path and mhttpd will find them, &#039;&#039;&#039;without needing to specify them individually &#039;&#039;&#039;  {{Odbpath|path=/Custom}} as custom-links.&lt;br /&gt;
&lt;br /&gt;
See also [[Custom Page Features#Resource files]] for more examples.&lt;br /&gt;
&lt;br /&gt;
= Example  =	&lt;br /&gt;
The following example using the [[odbedit]] &#039;&#039;&#039;ls&#039;&#039;&#039; command shows the optional custom tree for an experiment. &lt;br /&gt;
&amp;lt;br&amp;gt;Note the use of the &amp;quot;&amp;amp;&amp;quot; and &amp;quot;!&amp;quot; characters in the names of the custom keys  (see [[#Key names|key names]] for details).&lt;br /&gt;
 [local:pol:S]/ls -lr /Custom&lt;br /&gt;
 Key name                        Type    #Val  Size  Last Opn Mode Value&lt;br /&gt;
 ---------------------------------------------------------------------------&lt;br /&gt;
 custom                          DIR&lt;br /&gt;
    ppg_cycle&amp;amp;                  STRING  1    80    36h  0  RWD  /home/pol/online/pol/custom/pol_sc.html&lt;br /&gt;
    pol_functions!              STRING  1    80    36h  0  RWD  /home/pol/online/pol/custom/pol_functions.js&lt;br /&gt;
    style!                      STRING  1    80    36h  0  RWD  /home/pol/online/pol/custom/style.css&lt;br /&gt;
    images                      DIR&lt;br /&gt;
        pol_sc.gif              DIR&lt;br /&gt;
            background          STRING  1     80    36h  0   RWD  /home/pol/online/pol/custom/pol_sc.gif&lt;br /&gt;
            labels              DIR&lt;br /&gt;
                num bins        DIR&lt;br /&gt;
                    Src         STRING  1     256   36h  0   RWD  /Equipment/pol_acq/settings/output/num bins per cycle&lt;br /&gt;
                    Format      STRING  1     32    36h  0   RWD  %d&lt;br /&gt;
                    Font        STRING  1     32    36h  0   RWD  Medium&lt;br /&gt;
                    X           INT     1     4     36h  0   RWD  315&lt;br /&gt;
                    Y           INT     1     4     36h  0   RWD  502&lt;br /&gt;
                    Align       INT     1     4     36h  0   RWD  0&lt;br /&gt;
                    FGColor     STRING  1     8     36h  0   RWD  FFFFFF&lt;br /&gt;
                    BGColor     STRING  1     8     36h  0   RWD  0000FF&lt;br /&gt;
                dwell time      DIR&lt;br /&gt;
                    Src         STRING  1     256   36h  0   RWD  /Equipment/POL_ACQ/Settings/input/dwell time (ms)&lt;br /&gt;
                    Format      STRING  1     32    36h  0   RWD  %f ms&lt;br /&gt;
                    Font        STRING  1     32    36h  0   RWD  large&lt;br /&gt;
                    X           INT     1     4     36h  0   RWD  145&lt;br /&gt;
                    Y           INT     1     4     36h  0   RWD  430&lt;br /&gt;
                    Align       INT     1     4     36h  0   RWD  0&lt;br /&gt;
                    FGColor     STRING  1     8     36h  0   RWD  FFFFFF&lt;br /&gt;
                    BGColor     STRING  1     8     36h  0   RWD  0000FF&lt;br /&gt;
             fills              DIR&lt;br /&gt;
                    SSLevelBox  DIR&lt;br /&gt;
                    Src         STRING  1     256   36h  0   RWD  /Equipment/TpcGasPlc/GasCalc/Calculated[136]&lt;br /&gt;
                    X           INT     1     4     36h  0   RWD  578&lt;br /&gt;
                    Y           INT     1     4     36h  0   RWD  490&lt;br /&gt;
                    Limits      DOUBLE  3     8     2s   0   RWD&lt;br /&gt;
                                        [0]             0&lt;br /&gt;
                                        [1]             1&lt;br /&gt;
                                        [2]             2&lt;br /&gt;
                    Fillcolors  STRING  4     8     2s   0   RWD&lt;br /&gt;
                                        [0]             000000&lt;br /&gt;
                                        [1]             00FF00&lt;br /&gt;
                                        [2]             808080&lt;br /&gt;
             bars               DIR&lt;br /&gt;
                    temp        DIR&lt;br /&gt;
                    Src         STRING  1     256   36h  0   RWD  /Equipment/Temperature/Variables/Readback[5]&lt;br /&gt;
                    X           INT     1     4     36h  0   RWD  42&lt;br /&gt;
                    Y           INT     1     4     36h  0   RWD  68&lt;br /&gt;
                    Width       INT     1     4     36h  0   RWD  10&lt;br /&gt;
                    Height      INT     1     4     36h  0   RWD  50&lt;br /&gt;
                    Direction   INT     1     4     36h  0   RWD  0&lt;br /&gt;
                    Axis        INT     1     4     36h  0   RWD  1&lt;br /&gt;
                    Logscale    BOOL    1     4     &amp;gt;99d 0   RWD  n&lt;br /&gt;
                    Min         DOUBLE  1     8     &amp;gt;99d 0   RWD  0&lt;br /&gt;
                    Max         DOUBLE  1     8     &amp;gt;99d 0   RWD  0&lt;br /&gt;
                    FGcolor     STRING  1     8     2s   0   RWD  000000&lt;br /&gt;
                    BGcolor     STRING  1     8     2s   0   RWD  FFFFFF&lt;br /&gt;
                    BDcolor     STRING  1     8     2s   0   RWD  808080&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Pwd&amp;lt;/span&amp;gt; subtree=&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
This optional subtree in the  [[#top|/Custom ODB tree]] is created by the user if [[Custom Page]] write access is to be  [[Custom Page Features#Password protection of ODB variables|password protected]].&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;password&amp;gt;&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;  &amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
The &#039;&#039;&#039;name&#039;&#039;&#039; of the optional key(s) in the &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/Pwd&amp;lt;/span&amp;gt; subtree defines a password that the user must specify to gain access to a [[Custom Page Features#Password protection of ODB variables|password-protected]]&lt;br /&gt;
item on a [[Custom Page]]. &lt;br /&gt;
&lt;br /&gt;
=== Password examples ===&lt;br /&gt;
If the password is &#039;&#039;CustomPwd&#039;&#039;, the ODB key &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/Custom/Pwd/CustomPwd&amp;lt;/span&amp;gt; would be defined.&lt;br /&gt;
&lt;br /&gt;
By using an explicit name, one can use a single password for all controls on a page, or one could use several passwords on the same page. For example, a shift crew password for the less severe controls could be defined as &#039;&#039;ShiftPwd&#039;&#039;, and an &amp;quot;expert&amp;quot; password &#039;&#039;ExpertPwd&#039;&#039; for the critical things.&lt;br /&gt;
&lt;br /&gt;
In this case, the ODB would have two passwords defined, i.e.&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/Custom/Pwd/ExpertPwd&amp;lt;/span&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/Custom/Pwd/ShiftPwd&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The password is of course not secure in the sense that it is placed in plain text into the ODB, but its purpose is to prevent accidental modification, rather than malicious interference.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Images&amp;lt;/span&amp;gt; subtree =&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
This optional subtree in the  [[#top|/Custom ODB tree]] is created by the user. It is required if an imagefile (*.gif) is to be displayed on a custom page.&lt;br /&gt;
This subtree is also required for any &#039;&#039;&#039;labels, bars&#039;&#039;&#039; or &#039;&#039;&#039;fills&#039;&#039;&#039; to be superimposed on the image.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;Image-name&amp;gt;&amp;lt;/span&amp;gt; subtree ==&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory usually named for the corresponding gif-image, e.g. &amp;quot;pol_sc.gif&amp;quot; in the [[#Example|example]] above. For multiple images, multiple subdirectories may be defined. The user&lt;br /&gt;
chooses the name of this key.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Background&amp;lt;/span&amp;gt;  ===&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
This key in the  [[#&amp;lt;Image-name&amp;gt; subtree|&amp;lt;image-name&amp;gt; subtree]] contains the path and filename of the image file to be loaded into a custom page. Only &#039;&#039;&#039;gif&#039;&#039;&#039; format is supported for the image. This optional key is created by the user.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Labels&amp;lt;/span&amp;gt; subtree ===&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#&amp;lt;Image-name&amp;gt; subtree|&amp;lt;image-name&amp;gt; subtree]] required if &#039;&#039;&#039;labels&#039;&#039;&#039; are to be superimposed on an image on a custom page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;label-name&amp;gt;&amp;lt;/span&amp;gt; subtree ====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#Labels subtree|Labels subtree]] containing keys to define this label as listed below. There will be a &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;label-name&amp;gt;&amp;lt;/span&amp;gt; subtree for each label superimposed on the custom image.&lt;br /&gt;
&lt;br /&gt;
The user creates keys in this subtree with the names and types as listed below. See also the [[#Example|example]] above.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Labels Src&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Src&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [256]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the path of a valid ODB Key variable. This is the value to be used for this label on an image.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Format&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [32]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;%1.1f&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the format for this label on the image. Format specifications (c.f. &amp;quot;printf&amp;quot; in C) are used to convert the value specified by the [[#Labels Src|Src key]] into the output string that appears on the image. &lt;br /&gt;
For example, &lt;br /&gt;
* &amp;quot;Count Rate:%5d kB/s&amp;quot;  used to display an integer value&lt;br /&gt;
* &amp;quot;%5.2f%% iBu&amp;quot; used to display a floating point value. Note &amp;quot;%%&amp;quot; displays the &amp;quot;%&amp;quot; sign.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Font&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING[32]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;Medium&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the font size for this label. Supported values are &amp;quot;small&amp;quot;,  &amp;quot;medium&amp;quot; or &amp;quot;giant&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Labels X&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;X&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the X position for this label in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Labels Y&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Y&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the Y position for this label in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Align&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains an integer representing Horizontal Alignment for this label. Set to one of 0 (left), 1 (center) or 2 (right). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Labels FGColor&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;FGColor&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [8]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;000000&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the foreground colour  for this label in the format RRGGBB (hex). See [[#Colour table|colour table]]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Labels BGColor&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;BGColor&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [8]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;FFFFFF&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the background colour  for this label in the format RRGGBB (hex). See [[#Colour table|colour table]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Bars&amp;lt;/span&amp;gt; subtree ===&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#&amp;lt;Image-name&amp;gt; subtree|&amp;lt;image-name&amp;gt; subtree]] required if &#039;&#039;&#039;bars&#039;&#039;&#039; are to be superimposed on an image on a custom page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;bar-name&amp;gt;&amp;lt;/span&amp;gt; subtree ====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#Bars subtree|Fills subtree]] containing keys to define this &#039;&#039;&#039;bar&#039;&#039;&#039; as listed below. There will be a &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;bar-name&amp;gt;&amp;lt;/span&amp;gt; subtree for each bar superimposed on the custom image.&lt;br /&gt;
&lt;br /&gt;
The user creates keys in this subtree with the names and types as listed below. See also the [[#Example|example]] above.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Bars Src&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Src&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [256]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the path of a valid ODB Key variable. This is the value to be used for this bar. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Bars X&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;X&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the X position for this bar in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Bars Y&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Y&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the Y position for this bar in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Width&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 10&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the width of this bar in pixels.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Height&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 100&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the height of this bar in pixels.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Direction&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains an integer denoting the direction of this bar. It can be either 0 (vertical) or 1 (horizontal). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Axis&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 1&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains an integer specifying the axis of this bar. It can be either 0 (none), 1 (left) or 2 (right). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Logscale&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; BOOL&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;n&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] specifies whether the axis of this bar is logarithmic. Set to &amp;quot;y&amp;quot; for logarithmic, otherwise &amp;quot;n&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Min&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DOUBLE&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the minimum value for the axis of the bar. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Max&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DOUBLE&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 10&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the maximum value for the axis of the bar. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Bars FGColor&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;FGColor&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [8]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;000000&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the foreground colour  for this bar in the format RRGGBB (hex). See [[#Colour table|colour table]]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Bars BGColor&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;BGColor&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [8]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;FFFFFF&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the background colour  for this bar in the format RRGGBB (hex). See [[#Colour table|colour table]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;BDColor&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [8]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;808080&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the border colour  for this bar in the format RRGGBB (hex). See [[#Colour table|colour table]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Fills&amp;lt;/span&amp;gt; subtree ===&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#&amp;lt;Image-name&amp;gt; subtree|&amp;lt;image-name&amp;gt; subtree]] required if &#039;&#039;&#039;fills&#039;&#039;&#039; are to be superimposed on an image on a custom page.&lt;br /&gt;
A &amp;quot;fill&amp;quot; can change the colour of a region on the image. The contents of the ODB key defined in [[#Fills Src|Src]] determines the colour as defined by the Limits and Fillcolors arrays.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;fill-name&amp;gt;&amp;lt;/span&amp;gt; subtree ====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#Fills subtree|Fills subtree]] containing keys to define this fill as listed below. There will be a &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;fill-name&amp;gt;&amp;lt;/span&amp;gt; subtree for each fill superimposed on the custom image.&lt;br /&gt;
&lt;br /&gt;
The user creates keys in this subtree with the names and types as listed below. See also the [[#Example|example]] above.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Fills Src&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Src&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This key in the [[#&amp;lt;fill-name&amp;gt;subtree|&amp;lt;fill-name&amp;gt; subtree]] contains the path of a valid ODB Key variable. Unless a [[#logic_calculation|logic calculation]] is included,  the contents of this key determines the value used for the fill &lt;br /&gt;
on the image defined by the key [[#Background|Background]] (see fill-name &amp;quot;SSLevelBox&amp;quot; in the [[#Example|example]] above).&lt;br /&gt;
&amp;lt;div id=&amp;quot;logic_calculation&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
If a &#039;&#039;&#039;logic calculation&#039;&#039;&#039; is included, up to two operators are permitted, and they must be either&lt;br /&gt;
;&lt;br /&gt;
:    &amp;quot;&amp;gt;&amp;gt;&amp;quot; (shift to the right) or&lt;br /&gt;
:    &amp;quot;&amp;amp;&amp;quot; (bitwise AND).&lt;br /&gt;
&lt;br /&gt;
A hexadecimal number preceded by &amp;quot;0x&amp;quot; is also supported.&lt;br /&gt;
This feature enables a SRC key that is actually a bit pattern to be used for a fill.&lt;br /&gt;
&lt;br /&gt;
In the following example, a gas valve is open if bit 14 of PLCR[136] is TRUE and closed if bit 15 is TRUE (bits are from 0-15). The contents of PLCR[136] are shifted to the right by 14 and then a logical AND is performed to clear all but the lowest 2 bits. The result is used to colour the valve body lime green if the valve is open, and black if it is closed. If neither bit is set (i.e. the valve is neither open nor closed) the valve body is coloured red to indicate an error. Anything else (i.e. both bits TRUE) will give a gray colour.&lt;br /&gt;
&lt;br /&gt;
 [local:t2kgas:S]/&amp;gt;ls /custom/images/Pump_20.gif/fills/d2vb3&lt;br /&gt;
 Src                             /Equipment/TpcGasPlc/Variables/PLCR[136] &amp;gt;&amp;gt; 14 &amp;amp; 0x3&lt;br /&gt;
 X                               905&lt;br /&gt;
 Y                               536&lt;br /&gt;
 limits&lt;br /&gt;
                                0&lt;br /&gt;
                                1&lt;br /&gt;
                                2&lt;br /&gt;
                                3&lt;br /&gt;
 Fillcolors&lt;br /&gt;
                                808080&lt;br /&gt;
                                00FF00&lt;br /&gt;
                                000000&lt;br /&gt;
                                808080&lt;br /&gt;
                   &lt;br /&gt;
&lt;br /&gt;
Any fill that requires a more complicated calculation than this will have to be done using Javascript in the custom page. The calculated value can then be stored in an ODB key, which is then defined as a Fill [[#Fills Src|Src]] key.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Fills X&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;X&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;fill-name&amp;gt;subtree|&amp;lt;fill-name&amp;gt; subtree]] contains the X position for this fill in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Fills Y&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Y&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;fill-name&amp;gt;subtree|&amp;lt;fill-name&amp;gt; subtree]] contains the Y position for this fill in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Limits&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT array&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;fill-name&amp;gt;subtree|&amp;lt;fill-name&amp;gt; subtree]] is a variable-length array containing the values of the limits that when reached cause a colour change. Array length must match length of array &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Fillcolors&amp;lt;/span&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Fillcolors&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT array&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;fill-name&amp;gt;subtree|&amp;lt;fill-name&amp;gt; subtree]] is a variable-length array containing the colours corresponding to the [[#Limits|Limits]] array.  The colours are defined in the format RRGGBB (hex). See [[#Colour table|colour table]].  Array length must match length of &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Limits&amp;lt;/span&amp;gt; array.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Colour Table =&lt;br /&gt;
For convenience, a colour reference table is shown here for some common colours:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;  style=&amp;quot;margin: auto; ext-align: left; width: 25%; background-color: rgb(255, 255, 255);&amp;quot; border=&amp;quot;3&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: rgb(204, 204, 255); font-weight: bold;&amp;quot; | Colour&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: rgb(204, 204, 255); font-weight: bold;&amp;quot; | RGB Value&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; color: black; font-weight: normal;&amp;quot; | Black&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; color: black; font-weight: normal;&amp;quot; | 000000&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: silver; color: white; font-weight: normal;&amp;quot; | White&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: silver; color: white; font-weight: normal;&amp;quot; | FFFFFF&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: white; color: red; font-weight: normal;&amp;quot; | Red&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; color: black; font-weight: normal;&amp;quot; | FF0000&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: silver; color: lime; font-weight: normal;&amp;quot; | Lime green&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top;  background-color: silver; color: lime; font-weight: normal;&amp;quot; | 00FF00&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: white; color: blue; font-weight: normal;&amp;quot; | Blue&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; color: black; font-weight: normal;&amp;quot; | 0000FF&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: silver; color: yellow; font-weight: normal;&amp;quot; | Yellow&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: silver; color: yellow; font-weight: normal;&amp;quot; | FFFF00&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: white; color: grey; font-weight: normal;&amp;quot; | Grey&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; color: black; font-weight: normal;&amp;quot; | 808080&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:ODB Tree]] [[Category:Custom]]&lt;/div&gt;</summary>
		<author><name>Zaher</name></author>
	</entry>
	<entry>
		<id>https://daq00.triumf.ca/MidasWiki/index.php?title=/Custom_ODB_tree&amp;diff=3477</id>
		<title>/Custom ODB tree</title>
		<link rel="alternate" type="text/html" href="https://daq00.triumf.ca/MidasWiki/index.php?title=/Custom_ODB_tree&amp;diff=3477"/>
		<updated>2025-03-17T17:02:52Z</updated>

		<summary type="html">&lt;p&gt;Zaher: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Pagelinks}}&lt;br /&gt;
&lt;br /&gt;
= Links =&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* [[mhttpd |MIDAS web server (mhttpd)]] &lt;br /&gt;
* mhttpd [[Custom Page]]&lt;br /&gt;
* [[Custom Page Features]]&lt;br /&gt;
* mhttpd [[Status Page]]&lt;br /&gt;
* [[Mhttpd.js|MIDAS Javascript Library]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Purpose =&lt;br /&gt;
The {{Odbpath|path=/Custom}} ODB tree is required if the user wishes to create [[mhttpd]] custom pages. It contains essential data needed for [[mhttpd]] to display a custom page. The {{Odbpath|path=/images}} subtree is required if an imagefile (*.gif) is to be displayed on the custom page. Optionally, labels, bars and fills can be superimposed on the image.&lt;br /&gt;
&lt;br /&gt;
= Creating the &amp;lt;span style=&amp;quot;color:purple; font-style:italic;&amp;quot;&amp;gt;/Custom&amp;lt;/span&amp;gt;  tree =&lt;br /&gt;
The {{Odbpath|path=/Custom}} ODB tree is an optional tree that may be [[ODB#Creating ODB keys|created by the user]]. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Custom-Button&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div id=&amp;quot;Custom-Link&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
= Keys in the /Custom tree =&lt;br /&gt;
The optional ODB {{Odbpath|path=/Custom}} tree may contain any of the following :&lt;br /&gt;
&lt;br /&gt;
*  keys pointing to &#039;&#039;&#039;local&#039;&#039;&#039; external files containing custom web pages (html/javascript files)&lt;br /&gt;
*  keys pointing to &#039;&#039;&#039;local&#039;&#039;&#039; external files containing resources for custom web pages (e.g. .css style files, .js javascript file, images).&lt;br /&gt;
** Note: files that are have a &#039;.&#039; in the Key name are assumed to be resource files and are treated differently. See also the [[#Path key|Path key]] notes below.&lt;br /&gt;
** Note: .css, .js, .pdf, .jpg, .gif, .png, .svg, .ps, .eps, .xls, .doc, .txt, .asc, .zip files should get served up with the correct MIME types&lt;br /&gt;
*  keys containing the html code for [[Internal Custom Page#How to create an Internal Custom Page|internal custom webpages]] &lt;br /&gt;
*  &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Path&amp;lt;/span&amp;gt; variable, used to indicate where to look on host machine for external files.&lt;br /&gt;
*  &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/pwd&amp;lt;/span&amp;gt; subtree used to contain custom password keys&lt;br /&gt;
*  &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/images&amp;lt;/span&amp;gt; subtree used to specify images for custom pages&lt;br /&gt;
&lt;br /&gt;
Keys defined in this tree pointing to custom web pages of any kind are called &#039;&#039;&#039;&#039;&#039;custom-links&#039;&#039;&#039;&#039;&#039;.  &lt;br /&gt;
* External &#039;&#039;custom-links&#039;&#039; contain the path and filename of the external custom page file (or may be a symbolic link to a custom-link) &lt;br /&gt;
* Internal &#039;&#039;custom-links&#039;&#039; contain the code for an [[Internal Custom Page]]. &lt;br /&gt;
&lt;br /&gt;
If &#039;&#039;custom-links&#039;&#039; are defined in this tree, except where [[#Key names|noted below]], the &#039;&#039;custom-links&#039;&#039; will appear as &#039;&#039;&#039;&#039;&#039;custom-buttons&#039;&#039;&#039;&#039;&#039;  on the [[mhttpd]] [[Status Page]]. By clicking on one of these &#039;&#039;custom-buttons&#039;&#039;, the custom page will be visible in a new frame (see also [[#Key names|Key names]]). &lt;br /&gt;
&lt;br /&gt;
We will note some of the subtleties of how the Custom tree keys are used in the following sub-sections. &lt;br /&gt;
&lt;br /&gt;
== Key names ==&lt;br /&gt;
The user chooses the names of any keys in the &amp;lt;span style=&amp;quot;color:purple; font-style:italic;&amp;quot;&amp;gt;/Custom&amp;lt;/span&amp;gt; ODB tree except for&lt;br /&gt;
* the key name &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Status&amp;lt;/span&amp;gt; is reserved (see [[Custom Page#Custom Status page|Custom Status Page]]). &lt;br /&gt;
* the key name &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;pwd&amp;lt;/span&amp;gt; is reserved (see optional  [[#Pwd subtree|Pwd subtree]] for custom passwords)&lt;br /&gt;
* the key name &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Path&amp;lt;/span&amp;gt; is reserved (see optional  [[#Path key|Path key] for details)&lt;br /&gt;
* keys in the  &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/images&amp;lt;/span&amp;gt; subtree have defined names except for the user-defined [[#&amp;lt;Image-name&amp;gt; subtree|&amp;lt;Image-name&amp;gt; subtree]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There are two characters that have &#039;&#039;&#039;special meaning&#039;&#039;&#039; if they are the last character of a &#039;&#039;custom-link&#039;&#039; in the {{Odbpath|path=/Custom}} tree :&lt;br /&gt;
*    The character &amp;quot;&#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;&amp;quot; forces the page to be opened in a new tab/window when the &#039;&#039;custom-button&#039;&#039; is pressed. If this character is omitted, the page will be opened in the current frame. The &amp;quot;&amp;amp;&amp;quot; character is omitted from the name of the button.&lt;br /&gt;
*    The character &amp;quot;&#039;&#039;&#039;!&#039;&#039;&#039;&amp;quot; suppresses the &#039;&#039;custom-button&#039;&#039; from appearing on the [[Status Page]], forming a &#039;&#039;hidden-link&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;hidden-link&#039;&#039; feature can be used to provide external webpages hidden from the user, such as a stylesheet or a file of Javascript functions needed by other custom pages. If the value does not end with a file extention, e.g. clonsole.log(&amp;quot;this goes into onclick&amp;quot;), then no link is produced. Instead an &#039;&#039;onclick&#039;&#039; call is formed.&lt;br /&gt;
&lt;br /&gt;
The {{Odbpath|path=/Custom}} tree in the [[#Example|example]] below would produce one &#039;&#039;custom-button&#039;&#039;, i.e.{{Button|name=ppg&amp;amp;nbsp;cycle}}.&lt;br /&gt;
&lt;br /&gt;
;NOTE&lt;br /&gt;
: To avoid confusion, do not use custom-links that only differ by the special characters &amp;quot;&amp;amp;&amp;quot; and &amp;quot;!&amp;quot; (e.g. &amp;quot;test&amp;quot;, &amp;quot;test&amp;amp;&amp;quot; and &amp;quot;test!&amp;quot;) in the same ODB.&lt;br /&gt;
&lt;br /&gt;
= Path key =&lt;br /&gt;
&lt;br /&gt;
When creating custom external web pages you will usually want to use other resource files, like CSS style sheets or images.  &lt;br /&gt;
&lt;br /&gt;
One way to do that is to specify each of the files that you need to use in the  {{Odbpath|path=/Custom}} tree.  For instance, suppose you had a HTML file called  {{File|name=control.html}} that used an image called  {{File|name=valve.png}}.  You could &lt;br /&gt;
&lt;br /&gt;
 Key name                        Type    #Val  Size  Last Opn Mode Value&lt;br /&gt;
 ---------------------------------------------------------------------------&lt;br /&gt;
 Control                         STRING  1     256   1h   0   RWD  /home/expt/online/custom/control.html&lt;br /&gt;
 valve.png!                      STRING  1     256   1h   0   RWD  /home/expt/online/custom/valve.png&lt;br /&gt;
&lt;br /&gt;
You would then be able to refer to that png normally in your HTML&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 &amp;lt;img src=&amp;quot;valve.png!&amp;quot;&amp;gt;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
This approach can get tedious however, if you have a large number of resource files to add.&lt;br /&gt;
&lt;br /&gt;
An alternative is given by the {{Odbpath|path=Path}} ODB key.  This key can be used to specify a directory on the server file system where files should be searched for.  So, for instance, if the {{Odbpath|path=/Custom}} tree is set to &lt;br /&gt;
&lt;br /&gt;
 Key name                        Type    #Val  Size  Last Opn Mode Value&lt;br /&gt;
 ---------------------------------------------------------------------------&lt;br /&gt;
 Path                            STRING  1     256   1h   0   RWD  /home/expt/online/custom/&lt;br /&gt;
 Control                         STRING  1     256   1h   0   RWD  control.html&lt;br /&gt;
&lt;br /&gt;
you can instruct  {{Utility|name=mhttpd}} to look in the directory  {{Filepath|path=/home/expt/online/custom/}} and then map the custom page &#039;Control&#039; to &lt;br /&gt;
 {{Filepath|path=/home/expt/online/custom/control.html}}.   &lt;br /&gt;
&lt;br /&gt;
One very important point: when the key {{Odbpath|path=/Custom/Path}} is defined, mhttpd will treat differently how it serves up resources, depending on whether there is a &#039;.&#039; in the resource web address.  So, for instance, for the custom page described above &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     https://myhost:8443/?cmd=custom&amp;amp;page=Control   &lt;br /&gt;
 or  http://myhost:8081/CS/Control   (very old MIDAS versions )&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
you will need to have a ODB key called  {{Odbpath|path=/Custom/Control}}, as described above.  &lt;br /&gt;
&lt;br /&gt;
However, if you have the ODB key  {{Odbpath|path=/Custom/Path}} and you access content like&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   https://myhost:8443/?cmd=custom&amp;amp;page=valve.png&lt;br /&gt;
or http://myhost:8081/CS/valve.png (very old MIDAS versions )&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
then  {{Utility|name=mhttpd}} will automatically figure out that it should use the file&lt;br /&gt;
&lt;br /&gt;
 Value of &amp;quot;/Custom/Path&amp;quot; + valve.png&lt;br /&gt;
 i.e. /home/expt/online/custom/valve.png&lt;br /&gt;
&lt;br /&gt;
So the benefit is that with the   {{Odbpath|path=/Custom/Path}} key set, you can just place all your resource files in the directory pointed to by /Custom/Path and mhttpd will find them, &#039;&#039;&#039;without needing to specify them individually &#039;&#039;&#039;  {{Odbpath|path=/Custom}} as custom-links.&lt;br /&gt;
&lt;br /&gt;
See also [[Custom Page Features#Resource files]] for more examples.&lt;br /&gt;
&lt;br /&gt;
= Example  =	&lt;br /&gt;
The following example using the [[odbedit]] &#039;&#039;&#039;ls&#039;&#039;&#039; command shows the optional custom tree for an experiment. &lt;br /&gt;
&amp;lt;br&amp;gt;Note the use of the &amp;quot;&amp;amp;&amp;quot; and &amp;quot;!&amp;quot; characters in the names of the custom keys  (see [[#Key names|key names]] for details).&lt;br /&gt;
 [local:pol:S]/ls -lr /Custom&lt;br /&gt;
 Key name                        Type    #Val  Size  Last Opn Mode Value&lt;br /&gt;
 ---------------------------------------------------------------------------&lt;br /&gt;
 custom                          DIR&lt;br /&gt;
    ppg_cycle&amp;amp;                  STRING  1    80    36h  0  RWD  /home/pol/online/pol/custom/pol_sc.html&lt;br /&gt;
    pol_functions!              STRING  1    80    36h  0  RWD  /home/pol/online/pol/custom/pol_functions.js&lt;br /&gt;
    style!                      STRING  1    80    36h  0  RWD  /home/pol/online/pol/custom/style.css&lt;br /&gt;
    images                      DIR&lt;br /&gt;
        pol_sc.gif              DIR&lt;br /&gt;
            background          STRING  1     80    36h  0   RWD  /home/pol/online/pol/custom/pol_sc.gif&lt;br /&gt;
            labels              DIR&lt;br /&gt;
                num bins        DIR&lt;br /&gt;
                    Src         STRING  1     256   36h  0   RWD  /Equipment/pol_acq/settings/output/num bins per cycle&lt;br /&gt;
                    Format      STRING  1     32    36h  0   RWD  %d&lt;br /&gt;
                    Font        STRING  1     32    36h  0   RWD  Medium&lt;br /&gt;
                    X           INT     1     4     36h  0   RWD  315&lt;br /&gt;
                    Y           INT     1     4     36h  0   RWD  502&lt;br /&gt;
                    Align       INT     1     4     36h  0   RWD  0&lt;br /&gt;
                    FGColor     STRING  1     8     36h  0   RWD  FFFFFF&lt;br /&gt;
                    BGColor     STRING  1     8     36h  0   RWD  0000FF&lt;br /&gt;
                dwell time      DIR&lt;br /&gt;
                    Src         STRING  1     256   36h  0   RWD  /Equipment/POL_ACQ/Settings/input/dwell time (ms)&lt;br /&gt;
                    Format      STRING  1     32    36h  0   RWD  %f ms&lt;br /&gt;
                    Font        STRING  1     32    36h  0   RWD  large&lt;br /&gt;
                    X           INT     1     4     36h  0   RWD  145&lt;br /&gt;
                    Y           INT     1     4     36h  0   RWD  430&lt;br /&gt;
                    Align       INT     1     4     36h  0   RWD  0&lt;br /&gt;
                    FGColor     STRING  1     8     36h  0   RWD  FFFFFF&lt;br /&gt;
                    BGColor     STRING  1     8     36h  0   RWD  0000FF&lt;br /&gt;
             fills              DIR&lt;br /&gt;
                    SSLevelBox  DIR&lt;br /&gt;
                    Src         STRING  1     256   36h  0   RWD  /Equipment/TpcGasPlc/GasCalc/Calculated[136]&lt;br /&gt;
                    X           INT     1     4     36h  0   RWD  578&lt;br /&gt;
                    Y           INT     1     4     36h  0   RWD  490&lt;br /&gt;
                    Limits      DOUBLE  3     8     2s   0   RWD&lt;br /&gt;
                                        [0]             0&lt;br /&gt;
                                        [1]             1&lt;br /&gt;
                                        [2]             2&lt;br /&gt;
                    Fillcolors  STRING  4     8     2s   0   RWD&lt;br /&gt;
                                        [0]             000000&lt;br /&gt;
                                        [1]             00FF00&lt;br /&gt;
                                        [2]             808080&lt;br /&gt;
             bars               DIR&lt;br /&gt;
                    temp        DIR&lt;br /&gt;
                    Src         STRING  1     256   36h  0   RWD  /Equipment/Temperature/Variables/Readback[5]&lt;br /&gt;
                    X           INT     1     4     36h  0   RWD  42&lt;br /&gt;
                    Y           INT     1     4     36h  0   RWD  68&lt;br /&gt;
                    Width       INT     1     4     36h  0   RWD  10&lt;br /&gt;
                    Height      INT     1     4     36h  0   RWD  50&lt;br /&gt;
                    Direction   INT     1     4     36h  0   RWD  0&lt;br /&gt;
                    Axis        INT     1     4     36h  0   RWD  1&lt;br /&gt;
                    Logscale    BOOL    1     4     &amp;gt;99d 0   RWD  n&lt;br /&gt;
                    Min         DOUBLE  1     8     &amp;gt;99d 0   RWD  0&lt;br /&gt;
                    Max         DOUBLE  1     8     &amp;gt;99d 0   RWD  0&lt;br /&gt;
                    FGcolor     STRING  1     8     2s   0   RWD  000000&lt;br /&gt;
                    BGcolor     STRING  1     8     2s   0   RWD  FFFFFF&lt;br /&gt;
                    BDcolor     STRING  1     8     2s   0   RWD  808080&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Pwd&amp;lt;/span&amp;gt; subtree=&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
This optional subtree in the  [[#top|/Custom ODB tree]] is created by the user if [[Custom Page]] write access is to be  [[Custom Page Features#Password protection of ODB variables|password protected]].&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;password&amp;gt;&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;  &amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
The &#039;&#039;&#039;name&#039;&#039;&#039; of the optional key(s) in the &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/Pwd&amp;lt;/span&amp;gt; subtree defines a password that the user must specify to gain access to a [[Custom Page Features#Password protection of ODB variables|password-protected]]&lt;br /&gt;
item on a [[Custom Page]]. &lt;br /&gt;
&lt;br /&gt;
=== Password examples ===&lt;br /&gt;
If the password is &#039;&#039;CustomPwd&#039;&#039;, the ODB key &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/Custom/Pwd/CustomPwd&amp;lt;/span&amp;gt; would be defined.&lt;br /&gt;
&lt;br /&gt;
By using an explicit name, one can use a single password for all controls on a page, or one could use several passwords on the same page. For example, a shift crew password for the less severe controls could be defined as &#039;&#039;ShiftPwd&#039;&#039;, and an &amp;quot;expert&amp;quot; password &#039;&#039;ExpertPwd&#039;&#039; for the critical things.&lt;br /&gt;
&lt;br /&gt;
In this case, the ODB would have two passwords defined, i.e.&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/Custom/Pwd/ExpertPwd&amp;lt;/span&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/Custom/Pwd/ShiftPwd&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The password is of course not secure in the sense that it is placed in plain text into the ODB, but its purpose is to prevent accidental modification, rather than malicious interference.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Images&amp;lt;/span&amp;gt; subtree =&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
This optional subtree in the  [[#top|/Custom ODB tree]] is created by the user. It is required if an imagefile (*.gif) is to be displayed on a custom page.&lt;br /&gt;
This subtree is also required for any &#039;&#039;&#039;labels, bars&#039;&#039;&#039; or &#039;&#039;&#039;fills&#039;&#039;&#039; to be superimposed on the image.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;Image-name&amp;gt;&amp;lt;/span&amp;gt; subtree ==&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory usually named for the corresponding gif-image, e.g. &amp;quot;pol_sc.gif&amp;quot; in the [[#Example|example]] above. For multiple images, multiple subdirectories may be defined. The user&lt;br /&gt;
chooses the name of this key.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Background&amp;lt;/span&amp;gt;  ===&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
This key in the  [[#&amp;lt;Image-name&amp;gt; subtree|&amp;lt;image-name&amp;gt; subtree]] contains the path and filename of the image file to be loaded into a custom page. Only &#039;&#039;&#039;gif&#039;&#039;&#039; format is supported for the image. This optional key is created by the user.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Labels&amp;lt;/span&amp;gt; subtree ===&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#&amp;lt;Image-name&amp;gt; subtree|&amp;lt;image-name&amp;gt; subtree]] required if &#039;&#039;&#039;labels&#039;&#039;&#039; are to be superimposed on an image on a custom page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;label-name&amp;gt;&amp;lt;/span&amp;gt; subtree ====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#Labels subtree|Labels subtree]] containing keys to define this label as listed below. There will be a &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;label-name&amp;gt;&amp;lt;/span&amp;gt; subtree for each label superimposed on the custom image.&lt;br /&gt;
&lt;br /&gt;
The user creates keys in this subtree with the names and types as listed below. See also the [[#Example|example]] above.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Labels Src&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Src&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [256]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the path of a valid ODB Key variable. This is the value to be used for this label on an image.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Format&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [32]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;%1.1f&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the format for this label on the image. Format specifications (c.f. &amp;quot;printf&amp;quot; in C) are used to convert the value specified by the [[#Labels Src|Src key]] into the output string that appears on the image. &lt;br /&gt;
For example, &lt;br /&gt;
* &amp;quot;Count Rate:%5d kB/s&amp;quot;  used to display an integer value&lt;br /&gt;
* &amp;quot;%5.2f%% iBu&amp;quot; used to display a floating point value. Note &amp;quot;%%&amp;quot; displays the &amp;quot;%&amp;quot; sign.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Font&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING[32]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;Medium&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the font size for this label. Supported values are &amp;quot;small&amp;quot;,  &amp;quot;medium&amp;quot; or &amp;quot;giant&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Labels X&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;X&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the X position for this label in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Labels Y&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Y&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the Y position for this label in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Align&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains an integer representing Horizontal Alignment for this label. Set to one of 0 (left), 1 (center) or 2 (right). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Labels FGColor&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;FGColor&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [8]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;000000&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the foreground colour  for this label in the format RRGGBB (hex). See [[#Colour table|colour table]]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Labels BGColor&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;BGColor&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [8]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;FFFFFF&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the background colour  for this label in the format RRGGBB (hex). See [[#Colour table|colour table]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Bars&amp;lt;/span&amp;gt; subtree ===&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#&amp;lt;Image-name&amp;gt; subtree|&amp;lt;image-name&amp;gt; subtree]] required if &#039;&#039;&#039;bars&#039;&#039;&#039; are to be superimposed on an image on a custom page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;bar-name&amp;gt;&amp;lt;/span&amp;gt; subtree ====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#Bars subtree|Fills subtree]] containing keys to define this &#039;&#039;&#039;bar&#039;&#039;&#039; as listed below. There will be a &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;bar-name&amp;gt;&amp;lt;/span&amp;gt; subtree for each bar superimposed on the custom image.&lt;br /&gt;
&lt;br /&gt;
The user creates keys in this subtree with the names and types as listed below. See also the [[#Example|example]] above.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Bars Src&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Src&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [256]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the path of a valid ODB Key variable. This is the value to be used for this bar. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Bars X&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;X&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the X position for this bar in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Bars Y&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Y&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the Y position for this bar in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Width&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 10&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the width of this bar in pixels.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Height&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 100&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the height of this bar in pixels.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Direction&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains an integer denoting the direction of this bar. It can be either 0 (vertical) or 1 (horizontal). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Axis&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 1&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains an integer specifying the axis of this bar. It can be either 0 (none), 1 (left) or 2 (right). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Logscale&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; BOOL&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;n&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] specifies whether the axis of this bar is logarithmic. Set to &amp;quot;y&amp;quot; for logarithmic, otherwise &amp;quot;n&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Min&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DOUBLE&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the minimum value for the axis of the bar. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Max&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DOUBLE&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 10&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the maximum value for the axis of the bar. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Bars FGColor&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;FGColor&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [8]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;000000&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the foreground colour  for this bar in the format RRGGBB (hex). See [[#Colour table|colour table]]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Bars BGColor&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;BGColor&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [8]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;FFFFFF&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the background colour  for this bar in the format RRGGBB (hex). See [[#Colour table|colour table]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;BDColor&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [8]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;808080&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the border colour  for this bar in the format RRGGBB (hex). See [[#Colour table|colour table]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Fills&amp;lt;/span&amp;gt; subtree ===&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#&amp;lt;Image-name&amp;gt; subtree|&amp;lt;image-name&amp;gt; subtree]] required if &#039;&#039;&#039;fills&#039;&#039;&#039; are to be superimposed on an image on a custom page.&lt;br /&gt;
A &amp;quot;fill&amp;quot; can change the colour of a region on the image. The contents of the ODB key defined in [[#Fills Src|Src]] determines the colour as defined by the Limits and Fillcolors arrays.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;fill-name&amp;gt;&amp;lt;/span&amp;gt; subtree ====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#Fills subtree|Fills subtree]] containing keys to define this fill as listed below. There will be a &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;fill-name&amp;gt;&amp;lt;/span&amp;gt; subtree for each fill superimposed on the custom image.&lt;br /&gt;
&lt;br /&gt;
The user creates keys in this subtree with the names and types as listed below. See also the [[#Example|example]] above.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Fills Src&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Src&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This key in the [[#&amp;lt;fill-name&amp;gt;subtree|&amp;lt;fill-name&amp;gt; subtree]] contains the path of a valid ODB Key variable. Unless a [[#logic_calculation|logic calculation]] is included,  the contents of this key determines the value used for the fill &lt;br /&gt;
on the image defined by the key [[#Background|Background]] (see fill-name &amp;quot;SSLevelBox&amp;quot; in the [[#Example|example]] above).&lt;br /&gt;
&amp;lt;div id=&amp;quot;logic_calculation&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
If a &#039;&#039;&#039;logic calculation&#039;&#039;&#039; is included, up to two operators are permitted, and they must be either&lt;br /&gt;
;&lt;br /&gt;
:    &amp;quot;&amp;gt;&amp;gt;&amp;quot; (shift to the right) or&lt;br /&gt;
:    &amp;quot;&amp;amp;&amp;quot; (bitwise AND).&lt;br /&gt;
&lt;br /&gt;
A hexadecimal number preceded by &amp;quot;0x&amp;quot; is also supported.&lt;br /&gt;
This feature enables a SRC key that is actually a bit pattern to be used for a fill.&lt;br /&gt;
&lt;br /&gt;
In the following example, a gas valve is open if bit 14 of PLCR[136] is TRUE and closed if bit 15 is TRUE (bits are from 0-15). The contents of PLCR[136] are shifted to the right by 14 and then a logical AND is performed to clear all but the lowest 2 bits. The result is used to colour the valve body lime green if the valve is open, and black if it is closed. If neither bit is set (i.e. the valve is neither open nor closed) the valve body is coloured red to indicate an error. Anything else (i.e. both bits TRUE) will give a gray colour.&lt;br /&gt;
&lt;br /&gt;
 [local:t2kgas:S]/&amp;gt;ls /custom/images/Pump_20.gif/fills/d2vb3&lt;br /&gt;
 Src                             /Equipment/TpcGasPlc/Variables/PLCR[136] &amp;gt;&amp;gt; 14 &amp;amp; 0x3&lt;br /&gt;
 X                               905&lt;br /&gt;
 Y                               536&lt;br /&gt;
 limits&lt;br /&gt;
                                0&lt;br /&gt;
                                1&lt;br /&gt;
                                2&lt;br /&gt;
                                3&lt;br /&gt;
 Fillcolors&lt;br /&gt;
                                808080&lt;br /&gt;
                                00FF00&lt;br /&gt;
                                000000&lt;br /&gt;
                                808080&lt;br /&gt;
                   &lt;br /&gt;
&lt;br /&gt;
Any fill that requires a more complicated calculation than this will have to be done using Javascript in the custom page. The calculated value can then be stored in an ODB key, which is then defined as a Fill [[#Fills Src|Src]] key.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Fills X&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;X&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;fill-name&amp;gt;subtree|&amp;lt;fill-name&amp;gt; subtree]] contains the X position for this fill in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Fills Y&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Y&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;fill-name&amp;gt;subtree|&amp;lt;fill-name&amp;gt; subtree]] contains the Y position for this fill in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Limits&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT array&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;fill-name&amp;gt;subtree|&amp;lt;fill-name&amp;gt; subtree]] is a variable-length array containing the values of the limits that when reached cause a colour change. Array length must match length of array &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Fillcolors&amp;lt;/span&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Fillcolors&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT array&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;fill-name&amp;gt;subtree|&amp;lt;fill-name&amp;gt; subtree]] is a variable-length array containing the colours corresponding to the [[#Limits|Limits]] array.  The colours are defined in the format RRGGBB (hex). See [[#Colour table|colour table]].  Array length must match length of &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Limits&amp;lt;/span&amp;gt; array.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Colour Table =&lt;br /&gt;
For convenience, a colour reference table is shown here for some common colours:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;  style=&amp;quot;margin: auto; ext-align: left; width: 25%; background-color: rgb(255, 255, 255);&amp;quot; border=&amp;quot;3&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: rgb(204, 204, 255); font-weight: bold;&amp;quot; | Colour&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: rgb(204, 204, 255); font-weight: bold;&amp;quot; | RGB Value&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; color: black; font-weight: normal;&amp;quot; | Black&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; color: black; font-weight: normal;&amp;quot; | 000000&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: silver; color: white; font-weight: normal;&amp;quot; | White&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: silver; color: white; font-weight: normal;&amp;quot; | FFFFFF&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: white; color: red; font-weight: normal;&amp;quot; | Red&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; color: black; font-weight: normal;&amp;quot; | FF0000&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: silver; color: lime; font-weight: normal;&amp;quot; | Lime green&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top;  background-color: silver; color: lime; font-weight: normal;&amp;quot; | 00FF00&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: white; color: blue; font-weight: normal;&amp;quot; | Blue&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; color: black; font-weight: normal;&amp;quot; | 0000FF&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: silver; color: yellow; font-weight: normal;&amp;quot; | Yellow&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: silver; color: yellow; font-weight: normal;&amp;quot; | FFFF00&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: white; color: grey; font-weight: normal;&amp;quot; | Grey&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; color: black; font-weight: normal;&amp;quot; | 808080&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:ODB Tree]] [[Category:Custom]]&lt;/div&gt;</summary>
		<author><name>Zaher</name></author>
	</entry>
	<entry>
		<id>https://daq00.triumf.ca/MidasWiki/index.php?title=/Custom_ODB_tree&amp;diff=3476</id>
		<title>/Custom ODB tree</title>
		<link rel="alternate" type="text/html" href="https://daq00.triumf.ca/MidasWiki/index.php?title=/Custom_ODB_tree&amp;diff=3476"/>
		<updated>2025-03-17T16:58:37Z</updated>

		<summary type="html">&lt;p&gt;Zaher: new feature&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Pagelinks}}&lt;br /&gt;
&lt;br /&gt;
= Links =&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* [[mhttpd |MIDAS web server (mhttpd)]] &lt;br /&gt;
* mhttpd [[Custom Page]]&lt;br /&gt;
* [[Custom Page Features]]&lt;br /&gt;
* mhttpd [[Status Page]]&lt;br /&gt;
* [[Mhttpd.js|MIDAS Javascript Library]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Purpose =&lt;br /&gt;
The {{Odbpath|path=/Custom}} ODB tree is required if the user wishes to create [[mhttpd]] custom pages. It contains essential data needed for [[mhttpd]] to display a custom page. The {{Odbpath|path=/images}} subtree is required if an imagefile (*.gif) is to be displayed on the custom page. Optionally, labels, bars and fills can be superimposed on the image.&lt;br /&gt;
&lt;br /&gt;
= Creating the &amp;lt;span style=&amp;quot;color:purple; font-style:italic;&amp;quot;&amp;gt;/Custom&amp;lt;/span&amp;gt;  tree =&lt;br /&gt;
The {{Odbpath|path=/Custom}} ODB tree is an optional tree that may be [[ODB#Creating ODB keys|created by the user]]. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Custom-Button&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div id=&amp;quot;Custom-Link&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
= Keys in the /Custom tree =&lt;br /&gt;
The optional ODB {{Odbpath|path=/Custom}} tree may contain any of the following :&lt;br /&gt;
&lt;br /&gt;
*  keys pointing to &#039;&#039;&#039;local&#039;&#039;&#039; external files containing custom web pages (html/javascript files)&lt;br /&gt;
*  keys pointing to &#039;&#039;&#039;local&#039;&#039;&#039; external files containing resources for custom web pages (e.g. .css style files, .js javascript file, images).&lt;br /&gt;
** Note: files that are have a &#039;.&#039; in the Key name are assumed to be resource files and are treated differently. See also the [[#Path key|Path key]] notes below.&lt;br /&gt;
** Note: .css, .js, .pdf, .jpg, .gif, .png, .svg, .ps, .eps, .xls, .doc, .txt, .asc, .zip files should get served up with the correct MIME types&lt;br /&gt;
*  keys containing the html code for [[Internal Custom Page#How to create an Internal Custom Page|internal custom webpages]] &lt;br /&gt;
*  &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Path&amp;lt;/span&amp;gt; variable, used to indicate where to look on host machine for external files.&lt;br /&gt;
*  &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/pwd&amp;lt;/span&amp;gt; subtree used to contain custom password keys&lt;br /&gt;
*  &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/images&amp;lt;/span&amp;gt; subtree used to specify images for custom pages&lt;br /&gt;
&lt;br /&gt;
Keys defined in this tree pointing to custom web pages of any kind are called &#039;&#039;&#039;&#039;&#039;custom-links&#039;&#039;&#039;&#039;&#039;.  &lt;br /&gt;
* External &#039;&#039;custom-links&#039;&#039; contain the path and filename of the external custom page file (or may be a symbolic link to a custom-link) &lt;br /&gt;
* Internal &#039;&#039;custom-links&#039;&#039; contain the code for an [[Internal Custom Page]]. &lt;br /&gt;
&lt;br /&gt;
If &#039;&#039;custom-links&#039;&#039; are defined in this tree, except where [[#Key names|noted below]], the &#039;&#039;custom-links&#039;&#039; will appear as &#039;&#039;&#039;&#039;&#039;custom-buttons&#039;&#039;&#039;&#039;&#039;  on the [[mhttpd]] [[Status Page]]. By clicking on one of these &#039;&#039;custom-buttons&#039;&#039;, the custom page will be visible in a new frame (see also [[#Key names|Key names]]). &lt;br /&gt;
&lt;br /&gt;
We will note some of the subtleties of how the Custom tree keys are used in the following sub-sections. &lt;br /&gt;
&lt;br /&gt;
== Key names ==&lt;br /&gt;
The user chooses the names of any keys in the &amp;lt;span style=&amp;quot;color:purple; font-style:italic;&amp;quot;&amp;gt;/Custom&amp;lt;/span&amp;gt; ODB tree except for&lt;br /&gt;
* the key name &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Status&amp;lt;/span&amp;gt; is reserved (see [[Custom Page#Custom Status page|Custom Status Page]]). &lt;br /&gt;
* the key name &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;pwd&amp;lt;/span&amp;gt; is reserved (see optional  [[#Pwd subtree|Pwd subtree]] for custom passwords)&lt;br /&gt;
* the key name &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Path&amp;lt;/span&amp;gt; is reserved (see optional  [[#Path key|Path key] for details)&lt;br /&gt;
* keys in the  &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/images&amp;lt;/span&amp;gt; subtree have defined names except for the user-defined [[#&amp;lt;Image-name&amp;gt; subtree|&amp;lt;Image-name&amp;gt; subtree]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There are two characters that have &#039;&#039;&#039;special meaning&#039;&#039;&#039; if they are the last character of a &#039;&#039;custom-link&#039;&#039; in the {{Odbpath|path=/Custom}} tree :&lt;br /&gt;
*    The character &amp;quot;&#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;&amp;quot; forces the page to be opened in a new tab/window when the &#039;&#039;custom-button&#039;&#039; is pressed. If this character is omitted, the page will be opened in the current frame. The &amp;quot;&amp;amp;&amp;quot; character is omitted from the name of the button.&lt;br /&gt;
*    The character &amp;quot;&#039;&#039;&#039;!&#039;&#039;&#039;&amp;quot; suppresses the &#039;&#039;custom-button&#039;&#039; from appearing on the [[Status Page]], forming a &#039;&#039;hidden-link&#039;&#039;.&lt;br /&gt;
*    If the value does not end with a file extention, e.g. .html, then no link is produced. Instead an &#039;&#039;onclick&#039;&#039; call is formed.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;hidden-link&#039;&#039; feature can be used to provide external webpages hidden from the user, such as a stylesheet or a file of Javascript functions needed by other custom pages.&lt;br /&gt;
&lt;br /&gt;
The {{Odbpath|path=/Custom}} tree in the [[#Example|example]] below would produce one &#039;&#039;custom-button&#039;&#039;, i.e.{{Button|name=ppg&amp;amp;nbsp;cycle}}.&lt;br /&gt;
&lt;br /&gt;
;NOTE&lt;br /&gt;
: To avoid confusion, do not use custom-links that only differ by the special characters &amp;quot;&amp;amp;&amp;quot; and &amp;quot;!&amp;quot; (e.g. &amp;quot;test&amp;quot;, &amp;quot;test&amp;amp;&amp;quot; and &amp;quot;test!&amp;quot;) in the same ODB.&lt;br /&gt;
&lt;br /&gt;
= Path key =&lt;br /&gt;
&lt;br /&gt;
When creating custom external web pages you will usually want to use other resource files, like CSS style sheets or images.  &lt;br /&gt;
&lt;br /&gt;
One way to do that is to specify each of the files that you need to use in the  {{Odbpath|path=/Custom}} tree.  For instance, suppose you had a HTML file called  {{File|name=control.html}} that used an image called  {{File|name=valve.png}}.  You could &lt;br /&gt;
&lt;br /&gt;
 Key name                        Type    #Val  Size  Last Opn Mode Value&lt;br /&gt;
 ---------------------------------------------------------------------------&lt;br /&gt;
 Control                         STRING  1     256   1h   0   RWD  /home/expt/online/custom/control.html&lt;br /&gt;
 valve.png!                      STRING  1     256   1h   0   RWD  /home/expt/online/custom/valve.png&lt;br /&gt;
&lt;br /&gt;
You would then be able to refer to that png normally in your HTML&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 &amp;lt;img src=&amp;quot;valve.png!&amp;quot;&amp;gt;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
This approach can get tedious however, if you have a large number of resource files to add.&lt;br /&gt;
&lt;br /&gt;
An alternative is given by the {{Odbpath|path=Path}} ODB key.  This key can be used to specify a directory on the server file system where files should be searched for.  So, for instance, if the {{Odbpath|path=/Custom}} tree is set to &lt;br /&gt;
&lt;br /&gt;
 Key name                        Type    #Val  Size  Last Opn Mode Value&lt;br /&gt;
 ---------------------------------------------------------------------------&lt;br /&gt;
 Path                            STRING  1     256   1h   0   RWD  /home/expt/online/custom/&lt;br /&gt;
 Control                         STRING  1     256   1h   0   RWD  control.html&lt;br /&gt;
&lt;br /&gt;
you can instruct  {{Utility|name=mhttpd}} to look in the directory  {{Filepath|path=/home/expt/online/custom/}} and then map the custom page &#039;Control&#039; to &lt;br /&gt;
 {{Filepath|path=/home/expt/online/custom/control.html}}.   &lt;br /&gt;
&lt;br /&gt;
One very important point: when the key {{Odbpath|path=/Custom/Path}} is defined, mhttpd will treat differently how it serves up resources, depending on whether there is a &#039;.&#039; in the resource web address.  So, for instance, for the custom page described above &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     https://myhost:8443/?cmd=custom&amp;amp;page=Control   &lt;br /&gt;
 or  http://myhost:8081/CS/Control   (very old MIDAS versions )&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
you will need to have a ODB key called  {{Odbpath|path=/Custom/Control}}, as described above.  &lt;br /&gt;
&lt;br /&gt;
However, if you have the ODB key  {{Odbpath|path=/Custom/Path}} and you access content like&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   https://myhost:8443/?cmd=custom&amp;amp;page=valve.png&lt;br /&gt;
or http://myhost:8081/CS/valve.png (very old MIDAS versions )&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
then  {{Utility|name=mhttpd}} will automatically figure out that it should use the file&lt;br /&gt;
&lt;br /&gt;
 Value of &amp;quot;/Custom/Path&amp;quot; + valve.png&lt;br /&gt;
 i.e. /home/expt/online/custom/valve.png&lt;br /&gt;
&lt;br /&gt;
So the benefit is that with the   {{Odbpath|path=/Custom/Path}} key set, you can just place all your resource files in the directory pointed to by /Custom/Path and mhttpd will find them, &#039;&#039;&#039;without needing to specify them individually &#039;&#039;&#039;  {{Odbpath|path=/Custom}} as custom-links.&lt;br /&gt;
&lt;br /&gt;
See also [[Custom Page Features#Resource files]] for more examples.&lt;br /&gt;
&lt;br /&gt;
= Example  =	&lt;br /&gt;
The following example using the [[odbedit]] &#039;&#039;&#039;ls&#039;&#039;&#039; command shows the optional custom tree for an experiment. &lt;br /&gt;
&amp;lt;br&amp;gt;Note the use of the &amp;quot;&amp;amp;&amp;quot; and &amp;quot;!&amp;quot; characters in the names of the custom keys  (see [[#Key names|key names]] for details).&lt;br /&gt;
 [local:pol:S]/ls -lr /Custom&lt;br /&gt;
 Key name                        Type    #Val  Size  Last Opn Mode Value&lt;br /&gt;
 ---------------------------------------------------------------------------&lt;br /&gt;
 custom                          DIR&lt;br /&gt;
    ppg_cycle&amp;amp;                  STRING  1    80    36h  0  RWD  /home/pol/online/pol/custom/pol_sc.html&lt;br /&gt;
    pol_functions!              STRING  1    80    36h  0  RWD  /home/pol/online/pol/custom/pol_functions.js&lt;br /&gt;
    style!                      STRING  1    80    36h  0  RWD  /home/pol/online/pol/custom/style.css&lt;br /&gt;
    images                      DIR&lt;br /&gt;
        pol_sc.gif              DIR&lt;br /&gt;
            background          STRING  1     80    36h  0   RWD  /home/pol/online/pol/custom/pol_sc.gif&lt;br /&gt;
            labels              DIR&lt;br /&gt;
                num bins        DIR&lt;br /&gt;
                    Src         STRING  1     256   36h  0   RWD  /Equipment/pol_acq/settings/output/num bins per cycle&lt;br /&gt;
                    Format      STRING  1     32    36h  0   RWD  %d&lt;br /&gt;
                    Font        STRING  1     32    36h  0   RWD  Medium&lt;br /&gt;
                    X           INT     1     4     36h  0   RWD  315&lt;br /&gt;
                    Y           INT     1     4     36h  0   RWD  502&lt;br /&gt;
                    Align       INT     1     4     36h  0   RWD  0&lt;br /&gt;
                    FGColor     STRING  1     8     36h  0   RWD  FFFFFF&lt;br /&gt;
                    BGColor     STRING  1     8     36h  0   RWD  0000FF&lt;br /&gt;
                dwell time      DIR&lt;br /&gt;
                    Src         STRING  1     256   36h  0   RWD  /Equipment/POL_ACQ/Settings/input/dwell time (ms)&lt;br /&gt;
                    Format      STRING  1     32    36h  0   RWD  %f ms&lt;br /&gt;
                    Font        STRING  1     32    36h  0   RWD  large&lt;br /&gt;
                    X           INT     1     4     36h  0   RWD  145&lt;br /&gt;
                    Y           INT     1     4     36h  0   RWD  430&lt;br /&gt;
                    Align       INT     1     4     36h  0   RWD  0&lt;br /&gt;
                    FGColor     STRING  1     8     36h  0   RWD  FFFFFF&lt;br /&gt;
                    BGColor     STRING  1     8     36h  0   RWD  0000FF&lt;br /&gt;
             fills              DIR&lt;br /&gt;
                    SSLevelBox  DIR&lt;br /&gt;
                    Src         STRING  1     256   36h  0   RWD  /Equipment/TpcGasPlc/GasCalc/Calculated[136]&lt;br /&gt;
                    X           INT     1     4     36h  0   RWD  578&lt;br /&gt;
                    Y           INT     1     4     36h  0   RWD  490&lt;br /&gt;
                    Limits      DOUBLE  3     8     2s   0   RWD&lt;br /&gt;
                                        [0]             0&lt;br /&gt;
                                        [1]             1&lt;br /&gt;
                                        [2]             2&lt;br /&gt;
                    Fillcolors  STRING  4     8     2s   0   RWD&lt;br /&gt;
                                        [0]             000000&lt;br /&gt;
                                        [1]             00FF00&lt;br /&gt;
                                        [2]             808080&lt;br /&gt;
             bars               DIR&lt;br /&gt;
                    temp        DIR&lt;br /&gt;
                    Src         STRING  1     256   36h  0   RWD  /Equipment/Temperature/Variables/Readback[5]&lt;br /&gt;
                    X           INT     1     4     36h  0   RWD  42&lt;br /&gt;
                    Y           INT     1     4     36h  0   RWD  68&lt;br /&gt;
                    Width       INT     1     4     36h  0   RWD  10&lt;br /&gt;
                    Height      INT     1     4     36h  0   RWD  50&lt;br /&gt;
                    Direction   INT     1     4     36h  0   RWD  0&lt;br /&gt;
                    Axis        INT     1     4     36h  0   RWD  1&lt;br /&gt;
                    Logscale    BOOL    1     4     &amp;gt;99d 0   RWD  n&lt;br /&gt;
                    Min         DOUBLE  1     8     &amp;gt;99d 0   RWD  0&lt;br /&gt;
                    Max         DOUBLE  1     8     &amp;gt;99d 0   RWD  0&lt;br /&gt;
                    FGcolor     STRING  1     8     2s   0   RWD  000000&lt;br /&gt;
                    BGcolor     STRING  1     8     2s   0   RWD  FFFFFF&lt;br /&gt;
                    BDcolor     STRING  1     8     2s   0   RWD  808080&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Pwd&amp;lt;/span&amp;gt; subtree=&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
This optional subtree in the  [[#top|/Custom ODB tree]] is created by the user if [[Custom Page]] write access is to be  [[Custom Page Features#Password protection of ODB variables|password protected]].&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;password&amp;gt;&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;  &amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
The &#039;&#039;&#039;name&#039;&#039;&#039; of the optional key(s) in the &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/Pwd&amp;lt;/span&amp;gt; subtree defines a password that the user must specify to gain access to a [[Custom Page Features#Password protection of ODB variables|password-protected]]&lt;br /&gt;
item on a [[Custom Page]]. &lt;br /&gt;
&lt;br /&gt;
=== Password examples ===&lt;br /&gt;
If the password is &#039;&#039;CustomPwd&#039;&#039;, the ODB key &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/Custom/Pwd/CustomPwd&amp;lt;/span&amp;gt; would be defined.&lt;br /&gt;
&lt;br /&gt;
By using an explicit name, one can use a single password for all controls on a page, or one could use several passwords on the same page. For example, a shift crew password for the less severe controls could be defined as &#039;&#039;ShiftPwd&#039;&#039;, and an &amp;quot;expert&amp;quot; password &#039;&#039;ExpertPwd&#039;&#039; for the critical things.&lt;br /&gt;
&lt;br /&gt;
In this case, the ODB would have two passwords defined, i.e.&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/Custom/Pwd/ExpertPwd&amp;lt;/span&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/Custom/Pwd/ShiftPwd&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The password is of course not secure in the sense that it is placed in plain text into the ODB, but its purpose is to prevent accidental modification, rather than malicious interference.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Images&amp;lt;/span&amp;gt; subtree =&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
This optional subtree in the  [[#top|/Custom ODB tree]] is created by the user. It is required if an imagefile (*.gif) is to be displayed on a custom page.&lt;br /&gt;
This subtree is also required for any &#039;&#039;&#039;labels, bars&#039;&#039;&#039; or &#039;&#039;&#039;fills&#039;&#039;&#039; to be superimposed on the image.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;Image-name&amp;gt;&amp;lt;/span&amp;gt; subtree ==&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory usually named for the corresponding gif-image, e.g. &amp;quot;pol_sc.gif&amp;quot; in the [[#Example|example]] above. For multiple images, multiple subdirectories may be defined. The user&lt;br /&gt;
chooses the name of this key.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Background&amp;lt;/span&amp;gt;  ===&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
This key in the  [[#&amp;lt;Image-name&amp;gt; subtree|&amp;lt;image-name&amp;gt; subtree]] contains the path and filename of the image file to be loaded into a custom page. Only &#039;&#039;&#039;gif&#039;&#039;&#039; format is supported for the image. This optional key is created by the user.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Labels&amp;lt;/span&amp;gt; subtree ===&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#&amp;lt;Image-name&amp;gt; subtree|&amp;lt;image-name&amp;gt; subtree]] required if &#039;&#039;&#039;labels&#039;&#039;&#039; are to be superimposed on an image on a custom page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;label-name&amp;gt;&amp;lt;/span&amp;gt; subtree ====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#Labels subtree|Labels subtree]] containing keys to define this label as listed below. There will be a &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;label-name&amp;gt;&amp;lt;/span&amp;gt; subtree for each label superimposed on the custom image.&lt;br /&gt;
&lt;br /&gt;
The user creates keys in this subtree with the names and types as listed below. See also the [[#Example|example]] above.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Labels Src&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Src&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [256]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the path of a valid ODB Key variable. This is the value to be used for this label on an image.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Format&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [32]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;%1.1f&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the format for this label on the image. Format specifications (c.f. &amp;quot;printf&amp;quot; in C) are used to convert the value specified by the [[#Labels Src|Src key]] into the output string that appears on the image. &lt;br /&gt;
For example, &lt;br /&gt;
* &amp;quot;Count Rate:%5d kB/s&amp;quot;  used to display an integer value&lt;br /&gt;
* &amp;quot;%5.2f%% iBu&amp;quot; used to display a floating point value. Note &amp;quot;%%&amp;quot; displays the &amp;quot;%&amp;quot; sign.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Font&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING[32]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;Medium&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the font size for this label. Supported values are &amp;quot;small&amp;quot;,  &amp;quot;medium&amp;quot; or &amp;quot;giant&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Labels X&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;X&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the X position for this label in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Labels Y&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Y&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the Y position for this label in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Align&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains an integer representing Horizontal Alignment for this label. Set to one of 0 (left), 1 (center) or 2 (right). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Labels FGColor&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;FGColor&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [8]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;000000&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the foreground colour  for this label in the format RRGGBB (hex). See [[#Colour table|colour table]]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Labels BGColor&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;BGColor&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [8]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;FFFFFF&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the background colour  for this label in the format RRGGBB (hex). See [[#Colour table|colour table]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Bars&amp;lt;/span&amp;gt; subtree ===&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#&amp;lt;Image-name&amp;gt; subtree|&amp;lt;image-name&amp;gt; subtree]] required if &#039;&#039;&#039;bars&#039;&#039;&#039; are to be superimposed on an image on a custom page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;bar-name&amp;gt;&amp;lt;/span&amp;gt; subtree ====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#Bars subtree|Fills subtree]] containing keys to define this &#039;&#039;&#039;bar&#039;&#039;&#039; as listed below. There will be a &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;bar-name&amp;gt;&amp;lt;/span&amp;gt; subtree for each bar superimposed on the custom image.&lt;br /&gt;
&lt;br /&gt;
The user creates keys in this subtree with the names and types as listed below. See also the [[#Example|example]] above.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Bars Src&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Src&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [256]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the path of a valid ODB Key variable. This is the value to be used for this bar. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Bars X&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;X&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the X position for this bar in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Bars Y&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Y&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the Y position for this bar in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Width&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 10&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the width of this bar in pixels.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Height&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 100&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the height of this bar in pixels.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Direction&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains an integer denoting the direction of this bar. It can be either 0 (vertical) or 1 (horizontal). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Axis&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 1&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains an integer specifying the axis of this bar. It can be either 0 (none), 1 (left) or 2 (right). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Logscale&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; BOOL&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;n&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] specifies whether the axis of this bar is logarithmic. Set to &amp;quot;y&amp;quot; for logarithmic, otherwise &amp;quot;n&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Min&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DOUBLE&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the minimum value for the axis of the bar. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Max&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DOUBLE&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 10&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the maximum value for the axis of the bar. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Bars FGColor&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;FGColor&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [8]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;000000&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the foreground colour  for this bar in the format RRGGBB (hex). See [[#Colour table|colour table]]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Bars BGColor&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;BGColor&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [8]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;FFFFFF&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the background colour  for this bar in the format RRGGBB (hex). See [[#Colour table|colour table]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;BDColor&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [8]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;808080&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the border colour  for this bar in the format RRGGBB (hex). See [[#Colour table|colour table]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Fills&amp;lt;/span&amp;gt; subtree ===&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#&amp;lt;Image-name&amp;gt; subtree|&amp;lt;image-name&amp;gt; subtree]] required if &#039;&#039;&#039;fills&#039;&#039;&#039; are to be superimposed on an image on a custom page.&lt;br /&gt;
A &amp;quot;fill&amp;quot; can change the colour of a region on the image. The contents of the ODB key defined in [[#Fills Src|Src]] determines the colour as defined by the Limits and Fillcolors arrays.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;fill-name&amp;gt;&amp;lt;/span&amp;gt; subtree ====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#Fills subtree|Fills subtree]] containing keys to define this fill as listed below. There will be a &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;fill-name&amp;gt;&amp;lt;/span&amp;gt; subtree for each fill superimposed on the custom image.&lt;br /&gt;
&lt;br /&gt;
The user creates keys in this subtree with the names and types as listed below. See also the [[#Example|example]] above.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Fills Src&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Src&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This key in the [[#&amp;lt;fill-name&amp;gt;subtree|&amp;lt;fill-name&amp;gt; subtree]] contains the path of a valid ODB Key variable. Unless a [[#logic_calculation|logic calculation]] is included,  the contents of this key determines the value used for the fill &lt;br /&gt;
on the image defined by the key [[#Background|Background]] (see fill-name &amp;quot;SSLevelBox&amp;quot; in the [[#Example|example]] above).&lt;br /&gt;
&amp;lt;div id=&amp;quot;logic_calculation&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
If a &#039;&#039;&#039;logic calculation&#039;&#039;&#039; is included, up to two operators are permitted, and they must be either&lt;br /&gt;
;&lt;br /&gt;
:    &amp;quot;&amp;gt;&amp;gt;&amp;quot; (shift to the right) or&lt;br /&gt;
:    &amp;quot;&amp;amp;&amp;quot; (bitwise AND).&lt;br /&gt;
&lt;br /&gt;
A hexadecimal number preceded by &amp;quot;0x&amp;quot; is also supported.&lt;br /&gt;
This feature enables a SRC key that is actually a bit pattern to be used for a fill.&lt;br /&gt;
&lt;br /&gt;
In the following example, a gas valve is open if bit 14 of PLCR[136] is TRUE and closed if bit 15 is TRUE (bits are from 0-15). The contents of PLCR[136] are shifted to the right by 14 and then a logical AND is performed to clear all but the lowest 2 bits. The result is used to colour the valve body lime green if the valve is open, and black if it is closed. If neither bit is set (i.e. the valve is neither open nor closed) the valve body is coloured red to indicate an error. Anything else (i.e. both bits TRUE) will give a gray colour.&lt;br /&gt;
&lt;br /&gt;
 [local:t2kgas:S]/&amp;gt;ls /custom/images/Pump_20.gif/fills/d2vb3&lt;br /&gt;
 Src                             /Equipment/TpcGasPlc/Variables/PLCR[136] &amp;gt;&amp;gt; 14 &amp;amp; 0x3&lt;br /&gt;
 X                               905&lt;br /&gt;
 Y                               536&lt;br /&gt;
 limits&lt;br /&gt;
                                0&lt;br /&gt;
                                1&lt;br /&gt;
                                2&lt;br /&gt;
                                3&lt;br /&gt;
 Fillcolors&lt;br /&gt;
                                808080&lt;br /&gt;
                                00FF00&lt;br /&gt;
                                000000&lt;br /&gt;
                                808080&lt;br /&gt;
                   &lt;br /&gt;
&lt;br /&gt;
Any fill that requires a more complicated calculation than this will have to be done using Javascript in the custom page. The calculated value can then be stored in an ODB key, which is then defined as a Fill [[#Fills Src|Src]] key.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Fills X&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;X&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;fill-name&amp;gt;subtree|&amp;lt;fill-name&amp;gt; subtree]] contains the X position for this fill in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Fills Y&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Y&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;fill-name&amp;gt;subtree|&amp;lt;fill-name&amp;gt; subtree]] contains the Y position for this fill in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Limits&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT array&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;fill-name&amp;gt;subtree|&amp;lt;fill-name&amp;gt; subtree]] is a variable-length array containing the values of the limits that when reached cause a colour change. Array length must match length of array &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Fillcolors&amp;lt;/span&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Fillcolors&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT array&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;fill-name&amp;gt;subtree|&amp;lt;fill-name&amp;gt; subtree]] is a variable-length array containing the colours corresponding to the [[#Limits|Limits]] array.  The colours are defined in the format RRGGBB (hex). See [[#Colour table|colour table]].  Array length must match length of &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Limits&amp;lt;/span&amp;gt; array.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Colour Table =&lt;br /&gt;
For convenience, a colour reference table is shown here for some common colours:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;  style=&amp;quot;margin: auto; ext-align: left; width: 25%; background-color: rgb(255, 255, 255);&amp;quot; border=&amp;quot;3&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: rgb(204, 204, 255); font-weight: bold;&amp;quot; | Colour&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: rgb(204, 204, 255); font-weight: bold;&amp;quot; | RGB Value&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; color: black; font-weight: normal;&amp;quot; | Black&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; color: black; font-weight: normal;&amp;quot; | 000000&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: silver; color: white; font-weight: normal;&amp;quot; | White&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: silver; color: white; font-weight: normal;&amp;quot; | FFFFFF&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: white; color: red; font-weight: normal;&amp;quot; | Red&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; color: black; font-weight: normal;&amp;quot; | FF0000&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: silver; color: lime; font-weight: normal;&amp;quot; | Lime green&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top;  background-color: silver; color: lime; font-weight: normal;&amp;quot; | 00FF00&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: white; color: blue; font-weight: normal;&amp;quot; | Blue&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; color: black; font-weight: normal;&amp;quot; | 0000FF&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: silver; color: yellow; font-weight: normal;&amp;quot; | Yellow&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: silver; color: yellow; font-weight: normal;&amp;quot; | FFFF00&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: white; color: grey; font-weight: normal;&amp;quot; | Grey&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; color: black; font-weight: normal;&amp;quot; | 808080&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:ODB Tree]] [[Category:Custom]]&lt;/div&gt;</summary>
		<author><name>Zaher</name></author>
	</entry>
	<entry>
		<id>https://daq00.triumf.ca/MidasWiki/index.php?title=/Alias_ODB_tree&amp;diff=3475</id>
		<title>/Alias ODB tree</title>
		<link rel="alternate" type="text/html" href="https://daq00.triumf.ca/MidasWiki/index.php?title=/Alias_ODB_tree&amp;diff=3475"/>
		<updated>2025-03-17T14:18:39Z</updated>

		<summary type="html">&lt;p&gt;Zaher: Wrong information, with &amp;amp; it opens in a new tab&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div style=&amp;quot;column-count:4;-moz-column-count:4;-webkit-column-count:4&amp;quot;&amp;gt;&lt;br /&gt;
* [[Midas_documentation|Midas Documentation]]&lt;br /&gt;
* [[Feature_listing|Feature Listing]]&lt;br /&gt;
* [[Application_listing|Application Listing]]&lt;br /&gt;
* [[Online_Database|Online Database]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
The ODB &amp;lt;span style=&amp;quot;color: purple; font-style:italic;&amp;quot;&amp;gt;/Alias&amp;lt;/span&amp;gt; tree  provides the user with a way to access other webpages via buttons placed on the [[mhttpd]] [[Status Page]]. It can provide links to external webpages, or symbolic links (short-cuts) to ODB sub-trees.&lt;br /&gt;
&lt;br /&gt;
== Creating the /Alias tree ==&lt;br /&gt;
The &amp;lt;span style=&amp;quot;color: purple; font-style:italic;&amp;quot;&amp;gt;/Alias&amp;lt;/span&amp;gt; tree is optional, and is not present until [[ODB#Creating ODB keys|created by the user]]. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Alias-Button&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
== Keys in the /Alias tree ==&lt;br /&gt;
Any key created under &amp;lt;span style=&amp;quot;color: purple; font-style:italic;&amp;quot;&amp;gt;/Alias&amp;lt;/span&amp;gt; will appear as a button (i.e. &#039;&#039;&#039;alias-button&#039;&#039;&#039;) on the [[Status Page]], with the same name as the key (except as noted below).&lt;br /&gt;
&lt;br /&gt;
By default, the clicking of an alias-button in the web interface will load the page in the same tab. To force the display of the alias page in a new tab, an &amp;quot;&amp;amp;&amp;quot; has to be appended to the name of the alias key. The &amp;quot;&amp;amp;&amp;quot; is stripped off the alias name and replaced with an arrow when it appears as an alias-button (see [[#Symbolic Links|example]]).&lt;br /&gt;
&lt;br /&gt;
=== External links ===&lt;br /&gt;
The following [[odbedit]] commands demonstrate how to make a link to an external webpage:&lt;br /&gt;
&lt;br /&gt;
 [local:t2kgas:S] cd /Alias&lt;br /&gt;
 [local:t2kgas:S]create string triumf&lt;br /&gt;
 String length [32]:&lt;br /&gt;
 [local:t2kgas:S] set triumf &amp;quot;http://triumf.ca&amp;quot;&lt;br /&gt;
&lt;br /&gt;
This will cause a button &amp;lt;span style=&amp;quot;color: #444444; background-color: #CCCCCC; font-style:italic; font-size: 90; padding:0.25em;&lt;br /&gt;
	padding-left: 0.5em;padding-right: 0.5em;border:1px solid #808080;border-radius: 5px;margin-bottom:1px;&amp;quot;&amp;gt;triumf&amp;lt;/span&amp;gt; &lt;br /&gt;
on the status page,  Clicking on this alias-button will show the contents of the link in a new frame.&lt;br /&gt;
&lt;br /&gt;
=== Links to ODB ===&lt;br /&gt;
The &amp;lt;span style=&amp;quot;color: purple; font-style:italic;&amp;quot;&amp;gt;/Alias&amp;lt;/span&amp;gt; tree may also contain a list of symbolic links to any desired ODB location.&lt;br /&gt;
&lt;br /&gt;
Create a string under /alias with this contents:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
?cmd=odb&amp;amp;odb_path=/Programs&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:ODB Tree]]&lt;/div&gt;</summary>
		<author><name>Zaher</name></author>
	</entry>
	<entry>
		<id>https://daq00.triumf.ca/MidasWiki/index.php?title=/Custom_ODB_tree&amp;diff=3474</id>
		<title>/Custom ODB tree</title>
		<link rel="alternate" type="text/html" href="https://daq00.triumf.ca/MidasWiki/index.php?title=/Custom_ODB_tree&amp;diff=3474"/>
		<updated>2025-03-17T14:06:23Z</updated>

		<summary type="html">&lt;p&gt;Zaher: Wrong information, with &amp;amp; it opens in a new tab&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Pagelinks}}&lt;br /&gt;
&lt;br /&gt;
= Links =&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* [[mhttpd |MIDAS web server (mhttpd)]] &lt;br /&gt;
* mhttpd [[Custom Page]]&lt;br /&gt;
* [[Custom Page Features]]&lt;br /&gt;
* mhttpd [[Status Page]]&lt;br /&gt;
* [[Mhttpd.js|MIDAS Javascript Library]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Purpose =&lt;br /&gt;
The {{Odbpath|path=/Custom}} ODB tree is required if the user wishes to create [[mhttpd]] custom pages. It contains essential data needed for [[mhttpd]] to display a custom page. The {{Odbpath|path=/images}} subtree is required if an imagefile (*.gif) is to be displayed on the custom page. Optionally, labels, bars and fills can be superimposed on the image.&lt;br /&gt;
&lt;br /&gt;
= Creating the &amp;lt;span style=&amp;quot;color:purple; font-style:italic;&amp;quot;&amp;gt;/Custom&amp;lt;/span&amp;gt;  tree =&lt;br /&gt;
The {{Odbpath|path=/Custom}} ODB tree is an optional tree that may be [[ODB#Creating ODB keys|created by the user]]. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Custom-Button&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div id=&amp;quot;Custom-Link&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
= Keys in the /Custom tree =&lt;br /&gt;
The optional ODB {{Odbpath|path=/Custom}} tree may contain any of the following :&lt;br /&gt;
&lt;br /&gt;
*  keys pointing to &#039;&#039;&#039;local&#039;&#039;&#039; external files containing custom web pages (html/javascript files)&lt;br /&gt;
*  keys pointing to &#039;&#039;&#039;local&#039;&#039;&#039; external files containing resources for custom web pages (e.g. .css style files, .js javascript file, images).&lt;br /&gt;
** Note: files that are have a &#039;.&#039; in the Key name are assumed to be resource files and are treated differently. See also the [[#Path key|Path key]] notes below.&lt;br /&gt;
** Note: .css, .js, .pdf, .jpg, .gif, .png, .svg, .ps, .eps, .xls, .doc, .txt, .asc, .zip files should get served up with the correct MIME types&lt;br /&gt;
*  keys containing the html code for [[Internal Custom Page#How to create an Internal Custom Page|internal custom webpages]] &lt;br /&gt;
*  &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Path&amp;lt;/span&amp;gt; variable, used to indicate where to look on host machine for external files.&lt;br /&gt;
*  &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/pwd&amp;lt;/span&amp;gt; subtree used to contain custom password keys&lt;br /&gt;
*  &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/images&amp;lt;/span&amp;gt; subtree used to specify images for custom pages&lt;br /&gt;
&lt;br /&gt;
Keys defined in this tree pointing to custom web pages of any kind are called &#039;&#039;&#039;&#039;&#039;custom-links&#039;&#039;&#039;&#039;&#039;.  &lt;br /&gt;
* External &#039;&#039;custom-links&#039;&#039; contain the path and filename of the external custom page file (or may be a symbolic link to a custom-link) &lt;br /&gt;
* Internal &#039;&#039;custom-links&#039;&#039; contain the code for an [[Internal Custom Page]]. &lt;br /&gt;
&lt;br /&gt;
If &#039;&#039;custom-links&#039;&#039; are defined in this tree, except where [[#Key names|noted below]], the &#039;&#039;custom-links&#039;&#039; will appear as &#039;&#039;&#039;&#039;&#039;custom-buttons&#039;&#039;&#039;&#039;&#039;  on the [[mhttpd]] [[Status Page]]. By clicking on one of these &#039;&#039;custom-buttons&#039;&#039;, the custom page will be visible in a new frame (see also [[#Key names|Key names]]). &lt;br /&gt;
&lt;br /&gt;
We will note some of the subtleties of how the Custom tree keys are used in the following sub-sections. &lt;br /&gt;
&lt;br /&gt;
== Key names ==&lt;br /&gt;
The user chooses the names of any keys in the &amp;lt;span style=&amp;quot;color:purple; font-style:italic;&amp;quot;&amp;gt;/Custom&amp;lt;/span&amp;gt; ODB tree except for&lt;br /&gt;
* the key name &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Status&amp;lt;/span&amp;gt; is reserved (see [[Custom Page#Custom Status page|Custom Status Page]]). &lt;br /&gt;
* the key name &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;pwd&amp;lt;/span&amp;gt; is reserved (see optional  [[#Pwd subtree|Pwd subtree]] for custom passwords)&lt;br /&gt;
* the key name &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Path&amp;lt;/span&amp;gt; is reserved (see optional  [[#Path key|Path key] for details)&lt;br /&gt;
* keys in the  &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/images&amp;lt;/span&amp;gt; subtree have defined names except for the user-defined [[#&amp;lt;Image-name&amp;gt; subtree|&amp;lt;Image-name&amp;gt; subtree]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There are two characters that have &#039;&#039;&#039;special meaning&#039;&#039;&#039; if they are the last character of a &#039;&#039;custom-link&#039;&#039; in the {{Odbpath|path=/Custom}} tree :&lt;br /&gt;
*    The character &amp;quot;&#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;&amp;quot; forces the page to be opened in a new tab/window when the &#039;&#039;custom-button&#039;&#039; is pressed. If this character is omitted, the page will be opened in the current frame. The &amp;quot;&amp;amp;&amp;quot; character is omitted from the name of the button.&lt;br /&gt;
*    The character &amp;quot;&#039;&#039;&#039;!&#039;&#039;&#039;&amp;quot; suppresses the &#039;&#039;custom-button&#039;&#039; from appearing on the [[Status Page]], forming a &#039;&#039;hidden-link&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;hidden-link&#039;&#039; feature can be used to provide external webpages hidden from the user, such as a stylesheet or a file of Javascript functions needed by other custom pages.&lt;br /&gt;
&lt;br /&gt;
The {{Odbpath|path=/Custom}} tree in the [[#Example|example]] below would produce one &#039;&#039;custom-button&#039;&#039;, i.e.{{Button|name=ppg&amp;amp;nbsp;cycle}}.&lt;br /&gt;
&lt;br /&gt;
;NOTE&lt;br /&gt;
: To avoid confusion, do not use custom-links that only differ by the special characters &amp;quot;&amp;amp;&amp;quot; and &amp;quot;!&amp;quot; (e.g. &amp;quot;test&amp;quot;, &amp;quot;test&amp;amp;&amp;quot; and &amp;quot;test!&amp;quot;) in the same ODB.&lt;br /&gt;
&lt;br /&gt;
= Path key =&lt;br /&gt;
&lt;br /&gt;
When creating custom external web pages you will usually want to use other resource files, like CSS style sheets or images.  &lt;br /&gt;
&lt;br /&gt;
One way to do that is to specify each of the files that you need to use in the  {{Odbpath|path=/Custom}} tree.  For instance, suppose you had a HTML file called  {{File|name=control.html}} that used an image called  {{File|name=valve.png}}.  You could &lt;br /&gt;
&lt;br /&gt;
 Key name                        Type    #Val  Size  Last Opn Mode Value&lt;br /&gt;
 ---------------------------------------------------------------------------&lt;br /&gt;
 Control                         STRING  1     256   1h   0   RWD  /home/expt/online/custom/control.html&lt;br /&gt;
 valve.png!                      STRING  1     256   1h   0   RWD  /home/expt/online/custom/valve.png&lt;br /&gt;
&lt;br /&gt;
You would then be able to refer to that png normally in your HTML&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 &amp;lt;img src=&amp;quot;valve.png!&amp;quot;&amp;gt;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
This approach can get tedious however, if you have a large number of resource files to add.&lt;br /&gt;
&lt;br /&gt;
An alternative is given by the {{Odbpath|path=Path}} ODB key.  This key can be used to specify a directory on the server file system where files should be searched for.  So, for instance, if the {{Odbpath|path=/Custom}} tree is set to &lt;br /&gt;
&lt;br /&gt;
 Key name                        Type    #Val  Size  Last Opn Mode Value&lt;br /&gt;
 ---------------------------------------------------------------------------&lt;br /&gt;
 Path                            STRING  1     256   1h   0   RWD  /home/expt/online/custom/&lt;br /&gt;
 Control                         STRING  1     256   1h   0   RWD  control.html&lt;br /&gt;
&lt;br /&gt;
you can instruct  {{Utility|name=mhttpd}} to look in the directory  {{Filepath|path=/home/expt/online/custom/}} and then map the custom page &#039;Control&#039; to &lt;br /&gt;
 {{Filepath|path=/home/expt/online/custom/control.html}}.   &lt;br /&gt;
&lt;br /&gt;
One very important point: when the key {{Odbpath|path=/Custom/Path}} is defined, mhttpd will treat differently how it serves up resources, depending on whether there is a &#039;.&#039; in the resource web address.  So, for instance, for the custom page described above &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     https://myhost:8443/?cmd=custom&amp;amp;page=Control   &lt;br /&gt;
 or  http://myhost:8081/CS/Control   (very old MIDAS versions )&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
you will need to have a ODB key called  {{Odbpath|path=/Custom/Control}}, as described above.  &lt;br /&gt;
&lt;br /&gt;
However, if you have the ODB key  {{Odbpath|path=/Custom/Path}} and you access content like&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   https://myhost:8443/?cmd=custom&amp;amp;page=valve.png&lt;br /&gt;
or http://myhost:8081/CS/valve.png (very old MIDAS versions )&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
then  {{Utility|name=mhttpd}} will automatically figure out that it should use the file&lt;br /&gt;
&lt;br /&gt;
 Value of &amp;quot;/Custom/Path&amp;quot; + valve.png&lt;br /&gt;
 i.e. /home/expt/online/custom/valve.png&lt;br /&gt;
&lt;br /&gt;
So the benefit is that with the   {{Odbpath|path=/Custom/Path}} key set, you can just place all your resource files in the directory pointed to by /Custom/Path and mhttpd will find them, &#039;&#039;&#039;without needing to specify them individually &#039;&#039;&#039;  {{Odbpath|path=/Custom}} as custom-links.&lt;br /&gt;
&lt;br /&gt;
See also [[Custom Page Features#Resource files]] for more examples.&lt;br /&gt;
&lt;br /&gt;
= Example  =	&lt;br /&gt;
The following example using the [[odbedit]] &#039;&#039;&#039;ls&#039;&#039;&#039; command shows the optional custom tree for an experiment. &lt;br /&gt;
&amp;lt;br&amp;gt;Note the use of the &amp;quot;&amp;amp;&amp;quot; and &amp;quot;!&amp;quot; characters in the names of the custom keys  (see [[#Key names|key names]] for details).&lt;br /&gt;
 [local:pol:S]/ls -lr /Custom&lt;br /&gt;
 Key name                        Type    #Val  Size  Last Opn Mode Value&lt;br /&gt;
 ---------------------------------------------------------------------------&lt;br /&gt;
 custom                          DIR&lt;br /&gt;
    ppg_cycle&amp;amp;                  STRING  1    80    36h  0  RWD  /home/pol/online/pol/custom/pol_sc.html&lt;br /&gt;
    pol_functions!              STRING  1    80    36h  0  RWD  /home/pol/online/pol/custom/pol_functions.js&lt;br /&gt;
    style!                      STRING  1    80    36h  0  RWD  /home/pol/online/pol/custom/style.css&lt;br /&gt;
    images                      DIR&lt;br /&gt;
        pol_sc.gif              DIR&lt;br /&gt;
            background          STRING  1     80    36h  0   RWD  /home/pol/online/pol/custom/pol_sc.gif&lt;br /&gt;
            labels              DIR&lt;br /&gt;
                num bins        DIR&lt;br /&gt;
                    Src         STRING  1     256   36h  0   RWD  /Equipment/pol_acq/settings/output/num bins per cycle&lt;br /&gt;
                    Format      STRING  1     32    36h  0   RWD  %d&lt;br /&gt;
                    Font        STRING  1     32    36h  0   RWD  Medium&lt;br /&gt;
                    X           INT     1     4     36h  0   RWD  315&lt;br /&gt;
                    Y           INT     1     4     36h  0   RWD  502&lt;br /&gt;
                    Align       INT     1     4     36h  0   RWD  0&lt;br /&gt;
                    FGColor     STRING  1     8     36h  0   RWD  FFFFFF&lt;br /&gt;
                    BGColor     STRING  1     8     36h  0   RWD  0000FF&lt;br /&gt;
                dwell time      DIR&lt;br /&gt;
                    Src         STRING  1     256   36h  0   RWD  /Equipment/POL_ACQ/Settings/input/dwell time (ms)&lt;br /&gt;
                    Format      STRING  1     32    36h  0   RWD  %f ms&lt;br /&gt;
                    Font        STRING  1     32    36h  0   RWD  large&lt;br /&gt;
                    X           INT     1     4     36h  0   RWD  145&lt;br /&gt;
                    Y           INT     1     4     36h  0   RWD  430&lt;br /&gt;
                    Align       INT     1     4     36h  0   RWD  0&lt;br /&gt;
                    FGColor     STRING  1     8     36h  0   RWD  FFFFFF&lt;br /&gt;
                    BGColor     STRING  1     8     36h  0   RWD  0000FF&lt;br /&gt;
             fills              DIR&lt;br /&gt;
                    SSLevelBox  DIR&lt;br /&gt;
                    Src         STRING  1     256   36h  0   RWD  /Equipment/TpcGasPlc/GasCalc/Calculated[136]&lt;br /&gt;
                    X           INT     1     4     36h  0   RWD  578&lt;br /&gt;
                    Y           INT     1     4     36h  0   RWD  490&lt;br /&gt;
                    Limits      DOUBLE  3     8     2s   0   RWD&lt;br /&gt;
                                        [0]             0&lt;br /&gt;
                                        [1]             1&lt;br /&gt;
                                        [2]             2&lt;br /&gt;
                    Fillcolors  STRING  4     8     2s   0   RWD&lt;br /&gt;
                                        [0]             000000&lt;br /&gt;
                                        [1]             00FF00&lt;br /&gt;
                                        [2]             808080&lt;br /&gt;
             bars               DIR&lt;br /&gt;
                    temp        DIR&lt;br /&gt;
                    Src         STRING  1     256   36h  0   RWD  /Equipment/Temperature/Variables/Readback[5]&lt;br /&gt;
                    X           INT     1     4     36h  0   RWD  42&lt;br /&gt;
                    Y           INT     1     4     36h  0   RWD  68&lt;br /&gt;
                    Width       INT     1     4     36h  0   RWD  10&lt;br /&gt;
                    Height      INT     1     4     36h  0   RWD  50&lt;br /&gt;
                    Direction   INT     1     4     36h  0   RWD  0&lt;br /&gt;
                    Axis        INT     1     4     36h  0   RWD  1&lt;br /&gt;
                    Logscale    BOOL    1     4     &amp;gt;99d 0   RWD  n&lt;br /&gt;
                    Min         DOUBLE  1     8     &amp;gt;99d 0   RWD  0&lt;br /&gt;
                    Max         DOUBLE  1     8     &amp;gt;99d 0   RWD  0&lt;br /&gt;
                    FGcolor     STRING  1     8     2s   0   RWD  000000&lt;br /&gt;
                    BGcolor     STRING  1     8     2s   0   RWD  FFFFFF&lt;br /&gt;
                    BDcolor     STRING  1     8     2s   0   RWD  808080&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Pwd&amp;lt;/span&amp;gt; subtree=&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
This optional subtree in the  [[#top|/Custom ODB tree]] is created by the user if [[Custom Page]] write access is to be  [[Custom Page Features#Password protection of ODB variables|password protected]].&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;password&amp;gt;&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;  &amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
The &#039;&#039;&#039;name&#039;&#039;&#039; of the optional key(s) in the &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/Pwd&amp;lt;/span&amp;gt; subtree defines a password that the user must specify to gain access to a [[Custom Page Features#Password protection of ODB variables|password-protected]]&lt;br /&gt;
item on a [[Custom Page]]. &lt;br /&gt;
&lt;br /&gt;
=== Password examples ===&lt;br /&gt;
If the password is &#039;&#039;CustomPwd&#039;&#039;, the ODB key &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/Custom/Pwd/CustomPwd&amp;lt;/span&amp;gt; would be defined.&lt;br /&gt;
&lt;br /&gt;
By using an explicit name, one can use a single password for all controls on a page, or one could use several passwords on the same page. For example, a shift crew password for the less severe controls could be defined as &#039;&#039;ShiftPwd&#039;&#039;, and an &amp;quot;expert&amp;quot; password &#039;&#039;ExpertPwd&#039;&#039; for the critical things.&lt;br /&gt;
&lt;br /&gt;
In this case, the ODB would have two passwords defined, i.e.&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/Custom/Pwd/ExpertPwd&amp;lt;/span&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;/Custom/Pwd/ShiftPwd&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The password is of course not secure in the sense that it is placed in plain text into the ODB, but its purpose is to prevent accidental modification, rather than malicious interference.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Images&amp;lt;/span&amp;gt; subtree =&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
This optional subtree in the  [[#top|/Custom ODB tree]] is created by the user. It is required if an imagefile (*.gif) is to be displayed on a custom page.&lt;br /&gt;
This subtree is also required for any &#039;&#039;&#039;labels, bars&#039;&#039;&#039; or &#039;&#039;&#039;fills&#039;&#039;&#039; to be superimposed on the image.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;Image-name&amp;gt;&amp;lt;/span&amp;gt; subtree ==&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory usually named for the corresponding gif-image, e.g. &amp;quot;pol_sc.gif&amp;quot; in the [[#Example|example]] above. For multiple images, multiple subdirectories may be defined. The user&lt;br /&gt;
chooses the name of this key.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Background&amp;lt;/span&amp;gt;  ===&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
This key in the  [[#&amp;lt;Image-name&amp;gt; subtree|&amp;lt;image-name&amp;gt; subtree]] contains the path and filename of the image file to be loaded into a custom page. Only &#039;&#039;&#039;gif&#039;&#039;&#039; format is supported for the image. This optional key is created by the user.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Labels&amp;lt;/span&amp;gt; subtree ===&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#&amp;lt;Image-name&amp;gt; subtree|&amp;lt;image-name&amp;gt; subtree]] required if &#039;&#039;&#039;labels&#039;&#039;&#039; are to be superimposed on an image on a custom page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;label-name&amp;gt;&amp;lt;/span&amp;gt; subtree ====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#Labels subtree|Labels subtree]] containing keys to define this label as listed below. There will be a &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;label-name&amp;gt;&amp;lt;/span&amp;gt; subtree for each label superimposed on the custom image.&lt;br /&gt;
&lt;br /&gt;
The user creates keys in this subtree with the names and types as listed below. See also the [[#Example|example]] above.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Labels Src&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Src&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [256]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the path of a valid ODB Key variable. This is the value to be used for this label on an image.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Format&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [32]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;%1.1f&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the format for this label on the image. Format specifications (c.f. &amp;quot;printf&amp;quot; in C) are used to convert the value specified by the [[#Labels Src|Src key]] into the output string that appears on the image. &lt;br /&gt;
For example, &lt;br /&gt;
* &amp;quot;Count Rate:%5d kB/s&amp;quot;  used to display an integer value&lt;br /&gt;
* &amp;quot;%5.2f%% iBu&amp;quot; used to display a floating point value. Note &amp;quot;%%&amp;quot; displays the &amp;quot;%&amp;quot; sign.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Font&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING[32]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;Medium&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the font size for this label. Supported values are &amp;quot;small&amp;quot;,  &amp;quot;medium&amp;quot; or &amp;quot;giant&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Labels X&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;X&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the X position for this label in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Labels Y&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Y&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the Y position for this label in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Align&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains an integer representing Horizontal Alignment for this label. Set to one of 0 (left), 1 (center) or 2 (right). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Labels FGColor&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;FGColor&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [8]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;000000&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the foreground colour  for this label in the format RRGGBB (hex). See [[#Colour table|colour table]]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Labels BGColor&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;BGColor&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [8]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;FFFFFF&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;label-name&amp;gt;subtree|&amp;lt;label-name&amp;gt; subtree]] contains the background colour  for this label in the format RRGGBB (hex). See [[#Colour table|colour table]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Bars&amp;lt;/span&amp;gt; subtree ===&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#&amp;lt;Image-name&amp;gt; subtree|&amp;lt;image-name&amp;gt; subtree]] required if &#039;&#039;&#039;bars&#039;&#039;&#039; are to be superimposed on an image on a custom page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;bar-name&amp;gt;&amp;lt;/span&amp;gt; subtree ====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#Bars subtree|Fills subtree]] containing keys to define this &#039;&#039;&#039;bar&#039;&#039;&#039; as listed below. There will be a &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;bar-name&amp;gt;&amp;lt;/span&amp;gt; subtree for each bar superimposed on the custom image.&lt;br /&gt;
&lt;br /&gt;
The user creates keys in this subtree with the names and types as listed below. See also the [[#Example|example]] above.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Bars Src&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Src&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [256]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the path of a valid ODB Key variable. This is the value to be used for this bar. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Bars X&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;X&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the X position for this bar in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Bars Y&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Y&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the Y position for this bar in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Width&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 10&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the width of this bar in pixels.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Height&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 100&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the height of this bar in pixels.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Direction&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains an integer denoting the direction of this bar. It can be either 0 (vertical) or 1 (horizontal). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Axis&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 1&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains an integer specifying the axis of this bar. It can be either 0 (none), 1 (left) or 2 (right). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Logscale&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; BOOL&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;n&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] specifies whether the axis of this bar is logarithmic. Set to &amp;quot;y&amp;quot; for logarithmic, otherwise &amp;quot;n&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Min&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DOUBLE&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 0&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the minimum value for the axis of the bar. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Max&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DOUBLE&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; 10&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the maximum value for the axis of the bar. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Bars FGColor&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;FGColor&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [8]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;000000&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the foreground colour  for this bar in the format RRGGBB (hex). See [[#Colour table|colour table]]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Bars BGColor&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;BGColor&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [8]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;FFFFFF&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the background colour  for this bar in the format RRGGBB (hex). See [[#Colour table|colour table]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;BDColor&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING [8]&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039; &amp;quot;808080&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;bar-name&amp;gt;subtree|&amp;lt;bar-name&amp;gt; subtree]] contains the border colour  for this bar in the format RRGGBB (hex). See [[#Colour table|colour table]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Fills&amp;lt;/span&amp;gt; subtree ===&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#&amp;lt;Image-name&amp;gt; subtree|&amp;lt;image-name&amp;gt; subtree]] required if &#039;&#039;&#039;fills&#039;&#039;&#039; are to be superimposed on an image on a custom page.&lt;br /&gt;
A &amp;quot;fill&amp;quot; can change the colour of a region on the image. The contents of the ODB key defined in [[#Fills Src|Src]] determines the colour as defined by the Limits and Fillcolors arrays.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;fill-name&amp;gt;&amp;lt;/span&amp;gt; subtree ====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; DIR&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
User-created subdirectory  in the  [[#Fills subtree|Fills subtree]] containing keys to define this fill as listed below. There will be a &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;&amp;lt;fill-name&amp;gt;&amp;lt;/span&amp;gt; subtree for each fill superimposed on the custom image.&lt;br /&gt;
&lt;br /&gt;
The user creates keys in this subtree with the names and types as listed below. See also the [[#Example|example]] above.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Fills Src&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Src&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; STRING&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This key in the [[#&amp;lt;fill-name&amp;gt;subtree|&amp;lt;fill-name&amp;gt; subtree]] contains the path of a valid ODB Key variable. Unless a [[#logic_calculation|logic calculation]] is included,  the contents of this key determines the value used for the fill &lt;br /&gt;
on the image defined by the key [[#Background|Background]] (see fill-name &amp;quot;SSLevelBox&amp;quot; in the [[#Example|example]] above).&lt;br /&gt;
&amp;lt;div id=&amp;quot;logic_calculation&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
If a &#039;&#039;&#039;logic calculation&#039;&#039;&#039; is included, up to two operators are permitted, and they must be either&lt;br /&gt;
;&lt;br /&gt;
:    &amp;quot;&amp;gt;&amp;gt;&amp;quot; (shift to the right) or&lt;br /&gt;
:    &amp;quot;&amp;amp;&amp;quot; (bitwise AND).&lt;br /&gt;
&lt;br /&gt;
A hexadecimal number preceded by &amp;quot;0x&amp;quot; is also supported.&lt;br /&gt;
This feature enables a SRC key that is actually a bit pattern to be used for a fill.&lt;br /&gt;
&lt;br /&gt;
In the following example, a gas valve is open if bit 14 of PLCR[136] is TRUE and closed if bit 15 is TRUE (bits are from 0-15). The contents of PLCR[136] are shifted to the right by 14 and then a logical AND is performed to clear all but the lowest 2 bits. The result is used to colour the valve body lime green if the valve is open, and black if it is closed. If neither bit is set (i.e. the valve is neither open nor closed) the valve body is coloured red to indicate an error. Anything else (i.e. both bits TRUE) will give a gray colour.&lt;br /&gt;
&lt;br /&gt;
 [local:t2kgas:S]/&amp;gt;ls /custom/images/Pump_20.gif/fills/d2vb3&lt;br /&gt;
 Src                             /Equipment/TpcGasPlc/Variables/PLCR[136] &amp;gt;&amp;gt; 14 &amp;amp; 0x3&lt;br /&gt;
 X                               905&lt;br /&gt;
 Y                               536&lt;br /&gt;
 limits&lt;br /&gt;
                                0&lt;br /&gt;
                                1&lt;br /&gt;
                                2&lt;br /&gt;
                                3&lt;br /&gt;
 Fillcolors&lt;br /&gt;
                                808080&lt;br /&gt;
                                00FF00&lt;br /&gt;
                                000000&lt;br /&gt;
                                808080&lt;br /&gt;
                   &lt;br /&gt;
&lt;br /&gt;
Any fill that requires a more complicated calculation than this will have to be done using Javascript in the custom page. The calculated value can then be stored in an ODB key, which is then defined as a Fill [[#Fills Src|Src]] key.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Fills X&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;X&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;fill-name&amp;gt;subtree|&amp;lt;fill-name&amp;gt; subtree]] contains the X position for this fill in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Fills Y&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Y&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;fill-name&amp;gt;subtree|&amp;lt;fill-name&amp;gt; subtree]] contains the Y position for this fill in pixels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Limits&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT array&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;fill-name&amp;gt;subtree|&amp;lt;fill-name&amp;gt; subtree]] is a variable-length array containing the values of the limits that when reached cause a colour change. Array length must match length of array &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Fillcolors&amp;lt;/span&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Fillcolors&amp;lt;/span&amp;gt; =====&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Type:&#039;&#039;&#039; INT array&lt;br /&gt;
* &#039;&#039;&#039;Default:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
This key in the [[#&amp;lt;fill-name&amp;gt;subtree|&amp;lt;fill-name&amp;gt; subtree]] is a variable-length array containing the colours corresponding to the [[#Limits|Limits]] array.  The colours are defined in the format RRGGBB (hex). See [[#Colour table|colour table]].  Array length must match length of &amp;lt;span style=&amp;quot;color:purple; font-style:italic&amp;quot;&amp;gt;Limits&amp;lt;/span&amp;gt; array.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
---------&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Colour Table =&lt;br /&gt;
For convenience, a colour reference table is shown here for some common colours:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;  style=&amp;quot;margin: auto; ext-align: left; width: 25%; background-color: rgb(255, 255, 255);&amp;quot; border=&amp;quot;3&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: rgb(204, 204, 255); font-weight: bold;&amp;quot; | Colour&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: rgb(204, 204, 255); font-weight: bold;&amp;quot; | RGB Value&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; color: black; font-weight: normal;&amp;quot; | Black&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; color: black; font-weight: normal;&amp;quot; | 000000&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: silver; color: white; font-weight: normal;&amp;quot; | White&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: silver; color: white; font-weight: normal;&amp;quot; | FFFFFF&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: white; color: red; font-weight: normal;&amp;quot; | Red&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; color: black; font-weight: normal;&amp;quot; | FF0000&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: silver; color: lime; font-weight: normal;&amp;quot; | Lime green&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top;  background-color: silver; color: lime; font-weight: normal;&amp;quot; | 00FF00&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: white; color: blue; font-weight: normal;&amp;quot; | Blue&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; color: black; font-weight: normal;&amp;quot; | 0000FF&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: silver; color: yellow; font-weight: normal;&amp;quot; | Yellow&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: silver; color: yellow; font-weight: normal;&amp;quot; | FFFF00&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; background-color: white; color: grey; font-weight: normal;&amp;quot; | Grey&lt;br /&gt;
| colspan=&amp;quot;1&amp;quot; rowspan=&amp;quot;1&amp;quot; style=&amp;quot;vertical-align: top; color: black; font-weight: normal;&amp;quot; | 808080&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:ODB Tree]] [[Category:Custom]]&lt;/div&gt;</summary>
		<author><name>Zaher</name></author>
	</entry>
	<entry>
		<id>https://daq00.triumf.ca/MidasWiki/index.php?title=Custom_Page&amp;diff=3473</id>
		<title>Custom Page</title>
		<link rel="alternate" type="text/html" href="https://daq00.triumf.ca/MidasWiki/index.php?title=Custom_Page&amp;diff=3473"/>
		<updated>2025-03-17T14:03:46Z</updated>

		<summary type="html">&lt;p&gt;Zaher: Wrong information, with &amp;amp; it opens in a new tab&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Pagelinks}}&lt;br /&gt;
&lt;br /&gt;
= Links =&lt;br /&gt;
{{mhttpdpages3|[[Custom Page Features]]|[[/Custom ODB tree]]|[[Mhttpd.js|MIDAS Javascript library]]}}&lt;br /&gt;
&lt;br /&gt;
= Purpose =&lt;br /&gt;
A user-created [[mhttpd]] Custom Web Page accessible from the side menu allows the user additional flexibility. For example, a custom page may present the essential parameters of the controlled experiment in a more compact way. A custom page may even replace the default [[Status Page]].&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
Custom web pages provide the user with a means of creating secondary user-created web page(s) activated within the standard MIDAS web interface. These custom pages usually display ODB parameters or data to the user. They can contain specific links to the ODB so the user may also input information relevant to the experiment. Users create Custom Pages when the standard pages do not meet their requirements completely.&lt;br /&gt;
&lt;br /&gt;
We note that MIDAS has provided a number of different ways of providing custom pages over the years.  A new scheme of custom pages making use of modern HTML5 techniques has been introduced in 2017. This page will mostly only be providing documentation for the new scheme of custom pages.&lt;br /&gt;
&lt;br /&gt;
= Examples of Custom Pages =&lt;br /&gt;
&lt;br /&gt;
Click on the thumbnails to enlarge.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| [[File:Capture_sgas.png|thumb|left|Figure 1: MEG Gas System]] || &#039;&#039;&#039;Example 1&#039;&#039;&#039;&lt;br /&gt;
This page (Figure 1) from the MEG experiment at PSI shows a complex gas system. This shows the use of &amp;quot;fills&amp;quot; and &amp;quot;labels&amp;quot;. Open valves are represented as green circles, closed valves as red circles. If, for example, an open valve is clicked, the valve closes, and the circle turns red (provided the user successfully supplied the correct password).&lt;br /&gt;
|-&lt;br /&gt;
| [[File:custom_ROOT_analyzer_page.png|thumb|left|Figure 2: ROOT Analyzer (MEG Experiment)]] || &#039;&#039;&#039;Example 2&#039;&#039;&#039;&lt;br /&gt;
Many MIDAS experiments work with ROOT based analyzers today. One problem is that the graphical output of the root analyzer can only be seen through the X server and not through the web. At the MEG experiment, this problem was solved in an elegant way: The ROOT analyzer runs in the background, using a &amp;quot;virtual&amp;quot; X server called Xvfb. It plots its output (several panels) normally using this X server, then saves this panels every ten seconds into GIF files. These GIF files are then served through mhttpd using a custom page. The output is shown in Figure 2.&lt;br /&gt;
&lt;br /&gt;
The buttons on the left sides are actually HTML buttons on that custom page overlaid to the GIF image, which in this case shows one of the 800 PMT channels digitized at 1.6 GSPS. With these buttons one can cycle through the different GIF images, which then automatically update ever ten seconds. Of course it is not possible to feed interaction back to the analyzer (i.e. the waveform cannot be fitted interactively) but for monitoring an experiment in production mode this tool is extremely helpful, since it is seamlessly integrated into mhttpd. All the magic is done with JavaScript, and the buttons are overlaid on the graphics using CSS with absolute positioning. The analysis ratio on the top right is also done with JavaScript accessing the required information from the ODB. &lt;br /&gt;
&lt;br /&gt;
For details using Xvfb server, please contact Ryu Sawada &amp;lt;sawada@icepp.s.u-tokyo.ac.jp&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| [[File:deap_custom_scb.png|thumb|left|Figure 3: SCB Setup (Deap Experiment)]] || &#039;&#039;&#039;Example 3&#039;&#039;&#039;&lt;br /&gt;
This custom page from the Deap Experiment (Figure 3) allows the users to easily set individual channels, or a group of channels, or all channels of the SCB modules to a particular value.   &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Access a Custom Page from the Regular MIDAS pages =&lt;br /&gt;
Access to a Custom Page is set up through the [[/Custom ODB tree]] (see [[/Custom ODB tree#Keys in the /Custom tree|custom-link]]). This associates a custom page file on the disk with a menu item on the left navigation bar. Clicking on the resulting link will display that custom page.&lt;br /&gt;
&lt;br /&gt;
Often a custom page requires resources such as *.css (stylesheets) or *.js (javascript) files. It is convenient to store all such files with the custom page file (*.html) in&lt;br /&gt;
a particular directory, e.g. /home/expt/online/custom. By creating an ODB key /Custom/Path, all the custom page files and resources can be served easily from this directory.&lt;br /&gt;
See [[Custom Page Features#Resource files]] for more information.&lt;br /&gt;
&lt;br /&gt;
If the key  {{Odbpath|path=/Custom/myPage&amp;amp;}}  (see Note) is created, e.g.&lt;br /&gt;
 odbedit&amp;gt; ls /Custom&lt;br /&gt;
    Path                              /home/expt/online/custom&lt;br /&gt;
    myPage&amp;amp;                           mypage.html&lt;br /&gt;
&lt;br /&gt;
the custom link on the left navigation bar will be &amp;lt;code&amp;gt;myPage&amp;lt;/code&amp;gt; and the URL for the resulting custom page will be of the form &amp;lt;code&amp;gt;http://myhost.mydomain:myport/cmd=?Custom&amp;amp;page=myPage&amp;lt;/code&amp;gt; (see also [[mhttpd#usage]]).  &lt;br /&gt;
Clicking on &amp;lt;code&amp;gt;myPage&amp;lt;/code&amp;gt; will display the custom page in the same window.&lt;br /&gt;
&lt;br /&gt;
;Note&lt;br /&gt;
: With the &amp;quot;&amp;amp;&amp;quot; symbol in the key name, the page would appear in a new tab/window. See [[/Custom ODB tree#Key names|Key names]] for more information.&lt;br /&gt;
&lt;br /&gt;
If an experiment used many custom pages, the menu on the left side can get pretty long. To avoid that, custom pages can be structured in submenus. Simply put a custom page in an ODB subdirectory, and it will appear in a separate submenu, e.g.&lt;br /&gt;
&lt;br /&gt;
 odbedit&amp;gt; ls -r /Custom&lt;br /&gt;
    Path                              /home/expt/online/custom&lt;br /&gt;
    myPage&amp;amp;                           mypage.html&lt;br /&gt;
    Calorimeter&lt;br /&gt;
        HV                            hv.html&lt;br /&gt;
        Rates                         rates.html&lt;br /&gt;
    Baeam&lt;br /&gt;
        Beamline                      beamline.html&lt;br /&gt;
        Accelerator                   accel.html&lt;br /&gt;
&lt;br /&gt;
The pages then include the subdirectory in the URL, like &lt;br /&gt;
&lt;br /&gt;
 http://localhost:8080?cmd=custom&amp;amp;page=beam/Beamline&lt;br /&gt;
&lt;br /&gt;
Subdirectories can contain nested subdirectories. Please make sure that you specify the full path in your mhttpd_init() call, such as&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body class=&amp;quot;mcss&amp;quot; onload=&amp;quot;mhttpd_init(&#039;Calorimeter/HV&#039;);&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in order to keep the submenu open after you select the custom page.&lt;br /&gt;
&lt;br /&gt;
= How to write a custom page =&lt;br /&gt;
A custom page is usually written in a combination of HTML and Javascript. It can contain any of the features described below. A [[Mjsonrpc | Javascript MjsonRPC Library]] has been written to provide access to the ODB and other functions.&lt;br /&gt;
&lt;br /&gt;
In what follows, we describe a scheme for writing custom pages with the set of modb* javascript functions.  The advantages of using these modb* javascript functions are&lt;br /&gt;
&lt;br /&gt;
* modb* functions hide details about the underlying MjsonRPC calls, which should allow a user to write pretty and sophisticated custom pages quickly and cleanly.&lt;br /&gt;
* modb* functions ensure that all the periodic updates of the ODB value (and other MIDAS information) are done in a single MjsonRPC batch call, which should ensure optimal page loading speed.&lt;br /&gt;
* modb* functions encapsulate the underlying communication. Should the communication change in the future, the custom pages do not have to be changed.&lt;br /&gt;
&lt;br /&gt;
It is also possible for users to write their custom pages using only the underlying [[Mjsonrpc | MjsonRPC library]] calls, but they then need to ensure on their own that the page loading remains efficient.  In particular, if you combine the standard MIDAS navigation bars (described in next section) with your own periodic MjsonRPC calls then you will probably need at least two separate periodic RPC calls to populate the custom page (instead of one call).  It will also require more coding to implement the custom page with only MjsonRPC calls.&lt;br /&gt;
&lt;br /&gt;
== How to use the standard MIDAS navigation bars on your custom page == &lt;br /&gt;
&lt;br /&gt;
If you want to have your custom page use the same header and navigation bars as the standard MIDAS pages, you need to use the following syntax &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
   &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;midas.css&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;script src=&amp;quot;controls.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
   &amp;lt;script src=&amp;quot;midas.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
   &amp;lt;script src=&amp;quot;mhttpd.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
   &amp;lt;title&amp;gt;myPage&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;body class=&amp;quot;mcss&amp;quot; onload=&amp;quot;mhttpd_init(&#039;myPage&#039;);&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- header and side navigation will be filled in mhttpd_start --&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;mheader&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;msidenav&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;mmain&amp;quot;&amp;gt;&lt;br /&gt;
 ADD YOUR HTML/JS  CODE here...&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The call &amp;lt;code&amp;gt;mhttpd_init(&#039;myPage&#039;)&amp;lt;/code&amp;gt; is executed when the page is loaded, and  &amp;lt;code&amp;gt;myPage&amp;lt;/code&amp;gt; is the name of the page shown on the left menu bar. This corresponds to an ODB entry /Custom/myPage.&lt;br /&gt;
This pattern will allow you to use the standard MIDAS navigation whether you are using the modb* functions or the underlying [[Mjsonrpc | javascript libraries]].&lt;br /&gt;
&lt;br /&gt;
= modb* Javascript scheme = &lt;br /&gt;
&lt;br /&gt;
The general scheme of the custom page scheme is to write &amp;lt;code&amp;gt;&amp;amp;lt;div class=&amp;quot;modb...&amp;quot;&amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;&amp;amp;lt;span class=&amp;quot;modb...&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;&amp;lt;/code&amp;gt; tags with special class names, most of them starting with &amp;quot;modb...&amp;quot; (&amp;quot;MIDAS-ODB&amp;quot;). Use a &amp;lt;code&amp;gt;&amp;amp;lt;div&amp;amp;gt;&amp;lt;/code&amp;gt; tag if you want the element to appear in a separate line, and use the &amp;lt;code&amp;gt;&amp;amp;lt;span&amp;amp;gt;&amp;lt;/code&amp;gt; tag if you want to display the element in-line. The following description uses only &amp;lt;code&amp;gt;&amp;amp;lt;div&amp;amp;gt;&amp;lt;/code&amp;gt; tags, but all of them can be changed to &amp;lt;code&amp;gt;&amp;amp;lt;span&amp;amp;gt;&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
All HTML tags with &amp;quot;modb...&amp;quot; names are scanned by the &amp;lt;code&amp;gt;mhttp_init(&#039;name&#039;)&amp;lt;/code&amp;gt; function upon page load, and their inner contents are replaced by the requested ODB value or some graphics. The contents are then updated regularly. Updates are once per second by default. This can be changed by passing a second argument to &amp;lt;code&amp;gt;mhttpd_init(&#039;name&#039;, interval)&amp;lt;/code&amp;gt; where &amp;quot;interval&amp;quot; is in milliseconds. You can add or remove &amp;quot;modb...&amp;quot; elements at any time using javascript, and the new elements will be &amp;quot;discovered&amp;quot; automatically during the next update.&lt;br /&gt;
&lt;br /&gt;
== modbset(path, value) ==&lt;br /&gt;
&lt;br /&gt;
To set values in the ODB, the midas JavaScript function mjsonrpc_db_paste() is usually called. This function is implemented as a JavaScript promise, which lets you chain several request in order to change values inside the ODB in a certain order. If that functionality is not required, the simplified modbset() function can be called, which also implements standard error handling. Two versions of this function exist, one which accepts a single ODB path and a single value, and one which accepts an array of ODB paths and values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
modbset(&amp;quot;odb path&amp;quot;, value)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
modbset([&amp;quot;odb path1&amp;quot;, &amp;quot;odb path2&amp;quot;, ...], [value1, value2, ...])&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These functions are typically used by custom JavaScript code, like when some value in an experiment exceeds some limit and some action has to be taken like to close a valve. If the call fails (like if mhttpd is dead), a window with an error description is shown.&lt;br /&gt;
&lt;br /&gt;
== modb ==&lt;br /&gt;
&lt;br /&gt;
This special HTML div tag (abbreviation stands for Midas ODB) &amp;lt;code&amp;gt;&amp;amp;lt;div class=&amp;quot;modb&amp;quot; data-odb-path=&amp;quot;/Some/Path&amp;quot; onchange=&amp;quot;func()&amp;quot;&amp;amp;gt;&amp;lt;/code&amp;gt; can be used to call a user-defined function func() if a value in the ODB changes. This function must be defined inline or in a separate &amp;amp;lt;script&amp;amp;gt;...&amp;amp;lt;/script&amp;amp;gt; section, and can execute any operation, such as opening a dialog box, hiding/unhiding parts of the custom page, or changing colors and styles of page elements.&lt;br /&gt;
&lt;br /&gt;
The current value of the ODB entry is available inside the &amp;quot;onchange&amp;quot; function as &#039;&#039;&#039;this.value&#039;&#039;&#039;. Following tag will call a function which logs the current run number in the JavaScript console window:&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;div class=&amp;quot;modb&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; onchange=&amp;quot;func(this.value)&amp;quot;&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;amp;lt;script&amp;amp;gt;function func(value) {&lt;br /&gt;
console.log(value);&lt;br /&gt;
}&amp;amp;lt;/script&amp;amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
If the ODB path does not point to an individual value but to a subdirectory, the whole subdirectory is mapped to &#039;&#039;&#039;this.value&#039;&#039;&#039; as a JavaSctipt object such as&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;div class=&amp;quot;modb&amp;quot; data-odb-path=&amp;quot;/Runinfo&amp;quot; onchange=&amp;quot;func(this.value)&amp;quot;&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;amp;lt;script&amp;amp;gt;function func(value) {&lt;br /&gt;
console.log(value[&amp;quot;run number&amp;quot;]);&lt;br /&gt;
}&amp;amp;lt;/script&amp;amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Note that ODB entries are mapped to JavaScript objects without change. So if an ODB entry name contains a blank, it must be accessed via the JS square bracket &#039;&#039;&#039;value[&amp;quot;run number&amp;quot;]&#039;&#039;&#039; as shown in the above example. Otherwise, the entry can be accessed via the dot notation, such as &#039;&#039;&#039;value.state&#039;&#039;&#039; for /Runinfo/State for example.&lt;br /&gt;
&lt;br /&gt;
== modbvalue ==&lt;br /&gt;
&lt;br /&gt;
This special HTML div tag (abbreviation stands for &amp;quot;Midas ODB VALUE&amp;quot;) &lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;div class=&amp;quot;modbvalue&amp;quot; data-odb-path=&amp;quot;/Some/Path&amp;quot;&amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&amp;lt;/code&amp;gt; &lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
is now automatically replaced by the value in the ODB found at the given path and updated regularly as described above Following options are valid for this tag:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Table 1: List of valid options for modbvalue tag&lt;br /&gt;
|-&lt;br /&gt;
! Option !! Example !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| data-name || class=&amp;quot;modbvalue&amp;quot; || Tells the framework to replace this tag with an ODB value&lt;br /&gt;
|-&lt;br /&gt;
| data-odb-path || data-odb-path = &amp;quot;/Runinfo/Run number&amp;quot; || Path to the value in the ODB. If omitted, the value must be set via [[Custom_Page#Changing_values_of_indicators_programmatically | set_value]].&lt;br /&gt;
|-&lt;br /&gt;
| data-odb-editable || data-odb-editable=&amp;quot;1&amp;quot; || If set, the value is not only shown, but is also clickable for in-line editing. Hitting return send the new value to the ODB.&lt;br /&gt;
|-&lt;br /&gt;
| data-format || data-format=&amp;quot;f3&amp;quot; || Specify format of data shown. See Table 2 below for options.&lt;br /&gt;
|-&lt;br /&gt;
| data-size || data-size=&amp;quot;8&amp;quot; || Specify size (in chars) of edit box if one modifies the value. Default is 10.&lt;br /&gt;
|-&lt;br /&gt;
| data-formula || data-formula=&amp;quot;2*x+3&amp;quot; || Specify an optional formula to process with the current ODB value stored in x&lt;br /&gt;
|-&lt;br /&gt;
| data-validate || data-validate=&amp;quot;func&amp;quot; || Specify an optional validation function which gets called before submitting data (see below)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Validation ===&lt;br /&gt;
&lt;br /&gt;
Before a modified value is submitted to the ODB, an optional validation function can be called via the &amp;lt;code&amp;gt;data-validate&amp;lt;/code&amp;gt; option. The function&lt;br /&gt;
will be called with the current value and a reference to the current modbvalue element. If the function returns &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;, then the value&lt;br /&gt;
is not sent to the ODB.&lt;br /&gt;
&lt;br /&gt;
Following example shows a function which just rejects the submission of values above 1000:&lt;br /&gt;
&lt;br /&gt;
  &amp;amp;lt;div class=&amp;quot;modbvalue&amp;quot; ... data-odb-editable=&amp;quot;1&amp;quot; data-validate=&amp;quot;my_validate&amp;quot;&amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;amp;lt;script src=&amp;quot;controls.js&amp;quot;&amp;amp;gt;&amp;amp;lt;/script&amp;amp;gt; &amp;amp;lt;!-- needed of dlgAlert() --&amp;amp;gt;&lt;br /&gt;
  &amp;amp;lt;script&amp;amp;gt;&lt;br /&gt;
  function my_validate(value, element) {&lt;br /&gt;
     if (value &amp;gt; 1000) {&lt;br /&gt;
        dlgAlert(&amp;quot;Value cannot be above 1000&amp;quot;);&lt;br /&gt;
        return false;&lt;br /&gt;
     }&lt;br /&gt;
     return true;&lt;br /&gt;
  }&lt;br /&gt;
  &amp;amp;lt;/script&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
Following function corrects the return value to 1000 if it&#039;s above 1000:&lt;br /&gt;
&lt;br /&gt;
  &amp;amp;lt;script&amp;amp;gt;&lt;br /&gt;
  function my_validate2(value, element) {&lt;br /&gt;
     if (value &amp;gt; 1000) {&lt;br /&gt;
        element.childNodes[0].value = 1000;&lt;br /&gt;
     return true;&lt;br /&gt;
  }&lt;br /&gt;
  &amp;amp;lt;/script&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Confirmation ===&lt;br /&gt;
&lt;br /&gt;
Before a modified value is submitted to the ODB, a confirmation dialog box can be displayed to let the user confirm the change before it is actually written to the ODB. &lt;br /&gt;
This is done with the option &amp;lt;code&amp;gt;data-confirm=&amp;amp;lt;string&amp;amp;gt;&amp;lt;/code&amp;gt;. A dialog box is then shown with the &amp;lt;code&amp;gt;&amp;amp;lt;string&amp;amp;gt;&amp;lt;/code&amp;gt; as the main text and two buttons with &amp;quot;OK&amp;quot; and &amp;quot;Cancel&amp;quot;.&lt;br /&gt;
Hitting &amp;quot;OK&amp;quot; finally writes the value to the ODB, hitting &amp;quot;Cancel&amp;quot; keeps the old value.&lt;br /&gt;
&lt;br /&gt;
Following example shows an example:&lt;br /&gt;
&lt;br /&gt;
  &amp;amp;lt;div class=&amp;quot;modbvalue&amp;quot; ... data-odb-editable=&amp;quot;1&amp;quot; data-confirm=&amp;quot;Are you sure to change the value?&amp;quot;&amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
Following dialog box is then showed:&lt;br /&gt;
&lt;br /&gt;
[[File:Confirm.png|frame|left|Optional confirm dialog]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br clear=all&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Formatting ===&lt;br /&gt;
&lt;br /&gt;
Table 2 below lists the format specifiers supported with a modbvalue tag &amp;lt;code&amp;gt;data-format=&amp;quot;...&amp;quot;&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Table 2: Format specifiers for modbvalue tag &amp;lt;code&amp;gt;data-format=&amp;quot;...&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
! Option !! Valid for* !! Example !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| %d || int || 1234 || Shows a number in decimal encoding&lt;br /&gt;
|-&lt;br /&gt;
| %t || int, float || 1,234,567 || Shows a number in decimal encoding with commas as thousands separator&lt;br /&gt;
|-&lt;br /&gt;
| %x || int || 0x4D2 || Shows a number in hexadecimal encoding&lt;br /&gt;
|-&lt;br /&gt;
| %b || int || 10011010010b|| Shows a number in binary encoding. Options t, d, x, b can be combined, like &amp;lt;code&amp;gt;data-format=&amp;quot;%d / %x&amp;quot;&amp;lt;/code&amp;gt; to produce &amp;lt;code&amp;gt;1234 / 0x4D2&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| %f&amp;amp;lt;x&amp;amp;gt; || float || 1.234 || Shows a floating point number with &amp;amp;lt;x&amp;amp;gt; digits after the decimal. A value of f0 shows only the integer part.&lt;br /&gt;
|-&lt;br /&gt;
| %p&amp;amp;lt;x&amp;amp;gt; || float || 1.23 || Shows a floating point number with &amp;amp;lt;x&amp;amp;gt; significant digits of precision, independent of the decimal. For example a value of p2 can render a number to 12000 or 0.0012&lt;br /&gt;
|-&lt;br /&gt;
| %e&amp;amp;lt;x&amp;amp;gt; || float || 1.23e-05 || Shows a floating point number with &amp;amp;lt;x&amp;amp;gt; digits after the decimal in exponential format. Useful for small number such as pressures.&lt;br /&gt;
|-&lt;br /&gt;
| T= %f1 C || float || T= 25.4 C || Combination of text and float value is possible.&lt;br /&gt;
|-&lt;br /&gt;
| %d / %x / %b || int || 17 / 0x11 / 10001b|| Same integer value in different formats&lt;br /&gt;
|-&lt;br /&gt;
| [col1,col2] || bool || [red,var(--mgreen)] || Generates a color box filled with col1 (false, &amp;lt;span style=&amp;quot;display: inline-block; width: 1em; height: 1em; border: 1px solid black; background-color: red&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;) or col2 (true, &amp;lt;span style=&amp;quot;display: inline-block; width: 1em; height: 1em; border: 1px solid black; background-color: #a0ffb8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* Note that valid for &amp;quot;int&amp;quot; means all integral ODB types (regardless of size or signed/unsigned) and valid for &amp;quot;float&amp;quot; means both float and double.&lt;br /&gt;
&lt;br /&gt;
== modbbutton ==&lt;br /&gt;
&lt;br /&gt;
This tag generates a push-button which can set a certain ODB entry to a specific value. To set the &amp;quot;Run number&amp;quot; to 100, one can use the following tag:&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;button class=&amp;quot;modbbutton&amp;quot; class=&amp;quot;mbutton&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-odb-value=&amp;quot;100&amp;quot; data-validate=&amp;quot;my_validate&amp;quot;&amp;amp;gt;[Button Text]&amp;amp;lt;/button&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The optional &amp;lt;code&amp;gt;data-validate&amp;lt;/code&amp;gt; function can be used to prevent pressing the button under certain circumstances. If the validate function returns false, the value is not written to the ODB, similarly than for modbvalue tag.&lt;br /&gt;
&lt;br /&gt;
== modbbox ==&lt;br /&gt;
&lt;br /&gt;
This tag generates a rectangular box which changes color according to a value in the ODB. If the value is nonzero or true (for booleans), the &#039;&#039;&#039;data-color&#039;&#039;&#039; is used, otherwise the &#039;&#039;&#039;data-background-color&#039;&#039;&#039; is used&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;div class=&amp;quot;modbbox&amp;quot; data-odb-path=&amp;quot;/Logger/Write Data&amp;quot; data-formula=&amp;quot;x &amp;gt; 0&amp;quot; style=&amp;quot;width: 30px; height: 30px; border: 1px solid black&amp;quot; data-color=&amp;quot;lightgreen&amp;quot; data-background-color=&amp;quot;red&amp;quot;&amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Optionally, a &amp;lt;code&amp;gt;data-formula&amp;lt;/code&amp;gt; can be specified. The formula sees the ODB value in the variable &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt;, and can do any boolean operation. If the result of this is true, then the box gets the &amp;lt;code&amp;gt;data-color&amp;lt;/code&amp;gt;, otherwise the &amp;lt;code&amp;gt;data-background-color&amp;lt;/code&amp;gt;.&lt;br /&gt;
Examples for these formulas are &amp;lt;code&amp;gt;x &amp;gt; 10&amp;lt;/code&amp;gt; for a comparison or &amp;lt;code&amp;gt;x &amp;amp; 1&amp;lt;/code&amp;gt; which will do a bitwise AND operation and is true only for odd numbers.&lt;br /&gt;
&lt;br /&gt;
== modbcheckbox ==&lt;br /&gt;
&lt;br /&gt;
This tag generates a check box which can set a certain ODB entry to true or false. To set the &amp;quot;Write data&amp;quot; flag for the logger true or false, one can use the following tag:&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;input type=&amp;quot;checkbox&amp;quot; class=&amp;quot;modbcheckbox&amp;quot; data-odb-path=&amp;quot;/Logger/Write data&amp;quot; data-validate=&amp;quot;my_validate&amp;quot; /&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
If the ODB value changed by this control is of type integer, its value will be set to 1 or 0. The optional &amp;lt;code&amp;gt;data-validate&amp;lt;/code&amp;gt; function can be used to prevent changing a value under certain circumstances. If the validate function returns false, the value is not written to the ODB, similarly than for &amp;lt;code&amp;gt;modbvalue&amp;lt;/code&amp;gt; tag.&lt;br /&gt;
&lt;br /&gt;
== modbselect ==&lt;br /&gt;
&lt;br /&gt;
This tag generates a drop down box with certain valued which can be sent to a value in the ODB. Following example shows a drop-down box with three different values. When selected, they are sent to the ODB under &amp;lt;code&amp;gt;/Runinfo/Run number&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
  &amp;amp;lt;select class=&amp;quot;modbselect&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot;&amp;amp;gt;&lt;br /&gt;
    &amp;amp;lt;option value=&amp;quot;1&amp;quot;&amp;amp;gt;1&amp;amp;lt;/option&amp;amp;gt;&lt;br /&gt;
    &amp;amp;lt;option value=&amp;quot;5&amp;quot;&amp;amp;gt;5&amp;amp;lt;/option&amp;amp;gt;&lt;br /&gt;
    &amp;amp;lt;option value=&amp;quot;10&amp;quot;&amp;amp;gt;10&amp;amp;lt;/option&amp;amp;gt;&lt;br /&gt;
  &amp;amp;lt;/select&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
Instead of specifying the valid options in the javascript code, you can also specify them in the ODB, and populate the drop-down with those values. Specify &amp;lt;code&amp;gt;data-auto-options=&amp;quot;1&amp;quot;&amp;lt;/code&amp;gt; to enable this behaviour. For ODB key &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt;, you will need to create an ODB entry called &amp;lt;code&amp;gt;Options x&amp;lt;/code&amp;gt; in the same directory; this &amp;quot;options&amp;quot; key should be a list, with each element in the list being an allowable option.&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;!-- Will read options from &amp;quot;/Equipment/Example/Settings/Options Something&amp;quot; in this case --&amp;gt;&lt;br /&gt;
  &amp;amp;lt;select class=&amp;quot;modbselect&amp;quot; data-odb-path=&amp;quot;/Equipment/Example/Settings/Something&amp;quot; data-auto-options=&amp;quot;1&amp;quot;&amp;amp;gt;&lt;br /&gt;
  &amp;amp;lt;/select&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The benefit of the &amp;lt;code&amp;gt;data-auto-options=&amp;quot;1&amp;quot;&amp;lt;/code&amp;gt; approach is that the same options will be shown on the regular ODB browser webpage. &lt;br /&gt;
&lt;br /&gt;
Note that these options are only a convenience for the user interface - there is no strict enforcement in the ODB itself! Power-users are able to set other values via C++/Python/Javascript/odbedit etc.&lt;br /&gt;
&lt;br /&gt;
== modbhbar ==&lt;br /&gt;
&lt;br /&gt;
The following tag:&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;div class=&amp;quot;modbhbar&amp;quot; style=&amp;quot;width: 500px; height: 18px; color: lightgreen;&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-max-value=&amp;quot;10&amp;quot; &amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
shows a horizontal bar with a total length of 500px. Depending on the ODB value {{Odbpath|path=Run number}}. If {{Odbpath|path=Run number}} is 10, then the bar is filled all the way to the right, if {{Odbpath|path=Run number}} is 5, the bar is only filled halfway. Following options are possible:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Setting !! Meaning !! Required&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;width: 500px&amp;quot; || Total width of the horizontal bar || Yes&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;height: 18px&amp;quot; || Height of the horizontal bar || Yes&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;color: red&amp;quot; || Color of horizontal bar || Transparent if not present&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;background-color: red&amp;quot; || Background color of horizontal bar || Transparent if not present&lt;br /&gt;
|-&lt;br /&gt;
| data-odb-path || ODB path of value being displayed. If omitted, the value must be set via [[Custom_Page#Changing_values_of_indicators_programmatically | set_value]]. || No&lt;br /&gt;
|-&lt;br /&gt;
| data-min-value || Left limit of bar range || 0 if not present&lt;br /&gt;
|-&lt;br /&gt;
| data-max-value || Right limit of bar range || 1 if not present&lt;br /&gt;
|-&lt;br /&gt;
| data-log || Logarithmic display || No&lt;br /&gt;
|-&lt;br /&gt;
| data-print-value || If &amp;quot;1&amp;quot;, data value is shown as text overlay || No&lt;br /&gt;
|-&lt;br /&gt;
| data-format || Specify format of data shown. See Table 2 above for options || No&lt;br /&gt;
|-&lt;br /&gt;
| data-formula || Specify an optional formula to process with the current ODB value stored in x || No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== mhaxis ==&lt;br /&gt;
&lt;br /&gt;
A horizontal bar can be combined with an axis with tick marks and labels. The axis can be above or below the bar.&lt;br /&gt;
&lt;br /&gt;
The following tag:&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;div class=&amp;quot;mhaxis&amp;quot; style=&amp;quot;width: 500px; height: 22px;&amp;quot; data-min-value=&amp;quot;0&amp;quot; data-max-value=&amp;quot;10&amp;quot; &amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
shows a horizontal axis next to the bar. Following options are possible:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Setting !! Meaning !! Required&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;width: 500px&amp;quot; || Total width of the axis, must match the width of the horizontal bar || Yes&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;height: 18px&amp;quot; || Height of the axis, must be enough to display labels  || Yes&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align: top&amp;quot; || Must be &amp;quot;top&amp;quot; if the axis is below the bar || &amp;quot;bottom&amp;quot; if not given&lt;br /&gt;
|-&lt;br /&gt;
| data-min-value || Left limit of axis range || Yes&lt;br /&gt;
|-&lt;br /&gt;
| data-max-value || Right limit of axis range || Yes&lt;br /&gt;
|-&lt;br /&gt;
| data-log || Logarithmic display || No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== modbvbar ==&lt;br /&gt;
&lt;br /&gt;
Same as &amp;lt;code&amp;gt;modbhbar&amp;lt;/code&amp;gt;, except the bar grows vertically instead of horizontally.&lt;br /&gt;
&lt;br /&gt;
== mvaxis ==&lt;br /&gt;
&lt;br /&gt;
Same as &amp;lt;code&amp;gt;mhaxis&amp;lt;/code&amp;gt;, except the axis is shown vertically instead of horizontally.&lt;br /&gt;
&lt;br /&gt;
== modbthermo ==&lt;br /&gt;
&lt;br /&gt;
The following tag:&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;div class=&amp;quot;modbthermo&amp;quot; style=&amp;quot;width: 30px; height: 100px;&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-min-value=&amp;quot;-10&amp;quot; data-max-value=&amp;quot;30&amp;quot; data-color=&amp;quot;blue&amp;quot; data-print-value=&amp;quot;1&amp;quot; &amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
shows a vertical thermometer ranging from -10 to 30. Depending on the ODB value {{Odbpath|path=Run number}}. The run number was chosen instead of a real temperature since this ODB variable exists in all midas installations by default, so it&#039;s good for testing. Following options are possible:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Setting !! Meaning !! Required&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;width: 30px&amp;quot; || Width of the thermometer || Yes&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;height: 100px&amp;quot; || Total height of the thermometer || Yes&lt;br /&gt;
|-&lt;br /&gt;
| data-odb-path || ODB path of value being displayed. If omitted, the value must be set via [[Custom_Page#Changing_values_of_indicators_programmatically | set_value]]. || No&lt;br /&gt;
|-&lt;br /&gt;
| data-max-value || Upper range || Yes&lt;br /&gt;
|-&lt;br /&gt;
| data-min-value || Lower range || 0 if not present&lt;br /&gt;
|-&lt;br /&gt;
| data-color || Color of thermometer || Black if not present&lt;br /&gt;
|-&lt;br /&gt;
| data-background-color || Color of thermometer background || Transparent if not present&lt;br /&gt;
|-&lt;br /&gt;
| data-print-value || If &amp;quot;1&amp;quot;, data value is shown below the thermometer || No&lt;br /&gt;
|-&lt;br /&gt;
| data-scale || If &amp;quot;1&amp;quot;, the min and max values of the range are shown next to the thermometer || No&lt;br /&gt;
|-&lt;br /&gt;
| data-format || Specifies format of temperature shown below gauge. See Table 2 for options. || No&lt;br /&gt;
|-&lt;br /&gt;
| data-formula || Specify an optional formula to process with the current ODB value stored in x || No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== modbgauge ==&lt;br /&gt;
&lt;br /&gt;
The following tag:&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;amp;lt;div class=&amp;quot;modbgauge&amp;quot; style=&amp;quot;width: 100px; height: 50px;&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-min-value=&amp;quot;0&amp;quot; data-max-value=&amp;quot;10&amp;quot; data-color=&amp;quot;darkgreen&amp;quot;&amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
shows a circular gauge ranging from 0 to 10. Depending on the ODB value &amp;quot;Run number&amp;quot;. Following options are possible:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Setting !! Meaning !! Required&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;width: 100px&amp;quot; || Width of the gauge || Yes&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;height: 50px&amp;quot; || Total height of the gauge || Yes&lt;br /&gt;
|-&lt;br /&gt;
| data-odb-path || ODB path of value being displayed. If omitted, the value must be set via [[Custom_Page#Changing_values_of_indicators_programmatically | set_value]]. || No&lt;br /&gt;
|-&lt;br /&gt;
| data-max-value || Upper range || Yes&lt;br /&gt;
|-&lt;br /&gt;
| data-min-value || Lower range || 0 if not present&lt;br /&gt;
|-&lt;br /&gt;
| data-color || Color of gauge || Black if not present&lt;br /&gt;
|-&lt;br /&gt;
| data-background-color || Color of gauge background || Transparent if not present&lt;br /&gt;
|-&lt;br /&gt;
| data-print-value || If &amp;quot;1&amp;quot;, data value is shown below the gauge || No&lt;br /&gt;
|-&lt;br /&gt;
| data-format || Specifies format of temperature shown below gauge. See Table 2 for options. || No&lt;br /&gt;
|-&lt;br /&gt;
| data-scale || If &amp;quot;1&amp;quot;, the min and max values of the range are shown below the gauge || No&lt;br /&gt;
|-&lt;br /&gt;
| data-formula || Specify an optional formula to process with the current ODB value stored in x || No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If the gauge scale is not shown, the gauge height should be half the gauge width. If the scale is shown, 15px must be added to the height.&lt;br /&gt;
&lt;br /&gt;
== Changing properties of controls dynamically ==&lt;br /&gt;
&lt;br /&gt;
All custom controls can be configured to call a user&#039;s function when the control is first set up, or when the value changes. This is done by specifying the &#039;&#039;&#039;onload&#039;&#039;&#039; and/or &#039;&#039;&#039;onchange&#039;&#039;&#039; functions.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;onload&#039;&#039;&#039; is called only once, when the control&#039;s value is first read from the ODB.&lt;br /&gt;
* &#039;&#039;&#039;onchange&#039;&#039;&#039; is called each time the value in the ODB changes.&lt;br /&gt;
&lt;br /&gt;
The onload/onchange functions have access to the current value and can change any of the parameters of the control. The following callback for example changes the color of a thermometer to red if the value is above 30 and to blue if it is below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;onchange=&amp;quot;this.dataset.color=this.value &amp;gt; 30?&#039;red&#039;:&#039;blue&#039;;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
onchange can call any arbitrary javascript function. Rather than specifying the logic in the tag itself, the above example could also be implemented like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
function check_therm(elem) {&lt;br /&gt;
  if (elem.value &amp;gt; 30) {&lt;br /&gt;
    elem.dataset.color = &amp;quot;red&amp;quot;;&lt;br /&gt;
  } else {&lt;br /&gt;
    elem.dataset.color = &amp;quot;blue&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;modbthermo&amp;quot; style=&amp;quot;width: 30px; height: 100px;&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-min-value=&amp;quot;-10&amp;quot; data-max-value=&amp;quot;30&amp;quot; data-color=&amp;quot;blue&amp;quot; data-print-value=&amp;quot;1&amp;quot; onchange=&amp;quot;check_therm(this)&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Other example use cases include showing/hiding other elements on a webpage based on whether an modbcheckbox is checked or not, or temporarily changing the background color of an element to highlight that a value has changed.&lt;br /&gt;
&lt;br /&gt;
If you want the same function to be called for both onload and onchange, you could set &amp;lt;code&amp;gt;onload=&amp;quot;onchange()&amp;quot;&amp;lt;/code&amp;gt; and have the &amp;quot;real&amp;quot; function in onchange.&lt;br /&gt;
&lt;br /&gt;
== Changing values of indicators programmatically ==&lt;br /&gt;
&lt;br /&gt;
Usually, custom controls are directly linked to values in the ODB. Sometimes it is however necessary to combine several ODB values into a single indicator, like if you want to show the difference of two ODB values. &lt;br /&gt;
&lt;br /&gt;
For such cases, the &amp;lt;code&amp;gt;data-odb-path&amp;lt;/code&amp;gt; attribute can be removed and the the display value can be changed via JavaScript code like following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;mythermo&amp;quot; class=&amp;quot;modbthermo&amp;quot; data-min-value=&amp;quot;-10&amp;quot; data-max-value=&amp;quot;30&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
  let t = document.getElementById(&amp;quot;mythermo&amp;quot;);&lt;br /&gt;
  t.setValue(15);&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= mjshistory =&lt;br /&gt;
&lt;br /&gt;
Custom pages can contain one or more specific history panels usually shown on the &amp;quot;History&amp;quot; page. This makes it easy to combine current readings of values together with the history of these values.&lt;br /&gt;
&lt;br /&gt;
To enable interactive history panels, following lines have to be added to your custom page:&lt;br /&gt;
&lt;br /&gt;
Inisde the &amp;lt;head&amp;gt; tag:&lt;br /&gt;
&lt;br /&gt;
   &amp;lt;script src=&amp;quot;mhistory.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Inside the &amp;lt;body&amp;gt; tag:&lt;br /&gt;
&lt;br /&gt;
   &amp;lt;body ... onload=&amp;quot;mhistory_init();&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following tag:&lt;br /&gt;
&lt;br /&gt;
   &amp;amp;lt;div class=&amp;quot;mjshistory&amp;quot; data-group=&amp;quot;&amp;lt;group&amp;gt;&amp;quot; data-panel=&amp;quot;&amp;lt;panel&amp;gt;&amp;quot; style=&amp;quot;width: 320px; height: 200px;&amp;quot; &amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
shows a history panel defined in the ODB under /History/Display/&amp;amp;lt;group&amp;amp;gt;/&amp;amp;lt;panel&amp;amp;gt; (replace &amp;amp;lt;group&amp;amp;gt;/&amp;amp;lt;panel&amp;amp;gt; with groups and panels from your experiment).&lt;br /&gt;
&lt;br /&gt;
Following options are possible:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Setting !! Meaning !! Required&lt;br /&gt;
|-&lt;br /&gt;
| data-group || ODB group of history. Has to match a group under /History/Display || Yes&lt;br /&gt;
|-&lt;br /&gt;
| data-panel || ODB panel name of history. Has to match a panel name under /History/Display/&amp;amp;lt;group&amp;amp;gt;/ || Yes&lt;br /&gt;
|-&lt;br /&gt;
| data-scale || Time scale of history plot. Use 10m for 10 minutes and 5h for 5 hours. If not specified, the value from the ODB under /History/Display/&amp;amp;lt;group&amp;amp;gt;/&amp;amp;lt;panel&amp;amp;gt;/Timescale is used. || No&lt;br /&gt;
|-&lt;br /&gt;
| data-show-title || Flag to show or hide the title. Default is &amp;quot;1&amp;quot;. || No&lt;br /&gt;
|-&lt;br /&gt;
| data-show-values || Flag to show or hide the variable labels with their current value. Default is &amp;quot;1&amp;quot;. || No&lt;br /&gt;
|-&lt;br /&gt;
| data-show-axis || Flag to show or hide the X/Y axis. Default is &amp;quot;1&amp;quot;. || No&lt;br /&gt;
|-&lt;br /&gt;
| data-show-menu-buttons || Flag to show or hide the menu buttons. Default is &amp;quot;1&amp;quot;. || No&lt;br /&gt;
|-&lt;br /&gt;
| data-show-menu-buttons || Flag to show or hide the zoom buttons. Default is &amp;quot;1&amp;quot;. || No&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;width: 320px&amp;quot; || Width of the history panel || No&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;height: 200px&amp;quot; || Height of the history panel || No&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border: 1px solid black&amp;quot; || Border around the history panel || No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If width and height are omitted, the default values of 320px and 200px are used. History panels are automatically updated every second.&lt;br /&gt;
&lt;br /&gt;
In addition, it is possible to show a floating dialog box with a history panel. That might be useful if you show a single value on a custom page, and want to give users &lt;br /&gt;
the possibility to show the history of that variable. Just put a button next to the value and call &#039;&#039;&#039;mhistory_dialog(&amp;amp;lt;group&amp;amp;gt;, &amp;amp;lt;panel&amp;amp;gt;)&#039;&#039;&#039; from that button like:&lt;br /&gt;
&lt;br /&gt;
   &amp;amp;lt;span class=&amp;quot;modbvalue&amp;quot; data-odb-path=&amp;quot;/Some/Path&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;&lt;br /&gt;
   &amp;lt;button onclick=&amp;quot;mhistory_dialog(&#039;group&#039;,&#039;panel&#039;)&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;icons/activity.svg&amp;quot;&amp;gt;&amp;lt;/button&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The history panel will then be opened when the user clicks the button:&lt;br /&gt;
&lt;br /&gt;
[[File:History dialog.png|frame|left|Floating history dialog]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br clear=all&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If one wants to avoid the definition of a history panel in the ODB, a &amp;quot;direct variable plot&amp;quot; can be done with the function &#039;&#039;&#039;mhistory_dialog_var(&amp;amp;lt;variable&amp;amp;gt;)&#039;&#039;&#039; where &amp;amp;lt;variable&amp;amp;gt; has the format like the variable definition in the ODB (e.g. &amp;quot;System:Trigger per sec.&amp;quot;). Such a plot has some default parameters for the timescale etc., which can be overwritten by passing a parameter object to the function such as &#039;&#039;&#039;mhistory_dialog_var(&amp;quot;System:Trigger per sec.&amp;quot;, {&amp;quot;Timescale&amp;quot;: &amp;quot;24h&amp;quot;});&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A full example of a custom page with a history panel is shown below.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
  &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;midas.css&amp;quot; type=&amp;quot;text/css&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;script src=&amp;quot;midas.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;script src=&amp;quot;mhttpd.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;script src=&amp;quot;controls.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;script src=&amp;quot;mhistory.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body onload=&amp;quot;mhttpd_init(&#039;history_example&#039;); mhistory_init();&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;mheader&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;msidenav&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;  &lt;br /&gt;
  &amp;lt;div id=&amp;quot;mmain&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;mjshistory&amp;quot; data-group=&amp;quot;EPICS&amp;quot; data-panel=&amp;quot;Logging&amp;quot; style=&amp;quot;width: 500px; height: 300px;&amp;quot; &amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= mplot =&lt;br /&gt;
&lt;br /&gt;
Custom pages may contain scatter plots, histograms and other graphics. The syntax is described on the dedicated [[Custom plots with mplot]] page.&lt;br /&gt;
&lt;br /&gt;
= Dialog, popup and modal boxes =&lt;br /&gt;
&lt;br /&gt;
You can spawn a dialog box to either show a message to the user, ask for input, or require confirmation of an action. You can call all these functions from your own javascript code.&lt;br /&gt;
&lt;br /&gt;
== Showing a message ==&lt;br /&gt;
&lt;br /&gt;
The dlgMessage, dlgAlert and dlgWait functions show a message to the user. The dialog box contains an &amp;quot;Ok&amp;quot; button that the user may click to dismiss the message.&lt;br /&gt;
&lt;br /&gt;
=== dlgMessage ===&lt;br /&gt;
&lt;br /&gt;
dlgMessage is the most customisable of the 3 functions. The signature is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dlgMessage(title, message, modal, error, callback, param)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter !! Type !! Meaning !! Required&lt;br /&gt;
|-&lt;br /&gt;
| title || string || Title of the dialog box || Yes&lt;br /&gt;
|-&lt;br /&gt;
| message || string (can be arbitrary HTML) || Main message content || Yes&lt;br /&gt;
|-&lt;br /&gt;
| modal || boolean || If true, will grey out the rest of the page and require the user to dismiss the alert box before they can continue interacting with the page. || No. Defaults to false&lt;br /&gt;
|-&lt;br /&gt;
| error || boolean || If true, will use a red background for the title || No. Defaults to false&lt;br /&gt;
|-&lt;br /&gt;
| callback || function || Function to be called with the user clicks the &amp;quot;Ok&amp;quot; button. The callback function will be called with just a single paramter. || No. Defaults to not calling a callback function.&lt;br /&gt;
|-&lt;br /&gt;
| param || anything || Parameter that will be passed to the `callback` function || No. Defaults to undefined.&lt;br /&gt;
|}&lt;br /&gt;
 &lt;br /&gt;
Some example invocations are:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dlgMessage(&amp;quot;Message title&amp;quot;, &amp;quot;Message text&amp;quot;);&lt;br /&gt;
dlgMessage(&amp;quot;It&#039;s an error!&amp;quot;, &amp;quot;&amp;lt;b&amp;gt;Something is wrong!!!&amp;lt;/b&amp;gt;&amp;quot;, true, true);&lt;br /&gt;
dlgMessage(&amp;quot;Callback example&amp;quot;, &amp;quot;Testing&amp;quot;, true, false, my_message_cb, &amp;quot;some_param&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
function my_message_cb(param) {&lt;br /&gt;
   alert(&amp;quot;Message dismissed! The param was &amp;quot; + param);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== dlgAlert ===&lt;br /&gt;
&lt;br /&gt;
dlgAlert is a convenience function for making it easier to show a warning message to the user. The signature is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dlgAlert(message, callback)&lt;br /&gt;
&lt;br /&gt;
// The above is equivalent to:&lt;br /&gt;
dlgMessage(&amp;quot;Message&amp;quot;, message, true, true, callback)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== dlgWait ===&lt;br /&gt;
&lt;br /&gt;
dlgWait shows a message for a certain amount of time and then automatically closes itself. The signature is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dlgWait(time_in_seconds, message)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Asking for input ==&lt;br /&gt;
&lt;br /&gt;
=== dlgQuery ===&lt;br /&gt;
&lt;br /&gt;
dlgQuery asks the user to respond to a question. The dialog shows a message, an input field for the user to type in, and Ok/Cancel buttons. The user&#039;s response is sent to a callback function that you must implement yourself. The signature is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dlgQuery(message, value, callback, param)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter !! Type !! Meaning !! Required&lt;br /&gt;
|-&lt;br /&gt;
| message || string (can be arbitrary HTML) || The question to show the user || Yes&lt;br /&gt;
|-&lt;br /&gt;
| value || string || Default value to pre-populate the answer field with || Yes (but can be empty string)&lt;br /&gt;
|-&lt;br /&gt;
| callback || function || Function to be called when the user finishes with the dialog. The first parameter will be false if the user clicked the &amp;quot;Cancel&amp;quot; button, or their answer if they clicked the &amp;quot;Ok&amp;quot; button. || Yes&lt;br /&gt;
|-&lt;br /&gt;
| param || anything || Parameter that will be passed to the `callback` function as the 2nd parameter || No. Defaults to undefined.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example usage is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dlgQuery(&amp;quot;Enter a value:&amp;quot;, &amp;quot;my default value&amp;quot;, my_query_cb, &amp;quot;some_other_param&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
function my_query_cb(value, param) {&lt;br /&gt;
   if (value === false) {&lt;br /&gt;
      // User clicked the Cancel button&lt;br /&gt;
   } else {&lt;br /&gt;
      alert(&#039;Value is &#039; + value + &#039;, param is &#039; + param);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// where &#039;param&#039; can also be ommitted.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== dlgConfirm ===&lt;br /&gt;
&lt;br /&gt;
dlgConfirm is like dlgQuery, but just shows the Ok and Cancel buttons without an extra input field. The signature is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dlgConfirm(message, callback, param)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter !! Type !! Meaning !! Required&lt;br /&gt;
|-&lt;br /&gt;
| message || string (can be arbitrary HTML) || The question to show the user || Yes&lt;br /&gt;
|-&lt;br /&gt;
| callback || function || Function to be called when the user finishes with the dialog. The first parameter will be false if the user clicked the &amp;quot;Cancel&amp;quot; button, or true if they clicked the &amp;quot;Ok&amp;quot; button. || Yes&lt;br /&gt;
|-&lt;br /&gt;
| param || anything || Parameter that will be passed to the `callback` function as the 2nd parameter || No. Defaults to undefined.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example usage is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dlgConfirm(&amp;quot;Are you sure you wish to do that?&amp;quot;, my_confirm_cb, &amp;quot;some_other_param&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
function my_confirm_cb(value, param) {&lt;br /&gt;
   if (value === false) {&lt;br /&gt;
      alert(&amp;quot;User clicked Cancel! Param was &amp;quot; + param);&lt;br /&gt;
   } else {&lt;br /&gt;
      alert(&amp;quot;User clicked Ok! Param was &amp;quot; + param);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// where &#039;param&#039; can also be ommitted.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Complete Example =&lt;br /&gt;
&lt;br /&gt;
The following code shows an example page (contained in {{Filepath|path=resources/a_example.html}} in the MIDAS distribution) of a custom page implementing most of the new features. You activate this page by putting in the ODB:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/Custom&lt;br /&gt;
  Path     /midas/resources&lt;br /&gt;
  Test     a_example.html&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
The file &#039;&#039;&#039;a_example.html&#039;&#039;&#039; contains the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html class=&amp;quot;mcss&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
   &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;midas.css&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;script src=&amp;quot;controls.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
   &amp;lt;script src=&amp;quot;midas.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
   &amp;lt;script src=&amp;quot;mhttpd.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
   &amp;lt;title&amp;gt;Example&amp;lt;/title&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   &amp;lt;style&amp;gt;&lt;br /&gt;
      .mtable td { padding: 10px; }&lt;br /&gt;
   &amp;lt;/style&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;body class=&amp;quot;mcss&amp;quot; onload=&amp;quot;mhttpd_init(&#039;Example&#039;);&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- header and side navigation will be filled in mhttpd_init --&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;mheader&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;msidenav&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;mmain&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;table class=&amp;quot;mtable&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;th colspan=&amp;quot;2&amp;quot; class=&amp;quot;mtableheader&amp;quot;&amp;gt;Status&amp;lt;/th&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td style=&amp;quot;width: 200px;&amp;quot;&amp;gt;&lt;br /&gt;
            Run number:&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbvalue&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-odb-editable=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            Last run start:&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbvalue&amp;quot; data-odb-path=&amp;quot;/Runinfo/Start time&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            Last run stop:&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbvalue&amp;quot; data-odb-path=&amp;quot;/Runinfo/Stop time&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            Check box:&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            &amp;lt;!-- checkbox changes /Logger/Write data, fire dialog box on change (even if changed by odbedit) --&amp;gt;&lt;br /&gt;
            &amp;lt;input type=&amp;quot;checkbox&amp;quot; class=&amp;quot;modbcheckbox&amp;quot; data-odb-path=&amp;quot;/Logger/Write data&amp;quot;&amp;gt;&amp;lt;/input&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modb&amp;quot; data-odb-path=&amp;quot;/Logger/Write data&amp;quot; onchange=&amp;quot;dlgAlert(&#039;Flag has changed&#039;);&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            Color box:&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            &amp;lt;!-- box changes color according to /Logger/Write data --&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbbox&amp;quot; style=&amp;quot;width: 30px; height: 30px;&amp;quot; data-odb-path=&amp;quot;/Logger/Write data&amp;quot;&lt;br /&gt;
                 data-color=&amp;quot;lightgreen&amp;quot; data-background-color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            Horizontal bars:&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbhbar&amp;quot; style=&amp;quot;width:300px;height:20px;color:orange;&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot;&lt;br /&gt;
                 data-max-value=&amp;quot;10&amp;quot; data-print-value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;div class=&amp;quot;mhaxis&amp;quot; style=&amp;quot;width:500px;height:22px;&amp;quot; data-min-value=&amp;quot;0&amp;quot; data-max-value=&amp;quot;10&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbhbar&amp;quot; style=&amp;quot;width: 500px; height: 18px;color:lightblue&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot;&lt;br /&gt;
                 data-max-value=&amp;quot;10&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbhbar&amp;quot; style=&amp;quot;width: 200px; height: 10px;color:lightgreen;background-color:white&amp;quot;&lt;br /&gt;
                 data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-min-value=&amp;quot;0.1&amp;quot; data-max-value=&amp;quot;10&amp;quot; data-log=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;mhaxis&amp;quot; style=&amp;quot;width:200px;height:22px;vertical-align:top;&amp;quot; data-min-value=&amp;quot;0.1&amp;quot;&lt;br /&gt;
                 data-max-value=&amp;quot;10&amp;quot; data-line=&amp;quot;0&amp;quot; data-log=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            Vertical bars:&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            &amp;lt;span class=&amp;quot;mvaxis&amp;quot; style=&amp;quot;width:100px;height:200px;text-align:right;&amp;quot; data-min-value=&amp;quot;0&amp;quot; data-max-value=&amp;quot;20&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;modbvbar&amp;quot;&lt;br /&gt;
                  style=&amp;quot;width:20px;height:200px;color:yellow;&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot;&lt;br /&gt;
                  data-min-value=&amp;quot;0&amp;quot; data-max-value=&amp;quot;20&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
            &amp;lt;span class=&amp;quot;modbvbar&amp;quot; style=&amp;quot;width:10px;height:200px;vertical-align:top;color:red&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-min-value=&amp;quot;0.1&amp;quot;&lt;br /&gt;
                  data-max-value=&amp;quot;10&amp;quot; data-log=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;mvaxis&amp;quot; style=&amp;quot;width:100px;height:200px;text-align:left;&amp;quot; data-min-value=&amp;quot;0.1&amp;quot;&lt;br /&gt;
                                                                data-max-value=&amp;quot;10&amp;quot; data-log=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            Thermometer:&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbthermo&amp;quot; style=&amp;quot;width:30px;height:100px;&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-min-value=&amp;quot;-10&amp;quot; data-max-value=&amp;quot;30&amp;quot;&lt;br /&gt;
                 data-color=&amp;quot;darkgreen&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbthermo&amp;quot; style=&amp;quot;width:60px;height:100px;&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-min-value=&amp;quot;-10&amp;quot; data-max-value=&amp;quot;30&amp;quot;&lt;br /&gt;
                 data-color=&amp;quot;blue&amp;quot; data-scale=&amp;quot;1&amp;quot;&lt;br /&gt;
                 onchange=&amp;quot;this.dataset.color=this.value &amp;gt; 9?&#039;red&#039;:&#039;blue&#039;;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbthermo&amp;quot; style=&amp;quot;width:30px;height:100px;&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-min-value=&amp;quot;-10&amp;quot; data-max-value=&amp;quot;30&amp;quot;&lt;br /&gt;
                 data-color=&amp;quot;blue&amp;quot; data-background-color=&amp;quot;white&amp;quot; data-value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            Gauges:&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbgauge&amp;quot; style=&amp;quot;width:100px;height:50px;&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-min-value=&amp;quot;0&amp;quot; data-max-value=&amp;quot;10&amp;quot;&lt;br /&gt;
                 data-color=&amp;quot;darkgreen&amp;quot; data-background-color=&amp;quot;lightgrey&amp;quot; &amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;modbgauge&amp;quot; style=&amp;quot;width:100px;height:65px;&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-min-value=&amp;quot;0&amp;quot; data-max-value=&amp;quot;10&amp;quot;&lt;br /&gt;
                 data-color=&amp;quot;red&amp;quot; data-value=&amp;quot;1&amp;quot; data-scale=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td colspan=&amp;quot;2&amp;quot; style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- div around image with &amp;quot;relative&amp;quot; position as anchor for labels and bars --&amp;gt;&lt;br /&gt;
            &amp;lt;div style=&amp;quot;position:relative;width:300px;margin:auto&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
               &amp;lt;img src=&amp;quot;tank.gif&amp;quot;&amp;gt; &amp;lt;!-- background image of tank --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
               &amp;lt;!-- label next to valve --&amp;gt;&lt;br /&gt;
               &amp;lt;div class=&amp;quot;modbvalue&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-odb-editable=&amp;quot;1&amp;quot;&lt;br /&gt;
                    style=&amp;quot;position:absolute;top:157px;left:288px;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
               &amp;lt;!-- vertical bar inside tank, render red if value &amp;gt; 9 --&amp;gt;&lt;br /&gt;
               &amp;lt;div class=&amp;quot;modbvbar&amp;quot; style=&amp;quot;position:absolute;top:80px;left:10px;width:104px;height:170px;&amp;quot;&lt;br /&gt;
                    data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-max-value=&amp;quot;11&amp;quot; data-color=&amp;quot;green&amp;quot;&lt;br /&gt;
                    onchange=&amp;quot;this.firstChild.style.backgroundColor=(this.value &amp;gt; 9)?&#039;red&#039;:&#039;green&#039;;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
               &amp;lt;!-- thermometer inside tank --&amp;gt;&lt;br /&gt;
               &amp;lt;div class=&amp;quot;modbthermo&amp;quot; style=&amp;quot;position:absolute;top:140px;left:20px;width:20px;height:100px;&amp;quot;&lt;br /&gt;
                    data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-min-value=&amp;quot;-10&amp;quot; data-max-value=&amp;quot;30&amp;quot;&lt;br /&gt;
                    data-color=&amp;quot;blue&amp;quot; data-value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td colspan=&amp;quot;2&amp;quot; style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- three buttons to change an ODB entry (run number in this example) --&amp;gt;&lt;br /&gt;
            &amp;lt;button class=&amp;quot;modbbutton&amp;quot; class=&amp;quot;mbutton&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-odb-value=&amp;quot;1&amp;quot;&amp;gt;Set run&lt;br /&gt;
               number to 1&lt;br /&gt;
            &amp;lt;/button&amp;gt;&lt;br /&gt;
            &amp;lt;button class=&amp;quot;modbbutton&amp;quot; class=&amp;quot;mbutton&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-odb-value=&amp;quot;5&amp;quot;&amp;gt;Set run&lt;br /&gt;
               number to 5&lt;br /&gt;
            &amp;lt;/button&amp;gt;&lt;br /&gt;
            &amp;lt;button class=&amp;quot;modbbutton&amp;quot; class=&amp;quot;mbutton&amp;quot; data-odb-path=&amp;quot;/Runinfo/Run number&amp;quot; data-odb-value=&amp;quot;10&amp;quot;&amp;gt;Set run&lt;br /&gt;
               number to 10&lt;br /&gt;
            &amp;lt;/button&amp;gt;&lt;br /&gt;
         &amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
   &amp;lt;/table&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
which results in the page shown in Figure 1 below:&lt;br /&gt;
&lt;br /&gt;
[[File:Custom17.png|frame|left|Figure 1  Example custom page using most features]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt; &amp;lt;!-- clear wraparound after thumbnail --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Old custom page feature =&lt;br /&gt;
&lt;br /&gt;
There are a number of deprecated custom page features, which can be seen here: [[Old Custom Page Features]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:mhttpd Pages]] [[Category:Custom]]&lt;/div&gt;</summary>
		<author><name>Zaher</name></author>
	</entry>
	<entry>
		<id>https://daq00.triumf.ca/MidasWiki/index.php?title=Slow_Control_System&amp;diff=3426</id>
		<title>Slow Control System</title>
		<link rel="alternate" type="text/html" href="https://daq00.triumf.ca/MidasWiki/index.php?title=Slow_Control_System&amp;diff=3426"/>
		<updated>2024-05-01T11:44:41Z</updated>

		<summary type="html">&lt;p&gt;Zaher: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Pagelinks}}&lt;br /&gt;
&lt;br /&gt;
= Links =&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* [[Frontend user code]] &lt;br /&gt;
* [[Equipment List Parameters]]&lt;br /&gt;
*&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
= Introduction=&lt;br /&gt;
Slow Control Systems are used for setup and monitoring of hardware that is not time-critical, and can be run at a low priority. Slow Control systems in a typical experiment are often used to setup and/or monitor components such as high voltage modules, temperature sensors, pressure gauges, leak detectors, RF generators, PID controllers etc. often from a large number of hardware vendors. &lt;br /&gt;
&lt;br /&gt;
Examples of Device and Class Drivers can be found under [[Environment Variables#MIDASSYS|$MIDASSYS]]/drivers, and templates for slow control frontends are also available in the MIDAS package - see [[Frontend user code#Frontend Templates|Frontend templates]].&lt;br /&gt;
&lt;br /&gt;
= MIDAS Slow Control System=&lt;br /&gt;
In the Midas Slow Control System, instead of talking directly to each other, [[Frontend Operation#Frontend|Frontend]] and control programs exchange information through the ODB. If several types of hardware are to be included in a Slow Control System, they may be assigned to a separate Slow Control Equipments. Each Slow Control Equipment is assigned a corresponding ODB subtree under &amp;lt;span style=&amp;quot;color: purple; font-style:italic;&amp;quot;&amp;gt;/Equipment&amp;lt;/span&amp;gt;. This tree contains variables needed to control the equipment as well as variables measured by the equipment.&lt;br /&gt;
&lt;br /&gt;
In the case of a high voltage equipment this is&lt;br /&gt;
&lt;br /&gt;
*    a Demand array which contains voltages to be set,&lt;br /&gt;
*    a Measured array which contains read back voltages and&lt;br /&gt;
*    a Current array which contains the current drawn from each channel.&lt;br /&gt;
&lt;br /&gt;
To change the voltage of a channel, a control program writes the desired value to the Demand array. This array is connected to the high voltage [[Frontend Operation#Frontend|Frontend]] via an ODB hot-link. Each time the Demand value is modified, the frontend receives a notification and sets the new value. In the other direction, the frontend continuously reads the voltage and current values from all channels and updates the appropriate ODB array(s) if there has been a significant change. &lt;br /&gt;
&lt;br /&gt;
This design has a possible drawback due to the fact that the ODB is the key element of that control. Any failure or corruption of the database can result in incorrect driver control. Therefore it is not recommended to use this system to control systems that need redundancy for safety purposes. On the other hand, this system has several advantages:&lt;br /&gt;
&lt;br /&gt;
*   The control program does not need any knowledge of the frontend, it only talks to the ODB.&lt;br /&gt;
*    The control variables only exist at one place that guarantees consistency among all clients.&lt;br /&gt;
*    Basic control can be done through the [[mhttpd]] web interface (or [[odbedit]] )without the need of a special control program.&lt;br /&gt;
*    A special control program can be tested without having a frontend running.&lt;br /&gt;
*    In case of &#039;&#039;n&#039;&#039; frontend and &#039;&#039;m&#039;&#039; control programs, only &#039;&#039;n+m&#039;&#039; network connections are needed instead of &#039;&#039;n*m&#039;&#039; connection for point-to-point connections.&lt;br /&gt;
&lt;br /&gt;
Since all slow control values are contained in the ODB, they are automatically dumped to the logging channels. The slow control frontend uses the same framework as the normal frontend, and behaves similarly in many respects. They also create periodic events that contain the slow control variables and are logged together with trigger and scaler events. The only difference is that a routine is called periodically from the framework that has the task of reading channels and updating the ODB.&lt;br /&gt;
To access slow control hardware, a two-layer driver concept is used. The upper layer is a &amp;quot;class driver&amp;quot;, which establishes the connection to the ODB variables and contains high level functionality like channel limits, ramping etc. It uses a &amp;quot;device driver&amp;quot; to access the channels. These drivers implement only very simple commands like &amp;quot;set channel&amp;quot; and &amp;quot;read channel&amp;quot;. The device drivers themselves can use bus drivers like RS232 or GPIB to control the actual device. See also [https://midas.psi.ch/mscb/ MIDAS Slow Control Bus (MSCB)].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:classes2.jpg|Class driver, Device and Bus driver in the slow control system]]&lt;br /&gt;
&lt;br /&gt;
The separation into class and device drivers has the advantage that it is very easy to add new devices, because only the simple device driver needs to be written. All higher functionality is inherited from the class driver. The device driver can implement richer functionality, depending on the hardware. For some high voltage devices there is a current read-back for example. This is usually reflected by additional variables in the ODB, i.e. a Current array. Frontend equipment uses exactly one class driver, but a class driver can use more than one device driver. This makes it possible to control several high voltage devices for example with one frontend in one equipment. The number of channels for each device driver is defined in the slow control frontend. Several equipments with different class drivers can be defined in a single frontend.&lt;br /&gt;
&lt;br /&gt;
The Slow Control variables can be accessed through the web using the [[mhttpd]] web server [[Status Page#Equipment Information]] or [[MSCB Page]] if using MIDAS Slow Control Bus. &lt;br /&gt;
&lt;br /&gt;
Slow Control variables may also be sent to the [[History System]] (see [[History System#Frontend History Event]]). History tags for each variable are derived from the name of the variable in  {{Odbpath|path=/Equipment/&amp;lt;equipment name&amp;gt;/Settings/Names}} array if present. See [[/History ODB tree#Tags subtree]] for details.&lt;br /&gt;
&lt;br /&gt;
The [[mhttpd]] (MIDAS Web Server) [[History Page]] will also be automatically activated if [[mlogger]] is running.&lt;br /&gt;
&lt;br /&gt;
== Example of a Slow Control Equipment in ODB ==&lt;br /&gt;
&lt;br /&gt;
The following example shows the ODB keys of a slow control equipment called &amp;quot;Epics&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 Key name                        Type    #Val  Size  Last Opn Mode Value&lt;br /&gt;
 ---------------------------------------------------------------------------&lt;br /&gt;
 Epics                           DIR&lt;br /&gt;
    Settings                    DIR&lt;br /&gt;
        Channels                DIR&lt;br /&gt;
            Epics               INT     1     4     25h  0   RWD  3&lt;br /&gt;
        Devices                 DIR&lt;br /&gt;
            Epics               DIR&lt;br /&gt;
                Channel name    STRING  10    32    25h  0   RWD  &lt;br /&gt;
                                        [0]             GPS:VAR1&lt;br /&gt;
                                        [1]             GPS:VAR2&lt;br /&gt;
                                        [2]             GPS:VAR3&lt;br /&gt;
        Names                   STRING  10    32    17h  1   RWD  &lt;br /&gt;
                                        [0]             Current&lt;br /&gt;
                                        [1]             Voltage&lt;br /&gt;
                                        [2]             Watchdog&lt;br /&gt;
        Update Threshold MeasureFLOAT   10    4     17h  0   RWD  &lt;br /&gt;
                                        [0]             2&lt;br /&gt;
                                        [1]             2&lt;br /&gt;
                                        [2]             2&lt;br /&gt;
    Common                      DIR&lt;br /&gt;
        Event ID                WORD    1     2     17h  0   RWD  3&lt;br /&gt;
        Trigger mask            WORD    1     2     17h  0   RWD  0&lt;br /&gt;
        Buffer                  STRING  1     32    17h  0   RWD  SYSTEM&lt;br /&gt;
        Type                    INT     1     4     17h  0   RWD  4&lt;br /&gt;
        Source                  INT     1     4     17h  0   RWD  0&lt;br /&gt;
        Format                  STRING  1     8     17h  0   RWD  FIXED&lt;br /&gt;
        Enabled                 BOOL    1     4     17h  0   RWD  y&lt;br /&gt;
        Read on                 INT     1     4     17h  0   RWD  121&lt;br /&gt;
        Period                  INT     1     4     17h  0   RWD  60000&lt;br /&gt;
        Event limit             DOUBLE  1     8     17h  0   RWD  0&lt;br /&gt;
        Num subevents           DWORD   1     4     17h  0   RWD  0&lt;br /&gt;
        Log history             INT     1     4     17h  0   RWD  1&lt;br /&gt;
        Frontend host           STRING  1     32    17h  0   RWD  hostname&lt;br /&gt;
        Frontend name           STRING  1     32    17h  0   RWD  Epics&lt;br /&gt;
        Frontend file name      STRING  1     256   17h  0   RWD  feepic.c&lt;br /&gt;
    Variables                   DIR&lt;br /&gt;
        Demand                  FLOAT   10    4     0s   1   RWD  &lt;br /&gt;
                                        [0]             1.56&lt;br /&gt;
                                        [1]             120&lt;br /&gt;
                                        [2]             87&lt;br /&gt;
        Measured                FLOAT   10    4     2s   0   RWD  &lt;br /&gt;
                                        [0]             1.56&lt;br /&gt;
                                        [1]             120&lt;br /&gt;
                                        [2]             87&lt;br /&gt;
    Statistics                  DIR&lt;br /&gt;
        Events sent             DOUBLE  1     8     17h  0   RWDE 26&lt;br /&gt;
        Events per sec.         DOUBLE  1     8     17h  0   RWDE 0&lt;br /&gt;
        kBytes per sec.         DOUBLE  1     8     17h  0   RWDE 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Slow Control Frontend ==&lt;br /&gt;
&lt;br /&gt;
A [[Frontend user code|Frontend]] for Slow Control is similar to a regular frontend, except the Equipment List contain the&lt;br /&gt;
[[Equipment List Parameters#Class Driver|Class Driver]] and    [[Equipment List Parameters#Device Driver List|Device Driver List]],&lt;br /&gt;
which are normally left blank in non-Slow Control Frontends. &lt;br /&gt;
&lt;br /&gt;
=== Example of [[Equipment List Parameters|Equipment Declaration]] === &lt;br /&gt;
&lt;br /&gt;
  EQUIPMENT equipment[] = {&lt;br /&gt;
  { &amp;quot;HV&amp;quot;,                  // equipment name&lt;br /&gt;
    {&lt;br /&gt;
    ...&lt;br /&gt;
    &amp;quot;FIXED&amp;quot;,                   /* format */&lt;br /&gt;
    ...&lt;br /&gt;
    cd_hv_read,                 /* readout routine */&lt;br /&gt;
    cd_hv,                      /* class driver main routine */&lt;br /&gt;
    hv_driver,                  /* device driver list */&lt;br /&gt;
    NULL,                       /* init string */&lt;br /&gt;
    },&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
=== Example of  [[Equipment List Parameters#Readout Routine|readout routine]] ===&lt;br /&gt;
&lt;br /&gt;
 INT cd_hv_read(char *pevent, int offset)&lt;br /&gt;
 {&lt;br /&gt;
   float *pdata;&lt;br /&gt;
   DWORD *pdw;&lt;br /&gt;
   HV_INFO *hv_info;&lt;br /&gt;
   EQUIPMENT *pequipment;&lt;br /&gt;
                            //&lt;br /&gt;
   pequipment = *((EQUIPMENT **) pevent);&lt;br /&gt;
   hv_info = (HV_INFO *) pequipment-&amp;gt;cd_info;&lt;br /&gt;
                            //&lt;br /&gt;
   if (hv_info-&amp;gt;format == FORMAT_FIXED) {&lt;br /&gt;
      memcpy(pevent, hv_info-&amp;gt;demand, sizeof(float) * hv_info-&amp;gt;num_channels);&lt;br /&gt;
      pevent += sizeof(float) * hv_info-&amp;gt;num_channels;&lt;br /&gt;
                            //&lt;br /&gt;
    memcpy(pevent, hv_info-&amp;gt;measured, sizeof(float) * hv_info-&amp;gt;num_channels);&lt;br /&gt;
      pevent += sizeof(float) * hv_info-&amp;gt;num_channels;&lt;br /&gt;
                            //&lt;br /&gt;
      memcpy(pevent, hv_info-&amp;gt;current, sizeof(float) * hv_info-&amp;gt;num_channels);&lt;br /&gt;
      pevent += sizeof(float) * hv_info-&amp;gt;num_channels;&lt;br /&gt;
                            //&lt;br /&gt;
      return 3 * sizeof(float) * hv_info-&amp;gt;num_channels;&lt;br /&gt;
   }&lt;br /&gt;
  ....&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Multithreaded Slow Control Frontends ==&lt;br /&gt;
The Midas slow control system was modified in 2006 to support multi-threaded slow control frontends. Each device gets its own thread in the front-end, which has several advantages:&lt;br /&gt;
&lt;br /&gt;
* the communication of all devices runs in parallel and therefore is much faster&lt;br /&gt;
* slow devices can no longer block the frontend. Response times to run transitions etc. therefore become much faster.&lt;br /&gt;
&lt;br /&gt;
This modification required some minor modifications to existing class and device drivers (see [https://daq00.triumf.ca/elog-midas/Midas/289] for details). &lt;br /&gt;
&lt;br /&gt;
To enable multithread support in a [[Frontend user code#Frontend Templates|Slow Control Frontend]], see [[Equipment List Parameters#Device Driver List|Device Driver List]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Slow Control]] [[Category:Frontend]]&lt;/div&gt;</summary>
		<author><name>Zaher</name></author>
	</entry>
	<entry>
		<id>https://daq00.triumf.ca/MidasWiki/index.php?title=Odbxx&amp;diff=3425</id>
		<title>Odbxx</title>
		<link rel="alternate" type="text/html" href="https://daq00.triumf.ca/MidasWiki/index.php?title=Odbxx&amp;diff=3425"/>
		<updated>2024-05-01T09:05:00Z</updated>

		<summary type="html">&lt;p&gt;Zaher: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A C++11 object-oriented interface to the [[ODB|ODB (online database)]] was introduced in May 2020. You can think of it like a &amp;quot;magic&amp;quot; map/dictionary that automatically sends changes you make to the ODB, and receives updates that others have made.&lt;br /&gt;
&lt;br /&gt;
The header for this odbxx interface is at [https://bitbucket.org/tmidas/midas/src/develop/include/odbxx.h odbxx.h] and example usage in [https://bitbucket.org/tmidas/midas/src/develop/examples/odbxx/odbxx_test.cxx odbxx_test.cxx].&lt;br /&gt;
&lt;br /&gt;
You can find more details about the ODB on the [[ODB_Access_and_Use|ODB Access and Use]]  page, which includes links to the command-line, javascript, python, and non-object C++ interfaces.&lt;br /&gt;
&lt;br /&gt;
== Basic usage ==&lt;br /&gt;
&lt;br /&gt;
The simplest usage is like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Grab a bit of the ODB&lt;br /&gt;
midas::odb exp(&amp;quot;/Experiment&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// Simple read&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &amp;quot;The current transition timeout is &amp;quot; &amp;lt;&amp;lt; exp[&amp;quot;Transition timeout&amp;quot;] &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
&lt;br /&gt;
// Make a change. The new value is automatically sent to the ODB.&lt;br /&gt;
// Most C++ operators are supported (++, += etc), or you can do a simple&lt;br /&gt;
// re-assignment like `exp[&amp;quot;Transition timeout&amp;quot;] = 12345;`.&lt;br /&gt;
exp[&amp;quot;Transition timeout&amp;quot;] += 100;&lt;br /&gt;
&lt;br /&gt;
// Read the new value&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &amp;quot;The transition timeout is now &amp;quot; &amp;lt;&amp;lt; exp[&amp;quot;Transition timeout&amp;quot;] &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can automatically cast to regular data types (int, double) etc if you want a copy of the value to work with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int curr_timeout = exp[&amp;quot;Transition timeout&amp;quot;];&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: The ODB directory you connect to (&amp;quot;/Experiment&amp;quot; in the above example), has to start with a &amp;quot;/&amp;quot; to tell the midas::odb object&lt;br /&gt;
to connect directly to the ODB. Otherwise, a simple local midas::odb string object gets created without any connection to the ODB.&lt;br /&gt;
&lt;br /&gt;
== Automatic refreshing ==&lt;br /&gt;
&lt;br /&gt;
You may temporarily disable the automatic updating to/from the ODB&lt;br /&gt;
using &amp;lt;code&amp;gt;odb::set_auto_refresh_write(false)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;odb::set_auto_refresh_read(false)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If auto-refresh is enabled (the default), your new values are sent to&lt;br /&gt;
the ODB as soon as you touch the value in the &amp;lt;code&amp;gt;midas::odb&amp;lt;/code&amp;gt; object. The ODB&lt;br /&gt;
is queried for new values whenever you access the value. In the above&lt;br /&gt;
example, the ODB is queried 4 times (during construction of &amp;lt;code&amp;gt;exp&amp;lt;/code&amp;gt;, and&lt;br /&gt;
each time &amp;lt;code&amp;gt;exp[&amp;quot;Transition timeout&amp;quot;]&amp;lt;/code&amp;gt; is mentioned), and written to 1&lt;br /&gt;
time (when &amp;lt;code&amp;gt;exp[&amp;quot;Transition timeout&amp;quot;]&amp;lt;/code&amp;gt; is assigned to).&lt;br /&gt;
&lt;br /&gt;
See the [[#Callback functions]] section below for details on how to have a function&lt;br /&gt;
called when a value changes.&lt;br /&gt;
&lt;br /&gt;
== Arrays/vectors ==&lt;br /&gt;
&lt;br /&gt;
ODB arrays are represented by std vectors.&lt;br /&gt;
&lt;br /&gt;
You can access/edit individual elements using []:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;odb[&amp;quot;Example&amp;quot;][1] = 1.2;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can completely re-assign content using a std::vector or std::array:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;std::vector&amp;lt;float&amp;gt; vec = std::vector&amp;lt;float&amp;gt;(10);&lt;br /&gt;
odb[&amp;quot;Example&amp;quot;] = vec;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can resize arrays using &amp;lt;code&amp;gt;odb::resize()&amp;lt;/code&amp;gt;. If the existing array is longer,&lt;br /&gt;
it will be truncated; if shorter it will be extended with default values&lt;br /&gt;
(0 or an empty string).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;odb[&amp;quot;Example&amp;quot;].resize(5); // Now is 5 elements long&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that arithmetic operators are supported for arrays, and will apply&lt;br /&gt;
the operation to ALL ELEMENTS IN THE ARRAY:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Create the vector&lt;br /&gt;
std::vector&amp;lt;float&amp;gt; vec = std::vector&amp;lt;float&amp;gt;(2);&lt;br /&gt;
vec[0] = 3;&lt;br /&gt;
vec[1] = 5;&lt;br /&gt;
&lt;br /&gt;
// Assign in ODB&lt;br /&gt;
odb[&amp;quot;Example&amp;quot;] = vec;&lt;br /&gt;
&lt;br /&gt;
// Multiply ALL elements by 2&lt;br /&gt;
odb[&amp;quot;Example&amp;quot;] *= 2;&lt;br /&gt;
&lt;br /&gt;
// odb[&amp;quot;Example&amp;quot;] now contains {6, 10}.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can directly iterate over arrays/vectors:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Iterating using standard begin/end.&lt;br /&gt;
for (auto it = o[&amp;quot;Int Array&amp;quot;].begin(); it != o[&amp;quot;Int Array&amp;quot;].end(); it++) {&lt;br /&gt;
   int val = *it;&lt;br /&gt;
   std::cout &amp;lt;&amp;lt; val &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Iterating using C++11 range-based for loop.&lt;br /&gt;
for (int val : o[&amp;quot;Int Array&amp;quot;]) {&lt;br /&gt;
   std::cout &amp;lt;&amp;lt; val &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Strings ==&lt;br /&gt;
&lt;br /&gt;
Strings in the ODB are returned as std::string (unlike the midas.h &amp;lt;code&amp;gt;db_get_value()&amp;lt;/code&amp;gt;&lt;br /&gt;
family of functions, where strings are returned as char*). You may have vectors of strings.&lt;br /&gt;
&lt;br /&gt;
== Creating new bits of the ODB ==&lt;br /&gt;
&lt;br /&gt;
You can automatically create bits of the ODB by passing a struct to the&lt;br /&gt;
&amp;lt;code&amp;gt;midas::odb&amp;lt;/code&amp;gt; constructor, then calling &amp;lt;code&amp;gt;odb::connect()&amp;lt;/code&amp;gt;, like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Define the ODB structure&lt;br /&gt;
midas::odb o = {&lt;br /&gt;
   {&amp;quot;Int32 Key&amp;quot;, 42},&lt;br /&gt;
   {&amp;quot;Bool Key&amp;quot;, true},&lt;br /&gt;
   {&amp;quot;Subdir&amp;quot;, {&lt;br /&gt;
      {&amp;quot;Float key&amp;quot;, 1.2f},     // floats must be explicitly specified&lt;br /&gt;
   }},&lt;br /&gt;
   {&amp;quot;Int Array&amp;quot;, {1, 2, 3}},&lt;br /&gt;
   {&amp;quot;Double Array&amp;quot;, {1.2, 2.3, 3.4}},&lt;br /&gt;
   {&amp;quot;String Array&amp;quot;, {&amp;quot;Hello1&amp;quot;, &amp;quot;Hello2&amp;quot;, &amp;quot;Hello3&amp;quot;}},&lt;br /&gt;
   {&amp;quot;Large Array&amp;quot;, std::array&amp;lt;int, 10&amp;gt;{} },   // array with explicit size&lt;br /&gt;
   {&amp;quot;Large String&amp;quot;, std::string(63, &#039;\0&#039;) },  // string with explicit size&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// Then sync the structure. This function&lt;br /&gt;
// - keeps the existing value of any keys that are in the ODB and your code&lt;br /&gt;
// - creates any keys that are in your code but not yet in the ODB&lt;br /&gt;
o.connect(&amp;quot;/Test/Settings&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// If you make the `write_defaults` argument true, then the function&lt;br /&gt;
// - overwrites the value of any keys that are in the ODB with the value in your code&lt;br /&gt;
// - creates any keys that are in your code but not yet in the ODB&lt;br /&gt;
o.connect(&amp;quot;/Test/Settings&amp;quot;, true);&lt;br /&gt;
&lt;br /&gt;
// The `connect_and_fix_structure()` method acts like the old db_check_record() function, and&lt;br /&gt;
// - keeps the existing value of any keys that are in the ODB and your code&lt;br /&gt;
// - creates any keys that are in your code but not yet in the ODB&lt;br /&gt;
// - deletes any keys that are in the ODB but not your code&lt;br /&gt;
// - updates the order of keys in the ODB to match your code&lt;br /&gt;
o.connect_and_fix_structure(&amp;quot;/Test/Settings&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the ODB path in teh odb::connect() call must start with a &#039;/&#039;. The ODB root path like &amp;lt;code&amp;gt;o.connect(&amp;quot;/&amp;quot;);&amp;lt;/code&amp;gt; is not allowed in this call.&lt;br /&gt;
&lt;br /&gt;
If you want to add new keys to existing ODB subdirectories, you can also just use the [] operator:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;midas::odb existing_key(&amp;quot;/MyExistingKey&amp;quot;);&lt;br /&gt;
existing_key[&amp;quot;MyNewSubKey&amp;quot;] = 1.23;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also create new keys by providing a default value when reading a value. If the key doesn&#039;t already exist, the default value will be used.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;midas::odb existing_key(&amp;quot;/MyExistingKey&amp;quot;);&lt;br /&gt;
double val = existing_key[&amp;quot;MyNewSubKey&amp;quot;](1.23);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Iterating over subkeys ==&lt;br /&gt;
&lt;br /&gt;
You can iterate over subkeys using normal iterator functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Iterating using standard begin/end.&lt;br /&gt;
midas::odb exp(&amp;quot;/Experiment&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
for (auto it = exp.begin(); it != exp.end(); it++) {&lt;br /&gt;
   midas::odb&amp;amp; subkey = *it;&lt;br /&gt;
   std::cout &amp;lt;&amp;lt; subkey.get_name() &amp;lt;&amp;lt; &amp;quot; = &amp;quot; &amp;lt;&amp;lt; subkey &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Iterating using C++11 range-based for loop.&lt;br /&gt;
for (midas::odb&amp;amp; subkey : exp) {&lt;br /&gt;
   std::cout &amp;lt;&amp;lt; subkey.get_name() &amp;lt;&amp;lt; &amp;quot; = &amp;quot; &amp;lt;&amp;lt; subkey &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can check whether a subkey exists using &amp;lt;code&amp;gt;odb::is_subkey()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Callback functions ==&lt;br /&gt;
&lt;br /&gt;
You may also set up callback functions that are called whenever a value&lt;br /&gt;
changes, using the &amp;lt;code&amp;gt;odb::watch()&amp;lt;/code&amp;gt; function. Note that you must call&lt;br /&gt;
&amp;lt;code&amp;gt;cm_yield()&amp;lt;/code&amp;gt; (from midas.h) periodically for this to work - deep down it&lt;br /&gt;
is &amp;lt;code&amp;gt;cm_yield()&amp;lt;/code&amp;gt; itself that calls your callback function.&lt;br /&gt;
&lt;br /&gt;
The callback functions can either be a &amp;quot;normal&amp;quot; function, a C++ lambda, or a member function of a C++ class.&lt;br /&gt;
In all cases it should accept one argument - a &amp;lt;code&amp;gt;midas::odb&amp;lt;/code&amp;gt; object (passed&lt;br /&gt;
by reference) that contains the new state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Example with a lambda:&lt;br /&gt;
midas::odb to_watch(&amp;quot;/Experiment&amp;quot;);&lt;br /&gt;
to_watch.watch([](midas::odb &amp;amp;arg) {&lt;br /&gt;
   std::cout &amp;lt;&amp;lt; &amp;quot;Value of key \&amp;quot;&amp;quot; + arg.get_full_path() + &amp;quot;\&amp;quot; changed to &amp;quot; &amp;lt;&amp;lt; arg &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&amp;lt;pre&amp;gt;// Example with a &amp;quot;normal&amp;quot; function:&lt;br /&gt;
void my_function(midas::odb &amp;amp;arg) {&lt;br /&gt;
   std::cout &amp;lt;&amp;lt; &amp;quot;Value of key \&amp;quot;&amp;quot; + arg.get_full_path() + &amp;quot;\&amp;quot; changed to &amp;quot; &amp;lt;&amp;lt; arg &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
midas::odb to_watch(&amp;quot;/Experiment&amp;quot;);&lt;br /&gt;
to_watch.watch(my_function);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Example with a member function of a class:&lt;br /&gt;
#include &amp;lt;functional&amp;gt;&lt;br /&gt;
&lt;br /&gt;
void MyClass::my_function(midas::odb&amp;amp; arg) {&lt;br /&gt;
   std::cout &amp;lt;&amp;lt; &amp;quot;Value of key \&amp;quot;&amp;quot; + arg.get_full_path() + &amp;quot;\&amp;quot; changed to &amp;quot; &amp;lt;&amp;lt; arg &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyClass::some_initialisation_code() {&lt;br /&gt;
  // Arguments to std::bind() are: &amp;quot;member function to call&amp;quot;, &amp;quot;object to call that function on&amp;quot;, &amp;quot;placeholder for midas::odb arg&amp;quot;&lt;br /&gt;
  std::function&amp;lt;void(midas::odb&amp;amp;)&amp;gt; callback = std::bind(&amp;amp;MyClass::my_function, this, std::placeholders::_1);&lt;br /&gt;
&lt;br /&gt;
  midas::odb to_watch(&amp;quot;/Experiment&amp;quot;);&lt;br /&gt;
  to_watch.watch(callback);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Utility functions ==&lt;br /&gt;
&lt;br /&gt;
There are various utility functions which can be used:&lt;br /&gt;
&lt;br /&gt;
==== void odb::create(const char *name, int type) ====&lt;br /&gt;
&lt;br /&gt;
Simple wrapper around db_create_key() to create a single key in the ODB. &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt; is one of TID_xxx.&lt;br /&gt;
&lt;br /&gt;
==== void odb::delete_key() ====&lt;br /&gt;
&lt;br /&gt;
This member function of a midas::odb object deletes that object from the ODB:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;midas::odb o(&amp;quot;/Some/ODB/Path&amp;quot;);&lt;br /&gt;
o.delete_key();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== int odb::delete_key(const std::string &amp;amp;name) ====&lt;br /&gt;
&lt;br /&gt;
This function deletes a key or a subtree in the ODB passed by its path in the &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt; argument. It is a simple wrapper around the C function db_delete_key() and returns the status of that function.&lt;br /&gt;
&lt;br /&gt;
==== bool odb::exists(const std::string *name) ====&lt;br /&gt;
&lt;br /&gt;
This boolean function checks if a key given by its name exists in the ODB.&lt;br /&gt;
&lt;br /&gt;
==== void odb::exists(const std::string *name) ====&lt;br /&gt;
&lt;br /&gt;
This boolean function checks if a key given by its name exists in the ODB.&lt;br /&gt;
&lt;br /&gt;
==== void odb::set_debug(bool flag) / bool odb::get_debug() ====&lt;br /&gt;
&lt;br /&gt;
These functions set and retrieve the debug flag. If the debug flag is &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; all communication with the ODB is printed to the screen. This can be helpful in debugging some problems.&lt;br /&gt;
&lt;br /&gt;
== Example code ==&lt;br /&gt;
&lt;br /&gt;
A full working example exploring most of the features can be found in&lt;br /&gt;
&amp;lt;code&amp;gt;odbxx/odbxx_test.cxx&amp;lt;/code&amp;gt;. The test executable will be compiled as&lt;br /&gt;
&amp;lt;code&amp;gt;build/odbxx/odbxx_test&amp;lt;/code&amp;gt; (it is not installed in the `bin` directory).&lt;/div&gt;</summary>
		<author><name>Zaher</name></author>
	</entry>
	<entry>
		<id>https://daq00.triumf.ca/MidasWiki/index.php?title=Odbxx&amp;diff=3424</id>
		<title>Odbxx</title>
		<link rel="alternate" type="text/html" href="https://daq00.triumf.ca/MidasWiki/index.php?title=Odbxx&amp;diff=3424"/>
		<updated>2024-05-01T09:04:07Z</updated>

		<summary type="html">&lt;p&gt;Zaher: fixed links&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A C++11 object-oriented interface to the [[ODB|ODB (online database)]] was introduced in May 2020. You can think of it like a &amp;quot;magic&amp;quot; map/dictionary that automatically sends changes you make to the ODB, and receives updates that others have made.&lt;br /&gt;
&lt;br /&gt;
The header for this odbxx interface is at [https://bitbucket.org/tmidas/midas/src/develop/include/odbxx.h odbxx.h] and example usage in [https://bitbucket.org/tmidas/midas/src/develop/examples/odbxx/odbxx_test.cxx].&lt;br /&gt;
&lt;br /&gt;
You can find more details about the ODB on the [[ODB_Access_and_Use|ODB Access and Use]]  page, which includes links to the command-line, javascript, python, and non-object C++ interfaces.&lt;br /&gt;
&lt;br /&gt;
== Basic usage ==&lt;br /&gt;
&lt;br /&gt;
The simplest usage is like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Grab a bit of the ODB&lt;br /&gt;
midas::odb exp(&amp;quot;/Experiment&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// Simple read&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &amp;quot;The current transition timeout is &amp;quot; &amp;lt;&amp;lt; exp[&amp;quot;Transition timeout&amp;quot;] &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
&lt;br /&gt;
// Make a change. The new value is automatically sent to the ODB.&lt;br /&gt;
// Most C++ operators are supported (++, += etc), or you can do a simple&lt;br /&gt;
// re-assignment like `exp[&amp;quot;Transition timeout&amp;quot;] = 12345;`.&lt;br /&gt;
exp[&amp;quot;Transition timeout&amp;quot;] += 100;&lt;br /&gt;
&lt;br /&gt;
// Read the new value&lt;br /&gt;
std::cout &amp;lt;&amp;lt; &amp;quot;The transition timeout is now &amp;quot; &amp;lt;&amp;lt; exp[&amp;quot;Transition timeout&amp;quot;] &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can automatically cast to regular data types (int, double) etc if you want a copy of the value to work with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int curr_timeout = exp[&amp;quot;Transition timeout&amp;quot;];&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: The ODB directory you connect to (&amp;quot;/Experiment&amp;quot; in the above example), has to start with a &amp;quot;/&amp;quot; to tell the midas::odb object&lt;br /&gt;
to connect directly to the ODB. Otherwise, a simple local midas::odb string object gets created without any connection to the ODB.&lt;br /&gt;
&lt;br /&gt;
== Automatic refreshing ==&lt;br /&gt;
&lt;br /&gt;
You may temporarily disable the automatic updating to/from the ODB&lt;br /&gt;
using &amp;lt;code&amp;gt;odb::set_auto_refresh_write(false)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;odb::set_auto_refresh_read(false)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If auto-refresh is enabled (the default), your new values are sent to&lt;br /&gt;
the ODB as soon as you touch the value in the &amp;lt;code&amp;gt;midas::odb&amp;lt;/code&amp;gt; object. The ODB&lt;br /&gt;
is queried for new values whenever you access the value. In the above&lt;br /&gt;
example, the ODB is queried 4 times (during construction of &amp;lt;code&amp;gt;exp&amp;lt;/code&amp;gt;, and&lt;br /&gt;
each time &amp;lt;code&amp;gt;exp[&amp;quot;Transition timeout&amp;quot;]&amp;lt;/code&amp;gt; is mentioned), and written to 1&lt;br /&gt;
time (when &amp;lt;code&amp;gt;exp[&amp;quot;Transition timeout&amp;quot;]&amp;lt;/code&amp;gt; is assigned to).&lt;br /&gt;
&lt;br /&gt;
See the [[#Callback functions]] section below for details on how to have a function&lt;br /&gt;
called when a value changes.&lt;br /&gt;
&lt;br /&gt;
== Arrays/vectors ==&lt;br /&gt;
&lt;br /&gt;
ODB arrays are represented by std vectors.&lt;br /&gt;
&lt;br /&gt;
You can access/edit individual elements using []:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;odb[&amp;quot;Example&amp;quot;][1] = 1.2;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can completely re-assign content using a std::vector or std::array:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;std::vector&amp;lt;float&amp;gt; vec = std::vector&amp;lt;float&amp;gt;(10);&lt;br /&gt;
odb[&amp;quot;Example&amp;quot;] = vec;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can resize arrays using &amp;lt;code&amp;gt;odb::resize()&amp;lt;/code&amp;gt;. If the existing array is longer,&lt;br /&gt;
it will be truncated; if shorter it will be extended with default values&lt;br /&gt;
(0 or an empty string).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;odb[&amp;quot;Example&amp;quot;].resize(5); // Now is 5 elements long&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that arithmetic operators are supported for arrays, and will apply&lt;br /&gt;
the operation to ALL ELEMENTS IN THE ARRAY:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Create the vector&lt;br /&gt;
std::vector&amp;lt;float&amp;gt; vec = std::vector&amp;lt;float&amp;gt;(2);&lt;br /&gt;
vec[0] = 3;&lt;br /&gt;
vec[1] = 5;&lt;br /&gt;
&lt;br /&gt;
// Assign in ODB&lt;br /&gt;
odb[&amp;quot;Example&amp;quot;] = vec;&lt;br /&gt;
&lt;br /&gt;
// Multiply ALL elements by 2&lt;br /&gt;
odb[&amp;quot;Example&amp;quot;] *= 2;&lt;br /&gt;
&lt;br /&gt;
// odb[&amp;quot;Example&amp;quot;] now contains {6, 10}.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can directly iterate over arrays/vectors:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Iterating using standard begin/end.&lt;br /&gt;
for (auto it = o[&amp;quot;Int Array&amp;quot;].begin(); it != o[&amp;quot;Int Array&amp;quot;].end(); it++) {&lt;br /&gt;
   int val = *it;&lt;br /&gt;
   std::cout &amp;lt;&amp;lt; val &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Iterating using C++11 range-based for loop.&lt;br /&gt;
for (int val : o[&amp;quot;Int Array&amp;quot;]) {&lt;br /&gt;
   std::cout &amp;lt;&amp;lt; val &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Strings ==&lt;br /&gt;
&lt;br /&gt;
Strings in the ODB are returned as std::string (unlike the midas.h &amp;lt;code&amp;gt;db_get_value()&amp;lt;/code&amp;gt;&lt;br /&gt;
family of functions, where strings are returned as char*). You may have vectors of strings.&lt;br /&gt;
&lt;br /&gt;
== Creating new bits of the ODB ==&lt;br /&gt;
&lt;br /&gt;
You can automatically create bits of the ODB by passing a struct to the&lt;br /&gt;
&amp;lt;code&amp;gt;midas::odb&amp;lt;/code&amp;gt; constructor, then calling &amp;lt;code&amp;gt;odb::connect()&amp;lt;/code&amp;gt;, like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Define the ODB structure&lt;br /&gt;
midas::odb o = {&lt;br /&gt;
   {&amp;quot;Int32 Key&amp;quot;, 42},&lt;br /&gt;
   {&amp;quot;Bool Key&amp;quot;, true},&lt;br /&gt;
   {&amp;quot;Subdir&amp;quot;, {&lt;br /&gt;
      {&amp;quot;Float key&amp;quot;, 1.2f},     // floats must be explicitly specified&lt;br /&gt;
   }},&lt;br /&gt;
   {&amp;quot;Int Array&amp;quot;, {1, 2, 3}},&lt;br /&gt;
   {&amp;quot;Double Array&amp;quot;, {1.2, 2.3, 3.4}},&lt;br /&gt;
   {&amp;quot;String Array&amp;quot;, {&amp;quot;Hello1&amp;quot;, &amp;quot;Hello2&amp;quot;, &amp;quot;Hello3&amp;quot;}},&lt;br /&gt;
   {&amp;quot;Large Array&amp;quot;, std::array&amp;lt;int, 10&amp;gt;{} },   // array with explicit size&lt;br /&gt;
   {&amp;quot;Large String&amp;quot;, std::string(63, &#039;\0&#039;) },  // string with explicit size&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// Then sync the structure. This function&lt;br /&gt;
// - keeps the existing value of any keys that are in the ODB and your code&lt;br /&gt;
// - creates any keys that are in your code but not yet in the ODB&lt;br /&gt;
o.connect(&amp;quot;/Test/Settings&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// If you make the `write_defaults` argument true, then the function&lt;br /&gt;
// - overwrites the value of any keys that are in the ODB with the value in your code&lt;br /&gt;
// - creates any keys that are in your code but not yet in the ODB&lt;br /&gt;
o.connect(&amp;quot;/Test/Settings&amp;quot;, true);&lt;br /&gt;
&lt;br /&gt;
// The `connect_and_fix_structure()` method acts like the old db_check_record() function, and&lt;br /&gt;
// - keeps the existing value of any keys that are in the ODB and your code&lt;br /&gt;
// - creates any keys that are in your code but not yet in the ODB&lt;br /&gt;
// - deletes any keys that are in the ODB but not your code&lt;br /&gt;
// - updates the order of keys in the ODB to match your code&lt;br /&gt;
o.connect_and_fix_structure(&amp;quot;/Test/Settings&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the ODB path in teh odb::connect() call must start with a &#039;/&#039;. The ODB root path like &amp;lt;code&amp;gt;o.connect(&amp;quot;/&amp;quot;);&amp;lt;/code&amp;gt; is not allowed in this call.&lt;br /&gt;
&lt;br /&gt;
If you want to add new keys to existing ODB subdirectories, you can also just use the [] operator:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;midas::odb existing_key(&amp;quot;/MyExistingKey&amp;quot;);&lt;br /&gt;
existing_key[&amp;quot;MyNewSubKey&amp;quot;] = 1.23;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also create new keys by providing a default value when reading a value. If the key doesn&#039;t already exist, the default value will be used.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;midas::odb existing_key(&amp;quot;/MyExistingKey&amp;quot;);&lt;br /&gt;
double val = existing_key[&amp;quot;MyNewSubKey&amp;quot;](1.23);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Iterating over subkeys ==&lt;br /&gt;
&lt;br /&gt;
You can iterate over subkeys using normal iterator functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Iterating using standard begin/end.&lt;br /&gt;
midas::odb exp(&amp;quot;/Experiment&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
for (auto it = exp.begin(); it != exp.end(); it++) {&lt;br /&gt;
   midas::odb&amp;amp; subkey = *it;&lt;br /&gt;
   std::cout &amp;lt;&amp;lt; subkey.get_name() &amp;lt;&amp;lt; &amp;quot; = &amp;quot; &amp;lt;&amp;lt; subkey &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Iterating using C++11 range-based for loop.&lt;br /&gt;
for (midas::odb&amp;amp; subkey : exp) {&lt;br /&gt;
   std::cout &amp;lt;&amp;lt; subkey.get_name() &amp;lt;&amp;lt; &amp;quot; = &amp;quot; &amp;lt;&amp;lt; subkey &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can check whether a subkey exists using &amp;lt;code&amp;gt;odb::is_subkey()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Callback functions ==&lt;br /&gt;
&lt;br /&gt;
You may also set up callback functions that are called whenever a value&lt;br /&gt;
changes, using the &amp;lt;code&amp;gt;odb::watch()&amp;lt;/code&amp;gt; function. Note that you must call&lt;br /&gt;
&amp;lt;code&amp;gt;cm_yield()&amp;lt;/code&amp;gt; (from midas.h) periodically for this to work - deep down it&lt;br /&gt;
is &amp;lt;code&amp;gt;cm_yield()&amp;lt;/code&amp;gt; itself that calls your callback function.&lt;br /&gt;
&lt;br /&gt;
The callback functions can either be a &amp;quot;normal&amp;quot; function, a C++ lambda, or a member function of a C++ class.&lt;br /&gt;
In all cases it should accept one argument - a &amp;lt;code&amp;gt;midas::odb&amp;lt;/code&amp;gt; object (passed&lt;br /&gt;
by reference) that contains the new state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Example with a lambda:&lt;br /&gt;
midas::odb to_watch(&amp;quot;/Experiment&amp;quot;);&lt;br /&gt;
to_watch.watch([](midas::odb &amp;amp;arg) {&lt;br /&gt;
   std::cout &amp;lt;&amp;lt; &amp;quot;Value of key \&amp;quot;&amp;quot; + arg.get_full_path() + &amp;quot;\&amp;quot; changed to &amp;quot; &amp;lt;&amp;lt; arg &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&amp;lt;pre&amp;gt;// Example with a &amp;quot;normal&amp;quot; function:&lt;br /&gt;
void my_function(midas::odb &amp;amp;arg) {&lt;br /&gt;
   std::cout &amp;lt;&amp;lt; &amp;quot;Value of key \&amp;quot;&amp;quot; + arg.get_full_path() + &amp;quot;\&amp;quot; changed to &amp;quot; &amp;lt;&amp;lt; arg &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
midas::odb to_watch(&amp;quot;/Experiment&amp;quot;);&lt;br /&gt;
to_watch.watch(my_function);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Example with a member function of a class:&lt;br /&gt;
#include &amp;lt;functional&amp;gt;&lt;br /&gt;
&lt;br /&gt;
void MyClass::my_function(midas::odb&amp;amp; arg) {&lt;br /&gt;
   std::cout &amp;lt;&amp;lt; &amp;quot;Value of key \&amp;quot;&amp;quot; + arg.get_full_path() + &amp;quot;\&amp;quot; changed to &amp;quot; &amp;lt;&amp;lt; arg &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyClass::some_initialisation_code() {&lt;br /&gt;
  // Arguments to std::bind() are: &amp;quot;member function to call&amp;quot;, &amp;quot;object to call that function on&amp;quot;, &amp;quot;placeholder for midas::odb arg&amp;quot;&lt;br /&gt;
  std::function&amp;lt;void(midas::odb&amp;amp;)&amp;gt; callback = std::bind(&amp;amp;MyClass::my_function, this, std::placeholders::_1);&lt;br /&gt;
&lt;br /&gt;
  midas::odb to_watch(&amp;quot;/Experiment&amp;quot;);&lt;br /&gt;
  to_watch.watch(callback);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Utility functions ==&lt;br /&gt;
&lt;br /&gt;
There are various utility functions which can be used:&lt;br /&gt;
&lt;br /&gt;
==== void odb::create(const char *name, int type) ====&lt;br /&gt;
&lt;br /&gt;
Simple wrapper around db_create_key() to create a single key in the ODB. &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt; is one of TID_xxx.&lt;br /&gt;
&lt;br /&gt;
==== void odb::delete_key() ====&lt;br /&gt;
&lt;br /&gt;
This member function of a midas::odb object deletes that object from the ODB:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;midas::odb o(&amp;quot;/Some/ODB/Path&amp;quot;);&lt;br /&gt;
o.delete_key();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== int odb::delete_key(const std::string &amp;amp;name) ====&lt;br /&gt;
&lt;br /&gt;
This function deletes a key or a subtree in the ODB passed by its path in the &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt; argument. It is a simple wrapper around the C function db_delete_key() and returns the status of that function.&lt;br /&gt;
&lt;br /&gt;
==== bool odb::exists(const std::string *name) ====&lt;br /&gt;
&lt;br /&gt;
This boolean function checks if a key given by its name exists in the ODB.&lt;br /&gt;
&lt;br /&gt;
==== void odb::exists(const std::string *name) ====&lt;br /&gt;
&lt;br /&gt;
This boolean function checks if a key given by its name exists in the ODB.&lt;br /&gt;
&lt;br /&gt;
==== void odb::set_debug(bool flag) / bool odb::get_debug() ====&lt;br /&gt;
&lt;br /&gt;
These functions set and retrieve the debug flag. If the debug flag is &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; all communication with the ODB is printed to the screen. This can be helpful in debugging some problems.&lt;br /&gt;
&lt;br /&gt;
== Example code ==&lt;br /&gt;
&lt;br /&gt;
A full working example exploring most of the features can be found in&lt;br /&gt;
&amp;lt;code&amp;gt;odbxx/odbxx_test.cxx&amp;lt;/code&amp;gt;. The test executable will be compiled as&lt;br /&gt;
&amp;lt;code&amp;gt;build/odbxx/odbxx_test&amp;lt;/code&amp;gt; (it is not installed in the `bin` directory).&lt;/div&gt;</summary>
		<author><name>Zaher</name></author>
	</entry>
	<entry>
		<id>https://daq00.triumf.ca/MidasWiki/index.php?title=Mjsonrpc&amp;diff=3386</id>
		<title>Mjsonrpc</title>
		<link rel="alternate" type="text/html" href="https://daq00.triumf.ca/MidasWiki/index.php?title=Mjsonrpc&amp;diff=3386"/>
		<updated>2023-12-07T09:56:05Z</updated>

		<summary type="html">&lt;p&gt;Zaher: fixed links&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Pagelinks}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&amp;lt;div style=&amp;quot;column-count:3;-moz-column-count:3;-webkit-column-count:3&amp;quot;&amp;gt;&lt;br /&gt;
* [[Mhttpd.js|MIDAS Javascript library]]&lt;br /&gt;
* [[Custom Page]]&lt;br /&gt;
* [[Custom Page Features]]&lt;br /&gt;
* [[mhttpd]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= MIDAS JSON-RPC interface =&lt;br /&gt;
This page described the MIDAS JSON-RPC interface found in the MIDAS Javascript library [[mhttpd.js]].&lt;br /&gt;
&lt;br /&gt;
== JSON general information ==&lt;br /&gt;
&lt;br /&gt;
JSON is a lightweight data-interchange format usually associated with Javascript and web programming. It is a popular choice as replacement for older general purpose data formats such as XML. JSON is defined by [https://tools.ietf.org/html/rfc7159 RFC-7159] (read more at http://www.json.org/). When necessary, the overhead of text encoded JSON is reduced by compressing JSON documents (using gzip), or by using binary-encoded JSON.&lt;br /&gt;
&lt;br /&gt;
JSON documents look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{ &amp;quot;Runinfo&amp;quot; : { &amp;quot;State&amp;quot; : 1, &amp;quot;Online Mode&amp;quot; : 1, &amp;quot;Run number&amp;quot; : 13585 } }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the JSON standard is incompatible with [https://en.wikipedia.org/wiki/IEEE_floating_point IEEE Standard for Floating-Point Arithmetic (IEEE 754)], specifically, there is no standard way to encode the special numerical values +Infinity, -Infinity and NaN (&amp;quot;-0.0&amp;quot; is ok).&lt;br /&gt;
&lt;br /&gt;
In MIDAS, JSON support is provided by an ODB data encoder (in odb.c), an ODB &amp;quot;JSON paste&amp;quot; decoder (in json_paste.cxx) and a general purpose JSON encoder/decoder (mjson.h, mjson.cxx, see https://daq.triumf.ca/~daqweb/doc/midas-devel/html/mjson_8h.html and https://daq.triumf.ca/~daqweb/doc/midas-devel/html/class_m_json_node.html).&lt;br /&gt;
&lt;br /&gt;
The MIDAS implementation of JSON has following variances from the JSON standard:&lt;br /&gt;
* numerical values +Infinity, -Infinity and NaN are encoded and decoded as JSON strings &amp;quot;Infinity&amp;quot;, &amp;quot;-Infinity&amp;quot; and &amp;quot;NaN&amp;quot;. This is compatible with most in-browser JSON implementations. See also http://stackoverflow.com/questions/1423081/json-left-out-infinity-and-nan-json-status-in-ecmascript and similar.&lt;br /&gt;
* numerical values that are usually presented as hex numbers, such a DWORD values, are encoded as JSON strings, i.e. &amp;quot;0x55b961c8&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== JSON encoding of ODB data ==&lt;br /&gt;
&lt;br /&gt;
MIDAS has 3 way to encode ODB data into JSON:&lt;br /&gt;
* &amp;quot;save&amp;quot; format for saving all ODB data and metadata, ODB can be fully reloaded or restored from an ODB JSON save file. Links are preserved as links, upper and lower case in names of ODB keys is preserved.&lt;br /&gt;
* &amp;quot;db_values&amp;quot; format for exporting ODB data to web pages: links are followed to their final values, &#039;&#039;&#039;ODB key names are converted to lower case&#039;&#039;&#039; for use with case-sensitive languages such as Javascript.&lt;br /&gt;
* &amp;quot;list&amp;quot; format encodes a single ODB directory and returns the full information printed by the odbedit &amp;quot;ls -l&amp;quot; command.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
=== JSON &amp;quot;save&amp;quot; format: db_copy_json_save() ===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;save&amp;quot; format encodes all ODB data and metadata. ODB can be fully reloaded or restored from ODB JSON save files.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ odbedit&lt;br /&gt;
odbedit&amp;gt; cd runinfo&lt;br /&gt;
[local:testexpt:S]/Runinfo&amp;gt;json&lt;br /&gt;
status: 1, json: {&lt;br /&gt;
  &amp;quot;State/key&amp;quot; : { &amp;quot;type&amp;quot; : 7, &amp;quot;access_mode&amp;quot; : 7, &amp;quot;last_written&amp;quot; : 1438212553 },&lt;br /&gt;
  &amp;quot;State&amp;quot; : 1,&lt;br /&gt;
  &amp;quot;Online Mode/key&amp;quot; : { &amp;quot;type&amp;quot; : 7, &amp;quot;access_mode&amp;quot; : 7, &amp;quot;last_written&amp;quot; : 1436830326 },&lt;br /&gt;
  &amp;quot;Online Mode&amp;quot; : 1,&lt;br /&gt;
  &amp;quot;Run number/key&amp;quot; : { &amp;quot;type&amp;quot; : 7, &amp;quot;access_mode&amp;quot; : 7, &amp;quot;last_written&amp;quot; : 1438212481 },&lt;br /&gt;
  &amp;quot;Run number&amp;quot; : 13585,&lt;br /&gt;
  &amp;quot;Transition in progress/key&amp;quot; : { &amp;quot;type&amp;quot; : 7, &amp;quot;access_mode&amp;quot; : 7, &amp;quot;last_written&amp;quot; : 1438212553 },&lt;br /&gt;
  &amp;quot;Transition in progress&amp;quot; : 0,&lt;br /&gt;
  &amp;quot;Start abort/key&amp;quot; : { &amp;quot;type&amp;quot; : 7, &amp;quot;access_mode&amp;quot; : 7, &amp;quot;last_written&amp;quot; : 1438212552 },&lt;br /&gt;
  &amp;quot;Start abort&amp;quot; : 0,&lt;br /&gt;
  &amp;quot;Requested transition/key&amp;quot; : { &amp;quot;type&amp;quot; : 7, &amp;quot;access_mode&amp;quot; : 7, &amp;quot;last_written&amp;quot; : 1436923816 },&lt;br /&gt;
  &amp;quot;Requested transition&amp;quot; : 0,&lt;br /&gt;
  &amp;quot;Start time/key&amp;quot; : { &amp;quot;type&amp;quot; : 12, &amp;quot;item_size&amp;quot; : 32, &amp;quot;access_mode&amp;quot; : 7, &amp;quot;last_written&amp;quot; : 1438212481 },&lt;br /&gt;
  &amp;quot;Start time&amp;quot; : &amp;quot;Wed Jul 29 16:28:01 2015&amp;quot;,&lt;br /&gt;
  &amp;quot;Start time binary/key&amp;quot; : { &amp;quot;type&amp;quot; : 6, &amp;quot;access_mode&amp;quot; : 7, &amp;quot;last_written&amp;quot; : 1438212481 },&lt;br /&gt;
  &amp;quot;Start time binary&amp;quot; : &amp;quot;0x55b96181&amp;quot;,&lt;br /&gt;
  &amp;quot;Stop time/key&amp;quot; : { &amp;quot;type&amp;quot; : 12, &amp;quot;item_size&amp;quot; : 32, &amp;quot;access_mode&amp;quot; : 7, &amp;quot;last_written&amp;quot; : 1438212552 },&lt;br /&gt;
  &amp;quot;Stop time&amp;quot; : &amp;quot;Wed Jul 29 16:29:12 2015&amp;quot;,&lt;br /&gt;
  &amp;quot;Stop time binary/key&amp;quot; : { &amp;quot;type&amp;quot; : 6, &amp;quot;access_mode&amp;quot; : 7, &amp;quot;last_written&amp;quot; : 1438212552 },&lt;br /&gt;
  &amp;quot;Stop time binary&amp;quot; : &amp;quot;0x55b961c8&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
[local:testexpt:S]/Runinfo&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== JSON &amp;quot;db_values&amp;quot; format: db_copy_json_values() ===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;db_values&amp;quot; format is intended for easy web page development - main thing is to return easy to parse ODB values with minimal metadata (only ODB last_written is provided).&lt;br /&gt;
&lt;br /&gt;
Because most programming languages and most JSON parser (including Javascript) are case sensitive, but ODB key names are not, this JSON encoding normalizes ODB key names by converting them to lower-case. (Converting spaces to underscores is also a possibility). Only the function &amp;quot;db_get_values&amp;quot; returns lower-case names - this remains the simplest way to have simple parsing of ODB JSON data in Javascript. &amp;quot;db_get_values&amp;quot; now returns an additional field for true names of ODB entries from before they were converted to lower case. This can be turned off with the &amp;quot;omit_names&amp;quot; RPC parameter.&lt;br /&gt;
&lt;br /&gt;
This allows easy use of parsed JSON in Javascript, i.e. runinfo.state or runinfo[&amp;quot;run number&amp;quot;] while avoiding case-matching getter functions (i.e. get_case_insensitive_property(runinfo, &amp;quot;state&amp;quot;)).&lt;br /&gt;
&lt;br /&gt;
Symlinks are followed to their final values and subdirectories are recursed.&lt;br /&gt;
&lt;br /&gt;
An option is provided to &#039;&#039;&#039;transfer the minimum amount of data&#039;&#039;&#039; by suppressing  the &#039;last_written&#039; value and the true names by setting the RPC parameters &amp;quot;omit_last_written&amp;quot; and &amp;quot;omit_names&amp;quot;. See $MIDASSYS/examples/javascript1/example.html. &lt;br /&gt;
&lt;br /&gt;
Also you can specify a timestamp and only data that is newer will be returned (caveats: no way to get rid of empty directories, for now, and no way to specify timestamps for individual array elements - you get the whole array or none of it).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ odbedit&lt;br /&gt;
odbedit&amp;gt; cd runinfo&lt;br /&gt;
[local:testexpt:S]/Runinfo&amp;gt;jsvalues&lt;br /&gt;
status: 1, json: {&lt;br /&gt;
  &amp;quot;state/last_written&amp;quot; : 1438212553,&lt;br /&gt;
  &amp;quot;state&amp;quot; : 1,&lt;br /&gt;
  &amp;quot;online mode/last_written&amp;quot; : 1436830326,&lt;br /&gt;
  &amp;quot;online mode&amp;quot; : 1,&lt;br /&gt;
  &amp;quot;run number/last_written&amp;quot; : 1438212481,&lt;br /&gt;
  &amp;quot;run number&amp;quot; : 13585,&lt;br /&gt;
  &amp;quot;transition in progress/last_written&amp;quot; : 1438212553,&lt;br /&gt;
  &amp;quot;transition in progress&amp;quot; : 0,&lt;br /&gt;
  &amp;quot;start abort/last_written&amp;quot; : 1438212552,&lt;br /&gt;
  &amp;quot;start abort&amp;quot; : 0,&lt;br /&gt;
  &amp;quot;requested transition/last_written&amp;quot; : 1436923816,&lt;br /&gt;
  &amp;quot;requested transition&amp;quot; : 0,&lt;br /&gt;
  &amp;quot;start time/last_written&amp;quot; : 1438212481,&lt;br /&gt;
  &amp;quot;start time&amp;quot; : &amp;quot;Wed Jul 29 16:28:01 2015&amp;quot;,&lt;br /&gt;
  &amp;quot;start time binary/last_written&amp;quot; : 1438212481,&lt;br /&gt;
  &amp;quot;start time binary&amp;quot; : &amp;quot;0x55b96181&amp;quot;,&lt;br /&gt;
  &amp;quot;stop time/last_written&amp;quot; : 1438212552,&lt;br /&gt;
  &amp;quot;stop time&amp;quot; : &amp;quot;Wed Jul 29 16:29:12 2015&amp;quot;,&lt;br /&gt;
  &amp;quot;stop time binary/last_written&amp;quot; : 1438212552,&lt;br /&gt;
  &amp;quot;stop time binary&amp;quot; : &amp;quot;0x55b961c8&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
[local:testexpt:S]/Runinfo&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== JSON &amp;quot;ls&amp;quot; format: db_copy_json_ls() ===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;ls&amp;quot; format returns all the data printed by odbedit command &amp;quot;ls -l&amp;quot; and shown by the mhttpd ODB editor web page. It is intended for implementing web ODB editor functions.&lt;br /&gt;
&lt;br /&gt;
Note how subdirectories are encoded as empty JSON objects &amp;quot;{}&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ odbedit&lt;br /&gt;
odbedit&amp;gt; cd experiment&lt;br /&gt;
[local:testexpt:S]/Experiment&amp;gt;jsls&lt;br /&gt;
jsls &amp;quot;/Experiment&amp;quot;, status: 1, json: {&lt;br /&gt;
  &amp;quot;Name/key&amp;quot; : { &amp;quot;type&amp;quot; : 12, &amp;quot;item_size&amp;quot; : 32, &amp;quot;access_mode&amp;quot; : 7, &amp;quot;last_written&amp;quot; : 1448038414 },&lt;br /&gt;
  &amp;quot;Name&amp;quot; : &amp;quot;testexpt&amp;quot;,&lt;br /&gt;
  &amp;quot;Buffer sizes&amp;quot; : { },&lt;br /&gt;
  &amp;quot;edit on start&amp;quot; : { },&lt;br /&gt;
  &amp;quot;Security&amp;quot; : { },&lt;br /&gt;
  &amp;quot;Transition debug flag/key&amp;quot; : { &amp;quot;type&amp;quot; : 7, &amp;quot;access_mode&amp;quot; : 7, &amp;quot;last_written&amp;quot; : 1436830326 },&lt;br /&gt;
  &amp;quot;Transition debug flag&amp;quot; : 0,&lt;br /&gt;
  &amp;quot;Transition timeout/key&amp;quot; : { &amp;quot;type&amp;quot; : 7, &amp;quot;access_mode&amp;quot; : 7, &amp;quot;last_written&amp;quot; : 1436830326 },&lt;br /&gt;
  &amp;quot;Transition timeout&amp;quot; : 30000,&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Access to ODB arrays ==&lt;br /&gt;
&lt;br /&gt;
Some (not all) JSON-RPC methods allow access to individual array elements in ODB, i.e. {{Odbpath|path=/equipment/rpcexample/settings/a[10]}}.&lt;br /&gt;
&lt;br /&gt;
RPC methods that can do this are:&lt;br /&gt;
* db_copy&lt;br /&gt;
* db_get_values&lt;br /&gt;
* db_paste&lt;br /&gt;
&lt;br /&gt;
=== Supported array index syntax ===&lt;br /&gt;
An array index syntax has been implemented to make it easier to write individual array elements (Table 1)&lt;br /&gt;
;Table 1&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Array Syntax !! Array Elements !! Number of elements/data values&lt;br /&gt;
|-&lt;br /&gt;
| a[1] || 1 || 1 &lt;br /&gt;
|-&lt;br /&gt;
| a[1,2,3] || 1,2,3 || 3 &lt;br /&gt;
|-&lt;br /&gt;
| a[1-3] || 1,2,3 || 3 &lt;br /&gt;
|-&lt;br /&gt;
| a[3-1] || 3,2,1 || 3 &lt;br /&gt;
|-&lt;br /&gt;
| a[1,2,3-5,6] || 1,2,3,4,5,6 || 6 &lt;br /&gt;
|-&lt;br /&gt;
|  a[1-3,4-6,7-9]|| 1,2,3,4,5,6,7,8,9 || 9 &lt;br /&gt;
|-&lt;br /&gt;
| a[3-0,6-4,9-7] || 3,2,1,6,5,4,9,8,7 || 9  &lt;br /&gt;
|-&lt;br /&gt;
| a[4,2,5-6,8] || 4,2,5,6,8 || 5&lt;br /&gt;
|-&lt;br /&gt;
| a || 0-n || n &amp;lt;sup&amp;gt;**&amp;lt;/sup&amp;gt; &lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;sup&amp;gt;**&amp;lt;/sup&amp;gt; &amp;lt;small&amp;gt;n=number of data values supplied - see [[#array name only]].&amp;lt;/small&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See [[#Writing an array]] and [[#Reading an array]] for examples.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== JSON-RPC general information ==&lt;br /&gt;
&lt;br /&gt;
* JSON-RPC standard: https://daq.triumf.ca/~daqweb/doc/midas-devel/doc/jsonrpc/JSON-RPC%202.0%20Specification.html&lt;br /&gt;
* JSON-RPC home page: http://www.jsonrpc.org/specification&lt;br /&gt;
* JSON-RPC via HTTP transport: https://daq.triumf.ca/~daqweb/doc/midas-devel/doc/jsonrpc/simple%20is%20better%20-%20JSON-RPC%202.0%20Transport_%20HTTP.html&lt;br /&gt;
* http://www.simple-is-better.org/json-rpc/index.html&lt;br /&gt;
&lt;br /&gt;
== Javascript client library ==&lt;br /&gt;
&lt;br /&gt;
MIDAS provides a simple client library:&lt;br /&gt;
* documentation, see the mjsonrpc functions: https://daq.triumf.ca/~daqweb/doc/midas-develop/html/group__mjsonrpc__js.html&lt;br /&gt;
* source code, see the mjsonrpc functions: https://daq.triumf.ca/~daqweb/doc/midas-develop/resources/mhttpd.js&lt;br /&gt;
&lt;br /&gt;
The MIDAS JSON RPC client library is based on the &#039;&#039;&#039;Javascript Promise&#039;&#039;&#039; pattern:&lt;br /&gt;
&lt;br /&gt;
* http://www.html5rocks.com/en/tutorials/es6/promises/&lt;br /&gt;
* https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise&lt;br /&gt;
&lt;br /&gt;
A simple example using the Promise API to display an ODB value on a web page:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mjsonrpc_db_get_values([&amp;quot;/runinfo/run number&amp;quot;]).then(function(rpc) {&lt;br /&gt;
   document.getElementById(&amp;quot;run_number&amp;quot;).innerHTML = rpc.result.data[0];&lt;br /&gt;
}).catch(function(error) {&lt;br /&gt;
   mjsonrpc_error_alert(error);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A partial list of available javascript functions. For the full list, and for full documentation, please go to the doxygen-generated documentation at&lt;br /&gt;
https://daq.triumf.ca/~daqweb/doc/midas-devel/html/mhttpd_8js.html&lt;br /&gt;
&lt;br /&gt;
* function 	mjsonrpc_set_url (url) - set the URL of the MIDAS JSON-RPC server, if different from web page URL. Cross-site access is fully supported (see CORS).&lt;br /&gt;
* function 	mjsonrpc_call (method, params, id) - call arbitrary RPC method&lt;br /&gt;
* function 	mjsonrpc_start_program (name, id, callback, error_callback)&lt;br /&gt;
* function 	mjsonrpc_stop_program (name, unique, id, callback, error_callback)&lt;br /&gt;
* function 	mjsonrpc_db_get_values (paths, id, callback, error_callback) - read ODB values&lt;br /&gt;
* function 	mjsonrpc_db_paste (paths, values, id, callback, error_callback) - write ODB values&lt;br /&gt;
&lt;br /&gt;
=== Batch Requests ===&lt;br /&gt;
&lt;br /&gt;
The MIDAS mjson_rpc supports making combining together multiple different requests into the same HTTP request.  This batch mode requesting is much more efficient and should be used whenever possible.  An example of a mjson_rpc batch request for the transition status and ODB values is shown here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
var req = new Array;&lt;br /&gt;
req.push(mjsonrpc_make_request(&amp;quot;cm_transition_status&amp;quot;));&lt;br /&gt;
req.push(mjsonrpc_make_request(&amp;quot;db_get_values&amp;quot;, {&amp;quot;paths&amp;quot;: [&amp;quot;/runinfo&amp;quot;]}));&lt;br /&gt;
mjsonrpc_send_request(req).then(function (rpc) {&lt;br /&gt;
   USER CODE HERE&lt;br /&gt;
}).catch(function (error) {&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
&lt;br /&gt;
Only a few examples are given below. For more examples:&lt;br /&gt;
* look elsewhere on this page&lt;br /&gt;
* look at the example experiment examples/javascript1/example.html&lt;br /&gt;
* look at the doxygen-generated documentation for mjsonrpc_xxx functions&lt;br /&gt;
* look at the implementation of the functions&lt;br /&gt;
* look at the implementation of mhttpd internal web pages (functions mhttpd_xxx in mhttpd.js)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ curl -H &amp;quot;Content-Type: application/json&amp;quot; --data &#039;{&amp;quot;jsonrpc&amp;quot;:&amp;quot;2.0&amp;quot;,&amp;quot;id&amp;quot;:null,&amp;quot;method&amp;quot;:&amp;quot;db_get_values&amp;quot;,&amp;quot;params&amp;quot;:{&amp;quot;paths&amp;quot;:[&amp;quot;/runinfo/run number&amp;quot;]}}&#039; &#039;http://localhost:8080?mjsonrpc&#039;&lt;br /&gt;
{&amp;quot;jsonrpc&amp;quot;: &amp;quot;2.0&amp;quot;,&amp;quot;result&amp;quot;:{&amp;quot;data&amp;quot;:[324],&amp;quot;status&amp;quot;:[1],&amp;quot;last_written&amp;quot;:[1443570804]},&amp;quot;id&amp;quot;:null}&lt;br /&gt;
$ &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Read ODB data ===&lt;br /&gt;
The following code illustrates how to use function &#039;&#039;&#039;mjsonrpc_db_get_values()&#039;&#039;&#039; (see [https://daq.triumf.ca/~daqweb/doc/midas-devel/htm/group__mjsonrpc__js.html#ga80cf049d190f57f6a3f6004791d7f0e9| rpc get_values]) to read data from the ODB. Some of the data are displayed using InnerHTML. The data are read every 10 seconds. The time changes and a counter increments each time the data are read. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
&amp;lt;title&amp;gt;My Title&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;script src=&#039;mhttpd.js&#039;&amp;gt; &lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
var updatePeriod = 10000; // in msec&lt;br /&gt;
var updateTimerId = 0;&lt;br /&gt;
var counter = 0;&lt;br /&gt;
&lt;br /&gt;
function update()  {&lt;br /&gt;
   clearTimeout(updateTimerId);&lt;br /&gt;
   load();&lt;br /&gt;
   if (updatePeriod &amp;gt; 0)&lt;br /&gt;
   updateTimerId = setTimeout(&#039;update()&#039;, updatePeriod);&lt;br /&gt;
}&lt;br /&gt;
function load()   {&lt;br /&gt;
    counter++;&lt;br /&gt;
    document.getElementById(&#039;LastUpdated&#039;).innerHTML = &amp;quot;Updating...&amp;quot; + new Date;&lt;br /&gt;
    document.getElementById(&#039;counter&#039;).innerHTML = &#039;Counter: &#039;+ counter&lt;br /&gt;
&lt;br /&gt;
    mjsonrpc_db_get_values([&amp;quot;/Runinfo&amp;quot;,&amp;quot;/Experiment/name&amp;quot;]).then(function(rpc) {&lt;br /&gt;
       var runinfo= rpc.result.data[0]&lt;br /&gt;
       var name =  rpc.result.data[1]&lt;br /&gt;
       document.getElementById(&amp;quot;name&amp;quot;).innerHTML =&#039;Experiment name =&#039;+ name&lt;br /&gt;
       document.getElementById(&amp;quot;state&amp;quot;).innerHTML =&#039;Run State=&#039;+ runinfo.state&lt;br /&gt;
       document.getElementById(&amp;quot;rn&amp;quot;).innerHTML =&#039;Run number=&#039;+ runinfo[&amp;quot;run number&amp;quot;]&lt;br /&gt;
       document.getElementById(&amp;quot;status&amp;quot;).innerHTML = &#039;Status: &#039;+ rpc.result.status&lt;br /&gt;
    }).catch(function(error) {&lt;br /&gt;
       mjsonrpc_error_alert(error);&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
&amp;lt;h2&amp;gt; Javascript code example using mjson_db_get_values with Promises &amp;lt;/h2&amp;gt;&lt;br /&gt;
&amp;lt;p id=&amp;quot;LastUpdated&amp;quot;&amp;gt;Last updated: never&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p id=&amp;quot;rn&amp;quot;&amp;gt;Run Number : unknown&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p id=&amp;quot;state&amp;quot;&amp;gt;Run State : unknown&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p id=&amp;quot;name&amp;quot;&amp;gt;Experiment name : unknown&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p id=&amp;quot;status&amp;quot;&amp;gt;Status : unknown&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p id=&amp;quot;counter&amp;quot;&amp;gt;Counter: zero&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
update()&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When run as a [[Custom Page]] using the web server [[mhttpd]], the above html code looks like this:&lt;br /&gt;
[[File: mjson_example1.jpg|center|frame|Figure 1: code to read from ODB run as a Custom Page]]&lt;br /&gt;
&amp;lt;br clear=all&amp;gt;   &amp;lt;!-- clear wraparound after image --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The status value (rpc.result.status) is an array. &lt;br /&gt;
* rpc.result.status[0] is the status from reading &amp;quot;/Runinfo&amp;quot;, and &lt;br /&gt;
* rpc.result.status[1] is the status from reading &amp;quot;/Experiment/name&amp;quot;. &lt;br /&gt;
A value of 1 means success.&lt;br /&gt;
If the path does not exist, the status value will be 312, corresponding to the error DB_NO_KEY defined in midas.h.&lt;br /&gt;
&lt;br /&gt;
=== Write ODB data and read it back ===&lt;br /&gt;
The following example illustrates how to write ODB data using the function &#039;&#039;&#039;mjsonrpc_db_paste()&#039;&#039;&#039; (see [https://daq.triumf.ca/~daqweb/doc/midas-devel/html/group__mjsonrpc__js.html#ga2a1da2269d82fbb9edf410a9241997b8| rpc db_paste]). In this example, when the &amp;quot;Set&amp;quot; button is pressed, data are written to the ODB keys {{Odbpath|path=test}}(integer), {{Odbpath|path=pi}}(float) and {{Odbpath|path=my_string}}(string), all in the ODB subdirectory {{Odbpath|path=/equipment/rpcexample/settings/}}. When the &amp;quot;Read&amp;quot; button is pressed, the three ODB keys are read and the data written to the screen (Figure 2). For convenience, in function set(), the paths of the ODB keys to be written are stored in the array &amp;quot;paths&amp;quot;.  Unlike the example above, there is no automatic update.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
&amp;lt;title&amp;gt;My Custom Page Title&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;script src=&#039;mhttpd.js&#039;&amp;gt; &lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
var counter = 0;&lt;br /&gt;
&lt;br /&gt;
function load()  {&lt;br /&gt;
      counter++;&lt;br /&gt;
      document.getElementById(&#039;LastUpdated&#039;).innerHTML = &amp;quot;Updating...&amp;quot; + new Date;&lt;br /&gt;
      mjsonrpc_db_get_values([&amp;quot;/equipment/rpcexample/settings/&amp;quot;]).then(function(rpc) {&lt;br /&gt;
         settings= rpc.result.data[0]&lt;br /&gt;
         document.getElementById(&amp;quot;test&amp;quot;).innerHTML =&#039;Integer test =&#039;+  settings.test&lt;br /&gt;
         document.getElementById(&amp;quot;pi&amp;quot;).innerHTML =&#039;Float pi =&#039;+  settings.pi&lt;br /&gt;
         document.getElementById(&amp;quot;string&amp;quot;).innerHTML =&#039;String my_string=&#039;+ settings[&amp;quot;my string&amp;quot;]&lt;br /&gt;
         document.getElementById(&amp;quot;status&amp;quot;).innerHTML = &#039;Read Status: &#039;+ rpc.result.status&lt;br /&gt;
      }).catch(function(error) {&lt;br /&gt;
         mjsonrpc_error_alert(error);&lt;br /&gt;
      });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function set()  {&lt;br /&gt;
      var paths=[&amp;quot;/equipment/rpcexample/settings/test&amp;quot;,&amp;quot;/equipment/rpcexample/settings/pi&amp;quot;,&amp;quot;/equipment/rpcexample/settings/my string&amp;quot;];&lt;br /&gt;
      mjsonrpc_db_paste(paths, [10,3.1416,&amp;quot;hallo world&amp;quot;]).then(function(rpc) {&lt;br /&gt;
	 result=rpc.result;	      &lt;br /&gt;
         document.getElementById(&amp;quot;wstatus&amp;quot;).innerHTML = &#039;Write status &#039;+rpc.result.status	      &lt;br /&gt;
      }).catch(function(error) {&lt;br /&gt;
          mjsonrpc_error_alert(error);&lt;br /&gt;
      });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
&amp;lt;h2&amp;gt; Example code using mjsonrpc calls to write and read &amp;lt;/h2&amp;gt;&lt;br /&gt;
  &amp;lt;p id=&amp;quot;LastUpdated&amp;quot;&amp;gt;Last updated: never&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;p id=&amp;quot;test&amp;quot;&amp;gt; Test : unknown&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;p id=&amp;quot;pi&amp;quot;&amp;gt;Pi : unknown&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;p id=&amp;quot;string&amp;quot;&amp;gt;String : unknown&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;p id=&amp;quot;status&amp;quot;&amp;gt;Read Status : unknown&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;p id=&amp;quot;wstatus&amp;quot;&amp;gt;Write Status: zero&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;p&amp;gt; &amp;lt;input type=button value=&#039;Set values&#039; onClick=&#039;set();&#039;&amp;gt; &amp;lt;/input&amp;gt;&lt;br /&gt;
       &amp;lt;input type=button value=&#039;Read values&#039; onClick=&#039;load();&#039;&amp;gt;&amp;lt;/input&amp;gt; &amp;gt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When run as a [[Custom Page]] using the web server [[mhttpd]], the output from the above html code is shown in Figure 2 below.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Figure 2a: Initial custom page !! Figure 2b: After pressing &amp;quot;Set&amp;quot; button !! Figure 2c: After pressing &amp;quot;Read&amp;quot; button&lt;br /&gt;
|-&lt;br /&gt;
|[[File: mjson_example2a.jpg|frame]] || [[File: mjson_example2b.jpg|frame ]] || [[File: mjson_example2c.jpg|frame]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;br clear=all&amp;gt;   &amp;lt;!-- clear wraparound after image --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After the data is written (Figure 2b) the write status is shown. &lt;br /&gt;
The status value (rpc.result.status) is an array with each element showing the status of the three write operations to the three keys, i.e. &lt;br /&gt;
* rpc.result.status[0] is the status from writing &amp;quot;test&amp;quot;, and &lt;br /&gt;
* rpc.result.status[1] is the status from writing &amp;quot;pi&amp;quot;. &lt;br /&gt;
* rpc.result.status[2] is the status from writing &amp;quot;my_string&amp;quot; &lt;br /&gt;
A value of 1 means success.&lt;br /&gt;
After the data is read (Figure 2c), the values read and the read status is shown. In this case, the read status only has one value (1=success) because one read operation of the whole subdirectory is performed.&lt;br /&gt;
&lt;br /&gt;
==== Error handling ====&lt;br /&gt;
If one of the paths to write does not exist, there will be an error reported in the status value. For example, if the path to write the variable &amp;quot;pi&amp;quot; does not exist, the write status will be&lt;br /&gt;
: Write status 1,312,1&lt;br /&gt;
The value 312 is that of the error DB_NO_KEY defined in midas.h.&lt;br /&gt;
&lt;br /&gt;
If the number of data values supplied to the function mjsonrpc_db_paste() does not equal the number of paths (i.e. lengths of paths and data arrays are not equal) an error popup will result (Figure 3). The error message also contains the response ID - see [https://daq.triumf.ca/~daqweb/doc/midas-devel/html/group__mjsonrpc__js.html#ga2a1da2269d82fbb9edf410a9241997b8| rpc db_paste] for more information.&lt;br /&gt;
[[File: mjson_slerr.jpg|center|frame|Figure 3: Error popup when lengths of paths array and data array are not equal]]&lt;br /&gt;
&amp;lt;br clear=all&amp;gt;   &amp;lt;!-- clear wraparound after image --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Writing an array ===&lt;br /&gt;
The following example shows using mjsonrpc_db_paste() to write to an array in ODB. See above for [[#supported array index syntax]].&lt;br /&gt;
Because each array element is accessed individually, each array element value comes with a corresponding status value of odb db_get_data_index(), encoded as an array (i.e. rpc.result.status in example below). Note that the data to be written to the array elements must be enclosed by their own square brackets [] and the number of data values must match the number of array elements listed (except when the array name is used alone -  see [[#array name only]]). Too few data values will throw an error, too many will be ignored. &lt;br /&gt;
If the array in the ODB is not large enough for the number of elements and data to be written, it will be expanded automatically.&lt;br /&gt;
&lt;br /&gt;
==== Writing to a variable and an array ====&lt;br /&gt;
The following example shows using mjsonrpc_db_paste()  to&lt;br /&gt;
* write &amp;quot;9&amp;quot; to an integer variable called &amp;quot;test&amp;quot;, and to &lt;br /&gt;
* write values to a number of elements of the array &amp;quot;array&amp;quot;&lt;br /&gt;
Both &amp;quot;test&amp;quot; and &amp;quot;array&amp;quot; are keys in the ODB subdirectory {{Odbpath|path=/equipment/rpcexample/settings/}}.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  mjsonrpc_db_paste([&amp;quot;/equipment/rpcexample/settings/test&amp;quot;,&amp;quot;/equipment/rpcexample/settings/array[3-1,4,5,8-10]&amp;quot;], [9,[1,2,3,4,5,8,9,10]]).then(function(rpc) {&lt;br /&gt;
       document.getElementById(&amp;quot;wstatus&amp;quot;).innerHTML =&#039;Set Status=&#039;+ rpc.result.status&lt;br /&gt;
  }).catch(function(error) {&lt;br /&gt;
       mjsonrpc_error_alert(error);&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assuming the array was filled with zeroes to start with, after writing to the array  and [[#reading an array|reading it back]], it would now contain the values&lt;br /&gt;
: Array= 0,3,2,1,4,5,0,0,8,9,10,11 &lt;br /&gt;
: Set Status = 1,1,1,1,1,1,1,1,1   (rpc.result.status)&lt;br /&gt;
There are 9 elements in the rpc.result.status array, where 1=success. The first element is the status after writing &amp;quot;test&amp;quot;, the next 8 the status after writing each array element.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====  Automatically expand the array ====&lt;br /&gt;
If the array in the ODB contains 12 elements, writing&lt;br /&gt;
 mjsonrpc_db_paste([&amp;quot;/equipment/rpcexample/settings/test&amp;quot;,&amp;quot;/equipment/rpcexample/settings/array[3-1,4,5,8-10,14]&amp;quot;], [9,[1,2,3,4,5,8,9,10,14] ]).then(function(rpc) { ...&lt;br /&gt;
will automatically expand the array to 15 elements.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Too few data values ====&lt;br /&gt;
Supplying too few data values, e.g. writing&lt;br /&gt;
 mjsonrpc_db_paste([&amp;quot;/equipment/rpcexample/settings/array[4,5,8-10]&amp;quot;], [ [4,5,8,9] ]).then(function(rpc) { ...&lt;br /&gt;
results in an error (rpc.result.status= 315) i.e. DB_TYPE_MISMATCH because there aren&#039;t enough data words supplied (4) for the number of indices (5).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;array name only&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
==== Array name only supplied ====&lt;br /&gt;
If you supply just the array name, then you do not need to supply the same number of elements as the array length. For example,&lt;br /&gt;
 mjsonrpc_db_paste([&amp;quot;/equipment/rpcexample/settings/array&amp;quot;],[ [7,6,0] ]).then(function(rpc){ ...&lt;br /&gt;
will write the first three elements of the array to 7,6,0. Other array elements will be untouched. In this case, there is only one status value for the whole array. &lt;br /&gt;
: Array= 7,6,0,1,4,5,0,0,8,9,10,11 &lt;br /&gt;
: Set Status = 1   (rpc.result.status)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Set all elements to one value ====&lt;br /&gt;
If you want to set all 19 elements of an array to 1, you can write&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mjsonrpc_db_paste([&amp;quot;/equipment/rpcexample/settings/array[0-18]&amp;quot;], [1]).then(function(rpc) { ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
or to set a group of indices to 999, you can write&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mjsonrpc_db_paste([&amp;quot;/equipment/rpcexample/settings/array[1-3,4,5,8-10]&amp;quot;], [999]).then(function(rpc) { ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the single value is written as [999] rather than as an array with single value, i.e. [ [999] ].&lt;br /&gt;
&lt;br /&gt;
=== Reading an array ===&lt;br /&gt;
In the same way, you can read all or part of an array.  See above for [[#Supported array index syntax]].&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
var array = new Array();&lt;br /&gt;
mjsonrpc_db_get_values([&amp;quot;/Runinfo&amp;quot;,&amp;quot;/Experiment/name&amp;quot;,&amp;quot;/Equipment/rpcexample/Settings/array&amp;quot;,&amp;quot;/Equipment/rpcexample/Settings/array[3-6,11]&amp;quot;]).then(function(rpc) {&lt;br /&gt;
      document.getElementById(&amp;quot;status&amp;quot;).innerHTML = &#039;Status : &#039;+ result.status  &lt;br /&gt;
      var runinfo= rpc.result.data[0] &lt;br /&gt;
      var name =  rpc.result.data[1]&lt;br /&gt;
      array = rpc.result.data[2]   // whole array&lt;br /&gt;
      document.getElementById(&amp;quot;array&amp;quot;).innerHTML =&#039;Array=&#039;+ array&lt;br /&gt;
      array=rpc.result.data[3]    // array indices&lt;br /&gt;
      document.getElementById(&amp;quot;array_ele&amp;quot;).innerHTML =&#039;Array elements=&#039;+ array&lt;br /&gt;
}).catch(function(error) {&lt;br /&gt;
   mjsonrpc_error_alert(error);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This example gives &lt;br /&gt;
: Array=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0&lt;br /&gt;
: Array elements=4,5,6,7,12&lt;br /&gt;
: Status :  1,1,1,1,1,1,1,1  (rpc.result.status)&lt;br /&gt;
Note that the &amp;quot;Array elements&amp;quot; line has read the contents of indices 3-6 and 11 as requested (5 indices in total). The status array contains 8 values. The last 5 values are the status from reading the 5 array elements.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Schema (List of all RPC methods) ==&lt;br /&gt;
&lt;br /&gt;
The MIDAS JSON RPC API is documented via an automatically generated JSON Schema.&lt;br /&gt;
&lt;br /&gt;
The JSON Schema (&amp;quot;describes your JSON data format&amp;quot;) is not a well established standard (there is no final RFC) but seems to be in common use. Multiple 3rd party tools exist&lt;br /&gt;
to visualize, explore and interface with JSON documents described by JSON Schemas. For more general information go here:&lt;br /&gt;
* http://json-schema.org/&lt;br /&gt;
* https://tools.ietf.org/html/draft-zyp-json-schema-04&lt;br /&gt;
&lt;br /&gt;
The MIDAS JSON RPC Schema is automatically generated by mhttpd and is &amp;lt;b&amp;gt;linked by the mhttpd &amp;quot;Help&amp;quot; page in JSON and in text format&amp;lt;/b&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For reference, a recent copy of the JSON RPC API Schema is pasted here from the mhttpd &amp;quot;help&amp;quot; page. For final, complete and up-to-date schema, please get your own copy from the midas &amp;quot;help&amp;quot; page.&lt;br /&gt;
&lt;br /&gt;
In this schema, &amp;quot;?&amp;quot; means an optional parameter, &amp;quot;[]&amp;quot; means an array parameter. (There is an artefact: all method names have question marks because they are optional as far as the schema generator is concerned).&lt;br /&gt;
&lt;br /&gt;
=== MIDAS JSON RPC API Schema ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
Autogenerated schema for all MIDAS JSON-RPC methods&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
al_reset_alarm?             | reset alarms&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | alarms[]             | array of alarm names&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status[]             | return status of al_reset_alarm() for each alarm&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
al_trigger_alarm?           | trigger an alarm&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | name                 | string         | alarm name&lt;br /&gt;
                            |          | message              | string         | alarm message&lt;br /&gt;
                            |          | class                | string         | alarm class&lt;br /&gt;
                            |          | condition            | string         | alarm condition&lt;br /&gt;
                            |          | type                 | integer        | alarm type (AT_xxx)&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of al_trigger_alarm()&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
al_trigger_class?           | trigger an alarm&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | class                | string         | alarm class&lt;br /&gt;
                            |          | message              | string         | alarm message&lt;br /&gt;
                            |          | first?               | bool           | see al_trigger_class() in midas.c&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of al_trigger_class()&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
bm_receive_event?           | read event buffers&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | buffer_name          | string         | name of event buffer&lt;br /&gt;
                            |          | event_id?            | integer        | requested event id, -1 means any event id&lt;br /&gt;
                            |          | trigger_mask?        | integer        | requested trigger mask, -1 means any trigger mask&lt;br /&gt;
                            |          | get_recent?          | bool           | get last available event that matches this event request&lt;br /&gt;
                            |          | last_event_header[]? | do not resend an event we already received: event header of last received event [event_id,trigger_mask,serial_number,time_stamp]&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
                            |          | timeout_millisec?    | number         | how long to wait for an event&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | binary data          | arraybuffer    | binary event data&lt;br /&gt;
                            |          | status               | integer        | return status of bm_open_buffer(), bm_request_event(), bm_set_cache_size(), bm_receive_alloc()&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
cm_exist?                   | calls MIDAS cm_exist() to check if given MIDAS program is running&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | name                 | string         | name of the program, corresponding to ODB /Programs/name&lt;br /&gt;
                            |          | unique?              | bool           | bUnique argument to cm_exist()&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of cm_exist()&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
cm_msg1?                    | Generate a midas message using cm_msg1()&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | facility?            | string         | message facility, default is &amp;quot;midas&amp;quot;&lt;br /&gt;
                            |          | user?                | string         | message user, default is &amp;quot;javascript_commands&amp;quot;&lt;br /&gt;
                            |          | type?                | integer        | message type, MT_xxx from midas.h, default is MT_INFO&lt;br /&gt;
                            |          | message              | string         | message text&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of cm_msg1()&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
cm_msg_facilities?          | get message facilities using cm_msg_facilities()&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of cm_msg_facilities()&lt;br /&gt;
                            |          | facilities[]         | array of facility names&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
cm_msg_retrieve?            | Retrieve midas messages using cm_msg_retrieve2()&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | facility?            | string         | message facility, default is &amp;quot;midas&amp;quot;&lt;br /&gt;
                            |          | min_messages?        | integer        | get at least this many messages, default is 1&lt;br /&gt;
                            |          | time?                | number         | start from given timestamp, value 0 means give me newest messages, default is 0&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | num_messages         | integer        | number of messages returned&lt;br /&gt;
                            |          | messages             | string         | messages separated by \n&lt;br /&gt;
                            |          | status               | integer        | return status of cm_msg_retrieve2()&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
cm_shutdown?                | calls MIDAS cm_shutdown() to stop given MIDAS program&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | name                 | string         | name of the program, corresponding to ODB /Programs/name&lt;br /&gt;
                            |          | unique?              | bool           | bUnique argument to cm_shutdown()&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of cm_shutdown()&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
cm_transition?              | start and stop runs&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | transition           | string         | requested transition: TR_START, TR_STOP, TR_PAUSE, TR_RESUME&lt;br /&gt;
                            |          | run_number?          | integer        | New run number, value 0 means /runinfo/run_number + 1, default is 0&lt;br /&gt;
                            |          | async_flag?          | integer        | Transition type. Default is multithreaded transition TR_MTHREAD&lt;br /&gt;
                            |          | debug_flag?          | integer        | See cm_transition(), value 1: trace to stdout, value 2: trace to midas.log&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of cm_transition()&lt;br /&gt;
                            |          | error_string?        | string         | return error string from cm_transition()&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
db_copy?                    | get complete ODB data in the &amp;quot;save&amp;quot; json encoding, suitable for reloading with odbedit command &amp;quot;load&amp;quot;&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | paths[]              | array of ODB subtree paths&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | data[]               | keys and values of ODB data for each path&lt;br /&gt;
                            |          |                      | array of       | object     &lt;br /&gt;
                            |          | status[]             | return status of db_copy_json_save() for each path&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
db_create?                  | Create new ODB entries&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params[] | array of ODB paths to be created&lt;br /&gt;
                            |          | array of             | arguments to db_create_key() and db_set_num_values()&lt;br /&gt;
                            |          |                      | path           | string      | ODB path to be created&lt;br /&gt;
                            |          |                      | type           | integer     | MIDAS TID_xxx type&lt;br /&gt;
                            |          |                      | array_length?  | integer     | optional array length, default is 1&lt;br /&gt;
                            |          |                      | string_length? | integer     | for TID_STRING, optional string length, default is NAME_LENGTH&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status[]             | return status of db_create_key(), db_set_num_values() and db_set_data() (for TID_STRING) for each path&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
db_delete?                  | delete ODB keys&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | paths[]              | array of ODB paths to delete&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status[]             | return status of db_delete_key() for each path&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
db_get_values?              | get values of ODB data from given subtrees&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | paths[]              | array of ODB subtree paths, see note on array indices&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | omit_names?          | bool           | omit the /name entries&lt;br /&gt;
                            |          | omit_last_written?   | bool           | omit the /last_written entries and the last_written[] result&lt;br /&gt;
                            |          | omit_tid?            | bool           | omit the tid[] result&lt;br /&gt;
                            |          | omit_old_timestamp?  | number         | omit data older than given ODB timestamp&lt;br /&gt;
                            |          | preserve_case?       | bool           | preserve the capitalization of ODB key names (WARNING: ODB is not case sensitive); note that this will also have side effect of setting the omit_names option&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | data[]               | values of ODB data for each path, all key names are in lower case, all symlinks are followed&lt;br /&gt;
                            |          |                      | array of       | any        &lt;br /&gt;
                            |          | status[]             | return status of db_copy_json_values() or db_copy_json_index() for each path&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
                            |          | tid[]?               | odb type id for each path, absent if omit_tid is true&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
                            |          | last_written[]?      | last_written value of the ODB subtree for each path, absent if omit_last_written is true&lt;br /&gt;
                            |          |                      | array of       | number     &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
db_key?                     | get ODB keys&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | paths[]              | array of ODB paths&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status[]             | return status of db_key() for each path&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
                            |          | keys[]               | key data for each path&lt;br /&gt;
                            |          |                      | array of       | object     &lt;br /&gt;
                            |          | keys[]               | key type TID_xxx&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
                            |          | keys[]               | array length, 1 for normal entries&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
                            |          | keys[]               | key name&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | keys[]               | data total size in bytes&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
                            |          | keys[]               | array element size, string length for TID_STRING&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
                            |          | keys[]               | access mode bitmap of MODE_xxx&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
                            |          | keys[]               | number of hotlinks attached to this key&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
                            |          | keys[]               | timestamp when data was last updated&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
db_link?                    | Create ODB symlinks&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | new_links[]          | array of new symlinks to be created&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | target_paths[]       | array of existing ODB paths for each link&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status[]             | return status of db_create_link() for each path&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
db_load?                    | Save ODB subtree to file&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | filename             | string         | Filename to read ODB contents from&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of db_load&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
db_ls?                      | get contents of given ODB subdirectory in the &amp;quot;ls&amp;quot; json encoding - similar to odbedit command &amp;quot;ls -l&amp;quot;&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | paths[]              | array of ODB subtree paths&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | data[]               | keys and values of ODB data for each path&lt;br /&gt;
                            |          |                      | array of       | object     &lt;br /&gt;
                            |          | status[]             | return status of db_copy_json_ls() for each path&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
db_paste?                   | write data into ODB&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | paths[]              | array of ODB subtree paths, see note on array indices&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | values[]             | array of data values written to ODB via db_paste_json() for each path&lt;br /&gt;
                            |          |                      | array of       | any        &lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status[]             | array of return status of db_paste_json() for each path&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
db_rename?                  | Change size of ODB arrays&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | paths[]              | array of ODB paths to rename&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | new_names[]          | array of new names for each ODB path&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status[]             | return status of db_rename_key() for each path&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
db_reorder?                 | Change order of ODB keys in a subdirectory&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | paths[]              | array of new symlinks to be created&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | indices[]            | array of existing ODB paths for each link&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status[]             | return status of db_reorder_key() for each path&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
db_resize?                  | Change size of ODB arrays&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | paths[]              | array of ODB paths to resize&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | new_lengths[]        | array of new lengths for each ODB path&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status[]             | return status of db_set_num_values() for each path&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
db_resize_string?           | Change size of ODB string arrays&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | paths[]              | array of ODB paths to resize&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | new_lengths[]        | array of new lengths for each ODB path&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
                            |          | new_string_lengths[] | array of new string lengths for each ODB path&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status[]             | return status of db_resize_string() for each path&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
db_save?                    | Save ODB subtree to file&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | path                 | string         | ODB path&lt;br /&gt;
                            |          | filename             | string         | Filename so save ODB contents to&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of db_save&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
db_scl?                     | Show ODB clients&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | scl                  | json           | return value of db_scl()&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
db_sor?                     | Show ODB open records starting from given ODB path&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | path?                | string         | ODB path&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | sor                  | json           | return value of db_sor()&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
el_delete?                  | Delete elog message&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | tag                  | string         | tag of message to delete&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of el_delete&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
el_query?                   | Query elog messages&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | last_n_hours?        | integer        | return messages from the last N hours&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of el_retrieve&lt;br /&gt;
                            |          | msg[]                | message tag&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
el_retrieve?                | Get an elog message&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | tag                  | string         | elog message tag&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of el_retrieve&lt;br /&gt;
                            |          | msg.tag              | string         | message tag&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
exec_script?                | execute custom script defined in ODB /Script (scripts show in the menu) or /CustomScript (scripts from custom pages)&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | script?              | string         | Execute ODB /Script/xxx&lt;br /&gt;
                            |          | customscript?        | string         | Execute ODB /CustomScript/xxx&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of cm_exec_script()&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
ext_list_files?             | js_ext_list_files&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | subdir               | string         | List files in experiment_directory/userfiles/subdir&lt;br /&gt;
                            |          | fileext              | string         | Filename extension&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of midas library calls&lt;br /&gt;
                            |          | path                 | string         | Search path&lt;br /&gt;
                            |          | subdirs[]            | list of subdirectories&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | files[]              | script filename&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | files[]              | script description&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
ext_read_file?              | js_ext_read_script&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | filename             | string         | File name, read from experiment_directory/userfiles/filename&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | content              | string         | ASCII file content&lt;br /&gt;
                            |          | status               | integer        | return status of midas library calls&lt;br /&gt;
                            |          | error                | string         | error text&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
ext_save_file?              | js_ext_save_file&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | filename             | string         | File name, save in experiment_directory/userfiles/filename&lt;br /&gt;
                            |          | script               | string         | ASCII content&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of midas library calls&lt;br /&gt;
                            |          | error                | string         | error text&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
get_alarms?                 | get alarm data&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | get_all?             | bool           | get all alarms, even in alarm system not active and alarms not triggered&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of midas library calls&lt;br /&gt;
                            |          | alarm_system_active  | bool           | value of ODB &amp;quot;/Alarms/alarm system active&amp;quot;&lt;br /&gt;
                            |          | alarms               | object         | alarm data, keyed by alarm name&lt;br /&gt;
                            |          | alarms[]             | alarm is triggered&lt;br /&gt;
                            |          |                      | array of       | bool       &lt;br /&gt;
                            |          | alarms[]             | alarm is enabled&lt;br /&gt;
                            |          |                      | array of       | bool       &lt;br /&gt;
                            |          | alarms[]             | alarm class&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | alarms[]             | alarm type AT_xxx&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
                            |          | alarms[]             | display background color&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | alarms[]             | display foreground color&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | alarms[]             | alarm ODB message field&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | alarms[]             | alarm ODB condition field&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | alarms[]             | evaluated alarm condition (AT_EVALUATED alarms only)&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | alarms[]             | next time the periodic alarm will fire (AT_PERIODIC alarms only)&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | alarms[]             | time when alarm was triggered&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | alarms[]             | final alarm text shown to user by mhttpd&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
get_debug?                  | get current value of mjsonrpc_debug&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | any                  | there are no input parameters&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | integer              | current value of mjsonrpc_debug&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
get_http_trace?             | get current value of mhttpd http_trace&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | any                  | there are no input parameters&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | integer              | current value of http_trace&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
get_schema?                 | Get the MIDAS JSON-RPC schema JSON object&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | any                  | there are no input parameters&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | object               | returns the MIDAS JSON-RPC schema JSON object&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
get_sleep?                  | get current value of mjsonrpc_sleep&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | any                  | there are no input parameters&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | integer              | current value of mjsonrpc_sleep&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
get_time?                   | get current value of mjsonrpc_time&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | any                  | there are no input parameters&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | integer              | current value of mjsonrpc_time&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
get_timezone?               | get current server timezone offset in seconds&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | any                  | there are no input parameters&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | integer              | offset in seconds&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
hs_get_active_events?       | get list of active history events using hs_read_event_list()&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of hs_read_event_list()&lt;br /&gt;
                            |          | events[]             | array of history event names&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
hs_get_channels?            | get list of history channels in /Logger/History&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of hs_get_events()&lt;br /&gt;
                            |          | default_channel      | string         | name of the default logger history channel in /History/LoggerHistoryChannel&lt;br /&gt;
                            |          | channels[]           | logger history channel names&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
hs_get_events?              | get list of history events that existed at give time using hs_get_events()&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | channel?             | string         | midas history channel, default is the default reader channel&lt;br /&gt;
                            |          | time?                | number         | timestamp, value 0 means current time, default is 0&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of hs_get_events()&lt;br /&gt;
                            |          | channel              | string         | logger history channel name&lt;br /&gt;
                            |          | events[]             | array of history event names&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
hs_get_last_written?        | get list of history tags for given history events that existed at give time using hs_get_last_written()&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | channel?             | string         | midas history channel, default is the default reader channel&lt;br /&gt;
                            |          | time?                | number         | timestamp, value 0 means current time, default is 0&lt;br /&gt;
                            |          | events[]             | array of history event names&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | tags[]               | array of history event tag names&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | index[]              | array of history event tag array indices&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status&lt;br /&gt;
                            |          | channel              | string         | logger history channel name&lt;br /&gt;
                            |          | last_written[]       | array of last-written times for each history event&lt;br /&gt;
                            |          |                      | array of       | number     &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
hs_get_tags?                | get list of history tags for given history events that existed at give time using hs_get_tags()&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | channel?             | string         | midas history channel, default is the default reader channel&lt;br /&gt;
                            |          | time?                | number         | timestamp, value 0 means current time, default is 0&lt;br /&gt;
                            |          | events[]?            | array of history event names, default is get all events using hs_get_events()&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status&lt;br /&gt;
                            |          | channel              | string         | logger history channel name&lt;br /&gt;
                            |          | events[]             | array of history event names for each history event&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | events[]             | array of status ohistory tags for each history event&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
                            |          | events[]             | array of history tags for each history event&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | events[]             | history tag name&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | events[]             | history tag midas data type&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
                            |          | events[]             | history tag number of array elements, omitted if 1&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
hs_image_retrieve?          | Get a list of history image files&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | image?               | string         | image name as defined under /History/Images/&amp;lt;image&amp;gt;&lt;br /&gt;
                            |          | start_time           | number         | start time of the data&lt;br /&gt;
                            |          | end_time             | number         | end time of the data&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | time[]               | array of time stamps in seconds&lt;br /&gt;
                            |          |                      | array of       | arraybuffer&lt;br /&gt;
                            |          | filename[]           | array of file names&lt;br /&gt;
                            |          |                      | array of       | arraybuffer&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
hs_read?                    | get history data for given history events that existed at give time using hs_read_buffer()&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | channel?             | string         | midas history channel, default is the default reader channel&lt;br /&gt;
                            |          | start_time           | number         | start time of the data&lt;br /&gt;
                            |          | end_time             | number         | end time of the data&lt;br /&gt;
                            |          | events[]             | array of history event names&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | tags[]               | array of history event tag names&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | index[]              | array of history event tag array indices&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status&lt;br /&gt;
                            |          | channel              | string         | logger history channel name&lt;br /&gt;
                            |          | data[]               | array of history data&lt;br /&gt;
                            |          |                      | array of       | array      &lt;br /&gt;
                            |          | data[]               | status for each event&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
                            |          | data[]               | number of data for each event&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
                            |          | data[]               | time data&lt;br /&gt;
                            |          |                      | array of       | number     &lt;br /&gt;
                            |          | data[]               | value data&lt;br /&gt;
                            |          |                      | array of       | number     &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
hs_read_arraybuffer?        | get history data for given history events that existed at give time using hs_read_buffer()&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | channel?             | string         | midas history channel, default is the default reader channel&lt;br /&gt;
                            |          | start_time           | number         | start time of the data&lt;br /&gt;
                            |          | end_time             | number         | end time of the data&lt;br /&gt;
                            |          | events[]             | array of history event names&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | tags[]               | array of history event tag names&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | index[]              | array of history event tag array indices&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | binary data          | arraybuffer    | binary data, see documentation&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
hs_read_binned?             | get history data for given history events that existed at give time using hs_read_buffer()&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | channel?             | string         | midas history channel, default is the default reader channel&lt;br /&gt;
                            |          | start_time           | number         | start time of the data&lt;br /&gt;
                            |          | end_time             | number         | end time of the data&lt;br /&gt;
                            |          | num_bins             | integer        | number of time bins&lt;br /&gt;
                            |          | events[]             | array of history event names&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | tags[]               | array of history event tag names&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | index[]              | array of history event tag array indices&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status&lt;br /&gt;
                            |          | channel              | string         | logger history channel name&lt;br /&gt;
                            |          | data[]               | array of history data&lt;br /&gt;
                            |          |                      | array of       | array      &lt;br /&gt;
                            |          | data[]               | status for each event&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
                            |          | data[]               | number of data points for each event&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
                            |          | data[]               | number of data points for each bin&lt;br /&gt;
                            |          |                      | array of       | integer    &lt;br /&gt;
                            |          | data[]               | mean for each bin&lt;br /&gt;
                            |          |                      | array of       | number     &lt;br /&gt;
                            |          | data[]               | rms for each bin&lt;br /&gt;
                            |          |                      | array of       | number     &lt;br /&gt;
                            |          | data[]               | minimum value for each bin&lt;br /&gt;
                            |          |                      | array of       | number     &lt;br /&gt;
                            |          | data[]               | maximum value for each bin&lt;br /&gt;
                            |          |                      | array of       | number     &lt;br /&gt;
                            |          | data[]               | time of last data entry&lt;br /&gt;
                            |          |                      | array of       | number     &lt;br /&gt;
                            |          | data[]               | value of last data entry&lt;br /&gt;
                            |          |                      | array of       | number     &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
hs_read_binned_arraybuffer? | get history data for given history events that existed at give time using hs_read_buffer()&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | channel?             | string         | midas history channel, default is the default reader channel&lt;br /&gt;
                            |          | start_time           | number         | start time of the data&lt;br /&gt;
                            |          | end_time             | number         | end time of the data&lt;br /&gt;
                            |          | num_bins             | integer        | number of time bins&lt;br /&gt;
                            |          | events[]             | array of history event names&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | tags[]               | array of history event tag names&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | index[]              | array of history event tag array indices&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | binary data          | arraybuffer    | binary data, see documentation&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
hs_reopen?                  | reopen the history channel to make sure we see the latest list of events using hs_clear_cache()&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | channel?             | string         | midas history channel, default is the default reader channel&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of hs_get_events()&lt;br /&gt;
                            |          | channel              | string         | logger history channel name&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
jrpc?                       | make RPC call into frontend program via RPC_JRPC&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | client_name          | string         | Connect to this MIDAS client, see cm_connect_client()&lt;br /&gt;
                            |          | cmd                  | string         | Command passed to client&lt;br /&gt;
                            |          | args                 | string         | Parameters passed to client as a string, could be JSON encoded&lt;br /&gt;
                            |          | max_reply_length?    | integer        | Optional maximum length of client reply. MIDAS RPC does not support returning strings of arbitrary length, maximum length has to be known ahead of time.&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | reply                | string         | Reply from client as a string, could be JSON encoded&lt;br /&gt;
                            |          | status               | integer        | return status of cm_connect_client() and rpc_client_call()&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
null?                       | RPC method always returns null&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | any                  | method parameters are ignored&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | null                 | always returns null&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
seq_list_files?             | js_seq_list_files&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | subdir               | string         | List files in /Seq/State/Path/subdir&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of midas library calls&lt;br /&gt;
                            |          | path                 | string         | Search path&lt;br /&gt;
                            |          | subdirs[]            | list of subdirectories&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | files[]              | script filename&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
                            |          | files[]              | script description&lt;br /&gt;
                            |          |                      | array of       | string     &lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
seq_save_script?            | js_seq_save_script&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | filename             | string         | Script file name&lt;br /&gt;
                            |          | script               | string         | Script text&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of midas library calls&lt;br /&gt;
                            |          | error                | string         | error text&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
set_debug?                  | set new value of mjsonrpc_debug&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | integer              | new value of mjsonrpc_debug&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | integer              | new value of mjsonrpc_debug&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
set_http_trace?             | set new value of mhttpd http_trace&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | integer              | new value of http_trace&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | integer              | new value of http_trace&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
set_sleep?                  | set new value of mjsonrpc_sleep&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | integer              | new value of mjsonrpc_sleep&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | integer              | new value of mjsonrpc_sleep&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
set_time?                   | set new value of mjsonrpc_time&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | integer              | new value of mjsonrpc_time&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | integer              | new value of mjsonrpc_time&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
ss_millitime?               | get current MIDAS time using ss_millitime()&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | any                  | there are no input parameters&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | integer              | current value of ss_millitime()&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
start_program?              | start MIDAS program defined in ODB /Programs/name&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | name                 | string         | name of the program, corresponding to ODB /Programs/name&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | return status of ss_system()&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
user_example1?              | example of user defined RPC method that returns up to 3 results&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | arg                  | string         | example string argment&lt;br /&gt;
                            |          | optional_arg?        | integer        | optional example integer argument&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | string               | string         | returns the value of &amp;quot;arg&amp;quot; parameter&lt;br /&gt;
                            |          | integer              | integer        | returns the value of &amp;quot;optional_arg&amp;quot; parameter&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
user_example2?              | example of user defined RPC method that returns more than 3 results&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | arg                  | string         | example string argment&lt;br /&gt;
                            |          | optional_arg?        | integer        | optional example integer argument&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | string1              | string         | returns the value of &amp;quot;arg&amp;quot; parameter&lt;br /&gt;
                            |          | string2              | string         | returns &amp;quot;hello&amp;quot;&lt;br /&gt;
                            |          | string3              | string         | returns &amp;quot;world!&amp;quot;&lt;br /&gt;
                            |          | value1               | integer        | returns the value of &amp;quot;optional_arg&amp;quot; parameter&lt;br /&gt;
                            |          | value2               | number         | returns 3.14&lt;br /&gt;
-----------------------------------------------------------------------------------------------&lt;br /&gt;
user_example3?              | example of user defined RPC method that returns an error&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | params   | arg                  | integer        | integer value, if zero, throws a JSON-RPC error&lt;br /&gt;
                            | -----------------------------------------------------------------&lt;br /&gt;
                            | result   | status               | integer        | returns the value of &amp;quot;arg&amp;quot; parameter&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
[[Category:Javascript library]]&lt;/div&gt;</summary>
		<author><name>Zaher</name></author>
	</entry>
</feed>