/* package whatever; // don't place package name! */
import java.util.*;
import java.lang.*;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
private static final Pattern STRIP_COLOR_PATTERN
= Pattern.
compile("(?i)" + String.
valueOf('§') + "[0-9A-FK-OR]");
private enum ChatColor
{
/**
* Represents black
*/
BLACK('0', 0x00),
/**
* Represents dark blue
*/
DARK_BLUE('1', 0x1),
/**
* Represents dark green
*/
DARK_GREEN('2', 0x2),
/**
* Represents dark blue (aqua)
*/
DARK_AQUA('3', 0x3),
/**
* Represents dark red
*/
DARK_RED('4', 0x4),
/**
* Represents dark purple
*/
DARK_PURPLE('5', 0x5),
/**
* Represents gold
*/
GOLD('6', 0x6),
/**
* Represents gray
*/
GRAY('7', 0x7),
/**
* Represents dark gray
*/
DARK_GRAY('8', 0x8),
/**
* Represents blue
*/
BLUE('9', 0x9),
/**
* Represents green
*/
GREEN('a', 0xA),
/**
* Represents aqua
*/
AQUA('b', 0xB),
/**
* Represents red
*/
RED('c', 0xC),
/**
* Represents light purple
*/
LIGHT_PURPLE('d', 0xD),
/**
* Represents yellow
*/
YELLOW('e', 0xE),
/**
* Represents white
*/
WHITE('f', 0xF),
/**
* Represents magical characters that change around randomly
*/
MAGIC('k', 0x10, true),
/**
* Makes the text bold.
*/
BOLD('l', 0x11, true),
/**
* Makes a line appear through the text.
*/
STRIKETHROUGH('m', 0x12, true),
/**
* Makes the text appear underlined.
*/
UNDERLINE('n', 0x13, true),
/**
* Makes the text italic.
*/
ITALIC('o', 0x14, true),
/**
* Resets all previous chat colors or formats.
*/
RESET('r', 0x15);
/**
* The special character which prefixes all chat colour codes. Use this if
* you need to dynamically convert colour codes from your custom format.
*/
public static final char COLOR_CHAR = '\u00A7';
private static final Pattern STRIP_COLOR_PATTERN
= Pattern.
compile("(?i)" + String.
valueOf(COLOR_CHAR
) + "[0-9A-FK-OR]");
private final int intCode;
private final char code;
private final boolean isFormat;
private final String toString
; private final static Map
<Integer, ChatColor
> BY_ID
= new HashMap
<>(); private final static Map
<Character, ChatColor
> BY_CHAR
= new HashMap
<>();
private ChatColor(char code, int intCode) {
this(code, intCode, false);
}
private ChatColor(char code, int intCode, boolean isFormat) {
this.code = code;
this.intCode = intCode;
this.isFormat = isFormat;
this.
toString = new String(new char[] {COLOR_CHAR, code
}); }
/**
* Gets the char value associated with this color
*
* @return A char value of this color code
*/
public char getChar() {
return code;
}
@Override
return toString;
}
/**
* Checks if this code is a format code as opposed to a color code.
*/
public boolean isFormat() {
return isFormat;
}
/**
* Checks if this code is a color code as opposed to a format code.
*/
public boolean isColor() {
return !isFormat && this != RESET;
}
/**
* Gets the color represented by the specified color code
*
* @param code Code to check
* @return Associative {@link org.bukkit.ChatColor} with the given code,
* or null if it doesn't exist
*/
public static ChatColor getByChar(char code) {
return BY_CHAR.get(code);
}
/**
* Gets the color represented by the specified color code
*
* @param code Code to check
* @return Associative {@link org.bukkit.ChatColor} with the given code,
* or null if it doesn't exist
*/
public static ChatColor getByChar
(String code
) { return BY_CHAR.get(code.charAt(0));
}
/**
* Strips the given message of all color codes
*
* @param input String to strip of color
* @return A copy of the input string, without any coloring
*/
if (input == null) {
return null;
}
return STRIP_COLOR_PATTERN.matcher(input).replaceAll("");
}
/**
* Translates a string using an alternate color code character into a
* string that uses the internal ChatColor.COLOR_CODE color code
* character. The alternate color code character will only be replaced if
* it is immediately followed by 0-9, A-F, a-f, K-O, k-o, R or r.
*
* @param altColorChar The alternate color code character to replace. Ex: &
* @param textToTranslate Text containing the alternate color code character.
* @return Text containing the ChatColor.COLOR_CODE color code character.
*/
public static String translateAlternateColorCodes
(char altColorChar,
String textToTranslate
) { char[] b = textToTranslate.toCharArray();
for (int i = 0; i < b.length - 1; i++) {
if (b[i] == altColorChar && "0123456789AaBbCcDdEeFfKkLlMmNnOoRr".indexOf(b[i+1]) > -1) {
b[i] = ChatColor.COLOR_CHAR;
}
}
}
/**
* Gets the ChatColors used at the end of the given input string.
*
* @param input Input string to retrieve the colors from.
* @return Any remaining ChatColors to pass onto the next line.
*/
int length = input.length();
// Search backwards from the end as it is faster
for (int index = length - 1; index > -1; index--) {
char section = input.charAt(index);
if (section == COLOR_CHAR && index < length - 1) {
char c = input.charAt(index + 1);
ChatColor color = getByChar(c);
if (color != null) {
result = color.toString() + result;
// Once we find a color or reset we can stop searching
if (color.isColor() || color.equals(RESET)) {
break;
}
}
}
}
return result;
}
static {
for (ChatColor color : values()) {
BY_ID.put(color.intCode, color);
BY_CHAR.put(color.code, color);
}
}
}
public static String formatString
(String input, ChatColor...
formats) {
StringBuilder sb = new StringBuilder();
for (ChatColor cc : formats) sb.append(cc);
String formatString
= sb.
toString();
Matcher matcher = STRIP_COLOR_PATTERN.matcher(result);
while (matcher.find()) {
// Replace all chat colors with the chat color, followed by the format.
// Can optionally add a ChatColor#isColor() check here.
result = result.replace(matcher.group(), matcher.group() + formatString);
}
result += ChatColor.RESET;
return result;
}
public static String format
(String name, ChatColor...
formats) {
// Remove any initial section sign, to avoid empty Strings beforehand
StringBuilder sb = new StringBuilder();
for (ChatColor cc : formats)
sb.append(cc);
String format
= sb.
toString();
boolean startsWith
= name.
startsWith(String.
valueOf(ChatColor.
COLOR_CHAR)); if (startsWith)
name = name.substring(1);
int index = 0;
// Get length
int len = 0;
while ((index = name.indexOf(ChatColor.COLOR_CHAR, index + 1)) >= 0)
len++;
// resetting index
index = 0;
// For each colour char (section sign) in the String
for (int i = 0; (index = name.indexOf(ChatColor.COLOR_CHAR, index + 1)) >= 0; i++)
{
// I was lazy, don't forget the null check!!!!!
if (ChatColor.getByChar(name.substring(index + 1, index + 2)).isFormat())
{
// Skip formats
i--; // Undo increment
continue;
}
// Assign the part up to the section sign, and prepend a the section sign
parts[i] = ChatColor.COLOR_CHAR + name.substring(0, index);
// Remove the part beforehand
name = name.substring(index);
}
parts[parts.length - 1] = name; // Leftovers
// Now join
boolean first = true;
StringBuilder joined
= new StringBuilder
(startsWith
? String.
valueOf(ChatColor.
COLOR_CHAR) : ""); {
// Start with the format
joined.append(format);
// If it was the first, only add the colour char if it previously had any
if (first)
{
first = false;
}
else // they were split based on colour char, so always add one between
{
joined.append(ChatColor.COLOR_CHAR);
}
joined.append(part);
}
return joined.toString();
}
public static void main
(String[] args
) {
String name
= ChatColor.
RED + "Dragon" + ChatColor.
BLUE + "phase"; ChatColor[] formats = new ChatColor[]{ChatColor.BOLD, ChatColor.UNDERLINE};
long start
= System.
nanoTime(); for (int i = 0; i < 1000000; i++)
{
//formatString(name, formats);
format(name, formats);
}
System.
out.
println("Average per call: "+((end
- start
) / 1000000) + "ns"); }
}
LyogcGFja2FnZSB3aGF0ZXZlcjsgLy8gZG9uJ3QgcGxhY2UgcGFja2FnZSBuYW1lISAqLwoKaW1wb3J0IGphdmEudXRpbC4qOwppbXBvcnQgamF2YS5sYW5nLio7CmltcG9ydCBqYXZhLmlvLio7CgppbXBvcnQgamF2YS51dGlsLkhhc2hNYXA7CmltcG9ydCBqYXZhLnV0aWwuTWFwOwppbXBvcnQgamF2YS51dGlsLnJlZ2V4Lk1hdGNoZXI7CmltcG9ydCBqYXZhLnV0aWwucmVnZXguUGF0dGVybjsKLyogTmFtZSBvZiB0aGUgY2xhc3MgaGFzIHRvIGJlICJNYWluIiBvbmx5IGlmIHRoZSBjbGFzcyBpcyBwdWJsaWMuICovCmNsYXNzIElkZW9uZQp7CnByaXZhdGUgc3RhdGljIGZpbmFsIFBhdHRlcm4gU1RSSVBfQ09MT1JfUEFUVEVSTiA9IFBhdHRlcm4uY29tcGlsZSgiKD9pKSIgKyBTdHJpbmcudmFsdWVPZignwqcnKSArICJbMC05QS1GSy1PUl0iKTsKCiAgICBwcml2YXRlIGVudW0gQ2hhdENvbG9yCiAgICB7CiAgICAgICAgLyoqCiAgICAgICAgICogUmVwcmVzZW50cyBibGFjawogICAgICAgICAqLwogICAgICAgIEJMQUNLKCcwJywgMHgwMCksCiAgICAgICAgLyoqCiAgICAgICAgICogUmVwcmVzZW50cyBkYXJrIGJsdWUKICAgICAgICAgKi8KICAgICAgICBEQVJLX0JMVUUoJzEnLCAweDEpLAogICAgICAgIC8qKgogICAgICAgICAqIFJlcHJlc2VudHMgZGFyayBncmVlbgogICAgICAgICAqLwogICAgICAgIERBUktfR1JFRU4oJzInLCAweDIpLAogICAgICAgIC8qKgogICAgICAgICAqIFJlcHJlc2VudHMgZGFyayBibHVlIChhcXVhKQogICAgICAgICAqLwogICAgICAgIERBUktfQVFVQSgnMycsIDB4MyksCiAgICAgICAgLyoqCiAgICAgICAgICogUmVwcmVzZW50cyBkYXJrIHJlZAogICAgICAgICAqLwogICAgICAgIERBUktfUkVEKCc0JywgMHg0KSwKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIGRhcmsgcHVycGxlCiAgICAgICAgICovCiAgICAgICAgREFSS19QVVJQTEUoJzUnLCAweDUpLAogICAgICAgIC8qKgogICAgICAgICAqIFJlcHJlc2VudHMgZ29sZAogICAgICAgICAqLwogICAgICAgIEdPTEQoJzYnLCAweDYpLAogICAgICAgIC8qKgogICAgICAgICAqIFJlcHJlc2VudHMgZ3JheQogICAgICAgICAqLwogICAgICAgIEdSQVkoJzcnLCAweDcpLAogICAgICAgIC8qKgogICAgICAgICAqIFJlcHJlc2VudHMgZGFyayBncmF5CiAgICAgICAgICovCiAgICAgICAgREFSS19HUkFZKCc4JywgMHg4KSwKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIGJsdWUKICAgICAgICAgKi8KICAgICAgICBCTFVFKCc5JywgMHg5KSwKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIGdyZWVuCiAgICAgICAgICovCiAgICAgICAgR1JFRU4oJ2EnLCAweEEpLAogICAgICAgIC8qKgogICAgICAgICAqIFJlcHJlc2VudHMgYXF1YQogICAgICAgICAqLwogICAgICAgIEFRVUEoJ2InLCAweEIpLAogICAgICAgIC8qKgogICAgICAgICAqIFJlcHJlc2VudHMgcmVkCiAgICAgICAgICovCiAgICAgICAgUkVEKCdjJywgMHhDKSwKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIGxpZ2h0IHB1cnBsZQogICAgICAgICAqLwogICAgICAgIExJR0hUX1BVUlBMRSgnZCcsIDB4RCksCiAgICAgICAgLyoqCiAgICAgICAgICogUmVwcmVzZW50cyB5ZWxsb3cKICAgICAgICAgKi8KICAgICAgICBZRUxMT1coJ2UnLCAweEUpLAogICAgICAgIC8qKgogICAgICAgICAqIFJlcHJlc2VudHMgd2hpdGUKICAgICAgICAgKi8KICAgICAgICBXSElURSgnZicsIDB4RiksCiAgICAgICAgLyoqCiAgICAgICAgICogUmVwcmVzZW50cyBtYWdpY2FsIGNoYXJhY3RlcnMgdGhhdCBjaGFuZ2UgYXJvdW5kIHJhbmRvbWx5CiAgICAgICAgICovCiAgICAgICAgTUFHSUMoJ2snLCAweDEwLCB0cnVlKSwKICAgICAgICAvKioKICAgICAgICAgKiBNYWtlcyB0aGUgdGV4dCBib2xkLgogICAgICAgICAqLwogICAgICAgIEJPTEQoJ2wnLCAweDExLCB0cnVlKSwKICAgICAgICAvKioKICAgICAgICAgKiBNYWtlcyBhIGxpbmUgYXBwZWFyIHRocm91Z2ggdGhlIHRleHQuCiAgICAgICAgICovCiAgICAgICAgU1RSSUtFVEhST1VHSCgnbScsIDB4MTIsIHRydWUpLAogICAgICAgIC8qKgogICAgICAgICAqIE1ha2VzIHRoZSB0ZXh0IGFwcGVhciB1bmRlcmxpbmVkLgogICAgICAgICAqLwogICAgICAgIFVOREVSTElORSgnbicsIDB4MTMsIHRydWUpLAogICAgICAgIC8qKgogICAgICAgICAqIE1ha2VzIHRoZSB0ZXh0IGl0YWxpYy4KICAgICAgICAgKi8KICAgICAgICBJVEFMSUMoJ28nLCAweDE0LCB0cnVlKSwKICAgICAgICAvKioKICAgICAgICAgKiBSZXNldHMgYWxsIHByZXZpb3VzIGNoYXQgY29sb3JzIG9yIGZvcm1hdHMuCiAgICAgICAgICovCiAgICAgICAgUkVTRVQoJ3InLCAweDE1KTsKCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIHNwZWNpYWwgY2hhcmFjdGVyIHdoaWNoIHByZWZpeGVzIGFsbCBjaGF0IGNvbG91ciBjb2Rlcy4gVXNlIHRoaXMgaWYKICAgICAgICAgKiB5b3UgbmVlZCB0byBkeW5hbWljYWxseSBjb252ZXJ0IGNvbG91ciBjb2RlcyBmcm9tIHlvdXIgY3VzdG9tIGZvcm1hdC4KICAgICAgICAgKi8KICAgICAgICBwdWJsaWMgc3RhdGljIGZpbmFsIGNoYXIgQ09MT1JfQ0hBUiA9ICdcdTAwQTcnOwogICAgICAgIHByaXZhdGUgc3RhdGljIGZpbmFsIFBhdHRlcm4gU1RSSVBfQ09MT1JfUEFUVEVSTiA9IFBhdHRlcm4uY29tcGlsZSgiKD9pKSIgKyBTdHJpbmcudmFsdWVPZihDT0xPUl9DSEFSKSArICJbMC05QS1GSy1PUl0iKTsKCiAgICAgICAgcHJpdmF0ZSBmaW5hbCBpbnQgaW50Q29kZTsKICAgICAgICBwcml2YXRlIGZpbmFsIGNoYXIgY29kZTsKICAgICAgICBwcml2YXRlIGZpbmFsIGJvb2xlYW4gaXNGb3JtYXQ7CiAgICAgICAgcHJpdmF0ZSBmaW5hbCBTdHJpbmcgdG9TdHJpbmc7CiAgICAgICAgcHJpdmF0ZSBmaW5hbCBzdGF0aWMgTWFwPEludGVnZXIsIENoYXRDb2xvcj4gQllfSUQgPSBuZXcgSGFzaE1hcDw+KCk7CiAgICAgICAgcHJpdmF0ZSBmaW5hbCBzdGF0aWMgTWFwPENoYXJhY3RlciwgQ2hhdENvbG9yPiBCWV9DSEFSID0gbmV3IEhhc2hNYXA8PigpOwoKICAgICAgICBwcml2YXRlIENoYXRDb2xvcihjaGFyIGNvZGUsIGludCBpbnRDb2RlKSB7CiAgICAgICAgICAgIHRoaXMoY29kZSwgaW50Q29kZSwgZmFsc2UpOwogICAgICAgIH0KCiAgICAgICAgcHJpdmF0ZSBDaGF0Q29sb3IoY2hhciBjb2RlLCBpbnQgaW50Q29kZSwgYm9vbGVhbiBpc0Zvcm1hdCkgewogICAgICAgICAgICB0aGlzLmNvZGUgPSBjb2RlOwogICAgICAgICAgICB0aGlzLmludENvZGUgPSBpbnRDb2RlOwogICAgICAgICAgICB0aGlzLmlzRm9ybWF0ID0gaXNGb3JtYXQ7CiAgICAgICAgICAgIHRoaXMudG9TdHJpbmcgPSBuZXcgU3RyaW5nKG5ldyBjaGFyW10ge0NPTE9SX0NIQVIsIGNvZGV9KTsKICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIGNoYXIgdmFsdWUgYXNzb2NpYXRlZCB3aXRoIHRoaXMgY29sb3IKICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gQSBjaGFyIHZhbHVlIG9mIHRoaXMgY29sb3IgY29kZQogICAgICAgICAqLwogICAgICAgIHB1YmxpYyBjaGFyIGdldENoYXIoKSB7CiAgICAgICAgICAgIHJldHVybiBjb2RlOwogICAgICAgIH0KCiAgICAgICAgQE92ZXJyaWRlCiAgICAgICAgcHVibGljIFN0cmluZyB0b1N0cmluZygpIHsKICAgICAgICAgICAgcmV0dXJuIHRvU3RyaW5nOwogICAgICAgIH0KCiAgICAgICAgLyoqCiAgICAgICAgICogQ2hlY2tzIGlmIHRoaXMgY29kZSBpcyBhIGZvcm1hdCBjb2RlIGFzIG9wcG9zZWQgdG8gYSBjb2xvciBjb2RlLgogICAgICAgICAqLwogICAgICAgIHB1YmxpYyBib29sZWFuIGlzRm9ybWF0KCkgewogICAgICAgICAgICByZXR1cm4gaXNGb3JtYXQ7CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBDaGVja3MgaWYgdGhpcyBjb2RlIGlzIGEgY29sb3IgY29kZSBhcyBvcHBvc2VkIHRvIGEgZm9ybWF0IGNvZGUuCiAgICAgICAgICovCiAgICAgICAgcHVibGljIGJvb2xlYW4gaXNDb2xvcigpIHsKICAgICAgICAgICAgcmV0dXJuICFpc0Zvcm1hdCAmJiB0aGlzICE9IFJFU0VUOwogICAgICAgIH0KCiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgY29sb3IgcmVwcmVzZW50ZWQgYnkgdGhlIHNwZWNpZmllZCBjb2xvciBjb2RlCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gY29kZSBDb2RlIHRvIGNoZWNrCiAgICAgICAgICogQHJldHVybiBBc3NvY2lhdGl2ZSB7QGxpbmsgb3JnLmJ1a2tpdC5DaGF0Q29sb3J9IHdpdGggdGhlIGdpdmVuIGNvZGUsCiAgICAgICAgICogICAgIG9yIG51bGwgaWYgaXQgZG9lc24ndCBleGlzdAogICAgICAgICAqLwogICAgICAgIHB1YmxpYyBzdGF0aWMgQ2hhdENvbG9yIGdldEJ5Q2hhcihjaGFyIGNvZGUpIHsKICAgICAgICAgICAgcmV0dXJuIEJZX0NIQVIuZ2V0KGNvZGUpOwogICAgICAgIH0KCiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgY29sb3IgcmVwcmVzZW50ZWQgYnkgdGhlIHNwZWNpZmllZCBjb2xvciBjb2RlCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gY29kZSBDb2RlIHRvIGNoZWNrCiAgICAgICAgICogQHJldHVybiBBc3NvY2lhdGl2ZSB7QGxpbmsgb3JnLmJ1a2tpdC5DaGF0Q29sb3J9IHdpdGggdGhlIGdpdmVuIGNvZGUsCiAgICAgICAgICogICAgIG9yIG51bGwgaWYgaXQgZG9lc24ndCBleGlzdAogICAgICAgICAqLwogICAgICAgIHB1YmxpYyBzdGF0aWMgQ2hhdENvbG9yIGdldEJ5Q2hhcihTdHJpbmcgY29kZSkgewogICAgICAgICAgICByZXR1cm4gQllfQ0hBUi5nZXQoY29kZS5jaGFyQXQoMCkpOwogICAgICAgIH0KCiAgICAgICAgLyoqCiAgICAgICAgICogU3RyaXBzIHRoZSBnaXZlbiBtZXNzYWdlIG9mIGFsbCBjb2xvciBjb2RlcwogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGlucHV0IFN0cmluZyB0byBzdHJpcCBvZiBjb2xvcgogICAgICAgICAqIEByZXR1cm4gQSBjb3B5IG9mIHRoZSBpbnB1dCBzdHJpbmcsIHdpdGhvdXQgYW55IGNvbG9yaW5nCiAgICAgICAgICovCiAgICAgICAgcHVibGljIHN0YXRpYyBTdHJpbmcgc3RyaXBDb2xvcihmaW5hbCBTdHJpbmcgaW5wdXQpIHsKICAgICAgICAgICAgaWYgKGlucHV0ID09IG51bGwpIHsKICAgICAgICAgICAgICAgIHJldHVybiBudWxsOwogICAgICAgICAgICB9CgogICAgICAgICAgICByZXR1cm4gU1RSSVBfQ09MT1JfUEFUVEVSTi5tYXRjaGVyKGlucHV0KS5yZXBsYWNlQWxsKCIiKTsKICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIFRyYW5zbGF0ZXMgYSBzdHJpbmcgdXNpbmcgYW4gYWx0ZXJuYXRlIGNvbG9yIGNvZGUgY2hhcmFjdGVyIGludG8gYQogICAgICAgICAqIHN0cmluZyB0aGF0IHVzZXMgdGhlIGludGVybmFsIENoYXRDb2xvci5DT0xPUl9DT0RFIGNvbG9yIGNvZGUKICAgICAgICAgKiBjaGFyYWN0ZXIuIFRoZSBhbHRlcm5hdGUgY29sb3IgY29kZSBjaGFyYWN0ZXIgd2lsbCBvbmx5IGJlIHJlcGxhY2VkIGlmCiAgICAgICAgICogaXQgaXMgaW1tZWRpYXRlbHkgZm9sbG93ZWQgYnkgMC05LCBBLUYsIGEtZiwgSy1PLCBrLW8sIFIgb3Igci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBhbHRDb2xvckNoYXIgVGhlIGFsdGVybmF0ZSBjb2xvciBjb2RlIGNoYXJhY3RlciB0byByZXBsYWNlLiBFeDogJgogICAgICAgICAqIEBwYXJhbSB0ZXh0VG9UcmFuc2xhdGUgVGV4dCBjb250YWluaW5nIHRoZSBhbHRlcm5hdGUgY29sb3IgY29kZSBjaGFyYWN0ZXIuCiAgICAgICAgICogQHJldHVybiBUZXh0IGNvbnRhaW5pbmcgdGhlIENoYXRDb2xvci5DT0xPUl9DT0RFIGNvbG9yIGNvZGUgY2hhcmFjdGVyLgogICAgICAgICAqLwogICAgICAgIHB1YmxpYyBzdGF0aWMgU3RyaW5nIHRyYW5zbGF0ZUFsdGVybmF0ZUNvbG9yQ29kZXMoY2hhciBhbHRDb2xvckNoYXIsIFN0cmluZyB0ZXh0VG9UcmFuc2xhdGUpIHsKICAgICAgICAgICAgY2hhcltdIGIgPSB0ZXh0VG9UcmFuc2xhdGUudG9DaGFyQXJyYXkoKTsKICAgICAgICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCBiLmxlbmd0aCAtIDE7IGkrKykgewogICAgICAgICAgICAgICAgaWYgKGJbaV0gPT0gYWx0Q29sb3JDaGFyICYmICIwMTIzNDU2Nzg5QWFCYkNjRGRFZUZmS2tMbE1tTm5Pb1JyIi5pbmRleE9mKGJbaSsxXSkgPiAtMSkgewogICAgICAgICAgICAgICAgICAgIGJbaV0gPSBDaGF0Q29sb3IuQ09MT1JfQ0hBUjsKICAgICAgICAgICAgICAgICAgICBiW2krMV0gPSBDaGFyYWN0ZXIudG9Mb3dlckNhc2UoYltpKzFdKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gbmV3IFN0cmluZyhiKTsKICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIENoYXRDb2xvcnMgdXNlZCBhdCB0aGUgZW5kIG9mIHRoZSBnaXZlbiBpbnB1dCBzdHJpbmcuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gaW5wdXQgSW5wdXQgc3RyaW5nIHRvIHJldHJpZXZlIHRoZSBjb2xvcnMgZnJvbS4KICAgICAgICAgKiBAcmV0dXJuIEFueSByZW1haW5pbmcgQ2hhdENvbG9ycyB0byBwYXNzIG9udG8gdGhlIG5leHQgbGluZS4KICAgICAgICAgKi8KICAgICAgICBwdWJsaWMgc3RhdGljIFN0cmluZyBnZXRMYXN0Q29sb3JzKFN0cmluZyBpbnB1dCkgewogICAgICAgICAgICBTdHJpbmcgcmVzdWx0ID0gIiI7CiAgICAgICAgICAgIGludCBsZW5ndGggPSBpbnB1dC5sZW5ndGgoKTsKCiAgICAgICAgICAgIC8vIFNlYXJjaCBiYWNrd2FyZHMgZnJvbSB0aGUgZW5kIGFzIGl0IGlzIGZhc3RlcgogICAgICAgICAgICBmb3IgKGludCBpbmRleCA9IGxlbmd0aCAtIDE7IGluZGV4ID4gLTE7IGluZGV4LS0pIHsKICAgICAgICAgICAgICAgIGNoYXIgc2VjdGlvbiA9IGlucHV0LmNoYXJBdChpbmRleCk7CiAgICAgICAgICAgICAgICBpZiAoc2VjdGlvbiA9PSBDT0xPUl9DSEFSICYmIGluZGV4IDwgbGVuZ3RoIC0gMSkgewogICAgICAgICAgICAgICAgICAgIGNoYXIgYyA9IGlucHV0LmNoYXJBdChpbmRleCArIDEpOwogICAgICAgICAgICAgICAgICAgIENoYXRDb2xvciBjb2xvciA9IGdldEJ5Q2hhcihjKTsKCiAgICAgICAgICAgICAgICAgICAgaWYgKGNvbG9yICE9IG51bGwpIHsKICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0gY29sb3IudG9TdHJpbmcoKSArIHJlc3VsdDsKCiAgICAgICAgICAgICAgICAgICAgICAgIC8vIE9uY2Ugd2UgZmluZCBhIGNvbG9yIG9yIHJlc2V0IHdlIGNhbiBzdG9wIHNlYXJjaGluZwogICAgICAgICAgICAgICAgICAgICAgICBpZiAoY29sb3IuaXNDb2xvcigpIHx8IGNvbG9yLmVxdWFscyhSRVNFVCkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CgogICAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KCiAgICAgICAgc3RhdGljIHsKICAgICAgICAgICAgZm9yIChDaGF0Q29sb3IgY29sb3IgOiB2YWx1ZXMoKSkgewogICAgICAgICAgICAgICAgQllfSUQucHV0KGNvbG9yLmludENvZGUsIGNvbG9yKTsKICAgICAgICAgICAgICAgIEJZX0NIQVIucHV0KGNvbG9yLmNvZGUsIGNvbG9yKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBwdWJsaWMgc3RhdGljIFN0cmluZyBmb3JtYXRTdHJpbmcoU3RyaW5nIGlucHV0LCBDaGF0Q29sb3IuLi4gZm9ybWF0cykgewogICAgICAgIFN0cmluZyByZXN1bHQgPSBpbnB1dDsKCiAgICAgICAgU3RyaW5nQnVpbGRlciBzYiA9IG5ldyBTdHJpbmdCdWlsZGVyKCk7CiAgICAgICAgZm9yIChDaGF0Q29sb3IgY2MgOiBmb3JtYXRzKSBzYi5hcHBlbmQoY2MpOwogICAgICAgIFN0cmluZyBmb3JtYXRTdHJpbmcgPSBzYi50b1N0cmluZygpOwoKICAgICAgICBNYXRjaGVyIG1hdGNoZXIgPSBTVFJJUF9DT0xPUl9QQVRURVJOLm1hdGNoZXIocmVzdWx0KTsKCiAgICAgICAgd2hpbGUgKG1hdGNoZXIuZmluZCgpKSB7CiAgICAgICAgICAgIC8vIFJlcGxhY2UgYWxsIGNoYXQgY29sb3JzIHdpdGggdGhlIGNoYXQgY29sb3IsIGZvbGxvd2VkIGJ5IHRoZSBmb3JtYXQuCiAgICAgICAgICAgIC8vIENhbiBvcHRpb25hbGx5IGFkZCBhIENoYXRDb2xvciNpc0NvbG9yKCkgY2hlY2sgaGVyZS4KICAgICAgICAgICAgcmVzdWx0ID0gcmVzdWx0LnJlcGxhY2UobWF0Y2hlci5ncm91cCgpLCBtYXRjaGVyLmdyb3VwKCkgKyBmb3JtYXRTdHJpbmcpOwogICAgICAgIH0KICAgICAgICByZXN1bHQgKz0gQ2hhdENvbG9yLlJFU0VUOwoKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgfQoKICAgIHB1YmxpYyBzdGF0aWMgU3RyaW5nIGZvcm1hdChTdHJpbmcgbmFtZSwgQ2hhdENvbG9yLi4uZm9ybWF0cykKICAgIHsKICAgIC8vIFJlbW92ZSBhbnkgaW5pdGlhbCBzZWN0aW9uIHNpZ24sIHRvIGF2b2lkIGVtcHR5IFN0cmluZ3MgYmVmb3JlaGFuZAogICAgICAgIFN0cmluZ0J1aWxkZXIgc2IgPSBuZXcgU3RyaW5nQnVpbGRlcigpOwogICAgICAgIGZvciAoQ2hhdENvbG9yIGNjIDogZm9ybWF0cykKICAgICAgICAgICAgc2IuYXBwZW5kKGNjKTsKICAgICAgICBTdHJpbmcgZm9ybWF0ID0gc2IudG9TdHJpbmcoKTsKCiAgICAgICAgYm9vbGVhbiBzdGFydHNXaXRoID0gbmFtZS5zdGFydHNXaXRoKFN0cmluZy52YWx1ZU9mKENoYXRDb2xvci5DT0xPUl9DSEFSKSk7CiAgICAgICAgaWYgKHN0YXJ0c1dpdGgpCiAgICAgICAgbmFtZSA9IG5hbWUuc3Vic3RyaW5nKDEpOwoKICAgICAgICBpbnQgaW5kZXggPSAwOwogICAgICAgIC8vIEdldCBsZW5ndGgKICAgICAgICBpbnQgbGVuID0gMDsKICAgICAgICB3aGlsZSAoKGluZGV4ID0gbmFtZS5pbmRleE9mKENoYXRDb2xvci5DT0xPUl9DSEFSLCBpbmRleCArIDEpKSA+PSAwKQogICAgICAgIGxlbisrOwogICAgICAgIC8vIHJlc2V0dGluZyBpbmRleAogICAgICAgIGluZGV4ID0gMDsKICAgICAgICBTdHJpbmdbXSBwYXJ0cyA9IG5ldyBTdHJpbmdbbGVuICsgMV07CiAgICAgICAgLy8gRm9yIGVhY2ggY29sb3VyIGNoYXIgKHNlY3Rpb24gc2lnbikgaW4gdGhlIFN0cmluZwogICAgICAgIGZvciAoaW50IGkgPSAwOyAoaW5kZXggPSBuYW1lLmluZGV4T2YoQ2hhdENvbG9yLkNPTE9SX0NIQVIsIGluZGV4ICsgMSkpID49IDA7IGkrKykKICAgICAgICB7CiAgICAgICAgICAgIC8vIEkgd2FzIGxhenksIGRvbid0IGZvcmdldCB0aGUgbnVsbCBjaGVjayEhISEhCiAgICAgICAgICAgIGlmIChDaGF0Q29sb3IuZ2V0QnlDaGFyKG5hbWUuc3Vic3RyaW5nKGluZGV4ICsgMSwgaW5kZXggKyAyKSkuaXNGb3JtYXQoKSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgLy8gU2tpcCBmb3JtYXRzCiAgICAgICAgICAgICAgICBpLS07IC8vIFVuZG8gaW5jcmVtZW50CiAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgfQogICAgICAgICAgICAvLyBBc3NpZ24gdGhlIHBhcnQgdXAgdG8gdGhlIHNlY3Rpb24gc2lnbiwgYW5kIHByZXBlbmQgYSB0aGUgc2VjdGlvbiBzaWduCiAgICAgICAgICAgIHBhcnRzW2ldID0gQ2hhdENvbG9yLkNPTE9SX0NIQVIgKyBuYW1lLnN1YnN0cmluZygwLCBpbmRleCk7CiAgICAgICAgICAgIC8vIFJlbW92ZSB0aGUgcGFydCBiZWZvcmVoYW5kCiAgICAgICAgICAgIG5hbWUgPSBuYW1lLnN1YnN0cmluZyhpbmRleCk7CiAgICAgICAgfQogICAgICAgIHBhcnRzW3BhcnRzLmxlbmd0aCAtIDFdID0gbmFtZTsgLy8gTGVmdG92ZXJzCgogICAgICAgIC8vIE5vdyBqb2luCiAgICAgICAgYm9vbGVhbiBmaXJzdCA9IHRydWU7CiAgICAgICAgU3RyaW5nQnVpbGRlciBqb2luZWQgPSBuZXcgU3RyaW5nQnVpbGRlcihzdGFydHNXaXRoID8gU3RyaW5nLnZhbHVlT2YoQ2hhdENvbG9yLkNPTE9SX0NIQVIpIDogIiIpOwogICAgICAgIGZvciAoU3RyaW5nIHBhcnQgOiBwYXJ0cykKICAgICAgICB7CiAgICAgICAgICAgIC8vIFN0YXJ0IHdpdGggdGhlIGZvcm1hdAogICAgICAgICAgICBqb2luZWQuYXBwZW5kKGZvcm1hdCk7CiAgICAgICAgICAgIC8vIElmIGl0IHdhcyB0aGUgZmlyc3QsIG9ubHkgYWRkIHRoZSBjb2xvdXIgY2hhciBpZiBpdCBwcmV2aW91c2x5IGhhZCBhbnkKICAgICAgICAgICAgaWYgKGZpcnN0KQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBmaXJzdCA9IGZhbHNlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsc2UgLy8gdGhleSB3ZXJlIHNwbGl0IGJhc2VkIG9uIGNvbG91ciBjaGFyLCBzbyBhbHdheXMgYWRkIG9uZSBiZXR3ZWVuCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIGpvaW5lZC5hcHBlbmQoQ2hhdENvbG9yLkNPTE9SX0NIQVIpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGpvaW5lZC5hcHBlbmQocGFydCk7CiAgICAgICAgfQogICAgICAgIHJldHVybiBqb2luZWQudG9TdHJpbmcoKTsKICAgIH0KCiAgICBwdWJsaWMgc3RhdGljIHZvaWQgbWFpbihTdHJpbmdbXSBhcmdzKQogICAgewogICAgICAgIFN0cmluZyBuYW1lID0gQ2hhdENvbG9yLlJFRCArICJEcmFnb24iICsgQ2hhdENvbG9yLkJMVUUgKyAicGhhc2UiOwogICAgICAgIENoYXRDb2xvcltdIGZvcm1hdHMgPSBuZXcgQ2hhdENvbG9yW117Q2hhdENvbG9yLkJPTEQsIENoYXRDb2xvci5VTkRFUkxJTkV9OwogICAgICAgIGxvbmcgc3RhcnQgPSBTeXN0ZW0ubmFub1RpbWUoKTsKICAgICAgICBmb3IgKGludCBpID0gMDsgaSA8IDEwMDAwMDA7IGkrKykKICAgICAgICB7CiAgICAgICAgICAgIC8vZm9ybWF0U3RyaW5nKG5hbWUsIGZvcm1hdHMpOwogICAgICAgICAgICBmb3JtYXQobmFtZSwgZm9ybWF0cyk7CiAgICAgICAgfQogICAgICAgIGxvbmcgZW5kID0gU3lzdGVtLm5hbm9UaW1lKCk7CiAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKCJBdmVyYWdlIHBlciBjYWxsOiAiKygoZW5kIC0gc3RhcnQpIC8gMTAwMDAwMCkgKyAibnMiKTsKICAgIH0KfQ==