Demo Discussion
Forum Config Examples Contributions Vulnerabilities
  Contributions to ELOG, Page 5 of 6  Not logged in ELOG logo
ID Date Author Author Email Category Subject Statusdown Last Revision
  15   Thu Jul 28 18:42:48 2005 Emiliano GabrielliAlberT@SuperAlberT.itOther[New Feature]: JS calendar filter BetaThu Aug 4 11:20:36 2005 by Emiliano Gabrielli
NOTE:
it seems that for some strange reason it slows down elog very much when and only when elog is stunneled over ssl!


The attached tarball contains a full featured JavaScript allowing everyone to use a JS calendar (no popup windows, just JS and CSS!) to perform date-based filtering actions. An uncompressed version and the tarball for the last cvs rvision of this script is available at www.SuperAlberT.it

You can browse the ChangeLog here.

A simple way to use it is to uncompress the wall package into the elog data dir, under the "scripts" subdir.

the you can add the following code to your elog.cfg:
Filter Menu text = scripts/calendar_filter/calendar_filter.html

note that this configuration parameter is available in elog starting from
Revision 1.732 2005/07/29

and automagically have the new calendar_filter icon showed Smile

Attachment 2: elog_calendar_filter-1.0.1.tar.gz
  18   Mon Sep 25 11:24:05 2006 Yoshio ImaiDocumentationsecuring of elog with stunnel v4 under LinuxBeta 
The following instructions should work in securing the elog using stunnel version 4 under Linux. The specific paths may have to be adapted to your distribution. A sample configuration file is attached.
Attachment 1: elog-stunnel4.howto
1. Prepare a certificate
------------------------
either: request a certificate for your elog URL from your web administrator
- the private key must not be password-protected
- the 'common name' must be the URL of your elog server

or: create a self-signed certificate yourself with the OpenSSL package
- as root user, create a self-signed certificate with the command

root@localhost:# openssl req -new -x509 -config /etc/ssl/openssl.cnf -keyout stunnel.pem -out stunnel.pem -days 365 -nodes

- this creates a self-signed certificate (-x509) whith one year validity (-days 365)
  and no password protection for the private key (-nodes)
- private key and certificate are written to the same file, "stunnel.pem"

Answer all questions, making sure that the 'common name' is the URL under which users
are to reach your elog server.

For more information on how to create and/or manage SSL certificates, see e.g.
http://www.ibiblio.org/pub/Linux/docs/HOWTO/SSL-Certificates-HOWTO

Notice: Unless your web administrator can procure a certificate signed by an established
        CA, your elog users will be asked if they want to accept your (unverifiable) certificate
        when connecting to your elog server. This is no problem at all but can lead to
        questions if your users are unsure about this.


2. Adapt the certificate file to stunnel4 conventions
-----------------------------------------------------
The certificate filename must be the MD5 checksum:
- Retrieve the MD5 checksum of your certificate with

root@localhost:# openssl x509 -hash -noout -in stunnel.pem 

abcdefgh

- Rename the certificate file accordingly

root@localhost:# mv stunnel.pem abcdefgh.0

- Move the certificate file to the standard location, e.g. /etc/ssl/certs
- change the permissions of the file to -rw-------
- make sure there is a blank line between
  -----END RSA PRIVATE KEY----- and -----BEGIN CERTIFICATE-----
  and a blank line after
  -----END CERTIFICATE-----
  in your certificate file.


3. Configure stunnel4
---------------------
Install the stunnel4 package (if not already done).
Modify the configuration file (e.g. /etc/stunnel/stunnel.conf, depending on your
distribution):

- general options:
  cert = /etc/ssl/certs/abcdefgh.0    ; put the name of your certificate file here
  debug = 4                           ; otherwise ALL connection attempts will be logged to your syslog
  pid = /var/run/stunnel4/stunnel.pid ; check where the other services write their pid-files, depends 
                                      ; somewhat on the distribution

- comment out all lines containing chroot options
- comment out all CA lines
- comment out all service sections except the HTTPS section, which should look as follows

[https]
accept  = 443       ; i.e. stunnel listens on port 443, the standard https port
connect = 8080      ; and forwards all connections to port 8080 (use the port under which
                    ; your elogd is running here!)
TIMEOUTclose = 0    ; for buggy MS Internet Explorers, see the stunnel4 manpage


