import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.*;
public class Vam
extends JFrame{
private static final int FRAME_WIDTH = 800;
private static final int FRAME_HEIGHT = 800;
boolean stop;
public static byte SR; //Aufbau: (0,0,0,0,0,Overflow,GraterZero,SmallerZero)
public static byte BZ;
public static byte A;
public static byte R1;
public static byte R2;
public static byte R3;
public static byte R4;
public static byte R5;
public static byte R6;
public static byte R7;
public static byte R8;
public static byte R9;
public static byte R10;
public static byte R11;
public static byte R12;
public static byte R13;
public static byte R14;
public static byte R15;
private int numberOfLines = 1;
Vam(){
setSize(FRAME_WIDTH, FRAME_HEIGHT);
setResizable(false);
setTitle("Virtual Assembler Machine");
setDefaultCloseOperation(EXIT_ON_CLOSE);
textArea.addKeyListener(new MyKeyListener());
scrollPane.getVerticalScrollBar().setUnitIncrement(10); //sets the scroll-speed
lineNumbering.
setLayout(new GridLayout(numberOfLines,
2)); for(int i=0; i<numberOfLines; ++i) {
if(numberOfLines<10) {
lineNumbering.
add(new JLabel(String.
valueOf(numberOfLines
)+" ")); } else {
lineNumbering.
add(new JLabel(String.
valueOf(numberOfLines
))); }
lineNumbering.
add(new JLabel(":")); }
panelLeft.add(lineNumbering);
panelLeft.add(textArea);
reset();
add(scrollPane);
add(panelRight);
setVisible(true);
}
@Override
if(e.
getKeyCode() == KeyEvent.
VK_ENTER) { System.
out.
println("ENTER " + textArea.
getLineCount()+" "+numberOfLines
); //System.out.println(textArea.getText());
numberOfLines = textArea.getLineCount()+1;
lineNumbering.
setLayout(new GridLayout(numberOfLines,
2)); if(numberOfLines<10) {
lineNumbering.
add(new JLabel(String.
valueOf(numberOfLines
)+" ")); } else {
lineNumbering.
add(new JLabel(String.
valueOf(numberOfLines
))); }
lineNumbering.
add(new JLabel(":")); }
if(e.
getKeyCode() == KeyEvent.
VK_BACK_SPACE) { System.
out.
println("BACKSPACE " + textArea.
getLineCount()+" "+numberOfLines
); //System.out.println(textArea.getText());
if(textArea.getLineCount() == numberOfLines) {
try {
System.
out.
println(textArea.
getLineCount()+" "+numberOfLines
); if(textArea.getLineCount() != numberOfLines) {
numberOfLines = textArea.getLineCount()-1;
lineNumbering.
setLayout(new GridLayout(numberOfLines,
2)); lineNumbering.remove(lineNumbering.getComponentCount()-1);
lineNumbering.remove(lineNumbering.getComponentCount()-1);
}
}
}
}
@Override
@Override
}
return textArea.getText();
}
//line is the same number as the numbering of the lines on the right side
public String getTextInLine
(int line
) { String ret
= textArea.
getText(); for(int i=0; i<line-1; ++i) {
ret = ret.substring(ret.indexOf("\n")+1);
}
if(ret.contains("\n"))ret = ret.substring(0, ret.indexOf("\n"));
return ret;
}
//call this method, to update the values
public JPanel rightPanel
(byte[] by
) {
labels
[0][0] = new JLabel("SR"); labels
[0][1] = new JLabel("BZ"); labels
[0][2] = new JLabel("A");
for (int i=0; i<15; ++i) {
labels
[0][i
+3] = new JLabel("R"+(i
+1)); }
for(int i=0; i<18; i++) {
labels
[1][i
] = new JLabel(String.
format("%8s",
Integer.
toBinaryString(by
[i
] & 0xFF
)).
replace(' ',
'0')); }
for(int i=0; i<18; i++) {
ret.add(labels[0][i]);
ret.add(labels[1][i]);
}
start();
}
});
reset();
}
});
ret.add(start);
ret.add(reset);
return ret;
}
private void reset() {
stop = false;
SR = 0;
BZ = 1;
A = 0;
R1 = 0;
R2 = 0;
R3 = 0;
R4 = 0;
R5 = 0;
R6 = 0;
R7 = 0;
R8 = 0;
R9 = 0;
R10 = 0;
R11 = 0;
R12 = 0;
R13 = 0;
R14 = 0;
R15 = 0;
byte[] by = {SR, BZ, A, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15};
panelRight = rightPanel(by);
}
private void start() {
while(!stop) {
check(getTextInLine(BZ));
}
byte[] by = {SR, BZ, A, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15};
panelRight = rightPanel(by);
}
private void def
(String input
) {//dafault System.
out.
println("unknown command: \"" + input
+"\""); }
//calls the right method
if(rest.length()>0) {
if(rest.charAt(0) == ' ') {
switch(command) {
case "ADD":
add
(Integer.
valueOf(rest.
substring(1))); break;
case "DLOAD":
dload
(Integer.
valueOf(rest.
substring(1))); break;
case "DIV":
div
(Integer.
valueOf(rest.
substring(1))); break;
case "JEQ":
jeq
(Integer.
valueOf(rest.
substring(1))); break;
case "JGE":
jge
(Integer.
valueOf(rest.
substring(1))); break;
case "JGT":
jgt
(Integer.
valueOf(rest.
substring(1))); break;
case "JLE":
jle
(Integer.
valueOf(rest.
substring(1))); break;
case "JLT":
jlt
(Integer.
valueOf(rest.
substring(1))); break;
case "JNE":
jne
(Integer.
valueOf(rest.
substring(1))); break;
case "JUMP":
jump
(Integer.
valueOf(rest.
substring(1))); break;
case "LOAD":
load
(Integer.
valueOf(rest.
substring(1))); break;
case "MULT":
mult
(Integer.
valueOf(rest.
substring(1))); break;
case "STORE":
store
(Integer.
valueOf(rest.
substring(1))); break;
case "SUB":
sub
(Integer.
valueOf(rest.
substring(1))); break;
}
}else {
def(command+rest);
}
}else {
if(command.equals("END")) {
end();
}else {
def(command+rest);
}
}
}
private void end() {
stop = true;
BZ++;
}
private void add(int number) {
int i;
int temp;
switch(number) {
case 1: i = R1;
case 2: i = R2;
case 3: i = R3;
case 4: i = R4;
case 5: i = R5;
case 6: i = R6;
case 7: i = R7;
case 8: i = R8;
case 9: i = R9;
case 10: i = R10;
case 11: i = R11;
case 12: i = R12;
case 13: i = R13;
case 14: i = R14;
case 15: i = R15;
default:
System.
out.
println(number
+"is not a valid register!"); i=0;
end();
}
temp=A+i;
SR
= (byte) (SR
& Byte.
valueOf("11111100")); //set last 2 bit to 0 if(temp>0) {
SR
= (byte) (SR
| Byte.
valueOf("00000010")); //set bit before last to 1 }else {
if(temp<0) {
SR
= (byte) (SR
| Byte.
valueOf("00000001"));//set last bit to 1 }
}
if(temp<128&&temp>-129) {
A=(byte)temp;
SR
= (byte) (SR
& Byte.
valueOf("11111011"));//set 6. bit to 0 // 11111111112222222222333
}else { // 12345678901234567890123456789012
A
= (byte)(temp
& Byte.
valueOf("00000000000000000000000011111111")); SR
= (byte) (SR
| Byte.
valueOf("00000100"));//set 6. bit to 1 }
BZ++;
}
private void dload(int number) {
if(number<128&&number>-129) {
A = (byte)number;
}else {
System.
out.
println(number
+" is too big"); }
}
private void div(int number) {
int i;
int temp;
switch(number) {
case 1: i = R1;
case 2: i = R2;
case 3: i = R3;
case 4: i = R4;
case 5: i = R5;
case 6: i = R6;
case 7: i = R7;
case 8: i = R8;
case 9: i = R9;
case 10: i = R10;
case 11: i = R11;
case 12: i = R12;
case 13: i = R13;
case 14: i = R14;
case 15: i = R15;
default:
System.
out.
println(number
+"is not a valid register!"); i=0;
end();
}
temp=A/i;
SR
= (byte) (SR
& Byte.
valueOf("11111100")); //set last 2 bit to 0 if(temp>0) {
SR
= (byte) (SR
| Byte.
valueOf("00000010")); //set bit before last to 1 }else {
if(temp<0) {
SR
= (byte) (SR
| Byte.
valueOf("00000001"));//set last bit to 1 }
}
if(temp<128&&temp>-129) {
A=(byte)temp;
SR
= (byte) (SR
& Byte.
valueOf("11111011"));//set 6. bit to 0 // 11111111112222222222333
}else { // 12345678901234567890123456789012
A
= (byte)(temp
& Byte.
valueOf("00000000000000000000000011111111")); SR
= (byte) (SR
| Byte.
valueOf("00000100"));//set 6. bit to 1 }
BZ++;
}
private void jeq(int number) {
if(status.charAt(6)=='0'&&status.charAt(7)=='0') {
BZ=(byte)number;
}else {
BZ++;
}
}
private void jge(int number) {
if(status.charAt(7)=='0') {
BZ=(byte)number;
}else {
BZ++;
}
}
private void jgt(int number) {
if(status.charAt(6)=='1') {
BZ=(byte)number;
}else {
BZ++;
}
}
private void jle(int number) {
if(status.charAt(6)=='0') {
BZ=(byte)number;
}else {
BZ++;
}
}
private void jlt(int number) {
if(status.charAt(7)=='0') {
BZ=(byte)number;
}else {
BZ++;
}
}
private void jne(int number) {
if(status.charAt(6)=='1'||status.charAt(7)=='1') {
BZ=(byte)number;
}else {
BZ++;
}
}
private void jump(int number) {
BZ = (byte)number;
}
private void load(int number) {
int i;
switch(number) {
case 1: i = R1;
case 2: i = R2;
case 3: i = R3;
case 4: i = R4;
case 5: i = R5;
case 6: i = R6;
case 7: i = R7;
case 8: i = R8;
case 9: i = R9;
case 10: i = R10;
case 11: i = R11;
case 12: i = R12;
case 13: i = R13;
case 14: i = R14;
case 15: i = R15;
default:
System.
out.
println(number
+"is not a valid register!"); i=0;
end();
}
A=(byte)i;
SR
= (byte) (SR
& Byte.
valueOf("11111100")); //set last 2 bit to 0 if(A>0) {
SR
= (byte) (SR
| Byte.
valueOf("00000010")); //set bit before last to 1 }else {
if(A<0) {
SR
= (byte) (SR
| Byte.
valueOf("00000001"));//set last bit to 1 }
}
BZ++;
}
private void mult(int number) {
int i;
int temp;
switch(number) {
case 1: i = R1;
case 2: i = R2;
case 3: i = R3;
case 4: i = R4;
case 5: i = R5;
case 6: i = R6;
case 7: i = R7;
case 8: i = R8;
case 9: i = R9;
case 10: i = R10;
case 11: i = R11;
case 12: i = R12;
case 13: i = R13;
case 14: i = R14;
case 15: i = R15;
default:
System.
out.
println(number
+"is not a valid register!"); i=0;
end();
}
temp=A*i;
SR
= (byte) (SR
& Byte.
valueOf("11111100")); //set last 2 bit to 0 if(temp>0) {
SR
= (byte) (SR
| Byte.
valueOf("00000010")); //set bit before last to 1 }else {
if(temp<0) {
SR
= (byte) (SR
| Byte.
valueOf("00000001"));//set last bit to 1 }
}
if(temp<128&&temp>-129) {
A=(byte)temp;
SR
= (byte) (SR
& Byte.
valueOf("11111011"));//set 6. bit to 0 // 11111111112222222222333
}else { // 12345678901234567890123456789012
A
= (byte)(temp
& Byte.
valueOf("00000000000000000000000011111111")); SR
= (byte) (SR
| Byte.
valueOf("00000100"));//set 6. bit to 1 }
BZ++;
}
private void store(int number) {
switch(number) {
case 1: R1 = A;
case 2: R2 = A;
case 3: R3 = A;
case 4: R4 = A;
case 5: R5 = A;
case 6: R6 = A;
case 7: R7 = A;
case 8: R8 = A;
case 9: R9 = A;
case 10: R10 = A;
case 11: R11 = A;
case 12: R12 = A;
case 13: R13 = A;
case 14: R14 = A;
case 15: R15 = A;
default:
System.
out.
println(number
+"is not a valid register!"); end();
}
}
private void sub(int number) {
int i;
int temp;
switch(number) {
case 1: i = R1;
case 2: i = R2;
case 3: i = R3;
case 4: i = R4;
case 5: i = R5;
case 6: i = R6;
case 7: i = R7;
case 8: i = R8;
case 9: i = R9;
case 10: i = R10;
case 11: i = R11;
case 12: i = R12;
case 13: i = R13;
case 14: i = R14;
case 15: i = R15;
default:
System.
out.
println(number
+"is not a valid register!"); i=0;
end();
}
temp=A-i;
SR
= (byte) (SR
& Byte.
valueOf("11111100")); //set last 2 bit to 0 if(temp>0) {
SR
= (byte) (SR
| Byte.
valueOf("00000010")); //set bit before last to 1 }else {
if(temp<0) {
SR
= (byte) (SR
| Byte.
valueOf("00000001"));//set last bit to 1 }
}
if(temp<128&&temp>-129) {
A=(byte)temp;
SR
= (byte) (SR
& Byte.
valueOf("11111011"));//set 6. bit to 0 // 11111111112222222222333
}else { // 12345678901234567890123456789012
A
= (byte)(temp
& Byte.
valueOf("00000000000000000000000011111111")); SR
= (byte) (SR
| Byte.
valueOf("00000100"));//set 6. bit to 1 }
BZ++;
}
//separates the command and the rest
public void check
(String input
) { switch(input.charAt(0)){
case 'A'://A
switch(input.charAt(1)){
case 'D'://AD
switch(input.charAt(2)){
case 'D'://ADD
execute(input.substring(0, 3), input.substring(3));
break;
default:
def(input);
break;
}
break;
default:
def(input);
break;
}
break;
case 'D'://D
switch(input.charAt(1)){
case 'L'://DL
switch(input.charAt(2)){
case 'O'://DLO
switch(input.charAt(3)){
case 'A'://DLOA
switch(input.charAt(4)){
case 'D'://DLOAD
execute(input.substring(0, 5), input.substring(5));
break;
default:
def(input);
break;
}
break;
default:
def(input);
break;
}
break;
default:
def(input);
break;
}
break;
case 'I'://DI
switch(input.charAt(2)){
case 'V'://DIV
execute(input.substring(0, 3), input.substring(3));
break;
default:
def(input);
break;
}
break;
default:
def(input);
break;
}
break;
case 'E'://E
switch(input.charAt(1)){
case 'N'://EN
switch(input.charAt(2)){
case 'D'://END
execute(input.substring(0, 3), input.substring(3));
break;
default:
def(input);
break;
}
break;
default:
def(input);
break;
}
break;
case 'J'://J
switch(input.charAt(1)){
case 'E'://JE
switch(input.charAt(2)){
case 'Q'://JEQ
execute(input.substring(0, 3), input.substring(3));
break;
default:
def(input);
break;
}
break;
default:
def(input);
break;
case 'G'://JG
switch(input.charAt(2)){
case 'E'://JGE
execute(input.substring(0, 3), input.substring(3));
case 'T'://JGT
execute(input.substring(0, 3), input.substring(3));
default:
def(input);
}
case 'L'://JL
switch(input.charAt(2)){
case 'E'://JLE
execute(input.substring(0, 3), input.substring(3));
case 'T'://JLT
execute(input.substring(0, 3), input.substring(3));
default:
def(input);
}
case 'N'://JN
switch(input.charAt(2)){
case 'E'://JNE
execute(input.substring(0, 3), input.substring(3));
default:
def(input);
}
case 'U'://JU
switch(input.charAt(2)){
case 'M'://JUM
switch(input.charAt(3)){
case 'P'://JUMP
execute(input.substring(0, 4), input.substring(4));
default:
def(input);
}
default:
def(input);
}
}
case 'L'://L
switch(input.charAt(1)){
case 'O'://LO
switch(input.charAt(2)){
case 'A'://LOA
switch(input.charAt(3)){
case 'D'://LOAD
execute(input.substring(0, 4), input.substring(4));
default:
def(input);
}
default:
def(input);
}
default:
def(input);
}
case 'M'://M
switch(input.charAt(1)){
case 'U'://MU
switch(input.charAt(2)){
case 'L'://MUL
switch(input.charAt(3)){
case 'T'://MULT
execute(input.substring(0, 4), input.substring(4));
default:
def(input);
}
default:
def(input);
}
default:
def(input);
}
case 'S'://S
switch(input.charAt(1)){
case 'T'://ST
switch(input.charAt(2)){
case 'O'://STO
switch(input.charAt(3)){
case 'R'://STOR
switch(input.charAt(4)){
case 'E'://STORE
execute(input.substring(0, 5), input.substring(5));
default:
def(input);
}
default:
def(input);
}
default:
def(input);
}
case 'U'://SU
switch(input.charAt(2)){
case 'B'://SUB
execute(input.substring(0, 3), input.substring(3));
default:
def(input);
}
default:
def(input);
}
default:
def(input);
}
}
public static void main
(String args
[]) { new Vam();
}
}
/* Just a simple program to test:
DLOAD 10
LOAD 1
DLOAD 2
ADD 1
LOAD 2
END
*/
aW1wb3J0IGphdmEuYXd0Lio7CmltcG9ydCBqYXZhLmF3dC5ldmVudC5BY3Rpb25FdmVudDsKaW1wb3J0IGphdmEuYXd0LmV2ZW50LktleUV2ZW50OwppbXBvcnQgamF2YS5hd3QuZXZlbnQuS2V5TGlzdGVuZXI7CgppbXBvcnQgamF2YXguc3dpbmcuKjsKCgpwdWJsaWMgY2xhc3MgVmFtIGV4dGVuZHMgSkZyYW1lewoJCglwcml2YXRlIHN0YXRpYyBmaW5hbCBpbnQgRlJBTUVfV0lEVEggPSA4MDA7Cglwcml2YXRlIHN0YXRpYyBmaW5hbCBpbnQgRlJBTUVfSEVJR0hUID0gODAwOwoJCglib29sZWFuIHN0b3A7CgkKCXB1YmxpYyBzdGF0aWMgYnl0ZSBTUjsgLy9BdWZiYXU6ICgwLDAsMCwwLDAsT3ZlcmZsb3csR3JhdGVyWmVybyxTbWFsbGVyWmVybykKCXB1YmxpYyBzdGF0aWMgYnl0ZSBCWjsKCXB1YmxpYyBzdGF0aWMgYnl0ZSBBOwoJcHVibGljIHN0YXRpYyBieXRlIFIxOwoJcHVibGljIHN0YXRpYyBieXRlIFIyOwoJcHVibGljIHN0YXRpYyBieXRlIFIzOwoJcHVibGljIHN0YXRpYyBieXRlIFI0OwoJcHVibGljIHN0YXRpYyBieXRlIFI1OwoJcHVibGljIHN0YXRpYyBieXRlIFI2OwoJcHVibGljIHN0YXRpYyBieXRlIFI3OwoJcHVibGljIHN0YXRpYyBieXRlIFI4OwoJcHVibGljIHN0YXRpYyBieXRlIFI5OwoJcHVibGljIHN0YXRpYyBieXRlIFIxMDsKCXB1YmxpYyBzdGF0aWMgYnl0ZSBSMTE7CglwdWJsaWMgc3RhdGljIGJ5dGUgUjEyOwoJcHVibGljIHN0YXRpYyBieXRlIFIxMzsKCXB1YmxpYyBzdGF0aWMgYnl0ZSBSMTQ7CglwdWJsaWMgc3RhdGljIGJ5dGUgUjE1OwoJCgkKCXByaXZhdGUgaW50IG51bWJlck9mTGluZXMgPSAxOwoJCglwcml2YXRlIEpQYW5lbCBwYW5lbExlZnQgPSBuZXcgSlBhbmVsKCk7CgkJcHJpdmF0ZSBKU2Nyb2xsUGFuZSBzY3JvbGxQYW5lID0gbmV3IEpTY3JvbGxQYW5lKHBhbmVsTGVmdCk7CgkJcHJpdmF0ZSBKUGFuZWwgbGluZU51bWJlcmluZyA9IG5ldyBKUGFuZWwoKTsKCQkJcHJpdmF0ZSBKVGV4dEFyZWEgdGV4dEFyZWEgPSBuZXcgSlRleHRBcmVhKG51bWJlck9mTGluZXMsIDMwKTsKCQoJcHJpdmF0ZSBKUGFuZWwgcGFuZWxSaWdodDsKCQlwcml2YXRlIEpMYWJlbFtdW10gbGFiZWxzID0gbmV3IEpMYWJlbFsyXVsxOF07CgkJcHJpdmF0ZSBKQnV0dG9uIHN0YXJ0OwoJCXByaXZhdGUgSkJ1dHRvbiByZXNldDsKCQoJVmFtKCl7CgkJc2V0U2l6ZShGUkFNRV9XSURUSCwgRlJBTUVfSEVJR0hUKTsKCQlzZXRSZXNpemFibGUoZmFsc2UpOwoJCXNldExheW91dChuZXcgR3JpZExheW91dCgxLCAyKSk7CgkJc2V0VGl0bGUoIlZpcnR1YWwgQXNzZW1ibGVyIE1hY2hpbmUiKTsKCQlzZXREZWZhdWx0Q2xvc2VPcGVyYXRpb24oRVhJVF9PTl9DTE9TRSk7CgkJCgkJdGV4dEFyZWEuYWRkS2V5TGlzdGVuZXIobmV3IE15S2V5TGlzdGVuZXIoKSk7CgkJc2Nyb2xsUGFuZS5nZXRWZXJ0aWNhbFNjcm9sbEJhcigpLnNldFVuaXRJbmNyZW1lbnQoMTApOyAvL3NldHMgdGhlIHNjcm9sbC1zcGVlZAoJCQoJCWxpbmVOdW1iZXJpbmcuc2V0TGF5b3V0KG5ldyBHcmlkTGF5b3V0KG51bWJlck9mTGluZXMsIDIpKTsKCQlmb3IoaW50IGk9MDsgaTxudW1iZXJPZkxpbmVzOyArK2kpIHsKCQkJaWYobnVtYmVyT2ZMaW5lczwxMCkgewoJCQkJbGluZU51bWJlcmluZy5hZGQobmV3IEpMYWJlbChTdHJpbmcudmFsdWVPZihudW1iZXJPZkxpbmVzKSsiICAgIikpOwoJCQl9IGVsc2UgewoJCQkJbGluZU51bWJlcmluZy5hZGQobmV3IEpMYWJlbChTdHJpbmcudmFsdWVPZihudW1iZXJPZkxpbmVzKSkpOwoJCQl9CgkJCWxpbmVOdW1iZXJpbmcuYWRkKG5ldyBKTGFiZWwoIjoiKSk7CgkJfQoJCQoJCXBhbmVsTGVmdC5hZGQobGluZU51bWJlcmluZyk7CgkJcGFuZWxMZWZ0LmFkZCh0ZXh0QXJlYSk7CgkJCgkJcmVzZXQoKTsKCQkKCQlhZGQoc2Nyb2xsUGFuZSk7CgkJYWRkKHBhbmVsUmlnaHQpOwoJCXNldFZpc2libGUodHJ1ZSk7Cgl9CgkKCXB1YmxpYyBjbGFzcyBNeUtleUxpc3RlbmVyIGltcGxlbWVudHMgS2V5TGlzdGVuZXJ7CgkJQE92ZXJyaWRlCgkJcHVibGljIHZvaWQga2V5UHJlc3NlZChLZXlFdmVudCBlKSB7CgkJCWlmKGUuZ2V0S2V5Q29kZSgpID09IEtleUV2ZW50LlZLX0VOVEVSKSB7CgkJCQlTeXN0ZW0ub3V0LnByaW50bG4oIkVOVEVSICIgKyB0ZXh0QXJlYS5nZXRMaW5lQ291bnQoKSsiICIrbnVtYmVyT2ZMaW5lcyk7CgkJCQkvL1N5c3RlbS5vdXQucHJpbnRsbih0ZXh0QXJlYS5nZXRUZXh0KCkpOwoJCQkJbnVtYmVyT2ZMaW5lcyA9IHRleHRBcmVhLmdldExpbmVDb3VudCgpKzE7CgkJCQlsaW5lTnVtYmVyaW5nLnNldExheW91dChuZXcgR3JpZExheW91dChudW1iZXJPZkxpbmVzLCAyKSk7CgkJCQlpZihudW1iZXJPZkxpbmVzPDEwKSB7CgkJCQkJbGluZU51bWJlcmluZy5hZGQobmV3IEpMYWJlbChTdHJpbmcudmFsdWVPZihudW1iZXJPZkxpbmVzKSsiICAgIikpOwoJCQkJfSBlbHNlIHsKCQkJCQlsaW5lTnVtYmVyaW5nLmFkZChuZXcgSkxhYmVsKFN0cmluZy52YWx1ZU9mKG51bWJlck9mTGluZXMpKSk7CgkJCQl9CgkJCQlsaW5lTnVtYmVyaW5nLmFkZChuZXcgSkxhYmVsKCI6IikpOwoJCQl9CgkJCQoJCQlpZihlLmdldEtleUNvZGUoKSA9PSBLZXlFdmVudC5WS19CQUNLX1NQQUNFKSB7CgkJCQlTeXN0ZW0ub3V0LnByaW50bG4oIkJBQ0tTUEFDRSAiICsgdGV4dEFyZWEuZ2V0TGluZUNvdW50KCkrIiAiK251bWJlck9mTGluZXMpOwoJCQkJLy9TeXN0ZW0ub3V0LnByaW50bG4odGV4dEFyZWEuZ2V0VGV4dCgpKTsKCQkJCWlmKHRleHRBcmVhLmdldExpbmVDb3VudCgpID09IG51bWJlck9mTGluZXMpIHsKCQkJCQl0cnkgewoJCQkJCQlSb2JvdCByID0gbmV3IFJvYm90KCk7CgkJCQkJCVN5c3RlbS5vdXQucHJpbnRsbigiQkFDVkNLIik7CgkJCQkJCXIua2V5UHJlc3MoS2V5RXZlbnQuVktfQkFDS19TUEFDRSk7CgkJCQkJCXIua2V5UmVsZWFzZShLZXlFdmVudC5WS19CQUNLX1NQQUNFKTsKCQkJCQkJU3lzdGVtLm91dC5wcmludGxuKHRleHRBcmVhLmdldExpbmVDb3VudCgpKyIgIitudW1iZXJPZkxpbmVzKTsKCQkJCQkJaWYodGV4dEFyZWEuZ2V0TGluZUNvdW50KCkgIT0gbnVtYmVyT2ZMaW5lcykgewoJCQkJCQkJbnVtYmVyT2ZMaW5lcyA9IHRleHRBcmVhLmdldExpbmVDb3VudCgpLTE7CgkJCQkJCQlsaW5lTnVtYmVyaW5nLnNldExheW91dChuZXcgR3JpZExheW91dChudW1iZXJPZkxpbmVzLCAyKSk7CgkJCQkJCQlsaW5lTnVtYmVyaW5nLnJlbW92ZShsaW5lTnVtYmVyaW5nLmdldENvbXBvbmVudENvdW50KCktMSk7CgkJCQkJCQlsaW5lTnVtYmVyaW5nLnJlbW92ZShsaW5lTnVtYmVyaW5nLmdldENvbXBvbmVudENvdW50KCktMSk7CgkJCQkJCX0KCQkJCQl9Y2F0Y2goRXhjZXB0aW9uIGV4KSB7fQoJCQkJfQoJCQl9CgkJfQoKCQlAT3ZlcnJpZGUKCQlwdWJsaWMgdm9pZCBrZXlSZWxlYXNlZChLZXlFdmVudCBlKSB7fQoKCQlAT3ZlcnJpZGUKCQlwdWJsaWMgdm9pZCBrZXlUeXBlZChLZXlFdmVudCBlKSB7fQoJfQoJCglwdWJsaWMgU3RyaW5nIGdldEZ1bGxUZXh0KCkgewoJCXJldHVybiB0ZXh0QXJlYS5nZXRUZXh0KCk7Cgl9CgoJLy9saW5lIGlzIHRoZSBzYW1lIG51bWJlciBhcyB0aGUgbnVtYmVyaW5nIG9mIHRoZSBsaW5lcyBvbiB0aGUgcmlnaHQgc2lkZSAKCXB1YmxpYyBTdHJpbmcgZ2V0VGV4dEluTGluZShpbnQgbGluZSkgewoJCVN0cmluZyByZXQgPSB0ZXh0QXJlYS5nZXRUZXh0KCk7CgkJZm9yKGludCBpPTA7IGk8bGluZS0xOyArK2kpIHsKCQkJcmV0ID0gcmV0LnN1YnN0cmluZyhyZXQuaW5kZXhPZigiXG4iKSsxKTsKCQl9CgkJaWYocmV0LmNvbnRhaW5zKCJcbiIpKXJldCA9IHJldC5zdWJzdHJpbmcoMCwgcmV0LmluZGV4T2YoIlxuIikpOwoJCQoJCXJldHVybiByZXQ7Cgl9CgkKCS8vY2FsbCB0aGlzIG1ldGhvZCwgdG8gdXBkYXRlIHRoZSB2YWx1ZXMgCglwdWJsaWMgSlBhbmVsIHJpZ2h0UGFuZWwoYnl0ZVtdIGJ5KSB7CgkJSlBhbmVsIHJldCA9IG5ldyBKUGFuZWwoKTsKCQlyZXQuc2V0TGF5b3V0KG5ldyBHcmlkTGF5b3V0KDE5LCAyLCA0MCwgMCkpOwoJCQoJCWxhYmVsc1swXVswXSA9IG5ldyBKTGFiZWwoIlNSIik7CgkJbGFiZWxzWzBdWzFdID0gbmV3IEpMYWJlbCgiQloiKTsKCQlsYWJlbHNbMF1bMl0gPSBuZXcgSkxhYmVsKCJBIik7CgkJCgkJZm9yIChpbnQgaT0wOyBpPDE1OyArK2kpIHsKCQkJbGFiZWxzWzBdW2krM10gPSBuZXcgSkxhYmVsKCJSIisoaSsxKSk7CgkJfQoJCQoJCWZvcihpbnQgaT0wOyBpPDE4OyBpKyspIHsKCQkJbGFiZWxzWzFdW2ldID0gbmV3IEpMYWJlbChTdHJpbmcuZm9ybWF0KCIlOHMiLCBJbnRlZ2VyLnRvQmluYXJ5U3RyaW5nKGJ5W2ldICYgMHhGRikpLnJlcGxhY2UoJyAnLCAnMCcpKTsKCQl9CgkJCgkJZm9yKGludCBpPTA7IGk8MTg7IGkrKykgewoJCQlyZXQuYWRkKGxhYmVsc1swXVtpXSk7CgkJCXJldC5hZGQobGFiZWxzWzFdW2ldKTsKCQl9CgkJCgkJc3RhcnQgPSBuZXcgSkJ1dHRvbihuZXcgQWJzdHJhY3RBY3Rpb24oIlN0YXJ0Iil7CiAgICAgICAgICAgIHB1YmxpYyB2b2lkIGFjdGlvblBlcmZvcm1lZChBY3Rpb25FdmVudCBlKSB7CiAgICAgICAgICAgIAlzdGFydCgpOwogICAgICAgICAgICB9CgkJfSk7CgoJCXJlc2V0ID0gbmV3IEpCdXR0b24obmV3IEFic3RyYWN0QWN0aW9uKCJSZXNldCIpewogICAgICAgICAgICBwdWJsaWMgdm9pZCBhY3Rpb25QZXJmb3JtZWQoQWN0aW9uRXZlbnQgZSkgewogICAgICAgICAgICAJcmVzZXQoKTsKICAgICAgICAgICAgfQoJCX0pOwoJCQoJCXJldC5hZGQoc3RhcnQpOwoJCXJldC5hZGQocmVzZXQpOwoJCQoJCXJldHVybiByZXQ7Cgl9CgkKCXByaXZhdGUgdm9pZCByZXNldCgpIHsKCQlzdG9wID0gZmFsc2U7CgkJU1IgPSAwOwoJCUJaID0gMTsKCQlBID0gMDsKCQlSMSA9IDA7CgkJUjIgPSAwOwoJCVIzID0gMDsKCQlSNCA9IDA7CgkJUjUgPSAwOwoJCVI2ID0gMDsKCQlSNyA9IDA7CgkJUjggPSAwOwoJCVI5ID0gMDsKCQlSMTAgPSAwOwoJCVIxMSA9IDA7CgkJUjEyID0gMDsKCQlSMTMgPSAwOwoJCVIxNCA9IDA7CgkJUjE1ID0gMDsKCQkKCQlieXRlW10gYnkgPSB7U1IsIEJaLCBBLCBSMSwgUjIsIFIzLCBSNCwgUjUsIFI2LCBSNywgUjgsIFI5LCBSMTAsIFIxMSwgUjEyLCBSMTMsIFIxNCwgUjE1fTsKCQlwYW5lbFJpZ2h0ID0gcmlnaHRQYW5lbChieSk7Cgl9CgkKCXByaXZhdGUgdm9pZCBzdGFydCgpIHsKCQl3aGlsZSghc3RvcCkgewoJCQljaGVjayhnZXRUZXh0SW5MaW5lKEJaKSk7CgkJfQoJCWJ5dGVbXSBieSA9IHtTUiwgQlosIEEsIFIxLCBSMiwgUjMsIFI0LCBSNSwgUjYsIFI3LCBSOCwgUjksIFIxMCwgUjExLCBSMTIsIFIxMywgUjE0LCBSMTV9OwoJCXBhbmVsUmlnaHQgPSByaWdodFBhbmVsKGJ5KTsKCX0KCQoJcHJpdmF0ZSB2b2lkIGRlZihTdHJpbmcgaW5wdXQpIHsvL2RhZmF1bHQKCQlTeXN0ZW0ub3V0LnByaW50bG4oInVua25vd24gY29tbWFuZDogXCIiICsgaW5wdXQgKyJcIiIpOwoJfQoJCgkvL2NhbGxzIHRoZSByaWdodCBtZXRob2QgCglwcml2YXRlIHZvaWQgZXhlY3V0ZShTdHJpbmcgY29tbWFuZCwgU3RyaW5nIHJlc3QpIHsKCQlpZihyZXN0Lmxlbmd0aCgpPjApIHsKCQkJaWYocmVzdC5jaGFyQXQoMCkgPT0gJyAnKSB7CgkJCQlzd2l0Y2goY29tbWFuZCkgewoJCQkJY2FzZSAiQUREIjoKCQkJCQlhZGQoSW50ZWdlci52YWx1ZU9mKHJlc3Quc3Vic3RyaW5nKDEpKSk7CgkJCQkJYnJlYWs7CgkJCQljYXNlICJETE9BRCI6CgkJCQkJZGxvYWQoSW50ZWdlci52YWx1ZU9mKHJlc3Quc3Vic3RyaW5nKDEpKSk7CgkJCQkJYnJlYWs7CgkJCQljYXNlICJESVYiOgoJCQkJCWRpdihJbnRlZ2VyLnZhbHVlT2YocmVzdC5zdWJzdHJpbmcoMSkpKTsKCQkJCQlicmVhazsKCQkJCWNhc2UgIkpFUSI6CgkJCQkJamVxKEludGVnZXIudmFsdWVPZihyZXN0LnN1YnN0cmluZygxKSkpOwoJCQkJCWJyZWFrOwoJCQkJY2FzZSAiSkdFIjoKCQkJCQlqZ2UoSW50ZWdlci52YWx1ZU9mKHJlc3Quc3Vic3RyaW5nKDEpKSk7CgkJCQkJYnJlYWs7CgkJCQljYXNlICJKR1QiOgoJCQkJCWpndChJbnRlZ2VyLnZhbHVlT2YocmVzdC5zdWJzdHJpbmcoMSkpKTsKCQkJCQlicmVhazsKCQkJCWNhc2UgIkpMRSI6CgkJCQkJamxlKEludGVnZXIudmFsdWVPZihyZXN0LnN1YnN0cmluZygxKSkpOwoJCQkJCWJyZWFrOwoJCQkJY2FzZSAiSkxUIjoKCQkJCQlqbHQoSW50ZWdlci52YWx1ZU9mKHJlc3Quc3Vic3RyaW5nKDEpKSk7CgkJCQkJYnJlYWs7CgkJCQljYXNlICJKTkUiOgoJCQkJCWpuZShJbnRlZ2VyLnZhbHVlT2YocmVzdC5zdWJzdHJpbmcoMSkpKTsKCQkJCQlicmVhazsKCQkJCWNhc2UgIkpVTVAiOgoJCQkJCWp1bXAoSW50ZWdlci52YWx1ZU9mKHJlc3Quc3Vic3RyaW5nKDEpKSk7CgkJCQkJYnJlYWs7CgkJCQljYXNlICJMT0FEIjoKCQkJCQlsb2FkKEludGVnZXIudmFsdWVPZihyZXN0LnN1YnN0cmluZygxKSkpOwoJCQkJCWJyZWFrOwoJCQkJY2FzZSAiTVVMVCI6CgkJCQkJbXVsdChJbnRlZ2VyLnZhbHVlT2YocmVzdC5zdWJzdHJpbmcoMSkpKTsKCQkJCQlicmVhazsKCQkJCWNhc2UgIlNUT1JFIjoKCQkJCQlzdG9yZShJbnRlZ2VyLnZhbHVlT2YocmVzdC5zdWJzdHJpbmcoMSkpKTsKCQkJCQlicmVhazsKCQkJCWNhc2UgIlNVQiI6CgkJCQkJc3ViKEludGVnZXIudmFsdWVPZihyZXN0LnN1YnN0cmluZygxKSkpOwoJCQkJCWJyZWFrOwoJCQkJfQoJCQl9ZWxzZSB7CgkJCQlkZWYoY29tbWFuZCtyZXN0KTsKCQkJfQoJCQkKCQl9ZWxzZSB7CgkJCWlmKGNvbW1hbmQuZXF1YWxzKCJFTkQiKSkgewoJCQkJZW5kKCk7CgkJCX1lbHNlIHsKCQkJCWRlZihjb21tYW5kK3Jlc3QpOwoJCQl9CgkJfQoJfQoJCglwcml2YXRlIHZvaWQgZW5kKCkgewoJCXN0b3AgPSB0cnVlOwoJCUJaKys7Cgl9CgkKCXByaXZhdGUgdm9pZCBhZGQoaW50IG51bWJlcikgewoJCWludCBpOwoJCWludCB0ZW1wOwoJCXN3aXRjaChudW1iZXIpIHsKCQkJY2FzZSAxOiBpID0gUjE7CgkJCWNhc2UgMjogaSA9IFIyOwoJCQljYXNlIDM6IGkgPSBSMzsKCQkJY2FzZSA0OiBpID0gUjQ7CgkJCWNhc2UgNTogaSA9IFI1OwoJCQljYXNlIDY6IGkgPSBSNjsKCQkJY2FzZSA3OiBpID0gUjc7CgkJCWNhc2UgODogaSA9IFI4OwoJCQljYXNlIDk6IGkgPSBSOTsKCQkJY2FzZSAxMDogaSA9IFIxMDsKCQkJY2FzZSAxMTogaSA9IFIxMTsKCQkJY2FzZSAxMjogaSA9IFIxMjsKCQkJY2FzZSAxMzogaSA9IFIxMzsKCQkJY2FzZSAxNDogaSA9IFIxNDsKCQkJY2FzZSAxNTogaSA9IFIxNTsKCQkJZGVmYXVsdDogCgkJCQlTeXN0ZW0ub3V0LnByaW50bG4obnVtYmVyKyJpcyBub3QgYSB2YWxpZCByZWdpc3RlciEiKTsKCQkJCWk9MDsKCQkJCWVuZCgpOwoJCX0KCQl0ZW1wPUEraTsKCQkKCQlTUiA9IChieXRlKSAoU1IgJiBCeXRlLnZhbHVlT2YoIjExMTExMTAwIikpOyAvL3NldCBsYXN0IDIgYml0IHRvIDAKCQlpZih0ZW1wPjApIHsKCQkJU1IgPSAoYnl0ZSkgKFNSIHwgQnl0ZS52YWx1ZU9mKCIwMDAwMDAxMCIpKTsgLy9zZXQgYml0IGJlZm9yZSBsYXN0IHRvIDEKCQl9ZWxzZSB7CgkJCWlmKHRlbXA8MCkgewoJCQkJU1IgPSAoYnl0ZSkgKFNSIHwgQnl0ZS52YWx1ZU9mKCIwMDAwMDAwMSIpKTsvL3NldCBsYXN0IGJpdCB0byAxCgkJCX0KCQl9CgkJaWYodGVtcDwxMjgmJnRlbXA+LTEyOSkgewoJCQlBPShieXRlKXRlbXA7CgkJCVNSID0gKGJ5dGUpIChTUiAmIEJ5dGUudmFsdWVPZigiMTExMTEwMTEiKSk7Ly9zZXQgNi4gYml0IHRvIDAKCQkJCQkJCQkJCS8vICAgICAgICAgICAxMTExMTExMTExMjIyMjIyMjIyMjMzMwoJfWVsc2UgewkJCQkJCQkJLy8gIDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyCgkJCUEgPSAoYnl0ZSkodGVtcCAmIEJ5dGUudmFsdWVPZigiMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMTExMTExMTEiKSk7CgkJCVNSID0gKGJ5dGUpIChTUiB8IEJ5dGUudmFsdWVPZigiMDAwMDAxMDAiKSk7Ly9zZXQgNi4gYml0IHRvIDEKCQl9CgkJCgkJQlorKzsKCQkKCX0KCQoJcHJpdmF0ZSB2b2lkIGRsb2FkKGludCBudW1iZXIpIHsKCQlpZihudW1iZXI8MTI4JiZudW1iZXI+LTEyOSkgewoJCQlBID0gKGJ5dGUpbnVtYmVyOwoJCX1lbHNlIHsKCQkJU3lzdGVtLm91dC5wcmludGxuKG51bWJlcisiIGlzIHRvbyBiaWciKTsKCQl9Cgl9CgkKCXByaXZhdGUgdm9pZCBkaXYoaW50IG51bWJlcikgewoJCWludCBpOwoJCWludCB0ZW1wOwoJCXN3aXRjaChudW1iZXIpIHsKCQkJY2FzZSAxOiBpID0gUjE7CgkJCWNhc2UgMjogaSA9IFIyOwoJCQljYXNlIDM6IGkgPSBSMzsKCQkJY2FzZSA0OiBpID0gUjQ7CgkJCWNhc2UgNTogaSA9IFI1OwoJCQljYXNlIDY6IGkgPSBSNjsKCQkJY2FzZSA3OiBpID0gUjc7CgkJCWNhc2UgODogaSA9IFI4OwoJCQljYXNlIDk6IGkgPSBSOTsKCQkJY2FzZSAxMDogaSA9IFIxMDsKCQkJY2FzZSAxMTogaSA9IFIxMTsKCQkJY2FzZSAxMjogaSA9IFIxMjsKCQkJY2FzZSAxMzogaSA9IFIxMzsKCQkJY2FzZSAxNDogaSA9IFIxNDsKCQkJY2FzZSAxNTogaSA9IFIxNTsKCQkJZGVmYXVsdDogCgkJCQlTeXN0ZW0ub3V0LnByaW50bG4obnVtYmVyKyJpcyBub3QgYSB2YWxpZCByZWdpc3RlciEiKTsKCQkJCWk9MDsKCQkJCWVuZCgpOwoJCX0KCQl0ZW1wPUEvaTsKCQkKCQlTUiA9IChieXRlKSAoU1IgJiBCeXRlLnZhbHVlT2YoIjExMTExMTAwIikpOyAvL3NldCBsYXN0IDIgYml0IHRvIDAKCQlpZih0ZW1wPjApIHsKCQkJU1IgPSAoYnl0ZSkgKFNSIHwgQnl0ZS52YWx1ZU9mKCIwMDAwMDAxMCIpKTsgLy9zZXQgYml0IGJlZm9yZSBsYXN0IHRvIDEKCQl9ZWxzZSB7CgkJCWlmKHRlbXA8MCkgewoJCQkJU1IgPSAoYnl0ZSkgKFNSIHwgQnl0ZS52YWx1ZU9mKCIwMDAwMDAwMSIpKTsvL3NldCBsYXN0IGJpdCB0byAxCgkJCX0KCQl9CgkJaWYodGVtcDwxMjgmJnRlbXA+LTEyOSkgewoJCQlBPShieXRlKXRlbXA7CgkJCVNSID0gKGJ5dGUpIChTUiAmIEJ5dGUudmFsdWVPZigiMTExMTEwMTEiKSk7Ly9zZXQgNi4gYml0IHRvIDAKCQkJCQkJCQkJCS8vICAgICAgICAgICAxMTExMTExMTExMjIyMjIyMjIyMjMzMwoJCX1lbHNlIHsJCQkJCQkJLy8gIDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyCgkJCUEgPSAoYnl0ZSkodGVtcCAmIEJ5dGUudmFsdWVPZigiMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMTExMTExMTEiKSk7CgkJCVNSID0gKGJ5dGUpIChTUiB8IEJ5dGUudmFsdWVPZigiMDAwMDAxMDAiKSk7Ly9zZXQgNi4gYml0IHRvIDEKCQl9CgkJQlorKzsKCX0KCQoJcHJpdmF0ZSB2b2lkIGplcShpbnQgbnVtYmVyKSB7CgkJU3RyaW5nIHN0YXR1cyA9IFN0cmluZy5mb3JtYXQoIiU4cyIsIEludGVnZXIudG9CaW5hcnlTdHJpbmcoU1IgJiAweEZGKSkucmVwbGFjZSgnICcsICcwJyk7CgkJaWYoc3RhdHVzLmNoYXJBdCg2KT09JzAnJiZzdGF0dXMuY2hhckF0KDcpPT0nMCcpIHsKCQkJQlo9KGJ5dGUpbnVtYmVyOwoJCX1lbHNlIHsKCQkJQlorKzsKCQl9Cgl9CgkKCXByaXZhdGUgdm9pZCBqZ2UoaW50IG51bWJlcikgewoJCVN0cmluZyBzdGF0dXMgPSBTdHJpbmcuZm9ybWF0KCIlOHMiLCBJbnRlZ2VyLnRvQmluYXJ5U3RyaW5nKFNSICYgMHhGRikpLnJlcGxhY2UoJyAnLCAnMCcpOwoJCWlmKHN0YXR1cy5jaGFyQXQoNyk9PScwJykgewoJCQlCWj0oYnl0ZSludW1iZXI7CgkJfWVsc2UgewoJCQlCWisrOwoJCX0KCX0KCQoJcHJpdmF0ZSB2b2lkIGpndChpbnQgbnVtYmVyKSB7CgkJU3RyaW5nIHN0YXR1cyA9IFN0cmluZy5mb3JtYXQoIiU4cyIsIEludGVnZXIudG9CaW5hcnlTdHJpbmcoU1IgJiAweEZGKSkucmVwbGFjZSgnICcsICcwJyk7CgkJaWYoc3RhdHVzLmNoYXJBdCg2KT09JzEnKSB7CgkJCUJaPShieXRlKW51bWJlcjsKCQl9ZWxzZSB7CgkJCUJaKys7CgkJfQoJfQoJCglwcml2YXRlIHZvaWQgamxlKGludCBudW1iZXIpIHsKCQlTdHJpbmcgc3RhdHVzID0gU3RyaW5nLmZvcm1hdCgiJThzIiwgSW50ZWdlci50b0JpbmFyeVN0cmluZyhTUiAmIDB4RkYpKS5yZXBsYWNlKCcgJywgJzAnKTsKCQlpZihzdGF0dXMuY2hhckF0KDYpPT0nMCcpIHsKCQkJQlo9KGJ5dGUpbnVtYmVyOwoJCX1lbHNlIHsKCQkJQlorKzsKCQl9Cgl9CgkKCXByaXZhdGUgdm9pZCBqbHQoaW50IG51bWJlcikgewoJCVN0cmluZyBzdGF0dXMgPSBTdHJpbmcuZm9ybWF0KCIlOHMiLCBJbnRlZ2VyLnRvQmluYXJ5U3RyaW5nKFNSICYgMHhGRikpLnJlcGxhY2UoJyAnLCAnMCcpOwoJCWlmKHN0YXR1cy5jaGFyQXQoNyk9PScwJykgewoJCQlCWj0oYnl0ZSludW1iZXI7CgkJfWVsc2UgewoJCQlCWisrOwoJCX0KCX0KCQoJcHJpdmF0ZSB2b2lkIGpuZShpbnQgbnVtYmVyKSB7CgkJU3RyaW5nIHN0YXR1cyA9IFN0cmluZy5mb3JtYXQoIiU4cyIsIEludGVnZXIudG9CaW5hcnlTdHJpbmcoU1IgJiAweEZGKSkucmVwbGFjZSgnICcsICcwJyk7CgkJaWYoc3RhdHVzLmNoYXJBdCg2KT09JzEnfHxzdGF0dXMuY2hhckF0KDcpPT0nMScpIHsKCQkJQlo9KGJ5dGUpbnVtYmVyOwoJCX1lbHNlIHsKCQkJQlorKzsKCQl9Cgl9CgkKCXByaXZhdGUgdm9pZCBqdW1wKGludCBudW1iZXIpIHsKCQlCWiA9IChieXRlKW51bWJlcjsKCX0KCQoJcHJpdmF0ZSB2b2lkIGxvYWQoaW50IG51bWJlcikgewoJCWludCBpOwoJCXN3aXRjaChudW1iZXIpIHsKCQkJY2FzZSAxOiBpID0gUjE7CgkJCWNhc2UgMjogaSA9IFIyOwoJCQljYXNlIDM6IGkgPSBSMzsKCQkJY2FzZSA0OiBpID0gUjQ7CgkJCWNhc2UgNTogaSA9IFI1OwoJCQljYXNlIDY6IGkgPSBSNjsKCQkJY2FzZSA3OiBpID0gUjc7CgkJCWNhc2UgODogaSA9IFI4OwoJCQljYXNlIDk6IGkgPSBSOTsKCQkJY2FzZSAxMDogaSA9IFIxMDsKCQkJY2FzZSAxMTogaSA9IFIxMTsKCQkJY2FzZSAxMjogaSA9IFIxMjsKCQkJY2FzZSAxMzogaSA9IFIxMzsKCQkJY2FzZSAxNDogaSA9IFIxNDsKCQkJY2FzZSAxNTogaSA9IFIxNTsKCQkJZGVmYXVsdDogCgkJCQlTeXN0ZW0ub3V0LnByaW50bG4obnVtYmVyKyJpcyBub3QgYSB2YWxpZCByZWdpc3RlciEiKTsKCQkJCWk9MDsKCQkJCWVuZCgpOwoJCX0KCQlBPShieXRlKWk7CgkJCgkJU1IgPSAoYnl0ZSkgKFNSICYgQnl0ZS52YWx1ZU9mKCIxMTExMTEwMCIpKTsgLy9zZXQgbGFzdCAyIGJpdCB0byAwCgkJaWYoQT4wKSB7CgkJCVNSID0gKGJ5dGUpIChTUiB8IEJ5dGUudmFsdWVPZigiMDAwMDAwMTAiKSk7IC8vc2V0IGJpdCBiZWZvcmUgbGFzdCB0byAxCgkJfWVsc2UgewoJCQlpZihBPDApIHsKCQkJCVNSID0gKGJ5dGUpIChTUiB8IEJ5dGUudmFsdWVPZigiMDAwMDAwMDEiKSk7Ly9zZXQgbGFzdCBiaXQgdG8gMQoJCQl9CgkJfQoJCUJaKys7Cgl9CgkKCXByaXZhdGUgdm9pZCBtdWx0KGludCBudW1iZXIpIHsKCQlpbnQgaTsKCQlpbnQgdGVtcDsKCQlzd2l0Y2gobnVtYmVyKSB7CgkJCWNhc2UgMTogaSA9IFIxOwoJCQljYXNlIDI6IGkgPSBSMjsKCQkJY2FzZSAzOiBpID0gUjM7CgkJCWNhc2UgNDogaSA9IFI0OwoJCQljYXNlIDU6IGkgPSBSNTsKCQkJY2FzZSA2OiBpID0gUjY7CgkJCWNhc2UgNzogaSA9IFI3OwoJCQljYXNlIDg6IGkgPSBSODsKCQkJY2FzZSA5OiBpID0gUjk7CgkJCWNhc2UgMTA6IGkgPSBSMTA7CgkJCWNhc2UgMTE6IGkgPSBSMTE7CgkJCWNhc2UgMTI6IGkgPSBSMTI7CgkJCWNhc2UgMTM6IGkgPSBSMTM7CgkJCWNhc2UgMTQ6IGkgPSBSMTQ7CgkJCWNhc2UgMTU6IGkgPSBSMTU7CgkJCWRlZmF1bHQ6IAoJCQkJU3lzdGVtLm91dC5wcmludGxuKG51bWJlcisiaXMgbm90IGEgdmFsaWQgcmVnaXN0ZXIhIik7CgkJCQlpPTA7CgkJCQllbmQoKTsKCQl9CgkJdGVtcD1BKmk7CgkJCgkJU1IgPSAoYnl0ZSkgKFNSICYgQnl0ZS52YWx1ZU9mKCIxMTExMTEwMCIpKTsgLy9zZXQgbGFzdCAyIGJpdCB0byAwCgkJaWYodGVtcD4wKSB7CgkJCVNSID0gKGJ5dGUpIChTUiB8IEJ5dGUudmFsdWVPZigiMDAwMDAwMTAiKSk7IC8vc2V0IGJpdCBiZWZvcmUgbGFzdCB0byAxCgkJfWVsc2UgewoJCQlpZih0ZW1wPDApIHsKCQkJCVNSID0gKGJ5dGUpIChTUiB8IEJ5dGUudmFsdWVPZigiMDAwMDAwMDEiKSk7Ly9zZXQgbGFzdCBiaXQgdG8gMQoJCQl9CgkJfQoJCWlmKHRlbXA8MTI4JiZ0ZW1wPi0xMjkpIHsKCQkJQT0oYnl0ZSl0ZW1wOwoJCQlTUiA9IChieXRlKSAoU1IgJiBCeXRlLnZhbHVlT2YoIjExMTExMDExIikpOy8vc2V0IDYuIGJpdCB0byAwCgkJCQkJCQkJCQkvLyAgICAgICAgICAgMTExMTExMTExMTIyMjIyMjIyMjIzMzMKCQl9ZWxzZSB7CQkJCQkJCS8vICAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMgoJCQlBID0gKGJ5dGUpKHRlbXAgJiBCeXRlLnZhbHVlT2YoIjAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDExMTExMTExIikpOwoJCQlTUiA9IChieXRlKSAoU1IgfCBCeXRlLnZhbHVlT2YoIjAwMDAwMTAwIikpOy8vc2V0IDYuIGJpdCB0byAxCgkJfQoJCUJaKys7Cgl9CgkKCXByaXZhdGUgdm9pZCBzdG9yZShpbnQgbnVtYmVyKSB7CgkJc3dpdGNoKG51bWJlcikgewoJCQljYXNlIDE6IFIxID0gQTsKCQkJY2FzZSAyOiBSMiA9IEE7CgkJCWNhc2UgMzogUjMgPSBBOwoJCQljYXNlIDQ6IFI0ID0gQTsKCQkJY2FzZSA1OiBSNSA9IEE7CgkJCWNhc2UgNjogUjYgPSBBOwoJCQljYXNlIDc6IFI3ID0gQTsKCQkJY2FzZSA4OiBSOCA9IEE7CgkJCWNhc2UgOTogUjkgPSBBOwoJCQljYXNlIDEwOiBSMTAgPSBBOwoJCQljYXNlIDExOiBSMTEgPSBBOwoJCQljYXNlIDEyOiBSMTIgPSBBOwoJCQljYXNlIDEzOiBSMTMgPSBBOwoJCQljYXNlIDE0OiBSMTQgPSBBOwoJCQljYXNlIDE1OiBSMTUgPSBBOwoJCQlkZWZhdWx0OiAKCQkJCVN5c3RlbS5vdXQucHJpbnRsbihudW1iZXIrImlzIG5vdCBhIHZhbGlkIHJlZ2lzdGVyISIpOwoJCQkJZW5kKCk7CgkJfQoJfQoJCglwcml2YXRlIHZvaWQgc3ViKGludCBudW1iZXIpIHsKCQlpbnQgaTsKCQlpbnQgdGVtcDsKCQlzd2l0Y2gobnVtYmVyKSB7CgkJCWNhc2UgMTogaSA9IFIxOwoJCQljYXNlIDI6IGkgPSBSMjsKCQkJY2FzZSAzOiBpID0gUjM7CgkJCWNhc2UgNDogaSA9IFI0OwoJCQljYXNlIDU6IGkgPSBSNTsKCQkJY2FzZSA2OiBpID0gUjY7CgkJCWNhc2UgNzogaSA9IFI3OwoJCQljYXNlIDg6IGkgPSBSODsKCQkJY2FzZSA5OiBpID0gUjk7CgkJCWNhc2UgMTA6IGkgPSBSMTA7CgkJCWNhc2UgMTE6IGkgPSBSMTE7CgkJCWNhc2UgMTI6IGkgPSBSMTI7CgkJCWNhc2UgMTM6IGkgPSBSMTM7CgkJCWNhc2UgMTQ6IGkgPSBSMTQ7CgkJCWNhc2UgMTU6IGkgPSBSMTU7CgkJCWRlZmF1bHQ6IAoJCQkJU3lzdGVtLm91dC5wcmludGxuKG51bWJlcisiaXMgbm90IGEgdmFsaWQgcmVnaXN0ZXIhIik7CgkJCQlpPTA7CgkJCQllbmQoKTsKCQl9CgkJdGVtcD1BLWk7CgkJCgkJU1IgPSAoYnl0ZSkgKFNSICYgQnl0ZS52YWx1ZU9mKCIxMTExMTEwMCIpKTsgLy9zZXQgbGFzdCAyIGJpdCB0byAwCgkJaWYodGVtcD4wKSB7CgkJCVNSID0gKGJ5dGUpIChTUiB8IEJ5dGUudmFsdWVPZigiMDAwMDAwMTAiKSk7IC8vc2V0IGJpdCBiZWZvcmUgbGFzdCB0byAxCgkJfWVsc2UgewoJCQlpZih0ZW1wPDApIHsKCQkJCVNSID0gKGJ5dGUpIChTUiB8IEJ5dGUudmFsdWVPZigiMDAwMDAwMDEiKSk7Ly9zZXQgbGFzdCBiaXQgdG8gMQoJCQl9CgkJfQoJCWlmKHRlbXA8MTI4JiZ0ZW1wPi0xMjkpIHsKCQkJQT0oYnl0ZSl0ZW1wOwoJCQlTUiA9IChieXRlKSAoU1IgJiBCeXRlLnZhbHVlT2YoIjExMTExMDExIikpOy8vc2V0IDYuIGJpdCB0byAwCgkJCQkJCQkJCQkvLyAgICAgICAgICAgMTExMTExMTExMTIyMjIyMjIyMjIzMzMKCQl9ZWxzZSB7CQkJCQkJCS8vICAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMgoJCQlBID0gKGJ5dGUpKHRlbXAgJiBCeXRlLnZhbHVlT2YoIjAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDExMTExMTExIikpOwoJCQlTUiA9IChieXRlKSAoU1IgfCBCeXRlLnZhbHVlT2YoIjAwMDAwMTAwIikpOy8vc2V0IDYuIGJpdCB0byAxCgkJfQoJCUJaKys7Cgl9CgkKCS8vc2VwYXJhdGVzIHRoZSBjb21tYW5kIGFuZCB0aGUgcmVzdAoJcHVibGljIHZvaWQgY2hlY2soU3RyaW5nIGlucHV0KSB7CgkJc3dpdGNoKGlucHV0LmNoYXJBdCgwKSl7CgkJY2FzZSAnQSc6Ly9BCgkJCXN3aXRjaChpbnB1dC5jaGFyQXQoMSkpewoJCQljYXNlICdEJzovL0FECgkJCQlzd2l0Y2goaW5wdXQuY2hhckF0KDIpKXsKCQkJCWNhc2UgJ0QnOi8vQURECgkJCQkJZXhlY3V0ZShpbnB1dC5zdWJzdHJpbmcoMCwgMyksIGlucHV0LnN1YnN0cmluZygzKSk7CgkJCQkJYnJlYWs7CgkJCQlkZWZhdWx0OgoJCQkJCWRlZihpbnB1dCk7CgkJCQkJYnJlYWs7CgkJCQl9CgkJCQlicmVhazsKCQkJZGVmYXVsdDoKCQkJCWRlZihpbnB1dCk7CgkJCQlicmVhazsKCQkJfQoJCQlicmVhazsKCQljYXNlICdEJzovL0QKCQkJc3dpdGNoKGlucHV0LmNoYXJBdCgxKSl7CgkJCWNhc2UgJ0wnOi8vREwKCQkJCXN3aXRjaChpbnB1dC5jaGFyQXQoMikpewoJCQkJY2FzZSAnTyc6Ly9ETE8KCQkJCQlzd2l0Y2goaW5wdXQuY2hhckF0KDMpKXsKCQkJCQljYXNlICdBJzovL0RMT0EKCQkJCQkJc3dpdGNoKGlucHV0LmNoYXJBdCg0KSl7CgkJCQkJCWNhc2UgJ0QnOi8vRExPQUQKCQkJCQkJCWV4ZWN1dGUoaW5wdXQuc3Vic3RyaW5nKDAsIDUpLCBpbnB1dC5zdWJzdHJpbmcoNSkpOwoJCQkJCQkJYnJlYWs7CgkJCQkJCWRlZmF1bHQ6CgkJCQkJCQlkZWYoaW5wdXQpOwoJCQkJCQkJYnJlYWs7CgkJCQkJCX0KCQkJCQkJYnJlYWs7CgkJCQkJZGVmYXVsdDoKCQkJCQkJZGVmKGlucHV0KTsKCQkJCQkJYnJlYWs7CgkJCQkJfQoJCQkJCWJyZWFrOwoJCQkJZGVmYXVsdDoKCQkJCQlkZWYoaW5wdXQpOwoJCQkJCWJyZWFrOwoJCQkJfQoJCQkJYnJlYWs7CgkJCWNhc2UgJ0knOi8vREkKCQkJCXN3aXRjaChpbnB1dC5jaGFyQXQoMikpewoJCQkJY2FzZSAnVic6Ly9ESVYKCQkJCQlleGVjdXRlKGlucHV0LnN1YnN0cmluZygwLCAzKSwgaW5wdXQuc3Vic3RyaW5nKDMpKTsKCQkJCQlicmVhazsKCQkJCWRlZmF1bHQ6CgkJCQkJZGVmKGlucHV0KTsKCQkJCQlicmVhazsKCQkJCX0KCQkJCWJyZWFrOwoJCQlkZWZhdWx0OgoJCQkJZGVmKGlucHV0KTsKCQkJCWJyZWFrOwoJCQl9CgkJCWJyZWFrOwoJCWNhc2UgJ0UnOi8vRQoJCQlzd2l0Y2goaW5wdXQuY2hhckF0KDEpKXsKCQkJY2FzZSAnTic6Ly9FTgoJCQkJc3dpdGNoKGlucHV0LmNoYXJBdCgyKSl7CgkJCQljYXNlICdEJzovL0VORAoJCQkJCWV4ZWN1dGUoaW5wdXQuc3Vic3RyaW5nKDAsIDMpLCBpbnB1dC5zdWJzdHJpbmcoMykpOwoJCQkJCWJyZWFrOwoJCQkJZGVmYXVsdDoKCQkJCQlkZWYoaW5wdXQpOwoJCQkJCWJyZWFrOwoJCQkJfQoJCQkJYnJlYWs7CgkJCWRlZmF1bHQ6CgkJCQlkZWYoaW5wdXQpOwoJCQkJYnJlYWs7CgkJCX0KCQkJYnJlYWs7CgkJCQoJCWNhc2UgJ0onOi8vSgoJCQlzd2l0Y2goaW5wdXQuY2hhckF0KDEpKXsKCQkJY2FzZSAnRSc6Ly9KRQoJCQkJc3dpdGNoKGlucHV0LmNoYXJBdCgyKSl7CgkJCQljYXNlICdRJzovL0pFUQoJCQkJCWV4ZWN1dGUoaW5wdXQuc3Vic3RyaW5nKDAsIDMpLCBpbnB1dC5zdWJzdHJpbmcoMykpOwoJCQkJCWJyZWFrOwoJCQkJZGVmYXVsdDoKCQkJCQlkZWYoaW5wdXQpOwoJCQkJCWJyZWFrOwoJCQkJfQoJCQkJYnJlYWs7CgkJCWRlZmF1bHQ6CgkJCQlkZWYoaW5wdXQpOwoJCQkJYnJlYWs7CgkJCWNhc2UgJ0cnOi8vSkcKCQkJCXN3aXRjaChpbnB1dC5jaGFyQXQoMikpewoJCQkJY2FzZSAnRSc6Ly9KR0UKCQkJCQlleGVjdXRlKGlucHV0LnN1YnN0cmluZygwLCAzKSwgaW5wdXQuc3Vic3RyaW5nKDMpKTsKCQkJCWNhc2UgJ1QnOi8vSkdUCgkJCQkJZXhlY3V0ZShpbnB1dC5zdWJzdHJpbmcoMCwgMyksIGlucHV0LnN1YnN0cmluZygzKSk7CgkJCQlkZWZhdWx0OgoJCQkJCWRlZihpbnB1dCk7CgkJCQl9CgkJCWNhc2UgJ0wnOi8vSkwKCQkJCXN3aXRjaChpbnB1dC5jaGFyQXQoMikpewoJCQkJY2FzZSAnRSc6Ly9KTEUKCQkJCQlleGVjdXRlKGlucHV0LnN1YnN0cmluZygwLCAzKSwgaW5wdXQuc3Vic3RyaW5nKDMpKTsKCQkJCWNhc2UgJ1QnOi8vSkxUCgkJCQkJZXhlY3V0ZShpbnB1dC5zdWJzdHJpbmcoMCwgMyksIGlucHV0LnN1YnN0cmluZygzKSk7CgkJCQlkZWZhdWx0OgoJCQkJCWRlZihpbnB1dCk7CgkJCQl9CgkJCWNhc2UgJ04nOi8vSk4KCQkJCXN3aXRjaChpbnB1dC5jaGFyQXQoMikpewoJCQkJY2FzZSAnRSc6Ly9KTkUKCQkJCQlleGVjdXRlKGlucHV0LnN1YnN0cmluZygwLCAzKSwgaW5wdXQuc3Vic3RyaW5nKDMpKTsKCQkJCWRlZmF1bHQ6CgkJCQkJZGVmKGlucHV0KTsKCQkJCX0KCQkJY2FzZSAnVSc6Ly9KVQoJCQkJc3dpdGNoKGlucHV0LmNoYXJBdCgyKSl7CgkJCQljYXNlICdNJzovL0pVTQoJCQkJCXN3aXRjaChpbnB1dC5jaGFyQXQoMykpewoJCQkJCWNhc2UgJ1AnOi8vSlVNUAoJCQkJCQlleGVjdXRlKGlucHV0LnN1YnN0cmluZygwLCA0KSwgaW5wdXQuc3Vic3RyaW5nKDQpKTsKCQkJCQlkZWZhdWx0OgoJCQkJCQlkZWYoaW5wdXQpOwoJCQkJCX0KCQkJCWRlZmF1bHQ6CgkJCQkJZGVmKGlucHV0KTsKCQkJCX0JCQkJCgkJCX0KCQljYXNlICdMJzovL0wKCQkJc3dpdGNoKGlucHV0LmNoYXJBdCgxKSl7CgkJCWNhc2UgJ08nOi8vTE8KCQkJCXN3aXRjaChpbnB1dC5jaGFyQXQoMikpewoJCQkJY2FzZSAnQSc6Ly9MT0EKCQkJCQlzd2l0Y2goaW5wdXQuY2hhckF0KDMpKXsKCQkJCQljYXNlICdEJzovL0xPQUQKCQkJCQkJZXhlY3V0ZShpbnB1dC5zdWJzdHJpbmcoMCwgNCksIGlucHV0LnN1YnN0cmluZyg0KSk7CgkJCQkJZGVmYXVsdDoKCQkJCQkJZGVmKGlucHV0KTsKCQkJCQl9CgkJCQlkZWZhdWx0OgoJCQkJCWRlZihpbnB1dCk7CgkJCQl9CgkJCWRlZmF1bHQ6CgkJCQlkZWYoaW5wdXQpOwoJCQl9CgkJCQoJCWNhc2UgJ00nOi8vTQoJCQlzd2l0Y2goaW5wdXQuY2hhckF0KDEpKXsKCQkJY2FzZSAnVSc6Ly9NVQoJCQkJc3dpdGNoKGlucHV0LmNoYXJBdCgyKSl7CgkJCQljYXNlICdMJzovL01VTAoJCQkJCXN3aXRjaChpbnB1dC5jaGFyQXQoMykpewoJCQkJCWNhc2UgJ1QnOi8vTVVMVAoJCQkJCQlleGVjdXRlKGlucHV0LnN1YnN0cmluZygwLCA0KSwgaW5wdXQuc3Vic3RyaW5nKDQpKTsKCQkJCQlkZWZhdWx0OgoJCQkJCQlkZWYoaW5wdXQpOwoJCQkJCX0KCQkJCWRlZmF1bHQ6CgkJCQkJZGVmKGlucHV0KTsKCQkJCX0KCQkJZGVmYXVsdDoKCQkJCWRlZihpbnB1dCk7CgkJCX0KCQkJCgkJY2FzZSAnUyc6Ly9TCgkJCXN3aXRjaChpbnB1dC5jaGFyQXQoMSkpewoJCQljYXNlICdUJzovL1NUCgkJCQlzd2l0Y2goaW5wdXQuY2hhckF0KDIpKXsKCQkJCWNhc2UgJ08nOi8vU1RPCgkJCQkJc3dpdGNoKGlucHV0LmNoYXJBdCgzKSl7CgkJCQkJY2FzZSAnUic6Ly9TVE9SCgkJCQkJCXN3aXRjaChpbnB1dC5jaGFyQXQoNCkpewoJCQkJCQljYXNlICdFJzovL1NUT1JFCgkJCQkJCQlleGVjdXRlKGlucHV0LnN1YnN0cmluZygwLCA1KSwgaW5wdXQuc3Vic3RyaW5nKDUpKTsKCQkJCQkJZGVmYXVsdDoKCQkJCQkJCWRlZihpbnB1dCk7CgkJCQkJCX0KCQkJCQlkZWZhdWx0OgoJCQkJCQlkZWYoaW5wdXQpOwoJCQkJCX0KCQkJCWRlZmF1bHQ6CgkJCQkJZGVmKGlucHV0KTsKCQkJCX0KCQkJY2FzZSAnVSc6Ly9TVQoJCQkJc3dpdGNoKGlucHV0LmNoYXJBdCgyKSl7CgkJCQljYXNlICdCJzovL1NVQgoJCQkJCWV4ZWN1dGUoaW5wdXQuc3Vic3RyaW5nKDAsIDMpLCBpbnB1dC5zdWJzdHJpbmcoMykpOwoJCQkJZGVmYXVsdDoKCQkJCQlkZWYoaW5wdXQpOwoJCQkJfQoJCQlkZWZhdWx0OgoJCQkJZGVmKGlucHV0KTsKCQkJfQoJCQoJCWRlZmF1bHQ6CgkJCWRlZihpbnB1dCk7CgkJfQoJfQoJCglwdWJsaWMgc3RhdGljIHZvaWQgbWFpbihTdHJpbmcgYXJnc1tdKSB7CgkJbmV3IFZhbSgpOwoJfQp9CgovKiBKdXN0IGEgc2ltcGxlIHByb2dyYW0gdG8gdGVzdDoKRExPQUQgMTAKTE9BRCAxCkRMT0FEIDIKQUREIDEKTE9BRCAyCkVORAogKi8=