Jump to content

blob object & Protocol Buffers


Recommended Posts

blob object ==>  
https://developer.mozilla.org/en-US/docs/Web/API/Blob

protobuf (Protocol Buffers) ==>
https://developers.google.com/protocol-buffers
https://developers.google.com/protocol-buffers/docs/overview

Now problem is when connecting to site via websocket some of the site sends binary data as blob object / protobuf.

I thought I could able to decode the data using base64 code available on forum.
I also try https://www.base64decode.org for decoding the data but no luck.

On google search find code / example to transfer this blob object & protobuf to readable string but all are written in python or javascript.
So how do I decode the blob object & protobuf data to readable string in Autoit?

If asked I can provide link of the site I am trying to connect.
Thanks.

Edited by jugador
Link to comment
Share on other sites

for Protocol Buffers type data =>
check stackoverflow link it contain  site Name + returned data sample + python github link
https://stackoverflow.com/questions/59321908/decode-websocket-received-data

or to view sample data under ws tab of network monitor

Protocol Buffers sample data

blob object sample data

and to extract data from a Blob ==> https://stackoverflow.com/a/23024504
https://developer.mozilla.org/en-US/docs/Web/API/FileReader

Link to comment
Share on other sites

Is this mean that using webdriver it should be possible to catch downloaded pdf directly as a BinaryFormat instead as a file ?

Edited by mLipok

Signature beginning:
Please remember: "AutoIt"..... *  Wondering who uses AutoIt and what it can be used for ? * Forum Rules *
ADO.au3 UDF * POP3.au3 UDF * XML.au3 UDF * IE on Windows 11 * How to ask ChatGPT for AutoIt Codefor other useful stuff click the following button:

Spoiler

Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind. 

My contribution (my own projects): * Debenu Quick PDF Library - UDF * Debenu PDF Viewer SDK - UDF * Acrobat Reader - ActiveX Viewer * UDF for PDFCreator v1.x.x * XZip - UDF * AppCompatFlags UDF * CrowdinAPI UDF * _WinMergeCompare2Files() * _JavaExceptionAdd() * _IsBeta() * Writing DPI Awareness App - workaround * _AutoIt_RequiredVersion() * Chilkatsoft.au3 UDF * TeamViewer.au3 UDF * JavaManagement UDF * VIES over SOAP * WinSCP UDF * GHAPI UDF - modest begining - comunication with GitHub REST APIErrorLog.au3 UDF - A logging Library * Include Dependency Tree (Tool for analyzing script relations) * Show_Macro_Values.au3 *

 

My contribution to others projects or UDF based on  others projects: * _sql.au3 UDF  * POP3.au3 UDF *  RTF Printer - UDF * XML.au3 UDF * ADO.au3 UDF SMTP Mailer UDF * Dual Monitor resolution detection * * 2GUI on Dual Monitor System * _SciLexer.au3 UDF * SciTE - Lexer for console pane

Useful links: * Forum Rules * Forum etiquette *  Forum Information and FAQs * How to post code on the forum * AutoIt Online Documentation * AutoIt Online Beta Documentation * SciTE4AutoIt3 getting started * Convert text blocks to AutoIt code * Games made in Autoit * Programming related sites * Polish AutoIt Tutorial * DllCall Code Generator * 

Wiki: Expand your knowledge - AutoIt Wiki * Collection of User Defined Functions * How to use HelpFile * Good coding practices in AutoIt * 

OpenOffice/LibreOffice/XLS Related: WriterDemo.au3 * XLS/MDB from scratch with ADOX

IE Related:  * How to use IE.au3  UDF with  AutoIt v3.3.14.x * Why isn't Autoit able to click a Javascript Dialog? * Clicking javascript button with no ID * IE document >> save as MHT file * IETab Switcher (by LarsJ ) * HTML Entities * _IEquerySelectorAll() (by uncommon) * IE in TaskSchedulerIE Embedded Control Versioning (use IE9+ and HTML5 in a GUI) * PDF Related:How to get reference to PDF object embeded in IE * IE on Windows 11

I encourage you to read: * Global Vars * Best Coding Practices * Please explain code used in Help file for several File functions * OOP-like approach in AutoIt * UDF-Spec Questions *  EXAMPLE: How To Catch ConsoleWrite() output to a file or to CMD *

I also encourage you to check awesome @trancexx code:  * Create COM objects from modules without any demand on user to register anything. * Another COM object registering stuffOnHungApp handlerAvoid "AutoIt Error" message box in unknown errors  * HTML editor

winhttp.au3 related : * https://www.autoitscript.com/forum/topic/206771-winhttpau3-download-problem-youre-speaking-plain-http-to-an-ssl-enabled-server-port/

"Homo sum; humani nil a me alienum puto" - Publius Terentius Afer
"Program are meant to be read by humans and only incidentally for computers and execute" - Donald Knuth, "The Art of Computer Programming"
:naughty:  :ranting:, be  :) and       \\//_.

Anticipating Errors :  "Any program that accepts data from a user must include code to validate that data before sending it to the data store. You cannot rely on the data store, ...., or even your programming language to notify you of problems. You must check every byte entered by your users, making sure that data is the correct type for its field and that required fields are not empty."

Signature last update: 2023-04-24

Link to comment
Share on other sites

Looks like a standard base64 encoded string to me. "No luck" doesn't really help explain why it didn't work for you. I'm guessing that you forgot to call BinaryToString --

$sData = "CgRBTVpOFaQY3EQY4Kn0/99bKgNOTVMwCDgBRYjKzDxIyvN9ZQBQ4T7YAQQ="
$bData = _Base64Decode($sData)

ConsoleWrite($bData & @crlf)
ConsoleWrite(BinaryToString($bData) & @crlf)

Func _Base64Decode($input_string)

    Local $struct = DllStructCreate("int")

    $a_Call = DllCall("Crypt32.dll", "int", "CryptStringToBinary", _
            "str", $input_string, _
            "int", 0, _
            "int", 1, _
            "ptr", 0, _
            "ptr", DllStructGetPtr($struct, 1), _
            "ptr", 0, _
            "ptr", 0)

    If @error Or Not $a_Call[0] Then
        Return SetError(1, 0, "") ; error calculating the length of the buffer needed
    EndIf

    Local $a = DllStructCreate("byte[" & DllStructGetData($struct, 1) & "]")

    $a_Call = DllCall("Crypt32.dll", "int", "CryptStringToBinary", _
            "str", $input_string, _
            "int", 0, _
            "int", 1, _
            "ptr", DllStructGetPtr($a), _
            "ptr", DllStructGetPtr($struct, 1), _
            "ptr", 0, _
            "ptr", 0)

    If @error Or Not $a_Call[0] Then
        Return SetError(2, 0, ""); error decoding
    EndIf

    Return DllStructGetData($a, 1)

EndFunc   ;==>_Base64Decode

I haven't looked at the blob portion yet.

Link to comment
Share on other sites

@Danp2

"No luck" define using base64 decode failed to get readable string.
Now when you run this code you get readable data / string

$sData = "SGVsbG8gV29ybGQ="
$bData = _Base64Decode($sData)

ConsoleWrite($bData & @crlf)
ConsoleWrite(BinaryToString($bData) & @crlf)

so on running your code do do you get readable output?

If you scroll down stackoverflow link(provided above) you will see on proper decode you will get string like this....

"{"id":"PCG","price":10.97,"time":"1576616325000","exchange":"NYQ","quoteType":"EQUITY","marketHours":"REGULAR_MARKET","changePercent":13.443642,"dayVolume":"31495549","change":1.3000002,"priceHint":"2"}"

https://stackoverflow.com/a/59382147

Quote

Protobuf is open technology which allows to create marshalling code for multiple languages automatically when meta description of message is known.

the given stackoverflow link contain
> .proto (protobuf meta description) file
> protobuf compiler process
> python github link

Please check the given link on this thread to know how Protobuf work :D

Link to comment
Share on other sites

Here's an initial attempt at decoding a protobuf. Anyone is welcome to make improvements / corrections --

$sData = "CgNQQ0cVH4UvQRiQvr/a4lsqA05ZUTAIOAFFKBlXQUj61YQeZWhmpj/YAQQ="

;~ Results from https://protogen.marcgravell.com/decode
;~ Field #1: 0A String Length = 3, Hex = 03, UTF8 = "PCG"
;~ Field #2: 15 Fixed32 Value = 1093633311, Hex = 1F-85-2F-41
;~ Field #3: 18 Varint Value = 3153232650000, Hex = 90-BE-BF-DA-E2-5B
;~ Field #5: 2A String Length = 3, Hex = 03, UTF8 = "NYQ"
;~ Field #6: 30 Varint Value = 8, Hex = 08
;~ Field #7: 38 Varint Value = 1, Hex = 01
;~ Field #8: 45 Fixed32 Value = 1096227112, Hex = 28-19-57-41
;~ Field #9: 48 Varint Value = 62991098, Hex = FA-D5-84-1E
;~ Field #12: 65 Fixed32 Value = 1067869800, Hex = 68-66-A6-3F
;~ Field #27: D8-01 Varint Value = 4, Hex = 04

$bData = _Base64Decode($sData)
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $bData = ' & $bData & @CRLF) ;### Debug Console

$iPos = 1
$iLen = BinaryLen($bData)

While $iPos <= $iLen
    $bTag = BinaryMid($bData, $iPos, 1)

    $bField = BitShift($bTag, 3)
    $iWire  = BitAND($bTag, 7)

;~  ConsoleWrite("+> $iPos = " & $iPos & " - $bTag = " & $bTag & " - $bField = " & $bField & " - $iWire = " & $iWire  & @crlf)

    If BitAND($bField, 16) Then
        $bTag = BinaryMid($bData, $iPos + 1, 1) & BitAND($bField, 16)
        $iPos += 1
    EndIf

    Switch $iWire
        Case 0 ; VarInt
            $iEnd = $iPos + 1

            While $iEnd <= $iLen
                $bCompare = BinaryMid($bData, $iEnd, 1)
                If Not BitAND($bCompare, 128) Then ExitLoop

                $iEnd += 1
            WEnd

            $sResult = BinaryToString(BinaryMid($bData, $iPos + 1, $iEnd - $iPos))
            ConsoleWrite("(" & $iPos & ") " & $bField & " - " & Binary($sResult) & @crlf)
            $iPos = $iEnd

        Case 1 ; Fixed64

        Case 2 ; Length-delimited
            $bLen = BinaryMid($bData, $iPos + 1, 1)
            $sResult = BinaryToString(BinaryMid($bData, $iPos + 2, $bLen))

            ConsoleWrite("(" & $iPos & ") " & $bField & " - " & $sResult & @crlf)
            $iPos += Number($bLen) + 1

        Case 3 ; start group

        Case 4 ; end group

        Case 5 ; Fixed32
            $sResult = BinaryToString(BinaryMid($bData, $iPos + 1, 4))
            ConsoleWrite("(" & $iPos & ") " & $bField & " - " & Binary($sResult) & @crlf)
            $iPos += 4

    EndSwitch

    $iPos += 1
WEnd

Func _Base64Decode($input_string)

    Local $struct = DllStructCreate("int")

    $a_Call = DllCall("Crypt32.dll", "int", "CryptStringToBinary", _
            "str", $input_string, _
            "int", 0, _
            "int", 1, _
            "ptr", 0, _
            "ptr", DllStructGetPtr($struct, 1), _
            "ptr", 0, _
            "ptr", 0)

    If @error Or Not $a_Call[0] Then
        Return SetError(1, 0, "") ; error calculating the length of the buffer needed
    EndIf

    Local $a = DllStructCreate("byte[" & DllStructGetData($struct, 1) & "]")

    $a_Call = DllCall("Crypt32.dll", "int", "CryptStringToBinary", _
            "str", $input_string, _
            "int", 0, _
            "int", 1, _
            "ptr", DllStructGetPtr($a), _
            "ptr", DllStructGetPtr($struct, 1), _
            "ptr", 0, _
            "ptr", 0)

    If @error Or Not $a_Call[0] Then
        Return SetError(2, 0, ""); error decoding
    EndIf

    Return DllStructGetData($a, 1)

EndFunc   ;==>_Base64Decode

 

Link to comment
Share on other sites

Thanks @Danp2

Sorry for the trouble and it’s just because I don’t know python.
So thinking off opening a new thread to ask how to install python 😅 & run this github code.

;~ CgNQQ0cVH4UvQRiQvr/a4lsqA05ZUTAIOAFFKBlXQUj61YQeZWhmpj/YAQQ=
;~ Field #1: "PCG"      
;~ Field #2: 1093633311     ==> 10.97
;~ Field #3: 3153232650000  ==> 1576616325000
;~ Field #5: "NYQ"
;~ Field #8: 1096227112     ==> 13.4436416625977
;~ Field #9: 62991098       ==> 31495549
;~ Field #12: 1067869800    ==> 1.30000019073486


ConsoleWrite("-> price = " & IntToFlt(1093633311) & @crlf)              ;~ price = 10.9700002670288
ConsoleWrite("-> changePercent = " & IntToFlt(1096227112) & @crlf)      ;~ changePercent = 13.4436416625977
ConsoleWrite("-> change = " & IntToFlt(1067869800) & @crlf)             ;~ change = 1.30000019073486

ConsoleWrite("-> time = " & (3153232650000/2) & @crlf)                  ;~ time = 1576616325000
ConsoleWrite("-> dayVolume = " & (62991098/2) & @crlf)                  ;~ dayVolume = 31495549

Func IntToFlt($iVal)
; https://www.autoitscript.com/forum/topic/53842-integer-to-float-conversion/?do=findComment&comment=407905
Local $result
$fs = DllStructCreate("float")
$is = DllStructCreate("int64",DllStructGetPtr($fs))

DllStructSetData($is,1,$iVal)

$result =  DllStructGetData($fs,1)
$fs = 0
$is = 0
return $result
endfunc

 

Edited by jugador
Link to comment
Share on other sites

able to convert Hex to Fixed32 Value correctly....

;~ Field #2: 15 Fixed32 Value = 1093633311, Hex = 1F-85-2F-41
ConsoleWrite(__Hex2Dec('0x1F852F41', 3) & @CRLF)    ;~ 1093633311

; #FUNCTION# =============================================================================
; Name...........: __Hex2Dec
; =========================================================================================
Func __Hex2Dec($x_Hex, $x_StartPoint = 1)
    Local $o_Temp
    For $i = $x_StartPoint To StringLen($x_Hex) Step 2
        $o_Temp = StringMid($x_Hex, $i, 2) & $o_Temp
    Next
    Return Dec($o_Temp, 0)
EndFunc ;==>__Hex2Dec

but failed to convert Hex to Varint Value correctly.

;~ Field #3: 18 Varint Value = 3153232650000, Hex = 90-BE-BF-DA-E2-5B

@Danp2

help needed to convert     0x90BEBFDAE25B ==> 3153232650000
or is there way to get the value within the above code posted by you.

Edited by jugador
Link to comment
Share on other sites

I think you got an error somewhere :

ConsoleWrite(Hex(3153232650000) & @CRLF)

shows it is 0x02DE2B4FDF10.  In no way related to your hex...

Here another way to convert binary string to dec :

$bVal = Binary("0x1F852F41")
$tStruct = DllStructCreate("int data")
$tStruct.data = $bVal
ConsoleWrite($tStruct.data & @CRLF)

 

Edited by Nine
Link to comment
Share on other sites

@Nine  if you look at @Danp2 code  you will see this at the beginning

;~ Field #1: 0A String Length = 3, Hex = 03, UTF8 = "PCG"
;~ Field #2: 15 Fixed32 Value = 1093633311, Hex = 1F-85-2F-41
;~ Field #3: 18 Varint Value = 3153232650000, Hex = 90-BE-BF-DA-E2-5B
;~ Field #5: 2A String Length = 3, Hex = 03, UTF8 = "NYQ"
;~ Field #6: 30 Varint Value = 8, Hex = 08
;~ Field #7: 38 Varint Value = 1, Hex = 01
;~ Field #8: 45 Fixed32 Value = 1096227112, Hex = 28-19-57-41
;~ Field #9: 48 Varint Value = 62991098, Hex = FA-D5-84-1E
;~ Field #12: 65 Fixed32 Value = 1067869800, Hex = 68-66-A6-3F
;~ Field #27: D8-01 Varint Value = 4, Hex = 04

 

you can crosscheck the base64(date) using this site https://protogen.marcgravell.com/decode

CgNQQ0cVH4UvQRiQvr/a4lsqA05ZUTAIOAFFKBlXQUj61YQeZWhmpj/YAQQ=

 