Some Linux distributions require that in the file /etc/defaults/stunnel4 the option ENABLED be set
to ENABLED=1. If not, the stunnel will not be started at system bootup.


4. Start the stunnel4 server
----------------------------
root@localhost# stunnel4 /etc/stunnel/stunnel.conf

Your elog should now be accessible via

https://your.elog.server
Attachment 2: stunnel.conf
cert = /etc/ssl/certs/abcdefgh.0
pid = /var/run/stunnel4/stunnel.pid

; Some performance tunings
socket = l:TCP_NODELAY=1
socket = r:TCP_NODELAY=1

; Some debugging stuff useful for troubleshooting
debug = 4

; Service-level configuration
[https]
accept  = 443
connect = 8080
TIMEOUTclose = 0
  22   Wed Jul 11 11:13:16 2007 Peter Rienstrapeter.rienstra@gmail.comOtherCompiling elogd.c on HP-UX 64 bitBetaThu Jul 12 09:38:47 2007 by Peter Rienstra
We succeeded in compiling and running elogd (elog-2.6.5) on HP-UX 64 bit Itanium platform (HP-UX B.11.23 U ia64).

The main problem was we got a core dump after starting elogd. The cause was that the memory has be allocated with a 4 byte boundary. This could be the case on other 64 bit platforms as well. A colleague of mine (Sander Notting) found the solution.

Unzip and untar the zip file (elog-latest.tar.gz)
Go to the src directory (elog-2.6.5/src)

Edit elogd.c

Replace all:

show_selection_page(NULL); => show_selection_page();
seteuid => setuid
setegid => setgid

On line 564:
void *buffer => char *buffer


Line 645, add the text in bold:

void *xmalloc(size_t bytes)
{
char *temp;

/* Align buffer on 4 byte boundery for HP UX and other 64 bit systems to prevent Bus error(core dump)*/
if (bytes & 3)
bytes += 4 - (bytes & 3);


temp = (char *) malloc(bytes + 12);


After that compile:

cc -w -c -o regex.o regex.c
cc -w -c -o mxml.o ../../mxml/mxml.c
cc -w -c -o strlcpy.o ../../mxml/strlcpy.c
cc -I../../mxml -o elogd elogd.c regex.o mxml.o strlcpy.o

We didn't try to run elogd under root yet.
Attachment 1: elogdhpux64.c.gz
  23   Fri Jul 13 12:36:45 2007 Stefan Rittstefan.ritt@psi.chOtherRe: Compiling elogd.c on HP-UX 64 bitBetaThu Jul 12 09:38:47 2007 by Peter Rienstra
I applied most of your patches to the elog source code, SVN revision 1885. The only missing piece has to do with seteuid/setuid. I definitively need seteuid for linux, because elogd might be started under root, then it falls back to an optional elog user. But when it stops, it has to restore the original root user in order to delete the PID file (/var/run/elogd.pid) which was created under root. If seteuid does not exist under HP-UX, you should add something like
#ifdef HP-UX
  setuid(...)
#else
  seteuid(...)
#endif

Probably the HP-UX has to be something else, but I cannot test this since I don't have such an OS here. Once you get this working I can put it into the standard distribution.
  24   Mon Jul 16 15:27:08 2007 Peter Rienstrapeter.rienstra@gmail.comOtherRe: Compiling elogd.c on HP-UX 64 bitBetaThu Jul 12 09:38:47 2007 by Peter Rienstra
Stefan,

First I want to say I really like your program. We work in a small group of 5 database administrators, and this is exactly what we need to inform each other. Elog is simple but very functional, so thanks!


My problem is that I don't have root access to the HP-UX machines. We don't run elogd as root, so I wasn't really interested in the seteuid functionality, I just wanted to compile and run the program.

HP-UX doesn't have the "seteuid" and "setegid" functions. But there are "setuid+setgid", "setreuid+setregid" and "setresuid+setresgid" functions available. I'm not sure which one is the best to use. I uploaded the manpages as attachment. I hope this will help you.

If you want I can do a compile and run test on HP-UX with your altered source code. But I can't do a test with "root".




Stefan Ritt wrote:
I applied most of your patches to the elog source code, SVN revision 1885. The only missing piece has to do with seteuid/setuid. I definitively need seteuid for linux, because elogd might be started under root, then it falls back to an optional elog user. But when it stops, it has to restore the original root user in order to delete the PID file (/var/run/elogd.pid) which was created under root. If seteuid does not exist under HP-UX, you should add something like
#ifdef HP-UX
  setuid(...)
#else
  seteuid(...)
#endif

Probably the HP-UX has to be something else, but I cannot test this since I don't have such an OS here. Once you get this working I can put it into the standard distribution.
Attachment 1: man_setuid.txt


 setuid(2)							   setuid(2)




 NAME
      setuid(), setgid() - set user and group IDs

 SYNOPSIS
      #include <unistd.h>

      int setuid(uid_t uid);

      int setgid(gid_t gid);

 DESCRIPTION
      setuid() sets the real-user-ID (ruid), effective-user-ID (euid),
      and/or saved-user-ID (suid) of the calling process.  If the Security
      Containment product is installed, these interfaces treat a process
      observing CHSUBJIDENT as a privileged process.  Otherwise, only
      processes with an euid of zero are treated as privileged processes.
      See privileges(5) for more information on Security Containment and
      fine-grained privileges.

      The following conditions govern setuid's behavior:

	   +  If the process is privileged, setuid() sets the ruid, euid,
	      and suid to uid.

	   +  If the process is not privileged and the argument uid is equal
	      to the ruid or the suid, setuid() sets the euid to uid; the
	      ruid and suid remain unchanged.  (If a set-user-ID program is
	      not running as superuser, it can change its euid to match its
	      ruid and reset itself to the previous euid value.)

	   +  If the process is not privileged, the argument uid is equal to
	      the euid, and the calling process has the PRIV_SETRUGID
	      privilege, setuid() sets the ruid to uid; the euid and suid
	      remain unchanged.

      setgid() sets the real-group-ID (rgid), effective-group-ID (egid),
      and/or saved-group-ID (sgid) of the calling process.  The following
      conditions govern setgid()'s behavior:

	   +  If the process is privileged, setgid() sets the rgid and egid
	      to gid.

	   +  If the process is not privileged and the argument gid is equal
	      to the rgid or the sgid, setgid() sets the egid to gid; the
	      rgid and sgid remain unchanged.

	   +  If the process is not privileged, the argument gid is equal to
	      the egid, and the calling process has the PRIV_SETRUGID
	      privilege, setgid() sets the rgid to gid; the egid and sgid
	      remain unchanged.




 Hewlett-Packard Company	    - 1 -      HP-UX 11i Version 2: May 2006






 setuid(2)							   setuid(2)




    Security Restrictions
      Some or all of the actions associated with this system call require
      the CHSUBJIDENT privilege.  Processes owned by the superuser have this
      privilege.  Processes owned by other users may have this privilege,
      depending on system configuration.

      See privileges(5) for more information about privileged access on
      systems that support fine-grained privileges.

 RETURN VALUE
      Upon successful completion, setuid() and setgid() return 0; otherwise,
      they return -1 and set errno to indicate the error.

 ERRORS
      setuid() and setgid() fail and return -1 if any of the following
      conditions are encountered:

	   [EPERM]	  None of the conditions above are met.

	   [EINVAL]	  uid (gid) is not a valid user (group) ID.

 WARNINGS
      It is recommended that the PRIV_SETRUGID capability be avoided, as it
      is provided for backward compatibility.  This feature may be modified
      or dropped from future HP-UX releases.  When changing the real user ID
      and real group ID, use of setresuid() and setresgid() (see
      setresuid(2)) is recommended instead.

 AUTHOR
      setuid() was developed by AT&T, the University of California,
      Berkeley, and HP.

      setgid() was developed by AT&T.

 SEE ALSO
      exec(2), getuid(2), setresuid(2), privileges(5).

 STANDARDS CONFORMANCE
      setuid(): AES, SVID2, SVID3, XPG2, XPG3, XPG4, FIPS 151-2, POSIX.1

      setgid(): AES, SVID2, SVID3, XPG2, XPG3, XPG4, FIPS 151-2, POSIX.1













 Hewlett-Packard Company	    - 2 -      HP-UX 11i Version 2: May 2006



Attachment 2: man_setreuid.txt


 setreuid(2)							 setreuid(2)




 NAME
      setreuid - set real and effective user IDs

 SYNOPSIS
      #include <unistd.h>

      int setreuid(uid_t ruid, uid_t euid);

 DESCRIPTION
      The setreuid() function sets the real and effective user IDs of the
      current process to the values specified by the ruid and euid
      arguments. If ruid or euid is -1, the corresponding effective or real
      user ID of the current process is left unchanged.

      A process with appropriate privileges can set either ID to any value.
      An unprivileged process can only set the effective user ID if the euid
      argument is equal to either the real, effective, or saved user ID of
      the process.

      It is unspecified whether a process without appropriate privileges is
      permitted to change the real user ID to match the current real,
      effective or saved user ID of the process.

 RETURN VALUE
      Upon successful completion, 0 is returned. Otherwise, -1 is returned
      and errno is set to indicate the error.

 ERRORS
      The setreuid() function will fail if:

	   [EINVAL]		    The value of the ruid or euid argument
				    is invalid or out-of-range.

	   [EPERM]		    The current process does not have
				    appropriate privileges, and either an
				    attempt was made to change the effective
				    user ID to a value other than the real
				    user ID or the saved set-user-ID or an
				    attempt was made to change the real user
				    ID to a value not permitted by the
				    implementation.

 SEE ALSO
      getuid(2), setuid(2), <unistd.h>.

 CHANGE HISTORY
      First released in Issue 4, Version 2.







 Hewlett-Packard Company	    - 1 -   HP-UX 11i Version 2: August 2003



Attachment 3: man_setresuid.txt


 setresuid(2)							setresuid(2)




 NAME
      setresuid, setresgid - set real, effective, and saved user and group
      IDs

 SYNOPSIS
      #include <unistd.h>

      int setresuid(uid_t ruid, uid_t euid, uid_t suid);

      int setresgid(gid_t rgid, gid_t egid, gid_t sgid);

 DESCRIPTION
      setresuid() sets the real, effective and/or saved user ID of the
      calling process.

      If the current real, effective or saved user ID is equal to that of a
      user having appropriate privileges, setresuid() sets the real,
      effective and saved user IDs to ruid, euid, and suid, respectively.
      Otherwise, setresuid() only sets the real, effective, and saved user
      IDs if ruid, euid, and suid each match at least one of the current
      real, effective, or saved user IDs.

      If ruid, euid, or suid is -1, setresuid() leaves the current real,
      effective or saved user ID unchanged.

      setresgid() sets the real, effective and/or saved group ID of the
      calling process.

      If the current real, effective or saved user ID is equal to that of a
      user having appropriate privileges, setresgid() sets the real,
      effective, and saved group ID to rgid, egid, and sgid, respectively.
      Otherwise, setresgid() only sets the real, effective and saved group
      ID if rgid, egid, and sgid each match at least one of the current
      real, effective or saved group ID.

      If rgid, egid, or sgid is -1, setresgid() leaves the current real,
      effective or saved group ID unchanged.

    Security Restrictions
      Some or all of the actions associated with this system call require
      the PRIV_CHSUBJIDENT privilege (CHSUBJIDENT).  Processes owned by the
      superuser will have this privilege.  Processes owned by other users
      may have this privilege, depending on system configuration.  See
      privileges(5) for more information about privileged access on systems
      that support fine-grained privileges.

 RETURN VALUE
      Upon successful completion, setresuid() and setresgid() return 0;
      otherwise, they return -1 and set errno to indicate the error.





 Hewlett-Packard Company	    - 1 -      HP-UX 11i Version 2: May 2005






 setresuid(2)							setresuid(2)




 ERRORS
      setresuid() and setresgid() fail if any of the following conditions
      are encountered:

	   [EINVAL]	  ruid, euid, or suid (rgid, egid, or sgid) is not a
			  valid user (group) ID.

	   [EPERM]	  None of the conditions above are met.

 AUTHOR
      setresuid() and setresgid() were developed by HP.

 SEE ALSO
      exec(2), getuid(2), setuid(2).








































 Hewlett-Packard Company	    - 2 -      HP-UX 11i Version 2: May 2005



  25   Mon Jul 16 15:57:47 2007 Stefan Rittstefan.ritt@psi.chOtherRe: Compiling elogd.c on HP-UX 64 bitBetaThu Jul 12 09:38:47 2007 by Peter Rienstra

Peter Rienstra wrote:
HP-UX doesn't have the "seteuid" and "setegid" functions. But there are "setuid+setgid", "setreuid+setregid" and "setresuid+setresgid" functions available.


I had a look and found that setreuid/setregid is also available under Linux, so I use those functions instead, which should also work on HP-UX. Can you check revision 1888 (http://savannah.psi.ch/viewcvs/trunk/src/elogd.c?root=elog&rev=1888), compile it and see if you can run it at least under your non-root account.
  26   Mon Jul 16 16:43:07 2007 Peter Rienstrapeter.rienstra@gmail.comOtherRe: Compiling elogd.c on HP-UX 64 bitBetaThu Jul 12 09:38:47 2007 by Peter Rienstra

Stefan Ritt wrote:
Can you check revision 1888 (http://savannah.psi.ch/viewcvs/trunk/src/elogd.c?root=elog&rev=1888), compile it and see if you can run it at least under your non-root account.


I downloaded revision 1888. There were no problems compiling it. It's running on the HP-UX system now and everything seems to work fine. Smile
  35   Tue May 24 22:43:38 2011 JacekKdoctor99@poczta.onet.plScriptJavascript verification of simple attributes with regexpBetaTue May 24 22:46:38 2011 by JacekK

Hi,

I added possibility for a new verification of required fields in generated Javascript "function chkform()". To do this I added new logbook option "ValidPattern", in which you can set regular expression for an attribute, for example

ValidPattern HexDigits=[0-9a-fA-F]+

If there is a pattern set for required field, then in chkform() function is generated additional verification, if value of the field matches validation regexp.

Changes I made should not decrease performance of elogd. Let me know please if you can add it to regular version.

 

Jacek

Attachment 1: JScriptREVerify.patch
Index: elogd.c
===================================================================
--- elogd.c	(revision 2414)
+++ elogd.c	(working copy)
@@ -74,6 +74,8 @@
 char attr_list[MAX_N_ATTR][NAME_LENGTH];
 char attr_options[MAX_N_ATTR][MAX_N_LIST][NAME_LENGTH];
 int attr_flags[MAX_N_ATTR];
+/** Validation pattern for attribute, to test if it contains expected value */
+char attr_valid_pattern[MAX_N_ATTR][NAME_LENGTH];
 
 char attr_list_default[][NAME_LENGTH] = { "Author", "Type", "Category", "Subject", "" };
 
@@ -7033,7 +7035,7 @@
 
 int scan_attributes(char *logbook)
 /* scan configuration file for attributes and fill attr_list, attr_options
- and attr_flags arrays */
+ and attr_flags and attr_valid_pattern arrays */
 {
    char list[10000], str[NAME_LENGTH], str2[NAME_LENGTH], type[NAME_LENGTH],
        tmp_list[MAX_N_ATTR][NAME_LENGTH];
@@ -7062,11 +7064,20 @@
          }
       }
 
-      /* get options lists for attributes */
+      /* get options lists and validation patterns for attributes */
       memset(attr_options, 0, sizeof(attr_options));
+      memset(attr_valid_pattern, 0, sizeof(attr_valid_pattern));
       for (i = 0; i < n; i++) {
          n_options = 0;
 
+         sprintf(str, "ValidPattern %s", attr_list[i]);
+         if (getcfg(logbook, str, list, sizeof(list)))
+         {
+            strncpy(attr_valid_pattern[i], list, sizeof(attr_valid_pattern[i])-1);
+            attr_valid_pattern[i][sizeof(attr_valid_pattern[i])-1] = 0;
+            attr_flags[i] |= AF_HAS_VALID_PATT;
+         }
+
          sprintf(str, "Options %s", attr_list[i]);
          if (getcfg(logbook, str, list, sizeof(list)))
             n_options = strbreak(list, attr_options[i], MAX_N_LIST, ",", FALSE);
@@ -9650,6 +9661,17 @@
             rsprintf("    document.form1.%s.focus();\n", ua);
             rsprintf("    return false;\n");
             rsprintf("  }\n");
+            if (attr_flags[i] & AF_HAS_VALID_PATT) 
+            {
+              sprintf(str, loc("var validPatt=new RegExp(\"%s\");"), attr_valid_pattern[i]);
+              rsprintf("  %s\n", str);
+              rsprintf("  if (!validPatt.test(document.form1.%s.value)) {\n", ua);
+              sprintf(str, loc("Invalid value for attribute '%s'"), attr_list[i]);
+              rsprintf("    alert(\"%s\");\n", str);
+              rsprintf("    document.form1.%s.focus();\n", ua);
+              rsprintf("    return false;\n");
+              rsprintf("  }\n");
+            }
          }
       }
 
Index: elogd.h
===================================================================
--- elogd.h	(revision 2414)
+++ elogd.h	(working copy)
@@ -192,6 +192,7 @@
 #define AF_MUSERLIST         (1<<13)
 #define AF_USEREMAIL         (1<<14)
 #define AF_MUSEREMAIL        (1<<15)
+#define AF_HAS_VALID_PATT    (1<<16)
 
 /* attribute format flags */
 #define AFF_SAME_LINE              1
  38   Fri Sep 9 12:08:26 2011 Andreas Luedekeandreas.luedeke@psi.chScriptcreate incremental daily backups of logbooks for Unix/LinuxBeta 
A very simple backup utility for elog logbooks.
If you want to recover your logbook from corrupted entries, an incremental backup comes in handy:
you can just replace the corrupted files with the previous versions.
Below is a very simple wrapper to create backups of the logbook into some local directory (/logbooks_backup in
the example script). The second wrapper lists the files in a given ".tar" archive.

You would run the backup from a cron job with the line:
1 0 * * * /usr/local/elog/elog_backup_daily

This will create daily backups of modified logbook and config files and a weekly backup of the password file
/usr/local/elog/passwd.txt (if you wonder why: our passwd.txt file has more than 1 MByte and of course it
changes with every login).

elog_backup_daily (copy to /usr/local/elog) script to create tar file and remove tar files older than 90 days
exclude-logbooks  (copy to /usr/local/elog) list of files to be excluded in backup (thumbnails, etc.) 
elog_backup_listfiles (copy to /usr/local/bin) shows content of a given tar file (omits directories in list)
Attachment 1: elog_backup_daily
#!/bin/sh
# source file directory
srcd=/usr/local/elog/

# backup all files newer than 25 hours
date=$(date -d "-25hours" "+%Y%m%d %H:%M")
# backup file directory
tard=/logbooks_backup
# backup tar file name
tarf=$tard/$(date +%Y%m%d_%a.tar)
# do not backup files that match patterns in this file
excf=/usr/local/elog/exclude-logbooks
# create backup
cd $srcd
tar --ignore-case -X $excf --newer "$date" -cf $tarf . logbooks/*

# copy passwd.txt
if [ "$(date +%u)" -eq 1 ]
then
	passwd=$tard/passwd_$(date +%Y%m%d_%a.txt)
	cp $srcd/passwd.txt $passwd
	gzip -9 $passwd
fi
# delete all backups older than 90 days
find $tard -mtime +90 -name "*_???.tar"           -exec rm -f {} +
find $tard -mtime +90 -name "passwd_*_???.txt.gz" -exec rm -f {} +
Attachment 2: exclude-logbooks
*.png.png
*.gif.png
*.jpg.png
*.pdf.png
oldLogbooks/*
logbooks/elog.log
passwd.txt
ssl/*
logbooks/Backup/*
logbooks/old/*

Attachment 3: elog_backup_listfiles
tar -tf $1|grep -v "^.*/$"
  47   Sun Aug 23 21:27:00 2015 Daniel Sajdykdaniel.sajdyk@gmail.comTheme/SkinSimple themeBetaTue Sep 1 07:39:45 2015 by Daniel Sajdyk

Hello. 

I did simple theme for ELOG called "dansaj". 

This is verision which I did for my ELOG, and if you have troubles in other configurations, please let me know, and we will correct it. 

Vectors versions of icons you can find in oryginals folder (if you want to transform it). 

The most current version you can download from my blog - Elog theme, czyli skórka, albo temat.

Regards

Daniel.

Attachment 1: choose_elog.png
choose_elog.png
Attachment 2: entry.png
entry.png
Attachment 3: Full.png
Full.png
Attachment 4: login.png
login.png
Attachment 5: Summary.png
Summary.png
Attachment 6: Threaded_demo_logbook.png
Threaded_demo_logbook.png
Attachment 7: dansaj.7z
Attachment 8: Threaded.png
Threaded.png
ELOG V3.1.5-2eba886