Klassen Richtige Anwendung einer Enum-Klasse

PaulGustav

Mitglied
Hallo zusammen,

bisher habe ich hier echt tolle Ratschläge bekommen. Heute habe ich nur ein Anliegen bezüglich der Verbesserung meiner Rechenzeit.
Ich habe eine große Menge an Daten, welche in 30 sek Intervallen mit Zeitstempeln versehen sind:
Timestamp , Attribut1, Attribut2, SegmentIDs
2015-12-06T06:17:00Z, 5, 10 , 1001|1002|1003|
, 15, 25 , 2004|2005|2006|
2015-12-06T06:17:30Z, 10, 15 , 1001|1002|1003|1004|
, 20, 30 , 2004|2005|​
Während ich meine Daten auslese, speichere ich die SegmentIDs je nach ihrem Zeitstempel mit ihren Attributen in einer Map. Da ich an das Auftreten der SegmentIDs an verschiedenen Tagen und Tageszeiten interessiert bin, nutze ich eine Enum-Klasse, um festzustellen, ob die SegmentID entweder am Wochenende, wochentags, morgens oder abends gemeldet wurde. Es ergeben sich demnach 4 (hash)Maps: MP-WD, EP-WD, MP-WE, EP-WE
Wobei MP=MorningPeak, EP=EveningPeak, WD=Weekday, WE=Weekend.
Nun habe ich also die Enum-Klasse EnumDayProperties:
Java:
public class EnumDayProperties {
  
    public static String getWeekday (Instant day){
        String dayProperty = null;
        LocalDateTime ldt = LocalDateTime.ofInstant(day, ZoneId.of("Zulu"));
        LocalDate ld = LocalDate.parse(ldt.toLocalDate().toString());
        int ordinalNumberDay = getOrdinalFromWeekday(ld.getDayOfWeek().toString());
        if(ordinalNumberDay == 5 || ordinalNumberDay == 6)
            dayProperty = "WE";
        else
        dayProperty = "WD";
        return dayProperty;
    }
    public enum Weekday{
        MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
    }  
    public enum Peak{
        MP, EP, NP
    }
    public static String getOrdinalFromTime (LocalTime time){
        String peak = null;
        if(time.isAfter(LocalTime.parse("06:00:00")) && time.isBefore(LocalTime.parse("12:00:00")))
            peak = "MP";
        else if(time.isAfter(LocalTime.parse("12:00:00")) && time.isBefore(LocalTime.parse("18:00:00")))
            peak = "EP";
        peak = "NP";  
        return peak;
    }
    public static boolean TimeSliceIsMorning (String string){
        LocalTime morningEnd = LocalTime.parse("12:00:00");
        LocalTime morningStart = LocalTime.parse("06:00:00");
        LocalTime time = LocalTime.parse(string);
        return time.isBefore(morningEnd) && time.isAfter(morningStart);
    }
    private static int getOrdinalFromWeekday( String name )
    {
      try {
        return Weekday.valueOf( name ).ordinal();
      }
      catch ( IllegalArgumentException e ) {
        return 9999;
      }
    }
}

Auf der anderen Seite habe ich nun meine Ranking der SegmentIDs:
Java:
public class DsegRanking {
   public static void main(String[] args) throws Exception{
       Map<Long, DsegProperties> mpWD = new HashMap<>();
       Map<Long, EveningDsegProperties> epWD = new HashMap<>();
       Map<Long, DsegProperties> mpWE = new HashMap<>();
       Map<Long, EveningDsegProperties> epWE = new HashMap<>();
       List<File> fileList = new ArrayList<File>();
       //getting the list of all files that need to be parsed
       fileList = getAllFiles();
       String line = "";
       BufferedReader dataLine = null;
       Instant timestamp = null;
       for (int j = 0; j < fileList.size(); j++) {
           try {
               FileInputStream fin = new FileInputStream(fileList.get(j));
               GzipCompressorInputStream gzIn = new GzipCompressorInputStream(fin);
               Reader rd = new InputStreamReader(gzIn, "US-ASCII");
               dataLine = new BufferedReader(rd);
               while ((line = dataLine.readLine()) != null) {
                   String[] content = line.split(",");
                   if (StringUtils.isEmpty(content[COLUMN_TIMESTAMP]) == false ) {
                       timestamp =(content[COLUMN_TIMESTAMP]);
                       chooseMap(mpWD,epWD,mpWE,epWE,content,timestamp);
                   }
                   else if (content[COLUMN_TIMESTAMP].isEmpty()) {
                       chooseMap(mpWD,epWD,mpWE,epWE,content,timestamp);
                   }
               }
           }
            catch (IOException ex) {
               ex.printStackTrace();
           }
       }
       writeJamsMorningWeekdays(mpWD);
       writeJamsEveningWeekdays(epWD);
       writeJamsMorningWeekend(mpWE);
       writeJamsEveningWeekend(epWE);
   }
  
