Jump to content

Minecraft EmuServer


JRSmile
 Share

Recommended Posts

Hello There,

i want to create a little Minecraft 1.1 server which is capable of using the Minecraft client as GUI for AutoIT to do homeautomation.

this is what i have so far.

#NoTrayIcon
#include "TCP.au3"
ToolTip("SERVER: Creating server...", 10, 30)
$hServer = _TCP_Server_Create(25565); A MineCraftServer. Tadaa!
_TCP_RegisterEvent($hServer, $TCP_NEWCLIENT, "NewClient")
_TCP_RegisterEvent($hServer, $TCP_DISCONNECT, "Disconnect")
_TCP_RegisterEvent($hServer, $TCP_RECEIVE, "Received")
While 1
WEnd
Func NewClient($hSocket, $iError)
ToolTip("SERVER: New client connected.", 10, 30)
EndFunc   ;==>NewClient
Func Disconnect($hSocket, $iError)
ToolTip("SERVER: Client disconnected.", 10, 30)
EndFunc   ;==>Disconnect
Func Received($hSocket, $sReceived, $iError)
ConsoleWrite(">| " & Binary($sReceived) & @CRLF)
Protocol(Binary($sReceived),$hSocket)
EndFunc   ;==>Disconnect
Func Protocol($stream,$hSocket)
switch StringLeft($stream,4)
  Case 0xFE
   ConsoleWrite("+| Server List Ping" & @CRLF)
   _TCP_Send($hSocket, 0xFF)
  Case 0x02
   $username = BinaryToString("0x" & StringTrimLeft($stream,8),3) ; all strings are UCS-2 encoded which is luckily the same as UTF-16 BigEndian.
   ConsoleWrite("+| Handshake by " & $username & @CRLF)
   _TCP_Send($hSocket, "0x020001002D") ; StringToBinary("-",3)
  case Else
   ConsoleWrite("!| Unknown Packet!" & @CRLF)
   _TCP_Send($hSocket, 0xFF)
EndSwitch
EndFunc

It uses the from Kip.

as you can see it's not very much, the minecraft client recognices the server as online and can connect to it.

As of the Server Protocol specs http://wiki.vg/Protocol i have to send a Handshake reply to the client in order to proceed.

the specs say i have to send the packetid which is 0x02 for Handshake then the length of the string which would be 1 char because i don't use authentification and the a "-" (minus) in UTF-16 BigEndian.

But it Doesn't work, either autoit can't send HEX values longer then 8 i think or i have to send it as string which is bad to for the client.

Can' somebody explain to me how i can send it the correct way, or tell me a bit about binary analyses?

I don't think that doing a stringleft with binary is the right way but i can't figure out the correct one.

Best regards,

J.

$a=StringSplit("547275737420796F757220546563686E6F6C75737421","")
For $b=1 To UBound($a)+(-1*-1*-1)step(2^4/8);&$b+=1*2/40*µ&Asc(4)
Assign("c",Eval("c")&Chr(Dec($a[$b]&$a[$b+1])));''Chr("a")&"HI"
Next ;time_U&r34d,ths,U-may=get$the&c.l.u.e;b3st-regards,JRSmile;
MsgBox(0x000000,"",Eval("c"));PiEs:d0nt+*b3.s4d.4ft3r.1st-try:-)
Link to comment
Share on other sites

Ok, did some progress, the handshake is working ....

still no clue how to do binary stuff correctly.

and hanging on the Login Request Reply...

in addition from Ward is beeing used to compress chunk data for the Client, some how.

#NoTrayIcon
#include "TCP.au3"
#Include "ZLIB.au3"

; >>>>>>>>>> http://wiki.vg/Protocol

ToolTip("SERVER: Creating server...", 10, 30)
$hServer = _TCP_Server_Create(25565); A MineCraftServer. Tadaa!

_TCP_RegisterEvent($hServer, $TCP_NEWCLIENT, "NewClient")
_TCP_RegisterEvent($hServer, $TCP_DISCONNECT, "Disconnect")
_TCP_RegisterEvent($hServer, $TCP_RECEIVE, "Received")
While 1

WEnd

Func NewClient($hSocket, $iError)
    ToolTip("SERVER: New client connected.", 10, 30)
EndFunc   ;==>NewClient

Func Disconnect($hSocket, $iError)
    ToolTip("SERVER: Client disconnected.", 10, 30)
EndFunc   ;==>Disconnect

Func Received($hSocket, $sReceived, $iError)
    ConsoleWrite(">| " & Binary($sReceived) & @CRLF)
    Protocol(Binary($sReceived),$hSocket)
EndFunc   ;==>Disconnect

Func Protocol($stream,$hSocket)
    switch StringLeft($stream,4)
        Case 0xFE
            ConsoleWrite("+| Server List Ping" & @CRLF)
            _TCP_Send($hSocket, 0xFF)
        Case 0x02
            $username = BinaryToString("0x" & StringTrimLeft($stream,8),3) ; all strings are UCS-2 encoded which is luckily the same as UTF-16 BigEndian.
            ConsoleWrite("+| Handshake by " & $username & @CRLF)
            _TCP_Send($hSocket, "0x020001002D") ; StringToBinary("-",3)
        case 0x01
            $loginname = BinaryToString("0x" & StringTrimLeft($stream,16),3)
            ConsoleWrite("+| Login Request by " & $loginname & @CRLF)
            _TCP_Send($hSocket, "0x0100000148000060440b732bf1f642000000000001801406fffffbd600000040000001ef0400000000003fbb1503000800a7003500a7003600a7003400a70035") ; Login accepted
            _TCP_Send($hSocket, "0x05") ; Entity Equipment (Head,Body,pants,boots) ;EntitiyID (int), Slot 0= Hand 1-4 armor slot (short), Item ID (short), Damaged (short)...
            _TCP_Send($hSocket, "0x32000000001") ; Chunk init
            _TCP_Send($hSocket, "0x330000000000037F03") ; Chunk region data
            _TCP_Send($hSocket, "0x0D00000000000000000000000000000000000000001") ; player pos and Look
        case 0x03
            $message = BinaryToString("0x" & StringTrimLeft($stream,5),3)
            ConsoleWrite("-| Chat: " & $message & @CRLF)
        case Else
            ConsoleWrite("!| Unimplemented Packettype! Player KICKED!" & @CRLF)
            _TCP_Send($hSocket, 0xFF)
    EndSwitch
EndFunc

Func _MC_String($sText)
    Local $iLen = StringLen($sText)
    Local $bLen = Binary("0x" & hex(StringLen($sText),4))
    Local $bText = StringTrimLeft(StringToBinary($sText,3),2)
    Return Binary($bLen & $bText)
EndFunc

;~ Dim $Compressed = _ZLIB_Compress($Original, 9)
;~ Dim $Decompressed = _ZLIB_Uncompress($Compressed)

#cs
What's the normal login sequence for a client?

See Authentication for communication with minecraft.net

    The recommended login sequence looks like this, where C is the client and S is the server:

    C <> S : Connects
    C >  S : Sends handshake
    C <  S : Sends handshake response
    C >  S : After authenticating (if needed), sends the login packet
    C <  S : Either kicks (invalid login) or sends a login response
    C <  S : Sends pre-chunks and chunks and entities
    C <  S : Sends spawn position
    C <  S : Sends inventory [Need to verify this since inventory changed] (beta 1.1_02: looks like Window items with type=0, then a Set slot with window id = -1 and slot = -1)
    C <  S : Tell the client they're ready to spawn by sending a position + look packet. Note: The stance and Y should be swapped when the server sends it to the client (See Protocol Page)!
    C >  S : Sends a position + look packet to confirm the spawn position, with the stance and Y swapped back to the correct positions

I think I've done everything right, but…
…my player isn't spawning!

    After sending the common-sense packets (Handshake, Login, Inventory, Compass and Pre-chunk/Chunk pairs) you need to finally send the player their initial position for them to leave the "Loading Map" screen.

…my client isn't receiving complete map chunks!

    The standard Minecraft server server sends full chunks only when your client is sending player status update packets (any of Player (0x0A) through Player Position & Look (0x0D)).

…all connecting clients spasm and jerk uncontrollably!

    For newer clients, your server needs to send 49 chunks ahead of time, not just one. Send a 7x7 square of chunks, centered on the connecting client's position, before spawning them.
#ce
Edited by JRSmile
$a=StringSplit("547275737420796F757220546563686E6F6C75737421","")
For $b=1 To UBound($a)+(-1*-1*-1)step(2^4/8);&$b+=1*2/40*µ&Asc(4)
Assign("c",Eval("c")&Chr(Dec($a[$b]&$a[$b+1])));''Chr("a")&"HI"
Next ;time_U&r34d,ths,U-may=get$the&c.l.u.e;b3st-regards,JRSmile;
MsgBox(0x000000,"",Eval("c"));PiEs:d0nt+*b3.s4d.4ft3r.1st-try:-)
Link to comment
Share on other sites

This thread was reported since it has the word "game" in it. I'm on the fence about this one. On the one hand, yeah, it breaks the rules. On the other hand, I'm fairly sure Notch would be okay with something like this because it's a rather interesting thing. I also think it may be a bit above the heads of anyone who would use it maliciously. So I think I'll let this thread live.

Link to comment
Share on other sites

This thread was reported since it has the word "game" in it. I'm on the fence about this one. On the one hand, yeah, it breaks the rules. On the other hand, I'm fairly sure Notch would be okay with something like this because it's a rather interesting thing. I also think it may be a bit above the heads of anyone who would use it maliciously. So I think I'll let this thread live.

Hey Valik,

thanks for letting me life :)

Just to prevent further distraction, its a server, so to the impact on the minecraft community is rather low ;)

you still have to pay for minecraft if you want to use it as client.

the protocol is mentioned on the official wiki and you are encouraged to create 3rd party clients and servers.

in addition you won't be able to "play" the "game" as usual.

Just having a map build previously and imported is used to place buttons and levers and maybe some signs for ingame feedback for the user.

MAYBE Redstone state, which i don't think will be implemented.

No block breaking or placing.

implementation of the protocol just to the state the client thinks it is ingame and starts displaying things i want ;)

ps: any tricks to concatenate binarys ?

Edited by JRSmile
$a=StringSplit("547275737420796F757220546563686E6F6C75737421","")
For $b=1 To UBound($a)+(-1*-1*-1)step(2^4/8);&$b+=1*2/40*µ&Asc(4)
Assign("c",Eval("c")&Chr(Dec($a[$b]&$a[$b+1])));''Chr("a")&"HI"
Next ;time_U&r34d,ths,U-may=get$the&c.l.u.e;b3st-regards,JRSmile;
MsgBox(0x000000,"",Eval("c"));PiEs:d0nt+*b3.s4d.4ft3r.1st-try:-)
Link to comment
Share on other sites

I'm not sure what you mean by concatenate binary. I'm also not so familiar with TCP, but I imagine that packets can't be greater than a certain size. At first I thought perhaps you need to use BitOR, but some of the hex values in your code are too large and would need to be split. Could you give an example of what you mean by binary concatenation? I hope to learn something new here. :)

Edited by czardas
Link to comment
Share on other sites

This is from the winhttp UDF. Is that what you where looking for?

; #FUNCTION# ;===============================================================================
; Name...........: _WinHttpBinaryConcat
; Description ...: Concatenates two binary data returned by _WinHttpReadData() in binary mode.
; Syntax.........: _WinHttpBinaryConcat(ByRef $bBinary1, ByRef $bBinary2)
; Parameters ....: $bBinary1 - Binary data that is to be concatenated.
;                 $bBinary2 - Binary data to concat.
; Return values .: Success - Returns concatenated binary data.
;                 Failure - Returns empty binary and sets @error:
;                 |1 - Invalid input.
; Author ........: ProgAndy
; Modified.......: trancexx
; Remarks .......:
; Related .......: _WinHttpReadData
; Link ..........:
; Example .......:
;============================================================================================
Func _WinHttpBinaryConcat(ByRef $bBinary1, ByRef $bBinary2)
    Switch IsBinary($bBinary1) + 2 * IsBinary($bBinary2)
        Case 0
            Return SetError(1, 0, Binary(''))
        Case 1
            Return $bBinary1
        Case 2
            Return $bBinary2
    EndSwitch
    Local $tAuxiliary = DllStructCreate("byte[" & BinaryLen($bBinary1) & "];byte[" & BinaryLen($bBinary2) & "]")
    DllStructSetData($tAuxiliary, 1, $bBinary1)
    DllStructSetData($tAuxiliary, 2, $bBinary2)
    Local $tOutput = DllStructCreate("byte[" & DllStructGetSize($tAuxiliary) & "]", DllStructGetPtr($tAuxiliary))
    Return DllStructGetData($tOutput, 1)
EndFunc   ;==>_WinHttpBinaryConcat

@Valik You know you're going to have to explain game-botters why this thread is still open at least twice a day from now on right?

Link to comment
Share on other sites

@Valik You know you're going to have to explain game-botters why this thread is still open at least twice a day from now on right?

First your question, then your answer :)

I don't think he needs to, because a bot is used to get advantage out of automation in a game, during the fact that this is a server you won't get any advantages out of it for the real game, except the fact that you can use it as GUI as intended.

Thanks for the Help, but it isn't working as i expect.

for example:

$bBinary1 = Binary(0x00000001)
$bBinary2 = Binary(0x00000002)
ConsoleWrite(Hex(_WinHttpBinaryConcat($bBinary1, $bBinary2)))

Func _WinHttpBinaryConcat(ByRef $bBinary1, ByRef $bBinary2)
    Switch IsBinary($bBinary1) + 2 * IsBinary($bBinary2)
        Case 0
            Return SetError(1, 0, Binary(''))
        Case 1
            Return $bBinary1
        Case 2
            Return $bBinary2
    EndSwitch
    Local $tAuxiliary = DllStructCreate("byte[" & BinaryLen($bBinary1) & "];byte[" & BinaryLen($bBinary2) & "]")
    DllStructSetData($tAuxiliary, 1, $bBinary1)
    DllStructSetData($tAuxiliary, 2, $bBinary2)
    Local $tOutput = DllStructCreate("byte[" & DllStructGetSize($tAuxiliary) & "]", DllStructGetPtr($tAuxiliary))
    Return DllStructGetData($tOutput, 1)
EndFunc   ;==>_WinHttpBinaryConcat

results in: 0100000002000000

Which isn't what i need.

I will give a short example of my requirements:

$bBinary1 = Binary(0x00000001)
$bBinary2 = Binary(0x00000002)

$result = MAGIC($bBinary1, $bBinary2)

Consolewrite ($result & @CRLF)

Which should result in: 0x0000000100000002 [isBinary = TRUE]

Do i really have to code it with Stringreplace?

Or maybe is it possible to split the incomming packets into a Struct?

Edited by JRSmile
$a=StringSplit("547275737420796F757220546563686E6F6C75737421","")
For $b=1 To UBound($a)+(-1*-1*-1)step(2^4/8);&$b+=1*2/40*µ&Asc(4)
Assign("c",Eval("c")&Chr(Dec($a[$b]&$a[$b+1])));''Chr("a")&"HI"
Next ;time_U&r34d,ths,U-may=get$the&c.l.u.e;b3st-regards,JRSmile;
MsgBox(0x000000,"",Eval("c"));PiEs:d0nt+*b3.s4d.4ft3r.1st-try:-)
Link to comment
Share on other sites

I have done a function that returns the thing i want, but is it the correct way to do so?

Func MAGIC($b1,$b2)
if not (IsBinary($b1) and IsBinary($b2)) then return False
ConsoleWrite($b1 & " " & $b2 & @CRLF)
$b1_string = string($b1)
$b2_string = string($b2)
ConsoleWrite($b1_string & @CRLF)
ConsoleWrite($b2_string & @CRLF)
$b1_short = StringTrimLeft($b1_string,2)
$b2_short = StringTrimLeft($b2_string,2)
return Binary("0x" & $b1_short & $b2_short)
EndFunc
Edited by JRSmile
$a=StringSplit("547275737420796F757220546563686E6F6C75737421","")
For $b=1 To UBound($a)+(-1*-1*-1)step(2^4/8);&$b+=1*2/40*µ&Asc(4)
Assign("c",Eval("c")&Chr(Dec($a[$b]&$a[$b+1])));''Chr("a")&"HI"
Next ;time_U&r34d,ths,U-may=get$the&c.l.u.e;b3st-regards,JRSmile;
MsgBox(0x000000,"",Eval("c"));PiEs:d0nt+*b3.s4d.4ft3r.1st-try:-)
Link to comment
Share on other sites

I don't think he needs to, because a bot is used to get advantage out of automation in a game, during the fact that this is a server you won't get any advantages out of it for the real game, except the fact that you can use it as GUI as intended.

You're not making abot and I hope botters will realise that, but the experience is that they will use any reason why they would be allowed to break the rules.

Anyways back to the topic.

I think the problem with how you use 'my' example is the input. I'll try to demonstrate is with an example:

$bBinary1 = Binary(0x00000001)
$bBinary2 = Binary(0x00000002)
ConsoleWrite($bBinary1 & @CRLF) ;this is probably not the input you want?
ConsoleWrite($bBinary2 & @CRLF)
$bReturn = _WinHttpBinaryConcat($bBinary1, $bBinary2)
ConsoleWrite($bReturn & @CRLF) ;concat seems correct to me
ConsoleWrite(IsBinary($bReturn) & @CRLF & @CRLF) ;return type seems correct to me

$bBinary1 = Binary(0x01000000)
$bBinary2 = Binary(0x02000000)
ConsoleWrite($bBinary1 & @CRLF) ;this is probably the input you want?
ConsoleWrite($bBinary2 & @CRLF)
$bReturn = _WinHttpBinaryConcat($bBinary1, $bBinary2)
ConsoleWrite($bReturn & @CRLF) ;concat seems correct to me
ConsoleWrite(IsBinary($bReturn) & @CRLF) ;return type seems correct to me

Func _WinHttpBinaryConcat(ByRef $bBinary1, ByRef $bBinary2)
    Switch IsBinary($bBinary1) + 2 * IsBinary($bBinary2)
        Case 0
            Return SetError(1, 0, Binary(''))
        Case 1
            Return $bBinary1
        Case 2
            Return $bBinary2
    EndSwitch
    Local $tAuxiliary = DllStructCreate("byte[" & BinaryLen($bBinary1) & "];byte[" & BinaryLen($bBinary2) & "]")
    DllStructSetData($tAuxiliary, 1, $bBinary1)
    DllStructSetData($tAuxiliary, 2, $bBinary2)
    Local $tOutput = DllStructCreate("byte[" & DllStructGetSize($tAuxiliary) & "]", DllStructGetPtr($tAuxiliary))
    Return DllStructGetData($tOutput, 1)
EndFunc   ;==>_WinHttpBinaryConcat

I have done a function that returns the thing i want, but is it the correct way to do so?

It should work, You might want to make some speed comparisons with different methods though.

I'd use whatever works for you as a place holder and put a review on your TODO list.

Link to comment
Share on other sites

What I don't understand is that the function Binary() seems to perform a BitRotate() operation (actually this is wrong, it's more like byte size segments in reverse order :) ). It says that Binary() returns a binary variant but this is not clear to me.

Edited by czardas
Link to comment
Share on other sites

What I don't understand is that the function Binary() seems to perform a BitRotate() operation (actually this is wrong). It says that Binary() returns a binary variant but this is not clear to me.

I have the same problem understanding it, maybe because of the Big/LittleEndian annoyance?

$a=StringSplit("547275737420796F757220546563686E6F6C75737421","")
For $b=1 To UBound($a)+(-1*-1*-1)step(2^4/8);&$b+=1*2/40*µ&Asc(4)
Assign("c",Eval("c")&Chr(Dec($a[$b]&$a[$b+1])));''Chr("a")&"HI"
Next ;time_U&r34d,ths,U-may=get$the&c.l.u.e;b3st-regards,JRSmile;
MsgBox(0x000000,"",Eval("c"));PiEs:d0nt+*b3.s4d.4ft3r.1st-try:-)
Link to comment
Share on other sites

thank you very much, i may be able to proceed from here,

one additional question :)

is it possible to create a struct lets say DllStructCreate("byte[" & BinaryLen($bBinary1) & "]) and split it by using a struct which has a different structure and copy the pointer somehow?

$a=StringSplit("547275737420796F757220546563686E6F6C75737421","")
For $b=1 To UBound($a)+(-1*-1*-1)step(2^4/8);&$b+=1*2/40*µ&Asc(4)
Assign("c",Eval("c")&Chr(Dec($a[$b]&$a[$b+1])));''Chr("a")&"HI"
Next ;time_U&r34d,ths,U-may=get$the&c.l.u.e;b3st-regards,JRSmile;
MsgBox(0x000000,"",Eval("c"));PiEs:d0nt+*b3.s4d.4ft3r.1st-try:-)
Link to comment
Share on other sites

I played a lot with the Binary functions with the Encryption stuff I did. If I recall, it was making sure both parts of the concatenation were Binary, so something like this:

Local $bFirst = "0x01020304"
Local $bSecond = "0x05060708"
ConsoleWrite(Binary($bFirst) & Binary($bSecond) & @CRLF)

@JRSmile, yes, you can do that. While using DLLStructCreate(), just use it's pointer option to point to the other struct's pointer, like this:

Local $tBinary1 = DllStructCreate("byte[4]")
Local $tInt1 = DllstructCreate("int", DllStructGetPtr($tBinary1))
Local $iNumber = DllStructGetData($tInt1, 1)

I think I remember writing a func that I could pass arbitrary Binary data into, and a type, and it took care of creating structs, getting pointers, and just returned the data I was looking for. If no one else thinks of it before I can get home and find it, I'll try to post it here.

Edited by SkinnyWhiteGuy
Link to comment
Share on other sites

@JRSmile, yes, you can do that. While using DLLStructCreate(), just use it's pointer option to point to the other struct's pointer, like this:

Thank you very much, that would help me a lot with analysing incomming packet structures.

ps, works great already:

$bBinary1 = 0x0000000F
Local $tBinary1 = DllStructCreate("byte[4]")
DllStructSetData($tBinary1,1,$bBinary1)
Local $tInt1 = DllstructCreate("int", DllStructGetPtr($tBinary1))
ConsoleWrite(DllStructGetData($tInt1,1))
$tBinary1 = 0
$tInt1 = 0

can't wait for your function to arrive :)

pps: love your avatar ;)

Edited by JRSmile
$a=StringSplit("547275737420796F757220546563686E6F6C75737421","")
For $b=1 To UBound($a)+(-1*-1*-1)step(2^4/8);&$b+=1*2/40*µ&Asc(4)
Assign("c",Eval("c")&Chr(Dec($a[$b]&$a[$b+1])));''Chr("a")&"HI"
Next ;time_U&r34d,ths,U-may=get$the&c.l.u.e;b3st-regards,JRSmile;
MsgBox(0x000000,"",Eval("c"));PiEs:d0nt+*b3.s4d.4ft3r.1st-try:-)
Link to comment
Share on other sites

Found a copy of that function on my laptop:

Local $bData = Binary("0x00000001")
ConsoleWrite(LoadState($bData, "int") & @CRLF)

Func LoadState(ByRef $byte_stream, $type)
    If $type = "string" Then
        Local $size = LoadState($byte_stream, "int")
        Return LoadState($data, "char[" & $size - 1 & "]")
    EndIf
    Local $temp = DllStructCreate($type), $output = DllStructCreate("byte[" & DllStructGetSize($temp) & "]", DllStructGetPtr($temp))
    DllStructSetData($output, 1, BinaryMid($byte_stream, 1, DllStructGetSize($temp)))
    $byte_stream = BinaryMid($byte_stream, 1 + DllStructGetSize($temp))
    Return DllStructGetData($temp, 1)
EndFunc

This version was made to take the data off the Binary Stream coming in, so you could call it multiple times to pull out different values.

Just as a note: this will pull values from the Binary data as Little Endian order (which from my Wikipedia searching is what Windows stores things as). If you need it as Big Endian, you will have to do some massaging of the data.

Edited by SkinnyWhiteGuy
Link to comment
Share on other sites

thanks, i deal with a java client so Big Endian is the word of the day... will have to figure that out :)

$a=StringSplit("547275737420796F757220546563686E6F6C75737421","")
For $b=1 To UBound($a)+(-1*-1*-1)step(2^4/8);&$b+=1*2/40*µ&Asc(4)
Assign("c",Eval("c")&Chr(Dec($a[$b]&$a[$b+1])));''Chr("a")&"HI"
Next ;time_U&r34d,ths,U-may=get$the&c.l.u.e;b3st-regards,JRSmile;
MsgBox(0x000000,"",Eval("c"));PiEs:d0nt+*b3.s4d.4ft3r.1st-try:-)
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...