/* 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);
}
}
}
private interface Executor {
void execute();
}
public static void checkTime(int amount, Executor executor) {
long start
= System.
nanoTime();
for (int i = 0; i < amount; i++)
{
executor.execute();
}
System.
out.
println("Average per call: "+((end
- start
) / 1000000) + "ns"); }
public static String format1
(String input, ChatColor...
formats) {
StringBuilder result = new StringBuilder();
StringBuilder format = new StringBuilder();
for (ChatColor color : formats) format.append(color);
String formatString
= format.
toString();
for (int i = 0; i < input.length(); i ++) {
result.append(input.charAt(i));
if (input.charAt(i) == ChatColor.COLOR_CHAR) {
if (i + 1 < input.length()) {
ChatColor color = ChatColor.getByChar(input.charAt(++i));
if (color != null) {
result.append(color.getChar());
result.append(formatString);
}
}
}
}
result.append(ChatColor.RESET);
return result.toString();
}
public static String format2
(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};
System.
out.
println("Format1: " + format1
(name, formats
)); System.
out.
println("Format2: " + format2
(name, formats
));
checkTime(1000000, new Executor() {
public void execute() {
format1(name, formats);
}
});
checkTime(1000000, new Executor() {
public void execute() {
format2(name, formats);
}
});
}
}
LyogcGFja2FnZSB3aGF0ZXZlcjsgLy8gZG9uJ3QgcGxhY2UgcGFja2FnZSBuYW1lISAqLwoKaW1wb3J0IGphdmEudXRpbC4qOwppbXBvcnQgamF2YS5sYW5nLio7CmltcG9ydCBqYXZhLmlvLio7CmltcG9ydCBqYXZhLnV0aWwuSGFzaE1hcDsKaW1wb3J0IGphdmEudXRpbC5NYXA7CmltcG9ydCBqYXZhLnV0aWwucmVnZXguTWF0Y2hlcjsKaW1wb3J0IGphdmEudXRpbC5yZWdleC5QYXR0ZXJuOwoKLyogTmFtZSBvZiB0aGUgY2xhc3MgaGFzIHRvIGJlICJNYWluIiBvbmx5IGlmIHRoZSBjbGFzcyBpcyBwdWJsaWMuICovCmNsYXNzIElkZW9uZQp7Cglwcml2YXRlIHN0YXRpYyBmaW5hbCBQYXR0ZXJuIFNUUklQX0NPTE9SX1BBVFRFUk4gPSBQYXR0ZXJuLmNvbXBpbGUoIig/aSkiICsgU3RyaW5nLnZhbHVlT2YoJ8KnJykgKyAiWzAtOUEtRkstT1JdIik7CgogICAgcHJpdmF0ZSBlbnVtIENoYXRDb2xvcgogICAgewogICAgICAgIC8qKgogICAgICAgICAqIFJlcHJlc2VudHMgYmxhY2sKICAgICAgICAgKi8KICAgICAgICBCTEFDSygnMCcsIDB4MDApLAogICAgICAgIC8qKgogICAgICAgICAqIFJlcHJlc2VudHMgZGFyayBibHVlCiAgICAgICAgICovCiAgICAgICAgREFSS19CTFVFKCcxJywgMHgxKSwKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIGRhcmsgZ3JlZW4KICAgICAgICAgKi8KICAgICAgICBEQVJLX0dSRUVOKCcyJywgMHgyKSwKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIGRhcmsgYmx1ZSAoYXF1YSkKICAgICAgICAgKi8KICAgICAgICBEQVJLX0FRVUEoJzMnLCAweDMpLAogICAgICAgIC8qKgogICAgICAgICAqIFJlcHJlc2VudHMgZGFyayByZWQKICAgICAgICAgKi8KICAgICAgICBEQVJLX1JFRCgnNCcsIDB4NCksCiAgICAgICAgLyoqCiAgICAgICAgICogUmVwcmVzZW50cyBkYXJrIHB1cnBsZQogICAgICAgICAqLwogICAgICAgIERBUktfUFVSUExFKCc1JywgMHg1KSwKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIGdvbGQKICAgICAgICAgKi8KICAgICAgICBHT0xEKCc2JywgMHg2KSwKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIGdyYXkKICAgICAgICAgKi8KICAgICAgICBHUkFZKCc3JywgMHg3KSwKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIGRhcmsgZ3JheQogICAgICAgICAqLwogICAgICAgIERBUktfR1JBWSgnOCcsIDB4OCksCiAgICAgICAgLyoqCiAgICAgICAgICogUmVwcmVzZW50cyBibHVlCiAgICAgICAgICovCiAgICAgICAgQkxVRSgnOScsIDB4OSksCiAgICAgICAgLyoqCiAgICAgICAgICogUmVwcmVzZW50cyBncmVlbgogICAgICAgICAqLwogICAgICAgIEdSRUVOKCdhJywgMHhBKSwKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIGFxdWEKICAgICAgICAgKi8KICAgICAgICBBUVVBKCdiJywgMHhCKSwKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIHJlZAogICAgICAgICAqLwogICAgICAgIFJFRCgnYycsIDB4QyksCiAgICAgICAgLyoqCiAgICAgICAgICogUmVwcmVzZW50cyBsaWdodCBwdXJwbGUKICAgICAgICAgKi8KICAgICAgICBMSUdIVF9QVVJQTEUoJ2QnLCAweEQpLAogICAgICAgIC8qKgogICAgICAgICAqIFJlcHJlc2VudHMgeWVsbG93CiAgICAgICAgICovCiAgICAgICAgWUVMTE9XKCdlJywgMHhFKSwKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIHdoaXRlCiAgICAgICAgICovCiAgICAgICAgV0hJVEUoJ2YnLCAweEYpLAogICAgICAgIC8qKgogICAgICAgICAqIFJlcHJlc2VudHMgbWFnaWNhbCBjaGFyYWN0ZXJzIHRoYXQgY2hhbmdlIGFyb3VuZCByYW5kb21seQogICAgICAgICAqLwogICAgICAgIE1BR0lDKCdrJywgMHgxMCwgdHJ1ZSksCiAgICAgICAgLyoqCiAgICAgICAgICogTWFrZXMgdGhlIHRleHQgYm9sZC4KICAgICAgICAgKi8KICAgICAgICBCT0xEKCdsJywgMHgxMSwgdHJ1ZSksCiAgICAgICAgLyoqCiAgICAgICAgICogTWFrZXMgYSBsaW5lIGFwcGVhciB0aHJvdWdoIHRoZSB0ZXh0LgogICAgICAgICAqLwogICAgICAgIFNUUklLRVRIUk9VR0goJ20nLCAweDEyLCB0cnVlKSwKICAgICAgICAvKioKICAgICAgICAgKiBNYWtlcyB0aGUgdGV4dCBhcHBlYXIgdW5kZXJsaW5lZC4KICAgICAgICAgKi8KICAgICAgICBVTkRFUkxJTkUoJ24nLCAweDEzLCB0cnVlKSwKICAgICAgICAvKioKICAgICAgICAgKiBNYWtlcyB0aGUgdGV4dCBpdGFsaWMuCiAgICAgICAgICovCiAgICAgICAgSVRBTElDKCdvJywgMHgxNCwgdHJ1ZSksCiAgICAgICAgLyoqCiAgICAgICAgICogUmVzZXRzIGFsbCBwcmV2aW91cyBjaGF0IGNvbG9ycyBvciBmb3JtYXRzLgogICAgICAgICAqLwogICAgICAgIFJFU0VUKCdyJywgMHgxNSk7CgogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBzcGVjaWFsIGNoYXJhY3RlciB3aGljaCBwcmVmaXhlcyBhbGwgY2hhdCBjb2xvdXIgY29kZXMuIFVzZSB0aGlzIGlmCiAgICAgICAgICogeW91IG5lZWQgdG8gZHluYW1pY2FsbHkgY29udmVydCBjb2xvdXIgY29kZXMgZnJvbSB5b3VyIGN1c3RvbSBmb3JtYXQuCiAgICAgICAgICovCiAgICAgICAgcHVibGljIHN0YXRpYyBmaW5hbCBjaGFyIENPTE9SX0NIQVIgPSAnXHUwMEE3JzsKICAgICAgICBwcml2YXRlIHN0YXRpYyBmaW5hbCBQYXR0ZXJuIFNUUklQX0NPTE9SX1BBVFRFUk4gPSBQYXR0ZXJuLmNvbXBpbGUoIig/aSkiICsgU3RyaW5nLnZhbHVlT2YoQ09MT1JfQ0hBUikgKyAiWzAtOUEtRkstT1JdIik7CgogICAgICAgIHByaXZhdGUgZmluYWwgaW50IGludENvZGU7CiAgICAgICAgcHJpdmF0ZSBmaW5hbCBjaGFyIGNvZGU7CiAgICAgICAgcHJpdmF0ZSBmaW5hbCBib29sZWFuIGlzRm9ybWF0OwogICAgICAgIHByaXZhdGUgZmluYWwgU3RyaW5nIHRvU3RyaW5nOwogICAgICAgIHByaXZhdGUgZmluYWwgc3RhdGljIE1hcDxJbnRlZ2VyLCBDaGF0Q29sb3I+IEJZX0lEID0gbmV3IEhhc2hNYXA8PigpOwogICAgICAgIHByaXZhdGUgZmluYWwgc3RhdGljIE1hcDxDaGFyYWN0ZXIsIENoYXRDb2xvcj4gQllfQ0hBUiA9IG5ldyBIYXNoTWFwPD4oKTsKCiAgICAgICAgcHJpdmF0ZSBDaGF0Q29sb3IoY2hhciBjb2RlLCBpbnQgaW50Q29kZSkgewogICAgICAgICAgICB0aGlzKGNvZGUsIGludENvZGUsIGZhbHNlKTsKICAgICAgICB9CgogICAgICAgIHByaXZhdGUgQ2hhdENvbG9yKGNoYXIgY29kZSwgaW50IGludENvZGUsIGJvb2xlYW4gaXNGb3JtYXQpIHsKICAgICAgICAgICAgdGhpcy5jb2RlID0gY29kZTsKICAgICAgICAgICAgdGhpcy5pbnRDb2RlID0gaW50Q29kZTsKICAgICAgICAgICAgdGhpcy5pc0Zvcm1hdCA9IGlzRm9ybWF0OwogICAgICAgICAgICB0aGlzLnRvU3RyaW5nID0gbmV3IFN0cmluZyhuZXcgY2hhcltdIHtDT0xPUl9DSEFSLCBjb2RlfSk7CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIHRoZSBjaGFyIHZhbHVlIGFzc29jaWF0ZWQgd2l0aCB0aGlzIGNvbG9yCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIEEgY2hhciB2YWx1ZSBvZiB0aGlzIGNvbG9yIGNvZGUKICAgICAgICAgKi8KICAgICAgICBwdWJsaWMgY2hhciBnZXRDaGFyKCkgewogICAgICAgICAgICByZXR1cm4gY29kZTsKICAgICAgICB9CgogICAgICAgIEBPdmVycmlkZQogICAgICAgIHB1YmxpYyBTdHJpbmcgdG9TdHJpbmcoKSB7CiAgICAgICAgICAgIHJldHVybiB0b1N0cmluZzsKICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIENoZWNrcyBpZiB0aGlzIGNvZGUgaXMgYSBmb3JtYXQgY29kZSBhcyBvcHBvc2VkIHRvIGEgY29sb3IgY29kZS4KICAgICAgICAgKi8KICAgICAgICBwdWJsaWMgYm9vbGVhbiBpc0Zvcm1hdCgpIHsKICAgICAgICAgICAgcmV0dXJuIGlzRm9ybWF0OwogICAgICAgIH0KCiAgICAgICAgLyoqCiAgICAgICAgICogQ2hlY2tzIGlmIHRoaXMgY29kZSBpcyBhIGNvbG9yIGNvZGUgYXMgb3Bwb3NlZCB0byBhIGZvcm1hdCBjb2RlLgogICAgICAgICAqLwogICAgICAgIHB1YmxpYyBib29sZWFuIGlzQ29sb3IoKSB7CiAgICAgICAgICAgIHJldHVybiAhaXNGb3JtYXQgJiYgdGhpcyAhPSBSRVNFVDsKICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIGNvbG9yIHJlcHJlc2VudGVkIGJ5IHRoZSBzcGVjaWZpZWQgY29sb3IgY29kZQogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGNvZGUgQ29kZSB0byBjaGVjawogICAgICAgICAqIEByZXR1cm4gQXNzb2NpYXRpdmUge0BsaW5rIG9yZy5idWtraXQuQ2hhdENvbG9yfSB3aXRoIHRoZSBnaXZlbiBjb2RlLAogICAgICAgICAqICAgICBvciBudWxsIGlmIGl0IGRvZXNuJ3QgZXhpc3QKICAgICAgICAgKi8KICAgICAgICBwdWJsaWMgc3RhdGljIENoYXRDb2xvciBnZXRCeUNoYXIoY2hhciBjb2RlKSB7CiAgICAgICAgICAgIHJldHVybiBCWV9DSEFSLmdldChjb2RlKTsKICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIGNvbG9yIHJlcHJlc2VudGVkIGJ5IHRoZSBzcGVjaWZpZWQgY29sb3IgY29kZQogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGNvZGUgQ29kZSB0byBjaGVjawogICAgICAgICAqIEByZXR1cm4gQXNzb2NpYXRpdmUge0BsaW5rIG9yZy5idWtraXQuQ2hhdENvbG9yfSB3aXRoIHRoZSBnaXZlbiBjb2RlLAogICAgICAgICAqICAgICBvciBudWxsIGlmIGl0IGRvZXNuJ3QgZXhpc3QKICAgICAgICAgKi8KICAgICAgICBwdWJsaWMgc3RhdGljIENoYXRDb2xvciBnZXRCeUNoYXIoU3RyaW5nIGNvZGUpIHsKICAgICAgICAgICAgcmV0dXJuIEJZX0NIQVIuZ2V0KGNvZGUuY2hhckF0KDApKTsKICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIFN0cmlwcyB0aGUgZ2l2ZW4gbWVzc2FnZSBvZiBhbGwgY29sb3IgY29kZXMKICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBpbnB1dCBTdHJpbmcgdG8gc3RyaXAgb2YgY29sb3IKICAgICAgICAgKiBAcmV0dXJuIEEgY29weSBvZiB0aGUgaW5wdXQgc3RyaW5nLCB3aXRob3V0IGFueSBjb2xvcmluZwogICAgICAgICAqLwogICAgICAgIHB1YmxpYyBzdGF0aWMgU3RyaW5nIHN0cmlwQ29sb3IoZmluYWwgU3RyaW5nIGlucHV0KSB7CiAgICAgICAgICAgIGlmIChpbnB1dCA9PSBudWxsKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgcmV0dXJuIFNUUklQX0NPTE9SX1BBVFRFUk4ubWF0Y2hlcihpbnB1dCkucmVwbGFjZUFsbCgiIik7CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBUcmFuc2xhdGVzIGEgc3RyaW5nIHVzaW5nIGFuIGFsdGVybmF0ZSBjb2xvciBjb2RlIGNoYXJhY3RlciBpbnRvIGEKICAgICAgICAgKiBzdHJpbmcgdGhhdCB1c2VzIHRoZSBpbnRlcm5hbCBDaGF0Q29sb3IuQ09MT1JfQ09ERSBjb2xvciBjb2RlCiAgICAgICAgICogY2hhcmFjdGVyLiBUaGUgYWx0ZXJuYXRlIGNvbG9yIGNvZGUgY2hhcmFjdGVyIHdpbGwgb25seSBiZSByZXBsYWNlZCBpZgogICAgICAgICAqIGl0IGlzIGltbWVkaWF0ZWx5IGZvbGxvd2VkIGJ5IDAtOSwgQS1GLCBhLWYsIEstTywgay1vLCBSIG9yIHIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gYWx0Q29sb3JDaGFyIFRoZSBhbHRlcm5hdGUgY29sb3IgY29kZSBjaGFyYWN0ZXIgdG8gcmVwbGFjZS4gRXg6ICYKICAgICAgICAgKiBAcGFyYW0gdGV4dFRvVHJhbnNsYXRlIFRleHQgY29udGFpbmluZyB0aGUgYWx0ZXJuYXRlIGNvbG9yIGNvZGUgY2hhcmFjdGVyLgogICAgICAgICAqIEByZXR1cm4gVGV4dCBjb250YWluaW5nIHRoZSBDaGF0Q29sb3IuQ09MT1JfQ09ERSBjb2xvciBjb2RlIGNoYXJhY3Rlci4KICAgICAgICAgKi8KICAgICAgICBwdWJsaWMgc3RhdGljIFN0cmluZyB0cmFuc2xhdGVBbHRlcm5hdGVDb2xvckNvZGVzKGNoYXIgYWx0Q29sb3JDaGFyLCBTdHJpbmcgdGV4dFRvVHJhbnNsYXRlKSB7CiAgICAgICAgICAgIGNoYXJbXSBiID0gdGV4dFRvVHJhbnNsYXRlLnRvQ2hhckFycmF5KCk7CiAgICAgICAgICAgIGZvciAoaW50IGkgPSAwOyBpIDwgYi5sZW5ndGggLSAxOyBpKyspIHsKICAgICAgICAgICAgICAgIGlmIChiW2ldID09IGFsdENvbG9yQ2hhciAmJiAiMDEyMzQ1Njc4OUFhQmJDY0RkRWVGZktrTGxNbU5uT29SciIuaW5kZXhPZihiW2krMV0pID4gLTEpIHsKICAgICAgICAgICAgICAgICAgICBiW2ldID0gQ2hhdENvbG9yLkNPTE9SX0NIQVI7CiAgICAgICAgICAgICAgICAgICAgYltpKzFdID0gQ2hhcmFjdGVyLnRvTG93ZXJDYXNlKGJbaSsxXSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIG5ldyBTdHJpbmcoYik7CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIHRoZSBDaGF0Q29sb3JzIHVzZWQgYXQgdGhlIGVuZCBvZiB0aGUgZ2l2ZW4gaW5wdXQgc3RyaW5nLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGlucHV0IElucHV0IHN0cmluZyB0byByZXRyaWV2ZSB0aGUgY29sb3JzIGZyb20uCiAgICAgICAgICogQHJldHVybiBBbnkgcmVtYWluaW5nIENoYXRDb2xvcnMgdG8gcGFzcyBvbnRvIHRoZSBuZXh0IGxpbmUuCiAgICAgICAgICovCiAgICAgICAgcHVibGljIHN0YXRpYyBTdHJpbmcgZ2V0TGFzdENvbG9ycyhTdHJpbmcgaW5wdXQpIHsKICAgICAgICAgICAgU3RyaW5nIHJlc3VsdCA9ICIiOwogICAgICAgICAgICBpbnQgbGVuZ3RoID0gaW5wdXQubGVuZ3RoKCk7CgogICAgICAgICAgICAvLyBTZWFyY2ggYmFja3dhcmRzIGZyb20gdGhlIGVuZCBhcyBpdCBpcyBmYXN0ZXIKICAgICAgICAgICAgZm9yIChpbnQgaW5kZXggPSBsZW5ndGggLSAxOyBpbmRleCA+IC0xOyBpbmRleC0tKSB7CiAgICAgICAgICAgICAgICBjaGFyIHNlY3Rpb24gPSBpbnB1dC5jaGFyQXQoaW5kZXgpOwogICAgICAgICAgICAgICAgaWYgKHNlY3Rpb24gPT0gQ09MT1JfQ0hBUiAmJiBpbmRleCA8IGxlbmd0aCAtIDEpIHsKICAgICAgICAgICAgICAgICAgICBjaGFyIGMgPSBpbnB1dC5jaGFyQXQoaW5kZXggKyAxKTsKICAgICAgICAgICAgICAgICAgICBDaGF0Q29sb3IgY29sb3IgPSBnZXRCeUNoYXIoYyk7CgogICAgICAgICAgICAgICAgICAgIGlmIChjb2xvciAhPSBudWxsKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IGNvbG9yLnRvU3RyaW5nKCkgKyByZXN1bHQ7CgogICAgICAgICAgICAgICAgICAgICAgICAvLyBPbmNlIHdlIGZpbmQgYSBjb2xvciBvciByZXNldCB3ZSBjYW4gc3RvcCBzZWFyY2hpbmcKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNvbG9yLmlzQ29sb3IoKSB8fCBjb2xvci5lcXVhbHMoUkVTRVQpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CgogICAgICAgIHN0YXRpYyB7CiAgICAgICAgICAgIGZvciAoQ2hhdENvbG9yIGNvbG9yIDogdmFsdWVzKCkpIHsKICAgICAgICAgICAgICAgIEJZX0lELnB1dChjb2xvci5pbnRDb2RlLCBjb2xvcik7CiAgICAgICAgICAgICAgICBCWV9DSEFSLnB1dChjb2xvci5jb2RlLCBjb2xvcik7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CiAgICAKICAgIHByaXZhdGUgaW50ZXJmYWNlIEV4ZWN1dG9yIHsKICAgIAl2b2lkIGV4ZWN1dGUoKTsKICAgIH0KICAgIAogICAgcHVibGljIHN0YXRpYyB2b2lkIGNoZWNrVGltZShpbnQgYW1vdW50LCBFeGVjdXRvciBleGVjdXRvcikgewogICAgICAgIGxvbmcgc3RhcnQgPSBTeXN0ZW0ubmFub1RpbWUoKTsKICAgICAgICAKICAgICAgICBmb3IgKGludCBpID0gMDsgaSA8IGFtb3VudDsgaSsrKQogICAgICAgIHsKICAgICAgICAgICAgZXhlY3V0b3IuZXhlY3V0ZSgpOwogICAgICAgIH0KICAgICAgICAKICAgICAgICBsb25nIGVuZCA9IFN5c3RlbS5uYW5vVGltZSgpOwogICAgICAgIAogICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigiQXZlcmFnZSBwZXIgY2FsbDogIisoKGVuZCAtIHN0YXJ0KSAvIDEwMDAwMDApICsgIm5zIik7CiAgICB9CgogICAgcHVibGljIHN0YXRpYyBTdHJpbmcgZm9ybWF0MShTdHJpbmcgaW5wdXQsIENoYXRDb2xvci4uLmZvcm1hdHMpCiAgICB7CiAgICAJU3RyaW5nQnVpbGRlciByZXN1bHQgPSBuZXcgU3RyaW5nQnVpbGRlcigpOwoKICAgICAgICBTdHJpbmdCdWlsZGVyIGZvcm1hdCA9IG5ldyBTdHJpbmdCdWlsZGVyKCk7CiAgICAgICAgZm9yIChDaGF0Q29sb3IgY29sb3IgOiBmb3JtYXRzKSBmb3JtYXQuYXBwZW5kKGNvbG9yKTsKICAgICAgICBTdHJpbmcgZm9ybWF0U3RyaW5nID0gZm9ybWF0LnRvU3RyaW5nKCk7CiAgICAJCiAgICAJZm9yIChpbnQgaSA9IDA7IGkgPCBpbnB1dC5sZW5ndGgoKTsgaSArKykgewogICAgCQlyZXN1bHQuYXBwZW5kKGlucHV0LmNoYXJBdChpKSk7CiAgICAJCQogICAgCQlpZiAoaW5wdXQuY2hhckF0KGkpID09IENoYXRDb2xvci5DT0xPUl9DSEFSKSB7CiAgICAJCQlpZiAoaSArIDEgPCBpbnB1dC5sZW5ndGgoKSkgewoJICAgIAkJCUNoYXRDb2xvciBjb2xvciA9IENoYXRDb2xvci5nZXRCeUNoYXIoaW5wdXQuY2hhckF0KCsraSkpOwoJICAgIAkJCQoJICAgIAkJCWlmIChjb2xvciAhPSBudWxsKSB7CgkgICAgCQkJCXJlc3VsdC5hcHBlbmQoY29sb3IuZ2V0Q2hhcigpKTsKCSAgICAJCQkJcmVzdWx0LmFwcGVuZChmb3JtYXRTdHJpbmcpOwoJICAgIAkJCX0KICAgIAkJCX0KICAgIAkJfQogICAgCX0KICAgIAkKICAgIAlyZXN1bHQuYXBwZW5kKENoYXRDb2xvci5SRVNFVCk7CiAgICAJCiAgICAJcmV0dXJuIHJlc3VsdC50b1N0cmluZygpOwogICAgfQogICAgCiAgICBwdWJsaWMgc3RhdGljIFN0cmluZyBmb3JtYXQyKFN0cmluZyBuYW1lLCBDaGF0Q29sb3IuLi5mb3JtYXRzKQogICAgewogICAgLy8gUmVtb3ZlIGFueSBpbml0aWFsIHNlY3Rpb24gc2lnbiwgdG8gYXZvaWQgZW1wdHkgU3RyaW5ncyBiZWZvcmVoYW5kCiAgICAgICAgU3RyaW5nQnVpbGRlciBzYiA9IG5ldyBTdHJpbmdCdWlsZGVyKCk7CiAgICAgICAgZm9yIChDaGF0Q29sb3IgY2MgOiBmb3JtYXRzKQogICAgICAgICAgICBzYi5hcHBlbmQoY2MpOwogICAgICAgIFN0cmluZyBmb3JtYXQgPSBzYi50b1N0cmluZygpOwoKICAgICAgICBib29sZWFuIHN0YXJ0c1dpdGggPSBuYW1lLnN0YXJ0c1dpdGgoU3RyaW5nLnZhbHVlT2YoQ2hhdENvbG9yLkNPTE9SX0NIQVIpKTsKICAgICAgICBpZiAoc3RhcnRzV2l0aCkKICAgICAgICBuYW1lID0gbmFtZS5zdWJzdHJpbmcoMSk7CgogICAgICAgIGludCBpbmRleCA9IDA7CiAgICAgICAgLy8gR2V0IGxlbmd0aAogICAgICAgIGludCBsZW4gPSAwOwogICAgICAgIHdoaWxlICgoaW5kZXggPSBuYW1lLmluZGV4T2YoQ2hhdENvbG9yLkNPTE9SX0NIQVIsIGluZGV4ICsgMSkpID49IDApCiAgICAgICAgbGVuKys7CiAgICAgICAgLy8gcmVzZXR0aW5nIGluZGV4CiAgICAgICAgaW5kZXggPSAwOwogICAgICAgIFN0cmluZ1tdIHBhcnRzID0gbmV3IFN0cmluZ1tsZW4gKyAxXTsKICAgICAgICAvLyBGb3IgZWFjaCBjb2xvdXIgY2hhciAoc2VjdGlvbiBzaWduKSBpbiB0aGUgU3RyaW5nCiAgICAgICAgZm9yIChpbnQgaSA9IDA7IChpbmRleCA9IG5hbWUuaW5kZXhPZihDaGF0Q29sb3IuQ09MT1JfQ0hBUiwgaW5kZXggKyAxKSkgPj0gMDsgaSsrKQogICAgICAgIHsKICAgICAgICAgICAgLy8gSSB3YXMgbGF6eSwgZG9uJ3QgZm9yZ2V0IHRoZSBudWxsIGNoZWNrISEhISEKICAgICAgICAgICAgaWYgKENoYXRDb2xvci5nZXRCeUNoYXIobmFtZS5zdWJzdHJpbmcoaW5kZXggKyAxLCBpbmRleCArIDIpKS5pc0Zvcm1hdCgpKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAvLyBTa2lwIGZvcm1hdHMKICAgICAgICAgICAgICAgIGktLTsgLy8gVW5kbyBpbmNyZW1lbnQKICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIC8vIEFzc2lnbiB0aGUgcGFydCB1cCB0byB0aGUgc2VjdGlvbiBzaWduLCBhbmQgcHJlcGVuZCBhIHRoZSBzZWN0aW9uIHNpZ24KICAgICAgICAgICAgcGFydHNbaV0gPSBDaGF0Q29sb3IuQ09MT1JfQ0hBUiArIG5hbWUuc3Vic3RyaW5nKDAsIGluZGV4KTsKICAgICAgICAgICAgLy8gUmVtb3ZlIHRoZSBwYXJ0IGJlZm9yZWhhbmQKICAgICAgICAgICAgbmFtZSA9IG5hbWUuc3Vic3RyaW5nKGluZGV4KTsKICAgICAgICB9CiAgICAgICAgcGFydHNbcGFydHMubGVuZ3RoIC0gMV0gPSBuYW1lOyAvLyBMZWZ0b3ZlcnMKCiAgICAgICAgLy8gTm93IGpvaW4KICAgICAgICBib29sZWFuIGZpcnN0ID0gdHJ1ZTsKICAgICAgICBTdHJpbmdCdWlsZGVyIGpvaW5lZCA9IG5ldyBTdHJpbmdCdWlsZGVyKHN0YXJ0c1dpdGggPyBTdHJpbmcudmFsdWVPZihDaGF0Q29sb3IuQ09MT1JfQ0hBUikgOiAiIik7CiAgICAgICAgZm9yIChTdHJpbmcgcGFydCA6IHBhcnRzKQogICAgICAgIHsKICAgICAgICAgICAgLy8gU3RhcnQgd2l0aCB0aGUgZm9ybWF0CiAgICAgICAgICAgIGpvaW5lZC5hcHBlbmQoZm9ybWF0KTsKICAgICAgICAgICAgLy8gSWYgaXQgd2FzIHRoZSBmaXJzdCwgb25seSBhZGQgdGhlIGNvbG91ciBjaGFyIGlmIGl0IHByZXZpb3VzbHkgaGFkIGFueQogICAgICAgICAgICBpZiAoZmlyc3QpCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIGZpcnN0ID0gZmFsc2U7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZSAvLyB0aGV5IHdlcmUgc3BsaXQgYmFzZWQgb24gY29sb3VyIGNoYXIsIHNvIGFsd2F5cyBhZGQgb25lIGJldHdlZW4KICAgICAgICAgICAgewogICAgICAgICAgICAgICAgam9pbmVkLmFwcGVuZChDaGF0Q29sb3IuQ09MT1JfQ0hBUik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgam9pbmVkLmFwcGVuZChwYXJ0KTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGpvaW5lZC50b1N0cmluZygpOwogICAgfQoKICAgIHB1YmxpYyBzdGF0aWMgdm9pZCBtYWluKFN0cmluZ1tdIGFyZ3MpCiAgICB7CiAgICAgICAgU3RyaW5nIG5hbWUgPSBDaGF0Q29sb3IuUkVEICsgIkRyYWdvbiIgKyBDaGF0Q29sb3IuQkxVRSArICJwaGFzZSI7CiAgICAgICAgQ2hhdENvbG9yW10gZm9ybWF0cyA9IG5ldyBDaGF0Q29sb3JbXXtDaGF0Q29sb3IuQk9MRCwgQ2hhdENvbG9yLlVOREVSTElORX07CiAgICAgICAgCiAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKCJGb3JtYXQxOiAiICsgZm9ybWF0MShuYW1lLCBmb3JtYXRzKSk7CiAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKCJGb3JtYXQyOiAiICsgZm9ybWF0MihuYW1lLCBmb3JtYXRzKSk7CiAgICAgICAgCiAgICAgICAgY2hlY2tUaW1lKDEwMDAwMDAsIG5ldyBFeGVjdXRvcigpIHsKICAgICAgICAJcHVibGljIHZvaWQgZXhlY3V0ZSgpIHsKICAgICAgICAJCWZvcm1hdDEobmFtZSwgZm9ybWF0cyk7CiAgICAgICAgCX0KICAgICAgICB9KTsKICAgICAgICAKICAgICAgICBjaGVja1RpbWUoMTAwMDAwMCwgbmV3IEV4ZWN1dG9yKCkgewogICAgICAgIAlwdWJsaWMgdm9pZCBleGVjdXRlKCkgewogICAgICAgIAkJZm9ybWF0MihuYW1lLCBmb3JtYXRzKTsKICAgICAgICAJfQogICAgICAgIH0pOwogICAgfQp9