   private static void chooseMap(Map<Long, DsegProperties> mpWD, Map<Long, EveningDsegProperties> epWD,
           Map<Long, DsegProperties> mpWE, Map<Long, EveningDsegProperties> epWE, String[] content, Instant timestamp) {
       String day = Implements.EnumDayProperties.getWeekday(timestamp);
       String time = Implements.EnumDayProperties.getPeak(timestamp);
       if (day.contains("WD") && time.contains("MP"))
           calculateDsegProperties(content,mpWD,timestamp);
       else if (day.contains("WD") && time.contains("EP"))
           calculateEveningDsegProperties(content,epWD,timestamp);
       else if (day.contains("WE") && time.contains("MP"))
           calculateDsegProperties(content,mpWE,timestamp);
       else if (day.contains("WE") && time.contains("EP"))
           calculateEveningDsegProperties(content,epWE,timestamp);
   }
  
   private static void calculateDsegProperties(String[] content, Map<Long, DsegProperties> mapping, Instant timestamp) {
       List<Long> dsegColumnList = new ArrayList<>(600000);
       String dsegColumn = content[COLUMN_DSEGID];
       getDsegs(dsegColumn, dsegColumnList);
       for (Long segmentID : dsegColumnList){
           DsegProperties dsegProperties = mapping.get(segmentID);
           if (dsegProperties == null){
               dsegProperties = new DsegProperties(content,segmentID,timestamp);
               mapping.put(segmentID, dsegProperties);
           }
           else if(dsegProperties != null){
               dsegProperties.updateDsegID(content, segmentID,timestamp);
               mapping.put(segmentID, dsegProperties);
           }
       }
      
   }
   private static void calculateEveningDsegProperties(String[] content, Map<Long, EveningDsegProperties> mapping, Instant timestamp) {
       List<Long> dsegColumnList = new ArrayList<>(600000);
       String dsegColumn = content[COLUMN_DSEGID];
       getDsegs(dsegColumn, dsegColumnList);
       for (Long segmentID : dsegColumnList){
           EveningDsegProperties dsegProperties = mapping.get(segmentID);
           if (dsegProperties == null){
               dsegProperties = new EveningDsegProperties(content,segmentID,timestamp);
               mapping.put(segmentID, dsegProperties);
           }
           else if(dsegProperties != null){
               dsegProperties.updateEveningDsegID(content, segmentID,timestamp);
               mapping.put(segmentID, dsegProperties);
           }
       }
      
   }
}

Die Klasse DsegProperties hält lediglich die Attribute fest und inkrementiert diese via updateDsegProperties. Dafür nutze ich leider zweimal dieselbe Klasse. Einmal für den vormittags und einmal für abends. Für die Berechnung des gesamten Datensatzes über ein Jahr (ca 60 Mio Datensätze) habe ich nun 11 Std. benötigt. Kann ich die Enum-Klasse irgendwie effizienter verwenden, sodass die Rechenleistung gesteigert wird?

Ich hoffe, dass das soweit verständlich dargeboten ist. Vielen Dank schon mal

Paul
 
Kann ich die Enum-Klasse irgendwie effizienter verwenden, sodass die Rechenleistung gesteigert wird?
Naja, du könntest zumindest den enum überhaupt mal verwendet, aktuell ignorierst du die, wenn ich's richtig sehe, und benutzt nur dir statischen Klassen. Deine Code-Stil ist etwas ... gewöhnungsbedürftig, das macht das nicht so leicht...

Deine Weekday-Klasse ist völlig überflüssig, die kannst du ersetzten, mit einem enum mit WeekDay und WeekEnd, die du dann überall statt "WE" und "WD" benutzt.

Das gleiche solltest du mit Peak machen, und denn enum statt den Strings verwenden.

