Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <avr/pgmspace.h>
- const byte JAVA_PROGRAM[] PROGMEM = {
- 0xca, 0xfe, 0xba, 0xbe, 0x0, 0x0, 0x0, 0x32, 0x0, 0x31,
- 0xa, 0x0, 0xa, 0x0, 0x20, 0x8, 0x0, 0x21, 0xa, 0x0,
- 0x22, 0x0, 0x23, 0xa, 0x0, 0x22, 0x0, 0x24, 0xa, 0x0,
- 0x9, 0x0, 0x25, 0xa, 0x0, 0x22, 0x0, 0x26, 0x8, 0x0,
- 0x27, 0x9, 0x0, 0x9, 0x0, 0x28, 0x7, 0x0, 0x29, 0x7,
- 0x0, 0x2a, 0x1, 0x0, 0x7, 0x6d, 0x79, 0x56, 0x61, 0x6c,
- 0x75, 0x65, 0x1, 0x0, 0x1, 0x49, 0x1, 0x0, 0x6, 0x3c,
- 0x69, 0x6e, 0x69, 0x74, 0x3e, 0x1, 0x0, 0x3, 0x28, 0x29,
- 0x56, 0x1, 0x0, 0x4, 0x43, 0x6f, 0x64, 0x65, 0x1, 0x0,
- 0xf, 0x4c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65,
- 0x72, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x1, 0x0, 0x12, 0x4c,
- 0x6f, 0x63, 0x61, 0x6c, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62,
- 0x6c, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x1, 0x0, 0x4,
- 0x74, 0x68, 0x69, 0x73, 0x1, 0x0, 0x21, 0x4c, 0x64, 0x75,
- 0x6f, 0x76, 0x65, 0x6e, 0x74, 0x69, 0x70, 0x72, 0x6f, 0x67,
- 0x72, 0x61, 0x6d, 0x2f, 0x44, 0x55, 0x4f, 0x56, 0x65, 0x6e,
- 0x74, 0x69, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x3b,
- 0x1, 0x0, 0x4, 0x6d, 0x61, 0x69, 0x6e, 0x1, 0x0, 0x16,
- 0x28, 0x5b, 0x4c, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c, 0x61,
- 0x6e, 0x67, 0x2f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3b,
- 0x29, 0x56, 0x1, 0x0, 0x4, 0x61, 0x72, 0x67, 0x73, 0x1,
- 0x0, 0x13, 0x5b, 0x4c, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c,
- 0x61, 0x6e, 0x67, 0x2f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67,
- 0x3b, 0x1, 0x0, 0x8, 0x6d, 0x79, 0x4e, 0x75, 0x6d, 0x62,
- 0x65, 0x72, 0x1, 0x0, 0x8, 0x6d, 0x79, 0x52, 0x65, 0x73,
- 0x75, 0x6c, 0x74, 0x1, 0x0, 0x8, 0x6d, 0x79, 0x4d, 0x65,
- 0x74, 0x68, 0x6f, 0x64, 0x1, 0x0, 0x4, 0x28, 0x49, 0x29,
- 0x49, 0x1, 0x0, 0x6, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72,
- 0x1, 0x0, 0x8, 0x3c, 0x63, 0x6c, 0x69, 0x6e, 0x69, 0x74,
- 0x3e, 0x1, 0x0, 0xa, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65,
- 0x46, 0x69, 0x6c, 0x65, 0x1, 0x0, 0x14, 0x44, 0x55, 0x4f,
- 0x56, 0x65, 0x6e, 0x74, 0x69, 0x50, 0x72, 0x6f, 0x67, 0x72,
- 0x61, 0x6d, 0x2e, 0x6a, 0x61, 0x76, 0x61, 0xc, 0x0, 0xd,
- 0x0, 0xe, 0x1, 0x0, 0x17, 0x50, 0x6c, 0x65, 0x61, 0x73,
- 0x65, 0x20, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x61, 0x20,
- 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x2e, 0xa, 0x7, 0x0,
- 0x2b, 0xc, 0x0, 0x2c, 0x0, 0x2d, 0xc, 0x0, 0x2e, 0x0,
- 0x2f, 0xc, 0x0, 0x1a, 0x0, 0x1b, 0xc, 0x0, 0x2c, 0x0,
- 0x30, 0x1, 0x0, 0x10, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
- 0x65, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0xa,
- 0xc, 0x0, 0xb, 0x0, 0xc, 0x1, 0x0, 0x1f, 0x64, 0x75,
- 0x6f, 0x76, 0x65, 0x6e, 0x74, 0x69, 0x70, 0x72, 0x6f, 0x67,
- 0x72, 0x61, 0x6d, 0x2f, 0x44, 0x55, 0x4f, 0x56, 0x65, 0x6e,
- 0x74, 0x69, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x1,
- 0x0, 0x10, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c, 0x61, 0x6e,
- 0x67, 0x2f, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x1, 0x0,
- 0x18, 0x64, 0x75, 0x6f, 0x76, 0x65, 0x6e, 0x74, 0x69, 0x70,
- 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x2f, 0x45, 0x78, 0x63,
- 0x68, 0x61, 0x6e, 0x67, 0x65, 0x1, 0x0, 0x5, 0x70, 0x72,
- 0x69, 0x6e, 0x74, 0x1, 0x0, 0x15, 0x28, 0x4c, 0x6a, 0x61,
- 0x76, 0x61, 0x2f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x53, 0x74,
- 0x72, 0x69, 0x6e, 0x67, 0x3b, 0x29, 0x56, 0x1, 0x0, 0x9,
- 0x70, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x49, 0x6e, 0x74, 0x1,
- 0x0, 0x3, 0x28, 0x29, 0x49, 0x1, 0x0, 0x4, 0x28, 0x49,
- 0x29, 0x56, 0x0, 0x21, 0x0, 0x9, 0x0, 0xa, 0x0, 0x0,
- 0x0, 0x1, 0x0, 0xa, 0x0, 0xb, 0x0, 0xc, 0x0, 0x0,
- 0x0, 0x4, 0x0, 0x1, 0x0, 0xd, 0x0, 0xe, 0x0, 0x1,
- 0x0, 0xf, 0x0, 0x0, 0x0, 0x2f, 0x0, 0x1, 0x0, 0x1,
- 0x0, 0x0, 0x0, 0x5, 0x2a, 0xb7, 0x0, 0x1, 0xb1, 0x0,
- 0x0, 0x0, 0x2, 0x0, 0x10, 0x0, 0x0, 0x0, 0x6, 0x0,
- 0x1, 0x0, 0x0, 0x0, 0x4, 0x0, 0x11, 0x0, 0x0, 0x0,
- 0xc, 0x0, 0x1, 0x0, 0x0, 0x0, 0x5, 0x0, 0x12, 0x0,
- 0x13, 0x0, 0x0, 0x0, 0x9, 0x0, 0x14, 0x0, 0x15, 0x0,
- 0x1, 0x0, 0xf, 0x0, 0x0, 0x0, 0x6a, 0x0, 0x1, 0x0,
- 0x3, 0x0, 0x0, 0x0, 0x18, 0x12, 0x2, 0xb8, 0x0, 0x3,
- 0xb8, 0x0, 0x4, 0x3c, 0x1b, 0xb8, 0x0, 0x5, 0x3d, 0x1c,
- 0xb8, 0x0, 0x6, 0x12, 0x7, 0xb8, 0x0, 0x3, 0xb1, 0x0,
- 0x0, 0x0, 0x2, 0x0, 0x10, 0x0, 0x0, 0x0, 0x1a, 0x0,
- 0x6, 0x0, 0x0, 0x0, 0x9, 0x0, 0x5, 0x0, 0xa, 0x0,
- 0x9, 0x0, 0xb, 0x0, 0xe, 0x0, 0xc, 0x0, 0x12, 0x0,
- 0xd, 0x0, 0x17, 0x0, 0xe, 0x0, 0x11, 0x0, 0x0, 0x0,
- 0x20, 0x0, 0x3, 0x0, 0x0, 0x0, 0x18, 0x0, 0x16, 0x0,
- 0x17, 0x0, 0x0, 0x0, 0x9, 0x0, 0xf, 0x0, 0x18, 0x0,
- 0xc, 0x0, 0x1, 0x0, 0xe, 0x0, 0xa, 0x0, 0x19, 0x0,
- 0xc, 0x0, 0x2, 0x0, 0xa, 0x0, 0x1a, 0x0, 0x1b, 0x0,
- 0x1, 0x0, 0xf, 0x0, 0x0, 0x0, 0x47, 0x0, 0x2, 0x0,
- 0x2, 0x0, 0x0, 0x0, 0xb, 0x1a, 0xb2, 0x0, 0x8, 0x68,
- 0x3c, 0x84, 0x1, 0x1, 0x1b, 0xac, 0x0, 0x0, 0x0, 0x2,
- 0x0, 0x10, 0x0, 0x0, 0x0, 0xe, 0x0, 0x3, 0x0, 0x0,
- 0x0, 0x12, 0x0, 0x6, 0x0, 0x13, 0x0, 0x9, 0x0, 0x14,
- 0x0, 0x11, 0x0, 0x0, 0x0, 0x16, 0x0, 0x2, 0x0, 0x0,
- 0x0, 0xb, 0x0, 0x1c, 0x0, 0xc, 0x0, 0x0, 0x0, 0x6,
- 0x0, 0x5, 0x0, 0x19, 0x0, 0xc, 0x0, 0x1, 0x0, 0x8,
- 0x0, 0x1d, 0x0, 0xe, 0x0, 0x1, 0x0, 0xf, 0x0, 0x0,
- 0x0, 0x1d, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5,
- 0x5, 0xb3, 0x0, 0x8, 0xb1, 0x0, 0x0, 0x0, 0x1, 0x0,
- 0x10, 0x0, 0x0, 0x0, 0x6, 0x0, 0x1, 0x0, 0x0, 0x0,
- 0x6, 0x0, 0x1, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x2, 0x0,
- 0x1f
- };
- const byte ATTRIBUTE_NAME1[] PROGMEM = "Code";
- const byte METHOD_NAME1[] PROGMEM = "<clinit>";
- const byte METHOD_NAME2[] PROGMEM = "<init>";
- const byte METHOD_NAME3[] PROGMEM = "main";
- const byte ERROR_MESSAGE1[] PROGMEM = "Invalid class file.\n";
- const byte ERROR_MESSAGE2[] PROGMEM = "Invalid constant.\n";
- const byte ERROR_MESSAGE3[] PROGMEM = "Interfaces are not supported.\n";
- byte equalText(byte *buffer1, byte *buffer2)
- {
- long index = 0;
- while (index < 512)
- {
- byte tempValue1 = *buffer1;
- byte tempValue2 = *buffer2;
- if (tempValue1 != tempValue2)
- {
- return false;
- }
- if (tempValue1 == 0)
- {
- break;
- }
- buffer1 += 1;
- buffer2 += 1;
- index += 1;
- }
- return true;
- }
- byte equalData(long amount, byte *buffer1, byte *buffer2)
- {
- while (amount > 0)
- {
- byte tempValue1 = *buffer1;
- byte tempValue2 = *buffer2;
- if (tempValue1 != tempValue2)
- {
- return false;
- }
- buffer1 += 1;
- buffer2 += 1;
- amount -= 1;
- }
- return true;
- }
- void copyTextFromProgMemToBuffer(byte *destination, const byte *sequence)
- {
- byte count = 0;
- while (count < 250)
- {
- byte tempData = pgm_read_byte(sequence);
- *destination = tempData;
- if (tempData == 0)
- {
- break;
- }
- sequence += 1;
- destination += 1;
- count += 1;
- }
- }
- void copyDataFromProgMemToBuffer(byte *destination, long amount, const byte *sequence)
- {
- long index = 0;
- while (index < amount)
- {
- byte tempData = pgm_read_byte(sequence + index);
- *(destination + index) = tempData;
- index += 1;
- }
- }
- byte equalTextToTextFromProgMem(byte *buffer1, const byte *buffer2)
- {
- byte tempBuffer[250];
- copyTextFromProgMemToBuffer(tempBuffer, buffer2);
- return equalText(buffer1, tempBuffer);
- }
- void printFromProgMem(const byte *sequence)
- {
- byte tempBuffer[250];
- copyTextFromProgMemToBuffer(tempBuffer, sequence);
- Serial.print((char *)tempBuffer);
- }
- void readSequenceFromJavaProgram(long amount, byte *buffer, long address)
- {
- copyDataFromProgMemToBuffer(buffer, amount, JAVA_PROGRAM + address);
- }
- byte readByteFromJavaProgram(long address)
- {
- byte tempBuffer[1];
- readSequenceFromJavaProgram(1, tempBuffer, address);
- return tempBuffer[0];
- }
- unsigned int readUnsignedShortFromJavaProgram(long address)
- {
- byte tempBuffer[2];
- readSequenceFromJavaProgram(2, tempBuffer, address);
- return ((unsigned int)tempBuffer[0] << (unsigned int)8) + (unsigned int)tempBuffer[1];
- }
- unsigned long readUnsignedIntFromJavaProgram(long address)
- {
- byte tempBuffer[4];
- readSequenceFromJavaProgram(4, tempBuffer, address);
- long output = (unsigned long)tempBuffer[0] << (unsigned long)24;
- output += (unsigned long)tempBuffer[1] << (unsigned long)16;
- output += ((unsigned long)tempBuffer[2] << (unsigned long)8) + (unsigned long)tempBuffer[3];
- return output;
- }
- long constantAddressList[100];
- unsigned int thisJavaClass;
- long fieldAddressList[25];
- byte fieldAmount;
- byte fieldIndexList[25];
- byte fieldData[100];
- long methodAddressList[25];
- byte methodAmount;
- long methodCodeAttributeAddressList[25];
- int staticMethodIndex;
- int constructorMethodIndex;
- int mainMethodIndex;
- byte operandStack[100];
- unsigned int operandStackLevel;
- byte variableStack[200];
- unsigned int variableStackLevel;
- byte tempBuffer[400];
- void readJavaProgramStringConstant(byte *destination, unsigned int index)
- {
- long tempAddress = constantAddressList[index - 1];
- tempAddress += 1;
- unsigned int tempAmount = readUnsignedShortFromJavaProgram(tempAddress);
- tempAddress += 2;
- readSequenceFromJavaProgram(tempAmount, destination, tempAddress);
- *(destination + tempAmount) = 0;
- }
- byte getDescriptorSize(byte *destination, byte *buffer)
- {
- byte tempCharacter = *buffer;
- if (tempCharacter == 'B' || tempCharacter == 'C' || tempCharacter == 'F' || tempCharacter == 'I' || tempCharacter == 'S' || tempCharacter == 'Z')
- {
- *destination = 4;
- return 1;
- }
- if (tempCharacter == 'D' || tempCharacter == 'J')
- {
- *destination = 8;
- return 1;
- }
- if (tempCharacter == 'L')
- {
- *destination = 4;
- buffer += 1;
- byte output = 2;
- while (*buffer != ';' && output < 250)
- {
- buffer += 1;
- output += 1;
- }
- return output;
- }
- if (tempCharacter == '[')
- {
- *destination = 4;
- byte tempNumber;
- return 1 + getDescriptorSize(&tempNumber, buffer + 1);
- }
- }
- void pushOperandIntOntoStack(long operand)
- {
- *((long *)(operandStack + operandStackLevel)) = operand;
- operandStackLevel += 4;
- }
- long popOperandIntFromStack()
- {
- operandStackLevel -= 4;
- return *((long *)(operandStack + operandStackLevel));
- }
- void initializeJavaProgram(long address)
- {
- unsigned long tempValue = readUnsignedIntFromJavaProgram(address);
- address += 4;
- if (tempValue != 0xCAFEBABE)
- {
- printFromProgMem(ERROR_MESSAGE1);
- return;
- }
- // The version numbers could be read here.
- address += 4;
- unsigned int tempCount = readUnsignedShortFromJavaProgram(address);
- address += 2;
- unsigned int index = 1;
- while (index < tempCount)
- {
- constantAddressList[index - 1] = address;
- byte tempType = readByteFromJavaProgram(address);
- address += 1;
- if (tempType == 1)
- {
- unsigned int tempAmount = readUnsignedShortFromJavaProgram(address);
- address += 2;
- address += tempAmount;
- //readJavaProgramStringConstant(tempBuffer, index);
- //Serial.println((char *)tempBuffer);
- }
- if (tempType == 3 || tempType == 4 || tempType > 8)
- {
- address += 4;
- }
- if (tempType == 5 || tempType == 6)
- {
- address += 8;
- }
- if (tempType == 7 || tempType == 8)
- {
- address += 2;
- }
- if (tempType > 12)
- {
- printFromProgMem(ERROR_MESSAGE2);
- return;
- }
- index += 1;
- }
- // Access flags here.
- address += 2;
- thisJavaClass = readUnsignedShortFromJavaProgram(address);
- address += 2;
- // Superclass here.
- address += 2;
- tempCount = readUnsignedShortFromJavaProgram(address);
- address += 2;
- if (tempCount > 0)
- {
- printFromProgMem(ERROR_MESSAGE3);
- }
- // Interfaces here.
- fieldAmount = 0;
- tempCount = readUnsignedShortFromJavaProgram(address);
- address += 2;
- index = 0;
- while (tempCount > 0)
- {
- fieldAddressList[index] = address;
- index += 1;
- // Access flags here.
- address += 2;
- // Name index here.
- address += 2;
- // Descriptor index here.
- address += 2;
- unsigned int tempAmount = readUnsignedShortFromJavaProgram(address);
- address += 2;
- unsigned int tempIndex = 0;
- while (tempIndex < tempAmount)
- {
- // Attribute name index here.
- address += 2;
- unsigned long tempAmount2 = readUnsignedIntFromJavaProgram(address);
- address += 4;
- // Info here.
- address += tempAmount2;
- tempIndex += 1;
- }
- fieldAmount += 1;
- tempCount -= 1;
- }
- methodAmount = 0;
- tempCount = readUnsignedShortFromJavaProgram(address);
- address += 2;
- index = 0;
- while (tempCount > 0)
- {
- methodAddressList[index] = address;
- index += 1;
- // Access flags here.
- address += 2;
- // Name index here.
- unsigned int tempIndex2 = readUnsignedShortFromJavaProgram(address);
- readJavaProgramStringConstant(tempBuffer, tempIndex2);
- Serial.println((char *)tempBuffer);
- address += 2;
- // Descriptor index here.
- address += 2;
- unsigned int tempAmount = readUnsignedShortFromJavaProgram(address);
- address += 2;
- unsigned int tempIndex = 0;
- while (tempIndex < tempAmount)
- {
- unsigned int tempIndex2 = readUnsignedShortFromJavaProgram(address);
- readJavaProgramStringConstant(tempBuffer, tempIndex2);
- Serial.println((char *)tempBuffer);
- if (equalTextToTextFromProgMem(tempBuffer, ATTRIBUTE_NAME1))
- {
- methodCodeAttributeAddressList[index] = address;
- }
- address += 2;
- unsigned long tempAmount2 = readUnsignedIntFromJavaProgram(address);
- address += 4;
- // Info here.
- address += tempAmount2;
- tempIndex += 1;
- }
- methodAmount += 1;
- tempCount -= 1;
- }
- byte tempFieldIndex = 0;
- index = 0;
- while (index < fieldAmount)
- {
- fieldIndexList[index] = tempFieldIndex;
- long tempAddress = fieldAddressList[index];
- unsigned int tempIndex = readUnsignedShortFromJavaProgram(tempAddress + 4);
- readJavaProgramStringConstant(tempBuffer, tempIndex);
- byte tempSize;
- getDescriptorSize(&tempSize, tempBuffer);
- tempFieldIndex += tempSize;
- index += 1;
- }
- staticMethodIndex = -1;
- constructorMethodIndex = -1;
- mainMethodIndex = -1;
- index = 0;
- while (index < methodAmount)
- {
- long tempAddress = methodAddressList[index];
- unsigned int tempIndex = readUnsignedShortFromJavaProgram(tempAddress + 2);
- readJavaProgramStringConstant(tempBuffer, tempIndex);
- if (equalTextToTextFromProgMem(tempBuffer, METHOD_NAME1))
- {
- staticMethodIndex = index;
- }
- if (equalTextToTextFromProgMem(tempBuffer, METHOD_NAME2))
- {
- constructorMethodIndex = index;
- }
- if (equalTextToTextFromProgMem(tempBuffer, METHOD_NAME3))
- {
- mainMethodIndex = index;
- }
- index += 1;
- }
- operandStackLevel = 0;
- variableStackLevel = 0;
- }
- int findJavaProgramMethod(unsigned int index)
- {
- long tempAddress = constantAddressList[index];
- unsigned int nameAndDescriptorIndex = readUnsignedShortFromJavaProgram(tempAddress + 3);
- tempAddress = constantAddressList[nameAndDescriptorIndex];
- unsigned int nameIndex = readUnsignedShortFromJavaProgram(tempAddress + 1);
- unsigned int descriptorIndex = readUnsignedShortFromJavaProgram(tempAddress + 3);
- unsigned int tempIndex = 0;
- while (tempIndex < methodAmount)
- {
- long tempAddress = methodAddressList[tempIndex];
- unsigned int tempIndex2 = readUnsignedShortFromJavaProgram(tempAddress + 2);
- unsigned int tempIndex3 = readUnsignedShortFromJavaProgram(tempAddress + 4);
- if (tempIndex2 == nameIndex && tempIndex3 == descriptorIndex)
- {
- return tempIndex;
- }
- tempIndex += 1;
- }
- return -1;
- }
- void runJavaProgramMethodByIndex(unsigned int index)
- {
- unsigned int tempVariableStackLevel = variableStackLevel;
- long tempAddress = methodAddressList[index];
- unsigned int tempIndex = readUnsignedShortFromJavaProgram(tempAddress + 4);
- readJavaProgramStringConstant(tempBuffer, tempIndex);
- unsigned int tempSize = 0;
- tempIndex = 1;
- while (*(tempBuffer + tempIndex) != ')' && tempIndex < 400)
- {
- byte tempSize2;
- tempIndex += getDescriptorSize(&tempSize2, tempBuffer + tempIndex);
- tempSize += tempSize2;
- }
- tempAddress = methodCodeAttributeAddressList[index];
- variableStackLevel += 4 * readUnsignedShortFromJavaProgram(tempAddress + 8);
- variableStackLevel = tempVariableStackLevel;
- }
- void runJavaProgramMethod(unsigned int index)
- {
- int tempIndex = findJavaProgramMethod(index);
- if (tempIndex == -1)
- {
- return;
- }
- runJavaProgramMethodByIndex(tempIndex);
- }
- void runJavaProgram(long address)
- {
- initializeJavaProgram(address);
- runJavaProgramMethodByIndex(staticMethodIndex);
- runJavaProgramMethodByIndex(constructorMethodIndex);
- runJavaProgramMethodByIndex(mainMethodIndex);
- }
- void setup()
- {
- Serial.begin(9600);
- Serial.println("Hello world!");
- runJavaProgram(0);
- }
- void loop()
- {
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement