Created
April 22, 2010 11:09
-
-
Save Cellane/375086 to your computer and use it in GitHub Desktop.
RC3 verze | Nekopírovat, jen se inspirovat!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Created by IntelliJ IDEA. | |
* User: Milan | |
* Date: Apr 22, 2010 | |
* Time: 11:21:57 AM | |
*/ | |
import java.io.*; | |
import java.text.MessageFormat; | |
import java.util.Calendar; | |
import java.util.Scanner; | |
class InputOutput { | |
/** | |
* Method that asks user for a filename | |
* | |
* @return text string from an user | |
*/ | |
private static String getFileName () { | |
Scanner scanner = new Scanner (System.in); | |
String value; | |
System.out.print (MessageFormat.format ("{0}: ", "Název souboru")); | |
value = scanner.next (); | |
return (value); | |
} | |
/** | |
* Public overloaded method that calls getFileName () method to get the | |
* filename from user, then calls openFile () method to open specified | |
* file | |
* | |
* @return opened buffered stream | |
*/ | |
public static BufferedReader openFile () { | |
return openFile (getFileName ()); | |
} | |
/** | |
* Method that opens a buffered reader on a specified file and keeps that | |
* reader open by returning reference to that reader | |
* | |
* @param filename name of file to open | |
* | |
* @return opened buffered stream | |
*/ | |
private static BufferedReader openFile (String filename) { | |
try { | |
File file = new File (MessageFormat.format ("src{0}Queues{0}{1}", File.separator, filename)); | |
FileReader fileReader = new FileReader (file); | |
BufferedReader bufferedReader = new BufferedReader (fileReader); | |
return (bufferedReader); | |
} catch (FileNotFoundException e) { | |
System.out.println (MessageFormat.format ("Soubor neexistuje: {0}!", e.getLocalizedMessage ())); | |
return (null); | |
} | |
} | |
/** | |
* Public method that reads information about one plane from queue file | |
* and returns it without doing any edits as a string | |
* | |
* @param bufferedReader opened buffered stream | |
* | |
* @return one line from queue file as a string | |
*/ | |
public static String readPlane (BufferedReader bufferedReader) { | |
try { | |
return (bufferedReader.readLine ()); | |
} catch (IOException e) { | |
System.out.println (MessageFormat.format ("Ze souboru nelze číst: {0}!", e.getLocalizedMessage ())); | |
return (null); | |
} | |
} | |
/** | |
* Public method that tries to set a "backstop" in queue file | |
* | |
* @param bufferedReader opened buffered stream | |
*/ | |
public static void setMark (BufferedReader bufferedReader) { | |
try { | |
bufferedReader.mark (255); // should be more than enough! | |
} catch (IOException e) { | |
System.out.println ( | |
MessageFormat.format ("Nepodařilo se nastavit zarážku: {0}!", e.getLocalizedMessage ())); | |
} | |
} | |
/** | |
* Public method that tries to return to most recent backstop | |
* | |
* @param bufferedReader opened buffered stream | |
*/ | |
public static void resetMark (BufferedReader bufferedReader) { | |
try { | |
bufferedReader.reset (); | |
} catch (IOException e) { | |
System.out.println ( | |
MessageFormat.format ("Nepodařilo se vrátit se na zarážku: {0}!", e.getLocalizedMessage ())); | |
} | |
} | |
/** | |
* Closes previously opened file | |
* | |
* @param bufferedReader file stream identifier | |
*/ | |
public static void closeFile (BufferedReader bufferedReader) { | |
try { | |
bufferedReader.close (); | |
} catch (IOException e) { | |
System.out.println (MessageFormat.format ("Soubor se nepodařilo uzavřít: {0}!", e.getLocalizedMessage ())); | |
} | |
} | |
/** | |
* Public method that creates log file for session | |
* | |
* @return name of created log file | |
*/ | |
public static String createLogFile () { | |
Calendar calendar = Calendar.getInstance (); | |
String logFileName; | |
String year, month, day, hour, minute, second; | |
year = Integer.toString (calendar.get (Calendar.YEAR)); | |
month = Integer.toString (calendar.get (Calendar.MONTH) + 1); | |
day = Integer.toString (calendar.get (Calendar.DATE)); | |
hour = ((calendar.get (Calendar.AM_PM) == 0) ? | |
// Forenoon | |
(calendar.get (Calendar.HOUR) < 10) ? "0" + Integer.toString ( | |
calendar.get (Calendar.HOUR)) : Integer.toString (calendar.get (Calendar.HOUR)) : | |
// Afternoon | |
Integer.toString (calendar.get (Calendar.HOUR) + 12)); | |
minute = ((calendar.get (Calendar.MINUTE) < 10) ? "0" + Integer.toString ( | |
calendar.get (Calendar.MINUTE)) : Integer.toString (calendar.get (Calendar.MINUTE))); | |
second = ((calendar.get (Calendar.SECOND) < 10) ? "0" + Integer.toString ( | |
calendar.get (Calendar.SECOND)) : Integer.toString (calendar.get (Calendar.SECOND))); | |
logFileName = MessageFormat.format ("{0}. {1}. {2}. – {3}.{4}:{5}.txt", year, month, day, hour, minute, second); | |
try { | |
File logFile = new File (MessageFormat.format ("src{0}Logs{0}{1}", File.separator, logFileName)); | |
FileWriter logFileWriter = new FileWriter (logFile); | |
logFileWriter.close (); | |
return (logFileName); | |
} catch (IOException e) { | |
System.out.println (MessageFormat.format ("Soubor nelze vytvořit: {0}", e.getLocalizedMessage ())); | |
return (null); | |
} | |
} | |
public static void addLogEntry (String logFileName, String event, String name, int time, int fuel) { | |
try { | |
StringBuilder result = new StringBuilder (); | |
String line; | |
File logFile = new File (MessageFormat.format ("src{0}Logs{0}{1}", File.separator, logFileName)); | |
FileReader logFileReader = new FileReader (logFile); | |
BufferedReader bufferedLogReader = new BufferedReader (logFileReader); | |
while ((line = bufferedLogReader.readLine ()) != null) { | |
result.append (MessageFormat.format ("{0}\n", line)); | |
} | |
if (event.equals ("arrival")) { | |
result.append (MessageFormat.format ("{0} >-- {1} ({2})", time, name, fuel)); | |
} else if (event.equals ("landing")) { | |
result.append (MessageFormat.format ("{0} --> {1} ({2})", time, name, fuel)); | |
} else if (event.equals ("crash")) { | |
result.append (MessageFormat.format ("{0} --x {1} ({2})", time, name, fuel)); | |
} | |
FileWriter logFileWriter = new FileWriter (logFile); | |
BufferedWriter bufferedLogWriter = new BufferedWriter (logFileWriter); | |
bufferedLogWriter.write (result.toString ()); | |
bufferedLogWriter.close (); | |
} catch (IOException e) { | |
System.out.println (MessageFormat.format ("Nelze zalogovat událost: {0}", e.getLocalizedMessage ())); | |
} | |
} | |
/** | |
* Public method that prints simple header | |
* | |
* @param header text of header | |
* @param level level of header | |
*/ | |
public static void printHeader (String header, int level) { | |
if (level == 1) { | |
System.out.format ("========== %-15s ==========\n", header.toUpperCase ()); | |
} else if (level == 2) { | |
System.out.format ("========== %-15s ==========\n", header); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Created by IntelliJ IDEA. | |
* User: Milan | |
* Date: Apr 22, 2010 | |
* Time: 11:21:49 AM | |
*/ | |
class Plane { | |
Plane next; | |
String name; // Could as well be "final" | |
int arrivalTime; // __,^ | |
int fuel; | |
Plane (String name, int arrivalTime, int fuel) { | |
this.name = name; | |
this.arrivalTime = arrivalTime; | |
this.fuel = fuel; | |
next = null; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Created by IntelliJ IDEA. | |
* User: Milan | |
* Date: Apr 22, 2010 | |
* Time: 11:19:35 AM | |
*/ | |
import java.io.BufferedReader; | |
import java.text.MessageFormat; | |
public class Project { | |
/* | |
"Global" variables holding total amount of planes, landings and crashes | |
... just to make my life less painful | |
*/ | |
private static int numberOfPlanes = 0, numberOfCrashes = 0, numberOfLandings = 0; | |
/** | |
* Main method that asks the user for name of file with queue, opens that | |
* file, starts the simulation and closes file with queue | |
* | |
* @param args command line arguments; not used | |
*/ | |
public static void main (String[] args) { | |
BufferedReader bufferedReader; | |
String logFileName; | |
bufferedReader = InputOutput.openFile (); | |
logFileName = InputOutput.createLogFile (); | |
startSimulation (bufferedReader, logFileName); | |
InputOutput.closeFile (bufferedReader); | |
} | |
/** | |
* Method that does everything that happens above the airport during one | |
* second, which means: | |
* 1, checks if new airplanes arrived to airport | |
* 2, allows one plane to land | |
* 3, checks if any plane has fuel level of zero (= crashed plane) | |
* 4, decreases fuel level of all airplanes in the air | |
* 5, increases time unit by one | |
* | |
* @param bufferedReader reference to file with queue | |
* @param logFileName name of log file for given session | |
*/ | |
private static void startSimulation (BufferedReader bufferedReader, String logFileName) { | |
Queue queue = new Queue (); | |
boolean endOfFile; | |
int time = 0; | |
System.out.println ("Zahajuji simulaci…"); | |
do { | |
InputOutput.printHeader (MessageFormat.format ("{0}. sekunda", time), 1); | |
endOfFile = addPlanesToQueue (bufferedReader, logFileName, queue, time); | |
landPlane (logFileName, queue, time); | |
checkForCrashes (logFileName, queue, time); | |
decreaseFuelLevel (queue); | |
time = increaseTime (time); | |
System.out.println (); | |
} while ((!endOfFile) || (!queue.isEmpty ())); | |
System.out.println ("Ukončuji simulaci…\n"); | |
printStatistics (); | |
} | |
/** | |
* Method that checks if there are new planes in the air near airport and | |
* if so, adds them to queue | |
* | |
* @param bufferedReader opened buffered reader with queue file | |
* @param logFileName name of log file for this session | |
* @param queue queue with planes | |
* @param time current time | |
* | |
* @return returns true if plane was last plane in queue file | |
*/ | |
private static boolean addPlanesToQueue (BufferedReader bufferedReader, String logFileName, Queue queue, int time) { | |
String[] planeProperties; | |
String line; | |
String name; | |
int arrivalTime; | |
int fuel; | |
InputOutput.printHeader ("Přílety", 2); | |
do { | |
InputOutput.setMark (bufferedReader); | |
line = InputOutput.readPlane (bufferedReader); | |
if (line != null) { | |
planeProperties = line.split (" "); | |
name = planeProperties[0]; | |
arrivalTime = Integer.parseInt (planeProperties[1]); | |
fuel = Integer.parseInt (planeProperties[2]); | |
if (arrivalTime != time) { | |
InputOutput.resetMark (bufferedReader); | |
} else { | |
queue.addPlane (name, arrivalTime, fuel); | |
InputOutput.addLogEntry (logFileName, "arrival", name, time, fuel); | |
numberOfPlanes++; | |
System.out.println (MessageFormat.format ( | |
"Letadlo {0} právě přiletělo k letišti. Zbývá paliva na {1} sekund(y) letu.", name, fuel)); | |
} | |
} else { | |
return (true); // We just reached end of queue file | |
} | |
} while (arrivalTime == time); | |
return (false); | |
} | |
/** | |
* Method that lets one plane to land | |
* | |
* @param logFileName name of log file for this session | |
* @param queue queue with planes that are flying above airport | |
* @param time current time | |
*/ | |
private static void landPlane (String logFileName, Queue queue, int time) { | |
Plane plane; | |
InputOutput.printHeader ("Přistání", 2); | |
if (!queue.isEmpty ()) { | |
plane = queue.deletePlane (); | |
InputOutput.addLogEntry (logFileName, "landing", plane.name, time, plane.fuel); | |
numberOfLandings++; | |
System.out.println (MessageFormat.format ("Letadlo {0} úspešně přistálo.", plane.name)); | |
} | |
} | |
/** | |
* Method that checks if there are any planes with fuel level of zero | |
* and if so, it calls method to delete such plane | |
* | |
* @param logFileName name of log file for this session | |
* @param queue queue with planes that are flying above airport | |
* @param time current time | |
*/ | |
private static void checkForCrashes (String logFileName, Queue queue, int time) { | |
Plane auxiliary, crashed; | |
InputOutput.printHeader ("Havárie", 2); | |
if (!queue.isEmpty ()) { | |
auxiliary = queue.start; | |
while (auxiliary != null) { | |
if (auxiliary.fuel <= 0) { | |
crashed = queue.deleteCrashedPlane (auxiliary.name); | |
InputOutput.addLogEntry (logFileName, "crash", crashed.name, time, crashed.fuel); | |
numberOfCrashes++; | |
System.out.println (MessageFormat.format ("Letadlo {0} spadlo.", crashed.name)); | |
} | |
auxiliary = auxiliary.next; | |
} | |
} | |
} | |
/** | |
* Method that decreases fuel level of all flying airplanes by one | |
* | |
* @param queue queue with planes | |
*/ | |
private static void decreaseFuelLevel (Queue queue) { | |
queue.decreaseFuelLevel (); | |
} | |
/** | |
* Method that increases time by one and lets the program sleep for that | |
* one second | |
* | |
* @param time current time | |
* | |
* @return new time | |
*/ | |
private static int increaseTime (int time) { | |
time++; | |
try { | |
Thread.sleep (1000l); | |
} catch (InterruptedException e) { | |
System.out.println (MessageFormat.format ("Nepodařilo se uspat vlákno: {0}!", e.getLocalizedMessage ())); | |
} | |
return (time); | |
} | |
/** | |
* Method that writes to stdout statistics of simulation | |
*/ | |
private static void printStatistics () { | |
InputOutput.printHeader ("Statistiky", 1); | |
System.out.format ("%-30s%7d\n%-30s%7d\n%-30s%7d\n", "Celkem letadel:", numberOfPlanes, | |
"Celkem úspěšných přistání:", numberOfLandings, "Celkem pádů:", numberOfCrashes); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Created by IntelliJ IDEA. | |
* User: Milan | |
* Date: Apr 22, 2010 | |
* Time: 11:21:32 AM | |
*/ | |
class Queue { | |
Plane start; | |
Plane end; | |
/** | |
* Constructor that initializes a queue and sets start and end point to | |
* null; these nulls are overwritten when first plane is added | |
*/ | |
Queue () { | |
start = null; | |
end = null; | |
} | |
/** | |
* Method that checks if a queue is empty or not | |
* | |
* @return true = queue is empty | |
* false = queue contains at least one plane | |
*/ | |
boolean isEmpty () { | |
return (start == null); | |
} | |
/** | |
* Method that adds a plane into an arrival queue | |
* Planes with low amount of fuel are put at the start of a queue | |
* | |
* @param name plane name | |
* @param arrivalTime time of arrival at the airport | |
* @param fuel amount of remaining fuel | |
*/ | |
void addPlane (String name, int arrivalTime, int fuel) { | |
Plane auxiliary = start; | |
Plane plane = new Plane (name, arrivalTime, fuel); | |
// If queue is empty... | |
if (isEmpty ()) { | |
start = plane; | |
end = plane; | |
return; | |
} | |
// If plane needs to be put at the start of a queue... | |
if (start.fuel > plane.fuel) { | |
plane.next = start; | |
start = plane; | |
return; | |
} | |
// If plane needs to be put somewhere else... | |
while (auxiliary != null) { | |
// If plane needs to be put at the end of the queue... | |
if (auxiliary.next == null) { | |
end = plane; | |
auxiliary.next = plane; | |
return; | |
} | |
// If plane needs to be put in the middle of the queue... | |
if (auxiliary.next.fuel > plane.fuel) { | |
plane.next = auxiliary.next; | |
auxiliary.next = plane; | |
return; | |
} | |
auxiliary = auxiliary.next; | |
} | |
} | |
/** | |
* Removes first plane from queue | |
* | |
* @return removed plane | |
*/ | |
Plane deletePlane () { | |
Plane auxiliary = start; | |
start = start.next; | |
auxiliary.next = null; | |
if (start == null) { | |
end = null; | |
} | |
return auxiliary; | |
} | |
/** | |
* Removes plane with fuel level of zero from queue | |
* | |
* @param name name of plane, we're assuming plane name is an unique | |
* identifier | |
* | |
* @return crashed plane | |
*/ | |
Plane deleteCrashedPlane (String name) { | |
Plane auxiliary, crashed; | |
if (start.name.equals (name)) { | |
// If crashed plane is located at the start of a queue... | |
crashed = start; | |
start = start.next; | |
} else { | |
// If crashed plane is located somewhere else... | |
auxiliary = start; | |
crashed = null; | |
while (auxiliary != null) { | |
if (auxiliary.next.name.equals (name)) { | |
// If crashed plane is located at the end of te queue... | |
if (auxiliary.next == end) { | |
end = auxiliary; | |
} | |
crashed = auxiliary.next; | |
auxiliary.next = auxiliary.next.next.next; | |
} | |
auxiliary = auxiliary.next; | |
} | |
} | |
return crashed; | |
} | |
/** | |
* Decreases amount of fuel for all planes by one | |
*/ | |
void decreaseFuelLevel () { | |
Plane auxiliary = start; | |
while (auxiliary != null) { | |
auxiliary.fuel--; | |
auxiliary = auxiliary.next; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Created by IntelliJ IDEA. | |
* User: Milan | |
* Date: May 8, 2010 | |
* Time: 7:30:06 PM | |
*/ | |
import java.io.BufferedWriter; | |
import java.io.File; | |
import java.io.FileWriter; | |
import java.io.IOException; | |
import java.text.MessageFormat; | |
import java.util.Scanner; | |
public class QueueGenerator { | |
/* | |
"Global" variable holding current time | |
*/ | |
private static int time = 0; | |
/** | |
* Main method that asks the user for all information needed to start | |
* automatic generation of planes | |
* | |
* @param args command line arguments; not used | |
*/ | |
public static void main (String args[]) { | |
BufferedWriter bufferedWriter; | |
String plane; | |
int numberOfPlanes, planesPerSecond; | |
float fuelBase, fuelCoefficient; | |
bufferedWriter = openFile (); | |
numberOfPlanes = getPlanes ('t'); | |
planesPerSecond = getPlanes ('a'); | |
fuelBase = getFuel ('b'); | |
fuelCoefficient = getFuel ('c'); | |
System.out.println ("Už se na tom maká, šéfe."); | |
for (int i = 0; i < numberOfPlanes; i++) { | |
plane = generatePlane (fuelBase, fuelCoefficient, planesPerSecond); | |
writePlane (bufferedWriter, plane); | |
} | |
System.out.println ("Hotovka, šéfe."); | |
closeFile (bufferedWriter); | |
} | |
/** | |
* Method that asks the user for a filename | |
* | |
* @return text string from an user | |
*/ | |
private static String getFileName () { | |
Scanner scanner = new Scanner (System.in); | |
System.out.print (MessageFormat.format ("{0}: ", "Název souboru")); | |
return (scanner.next ()); | |
} | |
/** | |
* Method that asks the user for fuel-related values | |
* | |
* @param id 'b' = ask for base fuel value | |
* 'c' = ask for coefficient fuel value | |
* | |
* @return value from user | |
*/ | |
private static float getFuel (char id) { | |
Scanner scanner = new Scanner (System.in); | |
if (id == 'b') { // Base | |
System.out.print (MessageFormat.format ("{0}: ", "Benzín (základ)")); | |
} else if (id == 'c') { // Coefficient | |
System.out.print (MessageFormat.format ("{0}: ", "Benzín (koeficient)")); | |
} else { // Fallback | |
System.out.print (MessageFormat.format ("{0}: ", "Benzín")); | |
} | |
return (scanner.nextFloat ()); | |
} | |
/** | |
* Method that asks the user for plane-related values | |
* | |
* @param id 'a' = ask for average number of planes per secodn | |
* 't' = ask for total number of planes | |
* | |
* @return value from user | |
*/ | |
private static int getPlanes (char id) { | |
Scanner scanner = new Scanner (System.in); | |
if (id == 'a') { // Average | |
System.out.print (MessageFormat.format ("{0}: ", "Letadel za vteřinu (průměrně)")); | |
} else if (id == 't') { // Total | |
System.out.print (MessageFormat.format ("{0}: ", "Celkem letadel")); | |
} else { // Fallback | |
System.out.print (MessageFormat.format ("{0}: ", "Počet letadel")); | |
} | |
return (scanner.nextInt ()); | |
} | |
/** | |
* Overloaded method that calls getFileName () method to get the filename | |
* from user, then calls openFile () method to open specified file | |
* | |
* @return opened buffered stream | |
*/ | |
private static BufferedWriter openFile () { | |
return openFile (getFileName ()); | |
} | |
/** | |
* Method that opens a buffered writer on a specified file and keeps that | |
* writer open by returning reference to that writer | |
* | |
* @param filename name of file to open | |
* | |
* @return opened buffered stream | |
*/ | |
private static BufferedWriter openFile (String filename) { | |
try { | |
File file = new File (MessageFormat.format ("src{0}Queues{0}{1}", File.separator, filename)); | |
FileWriter fileReader = new FileWriter (file); | |
BufferedWriter bufferedWriter = new BufferedWriter (fileReader); | |
return (bufferedWriter); | |
} catch (IOException e) { | |
System.out.println (MessageFormat.format ("Soubor nelze otevřít: {0}!", e.getLocalizedMessage ())); | |
return (null); | |
} | |
} | |
/** | |
* Method that writes one generated plane into queue file | |
* | |
* @param bufferedWriter opened buffered stream | |
* @param plane plane details | |
*/ | |
private static void writePlane (BufferedWriter bufferedWriter, String plane) { | |
try { | |
bufferedWriter.write (plane); | |
} catch (IOException e) { | |
System.out.println ( | |
MessageFormat.format ("Nepodařilo se zapsat do souboru: {0}!", e.getLocalizedMessage ())); | |
} | |
} | |
/** | |
* Closes previously opened file | |
* | |
* @param bufferedWriter opened buffered stream | |
*/ | |
private static void closeFile (BufferedWriter bufferedWriter) { | |
try { | |
bufferedWriter.close (); | |
} catch (IOException e) { | |
System.out.println (MessageFormat.format ("Soubor se nepodařilo uzavřít: {0}!", e.getLocalizedMessage ())); | |
} | |
} | |
/** | |
* Method that generates one plane using the given paramethers | |
* | |
* @param fuelBase fuel base | |
* @param fuelCoefficient fuel coefficient | |
* @param planesPerSecond average amount of planes per second | |
* | |
* @return string with plane details | |
*/ | |
private static String generatePlane (double fuelBase, double fuelCoefficient, int planesPerSecond) { | |
String plane, planeName; | |
int fuel; | |
if ((int) (Math.random () * 5 + 1) == planesPerSecond) { | |
time++; | |
} | |
planeName = generatePlaneName (); | |
fuel = (int) ((fuelBase + (Math.random () * 10 + 1) / 5) * (fuelCoefficient + (Math.random () * 10 + 1) / 5)); | |
plane = planeName + ' ' + time + ' ' + fuel + '\n'; | |
return plane; | |
} | |
/** | |
* Generates random plane name | |
* | |
* @return generated plane name | |
*/ | |
private static String generatePlaneName () { | |
String planeName = ""; | |
char randomChar; | |
// Two letters | |
for (int i = 0; i < 2; i++) { | |
randomChar = (char) ((int) ('A') + Math.random () * ((int) ('Z') - (int) ('A') + 1)); | |
planeName += randomChar; | |
} | |
// And three numbers | |
for (int i = 0; i < 3; i++) { | |
planeName += (int) (Math.random () * 9 + 1); | |
} | |
return planeName; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment