Text processing/Max licenses in use
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.
You are encouraged to solve this task according to the task description, using any language you may know.
Assume the softwares file faithfully records a checkout event when a copy of the software starts and a checkin event when the software finishes. 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
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.
APL
<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
<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 maxtime = time }
}
$2=="IN" { count = count - 1 } END {print "The biggest number of licenses is " maxcount " at " maxtime " !"} </lang>
Output: The biggest number of licenses is 99 at 2008/10/03_08:39:34 !
C
<lang c>#include <stdio.h>
- include <stdlib.h>
- include <string.h>
- include <sys/types.h>
- define INOUT_LEN 4
- define TIME_LEN 20
- 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>
C++
<lang C++>#include <iostream>
- include <boost/algorithm/string.hpp>
- include <string>
- include <fstream>
- include <vector>
int main( int argc, char * argv[ ] ) {
if ( argc != 2 ) { std::cout << "Error: syntax: ./licenseout <filename of data file>!\n " ; return 1 ; } std::ifstream infile ( argv[ 1 ] , std::ios::in ) ; //nextLine holds the next line of the text file , maxTime the time with //most licenses out , timeOut the respective time entry in a file line std::string nextLine , maxTime , timeOut ; //count holds the number of licenses out at any time , maxcount the maximum //number int count = 0 , maxcount = 0 ; std::vector<std::string> lineElements ; //for the words of a text line if ( infile.is_open( ) ) { while ( infile ) {
getline( infile , nextLine ) ; boost::split( lineElements, nextLine , boost::is_any_of( " " ) ) ; if ( lineElements[ 1 ] == "OUT" ) { count++ ;
timeOut = lineElements[ 3 ] ;
} if ( lineElements[ 1 ] == "IN" ) count-- ; if ( count > maxcount ) { maxcount = count ; maxTime = timeOut ; } lineElements.clear( ) ;
} infile.close( ) ; std::cout << "The maximum number of licenses out is " << maxcount <<
" at " << maxTime << " !\n" ;
return 0 ; } else { std::cout << "Could not open " << argv[ 1 ] << " !\n" ; return 1 ; }
} </lang>
Output: The maximum number of licenses out is 99 at 2008/10/03_08:39:34 !
Common Lisp
<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> import std.stdio; import std.file; import std.string; void main() {
int maxlic = 0,currlic = 0; char[][]maxlic_times; foreach(line;split(cast(char[])read("mlijobs.txt"),"\n")) if (line.length) { if (line[8] == 'O') { // license out currlic++; if (currlic < maxlic) continue; if (currlic > maxlic) { maxlic = currlic; maxlic_times = null; } maxlic_times ~= line[14..33]; } else { // license in currlic--; } }
writefln("Found max %d licenses out at times:",maxlic); foreach(time;maxlic_times) { writefln("%s",time); }
} </lang>
E
<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>
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
<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
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>
J
<lang j>
NB. Parse data, select columns 'I D' =: (8 ; 14+i.19) { ::]"1 L:0 ];._2 ] 1!:1 ::("_) <'licenses.txt' NB. Calculate number of licenses used at any given time lu =: +/\ _1 ^ 'OI' i. I NB. Find the maxima mx =: (I.@:= >./) lu 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
<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
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
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
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
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
<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
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
Python
<lang python>out = 0 max_out = -1 max_times = []
for job in open('mlijobs.txt'):
if "OUT" in job: out += 1 else: out -= 1 if out > max_out: max_out = out max_times = [] if out == max_out: max_times.append(job.split()[3])
print "Maximum simultaneous license use is", max_out, "at the following times:" for time in max_times:
print " ", 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
R
<lang R>
- Read in data, discard useless bits
dfr <- read.table("mlijobs.txt") dfr <- dfr[,c(2,4)]
- 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)]
- As a bonus, plot license use
plot(times, n.checked.out, type="s") </lang>
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
Tcl
<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
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>
- import std
- 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
- 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 = 0 // Number of licenses active
- 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