Text processing/Max licenses in use

From Rosetta Code
Revision as of 17:49, 8 December 2021 by Jjuanhdez (talk | contribs) (Text processing/Max licenses in use en FreeBASIC)
Task
Text processing/Max licenses in use
You are encouraged to solve this task according to the task description, using any language you may know.

A company currently pays a fixed sum for the use of a particular licensed software package.   In determining if it has a good deal it decides to calculate its maximum use of the software from its license management log file.

Assume the software's licensing daemon faithfully records a checkout event when a copy of the software starts and a checkin event when the software finishes to its log file.

An example of checkout and checkin events are:

 License OUT @ 2008/10/03_23:51:05 for job 4974
 ...
 License IN  @ 2008/10/04_00:18:22 for job 4974


Task

Save the 10,000 line log file from   here   into a local file, then write a program to scan the file extracting both the maximum licenses that were out at any time, and the time(s) at which this occurs.

Mirror of log file available as a zip here (offsite mirror).

11l

Translation of: Python

<lang 11l>V out = 0 V max_out = -1 [String] max_times L(job) File(‘mlijobs.txt’).read_lines()

  out += I ‘OUT’ C job {1} E -1
  I out > max_out
     max_out = out
     max_times.clear()
  I out == max_out
     max_times.append(job.split(‘ ’)[3])