Deine Methoden sind oftmals etwas kompliziert gelöst
Java:
public static String getWeekday (Instant day){
        String dayProperty = null;
        LocalDateTime ldt = LocalDateTime.ofInstant(day, ZoneId.of("Zulu"));
        LocalDate ld = LocalDate.parse(ldt.toLocalDate().toString());
        int ordinalNumberDay = getOrdinalFromWeekday(ld.getDayOfWeek().toString());
        if(ordinalNumberDay == 5 || ordinalNumberDay == 6)
            dayProperty = "WE";
        else
        dayProperty = "WD";
        return dayProperty;
    }

Du bekommst einen Instant, erstellst daraus dein LocalDateTime-Objekt, formatierst das als String, parst daraus ein LocalDate, nimmst davon den Wochentag, formatierst den als String, parst daraus den Wochentag, und lässt dir davon den Index geben.

Das ganze ständige Umwandeln ist völlig überflüssig und kostet riesig Performance, stattdessen geht auch einfach:
Java:
public static String getWeekday (Instant day){
        String dayProperty = WD;
        LocalDateTime ldt = LocalDateTime.ofInstant(day, ZoneId.of("Zulu"));
        if (ldt.getDayOfWeek().getValue() >= 6) {
            dayProperty = WE;
       }
     return dayProperty;
    }

In den anderen Methoden das gleiche, das Parsen wiederholst du bei jedem Methodenaufruf, und mehrmals für die gleichen werte, die solltest du lieber als Konstanten anlagen und nur einmal Parsen,
 
Ja hi MrBrown,

vielen Dank für dein Feedback. So langsam wird mir mein umständlicher Code auch klar...

Deine Code-Stil ist etwas ... gewöhnungsbedürftig
Ich lerne seit August 2016 Java und entschuldige mich schon einmal für überflüssige Methodenaufrufe in meinen Codes.

Deine Weekday-Klasse ist völlig überflüssig, die kannst du ersetzten, mit einem enum mit WeekDay und WeekEnd, die du dann überall statt "WE" und "WD" benutzt.
Meinst du mit ersetzen, dass ich die zwei Enum-Größen vorab einfach definiere?
Code:
private static final Enum weekDay;
private static final Enum weekEnd;
Oder sollte ich etwa nur den Modifizierer ändern?
Code:
public enum Day{
       WeekDay, WeekEnd;
   }

Zudem verstehe ich leider deinen angebrachten Code nicht. WD und WE müssten ja Strings darstellen, welche von Anführungszeichen umgeben sind, oder? Damit wäre mein bisheriges Problem ja nicht gelöst.

Ich habe die Enum-Klasse lediglich über Java ist auch eine Insel kennengelernt.
 
Ich lerne seit August 2016 Java und entschuldige mich schon einmal für überflüssige Methodenaufrufe in meinen Codes.

gewöhnungsbedürftig ist vor allem auch deine Schreibweise bei ifs.
Mal ohne, mal mit Klammer, mal else, mal else if mit nur negierter Bedingung...das einheitlich zu haben macht es deutlich einfacher 😉


Oder sollte ich etwa nur den Modifizierer ändern?
Ja, genau so.

Zudem verstehe ich leider deinen angebrachten Code nicht. WD und WE müssten ja Strings darstellen, welche von Anführungszeichen umgeben sind, oder? Damit wäre mein bisheriges Problem ja nicht gelöst.
Nein, die sollen ja eben keine Strings sein, sondern enums 😉 In meinem Code oben muss es nicht String sondern Day sein, lässt sich nur jetzt nicht mehr bearbeiten, so muss es sein:

Java:
public static Day getWeekday (Instant day){
        Day dayProperty = WD;
        LocalDateTime ldt = LocalDateTime.ofInstant(day, ZoneId.of("Zulu"));
        if (ldt.getDayOfWeek().getValue() >= 6) {
            dayProperty = WE;
       }
     return dayProperty;
    }
 