for protobuf varints check this link https://developers.google.com/protocol-buffers/docs/encoding#varints

 

check this Python code on https://www.tutorialspoint.com/execute_python3_online.php
you will get same result as per protogen.marcgravell.com

# ;~ Field #9: 48 Varint Value = 62991098, Hex = 0xFAD5841E
import struct

def pack_varint(val):
    total = b''
    if val < 0:
        val = (1<<32)+val
    while val>=0x80:
        bits = val&0x7F
        val >>= 7
        total += struct.pack('B', (0x80|bits))
    bits = val&0x7F
    total += struct.pack('B', bits)
    return total

print ('protobuf varints ==> ' , pack_varint(62991098));
print('Hex ==> ' , hex(62991098))

 

python code for Hex to Varints but it's giving error....

def unpack_varint(buff):
    total = 0
    shift = 0
    val = 0x80
    while val&0x80:
        val = struct.unpack('B', buff.read(1))[0]
        total |= ((val&0x7F)<<shift)
        shift += 7
    if total&(1<<31):
        total = total - (1<<32)
    return total

 

Edited by jugador
Link to comment
Share on other sites

I see.  I was not aware of those VarInt things.   So here how to convert VarInt Hex to Decimal (up to 64 bits) :

#AutoIt3Wrapper_UseX64=y
#include "x64_Ops.au3"

Local $bData = Binary("0x90BEBFDAE25B")
;Local $bData = Binary("0xFAD5841E")
Local $iResult = 0, $iShift = 0
For $i = 1 To BinaryLen($bData)
  $iResult += _BitSHIFT64(BitAND(BinaryMid($bData, $i, 1), 0x7F), $iShift)
  $iShift -= 7
Next

ConsoleWrite($iResult & @CRLF)

You will need to use my x64 UDF to make it work though (see my signature).

Edited by Nine
Link to comment
Share on other sites

:cheer: Thanks @Nine
hope not to disturb you guys on protobuf issue anymore :D

@Nine one more thing to ask
do you know what blob object is and how to decode it.

can you please have a look at the blob object sample data

under  ws(websocket) Tab of network monitor (<= Chrome / Firefox)

will get json string (guessing) on decoding the blob object.

Edited by jugador
Link to comment
Share on other sites

Integrated my snippets inside @Danp2 example to create a more generalized script :

#AutoIt3Wrapper_UseX64=y
#include "x64_Ops.au3"
#include <Constants.au3>

Local Const $aType = ["VarInt", "Fixed64", "String", "Start Group", "End Group", "Fixed32"]

$sData = "CgNQQ0cVH4UvQRiQvr/a4lsqA05ZUTAIOAFFKBlXQUj61YQeZWhmpj/YAQQ="

;~ Results from https://protogen.marcgravell.com/decode
;~ Field #1: 0A String Length = 3, Hex = 03, UTF8 = "PCG"
;~ Field #2: 15 Fixed32 Value = 1093633311, Hex = 1F-85-2F-41
;~ Field #3: 18 Varint Value = 3153232650000, Hex = 90-BE-BF-DA-E2-5B
;~ Field #5: 2A String Length = 3, Hex = 03, UTF8 = "NYQ"
;~ Field #6: 30 Varint Value = 8, Hex = 08
;~ Field #7: 38 Varint Value = 1, Hex = 01
;~ Field #8: 45 Fixed32 Value = 1096227112, Hex = 28-19-57-41
;~ Field #9: 48 Varint Value = 62991098, Hex = FA-D5-84-1E
;~ Field #12: 65 Fixed32 Value = 1067869800, Hex = 68-66-A6-3F
;~ Field #27: D8-01 Varint Value = 4, Hex = 04

$bData = _Base64Decode($sData)
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $bData = ' & $bData & @CRLF) ;### Debug Console

Local $iPos = 1, $iLen = BinaryLen($bData), $iTag, $sResult, $iResult

While $iPos <= $iLen
  $sResult = VarInt($bData, $iPos, $iTag)
  $iField = BitShift($iTag, 3)
  $iWire = BitAND($iTag, 7)
  ConsoleWrite("Field #" & $iField & ": " & $sResult & " " & $aType[$iWire])

  Switch $iWire
    Case 0     ; VarInt
      $sResult = VarInt($bData, $iPos, $iResult)
      ConsoleWrite(" Value = " & $iResult & " Hex = " & $sResult & @CRLF)
    Case 1     ; Fixed64
      $sResult = BinaryMid($bData, $iPos, 8)
      $iResult = Fixed($sResult)
      ConsoleWrite(" Value = " & $iResult & " Hex = " & Hex($sResult) & @CRLF)
      $iPos += 8
    Case 2     ; Length-delimited
      $bLen = BinaryMid($bData, $iPos, 1)
      $sResult = BinaryToString(BinaryMid($bData, $iPos + 1, $bLen), $SB_UTF8)
      ConsoleWrite(" (" & Int($bLen) & ") = " & $sResult & @CRLF)
      $iPos += Number($bLen) + 1
    Case 3     ; start group
      ConsoleWrite(@CRLF)
    Case 4     ; end group
      ConsoleWrite(@CRLF)
    Case 5     ; Fixed32
      $sResult = BinaryMid($bData, $iPos, 4)
      $iResult = Fixed($sResult)
      ConsoleWrite(" Value = " & $iResult & " Hex = " & Hex($sResult) & @CRLF)
      $iPos += 4
  EndSwitch
WEnd

Func _Base64Decode($input_string)
  Local $struct = DllStructCreate("int")
  $a_Call = DllCall("Crypt32.dll", "int", "CryptStringToBinary", _
      "str", $input_string, _
      "int", 0, _
      "int", 1, _
      "ptr", 0, _
      "ptr", DllStructGetPtr($struct, 1), _
      "ptr", 0, _
      "ptr", 0)
  If @error Or Not $a_Call[0] Then Return SetError(1, 0, "")   ; error calculating the length of the buffer needed

  Local $a = DllStructCreate("byte[" & DllStructGetData($struct, 1) & "]")
  $a_Call = DllCall("Crypt32.dll", "int", "CryptStringToBinary", _
      "str", $input_string, _
      "int", 0, _
      "int", 1, _
      "ptr", DllStructGetPtr($a), _
      "ptr", DllStructGetPtr($struct, 1), _
      "ptr", 0, _
      "ptr", 0)
  If @error Or Not $a_Call[0] Then Return SetError(2, 0, "")  ; error decoding
  Return DllStructGetData($a, 1)
EndFunc   ;==>_Base64Decode

Func VarInt(ByRef Const $bStream, ByRef $iPos, ByRef $iResult)
  Local $iVal, $iStart = $iPos, $iShift
  $iResult = 0
  While True
    $iVal = BinaryMid($bStream, $iPos, 1)
    $iResult += _BitSHIFT64(BitAND($iVal, 0x7F), $iShift)
    $iShift -= 7
    $iPos += 1
    If Not BitAND($iVal, 0x80) Then ExitLoop
  WEnd
  Return Hex(BinaryMid($bStream, $iStart, $iPos - $iStart))
EndFunc   ;==>VarInt

Func Fixed($bVal)
  Local $iLen = BinaryLen($bVal)
  Local $tStruct = DllStructCreate(($bVal = 4 ? "int" : "int64") & " data")
  $tStruct.data = $bVal
  Return $tStruct.data
EndFunc

 

Edited by Nine
Link to comment
Share on other sites

@Nine & @Danp2 Idea is to decode Protobuf data to json ==> https://stackoverflow.com/a/59382147

CgRBTVpOFaQY3EQY4Kn0/99bKgNOTVMwCDgBRYjKzDxIyvN9ZQBQ4T7YAQQ=
"{"id":"PCG","price":10.97,"time":"1576616325000","exchange":"NYQ","quoteType":"EQUITY","marketHours":"REGULAR_MARKET","changePercent":13.443642,"dayVolume":"31495549","change":1.3000002,"priceHint":"2"}"

ProtobufToJson

prerequisite => @Nine x64 bitwise operations udf
link to Proto schema for this code

ProtobufToJson.au3

 

@Danp2 can you test this code with your autoit-websocket udf

Local $aSites[1][3] = [['streamer.finance.yahoo.com', '', '{"subscribe":["AMZN"]}']]
ConsoleWrite("Received message from the server: '" & __Protobuf_ToJson(BinaryToString($bRecv)) & "'" & @CRLF)

 

Edited by jugador
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

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...