diff --git a/Dockerfile b/Dockerfile index 894e5ec87..49d14dcfd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,12 @@ -FROM docker.io/bitnami/spark:3 +FROM docker.io/bitnami/spark:3.1.2 ENV SPARK_MASTER local[*] -ENV ZINGG_HOME /zingg-0.3.0-SNAPSHOT +ENV ZINGG_HOME /zingg-0.3.1-SNAPSHOT WORKDIR / USER root -WORKDIR /zingg-0.3.0-SNAPSHOT -RUN curl --location https://github.com/zinggAI/zingg/releases/download/v0.3.0/zingg-0.3.0-SNAPSHOT-spark-3.0.3.tar.gz | \ +WORKDIR /zingg-0.3.1-SNAPSHOT +RUN curl --location https://github.com/zinggAI/zingg/releases/download/v0.3.1/zingg-0.3.1-SNAPSHOT-spark-3.1.2.tar.gz | \ tar --extract --gzip --strip=1 +RUN chmod -R +rwx /zingg-0.3.1-SNAPSHOT/models #RUN chmod +x zingg-0.3.0-SNAPSHOT-spark-3.0.3.tar.gz #RUN tar --extract --gzip --strip=1 /tmp/zingg-0.3.0-SNAPSHOT-spark-3.0.3.tar.gz USER 1001 diff --git a/client/src/main/java/zingg/client/Client.java b/client/src/main/java/zingg/client/Client.java index 844c708f7..8988b9407 100644 --- a/client/src/main/java/zingg/client/Client.java +++ b/client/src/main/java/zingg/client/Client.java @@ -85,7 +85,7 @@ else if (args.getJobId() != -1) { } public static void printBanner() { - String versionStr = "0.3"; + String versionStr = "0.3.1"; LOG.info(""); LOG.info("********************************************************"); LOG.info("* Zingg AI *"); diff --git a/client/src/main/java/zingg/client/ZinggOptions.java b/client/src/main/java/zingg/client/ZinggOptions.java index 75ab1825f..c42023825 100644 --- a/client/src/main/java/zingg/client/ZinggOptions.java +++ b/client/src/main/java/zingg/client/ZinggOptions.java @@ -12,7 +12,8 @@ public enum ZinggOptions { FIND_TRAINING_DATA("findTrainingData"), LABEL("label"), LINK("link"), - GENERATE_DOCS("generateDocs"); + GENERATE_DOCS("generateDocs"), + UPDATE_LABEL("updateLabel"); private String value; diff --git a/core/src/main/java/zingg/Documenter.java b/core/src/main/java/zingg/Documenter.java index 4b9c5ea67..f91ee6471 100644 --- a/core/src/main/java/zingg/Documenter.java +++ b/core/src/main/java/zingg/Documenter.java @@ -41,7 +41,7 @@ public void execute() throws ZinggClientException { LOG.info("Document generation in progress"); Dataset markedRecords = PipeUtil.read(spark, false, false, PipeUtil.getTrainingDataMarkedPipe(args)); markedRecords = markedRecords.cache(); - List displayCols = DSUtil.getFieldDefColumns(markedRecords, args, false); + //List displayCols = DSUtil.getFieldDefColumns(markedRecords, args, false); List clusterIDs = markedRecords.select(ColName.CLUSTER_COLUMN).distinct().collectAsList(); int totalPairs = clusterIDs.size(); /* Create a data-model */ diff --git a/core/src/main/java/zingg/LabelUpdater.java b/core/src/main/java/zingg/LabelUpdater.java new file mode 100644 index 000000000..0d872fbca --- /dev/null +++ b/core/src/main/java/zingg/LabelUpdater.java @@ -0,0 +1,118 @@ +package zingg; + +import java.util.List; +import java.util.Scanner; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.spark.sql.Column; +import org.apache.spark.sql.Dataset; +import org.apache.spark.sql.Row; +import org.apache.spark.sql.SaveMode; + +import zingg.client.ZinggClientException; +import zingg.client.ZinggOptions; +import zingg.client.pipe.Pipe; +import zingg.client.util.ColName; +import zingg.client.util.ColValues; +import zingg.util.DSUtil; +import zingg.util.LabelMatchType; +import zingg.util.PipeUtil; + +public class LabelUpdater extends Labeller { + protected static String name = "zingg.LabelUpdater"; + public static final Log LOG = LogFactory.getLog(LabelUpdater.class); + + public LabelUpdater() { + setZinggOptions(ZinggOptions.UPDATE_LABEL); + } + + public void execute() throws ZinggClientException { + try { + LOG.info("Reading inputs for updateLabelling phase ..."); + Dataset markedRecords = PipeUtil.read(spark, false, false, PipeUtil.getTrainingDataMarkedPipe(args)); + processRecordsCli(markedRecords); + LOG.info("Finished updataLabelling phase"); + } catch (Exception e) { + e.printStackTrace(); + throw new ZinggClientException(e.getMessage()); + } + } + + public void processRecordsCli(Dataset lines) throws ZinggClientException { + LOG.info("Processing Records for CLI updateLabelling"); + getMarkedRecordsStat(lines); + printMarkedRecordsStat(); + if (lines == null || lines.count() == 0) { + LOG.info("There is no marked record for updating. Please run findTrainingData/label jobs to generate training data."); + return; + } + + List displayCols = DSUtil.getFieldDefColumns(lines, args, false); + try { + int matchFlag; + Dataset updatedRecords = null; + Dataset recordsToUpdate = lines; + int selectedOption = -1; + String postMsg; + + Scanner sc = new Scanner(System.in); + do { + System.out.print("\n\tPlease enter the cluster id (or 9 to exit): "); + String cluster_id = sc.next(); + if (cluster_id.equals("9")) { + LOG.info("User has exit in the middle. Updating the records."); + break; + } + Dataset currentPair = lines.filter(lines.col(ColName.CLUSTER_COLUMN).equalTo(cluster_id)); + if (currentPair.isEmpty()) { + System.out.println("\tInvalid cluster id. Enter '9' to exit"); + continue; + } + + matchFlag = currentPair.head().getAs(ColName.MATCH_FLAG_COL); + String preMsg = String.format("\n\tThe record pairs belonging to the input cluster id %s are:", cluster_id); + String matchType = LabelMatchType.get(matchFlag).msg; + postMsg = String.format("\tThe above pair is labeled as %s\n", matchType); + selectedOption = displayRecordsAndGetUserInput(DSUtil.select(currentPair, displayCols), preMsg, postMsg); + updateLabellerStat(selectedOption, +1); + updateLabellerStat(matchFlag, -1); + printMarkedRecordsStat(); + if (selectedOption == 9) { + LOG.info("User has quit in the middle. Updating the records."); + break; + } + recordsToUpdate = recordsToUpdate + .filter(recordsToUpdate.col(ColName.CLUSTER_COLUMN).notEqual(cluster_id)); + if (updatedRecords != null) { + updatedRecords = updatedRecords + .filter(updatedRecords.col(ColName.CLUSTER_COLUMN).notEqual(cluster_id)); + } + updatedRecords = updateRecords(selectedOption, currentPair, updatedRecords); + } while (selectedOption != 9); + + if (updatedRecords != null) { + updatedRecords = updatedRecords.union(recordsToUpdate); + } + writeLabelledOutput(updatedRecords); + sc.close(); + LOG.info("Processing finished."); + } catch (Exception e) { + if (LOG.isDebugEnabled()) { + e.printStackTrace(); + } + LOG.warn("An error has occured while Updating Label. " + e.getMessage()); + throw new ZinggClientException(e.getMessage()); + } + return; + } + + + + + protected Pipe getOutputPipe() { + Pipe p = PipeUtil.getTrainingDataMarkedPipe(args); + p.setMode(SaveMode.Overwrite); + return p; + } +} \ No newline at end of file diff --git a/core/src/main/java/zingg/Labeller.java b/core/src/main/java/zingg/Labeller.java index 2da1c5d44..a6da655cf 100644 --- a/core/src/main/java/zingg/Labeller.java +++ b/core/src/main/java/zingg/Labeller.java @@ -58,10 +58,7 @@ public Dataset getUnmarkedRecords() throws ZinggClientException { unmarkedRecords = unmarkedRecords.join(markedRecords, unmarkedRecords.col(ColName.CLUSTER_COLUMN).equalTo(markedRecords.col(ColName.CLUSTER_COLUMN)), "left_anti"); - positivePairsCount = markedRecords.filter(markedRecords.col(ColName.MATCH_FLAG_COL).equalTo(ColValues.MATCH_TYPE_MATCH)).count() / 2; - negativePairsCount = markedRecords.filter(markedRecords.col(ColName.MATCH_FLAG_COL).equalTo(ColValues.MATCH_TYPE_NOT_A_MATCH)).count() / 2; - notSurePairsCount = markedRecords.filter(markedRecords.col(ColName.MATCH_FLAG_COL).equalTo(ColValues.MATCH_TYPE_NOT_SURE)).count() / 2; - totalCount = markedRecords.count() / 2; + getMarkedRecordsStat(markedRecords); } } catch (Exception e) { LOG.warn("No unmarked record for labelling"); @@ -69,6 +66,13 @@ public Dataset getUnmarkedRecords() throws ZinggClientException { return unmarkedRecords; } + protected void getMarkedRecordsStat(Dataset markedRecords) { + positivePairsCount = markedRecords.filter(markedRecords.col(ColName.MATCH_FLAG_COL).equalTo(ColValues.MATCH_TYPE_MATCH)).count() / 2; + negativePairsCount = markedRecords.filter(markedRecords.col(ColName.MATCH_FLAG_COL).equalTo(ColValues.MATCH_TYPE_NOT_A_MATCH)).count() / 2; + notSurePairsCount = markedRecords.filter(markedRecords.col(ColName.MATCH_FLAG_COL).equalTo(ColValues.MATCH_TYPE_NOT_SURE)).count() / 2; + totalCount = markedRecords.count() / 2; + } + public void processRecordsCli(Dataset lines) throws ZinggClientException { LOG.info("Processing Records for CLI Labelling"); printMarkedRecordsStat(); @@ -96,14 +100,15 @@ public void processRecordsCli(Dataset lines) throws ZinggClientException { score = currentPair.head().getAs(ColName.SCORE_COL); prediction = currentPair.head().getAs(ColName.PREDICTION_COL); - msg1 = String.format("\tRecord pair %d out of %d records to be labelled by the user.\n", index, totalPairs); + msg1 = String.format("\tCurrent labelling round : %d/%d pairs labelled\n", index, totalPairs); String matchType = LabelMatchType.get(prediction).msg; - msg2 = String.format("\tZingg predicts the records %s with a similarity score of %.2f\n", + msg2 = String.format("\tZingg predicts the above records %s with a similarity score of %.2f", matchType, score); - String msgHeader = msg1 + msg2; + //String msgHeader = msg1 + msg2; - selected_option = displayRecordsAndGetUserInput(DSUtil.select(currentPair, displayCols), msgHeader); - updateLabellerStat(selected_option); + selected_option = displayRecordsAndGetUserInput(DSUtil.select(currentPair, displayCols), msg1, msg2); + updateLabellerStat(selected_option, 1); + printMarkedRecordsStat(); if (selected_option == 9) { LOG.info("User has quit in the middle. Updating the records."); break; @@ -123,15 +128,17 @@ public void processRecordsCli(Dataset lines) throws ZinggClientException { } - private int displayRecordsAndGetUserInput(Dataset records, String preMessage) { - System.out.println(); + protected int displayRecordsAndGetUserInput(Dataset records, String preMessage, String postMessage) { + //System.out.println(); System.out.println(preMessage); records.show(false); + System.out.println(postMessage); + System.out.println("\tWhat do you think? Your choices are: "); int selection = readCliInput(); return selection; } - private Dataset updateRecords(int matchValue, Dataset newRecords, Dataset updatedRecords) { + protected Dataset updateRecords(int matchValue, Dataset newRecords, Dataset updatedRecords) { newRecords = newRecords.withColumn(ColName.MATCH_FLAG_COL, functions.lit(matchValue)); if (updatedRecords == null) { updatedRecords = newRecords; @@ -142,52 +149,23 @@ private Dataset updateRecords(int matchValue, Dataset newRecords, Data } - private List getDisplayColumns(Dataset lines) { - List cols = Arrays.asList(lines.columns()); - List skipCols = getExcludedColumns(); - List displayCols = new ArrayList<>(); - for (String key : cols) { - if (!skipCols.contains(key)) { - displayCols.add(key); - } - } - return displayCols; - } - - private List getDisplayData(Row row, List cols) { - List strArray = new ArrayList<>(); - for (String key : cols) { - strArray.add(row.getAs(key).toString()); - } - return strArray; - } - - private List getExcludedColumns() { - List columns = new ArrayList<>(); - columns.add(ColName.ID_COL); - columns.add(ColName.CLUSTER_COLUMN); - columns.add(ColName.SCORE_COL); - columns.add(ColName.PREDICTION_COL); - columns.add(ColName.MATCH_FLAG_COL); - - return columns; - } + int readCliInput() { Scanner sc = new Scanner(System.in); System.out.println(); - System.out.println("\tPlease select from the following choices"); + System.out.println("\tNo, they do not match : 0"); System.out.println("\tYes, they match : 1"); System.out.println("\tNot sure : 2"); - System.out.println(""); + System.out.println(); System.out.println("\tTo exit : 9"); System.out.println(); System.out.print("\tPlease enter your choice [0,1,2 or 9]: "); while (!sc.hasNext("[0129]")) { sc.next(); - System.out.println("Nope, enter one of the allowed option!"); + System.out.println("Nope, please enter one of the allowed options!"); } String word = sc.next(); int selection = Integer.parseInt(word); @@ -196,36 +174,40 @@ int readCliInput() { return selection; } - private void updateLabellerStat(int selected_option) { + protected void updateLabellerStat(int selected_option, int increment) { + totalCount += increment; if (selected_option == ColValues.MATCH_TYPE_MATCH) { - ++positivePairsCount; - ++totalCount; + positivePairsCount += increment; } else if (selected_option == ColValues.MATCH_TYPE_NOT_A_MATCH) { - ++negativePairsCount; - ++totalCount; + negativePairsCount += increment; } else if (selected_option == ColValues.MATCH_TYPE_NOT_SURE) { - ++notSurePairsCount; - ++totalCount; + notSurePairsCount += increment; } - printMarkedRecordsStat(); } - private void printMarkedRecordsStat() { + protected void printMarkedRecordsStat() { String msg = String.format( - "\tLabelled Pairs : %d/%d MATCH, %d/%d DO NOT MATCH, %d/%d NOT SURE", positivePairsCount, totalCount, + "\tLabelled pairs so far : %d/%d MATCH, %d/%d DO NOT MATCH, %d/%d NOT SURE", positivePairsCount, totalCount, negativePairsCount, totalCount, notSurePairsCount, totalCount); + + System.out.println(); + System.out.println(); + System.out.println(); System.out.println(msg); } - void writeLabelledOutput(Dataset records) { + protected void writeLabelledOutput(Dataset records) { if (records == null) { LOG.warn("No records to be labelled."); return; - } - Pipe p = PipeUtil.getTrainingDataMarkedPipe(args); - PipeUtil.write(records, args, ctx, p); + } + PipeUtil.write(records, args, ctx, getOutputPipe()); + } + + protected Pipe getOutputPipe() { + return PipeUtil.getTrainingDataMarkedPipe(args); } } diff --git a/core/src/main/java/zingg/Trainer.java b/core/src/main/java/zingg/Trainer.java index 152ab3211..ec8a8c112 100644 --- a/core/src/main/java/zingg/Trainer.java +++ b/core/src/main/java/zingg/Trainer.java @@ -42,6 +42,8 @@ public void execute() throws ZinggClientException { tra = tra.cache(); positives = tra.filter(tra.col(ColName.MATCH_FLAG_COL).equalTo(ColValues.MATCH_TYPE_MATCH)); negatives = tra.filter(tra.col(ColName.MATCH_FLAG_COL).equalTo(ColValues.MATCH_TYPE_NOT_A_MATCH)); + LOG.warn("Training on positive pairs - " + positives.count()); + LOG.warn("Training on negative pairs - " + negatives.count()); Dataset testData = PipeUtil.read(spark, true, args.getNumPartitions(), false, args.getData()); Tree blockingTree = BlockingTreeUtil.createBlockingTreeFromSample(testData, positives, 0.5, diff --git a/core/src/main/java/zingg/ZFactory.java b/core/src/main/java/zingg/ZFactory.java index 38f1dbe14..2a76c6d9b 100644 --- a/core/src/main/java/zingg/ZFactory.java +++ b/core/src/main/java/zingg/ZFactory.java @@ -20,6 +20,7 @@ public ZFactory() {} zinggers.put(ZinggOptions.TRAIN_MATCH, TrainMatcher.name); zinggers.put(ZinggOptions.LINK, Linker.name); zinggers.put(ZinggOptions.GENERATE_DOCS, Documenter.name); + zinggers.put(ZinggOptions.UPDATE_LABEL, LabelUpdater.name); } public IZingg get(ZinggOptions z) throws InstantiationException, IllegalAccessException, ClassNotFoundException { diff --git a/core/src/main/java/zingg/util/ConsoleStringBuilder.java b/core/src/main/java/zingg/util/ConsoleStringBuilder.java new file mode 100644 index 000000000..864c96e8d --- /dev/null +++ b/core/src/main/java/zingg/util/ConsoleStringBuilder.java @@ -0,0 +1,543 @@ +package zingg.util; + +/** + * This is a direct port of https://github.com/nathan-fiscaletti/ansi-util + * + * @author Nathan Fiscaletti + * @see https://github.com/nathan-fiscaletti/ansi-util + * + * Usage: + * + * ConsoleStringBuilder sb = new ConsoleStringBuilder(); + * + * System.out.println( + * sb.raw("Hello, ") + * .underline("John Doe") + * .resetUnderline() + * .raw(". ") + * .raw("This is ") + * .color16(ConsoleStringBuilder.Color16.FG_RED, "red") + * .raw(".") + * ); + */ + + //All credits to this class belong to https://gist.github.com/nathan-fiscaletti/9dc252d30b51df7d710a +public class ConsoleStringBuilder +{ + /** + * The current String. + * + * @var String + */ + private String string = ""; + + /** + * Reset the hidden flag. + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder resetHidden() + { + return this.resetHidden(""); + } + + /** + * Reset the hidden flag. + * + * @param String value + * + * @return CConsoleStringBuilder + */ + public ConsoleStringBuilder resetHidden(String value) + { + this.ansi(Integer.toString(28)); + this.raw(value); + + return this; + } + + /** + * Reset the invert colors flag. + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder resetInvertColors() + { + return this.resetInvertColors(""); + } + + /** + * Reset the hidden flag. + * + * @param String value + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder resetInvertColors(String value) + { + this.ansi(Integer.toString(27)); + this.raw(value); + + return this; + } + + /** + * Reset the blink flag. + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder resetBlink() + { + return this.resetBlink(""); + } + + /** + * Reset the blink flag. + * + * @param String value + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder resetBlink(String value) + { + this.ansi(Integer.toString(25)); + this.raw(value); + + return this; + } + + /** + * Reset the underline flag. + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder resetUnderline() + { + return this.resetUnderline(""); + } + + /** + * Reset the underline flag. + * + * @param String value + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder resetUnderline(String value) + { + this.ansi(Integer.toString(24)); + this.raw(value); + + return this; + } + + /** + * Reset the dim flag. + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder resetDim() + { + return this.resetDim(""); + } + + /** + * Reset the dim flag. + * + * @param String value + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder resetDim(String value) + { + this.ansi(Integer.toString(22)); + this.raw(value); + + return this; + } + + /** + * Reset the bold flag. + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder resetBold() + { + return this.resetBold(""); + } + + /** + * Reset the bold flag. + * + * @param String value + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder resetBold(String value) + { + this.ansi(Integer.toString(21)); + this.raw(value); + + return this; + } + + + /** + * Reset to default. + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder reset() + { + return this.reset(""); + } + + /** + * Reset to default. + * + * @param String value + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder reset(String value) + { + this.ansi(Integer.toString(0)); + this.raw(value); + + return this; + } + + /** + * Set the hide flag. + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder hide() + { + return this.hide(""); + } + + /** + * Set the hide flag. + * + * @param String value + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder hide(String value) + { + this.ansi(Integer.toString(8)); + this.raw(value); + + return this; + } + + /** + * Set the invert color flag. + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder invertColor() + { + return this.invertColor(""); + } + + /** + * Set the invert color flag. + * + * @param String value + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder invertColor(String value) + { + this.ansi(Integer.toString(7)); + this.raw(value); + + return this; + } + + /** + * Set the blink flag. + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder blink() + { + return this.blink(""); + } + + /** + * Set the invert flag. + * + * @param String value + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder blink(String value) + { + this.ansi(Integer.toString(5)); + this.raw(value); + + return this; + } + + /** + * Set the underline flag. + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder underline() + { + return this.underline(""); + } + + /** + * Set the underline flag. + * + * @param String value + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder underline(String value) + { + this.ansi(Integer.toString(4)); + this.raw(value); + + return this; + } + + /** + * Set the dim flag. + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder dim() + { + return this.dim(""); + } + + /** + * Set the dim flag. + * + * @param String value + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder dim(String value) + { + this.ansi(Integer.toString(2)); + this.raw(value); + + return this; + } + + /** + * Set the bold flag. + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder bold() + { + return this.bold(""); + } + + /** + * Set the bold flag. + * + * @param String value + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder bold(String value) + { + this.ansi(Integer.toString(1)); + this.raw(value); + + return this; + } + + /** + * Set a 16-bit color. + * + * @param Color16 color + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder color16(Color16 color) + { + return this.color16(color, ""); + } + + /** + * Set a 16-bit color. + * + * @param Color16 color + * @param String value + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder color16(Color16 color, String value) + { + this.ansi(Integer.toString(color.getValue())); + this.raw(value); + + return this; + } + + /** + * Set a 256-bit color. + * + * @param int color + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder color256(int color) throws Exception + { + return this.color256(color, ""); + } + + /** + * Set a 256-bit color. + * + * @param int color + * @param String value + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder color256(int color, String value) throws Exception + { + if (color < 0 || color > 256) { + throw new Exception("Valid 256-bit colors must be within the range of 0 and 256."); + } + + this.ansi("38;5;" + color); + this.raw(value); + + return this; + } + + /** + * Set a 256-bit background color. + * + * @param int color + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder backgroundColor256(int color) throws Exception + { + return this.backgroundColor256(color, ""); + } + + /** + * Set a 256-bit background color. + * + * @param int color + * @param String value + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder backgroundColor256(int color, String value) throws Exception + { + if (color < 0 || color > 256) { + throw new Exception("Valid 256-bit colors must be within the range of 0 and 256."); + } + + this.ansi("48;5;" + color); + this.raw(value); + + return this; + } + + /** + * Appends a raw String. + * + * @param String value + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder raw(String value) + { + this.string += value; + return this; + } + + /** + * Add a custom ANSI flag. + * + * @param String value + * + * @return ConsoleStringBuilder + */ + public ConsoleStringBuilder ansi(String value) + { + this.string += "\u001b[" + value + "m"; + return this; + } + + /** + * Build the final string. + * + * @param String value + * + * @return ConsoleStringBuilder + */ + @Override + public String toString() + { + this.reset(); + return this.string; + } + + /** + * Color16 values. + */ + public enum Color16 + { + FG_RESET(39), + FG_BLACK(30), + FG_RED(31), + FG_GREEN(32), + FG_YELLOW(33), + FG_BLUE(34), + FG_MAGENTA(35), + FG_CYAN(36), + FG_LIGHT_GRAY(37), + FG_DARK_GRAY(90), + FG_LIGHT_RED(91), + FG_LIGHT_GREEN(92), + FG_LIGHT_YELLOW(93), + FG_LIGHT_BLUE(94), + FG_LIGHT_MAGENTA(95), + FG_LIGHT_CYAN(96), + FG_WHITE(97), + BG_RESET(49), + BG_BLACK(40), + BG_RED(41), + BG_GREEN(42), + BG_YELLOW(43), + BG_BLUE(44), + BG_MAGENTA(45), + BG_CYAN(46), + BG_LIGHT_GRAY(47), + BG_DARK_GRAY(100), + BG_LIGHT_RED(101), + BG_LIGHT_GREEN(102), + BG_LIGHT_YELLOW(103), + BG_LIGHT_BLUE(104), + BG_LIGHT_MAGENTA(105), + BG_LIGHT_CYAN(106), + BG_WHITE(107); + + private int value; + public int getValue() + { + return value; + } + + Color16(int value) + { + this.value = value; + } + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index c1a45b336..dcdc895a4 100644 --- a/pom.xml +++ b/pom.xml @@ -84,7 +84,7 @@ - 0.3.0-SNAPSHOT + 0.3.1-SNAPSHOT true false 8 diff --git a/scripts/zingg.sh b/scripts/zingg.sh index 567d4f1c6..1d26621f6 100755 --- a/scripts/zingg.sh +++ b/scripts/zingg.sh @@ -1,6 +1,6 @@ #!/bin/bash #ZINGG_HOME=./assembly/target -ZINGG_JARS=$ZINGG_HOME/zingg-0.3.0-SNAPSHOT.jar +ZINGG_JARS=$ZINGG_HOME/zingg-0.3.1-SNAPSHOT.jar EMAIL=xxx@yyy.com LICENSE="test" ##for local