/* 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 input, ChatColor...
formats) {
StringBuilder format = new StringBuilder();
for (ChatColor color : formats) format.append(color);
char[] formatString = format.toString().toCharArray();
char[] o = input.toCharArray();
// List of indices where we should inject our format
LinkedList<Integer> indices = new LinkedList<>();
for (int i = 0; i < o.length - 1; i++) {
int j = i + 1;
if (o[i] == ChatColor.COLOR_CHAR && (('0' <= o[j] && o[j] <= '9') || ('a' <= o[j] && o[j] <= 'f') || ('A' <= o[j] && o[j] <= 'F'))) {
indices.add(j + 1);
i++; // Skip this char
}
}
char[] n = new char[o.length + formatString.length * indices.size() + 2];
n[n.length - 2] = ChatColor.COLOR_CHAR;
n[n.length - 1] = 'r';
Iterator<Integer> it = indices.iterator();
int offset = 0;
int previous = 0;
while (it.hasNext()) {
int next = it.next();
System.
arraycopy(o, previous, n, previous
+ offset, next
- previous
); System.
arraycopy(formatString,
0, n, next
+ offset, formatString.
length); previous = next;
offset += formatString.length;
}
System.
arraycopy(o, previous, n, previous
+ offset, o.
length - previous
); }
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+IC0xOyBpbmRleC0tKSB7CiAgICAgICAgICAgICAgICBjaGFyIHNlY3Rpb24gPSBpbnB1dC5jaGFyQXQoaW5kZXgpOwogICAgICAgICAgICAgICAgaWYgKHNlY3Rpb24gPT0gQ09MT1JfQ0hBUiAmJiBpbmRleCA8IGxlbmd0aCAtIDEpIHsKICAgICAgICAgICAgICAgICAgICBjaGFyIGMgPSBpbnB1dC5jaGFyQXQoaW5kZXggKyAxKTsKICAgICAgICAgICAgICAgICAgICBDaGF0Q29sb3IgY29sb3IgPSBnZXRCeUNoYXIoYyk7CgogICAgICAgICAgICAgICAgICAgIGlmIChjb2xvciAhPSBudWxsKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IGNvbG9yLnRvU3RyaW5nKCkgKyByZXN1bHQ7CgogICAgICAgICAgICAgICAgICAgICAgICAvLyBPbmNlIHdlIGZpbmQgYSBjb2xvciBvciByZXNldCB3ZSBjYW4gc3RvcCBzZWFyY2hpbmcKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNvbG9yLmlzQ29sb3IoKSB8fCBjb2xvci5lcXVhbHMoUkVTRVQpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CgogICAgICAgIHN0YXRpYyB7CiAgICAgICAgICAgIGZvciAoQ2hhdENvbG9yIGNvbG9yIDogdmFsdWVzKCkpIHsKICAgICAgICAgICAgICAgIEJZX0lELnB1dChjb2xvci5pbnRDb2RlLCBjb2xvcik7CiAgICAgICAgICAgICAgICBCWV9DSEFSLnB1dChjb2xvci5jb2RlLCBjb2xvcik7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CiAgICAKICAgIHByaXZhdGUgaW50ZXJmYWNlIEV4ZWN1dG9yIHsKICAgIAl2b2lkIGV4ZWN1dGUoKTsKICAgIH0KICAgIAogICAgcHVibGljIHN0YXRpYyB2b2lkIGNoZWNrVGltZShpbnQgYW1vdW50LCBFeGVjdXRvciBleGVjdXRvcikgewogICAgICAgIGxvbmcgc3RhcnQgPSBTeXN0ZW0ubmFub1RpbWUoKTsKICAgICAgICAKICAgICAgICBmb3IgKGludCBpID0gMDsgaSA8IGFtb3VudDsgaSsrKQogICAgICAgIHsKICAgICAgICAgICAgZXhlY3V0b3IuZXhlY3V0ZSgpOwogICAgICAgIH0KICAgICAgICAKICAgICAgICBsb25nIGVuZCA9IFN5c3RlbS5uYW5vVGltZSgpOwogICAgICAgIAogICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigiQXZlcmFnZSBwZXIgY2FsbDogIisoKGVuZCAtIHN0YXJ0KSAvIDEwMDAwMDApICsgIm5zIik7CiAgICB9CgogICAgcHVibGljIHN0YXRpYyBTdHJpbmcgZm9ybWF0MShTdHJpbmcgaW5wdXQsIENoYXRDb2xvci4uLmZvcm1hdHMpCiAgICB7CiAgICAJU3RyaW5nQnVpbGRlciByZXN1bHQgPSBuZXcgU3RyaW5nQnVpbGRlcigpOwoKICAgICAgICBTdHJpbmdCdWlsZGVyIGZvcm1hdCA9IG5ldyBTdHJpbmdCdWlsZGVyKCk7CiAgICAgICAgZm9yIChDaGF0Q29sb3IgY29sb3IgOiBmb3JtYXRzKSBmb3JtYXQuYXBwZW5kKGNvbG9yKTsKICAgICAgICBTdHJpbmcgZm9ybWF0U3RyaW5nID0gZm9ybWF0LnRvU3RyaW5nKCk7CiAgICAJCiAgICAJZm9yIChpbnQgaSA9IDA7IGkgPCBpbnB1dC5sZW5ndGgoKTsgaSArKykgewogICAgCQlyZXN1bHQuYXBwZW5kKGlucHV0LmNoYXJBdChpKSk7CiAgICAJCQogICAgCQlpZiAoaW5wdXQuY2hhckF0KGkpID09IENoYXRDb2xvci5DT0xPUl9DSEFSKSB7CiAgICAJCQlpZiAoaSArIDEgPCBpbnB1dC5sZW5ndGgoKSkgewoJICAgIAkJCUNoYXRDb2xvciBjb2xvciA9IENoYXRDb2xvci5nZXRCeUNoYXIoaW5wdXQuY2hhckF0KCsraSkpOwoJICAgIAkJCQoJICAgIAkJCWlmIChjb2xvciAhPSBudWxsKSB7CgkgICAgCQkJCXJlc3VsdC5hcHBlbmQoY29sb3IuZ2V0Q2hhcigpKTsKCSAgICAJCQkJcmVzdWx0LmFwcGVuZChmb3JtYXRTdHJpbmcpOwoJICAgIAkJCX0KICAgIAkJCX0KICAgIAkJfQogICAgCX0KICAgIAkKICAgIAlyZXN1bHQuYXBwZW5kKENoYXRDb2xvci5SRVNFVCk7CiAgICAJCiAgICAJcmV0dXJuIHJlc3VsdC50b1N0cmluZygpOwogICAgfQogICAgCiAgICBwdWJsaWMgc3RhdGljIFN0cmluZyBmb3JtYXQyKFN0cmluZyBpbnB1dCwgQ2hhdENvbG9yLi4uZm9ybWF0cykKICAgIHsKICAgIAlTdHJpbmdCdWlsZGVyIGZvcm1hdCA9IG5ldyBTdHJpbmdCdWlsZGVyKCk7CgkJZm9yIChDaGF0Q29sb3IgY29sb3IgOiBmb3JtYXRzKSBmb3JtYXQuYXBwZW5kKGNvbG9yKTsKCQljaGFyW10gZm9ybWF0U3RyaW5nID0gZm9ybWF0LnRvU3RyaW5nKCkudG9DaGFyQXJyYXkoKTsKCQljaGFyW10gbyA9IGlucHV0LnRvQ2hhckFycmF5KCk7CgkJLy8gTGlzdCBvZiBpbmRpY2VzIHdoZXJlIHdlIHNob3VsZCBpbmplY3Qgb3VyIGZvcm1hdAoJCUxpbmtlZExpc3Q8SW50ZWdlcj4gaW5kaWNlcyA9IG5ldyBMaW5rZWRMaXN0PD4oKTsKCQlmb3IgKGludCBpID0gMDsgaSA8IG8ubGVuZ3RoIC0gMTsgaSsrKSB7CgkJICAgIGludCBqID0gaSArIDE7CgkJICAgIGlmIChvW2ldID09IENoYXRDb2xvci5DT0xPUl9DSEFSICYmICgoJzAnIDw9IG9bal0gJiYgb1tqXSA8PSAnOScpIHx8ICgnYScgPD0gb1tqXSAmJiBvW2pdIDw9ICdmJykgfHwgKCdBJyA8PSBvW2pdICYmIG9bal0gPD0gJ0YnKSkpIHsKCQkgICAgICAgIGluZGljZXMuYWRkKGogKyAxKTsKCQkgICAgICAgIGkrKzsgLy8gU2tpcCB0aGlzIGNoYXIKCQkgICAgfQoJCX0KCQljaGFyW10gbiA9IG5ldyBjaGFyW28ubGVuZ3RoICsgZm9ybWF0U3RyaW5nLmxlbmd0aCAqIGluZGljZXMuc2l6ZSgpICsgMl07CgkJbltuLmxlbmd0aCAtIDJdID0gQ2hhdENvbG9yLkNPTE9SX0NIQVI7CgkJbltuLmxlbmd0aCAtIDFdID0gJ3InOwoJCUl0ZXJhdG9yPEludGVnZXI+IGl0ID0gaW5kaWNlcy5pdGVyYXRvcigpOwoJCWludCBvZmZzZXQgPSAwOwoJCWludCBwcmV2aW91cyA9IDA7CgkJd2hpbGUgKGl0Lmhhc05leHQoKSkgewoJCSAgICBpbnQgbmV4dCA9IGl0Lm5leHQoKTsKCQkgICAgU3lzdGVtLmFycmF5Y29weShvLCBwcmV2aW91cywgbiwgcHJldmlvdXMgKyBvZmZzZXQsIG5leHQgLSBwcmV2aW91cyk7CgkJICAgIFN5c3RlbS5hcnJheWNvcHkoZm9ybWF0U3RyaW5nLCAwLCBuLCBuZXh0ICsgb2Zmc2V0LCBmb3JtYXRTdHJpbmcubGVuZ3RoKTsKCQkgICAgcHJldmlvdXMgPSBuZXh0OwoJCSAgICBvZmZzZXQgKz0gZm9ybWF0U3RyaW5nLmxlbmd0aDsKCQl9CgkgICAgU3lzdGVtLmFycmF5Y29weShvLCBwcmV2aW91cywgbiwgcHJldmlvdXMgKyBvZmZzZXQsIG8ubGVuZ3RoIC0gcHJldmlvdXMpOwoJCXJldHVybiBuZXcgU3RyaW5nKG4pOwogICAgfQoKICAgIHB1YmxpYyBzdGF0aWMgdm9pZCBtYWluKFN0cmluZ1tdIGFyZ3MpCiAgICB7CiAgICAgICAgU3RyaW5nIG5hbWUgPSBDaGF0Q29sb3IuUkVEICsgIkRyYWdvbiIgKyBDaGF0Q29sb3IuQkxVRSArICJwaGFzZSI7CiAgICAgICAgQ2hhdENvbG9yW10gZm9ybWF0cyA9IG5ldyBDaGF0Q29sb3JbXXtDaGF0Q29sb3IuQk9MRCwgQ2hhdENvbG9yLlVOREVSTElORX07CiAgICAgICAgCiAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKCJGb3JtYXQxOiAiICsgZm9ybWF0MShuYW1lLCBmb3JtYXRzKSk7CiAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKCJGb3JtYXQyOiAiICsgZm9ybWF0MihuYW1lLCBmb3JtYXRzKSk7CiAgICAgICAgY2hlY2tUaW1lKDEwMDAwMDAsIG5ldyBFeGVjdXRvcigpIHsKICAgICAgICAJcHVibGljIHZvaWQgZXhlY3V0ZSgpIHsKICAgICAgICAJCWZvcm1hdDEobmFtZSwgZm9ybWF0cyk7CiAgICAgICAgCX0KICAgICAgICB9KTsKICAgICAgICAKICAgICAgICBjaGVja1RpbWUoMTAwMDAwMCwgbmV3IEV4ZWN1dG9yKCkgewogICAgICAgIAlwdWJsaWMgdm9pZCBleGVjdXRlKCkgewogICAgICAgIAkJZm9ybWF0MihuYW1lLCBmb3JtYXRzKTsKICAgICAgICAJfQogICAgICAgIH0pOwogICAgfQp9