Okay ich habe nun die Methoden getPeak und getWeekday wie folgt angepasst:
Java:
public static Day getWeekday (Instant day){
       Day dayProperty = Day.WeekDay;
       LocalDateTime ldt = LocalDateTime.ofInstant(day, ZoneId.of("Zulu"));
       if(ldt.getDayOfWeek().getValue()>=6){
           dayProperty = Day.WeekEnd;
       }
       return dayProperty;
   }
 
   public static Peak getPeak (Instant time){
       Peak peakProperty = Peak.EP;
       LocalDateTime ldt = LocalDateTime.ofInstant(time, ZoneId.of("Zulu"));
       LocalTime morningBeginn = LocalTime.parse("06:00:00");
       LocalTime morningEnd = LocalTime.parse("12:00:00");
       if (ldt.toLocalTime().isAfter(morningBeginn)&&ldt.toLocalTime().isBefore(morningEnd)){
           peakProperty = Peak.MP;
       }
       return peakProperty;
   }
 
   public enum Day{
       WeekDay, WeekEnd;
   }
 
   public enum Peak{
       MP, EP
   }

Nun muss ich nur noch die Klasse DsegRanking darauf abstimmen. Bisher habe ich die Ergebnisse aus der EnumDayProperties wie folgt angewandt:
Java:
private static void chooseMap(Map<Long, DsegProperties> mpWD, Map<Long, EveningDsegProperties> epWD,
           Map<Long, DsegProperties> mpWE, Map<Long, EveningDsegProperties> epWE, String[] content, Instant timestamp) {
       String day = Implements.EnumDayProperties.getWeekday(timestamp);
       String time = Implements.EnumDayProperties.getPeak(timestamp);
       if (day.contains("WD") && time.contains("MP"))
           calculateDsegProperties(content,mpWD,timestamp);
       else if (day.contains("WD") && time.contains("EP"))
           calculateEveningDsegProperties(content,epWD,timestamp);
       else if (day.contains("WE") && time.contains("MP"))
           calculateDsegProperties(content,mpWE,timestamp);
       else if (day.contains("WE") && time.contains("EP"))
           calculateEveningDsegProperties(content,epWE,timestamp);
   }

Da ich ja vermeiden will bzw sollte, dass ich die Enums mit einem String vergleich, habe ich mir gedacht, dass man ja die ordinalen Zahlen nehmen kann, die bei den Enums hinterlegt sind:
Java:
private static void chooseMap(Map<Long, DsegProperties> mpWD, Map<Long, EveningDsegProperties> epWD,
           Map<Long, DsegProperties> mpWE, Map<Long, EveningDsegProperties> epWE, String[] content, Instant timestamp, List<Instant> timeStampList) {
       Enum day = Implements.EnumDayProperties.getWeekday(timestamp);
       Enum time = Implements.EnumDayProperties.getPeak(timestamp);
       System.out.println("Enum day (ord) = " + day.ordinal());
       System.out.println("Enum time (ord) = " + time.ordinal());
       if (day.ordinal()==0 && time.ordinal()==0){
           System.out.println("timestamp is WD-MP");
           calculateDsegProperties(content,mpWD,timestamp,timeStampList);
       }
//same code äquivalent for epWD, mpWE, epWE
// and without the print-functions
   }
Das scheint so erstmal zu klappen. Danke vielmals.

Oder meinst du, ich könnte die ChooseMap noch besser gestalten?

Oder kann ich die Schritte für
 
Nun muss ich nur noch die Klasse DsegRanking darauf abstimmen. Bisher habe ich die Ergebnisse aus der EnumDayProperties wie folgt angewandt:

Da ich ja vermeiden will bzw sollte, dass ich die Enums mit einem String vergleich, habe ich mir gedacht, dass man ja die ordinalen Zahlen nehmen kann, die bei den Enums hinterlegt sind:
Anstatt mit dem Ordinal zu vergleichen vergleiche direkt mit dem EnumWert 😉

Java:
....
   if (day == Day.WeekDay && time == Peak.MP) {
       calculateDsegProperties(content,mpWD,timestamp);
   } else if (day == Day.WeekDay && time == Peak.EP) {
       calculateEveningDsegProperties(content,epWD,timestamp);
   } else if (day == Day.WeekEnd && time == Peak.MP) {
       calculateDsegProperties(content,mpWE,timestamp);
   } else if (day == Day.WeekEnd && time == Peak.EP) {
       calculateEveningDsegProperties(content,epWE,timestamp);
   }...

Ach ja ich würde dir raten, auch wenn der Compiler es erlaubt sei wegzulassen, immer Klammern zu setzen 😉
 