print(‘Maximum simultaneous license use is #. at the following times:’.format(max_out)) print(‘ ’max_times.join("\n "))</lang>

Output:
Maximum simultaneous license use is 99 at the following times:
  2008/10/03_08:39:34
  2008/10/03_08:40:40

Ada

<lang Ada>-- licenselist.adb -- -- run under GPS 4.3-5 (Sidux/Debian) -- process rosetta.org text_processing/3 example -- uses linked-list to hold times with Ada.Text_IO, Ada.Integer_Text_IO, Ada.Strings.Unbounded,

    Ada.Strings.Unbounded.Text_IO,
    Ada.Containers.Doubly_Linked_Lists;

use Ada.Text_IO, Ada.Integer_Text_IO,

   Ada.Strings.Unbounded, Ada.Strings.Unbounded.Text_IO,
   Ada.Containers;

procedure licenselist is

type logrec is record  -- define a record 'logrec' to place in a list
   logtext : String(1..19);
end record;
package dblist is new Doubly_Linked_Lists(logrec);
use dblist;
      -- declare dblist as a list of logrec's
licenselog : list;
logtime    : logrec;
 -- to record the time of max OUT licenses
infile : File_Type;           -- file handle
str    : Unbounded_String;        -- input string buffer of unknown length
outcnt, maxoutcnt : integer := 0;
infilename : string := "license.log";
 procedure trace_times  is
 -- loop thru times list and print
    pntr : cursor := licenselog.first;
 -- pntr is of system type cursor reference to local list 'licenselog'
 begin
      new_line;
      while has_element(pntr) loop
       put(element(pntr).logtext); new_line;
       next(pntr);
      end loop;
 end trace_times;

begin -- main program --

  open ( infile,
        mode=> in_file,
        name=> infilename );
 loop
   exit when End_of_file ( infile );
   str := get_line( infile );
   if index( str, "OUT" ) > 0 then -- test if OUT record
     outcnt := outcnt +1;
   else                            -- else assume IN record
     outcnt := outcnt -1;
   end if;
   if outcnt > maxoutcnt then
        maxoutcnt := outcnt;
    logtime.logtext := slice(str,15,33); -- date_time field
        licenselog.clear;             -- reset list for new time(s)
        licenselog.append (logtime);  -- put current time into list
   elsif outcnt = maxoutcnt then
        logtime.logtext := slice(str,15,33);  -- date_time field
        licenselog.append (logtime);   -- add current time into list
   end if;  -- have to account for possibility of equal number of OUT's
 end loop;
  put("The max. number of licenses OUT is ");put(maxoutcnt,5); new_line;
  put(" at these times ");
 trace_times;
 close ( infile );

end licenselist;</lang> Output:

The max. number of licenses out is    99
 at these times 
2008/10/03_08:39:34
2008/10/03_08:40:40
[2010-06-06 01:06:07] process terminated successfully (elapsed time: 00.25s)

ALGOL 68

Translation of: C

note: This specimen retains the original C coding style.

Works with: ALGOL 68G version Any - tested with release 1.18.0-9h.tiny

<lang algol68>PROC report = (REF FILE file in)INT: (

 MODE TIME = [19]CHAR;
 STRUCT ([3]CHAR inout, TIME time, INT jobnum) record;
 FORMAT record fmt = $"License "g" @ "g" for job "g(0)l$;
 FLEX[1]TIME max time;
 INT lic out := 0, max out := LWB max time-1, max count := LWB max time-1;
 BOOL file in ended := FALSE;
 on logical file end(file in, (REF FILE file in)BOOL: file in ended := TRUE);
 WHILE
   getf(file in, (record fmt, record));
  1. WHILE # NOT file in ended DO
   IF inout OF record = "OUT" THEN
     lic out +:= 1
   ELIF lic out > 0 THEN # incase license already "OUT" #
     lic out -:= 1
   FI;
   IF lic out > max out THEN
     max out := lic out;
     max count := LWB max time-1
   FI;
   IF lic out = max out THEN
     IF max count = UPB max time THEN
       [UPB max time*2]TIME new max time;
       new max time[:UPB max time] := max time;
       max time := new max time
       # ;putf(stand error, ($"increasing UPB max time (now it is "g(0)")"l$, UPB max time)); #
     FI;
     max time[max count +:= 1] := time OF record
   FI
 OD;
 printf(($"Maximum simultaneous license use is "g(0)" at the following times:"l$, max out));
 FOR lic out FROM LWB max time TO max count DO
   printf(($gl$, max time[lic out]))
 OD;
 0 EXIT
 exit report error: errno

);

INT errno;

COMMENT

 Usage:
   a68g Text_processing_3.a68 --exit Text_processing_3.dat
   a68g Text_processing_3.a68 < Text_processing_3.dat

END COMMENT

main: (

 INT argv1 := 4;
 IF argc >= argv1 THEN
   FOR i FROM argv1 TO argc DO
     FILE file in;
     errno := open(file in, argv(i), stand in channel);
     IF errno /= 0 THEN
       putf(stand error, ($"cannot read "gl$, argv(1)));
       exit main error
     ELSE
       report(file in)
     FI;
     close(file in)
   OD
 ELSE
   report(stand in)
 FI;
 exit main error: SKIP

)</lang> Output:

Maximum simultaneous license use is 99 at the following times:
2008/10/03_08:39:34
2008/10/03_08:40:40

APL

Works with: APL2
Translation of: J

<lang apl>⍝ Copy/paste file's contents into TXT (easiest), or TXT ← ⎕NREAD

      I  ←  TXT[;8+⎕IO]
      D  ←  TXT[;⎕IO+14+⍳19]
      lu ←  +\ ¯1 * 'OI' ⍳ I
      mx ←  (⎕IO+⍳⍴lu)/⍨lu= max ← ⌈/ lu
      ⎕  ←  'Maximum simultaneous license use is ' , ' at the following times:' ,⍨ ⍕max ⋄ ⎕←D[mx;]</lang>

<lang apl>Maximum simultaneous license use is 99 at the following times:

2008/10/03_08:39:34
2008/10/03_08:40:40</lang>

AutoHotkey

Translation of: Python

<lang autohotkey> IfNotExist, mlijobs.txt

 UrlDownloadToFile, http://rosettacode.org/mlijobs.txt, mlijobs.txt

out := 0, max_out := -1, max_times := ""

Loop, Read, mlijobs.txt {

 If InStr(A_LoopReadLine, "OUT")
   out++
 Else
   out--
 If (out > max_out)
   max_out := out, max_times := ""
 If (out = max_out)
 {
   StringSplit, lineArr, A_LoopReadLine, %A_Space%
   max_times .= lineArr4 . "`n"
 }

}

MsgBox Maximum use is %max_out% at:`n`n%max_times% </lang>

Maximum use is 99 at:

2008/10/03_08:39:34
2008/10/03_08:40:40

AWK

to be called with awk -f licenses.awk ./mlijobs.txt <lang awk>$2=="OUT" {

   count = count + 1 
   time = $4 
   if ( count > maxcount ) {
       maxcount = count 
       maxtimes = time
   } else { 
       if ( count == maxcount ) {
           maxtimes = maxtimes " and " time 
       }
   }

} $2=="IN" { count = count - 1 } END {print "The biggest number of licenses is " maxcount " at " maxtimes " !"}</lang>

Sample output

The biggest number of licenses is 99 at 2008/10/03_08:39:34 and 2008/10/03_08:40:40 !

On a 2.53MHz machine, these timings were obtained using GNU Awk 4.0.2:

user   0m0.015s
sys    0m0.008s

BBC BASIC

<lang bbcbasic> max% = 0

     nlicence% = 0
     file% = OPENIN("mlijobs.txt")
     
     WHILE NOT EOF#file%
       a$ = GET$#file%
       stamp$ = MID$(a$, 15, 19)
       IF INSTR(a$, "OUT") THEN
         nlicence% += 1
         IF nlicence% > max% THEN
           max% = nlicence%
           start$ = stamp$
         ENDIF
       ENDIF
       IF INSTR(a$, "IN") THEN
         IF nlicence% = max% THEN
           finish$ = previous$
         ENDIF
         nlicence% -= 1
       ENDIF
       previous$ = stamp$
     ENDWHILE
     CLOSE #file%
     
     PRINT "Maximum licences checked out = " ; max%
     PRINT "From " start$ " to " finish$
     END</lang>

Output:

Maximum licences checked out = 99
From 2008/10/03_08:39:34 to 2008/10/03_08:40:40

Bracmat

<lang bracmat>( 0:?N:?n

 & :?Ts
 & @( get$("mlijobs.txt",STR)
    :   ?
        ( "e " ?OI " @ " ?T " " ?
        &   (   !OI:OUT
              &   !n+1
                : ( >!N:?N&!T:?Ts
                  | !N&!Ts !T:?Ts
                  | ?
                  )
            | !n+-1
            )
          : ?n
        & ~
        )
    )

| out$(!N !Ts) ); </lang> Output:

99 2008/10/03_08:39:34 2008/10/03_08:40:40

C

<lang c>#include <stdio.h>

  1. include <stdlib.h>
  2. include <string.h>
  3. include <sys/types.h>
  1. define INOUT_LEN 4
  2. define TIME_LEN 20
  3. define MAX_MAXOUT 1000

char inout[INOUT_LEN]; char time[TIME_LEN]; uint jobnum;

char maxtime[MAX_MAXOUT][TIME_LEN];

int main(int argc, char **argv) {

 FILE *in = NULL;
 int l_out = 0, maxout=-1, maxcount=0;
 if ( argc > 1 ) {
   in = fopen(argv[1], "r");
   if ( in == NULL ) {
     fprintf(stderr, "cannot read %s\n", argv[1]);
     exit(1);
   }
 } else {
   in = stdin;
 }
 while( fscanf(in, "License %s @ %s for job %u\n", inout, time, &jobnum) != EOF ) {
   if ( strcmp(inout, "OUT") == 0 )
     l_out++;
   else
     l_out--;
   if ( l_out > maxout ) {
     maxout = l_out;
     maxcount=0; maxtime[0][0] = '\0';
   }
   if ( l_out == maxout ) {
     if ( maxcount < MAX_MAXOUT ) {
   strncpy(maxtime[maxcount], time, TIME_LEN);
   maxcount++;
     } else {
   fprintf(stderr, "increase MAX_MAXOUT (now it is %u)\n", MAX_MAXOUT);
   exit(1);
     }
   }
 }
 printf("Maximum simultaneous license use is %d at the following times:\n", maxout);
 for(l_out=0; l_out < maxcount; l_out++) {
   printf("%s\n", maxtime[l_out]);
 }
 if ( in != stdin ) fclose(in);
 exit(0);

}</lang>

Using mmap, no extra storage (think this as a search and replace):<lang c>#include <stdio.h>

  1. include <unistd.h>
  2. include <fcntl.h>
  3. include <sys/types.h>
  4. include <sys/stat.h>
  5. include <sys/mman.h>
  6. include <err.h>
  7. include <string.h>

int main() {

   struct stat s;
   int fd = open("mlijobs.txt", O_RDONLY);
   int cnt, max_cnt, occur;
   char *buf, *ptr;
   if (fd == -1) err(1, "open");
   fstat(fd, &s);
   ptr = buf = mmap(0, s.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
   cnt = max_cnt = 0;
   while(ptr - buf < s.st_size - 33) {
       if (!strncmp(ptr, "License OUT", 11) && ++cnt >= max_cnt) {
           if (cnt > max_cnt) {
               max_cnt = cnt;
               occur = 0;
           }
           /* can't sprintf time stamp: might overlap */
           memmove(buf + 26 * occur, ptr + 14, 19);
           sprintf(buf + 26 * occur + 19, "%6d\n", cnt);
           occur++;
       } else if (!strncmp(ptr, "License IN ", 11)) cnt --;
       while (ptr < buf + s.st_size && *ptr++ != '\n');
   }
   printf(buf);
   munmap(buf, s.st_size);
   return close(fd);

}</lang>output<lang>2008/10/03_08:39:34 99 2008/10/03_08:40:40 99</lang>

C#

<lang csharp> using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO;

namespace TextProc3 {

   class Program
   {
       static void Main(string[] args)
       {            
           string line;
           int count = 0, maxcount = 0;
           List<string> times = new List<string>();
           System.IO.StreamReader file = new StreamReader("mlijobs.txt");
           while ((line = file.ReadLine()) != null)
           {
               string[] lineelements = line.Split(' ');                
               switch (lineelements[1])
               {
                   case "IN":
                       count--;
                       break;
                   case "OUT":
                       count++;
                       if (count > maxcount)
                       {
                           maxcount = count;
                           times.Clear();
                           times.Add(lineelements[3]);
                       }else if(count == maxcount){
                           times.Add(lineelements[3]);
                       }
                       break;
               }                
           }
           file.Close();
           Console.WriteLine(maxcount);
           foreach (string time in times)
           {
               Console.WriteLine(time);
           }
       }
   }

} </lang>

99
2008/10/03_08:39:34
2008/10/03_08:40:40

C++

<lang cpp>#include <fstream>

  1. include <iostream>
  2. include <iterator>
  3. include <string>
  4. include <vector>

int main() {

   const char logfilename[] = "mlijobs.txt";
   std::ifstream logfile(logfilename);
   if (!logfile.is_open())
   {
       std::cerr << "Error opening: " << logfilename << "\n";
       return -1;
   }
   int license = 0, max_license = 0;
   std::vector<std::string> max_timestamp;
   for (std::string logline; std::getline(logfile, logline); )
   {
       std::string action(logline.substr(8,3));
       if (action == "OUT")
       {
           if (++license >= max_license)
           {
               if (license > max_license)
               {
                   max_license = license;
                   max_timestamp.clear();
               }
               max_timestamp.push_back(logline.substr(14, 19));
           }
       }
       else if (action == "IN ")
       {
           --license;
       }
   }
   std::cout << "License count at log end: " << license
       << "\nMaximum simultaneous license: " << max_license
       << "\nMaximum license time(s):\n";
   std::copy(max_timestamp.begin(), max_timestamp.end(),
       std::ostream_iterator<std::string>(std::cout, "\n"));

}</lang>

Output:

License count at log end: 0
Maximum simultaneous licenses: 99
Maximum license time(s):
2008/10/03_08:39:34
2008/10/03_08:40:40

Clojure

<lang clojure>(defn delta [entry]

 (case (second (re-find #"\ (.*)\ @" entry))
   "IN " -1
   "OUT" 1
   (throw (Exception. (str "Invalid entry:" entry)))))

(defn t [entry]

 (second (re-find #"@\ (.*)\ f" entry)))

(let [entries (clojure.string/split (slurp "mlijobs.txt") #"\n")

     in-use (reductions + (map delta entries))
     m (apply max in-use)
     times (map #(nth (map t entries) %)
                (keep-indexed #(when (= m %2) %1) in-use))]
 (println "Maximum simultaneous license use is" m "at the following times:")
 (map println times))</lang>
Maximum simultaneous license use is 99 at the following times:
2008/10/03_08:39:34
2008/10/03_08:40:40

COBOL

Works with: OpenCOBOL

<lang cobol> IDENTIFICATION DIVISION.

      PROGRAM-ID. max-licenses-in-use.
      ENVIRONMENT DIVISION.
      INPUT-OUTPUT SECTION.
      FILE-CONTROL.
          SELECT license-file ASSIGN "mlijobs.txt"
              ORGANIZATION LINE SEQUENTIAL
              FILE STATUS file-status.
      DATA DIVISION.
      FILE SECTION.
      FD  license-file.
      01  license-record.
          03  FILLER                   PIC X(8).
          03  action                   PIC X(3).
              88  license-out          VALUE "OUT".
          03  FILLER                   PIC X(3).
          03  license-timestamp        PIC X(19).
          03  FILLER                   PIC X(13).
      WORKING-STORAGE SECTION.
      01  file-status                  PIC XX.
          88  file-ok                  VALUE "00".
      01  max-licenses-out             PIC 9(6).
      01  num-max-times                PIC 99.
      01  max-license-times-area.
          03  max-timestamps           PIC X(19) OCCURS 1 TO 50 TIMES
              DEPENDING ON num-max-times.
      01  current-licenses-out         PIC 9(6).
      
      01  i                            PIC 99.
      PROCEDURE DIVISION.
      DECLARATIVES.
      license-file-error SECTION.
          USE AFTER ERROR ON license-file.
          DISPLAY "An unexpected error has occurred. Error "
              file-status ". The program will close."
          GOBACK
          .
      END DECLARATIVES.
      main-line.
          OPEN INPUT license-file
          IF NOT file-ok
              DISPLAY "File could not be opened. Error " file-status
                  "."
              GOBACK
          END-IF
          
          PERFORM FOREVER
              READ license-file
                  AT END
                      EXIT PERFORM
              END-READ
              IF license-out
                  ADD 1 TO current-licenses-out
                  EVALUATE TRUE
                      WHEN current-licenses-out > max-licenses-out
                          MOVE 1 TO num-max-times
                          MOVE current-licenses-out TO max-licenses-out
                          MOVE license-timestamp
                              TO max-timestamps (num-max-times)
                      WHEN current-licenses-out = max-licenses-out
                          ADD 1 TO num-max-times
                          MOVE license-timestamp
                              TO max-timestamps (num-max-times)
                  END-EVALUATE
              ELSE
                  SUBTRACT 1 FROM current-licenses-out
              END-IF
          END-PERFORM
          CLOSE license-file
          DISPLAY "License count at log end: " current-licenses-out
          DISPLAY "Maximum simulataneous licenses: " max-licenses-out
          DISPLAY "Time(s):"
          PERFORM VARYING i FROM 1 BY 1 UNTIL num-max-times < i
              DISPLAY max-timestamps (i)
          END-PERFORM
          GOBACK
          .</lang>

Common Lisp

Library: CL-PPCRE

<lang lisp>(defun max-licenses (&optional (logfile "mlijobs.txt"))

 (with-open-file (log logfile :direction :input)
   (do ((current-logs 0) (max-logs 0) (max-log-times '())
        (line #1=(read-line log nil nil) #1#))
       ((null line)
        (format t "~&Maximum simultaneous license use is ~w at the ~
                    following time~p: ~{~%  ~a~}."
                max-logs (length max-log-times) (nreverse max-log-times)))
     (cl-ppcre:register-groups-bind (op time)
         ("License (\\b.*\\b)[ ]{1,2}@ (\\b.*\\b)" line)
       (cond ((string= "OUT" op) (incf current-logs))
             ((string= "IN"  op) (decf current-logs))
             (t (cerror "Ignore it." "Malformed entry ~s." line)))
       (cond ((> current-logs max-logs)
              (setf max-logs current-logs
                    max-log-times (list time)))
             ((= current-logs max-logs)
              (push time max-log-times)))))))</lang>
> (max-licenses)
Maximum simultaneous license use is 99 at the following times: 
  2008/10/03_08:39:34
  2008/10/03_08:40:40.
NIL

D

<lang d>void main() {

   import std.stdio;
   int nOut, maxOut = -1;
   string[] maxTimes;
   foreach (string job; lines(File("mlijobs.txt"))) {
       nOut += (job[8] == 'O') ? 1 : -1;
       if (nOut > maxOut) {
           maxOut = nOut;
           maxTimes = null;
       }
       if (nOut == maxOut)
           maxTimes ~= job[14 .. 33];
   }
   writefln("Maximum simultaneous license use is %d at" ~
            " the following times:\n%( %s\n%)", maxOut, maxTimes);

}</lang>

Output:
Maximum simultaneous license use is 99 at the following times:
 "2008/10/03_08:39:34"
 "2008/10/03_08:40:40"

E

Translation of: Python

<lang e>var out := 0 var maxOut := 0 var maxTimes := []

def events := ["OUT " => 1, "IN " => -1]

for line in <file:mlijobs.txt> {

   def `License @{via (events.fetch) delta}@@ @time for job @num$\n` := line
   out += delta
   if (out > maxOut) {
       maxOut := out
       maxTimes := []
   }
   if (out == maxOut) {
       maxTimes with= time
   }

}

println(`Maximum simultaneous license use is $maxOut at the following times:`) for time in maxTimes {

   println(` $time`)

}</lang>

Eiffel

<lang Eiffel> class

   APPLICATION

create

   make

feature

   make
           -- Max Licences used.
       local
           count: INTEGER
           max_count: INTEGER
           date: STRING
       do
           read_list
           create date.make_empty
           across
               data as d
           loop
               if d.item.has_substring ("OUT") then
                   count := count + 1
                   if count > max_count then
                       max_count := count
                       date := d.item
                   end
               elseif d.item.has_substring ("IN") then
                   count := count - 1
               end
           end
           io.put_string ("Max Licences OUT: " + max_count.out)
           io.new_line
           io.put_string ("Date: " + date.substring (15, 33))
       end
   original_list: STRING = "mlijobs.txt"

feature {NONE}

   read_list
           -- Data read into 'data.
       local
           l_file: PLAIN_TEXT_FILE
       do
           create l_file.make_open_read_write (original_list)
           l_file.read_stream (l_file.count)
           data := l_file.last_string.split ('%N')
           l_file.close
       end
   data: LIST [STRING]

end </lang>

Output:
Max Licences OUT: 99
Date: 2008/10/03_08:39:34

Erlang

<lang Erlang> -module( text_processing_max_licenses ).

-export( [out_dates_from_file/1, task/0] ).

out_dates_from_file( Name ) ->

   {ok, Binary} = file:read_file( Name ),
   Lines = binary:split( Binary, <<"\n">>, [global] ),
   {_N, _Date, Dict} = lists:foldl( fun out_dates/2, {0, "", dict:new()}, Lines ),
   [{X, dict:fetch(X, Dict)} || X <- dict:fetch_keys( Dict )].

task() ->

   [{Max, Dates} | _T] = lists:reverse(lists:sort(out_dates_from_file("mlijobs.txt")) ),
   io:fwrite( "Max licenses was ~p at ~p~n", [Max, Dates] ).


out_dates( <<>>, Acc ) -> Acc; out_dates( Line, {N, Date, Dict} ) ->

   [_License, Direction, <<"@">>, New_date | _T] = [X || X <- binary:split(Line, <<" ">>, [global]), X =/= <<>>],
   New_n = out_dates_n( N, Direction ),
   New_dict = out_dates_dict( N, New_n, Date, Dict ),
   {New_n, New_date, New_dict}.

out_dates_dict( N, New_n, Date, Dict ) when N > New_n -> dict:append( N, Date, Dict ); out_dates_dict( _N, _New_n, _Date, Dict ) -> Dict.

out_dates_n( N, <<"OUT">> ) -> N + 1; out_dates_n( N, <<"IN">> ) -> N - 1. </lang>

Output:
12> text_processing_max_licenses:task().
Max licenses was 99 at [<<"2008/10/03_08:39:34">>,<<"2008/10/03_08:40:40">>]

Euphoria

<lang euphoria>function split(sequence s, integer c)

   sequence out
   integer first, delim
   out = {}
   first = 1
   while first <= length(s) do
       delim = find_from(c, s, first)
       if delim = 0 then
           delim = length(s) + 1
       end if
       out = append(out, s[first..delim-1])
       first = delim + 1
   end while
   return out

end function

include get.e function val(sequence s)

   sequence v
   v = value(s)
   return v[2] - v[1] * v[1]

end function

constant fn = open("mlijobs.txt", "r") integer maxout sequence jobs, line, maxtime object x jobs = {} maxout = 0 while 1 do

   x = gets(fn)
   if atom(x) then
       exit
   end if
   line = split(x, ' ')
   line[$] = val(line[$])
   if equal(line[2], "OUT") then
       jobs &= line[$]
       if length(jobs) > maxout then
           maxout = length(jobs)
           maxtime = {line[4]}
       elsif length(jobs) = maxout then
           maxtime = append(maxtime, line[4])
       end if
   else
       jobs[find(line[$],jobs)] = jobs[$]
       jobs = jobs[1..$-1]
   end if

end while close(fn)

printf(1, "Maximum simultaneous license use is %d at the following times:\n", maxout) for i = 1 to length(maxtime) do

   printf(1, "%s\n", {maxtime[i]})

end for</lang>

Output:

Maximum simultaneous license use is 99 at the following times:
2008/10/03_08:39:34
2008/10/03_08:40:40

Factor

Placing the file in resource:work/mlijobs.txt:

<lang factor>USING: kernel sequences splitting math accessors io.encodings.ascii io.files math.parser io ; IN: maxlicenses

TUPLE: maxlicense max-count current-count times ;

<PRIVATE

<maxlicense> ( -- max ) -1 0 V{ } clone \ maxlicense boa ; inline
out? ( line -- ? ) [ "OUT" ] dip subseq? ; inline
line-time ( line -- time ) " " split harvest fourth ; inline
update-max-count ( max -- max' )
   dup [ current-count>> ] [ max-count>> ] bi >
   [ dup current-count>> >>max-count V{ } clone >>times ] when ;
(inc-current-count) ( max ? -- max' )
   [ [ 1 + ] change-current-count ]
   [ [ 1 - ] change-current-count ]
   if
   update-max-count ; inline
inc-current-count ( max ? time -- max' time )
   [ (inc-current-count) ] dip ;
current-max-equal? ( max -- max ? )
   dup [ current-count>> ] [ max-count>> ] bi = ;
update-time ( max time -- max' )
   [ current-max-equal? ] dip
   swap
   [ [ suffix ] curry change-times ] [ drop ] if ;
   
split-line ( line -- ? time ) [ out? ] [ line-time ] bi ;
process ( max line -- max ) split-line inc-current-count update-time ;

PRIVATE>

find-max-licenses ( -- max )
   "resource:work/mlijobs.txt" ascii file-lines
   <maxlicense> [ process ] reduce ;
print-max-licenses ( max -- )
   [ times>> ] [ max-count>> ] bi
   "Maximum simultaneous license use is " write
   number>string write
   " at the following times: " print
   [ print ] each ;</lang>

<lang factor>( scratchpad ) [ find-max-licenses print-max-licenses ] time Maximum simultaneous license use is 99 at the following times: 2008/10/03_08:39:34 2008/10/03_08:40:40 Running time: 0.16164423 seconds</lang>

Forth

<lang forth> 20 constant date-size create max-dates date-size 100 * allot variable max-out variable counter

stdin value input

process ( addr len -- )
 8 /string
 over 3 s" OUT" compare 0= if
   1 counter +!
   counter @ max-out @ > if
     counter @ max-out !
     drop 5 + date-size max-dates  place
   else counter @ max-out @ = if
     drop 5 + date-size max-dates +place
   else 2drop then then
 else drop 2 s" IN" compare 0= if
   -1 counter +!
 then then ;
main
 0 max-out !
 0 counter !
 s" mlijobs.txt" r/o open-file throw to input
 begin  pad 80 input read-line throw
 while  pad swap process
 repeat drop
 input close-file throw
 max-out @ . ." max licenses in use @"
 max-dates count type cr ;

main bye </lang>

Fortran

Works with: Fortran version 90 and later

<lang fortran>

PROGRAM MAX_LICENSES
  IMPLICIT NONE

  INTEGER :: out=0, maxout=0, maxcount=0, err
  CHARACTER(50) :: line
  CHARACTER(19) :: maxtime(100)

  OPEN (UNIT=5, FILE="Licenses.txt", STATUS="OLD", IOSTAT=err)
  IF (err > 0) THEN
    WRITE(*,*) "Error opening file Licenses.txt"
    STOP
  END IF

  DO 
    READ(5, "(A)", IOSTAT=err) line
    IF (err == -1) EXIT          ! EOF detected
    IF (line(9:9) == "O") THEN
      out = out + 1
    ELSE IF (line(9:9) == "I") THEN
      out = out - 1
    END IF
    IF (out > maxout ) THEN
      maxout = maxout + 1
      maxcount = 1
      maxtime(maxcount) = line(15:33)
    ELSE IF (out == maxout) THEN
      maxcount = maxcount + 1
      maxtime(maxcount) = line(15:33)
    END IF
  END DO
 
  CLOSE(5)
 
  WRITE(*,"(A,I4,A)") "Maximum simultaneous license use is", maxout, " at the following times:"
  WRITE(*,"(A)") maxtime(1:maxcount)
 
END PROGRAM MAX_LICENSES

</lang> Output

 Maximum simultaneous license use is  99 at the following times:
 2008/10/03_08:39:34                                           
 2008/10/03_08:40:40


FreeBASIC

Translation of: PureBasic

<lang freebasic>Const CRLF = Chr(13) & Chr(10) Dim As String currline, maxtime Dim As Integer counter = 0, max = 0 Dim As String filename = "mlijobs.txt"

Open filename For Input As #1 While Not Eof(1)

   Line Input #1, currline
   
   If Mid(currline,9,3) = "OUT" Then
       counter += 1
   Else
       counter -= 1
   End If
   If counter > max Then
       max = counter
       maxtime = Mid(currline,15,19)
   Elseif counter = max Then
       maxtime &= CRLF & Mid(currline,15,19)
   End If

Wend Print Str(max); " license(s) used at ;"; CRLF; maxtime Close #1 Print !"\nPress ENTER to exit" Sleep</lang>

Output:
Igual que la entrada de PureBasic.


Gema

Start with gema -f licenses.gema mlijobs.txt <lang gema> @set{count;0};@set{max;0}

License OUT \@ * *\n=@incr{count}@testmax{${count},*} License IN \@ * *\n=@decr{count} \Z=@report{${max},${times${max}}}

testmax:*,*=@cmpn{${max};$1;@set{max;$1};;}@append{times${count};$2\n}

report:*,*=Maximum simultaneous license use is * at\n* </lang> Output:

Maximum simultaneous license use is 99 at
2008/10/03_08:39:34
2008/10/03_08:40:40

Go

<lang go>package main

import (

   "bufio"
   "bytes"
   "fmt"
   "log"
   "os"

)

const (

   filename   = "mlijobs.txt"
   inoutField = 1
   timeField  = 3
   numFields  = 7

)

func main() {

   file, err := os.Open(filename)
   if err != nil {
       log.Fatal(err)
   }
   defer file.Close()
   var ml, out int
   var mlTimes []string
   in := []byte("IN")
   s := bufio.NewScanner(file)
   for s.Scan() {
       f := bytes.Fields(s.Bytes())
       if len(f) != numFields {
           log.Fatal("unexpected format,", len(f), "fields.")
       }
       if bytes.Equal(f[inoutField], in) {
           out--
           if out < 0 {
               log.Fatalf("negative license use at %s", f[timeField])
           }
           continue
       }
       out++
       if out < ml {
           continue
       }
       if out > ml {
           ml = out
           mlTimes = mlTimes[:0]
       }
       mlTimes = append(mlTimes, string(f[timeField]))
   }
   if err = s.Err(); err != nil {
       log.Fatal(err)
   }
   fmt.Println("max licenses:", ml)
   fmt.Println("at:")
   for _, t := range mlTimes {
       fmt.Println(" ", t)
   }

}</lang>

Output:
max licenses: 99
at:
  2008/10/03_08:39:34
  2008/10/03_08:40:40

Groovy

<lang groovy>def max = 0 def dates = [] def licenses = [:] new File('licenseFile.txt').eachLine { line ->

   (line =~ /License (\w+)\s+@ ([\d\/_:]+) for job (\d+)/).each { matcher, action, date, job ->
       switch (action) {
       case 'IN':
           assert licenses[job] != null : "License has not been checked out for $job"
           licenses.remove job
           break
       case 'OUT':
           assert licenses[job] == null : "License has already been checked out for $job"
           licenses[job] = date
           def count = licenses.keySet().size()
           if (count > max) {
               max = count
               dates = [ date ]
           } else if (count == max) {
               dates << date
           }
           break
       default:
           throw new IllegalArgumentException("Unsupported license action $action")
       }
   }

}

println "Maximum Licenses $max" dates.each { date -> println " $date" } </lang> Output:

Maximum Licenses 99
  2008/10/03_08:39:34
  2008/10/03_08:40:40

Haskell

<lang haskell> import Data.List

main = do

 f <- readFile "./../Puzzels/Rosetta/inout.txt"
 let (ioo,dt) = unzip. map ((\(_:io:_:t:_)-> (io,t)). words) . lines $ f
     cio = drop 1 . scanl (\c io -> if io == "IN" then pred c else succ c) 0 $ ioo 
     mo = maximum cio
 putStrLn $ "Maximum simultaneous license use is " ++ show mo ++ " at:"
 mapM_ (putStrLn . (dt!!)) . elemIndices mo $ cio

</lang>

HicEst

This example is incorrect. It does not accomplish the given task. Please fix the code and remove this message.

We open Licenses.txt in MatrixExplorer mode with 3 columns: IN/OUT, date_time, ID_nr. This allows to adress single file elements by Licenses(row, column). <lang HicEst>CHARACTER Licenses="Licenses.txt" REAL :: counts(1), Top10(10)

OPEN(FIle=Licenses, fmt='8x,A3,3x,A19,Nb ,', LENgth=lines)

ALLOCATE(counts, lines) counts(1) = 1 DO line = 2, lines

  counts(line) = counts(line-1) + 1 - 2*(Licenses(line,1)=='IN')

ENDDO

SORT(Vector=counts, Descending=1, Index=Top10)

DO i = 1, LEN(Top10)

 WRITE() counts(Top10(i)), Licenses(Top10(i), 2)

ENDDO

END</lang>

99 2008/10/03_08:40:40
99 2008/10/03_08:39:34
98 2008/10/03_08:40:47
98 2008/10/03_08:40:11
98 2008/10/03_08:39:46
98 2008/10/03_08:39:45
98 2008/10/03_08:39:30
97 2008/10/03_20:44:58
97 2008/10/03_08:41:36
97 2008/10/03_08:40:53

Icon and Unicon

The following solution works in both languages: <lang unicon>procedure main(A)

   maxCount := count := 0
   every !&input ?  case tab(upto('@')) of {
       "License OUT ": {
            maxTime := (maxCount <:= (count +:= 1), [])
            put(maxTime, (maxCount = count, ="@ ", tab(find(" for "))))
            }
       "License IN  ": count -:= (count > 0, 1)     # Error check
       }
   write("There were ",maxCount," licenses out at:")
   every write("\t",!maxTime)

end</lang>

And a run of the program:

->ml <mlijobs.txt
There were 99 licenses out at:
        2008/10/03_08:39:34
        2008/10/03_08:40:40
->


J

<lang j> require 'files'

  'I D' =: (8 ; 14+i.19) {"1 &.> <'m' fread 'licenses.txt' NB.  read file as matrix, select columns
  lu    =:  +/\ _1 ^ 'OI' i. I                             NB.  Number of licenses in use at any given time
  mx    =:  (I.@:= >./) lu                                 NB.  Indicies of maxima
  NB.  Output results
  (mx { D) ,~ 'Maximum simultaneous license use is ' , ' at the following times:' ,~ ": {. ,mx { lu</lang>
 Maximum simultaneous license use is 99 at the following times:
 2008/10/03_08:39:34                                           
 2008/10/03_08:40:40

Java

Works with: Java version 1.5+

<lang java5>import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.LinkedList;

public class License {

 public static void main(String[] args) throws FileNotFoundException, IOException{
   BufferedReader in = new BufferedReader(new FileReader(args[0]));
   int max = Integer.MIN_VALUE;
   LinkedList<String> dates = new LinkedList<String>();
   String line;
   int count = 0;
   while((line = in.readLine()) != null){
     if(line.startsWith("License OUT ")) count++;
     if(line.startsWith("License IN ")) count--;
     if(count > max){
       max = count;
       String date = line.split(" ")[3];
       dates.clear();
       dates.add(date);
     }else if(count == max){
       String date = line.split(" ")[3];
       dates.add(date);
     }
   }
   System.out.println("Max licenses out: "+max);
   System.out.println("At time(s): "+dates);
 }

}</lang>

Max licenses out: 99
At time(s): [2008/10/03_08:39:34, 2008/10/03_08:40:40]

JavaScript

Works with: JScript

for the file i/o

<lang javascript>var file_system = new ActiveXObject("Scripting.FileSystemObject"); var fh = file_system.openTextFile('mlijobs.txt', 1); // 1 == open for reading var in_use = 0, max_in_use = -1, max_in_use_at = [];

while ( ! fh.atEndOfStream) {

   var line = fh.readline();
   if (line.substr(8,3) == "OUT") {
       in_use++;
       if (in_use > max_in_use) {
           max_in_use = in_use;
           max_in_use_at = [ line.split(' ')[3] ];
       }
       else if (in_use == max_in_use)
           max_in_use_at.push( line.split(' ')[3] );
   }
   else if (line.substr(8,2) == "IN") 
       in_use--;

}

fh.close();

WScript.echo("Max licenses out: " + max_in_use + "\n " + max_in_use_at.join('\n '));</lang>

output:

Max licenses out: 99
  2008/10/03_08:39:34
  2008/10/03_08:40:40

jq

Works with: jq version 1.4

<lang jq># Input: an array of strings def max_licenses_in_use:

 # state: [in_use = 0, max_in_use = -1, max_in_use_at = [] ]
 reduce .[] as $line
   ([0,  -1, [] ];
    ($line|split(" ")) as $line
    | if $line[1] == "OUT" then 
        .[0] += 1                          # in_use++;
        | if   .[0] > .[1]                 # (in_use > max_in_use)
          then .[1] = .[0]                 # max_in_use = in_use
            |  .[2] = [$line[3]]           # max_in_use_at = [$line[3]]
          elif .[0] == .[1]                # (in_use == max_in_use)
            then .[2] += [$line[3]]        # max_in_use_at << $line[3]
          else .
          end
      elif $line[1] == "IN" then .[0] -= 1 # in_use--
      else .
      end )
  | "Max licenses out: \(.[1]) at:\n \(.[2]|join("\n "))" ;
  1. The file is read in as a single string and so must be split at newlines:

split("\n") | max_licenses_in_use</lang>

Output:
$ time /usr/local/bin/jq -M -R -r -s -f Max_licences_in_use.jq mlijobs.txt
Max licenses out: 99 at:
 2008/10/03_08:39:34
 2008/10/03_08:40:40

real   0m0.163s
user   0m0.154s
sys    0m0.005s

Julia

Works with: Julia version 0.6
Translation of: Python

<lang julia>function maximumsimultlicenses(io::IO)

   out, maxout, maxtimes = 0, -1, String[]
   for job in readlines(io)
       out += ifelse(occursin("OUT", job), 1, -1)
       if out > maxout
           maxout = out
           empty!(maxtimes)
       end
       if out == maxout
           push!(maxtimes, split(job)[4])
       end
   end
   return maxout, maxtimes

end

let (maxout, maxtimes) = open(maximumsimultlicenses, "data/mlijobs.txt")

   println("Maximum simultaneous license use is $maxout at the following times: \n - ", join(maxtimes, "\n - "))

end</lang>

Output:
Maximum simultaneous license use is 99 at the following times:
 - 2008/10/03_08:39:34
 - 2008/10/03_08:40:40

K

<lang K> r:m@&a=x:|/a:+\{:[x[8+!3]~"OUT";1;-1]}'m:0:"mlijobs.txt";

 `0:,/"Maximum simultaneous license use is ",$x;
 `0:" at the following times:\n";`0:r[;14+!19]</lang>

Output:

<lang K>Maximum simultaneous license use is 99 at the following times: 2008/10/03_08:39:34 2008/10/03_08:40:40</lang>

Kotlin

The link for downloading the file, mlijobs.txt, is currently broken so I've created a small file myself to test the program: <lang scala>// version 1.1.51

import java.io.File

fun main(args: Array<String>) {

   val filePath = "mlijobs.txt"
   var licenses = 0
   var maxLicenses = 0
   val dates = mutableListOf<String>()
   val f = File(filePath) 
   f.forEachLine { line ->
       if (line.startsWith("License OUT")) {
           licenses++
           if (licenses > maxLicenses) {
               maxLicenses = licenses
               dates.clear() 
               dates.add(line.substring(14, 33))
           }
           else if(licenses == maxLicenses) {
               dates.add(line.substring(14, 33))
           }
       }
       else if (line.startsWith("License IN")) {
           licenses--
       }
   }
   println("Maximum simultaneous license use is $maxLicenses at the following time(s):")
   println(dates.map { "  $it" }.joinToString("\n"))               

}</lang>

The file used for testing:

License OUT @ 2008/10/03_23:51:05 for job 4974
License OUT @ 2008/10/03_23:57:00 for job 4975
License IN  @ 2008/10/04_00:00:06 for job 4975
License OUT @ 2008/10/04_00:07:19 for job 4976
License IN  @ 2008/10/04_00:11:32 for job 4976
License IN  @ 2008/10/04_00:18:22 for job 4974
Output:
Maximum simultaneous license use is 2 at the following time(s):
  2008/10/03_23:57:00
  2008/10/04_00:07:19

Lua

<lang lua> filename = "mlijobs.txt" io.input( filename )

max_out, n_out = 0, 0 occurr_dates = {}

while true do

   line = io.read( "*line" )
   if line == nil then break end
   if string.find( line, "OUT" ) ~= nil then
       n_out = n_out + 1
       if n_out > max_out then
           max_out = n_out
           occurr_dates = {}
           occurr_dates[#occurr_dates+1] = string.match( line, "@ ([%d+%p]+)" )
       elseif n_out == max_out then
           occurr_dates[#occurr_dates+1] = string.match( line, "@ ([%d+%p]+)" )
       end
   else
       n_out = n_out - 1
   end

end

print( "Maximum licenses in use:", max_out ) print( "Occurrences:" ) for i = 1, #occurr_dates do

   print( "", occurr_dates[i] )

end</lang> Output:

Maximum licenses in use: 99
Occurrences:
    2008/10/03_08:39:34
    2008/10/03_08:40:40

M2000 Interpreter

Load.Doc load txt in any format of UTF-16LE, UTF16-BE, UTF-8, ANSI, in any line separator CRLF, CR, LF and place text in paragraphs in a document object. A document object return a string containing text (as utf16le using CRLF), but for some specific functions and statements treated as object. So changing paragraphs done with Paragraph$(a$, (m)) where m is by reference with a special syntax for this function (using without m we place order number, but m is a valid paragraph id, which always point to same paragraph until removing it).

In Wine 1.8 can't download.

<lang M2000 Interpreter> Module Checkit {

     Document a$, max_time$
     Load.doc a$, "mlijobs.txt"
     const dl$=" ", nl$={
     }
     Def long m, out, max_out=-1
     m=Paragraph(a$, 0) 
     If Forward(a$,m) then {
           While m {
                 job$=Paragraph$(a$,(m))
                 out+=If(Piece$(job$,dl$,2)="OUT"->1&, -1&)
                 If out>max_out then max_out=out : Clear max_time$
                 If out=max_out then max_time$=Piece$(job$,dl$,4)+nl$
           }
     }
     Report Format$("Maximum simultaneous license use is {0} at the following times:",max_out)
     Print "    ";  ' left margin
     Report max_time$

} Checkit </lang> Output

Maximum simultaneous license use is 99 at the following times:
    2008/10/03_08:39:34
    2008/10/03_08:40:40

M4

<lang M4> divert(-1) define(`current',0) define(`max',0) define(`OUT',`define(`current',incr(current))`'ifelse(eval(current>max),1,

  `define(`max',current)`'divert(-1)`'undivert(1)`'divert(1)',
  `ifelse(current,max,`divert(1)undivert(1)')')')

define(`IN',`define(`current',decr(current))') define(`for',`divert(-1)') include(mlijobs.txt)) divert max undivert(1) </lang>

Output:

99
 @ 2008/10/03_08:39:34  @ 2008/10/03_08:40:40

Mathematica/Wolfram Language

<lang Mathematica>LC = 0; LCMax = 0; Scan[

  If[MemberQ[#, "OUT"], LC++; 
     If[LCMax < LC, LCMax = LC; LCMaxtimes = {};]; 
     If[LCMax == LC, AppendTo[LCMaxtimes, #4]],
  LC--;] &, Import["mlijobs.txt", "Table"]]

Print["The maximum number of licenses used was ", LCMax, ", at ", LCMaxtimes]</lang>

Output:
-> The maximum number of licenses used was 99, at {2008/10/03_08:39:34,2008/10/03_08:40:40}

MAXScript

<lang maxscript>fn licencesInUse = (

   local logFile = openFile "mlijobs.txt"
   local out = 0
   local maxOut = -1
   local maxTimes = #()
   
   while not EOF logFile do
   (
       line = readLine logFile
       if findString line "OUT" != undefined then
       (
           out += 1
       )
       else
       (
           out -= 1
       )
       if out > maxOut then
       (
           maxOut = out
           maxTimes = #()
       )
       if out == maxOut then
       (
           append maxTimes (filterString line " ")[4]
       )
   )
   format "Maximum simultaneous license use is % at the following times:\n" maxOut 
   for time in maxTimes do
   (
       format "%\n" time
   )
   close logFile

)

licencesInUse()</lang> Output

Maximum simultaneous license use is 99 at the following times:
2008/10/03_08:39:34
2008/10/03_08:40:40

Nim

Translation of: Python

<lang nim>import strutils

var

 curOut = 0
 maxOut = -1
 maxTimes = newSeq[string]()

for job in lines "mlijobs.txt":

 if "OUT" in job: inc curOut else: dec curOut
 if curOut > maxOut:
   maxOut = curOut
   maxTimes.setLen(0)
 if curOut == maxOut:
   maxTimes.add job.split[3]

echo "Maximum simultaneous license use is ", maxOut, " at the following times:" for i in maxTimes: echo " ", i</lang>

Output:
Maximum simultaneous license use is 99 at the following times:
  2008/10/03_08:39:34
  2008/10/03_08:40:40

OCaml

<lang ocaml>let () =

 let out = ref 0 in
 let max_out = ref(-1) in
 let max_times = ref [] in
 let ic = open_in "mlijobs.txt" in
 try while true do
   let line = input_line ic in
   let io, date, n =
     Scanf.sscanf line
       "License %3[IN OUT] %_c %19[0-9/:_] for job %d"
       (fun io date n -> (io, date, n))
   in
   if io = "OUT" then incr out else decr out;
   if !out > !max_out then
   ( max_out := !out;
     max_times := [date]; )
   else if !out = !max_out then
     max_times := date :: !max_times;
 done
 with End_of_file ->
   close_in ic;
   Printf.printf
     "Maximum simultaneous license use is %d \
      at the following times:\n" !max_out;
   List.iter print_endline !max_times;
</lang>

Oz

Translation of: Python

<lang oz>declare

 fun {MaxLicenses Filename ?Times}
    InUse = {NewCell 0}
    MaxInUse = {NewCell 0}
    MaxTimes = {NewCell nil}
 in
    for Job in {ReadLines Filename} do
       case {List.take Job 11} of "License OUT" then
    InUse := @InUse + 1
    if @InUse > @MaxInUse then
       MaxInUse := @InUse
       MaxTimes := nil
    end
    if @InUse == @MaxInUse then
       JobTime = {Nth {String.tokens Job & } 4}
    in
       MaxTimes := JobTime|@MaxTimes
    end
       [] "License IN " then
    InUse := @InUse - 1
       end
    end
    Times = {Reverse @MaxTimes}
    @MaxInUse
 end
 %% Helper.
 %% Returns a lazy list. So we don't keep the whole logfile in memory...
 fun {ReadLines Filename}
    F = {New class $ from Open.file Open.text end init(name:Filename)}
    fun lazy {ReadNext}
       case {F getS($)} of
          false then nil
       [] Line then
          Line|{ReadNext}
       end
    end
 in
    %% close file when handle becomes unreachable
    {Finalize.register F proc {$ F} {F close} end}
    {ReadNext}
 end
 Times
 MaxInUse = {MaxLicenses "mlijobs.txt" ?Times}

in

 {System.showInfo
  "Maximum simultaneous license use is "#MaxInUse#" at the following times:"}
 {ForAll Times System.showInfo}</lang>

Output:

Maximum simultaneous license use is 99 at the following times:
2008/10/03_08:39:34
2008/10/03_08:40:40

PARI/GP

<lang parigp>license()={

   my(v=externstr("type mlijobs.txt"),u,cur,rec,t);
   for(i=1,#v,
       u=Vec(v[i]);
       if(#u>9 && u[9] == "O",
           if(cur++>rec,
               rec=cur;
               t=[v[i]]
           ,
               if(cur == rec,t=concat(t,[v[i]]))
           )
       ,
           cur--
       )
   );
   print(apply(s->concat(vecextract(Vec(s),"15..33")), t));
   rec

};</lang>

["2008/10/03_08:39:34", "2008/10/03_08:40:40"]
%1 = 99

Perl

<lang perl>#!/usr/bin/perl -w use strict;

my $out = 0; my $max_out = -1; my @max_times;

open FH, '<mlijobs.txt' or die "Can't open file: $!"; while (<FH>) {

   chomp;
   if (/OUT/) {
       $out++;
   } else {
       $out--;
   }
   if ($out > $max_out) {
       $max_out = $out;
       @max_times = ();
   }
   if ($out == $max_out) {
       push @max_times, (split)[3];
   }

} close FH;

print "Maximum simultaneous license use is $max_out at the following times:\n"; print " $_\n" foreach @max_times;</lang> Example output:

Maximum simultaneous license use is 99 at the following times:
  2008/10/03_08:39:34
  2008/10/03_08:40:40

Phix

Modified copy of [[Euphoria]] <lang Phix>constant fn = open("mlijobs.txt", "r") integer maxout = 0, jobnumber sequence jobs = {}, maxtime, scanres string inout, jobtime object line while 1 do

   line = gets(fn)
   if atom(line) then exit end if
   scanres = scanf(line,"License %s @ %s for job %d\n")
   if length(scanres)!=1 then
       printf(1,"error scanning line: %s\n",{line})
       {} = wait_key()
       abort(0)
   end if
   Template:Inout,jobtime,jobnumber = scanres
   if inout="OUT" then
       jobs &= jobnumber
       if length(jobs)>maxout then
           maxout = length(jobs)
           maxtime = {jobtime}
       elsif length(jobs)=maxout then
           maxtime = append(maxtime, jobtime)
       end if
   else
       jobs[find(jobnumber,jobs)] = jobs[$]
       jobs = jobs[1..$-1]
   end if

end while close(fn)

printf(1, "Maximum simultaneous license use is %d at the following times:\n", maxout) for i = 1 to length(maxtime) do

   printf(1, "%s\n", {maxtime[i]})

end for</lang>

Output:
Maximum simultaneous license use is 99 at the following times:
2008/10/03_08:39:34
2008/10/03_08:40:40

PHP

<lang php>$handle = fopen ("mlijobs.txt", "rb"); $maxcount = 0; $count = 0; $times = array(); while (!feof($handle)) {

   $buffer = fgets($handle);
   $op = trim(substr($buffer,8,3));
   switch ($op){
       case 'IN':
           $count--;
       break;
       case 'OUT':
           $count++;
           preg_match('/([\d|\/|_|:]+)/',$buffer,$time);
           if($count>$maxcount){
               $maxcount = $count;
               $times = Array($time[0]);
           }elseif($count == $maxcount){
               $times[] = $time[0];
           }
       break;
   }   

} fclose ($handle);

echo $maxcount . '
'; for($i=0;$i<count($times);$i++){

   echo $times[$i] . '
';

}</lang>

99
2008/10/03_08:39:34
2008/10/03_08:40:40

PicoLisp

Translation of: AWK

Put the following into an executable file "licenses": <lang PicoLisp>#!/usr/bin/picolisp /usr/lib/picolisp/lib.l

(zero Count MaxCount)

(in (opt)

  (while (split (line) " ")
     (case (pack (cadr (setq Line @)))
        (IN
           (dec 'Count) )
        (OUT
           (let Time (cadddr Line)
              (cond
                 ((> (inc 'Count) MaxCount)
                    (setq MaxCount Count  MaxTimes Time) )
                 ((= Count MaxCount)
                    (setq MaxTimes (pack MaxTimes " and " Time)) ) ) ) ) ) ) )

(prinl "The biggest number of licenses is " MaxCount " at " MaxTimes " !") (bye)</lang> Then it can be called as

$ ./licenses mlijobs.txt
The biggest number of licenses is 99 at 2008/10/03_08:39:34 and 2008/10/03_08:40:40 !

PL/I

<lang pli> text3: procedure options (main); /* 19 November 2011 */

  declare line character (80) varying;
  declare (nout, max_nout) fixed;
  declare saveline character (80) varying controlled;
  declare k fixed binary;
  declare in file input;
  open file (in) title ('/TEXT-MAX.DAT,TYPE(TEXT),RECSIZE(80)' );
  on endfile (in) go to finish_up;
  max_nout, nout = 0;
  do forever;
     get file (in) edit (line) (L);
     if substr(line, 9, 4) = 'OUT' then nout = nout+1;
     else if substr(line, 9, 3) = 'IN' then
        nout = nout-1;
     if nout = max_nout then
        do; allocate saveline; saveline = line; end;
     if nout > max_nout then
        do;
           do while (allocation(saveline) > 0); free saveline; end;
           max_nout = nout;
           allocate saveline;
           saveline = line;
        end;
  end;

finish_up:

  put skip list ('The maximum number of licences taken out = ' || max_nout);
  do while (allocation(saveline) > 0);
     k = index(saveline, '@');
     if k > 0 then put skip list ('It occurred at ' || substr(saveline, k+1) );
     free saveline;
  end;

end text3; </lang> OUTPUT:

The maximum number of licences taken out =       99 
It occurred at  2008/10/03_08:40:40 for job 1837 
It occurred at  2008/10/03_08:39:34 for job 1833 

PowerShell

<lang PowerShell> [int]$count = 0 [int]$maxCount = 0 [datetime[]]$times = @()

$jobs = Get-Content -Path ".\mlijobs.txt" | ForEach-Object {

   [string[]]$fields   = $_.Split(" ",[StringSplitOptions]::RemoveEmptyEntries)
   [datetime]$datetime = Get-Date $fields[3].Replace("_"," ")
   [PSCustomObject]@{
       State = $fields[1]
       Date  = $datetime
       Job   = $fields[6]
   }

}

foreach ($job in $jobs) {

   switch ($job.State)
   {
       "IN"
       {
           $count--
       }
       "OUT"
       {
           $count++
           if ($count -gt $maxCount)
           {
               $maxCount = $count
               $times = @()
               $times+= $job.Date
           }
           elseif ($count -eq $maxCount)
           {
               $times+= $job.Date
           }
       }
   }

}

[PSCustomObject]@{

   LicensesOut = $maxCount
   StartTime   = $times[0]
   EndTime     = $times[1]

} </lang>

Output:
LicensesOut StartTime            EndTime             
----------- ---------            -------             
         99 10/3/2008 8:39:34 AM 10/3/2008 8:40:40 AM

PureBasic

<lang PureBasic>OpenConsole()

If ReadFile(0, OpenFileRequester("Text processing/3","mlijobs.txt","All files",1))

 While Not Eof(0)
   currline$=ReadString(0)
   If StringField(currline$,2," ")="OUT"
     counter+1
   Else
     counter-1
   EndIf
   If counter>max  
     max=counter
     maxtime$=StringField(currline$,4," ")
   ElseIf counter=max
     maxtime$+#CRLF$+StringField(currline$,4," ")
   EndIf
 Wend
 PrintN(Str(max)+" license(s) used at ;"+#CRLF$+maxtime$)
 CloseFile(0)            

Else

 PrintN("Failed to open the file.")

EndIf

PrintN(#CRLF$+"Press ENTER to exit"): Input() CloseConsole()</lang>

99 license(s) used at ;
2008/10/03_08:39:34
2008/10/03_08:40:40

Press ENTER to exit

Python

<lang python>out, max_out, max_times = 0, -1, [] for job in open('mlijobs.txt'):

   out += 1 if "OUT" in job else -1
   if out > max_out:
       max_out, max_times = out, []
   if out == max_out:
       max_times.append(job.split()[3])
       

print("Maximum simultaneous license use is %i at the following times:" % max_out) print(' ' + '\n '.join(max_times))</lang>

Output:
Maximum simultaneous license use is 99 at the following times:
  2008/10/03_08:39:34
  2008/10/03_08:40:40

R

<lang R>

  1. Read in data, discard useless bits

dfr <- read.table("mlijobs.txt") dfr <- dfr[,c(2,4)]

  1. Find most concurrent licences, and when

n.checked.out <- cumsum(ifelse(dfr$V2=="OUT", 1, -1)) times <- strptime(dfr$V4, "%Y/%m/%d_%H:%M:%S") most.checked.out <- max(n.checked.out) when.most.checked.out <- times[which(n.checked.out==most.checked.out)]

  1. As a bonus, plot license use

plot(times, n.checked.out, type="s") </lang>

Racket

<lang racket>#lang racket

reads a licence file on standard input
returns max licences used and list of times this occurred

(define (count-licences)

 (let inner ((ln (read-line)) (in-use 0) (max-in-use 0) (times-list null))
   (if (eof-object? ln) 
       (values max-in-use (reverse times-list))
       (let ((mtch (regexp-match #px"License (IN |OUT) @ (.*) for job.*" ln)))
         (cond
           [(string=? "OUT" (second mtch))
            (let ((in-use+1 (add1 in-use)))
              (cond
                [(> in-use+1 max-in-use)
                 (inner (read-line) in-use+1 in-use+1 (list (third mtch)))]
                [(= in-use+1 max-in-use)
                 (inner (read-line) in-use+1 max-in-use (cons (third mtch) times-list))]
                [else (inner (read-line) in-use+1 max-in-use times-list)]))]
           [(string=? "IN " (second mtch))
            (inner (read-line) (sub1 in-use) max-in-use times-list)]
           [else (inner (read-line) in-use max-in-use times-list)])))))

(define-values (max-used max-used-when) (with-input-from-file "mlijobs.txt" count-licences)) (printf "Maximum licences in simultaneously used is ~a at the following times:~%"

       max-used)

(for-each displayln max-used-when) </lang> Output:

Maximum licences in simultaneously used is 99 at the following times:
2008/10/03_08:39:34
2008/10/03_08:40:40

The following takes advantage of a combination of for/fold and (in-lines) (and is possible more in the Racket idiom, rather than just using (read-line) and (regexp-match):

<lang racket>#lang racket

reads a licence file on standard input
returns max licences used and list of times this occurred

(define (count-licences)

 (define (sub-count-licences)
   (for/fold ((in-use 0) (max-in-use 0) (times-list null))
     ((ln (in-lines)))
     (let ((mtch (regexp-match #px"License (IN |OUT) @ (.*) for job.*" ln)))
       (cond
         [(string=? "OUT" (second mtch))
          (let ((in-use+1 (add1 in-use)))
            (cond
              [(> in-use+1 max-in-use) (values in-use+1 in-use+1 (list (third mtch)))]
              [(= in-use+1 max-in-use) (values in-use+1 max-in-use (cons (third mtch) times-list))]
              [else (values in-use+1 max-in-use times-list)]))]
         [(string=? "IN " (second mtch)) (values (sub1 in-use) max-in-use times-list)]
         [else (values in-use max-in-use times-list)]))))
 (let-values (((in-use max-in-use times-list) (sub-count-licences)))
   (values max-in-use (reverse times-list))))

(define-values (max-used max-used-when) (with-input-from-file "mlijobs.txt" count-licences)) (printf "Maximum licences in simultaneously used is ~a at the following times:~%" max-used) (for-each displayln max-used-when)</lang> (Same output)

Raku

(formerly Perl 6) Add some error trapping as recommended by Dijkstra. Not particularly necessary for this specific example but it doesn't hurt to be proactive.


Redirecting the mlijobs.txt file to STDIN: <lang perl6>my %licenses;

%licenses<count max> = 0,0;

for $*IN.lines -> $line {

   my ( $license, $date_time );
   ( *, $license, *, $date_time ) = split /\s+/, $line;
   if $license eq 'OUT' {
       %licenses<count>++;
       if %licenses<count> > %licenses<max> {
           %licenses<max>   = %licenses<count>;
           %licenses<times> = [$date_time];
       }
       elsif %licenses<count> == %licenses<max> {
           %licenses<times>.push($date_time);
       }
   }
   elsif $license eq 'IN' {
       if %licenses<count> == %licenses<max> {
           %licenses<times>[*-1] ~= " through " ~ $date_time;
       }
       %licenses<count>--;
   }
   else {
       # Not a licence OUT or IN event, do nothing
   }

};

my $plural = %licenses<times>.elems == 1 ??  !! 's';

say "Maximum concurrent licenses in use: {%licenses<max>}, in the time period{$plural}:"; say join ",\n", %licenses<times>.list;</lang>

Example output:

Maximum concurrent licenses in use: 99, in the time periods:
2008/10/03_08:39:34 through 2008/10/03_08:39:45,
2008/10/03_08:40:40 through 2008/10/03_08:40:47

REXX

version 1

<lang rexx>/*REXX program processes instrument data as read from a time sorted data file.*/ iFID= 'LICENSE.LOG' /*the fileID of the input file. */ high=0 /*highest number of licenses (so far). */

  1. =0 /*the count of number of licenses out. */

n=0 /*the number of highest licenses out. */

   do recs=0  while lines(iFID)\==0   /* [↓]  read file  until  end─of─file. */
   parse value linein(iFID) with . ? . $       /*get IN│OUT status, job info.*/
   if ?=='IN'  then                   #=#-1    /*decrement the license count.*/
               else if ?=='OUT'  then #=#+1    /*increment  "     "      "   */
   if # >high then do;  n=1;    job.1=$;  end  /*the job info for highest cnt*/
   if #==high then do;  n=n+1;  job.n=$;  end  /* "   "    "   "   equal   " */
   high=max(high,#)                            /*calculate max license count.*/
   end   /*while ···*/

say recs 'records read from the input file: ' iFID say 'The maximum number of licenses out is ' high " at:" say

    do j=1  for n                     /*show what/when max licenses occurred.*/
    say left(,20)  job.j            /*indent the information displayed.    */
    end   /*j*/                       /*stick a fork in it,  we're all done. */</lang>

output   when using the default input file:

10000 records read from the input file:  LICENSE.LOG
The maximum number of licenses out is  99  at:

                     2008/10/03_08:39:34 for job 1833
                     2008/10/03_08:40:40 for job 1837

Version 2 dual-coded for PC and TSO

It should be noted that almost every REXX interpreter returns a different string for   parse source   under Microsoft Windows:

  •   MSDOS     for   BREXX
  •   PCDOS     for   PC/REXX   and   Personal Rexx for DOS
  •   WIN           for   Personal Rexx for Windows
  •   WIN32       for   Regina
  •   Win32       for   R4   and   ROO


It is unknown which classic REXX interpreter can be used (under Windows) below, it fails for the above mentioned seven REXX interpreters.
I am sure it has worked for Regina. Maybe this is now correct for all the WIN (and xxDOS) situations (pun intended) <lang rexx>/* REXX **************************************************************

  • 19.11.2012 Walter Pachl transcribed from PL/I
  • and dual-coded (for PC (Windows) and TSO)
                                                                                                                                            • /

Parse Source source call time 'R' Say source Parse Upper source system . If left(system,3)='WIN' |, /* changed from 'Windows' (I see WIN64 in source) */

  wordpos(system,'MSDOS PCDOS')>0 Then Do  
 fid='mlijobs.txt'
 Do i=1 By 1 While lines(fid)>0
   l.i=linein(fid)
   End
 l.0=i-1
 End

Else Do

 "ALLOC FI(IN) DA(MLIJOBS.TEXT) SHR REUSE"
 'EXECIO * DISKR IN (STEM L. FINIS'
 'FREE FI(IN)'
 End

store.0=0 max_nout=0 nout =0 cnt=0 cnt.=0 do i=1 To l.0

 line=l.i
 Parse Var line 9 inout +3
 Select
   When inout='OUT' then nout = nout+1;
   When inout='IN'  then nout = nout-1;
   Otherwise Iterate
   End
 cnt.nout=cnt.nout+1
 cnt=cnt+1
 if nout = max_nout then
   Call store line
 if nout > max_nout then Do
   max_nout=nout
   drop store.
   store.0=0
   Call store
   end;
 end;

Say 'The maximum number of licences taken out = ' max_nout Do i=1 to store.0

 k=pos('@',store.i)
 Say 'It occurred at 'substr(store.i,k+1)
 End

limit=5 Do nout=0 To max_nout

 If nout=limit+1 Then Say '.........'
 If nout<=limit | nout>=max_nout-limit Then
   Say right(cnt.nout,5) right(nout,3)
 End

Say right(cnt,5) 'Jobs' Say time('E') 'seconds (elapsed)' Exit

store:

 z=store.0+1
 store.z=line
 store.0=z
 Return</lang>
Output:

on Windows

D:\>rexx maxl
WindowsNT COMMAND D:\maxl.rex
The maximum number of licences taken out =  99
It occurred at  2008/10/03_08:39:34 for job 1833
It occurred at  2008/10/03_08:40:40 for job 1837
    1   0
    2   1
    2   2
    2   3
    2   4
    2   5
.........
   24  94
   22  95
   15  96
    7  97
    5  98
    2  99
10000 Jobs
0.234000 seconds (elapsed) ooRexx

D:\>regina maxl
WIN64 COMMAND D:\maxl.rex
...
10000 Jobs
.177000 seconds (elapsed) Regina
Output:

on TSO

TSO COMMAND LIC SYS00059 N555555.PRIV.CLIST ? TSO ISPF ?
The maximum number of licences taken out =  99
It occurred at  2008/10/03_08:39:34 for job 1833
It occurred at  2008/10/03_08:40:40 for job 1837
    1   0
    2   1
    2   2
    2   3
    2   4
    2   5
.........
   24  94
   22  95
   15  96
    7  97
    5  98
    2  99
10000 Jobs
0.384154 seconds (elapsed)

Ruby

<lang ruby>out = 0 max_out = -1 max_times = []

File.foreach('mlijobs.txt') do |line|

 out += line.include?("OUT") ? 1 : -1
 if out > max_out
   max_out = out
   max_times = []
 end
 max_times << line.split[3]  if out == max_out

end

puts "Maximum simultaneous license use is #{max_out} at the following times:" max_times.each {|time| puts " #{time}"}</lang>

Example output:

Maximum simultaneous license use is 99 at the following times:
  2008/10/03_08:39:34
  2008/10/03_08:40:40

Run BASIC

<lang lb>open "c:\data\temp\logFile.txt" for input as #f while not(eof(#f))

 line input #f, a$
 if word$(a$,2," ") = "IN" then count = count - 1 else count = count + 1
 maxCount = max(maxCount,count)

wend open "c:\data\temp\logFile.txt" for input as #f while not(eof(#f))

 line input #f, a$
 if word$(a$,2," ") = "IN" then count = count - 1 else count = count + 1
 if count = maxCount then theDate$ = theDate$ + " | " + word$(a$,4," ") + " Job:";word$(a$,7," ")

wend print maxCount;" ";theDate$</lang>

Rust

<lang Rust>type Timestamp = String;

fn compute_usage<R, S, E>(lines: R) -> Result<(u32, Vec<Timestamp>), E> where

   S: AsRef<str>,
   R: Iterator<Item = Result<S, E>>,

{

   let mut timestamps = Vec::new();
   let mut current = 0;
   let mut maximum = 0;
   for line in lines {
       let line = line?;
       let line = line.as_ref();
       if line.starts_with("License IN") {
           current -= 1;
       } else if line.starts_with("License OUT") {
           current += 1;
           if maximum <= current {
               let date = line.split_whitespace().nth(3).unwrap().to_string();
               if maximum < current {
                   maximum = current;
                   timestamps.clear();
               }
               timestamps.push(date);
           }
       }
   }
   Ok((maximum, timestamps))

}

fn main() -> std::io::Result<()> {

   use std::io::{BufRead, BufReader};
   let file = std::fs::OpenOptions::new().read(true).open("mlijobs.txt")?;
   let (max, timestamps) = compute_usage(BufReader::new(file).lines())?;
   println!("Maximum licenses out: {}", max);
   println!("At time(s): {:?}", timestamps);
   Ok(())

}</lang>

Scala

Translated imperative version

Can be seen running in your browser Scastie (remote JVM). <lang Scala>import java.io.{BufferedReader, InputStreamReader} import java.net.URL

object License0 extends App {

 val url = new URL("https://raw.githubusercontent.com/def-/nim-unsorted/master/mlijobs.txt")
 val in = new BufferedReader(new InputStreamReader(url.openStream()))
 val dates = new collection.mutable.ListBuffer[String]
 var (count: Int, max: Int) = (0, Int.MinValue)
 var line: String = _
 while ( {line = in.readLine; line} != null) {
   if (line.startsWith("License OUT ")) count += 1
   if (line.startsWith("License IN ")) count -= 1 // Redundant test when "OUT" 
   if (count > max) { // Fruitless execution when "License IN " 
     max = count
     val date = line.split(" ")(3)
     dates.clear()
     dates += date
   } else if (count == max) {
     val date = line.split(" ")(3)
     dates += date
   }
 }
 println("Max licenses out: " + max)
 println("At time(s): " + dates.mkString(", "))

}</lang>

Smart Imperative Scala with dirty side effects

Output:

Best seen running in your browser Scastie (remote JVM).

<lang Scala>import scala.collection.mutable.ListBuffer

object License1 extends App {

 val src = io.Source.fromURL("https://raw.githubusercontent.com/def-/nim-unsorted/master/mlijobs.txt")
 val dates = new ListBuffer[String]
 var (max, count) = (Int.MinValue, 0)
 src.getLines.foreach { line =>
   def date = line.split(" ")(3)
   if (line.startsWith("License OUT ")) {
     count += 1
     if (count > max) {
       max = count
       dates.clear
     }
     if (count == max) dates += date
   } else if (line.startsWith("License IN ")) count -= 1
 }
 println("Max licenses out: " + max)
 println("At time(s): " + dates.mkString(", "))

}</lang>

Clean coded FP with (tail) recursion, no side effects

Output:

Best seen running in your browser Scastie (remote JVM).

<lang Scala>import scala.annotation.tailrec

object License2 extends App {

 type resultTuple = (Int /*max*/, Int /*count*/, List[String] /*dates*/ )
 val src = io.Source.fromURL(
   "https://raw.githubusercontent.com/def-/nim-unsorted/master/mlijobs.txt")
 val iter = src.getLines()
 val (max, count, dates) = loop(Int.MinValue, 0, Nil)
 def lineToResult(tuple: (resultTuple, String)): resultTuple = {
   val ((max, count, dates), line) = tuple
   def date = line.split(" ")(3)
   if (line.startsWith("License OUT ")) {
     if (count + 1 > max) (count + 1, count + 1, List(date))
     else if (count + 1 == max) (max, max, dates :+ date)
     else (max, count + 1, dates)
   } else if (line.startsWith("License IN ")) tuple._1.copy(_2 = count - 1)
   else tuple._1
 }
 @tailrec
 private def loop(tuple: resultTuple): resultTuple = {
   def lineToResult(tuple: (resultTuple, String)): resultTuple = {
     val ((max, count, dates), line) = tuple
     def date = line.split(" ")(3)
     if (line.startsWith("License OUT ")) {
       if (count + 1 > max) (count + 1, count + 1, List(date))
       else if (count + 1 == max) (max, max, dates :+ date)
       else (max, count + 1, dates)
     } else if (line.startsWith("License IN ")) tuple._1.copy(_2 = count - 1)
     else tuple._1
   }
   if (iter.hasNext)
     loop(lineToResult(tuple, iter.next()))
   else tuple
 }
 println("Max licenses out: " + max)
 println("At time(s): " + dates.mkString(", "))

}</lang>

Totally FP with foldLeft

Output:

Best seen running in your browser Scastie (remote JVM).

<lang Scala>object License3 extends App {

 type resultTuple = (Int /*max*/, Int /*count*/, List[String] /*dates*/ )
 val src = io.Source.fromURL("https://raw.githubusercontent.com/def-/nim-unsorted/master/mlijobs.txt")
 val (max, count, dates): resultTuple =
   src.getLines().foldLeft(Int.MinValue, 0, Nil: List[String]) {
     case ((max: Int, count: Int, dates: List[String]), line: String)
       if line.startsWith("License OUT ") =>
       def date = line.split(" ")(3)
       if (count + 1 > max) (count + 1, count + 1, List(date))
       else if (count + 1 == max) (max, max, dates :+ date)
       else (max, count + 1, dates)
     case (resultPart: resultTuple, line: String)
       if line.startsWith("License IN ") =>
       resultPart.copy(_2 = resultPart._2 - 1)
     case (resultPart, _) => resultPart
   }
 println("Max licenses out: " + max)
 println("At time(s): " + dates.mkString(", "))

}</lang>

Seed7

<lang seed7>$ include "seed7_05.s7i";

const proc: main is func

 local
   var file: inFile is STD_NULL;
   var string: line is "";
   var integer: currLicenses is 0;
   var integer: maxLicenses is 0;
   var array string: maxLicenseTimes is 0 times "";
   var string: eventTime is "";
 begin
   inFile := open("mlijobs.txt", "r");
   while hasNext(inFile) do
     line := getln(inFile);
     if line[9 len 3] = "OUT" then
       incr(currLicenses);
       if currLicenses >= maxLicenses then
         if currLicenses > maxLicenses then
           maxLicenses := currLicenses;
           maxLicenseTimes := 0 times "";
         end if;
         maxLicenseTimes &:= line[15 len 19];
       end if;
     elsif currLicenses > 0 then
       decr(currLicenses);
     end if;
   end while;
   close(inFile);
   writeln("Maximum simultaneous license use is " <& maxLicenses <& " at the following times:");
   for eventTime range maxLicenseTimes do
     writeln(eventTime);
   end for;
 end func;</lang>

Output:

Maximum simultaneous license use is 99 at the following times:
2008/10/03_08:39:34
2008/10/03_08:40:40

Sidef

Translation of: Perl

<lang ruby>var out = 0 var max_out = -1 var max_times = []

ARGF.each { |line|

   out += (line ~~ /OUT/ ? 1 : -1)
   if (out > max_out) {
       max_out = out
       max_times = []
   }
   if (out == max_out) {
       max_times << line.split(' ')[3]
   }

}

say "Maximum simultaneous license use is #{max_out} at the following times:" max_times.each {|t| say " #{t}" }</lang>

Output:
$ sidef max_licenses.sf < mlijobs.txt
Maximum simultaneous license use is 99 at the following times:
  2008/10/03_08:39:34
  2008/10/03_08:40:40

Tcl

Translation of: Python

<lang tcl> set out 0

set max_out -1
set max_times {}

foreach job [split [read [open "mlijobs.txt" "r"]] "\n"] {
    if {[lindex $job 1] == "OUT"} {
        incr out 
    } { 
        incr out -1
    }   
    if {$out > $max_out} {
        set max_out $out
        set max_times {}
    }   
    if {$out == $max_out} {
        lappend max_times [lindex $job 3]
    }   
}

puts "Maximum simultaneous license use is $max_out at the following times:"
foreach t $max_times {
    puts "  $t"
}</lang>

Output matches Python

TUSCRIPT

<lang tuscript> $$ MODE TUSCRIPT joblog="mlijobs.txt",jobnrout=0 log=FILE (joblog) DICT jobnrout CREATE LOOP l=log jobout=EXTRACT (l,":License :"|,": :")

IF (jobout=="out") THEN
 time=EXTRACT (l,":@ :"|,": :"), jobnrout=jobnrout+1
 DICT jobnrout APPEND/QUIET jobnrout,num,cnt,time;" "
ELSE
 jobnrout=jobnrout-1
ENDIF

ENDLOOP DICT jobnrout UNLOAD jobnrout,num,cnt,time DICT jobnrout SIZE maxlicout times=SELECT (time,#maxlicout) PRINT "The max. number of licences out is ", maxlicout PRINT "at these times: ", times </lang> Output:

The max. number of licences out is 99
at these times: 2008/10/03_08:39:34 2008/10/03_08:40:40

TXR

Working with Version 266. <lang TXR> @(bind *times* #H((:eql-based) nil)) @(bind *licenses-out* 0) @(bind *maximum-licenses-out* 0) @(collect) License @statuses @@ @dateTimes for job @jobNumbers @(end) @(do (each ((status statuses)

            (dateTime dateTimes)
            (jobNumber jobNumbers))
      (set *licenses-out*
        (if (equal status "OUT")
          (progn 
            (when (>= (+ *licenses-out* 1) *maximum-licenses-out*)
              (set *maximum-licenses-out* (+ *licenses-out* 1))
              (pushhash *times* *maximum-licenses-out* dateTime))
            (+ *licenses-out* 1))
          (+ *licenses-out* -1)))))

@(output) Maximum # of licenses out: @{*maximum-licenses-out*} Peak time(s): @{(reverse (gethash *times* *maximum-licenses-out*))} @(end) </lang> Output:

Maximum # of licenses out: 99
Peak time(s): 2008/10/03_08:39:34 2008/10/03_08:40:40

Ursala

Four functions are defined. Log lexes the log file, which can be accessed as a pre-declared constant without explicit I/O by being given as a compile-time command line parameter. Scan accumulates running totals of licenses in use. Search identifies the maxima, and format transforms the results to human readable form.

<lang Ursala>

  1. import std
  2. import nat

log = ^(~&hh==`O,~&tth)*FtPS sep` *F mlijobs_dot_txt scan = @NiX ~&ar^& ^C/~&alrhr2X ~&arlh?/~&faNlCrtPXPR ~&fabt2R search = @lSzyCrSPp leql$^&hl@lK2; ^/length@hl ~&rS format = ^|C\~& --' licenses in use at'@h+ %nP

  1. show+

main = format search scan log</lang> output:

99 licenses in use at
2008/10/03_08:39:34
2008/10/03_08:40:40

Vedit macro language

<lang vedit> File_Open("|(PATH_ONLY)\data\mlijobs.txt", BROWSE)

  1. 1 = 0 // Number of licenses active
  2. 2 = 0 // Max number of active licenses found

Repeat(ALL) {

   Search("|{OUT,IN}|W@", ADVANCE+ERRBREAK)
   if (Match_Item == 1) {                      // "OUT"
       #1++
       if (#1 > #2) {                          // new high value
           #2 = #1
           Reg_Empty(10)                       // empty the time list
       }
       if (#1 == #2) {                         // same as high value
           Reg_Copy(10, 1, APPEND)             // store time
       }
   } else {                                    // "IN"
       #1--
   }

}

Message("Maximum simultaneous license use is ") Num_Type(#2, LEFT+NOCR) Message(" at the following times:\n") Reg_Type(10)

Buf_Quit(OK) </lang>

Output:

Maximum simultaneous license use is 99 at the following times:
 2008/10/03_08:39:34 for job 1833
 2008/10/03_08:40:40 for job 1837

Wren

<lang ecmascript>import "io" for File

var lines = File.read("mlijobs.txt").replace("\r", "").split("\n") var out = 0 var max = 0 var times = [] for (line in lines) {

   if (line.startsWith("License OUT")) {
       out = out + 1
       if (out >= max) {
           var sp = line.split(" ")
           if (out > max) {
               max = out
               times.clear()
           }
           times.add(sp[3])
       }
   } else if (line.startsWith("License IN")) {
       out = out - 1
   }

}

System.print("The maximum licenses that were out = %(max) at time(s):") System.print(" " + times.join("\n "))</lang>

Output:
The maximum licenses that were out = 99 at time(s):
  2008/10/03_08:39:34
  2008/10/03_08:40:40

zkl

Translation of: D

The referenced log file is no longer available, so, using the example log: <lang zkl>nOut,maxOut,maxTimes:=0,-1,List(); foreach job in (File("mlijobs.txt")){

  _,status,_,date:=job.split();
  nOut+=( if(status.toUpper()=="OUT") 1 else -1 );
  if(nOut>maxOut){ maxOut=nOut; maxTimes.clear(); }
  if(nOut==maxOut) maxTimes.append(date);

} println(("Maximum simultaneous license use is %d at"

        " the following times:\n %s").fmt(maxOut,maxTimes.concat("\n")));</lang>
Output:
Maximum simultaneous license use is 1 at the following times:
 2008/10/03_23:51:05