Skip to content

Commit

Permalink
added some documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
AsbjoernJC committed Jun 18, 2024
1 parent beac31f commit 259a34a
Show file tree
Hide file tree
Showing 19 changed files with 157 additions and 36 deletions.
1 change: 0 additions & 1 deletion TimeTrace/src/components/predefined-res/Interval.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {FormEvent, useState } from "react";
import ModalInput from "../modal/ModalInput";
import { IntervalClass } from "./PredefinedREs";
import FormButtonGroup from "../button/FormButtonGroup";
import { validateNumberInput } from "./numbersOnlyInput";

interface IntervalProps {
reObject: IntervalClass;
Expand Down
1 change: 0 additions & 1 deletion TimeTrace/src/components/predefined-res/Over.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {FormEvent, useState } from "react";
import ModalInput from "../modal/ModalInput";
import { OverClass } from "./PredefinedREs";
import FormButtonGroup from "../button/FormButtonGroup";
import { validateNumberInput } from "./numbersOnlyInput";

interface InclusiveOverProps {
reObject: OverClass;
Expand Down
7 changes: 0 additions & 7 deletions TimeTrace/src/components/predefined-res/numbersOnlyInput.ts

This file was deleted.

8 changes: 7 additions & 1 deletion TimeTrace/src/components/predefined-tres/PredefinedTREs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,18 @@ export enum PredefinedTre {
TimedSequential,
}

/**
* Every predefinedTRE must have a title ({@link IPredefinedTRE.title}) used for the title of the modal
* Every predefiendTRE must have a method ({@link IPredefinedTRE.insertTRE}) that returns the predefinedTRE as a string
*/
export interface IPredefinedTRE {
title: string;
insertTRE: () => string;
}


/**
* To make the {@link WithinTREClass} a bit more compact
*/
export interface WithinTREInput {
firstGroup: string;
secondGroup: string;
Expand Down
5 changes: 5 additions & 0 deletions TimeTrace/src/models/LogHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,22 @@ export abstract class LogHandler {

for (let i = 0; i < MonaaOutput.length; i++) {
const line = MonaaOutput[i];

//Indicates that a new match begins
if (line.includes("=======") && foundStart !== -1 && foundEnd !== -1) { //RESET interval
let SearchInterval: SearchInterval = { start: foundStart, end: foundEnd };
foundIntervals.push(SearchInterval);

foundStart = -1;
foundEnd = -1;
}
//Lower bound of Monaazone
else if (MonaaOutput[i].includes("<= t <") || MonaaOutput[i].includes("< t <") || MonaaOutput[i].includes("< t <=") || MonaaOutput[i].includes("<= t <=")) { //FIND Start

foundStart = parseFloat(MonaaOutput[i].split(/\s+/).filter(part => !isNaN(parseFloat(part))).pop() || '');
}

//Upper bound of Monaazone
else if (MonaaOutput[i].includes("<= t' <") || MonaaOutput[i].includes("< t' <") || MonaaOutput[i].includes("< t' <=") || MonaaOutput[i].includes("<= t' <=")) { //FIND End

foundEnd = parseFloat(MonaaOutput[i].split(/\s+/).filter(part => !isNaN(parseFloat(part))).shift() || '');
Expand Down
24 changes: 20 additions & 4 deletions TimeTrace/src/models/LogSearcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,29 @@ export abstract class LogSearcher {
return this._hashMap;
}

/**
* Finds the indices in the logfile where there is a match
*/
public static findZones(searchIntervals: SearchInterval[]): MonaaZone[] {
console.time("findZones");
let binaryTime = 0, binaryCount = 0
let hashTime = 0, hashCount = 0
let startOfLastFoundMatch = 0;
const MonaaZoneMatches: MonaaZone[] = [];

for (let i = 0; i < searchIntervals.length; i++) {
let match = new MonaaZone();
let hashTimeStart = performance.now()
let start: number | null = this.hashMap.get(Math.round(searchIntervals[i].start).toString());
let end: number | null = this.hashMap.get(Math.round(searchIntervals[i].end).toString());

// Start and end could be looked up in the hashmap.
if (start !== null && end !== null) {
match.lineMatches = Array.from({ length: end - start + 1 }, (_, index) => start! + index); //array containing numbers from start to end
hashTime += performance.now() - hashTimeStart;
hashCount++;
}
// Start or end may be null. We will use binary search
else {
let binaryTimeStart = performance.now()
match = this.findNearestZone(searchIntervals[i], start != null ? start : startOfLastFoundMatch);
Expand All @@ -50,6 +57,9 @@ export abstract class LogSearcher {
return MonaaZoneMatches
}

/**
* Finds an individual match in the case where the start or end could not be found via the hashmap.
*/
public static findNearestZone(searchInterval: SearchInterval, startOfLastMatch: number): MonaaZone {
let foundmatch = new MonaaZone();
let startingIndex = this.findNearestIndex(startOfLastMatch, searchInterval);
Expand All @@ -63,14 +73,16 @@ export abstract class LogSearcher {
return foundmatch;
}

/**
*
* Converts the timestamps to ms when a file is uploaded
*/
public static updateTimestampInfo(logFile: string[]) {
let prevLineTime: number = 0;
const timestamps: number[] = [];

logFile.forEach((line: string) => {
const eventTimeStamp = parseInt(LogFormatter.convertDateToMs(extractTimeStamp(line)));
timestamps.push(eventTimeStamp);
prevLineTime = eventTimeStamp;
});

let averageTimegrowth: number = (timestamps[timestamps.length - 1] - timestamps[0]) / timestamps.length
Expand All @@ -79,15 +91,19 @@ export abstract class LogSearcher {
this.averageGrowth = averageTimegrowth;
}

/** Used to find the starting index. */
private static findNearestIndex(lastFoundIndex: number, searchInterval: SearchInterval): number {
const firstTimestamp = this.timestamps[0];
const difference = searchInterval.start - firstTimestamp;
const multiplum = difference / this.averageGrowth;
let startingIndex = Math.floor(multiplum);

if (searchInterval.start < this.timestamps[startingIndex]) { // search in left side if we overshot estimation
// search in left side if we overshot estimation
if (searchInterval.start < this.timestamps[startingIndex]) {
startingIndex = this.binarySearch(searchInterval.start, lastFoundIndex, startingIndex);
} else if (searchInterval.start > this.timestamps[startingIndex]) {//search in right side of array if we undershot estimation
}
// search in right side of array if we undershot estimation
else if (searchInterval.start > this.timestamps[startingIndex]) {
startingIndex = startingIndex < lastFoundIndex ? lastFoundIndex : startingIndex;
startingIndex = this.binarySearch(searchInterval.start, startingIndex, this.timestamps.length - 1);
}else {
Expand Down
29 changes: 28 additions & 1 deletion TimeTrace/src/models/Types/EventMapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,35 +29,50 @@ export class CustomMap {
}
}

/**
* Generic set that will either insert a key-value pair into the string or regexMap
*/
set(key: MapKey, value: string) {
if (key.isRegex)
this.setRegex(key.key, value)
else
this.setString(key.key, value)
}

/**
* Creates an entry in the stringMap
*/
setString(key: string, value: string): this {
this.stringMap.set(key, value);
return this;
}

/**
* Creates an entry in the regexMap
*/
setRegex(key: string, value: string): this {
this.regexMap.set(key, value);
return this;
}

/**
* Used to retrieve the mapping of an event
* @returns string | undefined
*/
get(eventString: string, fullString?: string): string | undefined {
let value = this.stringMap.get(eventString);
if (value !== undefined && value!=="") {
if (value !== undefined && value !=="") {
return value;
}

if (fullString !== undefined) {
value = this.stringMap.get(fullString);
// A mapping for the event was found in the stringMap.
if (value !== undefined && value!=="") {
return value;
}

// A mapping for the event was found in the regexMap.
for (const [regex, val] of Array.from(this.regexMap.entries())) {
if (new RegExp(regex).test(fullString)) { //only search in regex on full string
return val;
Expand All @@ -68,6 +83,9 @@ export class CustomMap {
return undefined;
}

/**
* Removes either a key from the string or regex map
*/
remove(key: string): void {
if (this.stringMap.has(key)) {
this.stringMap.delete(key);
Expand All @@ -80,6 +98,11 @@ export class CustomMap {
}
}

/**
*
* @returns An array of tuples [string, string], where each tuple is an entry in the map.
* The first item of the tuple is the key from one of the maps and the value is the value.
*/
allMappings(): [string, string][] {
let mappings: [string, string][] = [];
for (const [regex, val] of Array.from(this.regexMap.entries())) {
Expand All @@ -93,6 +116,10 @@ export class CustomMap {
return mappings
}

/**
*
* @returns A string[] containing the values from the regexMap concatenated with the values from the stringMap.
*/
values(): string[] {
return Array.from(this.regexMap.values()).concat(Array.from(this.stringMap.values()));
}
Expand Down
4 changes: 0 additions & 4 deletions TimeTrace/src/models/Types/FileLine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,4 @@ export type FileLine = {

export function mapEventsToFileLine(events: string[]): FileLine[] {
return events.map((event, fileLine) => { return { text: event, line: fileLine } as FileLine })
}

export function mapFileLineToEvents(fileLines: FileLine[]): string[] {
return fileLines.map((fileLine) => fileLine.text);
}
4 changes: 4 additions & 0 deletions TimeTrace/src/models/Types/hashMap.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@

/**
* HashMap consisting of key-value pairs where the key is the timestamp from an event and the value is the index of the line in the logfile.
*/
export class HashMap {
private map: Record<string, number>;

Expand Down
5 changes: 5 additions & 0 deletions TimeTrace/src/models/helpers/cn.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@

/**
* Typically used when html classes are conditionally rendered
* @returns a string array of all the html classes that will be added to an element.
*/
export function cn(...classes: String[]) {
return classes.filter(Boolean).join(" ");
}
12 changes: 12 additions & 0 deletions TimeTrace/src/models/helpers/dateFormats.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
import { LogFormatter } from "../LogFormatter";

/**
* Defines the different Dateformats one can choose.
*/
export enum DateFormat {
ISO_8601 = "ISO 8601",
YYMMDD_HH_MM_SS = "YYMMDD HH.MM.SS",
DD_MM_YYYY_HH_MM_SS = "DD/MM/YYYY HH:MM:SS",
YYYY_MM_DD_HH_MM_SS_MMM = "YYYY-DD-MM HH:MM:SS.MMM",
}

/**
* Used to define the properties in the dateFormats object {@link dateFormats}
*/
interface DateFormats {
[DateFormat.ISO_8601]: RegExp;
[DateFormat.YYMMDD_HH_MM_SS]: RegExp;
[DateFormat.DD_MM_YYYY_HH_MM_SS]: RegExp;
[DateFormat.YYYY_MM_DD_HH_MM_SS_MMM]: RegExp;
}

/**
* Object that is used to dynamically access the regex needed to extract timestamps based on the
* {@link LogFormatter.DateFormat}
*/
export const dateFormats : DateFormats = {
[DateFormat.ISO_8601]: /\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{1,6}(Z|[+-]\d{2}:\d{2})\b/g,
[DateFormat.YYMMDD_HH_MM_SS]: /\b\d{6} \d{2}\.\d{2}\.\d{2}\b/g,
Expand Down
10 changes: 8 additions & 2 deletions TimeTrace/src/models/helpers/extractEventFromLine.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@

/**
* @returns a string that is only an event string from the log file
*/
export function extractEventFromLine(line: string, timestamp: string): string {
line = line.replace(timestamp, "")
line = line.replace(/(^\s*)|(\s*$)/gi,""); //remove leading and trailing spaces
line = line.replace(/\n /,"\n"); //remove newlines
//remove leading and trailing spaces
line = line.replace(/(^\s*)|(\s*$)/gi,"");
//remove newlines
line = line.replace(/\n /,"\n");
line = line.replace(/\r/, "");
return line;
}
4 changes: 4 additions & 0 deletions TimeTrace/src/models/helpers/extractEventsFromFileLines.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { extractEventFromLine } from "./extractEventFromLine";
import { extractTimeStamp } from "./extractTimeStamp";


/**
* @returns All the event strings in a log file
*/
export function extractEventsFromFileLines(fileLines: string[]): string[] {

let events = fileLines.map((line, i) => {
Expand Down
4 changes: 4 additions & 0 deletions TimeTrace/src/models/helpers/extractTimeStamp.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { LogFormatter } from "../LogFormatter";
import { dateFormats } from "./dateFormats";


/**
* @returns a timestamp extracted via {@link dateFormats} and the currently selected dateFormat {@link LogFormatter.dateFormat}
*/
export function extractTimeStamp(line: string): string {
let timestamp: string | undefined;

Expand Down
5 changes: 3 additions & 2 deletions TimeTrace/src/models/helpers/filterLinesBasedOnShowMode.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { ShowLinesMode } from "../../context/LogTableContext";
import { FileLine } from "../FileLine";
import { CustomMap } from "../Types/EventMapping";
import { extractEventFromLine } from "./extractEventFromLine";
import { extractTimeStamp } from "./extractTimeStamp";


/**
* @returns Only the lines the user want to read based on {@link ShowLinesMode}
*/
export function filterAllMappedUnmappedLines(lines: FileLine[], mode: ShowLinesMode, mappings: CustomMap): FileLine[] {
const filtered = lines.filter((line: FileLine) => { //filter that either returns all lines, lines where mapping!==undefined (mapped) or mapping===undefined (unmapped)
switch (mode) {
Expand Down
19 changes: 13 additions & 6 deletions TimeTrace/src/models/helpers/getFileLines.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@

/**
* @returns A promise Promise<string[]>. That is a promise that when resolved contains all the lines from a logfile.
*/
export async function getFileLines(file: File): Promise<string[]> {
return new Promise<string[]>((resolve, reject) => { //must return promise because reader is async
//must return promise because reader is async
return new Promise<string[]>((resolve, reject) => {
let reader = new FileReader();
reader.onload = async (event) => {
let textLines = (reader.result as string).split("\n"); //split file on newlines
//split file on newlines
let textLines = (reader.result as string).split("\n");
textLines = textLines.filter(line => line.replace(/(\r\n|\n|\r)/gm, "") !== '')
resolve(textLines); //all went well, return textLines
//all went well, return textLines
resolve(textLines);
};
reader.onerror = async (e) => { //on error reject
//on error reject
reader.onerror = async (e) => {
console.error("Unable to read file", file.name, e);
reject(e);
};
reader.readAsText(file); //call reader
//call reader
reader.readAsText(file);
});
}
Loading

0 comments on commit 259a34a

Please sign in to comment.