Wow sauber!
Allein für 10 h eines Tages (ca. 50 - 70k Datensätze) brauche ich nun nur noch 28 statt 50 sek Zeit.
Sobald ich das ganze Jahr nochmal durchlaufen lasse, poste ich dann auch mal diesen Fortschritt.

Vielen Dank.

P.S.: Die Bedingungen versuche ich fortan immer konsistent zu halten.
 
Allein für 10 h eines Tages (ca. 50 - 70k Datensätze) brauche ich nun nur noch 28 statt 50 sek Zeit.
Sobald ich das ganze Jahr nochmal durchlaufen lasse, poste ich dann auch mal diesen Fortschritt.

Ein paar kleine Vorschläge hätte ich noch. Bin mir zwar nicht sicher ob diese einen wirklichen Unterschied ausmachen werden, aber probieren kannst du es ja.

In der Klasse mit deiner getPeak Methode könntest du das Parsen von den 2 Uhrzeiten aus der Methode auslagern.
Vorteil: Du musst beide Zeiten nur 1x parsen und kannst sie immer verwenden.
Auch den Aufruf toLocalTime() würde ich vor das if-ziehen.
Vorteil: Auch hier sparst du dir doppeltes umwandeln
Java:
private static LocalTime begin = LocalTime.parse("06:00:00");

private static LocalTime end = LocalTime.parse("12:00:00");

public static Peak getPeak (Instant time) {
   Peak peakProperty = Peak.EP;
   LocalDateTime dateTime = LocalDateTime.ofInstant(time, ZoneId.of("Zulu"));
   LocalTime time = dateTime.toLocalTime();
   if (time.isAfter(begin) && time.isBefore(end)) {
       peakProperty = Peak.MP;
   }
   return peakProperty;
}

In der Methode getWeekday(Instant)[icode] und [icode]getPeak(Instant) wandelst du jeweils das Instant Objekt zu einem LocalDateTime um.
Sprich auch hier machst du dieselbe Umwandlung doppelt.
Mögliche Verbesserung:
Java:
LocalDateTime dateTime = LocalDateTime.ofInstant(time, ZoneId.of("Zulu"));
String day = Implements.EnumDayProperties.getWeekday(dateTime);
String time = Implements.EnumDayProperties.getPeak(dateTime);
Natürlich musst du die Methoden getWeekday(Instant)[icode] und [icode]getPeak(Instant) entsprechend anpassen.


Eine Codevereinfachung ist vielleicht auch bei den Methoden calculateDsegProperties und calculateEveningDsegProperties möglich.
Der einzige Unterschied besteht hierbei, dass entweder ein DsegProperties oder EveningDsegProperties Objekt erstellt wird (und der entsprechenden "update" Methode). Worin unterscheiden sich diese Klassen?
Vielleicht wäre eine passende gemeinsame Basisklasse hilfreich.

Java:
private static void calculateProperties(String[] content, Map<Long, DsegProperties> mapping, Instant timestamp, boolean evening) {
   List<Long> dsegColumnList = getDsegs(content[COLUMN_DSEGID]); // die Methode "getDsegs" liefert nun eine Liste zurück -> was man sich auch erwarten darf wenn die Methode mit "get.." beginnt ;) ansonsten solltest du sie in "fillDsegList" umbenennen
   for (Long segmentID : dsegColumnList) {
       BaseDsegProperties baseDseg = mapping.get(segmentID);
       if (baseDseg == null) {
           if(evening) {
               baseDseg = new EveningDsegProperties(content, segmentID, timestamp);
           } else {
               baseDseg = new DsegProperties(content, segmentID, timestamp);
           }
           mapping.put(segmentID, baseDseg);
       } else if(baseDseg != null) {
           baseDseg.updateID(content, segmentID, timestamp);
           //mapping.put(segmentID, baseDseg); Diese "put" ist unnötig! Das Element ist ja schon in der Liste drinnen ;)
       }
   }
}
 
Okay. Ich verstehe deine Empfehlung soweit ganz gut. Das herausziehen der LocalTime-Variablen macht das zudem noch übersichtlicher. Ist erledigt.

LocalDateTime dateTime = LocalDateTime.ofInstant(time, ZoneId.of("Zulu"));
String day = Implements.EnumDayProperties.getWeekday(dateTime);
String time = Implements.EnumDayProperties.getPeak(dateTime);

