better styling, fixed some logic

This commit is contained in:
Daniel
2024-10-15 02:11:01 +03:00
parent d46d258889
commit 25d59bedbf
8 changed files with 363 additions and 253 deletions

View File

@@ -30,6 +30,7 @@
<artifactId>atlantafx-base</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>

View File

@@ -2,26 +2,27 @@ package org.lumijiez.monoalpha;
import javafx.fxml.FXML;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
import org.lumijiez.monoalpha.util.CharacterSwitcher;
import org.lumijiez.monoalpha.util.InputAnalyzer;
import org.lumijiez.monoalpha.util.PatternGenerator;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.lumijiez.monoalpha.util.GlobalVars.RAINBOW;
import static org.lumijiez.monoalpha.util.PatternGenerator.matchPattern;
public class MainController {
@FXML
private BarChart<String, Integer> barChart;
private BarChart<String, Number> barChart;
@FXML
private TextArea inputArea;
@@ -30,7 +31,7 @@ public class MainController {
private TextArea ruleArea;
@FXML
private TextArea outputArea;
private TextFlow outputArea;
@FXML
private TextField patternInput;
@@ -41,98 +42,38 @@ public class MainController {
@FXML
private TextArea patternOutput;
private Map<String, List<String>> dictionaryMap;
@FXML
private CheckBox rainbowCheckbox;
private final Map<String, List<String>> dictionaryMap = new HashMap<>();
@FXML
private void initialize() {
analyzeText();
loadDictionary();
barChart.setStyle("-fx-font-size: 18px;");
PatternGenerator.loadDictionary(dictionaryMap, patternOutput);
//barChart.setStyle("-fx-font-size: 18px;");
inputArea.textProperty().addListener((observable, oldValue, newValue) -> {
analyzeText();
applyChanges();
applyChanges(ruleArea.getText());
});
ruleArea.textProperty().addListener((observable, oldValue, newValue) -> applyChanges(newValue));
patternButton.setOnAction(e -> matchPattern(patternInput.getText().trim(), patternOutput, dictionaryMap));
rainbowCheckbox.selectedProperty().addListener((observable, oldValue, newValue) -> {
RAINBOW = newValue;
analyzeText();
});
ruleArea.textProperty().addListener((observable, oldValue, newValue) -> applyChanges());
patternButton.setOnAction(e -> matchPattern());
}
@FXML
private void analyzeText() {
String inputText = inputArea.getText();
Map<Character, Integer> frequencyMap = InputAnalyzer.analyzeFrequency(inputText);
List<XYChart.Data<String, Integer>> barChartData = InputAnalyzer.getBarChartData(frequencyMap);
InputAnalyzer.updateBarChart(barChart, barChartData);
String input = inputArea.getText();
Map<Character, Integer> frequencyMap = InputAnalyzer.analyzeFrequency(input);
InputAnalyzer.updateBarChart(barChart, frequencyMap);
}
private void applyChanges() {
String rules = ruleArea.getText();
String changedText = CharacterSwitcher.applyRules(rules, inputArea.getText());
outputArea.setText(changedText);
}
private void loadDictionary() {
dictionaryMap = new HashMap<>();
try (InputStream is = getClass().getResourceAsStream("/org/lumijiez/monoalpha/dictionary.txt")) {
assert is != null;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split(" ");
if (parts.length == 2) {
String pattern = parts[0];
String word = parts[1];
dictionaryMap.computeIfAbsent(pattern, k -> new ArrayList<>()).add(word);
}
}
}
} catch (IOException e) {
e.printStackTrace();
patternOutput.setText("Error loading dictionary");
}
}
private void matchPattern() {
String inputWord = patternInput.getText().trim();
if (inputWord.isEmpty()) {
patternOutput.setText("Please enter a word.");
return;
}
String inputPattern = generatePattern(inputWord);
List<String> matchingWords = dictionaryMap.getOrDefault(inputPattern, new ArrayList<>());
if (matchingWords.isEmpty()) {
patternOutput.setText("No matching words found.");
} else {
patternOutput.setText(String.join("\n", matchingWords));
}
}
private String generatePattern(String word) {
StringBuilder pattern = new StringBuilder();
char nextLower = 'a';
char nextUpper = 'A';
Map<Character, Character> charMap = new HashMap<>();
for (char c : word.toCharArray()) {
if (Character.isLowerCase(c)) {
if (!charMap.containsKey(c)) {
charMap.put(c, nextLower++);
}
pattern.append(charMap.get(c));
} else if (Character.isUpperCase(c)) {
if (!charMap.containsKey(c)) {
charMap.put(c, nextUpper++);
}
pattern.append(charMap.get(c));
} else {
pattern.append(c);
}
}
return pattern.toString();
private void applyChanges(String input) {
List<Text> textNodes = CharacterSwitcher.applyRules(input, inputArea.getText());
outputArea.getChildren().clear();
outputArea.getChildren().addAll(textNodes);
}
}

View File

@@ -1,24 +1,18 @@
package org.lumijiez.monoalpha;
import atlantafx.base.theme.Dracula;
import atlantafx.base.theme.PrimerLight;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.layout.BackgroundImage;
import javafx.scene.layout.BackgroundPosition;
import javafx.scene.layout.BackgroundRepeat;
import javafx.scene.layout.BackgroundSize;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.Objects;
public class MonoAlpha extends Application {
@Override
public void start(Stage stage) throws IOException {
Application.setUserAgentStylesheet(new Dracula().getUserAgentStylesheet());
Application.setUserAgentStylesheet(new PrimerLight().getUserAgentStylesheet());
FXMLLoader fxmlLoader = new FXMLLoader(MonoAlpha.class.getResource("monoalpha.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 1280, 720);

View File

@@ -1,30 +1,53 @@
package org.lumijiez.monoalpha.util;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class CharacterSwitcher {
public static String applyRules(String rulesInput, String text) {
public static List<Text> applyRules(String rulesInput, String text) {
Map<Character, Character> ruleMap = new HashMap<>();
String[] rules = rulesInput.split(";");
for (String rule : rules) {
String[] parts = rule.split(">");
if (parts.length != 2 || parts[0].trim().length() != 1 || parts[1].trim().length() != 1) {
return "BAD RULE";
List<Text> errorText = new ArrayList<>();
errorText.add(createErrorText());
return errorText;
}
char from = parts[0].trim().charAt(0);
char to = parts[1].trim().charAt(0);
ruleMap.put(from, to);
}
StringBuilder result = new StringBuilder();
text = text.replaceAll("\\r?\\n", "");
List<Text> textNodes = new ArrayList<>();
for (char c : text.toCharArray()) {
char newChar = ruleMap.getOrDefault(c, c);
result.append(newChar);
Text textNode = new Text(newChar + "");
if (c != newChar) {
textNode.setFill(Color.RED);
}
textNodes.add(textNode);
}
return result.toString();
return textNodes;
}
private static Text createErrorText() {
Text errorText = new Text("BAD RULE");
errorText.setFill(Color.RED);
return errorText;
}
}

View File

@@ -0,0 +1,5 @@
package org.lumijiez.monoalpha.util;
public class GlobalVars {
public static boolean RAINBOW = false;
}

View File

@@ -8,45 +8,102 @@ import javafx.util.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;
import static org.lumijiez.monoalpha.util.GlobalVars.RAINBOW;
public class InputAnalyzer {
private static final Map<String, Double> ENGLISH_FREQUENCIES = createEnglishFrequencies();
private static final Random RANDOM = new Random();
private static Map<String, Double> createEnglishFrequencies() {
Map<String, Double> frequencies = new HashMap<>();
String[] letters = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
"K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
"U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d",
"e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
"o", "p", "q", "r", "s", "t", "u", "v", "w", "x",
"y", "z"};
double[] frequenciesValues = {8.17, 1.49, 2.78, 4.25, 12.70, 2.23, 2.01, 6.09, 6.97, 0.15,
0.77, 4.03, 2.41, 6.75, 7.51, 1.93, 0.09, 5.99, 6.33, 9.06,
2.76, 0.98, 2.36, 0.15, 1.97, 0.07, 8.17, 1.49, 2.78, 4.25,
12.70, 2.23, 2.01, 6.09, 6.97, 0.15, 0.77, 4.03, 2.41, 6.75,
7.51, 1.93, 0.09, 5.99, 6.33, 9.06, 2.76, 0.98, 2.36, 0.15,
1.97, 0.07};
for (int i = 0; i < letters.length; i++) {
frequencies.put(letters[i], frequenciesValues[i]);
}
return frequencies;
}
public static Map<Character, Integer> analyzeFrequency(String text) {
Map<Character, Integer> frequencyMap = new HashMap<>();
for (char ch : text.toCharArray()) {
if (Character.isLetter(ch)) {
frequencyMap.put(ch, frequencyMap.getOrDefault(ch, 0) + 1);
}
}
text.chars()
.filter(Character::isLetter)
.forEach(ch -> frequencyMap.merge((char) ch, 1, Integer::sum));
return frequencyMap;
}
public static List<XYChart.Data<String, Integer>> getBarChartData(Map<Character, Integer> frequencyMap) {
public static List<XYChart.Data<String, Double>> getBarChartData(Map<Character, Integer> frequencyMap) {
int totalCount = frequencyMap.values().stream().mapToInt(Integer::intValue).sum();
return frequencyMap.entrySet().stream()
.map(entry -> new XYChart.Data<>(entry.getKey().toString(), entry.getValue()))
.map(entry -> new XYChart.Data<>(entry.getKey().toString(), (entry.getValue() / (double) totalCount) * 100))
.collect(Collectors.toList());
}
public static void updateBarChart(BarChart<String, Integer> barChart, List<XYChart.Data<String, Integer>> data) {
public static List<XYChart.Data<String, Double>> getStaticEnglishFrequencies() {
return ENGLISH_FREQUENCIES.entrySet().stream()
.map(entry -> new XYChart.Data<>(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
}
public static void updateBarChart(BarChart<String, Number> barChart, Map<Character, Integer> frequencyMap) {
barChart.getData().clear();
XYChart.Series<String, Integer> series = new XYChart.Series<>();
for (XYChart.Data<String, Integer> datum : data) {
series.getData().add(new XYChart.Data<>(datum.getXValue(), datum.getYValue()));
List<XYChart.Data<String, Double>> actualData = getBarChartData(frequencyMap);
List<XYChart.Data<String, Double>> englishData = getStaticEnglishFrequencies();
barChart.getData().add(createSeries("Actual Frequency", actualData, true)); // Random colors
barChart.getData().add(createSeries("English Frequency", englishData, false)); // Constant color
setTooltips(barChart.getData().get(0));
setTooltips(barChart.getData().get(1));
}
private static XYChart.Series<String, Number> createSeries(String name, List<XYChart.Data<String, Double>> data, boolean randomizeColor) {
XYChart.Series<String, Number> series = new XYChart.Series<>();
series.setName(name);
for (XYChart.Data<String, Double> datum : data) {
XYChart.Data<String, Number> barData = new XYChart.Data<>(datum.getXValue(), datum.getYValue());
barData.nodeProperty().addListener((obs, oldNode, newNode) -> {
if (RAINBOW && randomizeColor && newNode != null) {
String color = randomColor();
newNode.setStyle("-fx-bar-fill: " + color + ";");
}
});
series.getData().add(barData);
}
setTooltips(series);
return series;
}
barChart.getXAxis().setAnimated(false);
barChart.getData().add(series);
for (XYChart.Data<String, Integer> datum : series.getData()) {
Tooltip tooltip = new Tooltip("Frequency: " + datum.getYValue());
tooltip.setShowDelay(new Duration(0));
tooltip.setHideDelay(new Duration(0));
private static String randomColor() {
int r = RANDOM.nextInt(256);
int g = RANDOM.nextInt(256);
int b = RANDOM.nextInt(256);
return String.format("rgb(%d,%d,%d)", r, g, b);
}
private static void setTooltips(XYChart.Series<String, Number> series) {
for (XYChart.Data<String, Number> datum : series.getData()) {
String tooltipText = String.format("%s: %.2f%%", series.getName(), (Double) datum.getYValue());
Tooltip tooltip = new Tooltip(tooltipText);
tooltip.setShowDelay(Duration.ZERO);
tooltip.setHideDelay(Duration.ZERO);
Tooltip.install(datum.getNode(), tooltip);
}
}
}

View File

@@ -0,0 +1,82 @@
package org.lumijiez.monoalpha.util;
import javafx.scene.control.TextArea;
import org.lumijiez.monoalpha.MainController;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class PatternGenerator {
public static String generatePattern(String word) {
StringBuilder pattern = new StringBuilder();
char nextLower = 'a';
char nextUpper = 'A';
Map<Character, Character> charMap = new HashMap<>();
for (char c : word.toCharArray()) {
if (Character.isLowerCase(c)) {
if (!charMap.containsKey(c)) {
charMap.put(c, nextLower++);
}
pattern.append(charMap.get(c));
} else if (Character.isUpperCase(c)) {
if (!charMap.containsKey(c)) {
charMap.put(c, nextUpper++);
}
pattern.append(charMap.get(c));
} else {
pattern.append(c);
}
}
return pattern.toString();
}
public static void loadDictionary(Map<String, List<String>> dictionaryMap, TextArea textArea) {
try (InputStream is = MainController.class.getResourceAsStream("/org/lumijiez/monoalpha/dictionary.txt")) {
assert is != null;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split(" ");
if (parts.length == 2) {
String pattern = parts[0];
String word = parts[1];
dictionaryMap.computeIfAbsent(pattern, k -> new ArrayList<>()).add(word);
}
}
}
} catch (IOException e) {
System.out.println(e.getMessage());
textArea.setText("Error loading dictionary");
}
}
public static void matchPattern(String inputWord, TextArea patternOutput, Map<String, List<String>> dictionaryMap) {
if (inputWord.isEmpty()) {
patternOutput.setText("Please enter a word.");
return;
}
String inputPattern = generatePattern(inputWord);
List<String> matchingWords = dictionaryMap.getOrDefault(inputPattern, new ArrayList<>());
if (matchingWords.isEmpty()) {
patternOutput.setText("No matching words found.");
} else {
patternOutput.setText(String.join("\n", matchingWords));
}
}
}

View File

@@ -4,161 +4,168 @@
<?import javafx.scene.chart.CategoryAxis?>
<?import javafx.scene.chart.NumberAxis?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.TextFlow?>
<GridPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" style="-fx-background-image: url(https://i.ibb.co/mRZkK7v/Pngtree-wrinkled-polyethylene-film-cling-film-7266284.png); -fx-padding: 10; -fx-background-repeat: no-repeat; -fx-background-size: cover;" xmlns="http://javafx.com/javafx/23" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.lumijiez.monoalpha.MainController">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="80" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="20" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<GridPane>
<GridPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" style="-fx-padding: 10; -fx-background-repeat: no-repeat; -fx-background-size: cover;" xmlns="http://javafx.com/javafx/23" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.lumijiez.monoalpha.MainController">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="100.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" percentHeight="30" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" percentHeight="70" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" percentHeight="30" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" percentHeight="70" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="15.0" percentWidth="15" prefWidth="100.0" />
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<BarChart fx:id="barChart" alternativeColumnFillVisible="true" legendSide="TOP" legendVisible="false" opacity="0.85" GridPane.columnIndex="1">
<xAxis>
<CategoryAxis side="BOTTOM" />
</xAxis>
<yAxis>
<NumberAxis side="LEFT" tickLabelFill="WHITE">
<tickLabelFont>
<Font name="Copperplate Gothic Light" size="18.0" />
</tickLabelFont></NumberAxis>
</yAxis>
</BarChart>
<GridPane>
</rowConstraints>
<BarChart fx:id="barChart" alternativeRowFillVisible="false" horizontalGridLinesVisible="false" horizontalZeroLineVisible="false" legendSide="TOP" style="-fx-bar-gap: 0; -fx-category-gap: 3px; -fx-vertical-grid-lines-visible: false; -fx-horizontal-grid-lines-visible: false;" verticalGridLinesVisible="false" verticalZeroLineVisible="false">
<xAxis>
<CategoryAxis side="BOTTOM" />
</xAxis>
<yAxis>
<NumberAxis side="LEFT" />
</yAxis>
</BarChart>
</GridPane>
<GridPane hgap="5.0" style="-fx-padding: 5; -fx-border-insets: 5; -fx-background-insets: 5;" GridPane.rowIndex="1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="20" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="20" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" percentHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" percentHeight="90.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" percentHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<Label alignment="CENTER" contentDisplay="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="Encrypted Input">
<font>
<Font name="SansSerif Regular" size="22.0" />
</font>
</Label>
<TextArea fx:id="inputArea" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" onInputMethodTextChanged="#analyzeText" opacity="0.85" prefHeight="200.0" prefWidth="200.0" promptText="Input encrypted text..." wrapText="true" GridPane.rowIndex="1">
<font>
<Font name="SansSerif Regular" size="14.0" />
</font>
</TextArea>
<CheckBox fx:id="rainbowCheckbox" mnemonicParsing="false" text="Randomize Colors" GridPane.rowIndex="2">
<font>
<Font name="SansSerif Regular" size="12.0" />
</font>
</CheckBox>
</GridPane>
<GridPane GridPane.columnIndex="1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" percentHeight="40.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<GridPane GridPane.rowIndex="1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints halignment="CENTER" hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" percentHeight="20" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" percentHeight="15.0" prefHeight="30.0" valignment="CENTER" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" percentHeight="20.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" percentHeight="70.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label alignment="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="F(X) -&gt; Y">
<font>
<Font name="Copperplate Gothic Bold" size="12.0" />
</font></Label>
<TextArea fx:id="ruleArea" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" opacity="0.85" prefHeight="200.0" prefWidth="200.0" promptText="a &gt; C; G &gt; g;" wrapText="true" GridPane.rowIndex="1">
<font>
<Font size="20.0" />
</font>
</TextArea>
</children>
</GridPane>
</children>
</GridPane>
<GridPane style="-fx-padding: 5; -fx-border-insets: 5; -fx-background-insets: 5;" GridPane.rowIndex="1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="75" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<GridPane prefHeight="280.0" prefWidth="263.0" style="-fx-background-insets: 5; -fx-border-insets: 5; -fx-padding: 5;" GridPane.columnIndex="1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" percentHeight="10" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" percentHeight="10" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" percentHeight="10" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label alignment="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="Pattern Matcher">
<font>
<Font name="Copperplate Gothic Bold" size="16.0" />
</font>
</Label>
<TextField fx:id="patternInput" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" promptText="Any word..." GridPane.rowIndex="1">
<font>
<Font size="18.0" />
</font>
<Label alignment="CENTER" contentDisplay="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="Pattern Matcher">
<font>
<Font name="SansSerif Regular" size="22.0" />
</font>
</Label>
<TextArea fx:id="patternOutput" editable="false" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" opacity="0.85" prefHeight="55.0" prefWidth="113.0" wrapText="true" GridPane.rowIndex="2">
<font>
<Font name="SansSerif Regular" size="18.0" />
</font>
</TextArea>
<GridPane GridPane.rowIndex="1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="70.0" prefWidth="100.0"/>
<ColumnConstraints halignment="CENTER" hgrow="SOMETIMES" minWidth="10.0" percentWidth="30.0"
prefWidth="100.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
</rowConstraints>
<TextField fx:id="patternInput" maxWidth="1.7976931348623157E308" promptText="Any word...">
<font>
<Font size="18.0"/>
</font>
</TextField>
<Button fx:id="patternButton" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" text="Search" GridPane.rowIndex="2" />
<TextArea fx:id="patternOutput" editable="false" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" opacity="0.85" prefHeight="200.0" prefWidth="200.0" wrapText="true" GridPane.rowIndex="3">
<font>
<Font size="16.0" />
</font></TextArea>
</children>
</GridPane>
<GridPane>
<Button fx:id="patternButton" alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false"
styleClass="success" text="Search" GridPane.columnIndex="1"/>
</GridPane>
</GridPane>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" percentHeight="10" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" percentHeight="25.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" percentHeight="75.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<TextArea fx:id="outputArea" editable="false" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" opacity="0.85" prefHeight="200.0" prefWidth="200.0" wrapText="true" GridPane.rowIndex="1">
<font>
<Font size="19.0" />
</font>
</TextArea>
<Label alignment="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="Decrypted Output">
<font>
<Font name="Copperplate Gothic Bold" size="22.0" />
</font>
</Label>
</children>
</GridPane>
</children>
<Label alignment="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="F(X) -&gt; Y">
<font>
<Font name="SansSerif Regular" size="22.0" />
</font>
</Label>
<TextArea fx:id="ruleArea" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" opacity="0.85" prefHeight="200.0" prefWidth="200.0" promptText="a &gt; C; G &gt; g;" wrapText="true" GridPane.rowIndex="1">
<font>
<Font name="SansSerif Regular" size="20.0" />
</font>
</TextArea>
</GridPane>
</GridPane>
</children>
</GridPane>
<VBox prefHeight="200.0" prefWidth="100.0" GridPane.columnIndex="1">
<children>
<GridPane VBox.vgrow="ALWAYS">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" percentHeight="7" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label alignment="CENTER" contentDisplay="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="Encrypted Input">
<font>
<Font name="Copperplate Gothic Bold" size="22.0" />
</font>
</Label>
<TextArea fx:id="inputArea" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" onInputMethodTextChanged="#analyzeText" opacity="0.85" prefHeight="200.0" prefWidth="200.0" promptText="Input encrypted text..." wrapText="true" GridPane.rowIndex="1">
<font>
<Font size="13.0" />
</font>
</TextArea>
</children>
<GridPane GridPane.columnIndex="2">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" percentHeight="10" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" percentHeight="90.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<Label alignment="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="Decrypted Output">
<font>
<Font name="SansSerif Regular" size="22.0" />
</font>
</Label>
<ScrollPane fitToHeight="true" fitToWidth="true" maxWidth="1.7976931348623157E308" prefHeight="200.0"
prefWidth="200.0"
style="-fx-border-color: lightgray; -fx-border-width: 1; -fx-border-radius: 5px;"
GridPane.hgrow="ALWAYS" GridPane.rowIndex="1" GridPane.vgrow="ALWAYS">
<TextFlow fx:id="outputArea" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
prefHeight="200.0" prefWidth="200.0" style="-fx-padding: 5px;"/>
</ScrollPane>
</GridPane>
</children>
</VBox>
</children>
</GridPane>
</GridPane>
</GridPane>