/* 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"); }
}
LyogcGFja2FnZSB3aGF0ZXZlcjsgLy8gZG9uJ3QgcGxhY2UgcGFja2FnZSBuYW1lISAqLwoKaW1wb3J0IGphdmEudXRpbC4qOwppbXBvcnQgamF2YS5sYW5nLio7CmltcG9ydCBqYXZhLmlvLio7CmltcG9ydCBqYXZhLnV0aWwuSGFzaE1hcDsKaW1wb3J0IGphdmEudXRpbC5NYXA7CmltcG9ydCBqYXZhLnV0aWwucmVnZXguTWF0Y2hlcjsKaW1wb3J0IGphdmEudXRpbC5yZWdleC5QYXR0ZXJuOwoKLyogTmFtZSBvZiB0aGUgY2xhc3MgaGFzIHRvIGJlICJNYWluIiBvbmx5IGlmIHRoZSBjbGFzcyBpcyBwdWJsaWMuICovCmNsYXNzIElkZW9uZQp7Cglwcml2YXRlIHN0YXRpYyBmaW5hbCBQYXR0ZXJuIFNUUklQX0NPTE9SX1BBVFRFUk4gPSBQYXR0ZXJuLmNvbXBpbGUoIig/aSkiICsgU3RyaW5nLnZhbHVlT2YoJ8KnJykgKyAiWzAtOUEtRkstT1JdIik7CgogICAgcHJpdmF0ZSBlbnVtIENoYXRDb2xvcgogICAgewogICAgICAgIC8qKgogICAgICAgICAqIFJlcHJlc2VudHMgYmxhY2sKICAgICAgICAgKi8KICAgICAgICBCTEFDSygnMCcsIDB4MDApLAogICAgICAgIC8qKgogICAgICAgICAqIFJlcHJlc2VudHMgZGFyayBibHVlCiAgICAgICAgICovCiAgICAgICAgREFSS19CTFVFKCcxJywgMHgxKSwKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIGRhcmsgZ3JlZW4KICAgICAgICAgKi8KICAgICAgICBEQVJLX0dSRUVOKCcyJywgMHgyKSwKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIGRhcmsgYmx1ZSAoYXF1YSkKICAgICAgICAgKi8KICAgICAgICBEQVJLX0FRVUEoJzMnLCAweDMpLAogICAgICAgIC8qKgogICAgICAgICAqIFJlcHJlc2VudHMgZGFyayByZWQKICAgICAgICAgKi8KICAgICAgICBEQVJLX1JFRCgnNCcsIDB4NCksCiAgICAgICAgLyoqCiAgICAgICAgICogUmVwcmVzZW50cyBkYXJrIHB1cnBsZQogICAgICAgICAqLwogICAgICAgIERBUktfUFVSUExFKCc1JywgMHg1KSwKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIGdvbGQKICAgICAgICAgKi8KICAgICAgICBHT0xEKCc2JywgMHg2KSwKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIGdyYXkKICAgICAgICAgKi8KICAgICAgICBHUkFZKCc3JywgMHg3KSwKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIGRhcmsgZ3JheQogICAgICAgICAqLwogICAgICAgIERBUktfR1JBWSgnOCcsIDB4OCksCiAgICAgICAgLyoqCiAgICAgICAgICogUmVwcmVzZW50cyBibHVlCiAgICAgICAgICovCiAgICAgICAgQkxVRSgnOScsIDB4OSksCiAgICAgICAgLyoqCiAgICAgICAgICogUmVwcmVzZW50cyBncmVlbgogICAgICAgICAqLwogICAgICAgIEdSRUVOKCdhJywgMHhBKSwKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIGFxdWEKICAgICAgICAgKi8KICAgICAgICBBUVVBKCdiJywgMHhCKSwKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIHJlZAogICAgICAgICAqLwogICAgICAgIFJFRCgnYycsIDB4QyksCiAgICAgICAgLyoqCiAgICAgICAgICogUmVwcmVzZW50cyBsaWdodCBwdXJwbGUKICAgICAgICAgKi8KICAgICAgICBMSUdIVF9QVVJQTEUoJ2QnLCAweEQpLAogICAgICAgIC8qKgogICAgICAgICAqIFJlcHJlc2VudHMgeWVsbG93CiAgICAgICAgICovCiAgICAgICAgWUVMTE9XKCdlJywgMHhFKSwKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIHdoaXRlCiAgICAgICAgICovCiAgICAgICAgV0hJVEUoJ2YnLCAweEYpLAogICAgICAgIC8qKgogICAgICAgICAqIFJlcHJlc2VudHMgbWFnaWNhbCBjaGFyYWN0ZXJzIHRoYXQgY2hhbmdlIGFyb3VuZCByYW5kb21seQogICAgICAgICAqLwogICAgICAgIE1BR0lDKCdrJywgMHgxMCwgdHJ1ZSksCiAgICAgICAgLyoqCiAgICAgICAgICogTWFrZXMgdGhlIHRleHQgYm9sZC4KICAgICAgICAgKi8KICAgICAgICBCT0xEKCdsJywgMHgxMSwgdHJ1ZSksCiAgICAgICAgLyoqCiAgICAgICAgICogTWFrZXMgYSBsaW5lIGFwcGVhciB0aHJvdWdoIHRoZSB0ZXh0LgogICAgICAgICAqLwogICAgICAgIFNUUklLRVRIUk9VR0goJ20nLCAweDEyLCB0cnVlKSwKICAgICAgICAvKioKICAgICAgICAgKiBNYWtlcyB0aGUgdGV4dCBhcHBlYXIgdW5kZXJsaW5lZC4KICAgICAgICAgKi8KICAgICAgICBVTkRFUkxJTkUoJ24nLCAweDEzLCB0cnVlKSwKICAgICAgICAvKioKICAgICAgICAgKiBNYWtlcyB0aGUgdGV4dCBpdGFsaWMuCiAgICAgICAgICovCiAgICAgICAgSVRBTElDKCdvJywgMHgxNCwgdHJ1ZSksCiAgICAgICAgLyoqCiAgICAgICAgICogUmVzZXRzIGFsbCBwcmV2aW91cyBjaGF0IGNvbG9ycyBvciBmb3JtYXRzLgogICAgICAgICAqLwogICAgICAgIFJFU0VUKCdyJywgMHgxNSk7CgogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBzcGVjaWFsIGNoYXJhY3RlciB3aGljaCBwcmVmaXhlcyBhbGwgY2hhdCBjb2xvdXIgY29kZXMuIFVzZSB0aGlzIGlmCiAgICAgICAgICogeW91IG5lZWQgdG8gZHluYW1pY2FsbHkgY29udmVydCBjb2xvdXIgY29kZXMgZnJvbSB5b3VyIGN1c3RvbSBmb3JtYXQuCiAgICAgICAgICovCiAgICAgICAgcHVibGljIHN0YXRpYyBmaW5hbCBjaGFyIENPTE9SX0NIQVIgPSAnXHUwMEE3JzsKICAgICAgICBwcml2YXRlIHN0YXRpYyBmaW5hbCBQYXR0ZXJuIFNUUklQX0NPTE9SX1BBVFRFUk4gPSBQYXR0ZXJuLmNvbXBpbGUoIig/aSkiICsgU3RyaW5nLnZhbHVlT2YoQ09MT1JfQ0hBUikgKyAiWzAtOUEtRkstT1JdIik7CgogICAgICAgIHByaXZhdGUgZmluYWwgaW50IGludENvZGU7CiAgICAgICAgcHJpdmF0ZSBmaW5hbCBjaGFyIGNvZGU7CiAgICAgICAgcHJpdmF0ZSBmaW5hbCBib29sZWFuIGlzRm9ybWF0OwogICAgICAgIHByaXZhdGUgZmluYWwgU3RyaW5nIHRvU3RyaW5nOwogICAgICAgIHByaXZhdGUgZmluYWwgc3RhdGljIE1hcDxJbnRlZ2VyLCBDaGF0Q29sb3I+IEJZX0lEID0gbmV3IEhhc2hNYXA8PigpOwogICAgICAgIHByaXZhdGUgZmluYWwgc3RhdGljIE1hcDxDaGFyYWN0ZXIsIENoYXRDb2xvcj4gQllfQ0hBUiA9IG5ldyBIYXNoTWFwPD4oKTsKCiAgICAgICAgcHJpdmF0ZSBDaGF0Q29sb3IoY2hhciBjb2RlLCBpbnQgaW50Q29kZSkgewogICAgICAgICAgICB0aGlzKGNvZGUsIGludENvZGUsIGZhbHNlKTsKICAgICAgICB9CgogICAgICAgIHByaXZhdGUgQ2hhdENvbG9yKGNoYXIgY29kZSwgaW50IGludENvZGUsIGJvb2xlYW4gaXNGb3JtYXQpIHsKICAgICAgICAgICAgdGhpcy5jb2RlID0gY29kZTsKICAgICAgICAgICAgdGhpcy5pbnRDb2RlID0gaW50Q29kZTsKICAgICAgICAgICAgdGhpcy5pc0Zvcm1hdCA9IGlzRm9ybWF0OwogICAgICAgICAgICB0aGlzLnRvU3RyaW5nID0gbmV3IFN0cmluZyhuZXcgY2hhcltdIHtDT0xPUl9DSEFSLCBjb2RlfSk7CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIHRoZSBjaGFyIHZhbHVlIGFzc29jaWF0ZWQgd2l0aCB0aGlzIGNvbG9yCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIEEgY2hhciB2YWx1ZSBvZiB0aGlzIGNvbG9yIGNvZGUKICAgICAgICAgKi8KICAgICAgICBwdWJsaWMgY2hhciBnZXRDaGFyKCkgewogICAgICAgICAgICByZXR1cm4gY29kZTsKICAgICAgICB9CgogICAgICAgIEBPdmVycmlkZQogICAgICAgIHB1YmxpYyBTdHJpbmcgdG9TdHJpbmcoKSB7CiAgICAgICAgICAgIHJldHVybiB0b1N0cmluZzsKICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIENoZWNrcyBpZiB0aGlzIGNvZGUgaXMgYSBmb3JtYXQgY29kZSBhcyBvcHBvc2VkIHRvIGEgY29sb3IgY29kZS4KICAgICAgICAgKi8KICAgICAgICBwdWJsaWMgYm9vbGVhbiBpc0Zvcm1hdCgpIHsKICAgICAgICAgICAgcmV0dXJuIGlzRm9ybWF0OwogICAgICAgIH0KCiAgICAgICAgLyoqCiAgICAgICAgICogQ2hlY2tzIGlmIHRoaXMgY29kZSBpcyBhIGNvbG9yIGNvZGUgYXMgb3Bwb3NlZCB0byBhIGZvcm1hdCBjb2RlLgogICAgICAgICAqLwogICAgICAgIHB1YmxpYyBib29sZWFuIGlzQ29sb3IoKSB7CiAgICAgICAgICAgIHJldHVybiAhaXNGb3JtYXQgJiYgdGhpcyAhPSBSRVNFVDsKICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIGNvbG9yIHJlcHJlc2VudGVkIGJ5IHRoZSBzcGVjaWZpZWQgY29sb3IgY29kZQogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGNvZGUgQ29kZSB0byBjaGVjawogICAgICAgICAqIEByZXR1cm4gQXNzb2NpYXRpdmUge0BsaW5rIG9yZy5idWtraXQuQ2hhdENvbG9yfSB3aXRoIHRoZSBnaXZlbiBjb2RlLAogICAgICAgICAqICAgICBvciBudWxsIGlmIGl0IGRvZXNuJ3QgZXhpc3QKICAgICAgICAgKi8KICAgICAgICBwdWJsaWMgc3RhdGljIENoYXRDb2xvciBnZXRCeUNoYXIoY2hhciBjb2RlKSB7CiAgICAgICAgICAgIHJldHVybiBCWV9DSEFSLmdldChjb2RlKTsKICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIGNvbG9yIHJlcHJlc2VudGVkIGJ5IHRoZSBzcGVjaWZpZWQgY29sb3IgY29kZQogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGNvZGUgQ29kZSB0byBjaGVjawogICAgICAgICAqIEByZXR1cm4gQXNzb2NpYXRpdmUge0BsaW5rIG9yZy5idWtraXQuQ2hhdENvbG9yfSB3aXRoIHRoZSBnaXZlbiBjb2RlLAogICAgICAgICAqICAgICBvciBudWxsIGlmIGl0IGRvZXNuJ3QgZXhpc3QKICAgICAgICAgKi8KICAgICAgICBwdWJsaWMgc3RhdGljIENoYXRDb2xvciBnZXRCeUNoYXIoU3RyaW5nIGNvZGUpIHsKICAgICAgICAgICAgcmV0dXJuIEJZX0NIQVIuZ2V0KGNvZGUuY2hhckF0KDApKTsKICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIFN0cmlwcyB0aGUgZ2l2ZW4gbWVzc2FnZSBvZiBhbGwgY29sb3IgY29kZXMKICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBpbnB1dCBTdHJpbmcgdG8gc3RyaXAgb2YgY29sb3IKICAgICAgICAgKiBAcmV0dXJuIEEgY29weSBvZiB0aGUgaW5wdXQgc3RyaW5nLCB3aXRob3V0IGFueSBjb2xvcmluZwogICAgICAgICAqLwogICAgICAgIHB1YmxpYyBzdGF0aWMgU3RyaW5nIHN0cmlwQ29sb3IoZmluYWwgU3RyaW5nIGlucHV0KSB7CiAgICAgICAgICAgIGlmIChpbnB1dCA9PSBudWxsKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgcmV0dXJuIFNUUklQX0NPTE9SX1BBVFRFUk4ubWF0Y2hlcihpbnB1dCkucmVwbGFjZUFsbCgiIik7CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBUcmFuc2xhdGVzIGEgc3RyaW5nIHVzaW5nIGFuIGFsdGVybmF0ZSBjb2xvciBjb2RlIGNoYXJhY3RlciBpbnRvIGEKICAgICAgICAgKiBzdHJpbmcgdGhhdCB1c2VzIHRoZSBpbnRlcm5hbCBDaGF0Q29sb3IuQ09MT1JfQ09ERSBjb2xvciBjb2RlCiAgICAgICAgICogY2hhcmFjdGVyLiBUaGUgYWx0ZXJuYXRlIGNvbG9yIGNvZGUgY2hhcmFjdGVyIHdpbGwgb25seSBiZSByZXBsYWNlZCBpZgogICAgICAgICAqIGl0IGlzIGltbWVkaWF0ZWx5IGZvbGxvd2VkIGJ5IDAtOSwgQS1GLCBhLWYsIEstTywgay1vLCBSIG9yIHIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gYWx0Q29sb3JDaGFyIFRoZSBhbHRlcm5hdGUgY29sb3IgY29kZSBjaGFyYWN0ZXIgdG8gcmVwbGFjZS4gRXg6ICYKICAgICAgICAgKiBAcGFyYW0gdGV4dFRvVHJhbnNsYXRlIFRleHQgY29udGFpbmluZyB0aGUgYWx0ZXJuYXRlIGNvbG9yIGNvZGUgY2hhcmFjdGVyLgogICAgICAgICAqIEByZXR1cm4gVGV4dCBjb250YWluaW5nIHRoZSBDaGF0Q29sb3IuQ09MT1JfQ09ERSBjb2xvciBjb2RlIGNoYXJhY3Rlci4KICAgICAgICAgKi8KICAgICAgICBwdWJsaWMgc3RhdGljIFN0cmluZyB0cmFuc2xhdGVBbHRlcm5hdGVDb2xvckNvZGVzKGNoYXIgYWx0Q29sb3JDaGFyLCBTdHJpbmcgdGV4dFRvVHJhbnNsYXRlKSB7CiAgICAgICAgICAgIGNoYXJbXSBiID0gdGV4dFRvVHJhbnNsYXRlLnRvQ2hhckFycmF5KCk7CiAgICAgICAgICAgIGZvciAoaW50IGkgPSAwOyBpIDwgYi5sZW5ndGggLSAxOyBpKyspIHsKICAgICAgICAgICAgICAgIGlmIChiW2ldID09IGFsdENvbG9yQ2hhciAmJiAiMDEyMzQ1Njc4OUFhQmJDY0RkRWVGZktrTGxNbU5uT29SciIuaW5kZXhPZihiW2krMV0pID4gLTEpIHsKICAgICAgICAgICAgICAgICAgICBiW2ldID0gQ2hhdENvbG9yLkNPTE9SX0NIQVI7CiAgICAgICAgICAgICAgICAgICAgYltpKzFdID0gQ2hhcmFjdGVyLnRvTG93ZXJDYXNlKGJbaSsxXSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIG5ldyBTdHJpbmcoYik7CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIHRoZSBDaGF0Q29sb3JzIHVzZWQgYXQgdGhlIGVuZCBvZiB0aGUgZ2l2ZW4gaW5wdXQgc3RyaW5nLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGlucHV0IElucHV0IHN0cmluZyB0byByZXRyaWV2ZSB0aGUgY29sb3JzIGZyb20uCiAgICAgICAgICogQHJldHVybiBBbnkgcmVtYWluaW5nIENoYXRDb2xvcnMgdG8gcGFzcyBvbnRvIHRoZSBuZXh0IGxpbmUuCiAgICAgICAgICovCiAgICAgICAgcHVibGljIHN0YXRpYyBTdHJpbmcgZ2V0TGFzdENvbG9ycyhTdHJpbmcgaW5wdXQpIHsKICAgICAgICAgICAgU3RyaW5nIHJlc3VsdCA9ICIiOwogICAgICAgICAgICBpbnQgbGVuZ3RoID0gaW5wdXQubGVuZ3RoKCk7CgogICAgICAgICAgICAvLyBTZWFyY2ggYmFja3dhcmRzIGZyb20gdGhlIGVuZCBhcyBpdCBpcyBmYXN0ZXIKICAgICAgICAgICAgZm9yIChpbnQgaW5kZXggPSBsZW5ndGggLSAxOyBpbmRleCA+IC0xOyBpbmRleC0tKSB7CiAgICAgICAgICAgICAgICBjaGFyIHNlY3Rpb24gPSBpbnB1dC5jaGFyQXQoaW5kZXgpOwogICAgICAgICAgICAgICAgaWYgKHNlY3Rpb24gPT0gQ09MT1JfQ0hBUiAmJiBpbmRleCA8IGxlbmd0aCAtIDEpIHsKICAgICAgICAgICAgICAgICAgICBjaGFyIGMgPSBpbnB1dC5jaGFyQXQoaW5kZXggKyAxKTsKICAgICAgICAgICAgICAgICAgICBDaGF0Q29sb3IgY29sb3IgPSBnZXRCeUNoYXIoYyk7CgogICAgICAgICAgICAgICAgICAgIGlmIChjb2xvciAhPSBudWxsKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IGNvbG9yLnRvU3RyaW5nKCkgKyByZXN1bHQ7CgogICAgICAgICAgICAgICAgICAgICAgICAvLyBPbmNlIHdlIGZpbmQgYSBjb2xvciBvciByZXNldCB3ZSBjYW4gc3RvcCBzZWFyY2hpbmcKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNvbG9yLmlzQ29sb3IoKSB8fCBjb2xvci5lcXVhbHMoUkVTRVQpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CgogICAgICAgIHN0YXRpYyB7CiAgICAgICAgICAgIGZvciAoQ2hhdENvbG9yIGNvbG9yIDogdmFsdWVzKCkpIHsKICAgICAgICAgICAgICAgIEJZX0lELnB1dChjb2xvci5pbnRDb2RlLCBjb2xvcik7CiAgICAgICAgICAgICAgICBCWV9DSEFSLnB1dChjb2xvci5jb2RlLCBjb2xvcik7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CgogICAgcHVibGljIHN0YXRpYyBTdHJpbmcgZm9ybWF0U3RyaW5nKFN0cmluZyBpbnB1dCwgQ2hhdENvbG9yLi4uIGZvcm1hdHMpIHsKICAgICAgICBTdHJpbmcgcmVzdWx0ID0gaW5wdXQ7CgogICAgICAgIFN0cmluZ0J1aWxkZXIgc2IgPSBuZXcgU3RyaW5nQnVpbGRlcigpOwogICAgICAgIGZvciAoQ2hhdENvbG9yIGNjIDogZm9ybWF0cykgc2IuYXBwZW5kKGNjKTsKICAgICAgICBTdHJpbmcgZm9ybWF0U3RyaW5nID0gc2IudG9TdHJpbmcoKTsKCiAgICAgICAgTWF0Y2hlciBtYXRjaGVyID0gU1RSSVBfQ09MT1JfUEFUVEVSTi5tYXRjaGVyKHJlc3VsdCk7CgogICAgICAgIHdoaWxlIChtYXRjaGVyLmZpbmQoKSkgewogICAgICAgICAgICAvLyBSZXBsYWNlIGFsbCBjaGF0IGNvbG9ycyB3aXRoIHRoZSBjaGF0IGNvbG9yLCBmb2xsb3dlZCBieSB0aGUgZm9ybWF0LgogICAgICAgICAgICAvLyBDYW4gb3B0aW9uYWxseSBhZGQgYSBDaGF0Q29sb3IjaXNDb2xvcigpIGNoZWNrIGhlcmUuCiAgICAgICAgICAgIHJlc3VsdCA9IHJlc3VsdC5yZXBsYWNlKG1hdGNoZXIuZ3JvdXAoKSwgbWF0Y2hlci5ncm91cCgpICsgZm9ybWF0U3RyaW5nKTsKICAgICAgICB9CiAgICAgICAgcmVzdWx0ICs9IENoYXRDb2xvci5SRVNFVDsKCiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgIH0KCiAgICBwdWJsaWMgc3RhdGljIFN0cmluZyBmb3JtYXQoU3RyaW5nIG5hbWUsIENoYXRDb2xvci4uLmZvcm1hdHMpCiAgICB7CiAgICAvLyBSZW1vdmUgYW55IGluaXRpYWwgc2VjdGlvbiBzaWduLCB0byBhdm9pZCBlbXB0eSBTdHJpbmdzIGJlZm9yZWhhbmQKICAgICAgICBTdHJpbmdCdWlsZGVyIHNiID0gbmV3IFN0cmluZ0J1aWxkZXIoKTsKICAgICAgICBmb3IgKENoYXRDb2xvciBjYyA6IGZvcm1hdHMpCiAgICAgICAgICAgIHNiLmFwcGVuZChjYyk7CiAgICAgICAgU3RyaW5nIGZvcm1hdCA9IHNiLnRvU3RyaW5nKCk7CgogICAgICAgIGJvb2xlYW4gc3RhcnRzV2l0aCA9IG5hbWUuc3RhcnRzV2l0aChTdHJpbmcudmFsdWVPZihDaGF0Q29sb3IuQ09MT1JfQ0hBUikpOwogICAgICAgIGlmIChzdGFydHNXaXRoKQogICAgICAgIG5hbWUgPSBuYW1lLnN1YnN0cmluZygxKTsKCiAgICAgICAgaW50IGluZGV4ID0gMDsKICAgICAgICAvLyBHZXQgbGVuZ3RoCiAgICAgICAgaW50IGxlbiA9IDA7CiAgICAgICAgd2hpbGUgKChpbmRleCA9IG5hbWUuaW5kZXhPZihDaGF0Q29sb3IuQ09MT1JfQ0hBUiwgaW5kZXggKyAxKSkgPj0gMCkKICAgICAgICBsZW4rKzsKICAgICAgICAvLyByZXNldHRpbmcgaW5kZXgKICAgICAgICBpbmRleCA9IDA7CiAgICAgICAgU3RyaW5nW10gcGFydHMgPSBuZXcgU3RyaW5nW2xlbiArIDFdOwogICAgICAgIC8vIEZvciBlYWNoIGNvbG91ciBjaGFyIChzZWN0aW9uIHNpZ24pIGluIHRoZSBTdHJpbmcKICAgICAgICBmb3IgKGludCBpID0gMDsgKGluZGV4ID0gbmFtZS5pbmRleE9mKENoYXRDb2xvci5DT0xPUl9DSEFSLCBpbmRleCArIDEpKSA+PSAwOyBpKyspCiAgICAgICAgewogICAgICAgICAgICAvLyBJIHdhcyBsYXp5LCBkb24ndCBmb3JnZXQgdGhlIG51bGwgY2hlY2shISEhIQogICAgICAgICAgICBpZiAoQ2hhdENvbG9yLmdldEJ5Q2hhcihuYW1lLnN1YnN0cmluZyhpbmRleCArIDEsIGluZGV4ICsgMikpLmlzRm9ybWF0KCkpCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIC8vIFNraXAgZm9ybWF0cwogICAgICAgICAgICAgICAgaS0tOyAvLyBVbmRvIGluY3JlbWVudAogICAgICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gQXNzaWduIHRoZSBwYXJ0IHVwIHRvIHRoZSBzZWN0aW9uIHNpZ24sIGFuZCBwcmVwZW5kIGEgdGhlIHNlY3Rpb24gc2lnbgogICAgICAgICAgICBwYXJ0c1tpXSA9IENoYXRDb2xvci5DT0xPUl9DSEFSICsgbmFtZS5zdWJzdHJpbmcoMCwgaW5kZXgpOwogICAgICAgICAgICAvLyBSZW1vdmUgdGhlIHBhcnQgYmVmb3JlaGFuZAogICAgICAgICAgICBuYW1lID0gbmFtZS5zdWJzdHJpbmcoaW5kZXgpOwogICAgICAgIH0KICAgICAgICBwYXJ0c1twYXJ0cy5sZW5ndGggLSAxXSA9IG5hbWU7IC8vIExlZnRvdmVycwoKICAgICAgICAvLyBOb3cgam9pbgogICAgICAgIGJvb2xlYW4gZmlyc3QgPSB0cnVlOwogICAgICAgIFN0cmluZ0J1aWxkZXIgam9pbmVkID0gbmV3IFN0cmluZ0J1aWxkZXIoc3RhcnRzV2l0aCA/IFN0cmluZy52YWx1ZU9mKENoYXRDb2xvci5DT0xPUl9DSEFSKSA6ICIiKTsKICAgICAgICBmb3IgKFN0cmluZyBwYXJ0IDogcGFydHMpCiAgICAgICAgewogICAgICAgICAgICAvLyBTdGFydCB3aXRoIHRoZSBmb3JtYXQKICAgICAgICAgICAgam9pbmVkLmFwcGVuZChmb3JtYXQpOwogICAgICAgICAgICAvLyBJZiBpdCB3YXMgdGhlIGZpcnN0LCBvbmx5IGFkZCB0aGUgY29sb3VyIGNoYXIgaWYgaXQgcHJldmlvdXNseSBoYWQgYW55CiAgICAgICAgICAgIGlmIChmaXJzdCkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgZmlyc3QgPSBmYWxzZTsKICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIC8vIHRoZXkgd2VyZSBzcGxpdCBiYXNlZCBvbiBjb2xvdXIgY2hhciwgc28gYWx3YXlzIGFkZCBvbmUgYmV0d2VlbgogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBqb2luZWQuYXBwZW5kKENoYXRDb2xvci5DT0xPUl9DSEFSKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBqb2luZWQuYXBwZW5kKHBhcnQpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gam9pbmVkLnRvU3RyaW5nKCk7CiAgICB9CgogICAgcHVibGljIHN0YXRpYyB2b2lkIG1haW4oU3RyaW5nW10gYXJncykKICAgIHsKICAgICAgICBTdHJpbmcgbmFtZSA9IENoYXRDb2xvci5SRUQgKyAiRHJhZ29uIiArIENoYXRDb2xvci5CTFVFICsgInBoYXNlIjsKICAgICAgICBDaGF0Q29sb3JbXSBmb3JtYXRzID0gbmV3IENoYXRDb2xvcltde0NoYXRDb2xvci5CT0xELCBDaGF0Q29sb3IuVU5ERVJMSU5FfTsKICAgICAgICBsb25nIHN0YXJ0ID0gU3lzdGVtLm5hbm9UaW1lKCk7CiAgICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCAxMDAwMDAwOyBpKyspCiAgICAgICAgewogICAgICAgICAgICBmb3JtYXRTdHJpbmcobmFtZSwgZm9ybWF0cyk7CiAgICAgICAgICAgIC8vZm9ybWF0KG5hbWUsIGZvcm1hdHMpOwogICAgICAgIH0KICAgICAgICBsb25nIGVuZCA9IFN5c3RlbS5uYW5vVGltZSgpOwogICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigiQXZlcmFnZSBwZXIgY2FsbDogIisoKGVuZCAtIHN0YXJ0KSAvIDEwMDAwMDApICsgIm5zIik7CiAgICB9Cn0=