Meinst du, dass es sich mit einem String nun doch schneller rechnen lässt. Mit den Enum-Objekten läuft es doch eigtl ganz gut:
Java:
...
Enum day = Implements.EnumDayProperties.getWeekday(timestamp);
       Enum time = Implements.EnumDayProperties.getPeak(timestamp);
       if (day == Day.WeekDay && time == Peak.MP){
           calculateDsegProperties(content,mpWD,timestamp,timeStampList);
       }
...

Vielleicht wäre eine passende gemeinsame Basisklasse hilfreich.

Ja an solch eine Vereinfachung hatte ich schon gedacht. Die beiden Klassen DsegProperties und EveningDsegProperties verfügen grundlegend über den selben Inhalt. Die Trennung soll lediglich vermeiden, dass die Attribute getrennt (je nach Zeitscheibe) berechnet werden. Ich hatte die Klassen damals sporadisch trennen müssen, als ich die Trennung zwischen Morgen- und Abendstunden eingeführt hatte. Weiter hatte ich mich darum noch nicht gekümmert. Eine Verwirrung "des Lesers" ist hier echt verständlich.

In deime Vorschlag führst du ja die neue Klasse BaseDsegProperties und die Variable evening ein. Es fässt die calculateDsegProperties und calculateEveningDsegProperties zusammen.

Die Methode getDsegs sieht wie folgt aus:
Java:
private static void getDsegs (String dsegColumn, List<Long> dsegColumnList){
       Long id;
       int dsegCount;
       dsegCount=0;
       for (int i=0;i<dsegColumn.length();i++)
       {
           if(dsegColumn.charAt(i) == '|')
           dsegCount++;
       };
       String[] split = dsegColumn.split("\\|");
       for (int i=0;i<dsegCount;i++)
       {
           id = Long.parseLong(split[i]);
           dsegColumnList.add(id);
       }
   }
 
Meinst du, dass es sich mit einem String nun doch schneller rechnen lässt. Mit den Enum-Objekten läuft es doch eigtl ganz gut:
Tippfehler, das sollten enums bleiben 😉

Die Methode getDsegs sieht wie folgt aus:
Methoden die mit 'get' beginnen, sollten irgendwas zurückgeben 😉

Sicher, dass die so richtig ist, und aus dsegColumn der letzte Wert egal ist?
aktuell werden aus zb "1111|222|33" nur 1111 und 222 der Liste hinzugefügt, 33 wird ignoriert.
Edit: Grad gesehen, dass die immer mit '|' enden, dann ists natürlich passend so.

Die erste for-Schleife sieht auch überflüssig aus, die Anzahl Elemente bekommst du einfach mit split.length
 
Meinst du, dass es sich mit einem String nun doch schneller rechnen lässt. Mit den Enum-Objekten läuft es doch eigtl ganz gut:
Copy&Paste Fehler, wie @mrBrown schon sagt -> bleib bei den Enums

Die Methode getDsegs sieht wie folgt aus:
Ja das kann man auch etwas optimieren.
Java:
private static void getDsegs (String dsegColumn) {
   List<Long> dsegColumnList = new ArrayList<>();
   String[] split = dsegColumn.split("\\|");
   for (int i = 0; i < split.length; i++) {
       long id = Long.parseLong(split[i]);
       dsegColumnList.add(id);
   }
   return dsegColumnList;
}
 
Habe die Methode getDsegs() schon umgesetzt. Ich habe nun schon einige Durchläufe machen können und folgende Verbesserungen hinsichtlich der Rechenzeiten erreichen können:
Komplettes Jahr 2015:
vorher: time used for 952,399 rows of timestamps: 11:50:08.742
nachher: time used for 952,399 rows of timestamps: 07:03:52.691
Quartal 1 - 2015:
nachher: time used for 245,716 rows of timestamps: 00:56:03.683
Quartal 3 - 2015
vorher: time used for 230,283 rows of timestamps: 04:18:58.123
Quartal 4 - 2015
vorher: time used for 233,266 rows of timestamps: 03:35:41.010

In diesem Sinne: Vielen Dank Leute!

Sobald ich Zeit dafür finde, optimiere ich dann auch mal die calculateDsegProperties bzw calculateEveningDsegProperties und fasse diese zu einer Methode calculateProperties zusammen. Dann sollte der Spaß noch schneller von statten gehen.
 

Zurück
Oben