Kitz ADSL Broadband Information
adsl spacer  
Support this site
Home Broadband ISPs Tech Routers Wiki Forum
 
     
   Compare ISP   Rate your ISP
   Glossary   Glossary
 
Please login or register.

Login with username, password and session length
Advanced search  

News:

Pages: [1] 2

Author Topic: how to capture a signature and insert into SQL database as IMAGE field type  (Read 12619 times)

chenks

  • Kitizen
  • ****
  • Posts: 1106

this is going to be quite a niche thing, but here goes.

does anyone have an experience in capturing a signature on a website (via a form primarily) which, when submitted, gets inserted into an SQL database field where the field type is "image"?
it's an SQL 2012 server, and it's IIS on Windows Server 2008 R2 (likely to be upgraded to Server 2016 in the neat future). the site (which is mostly for intranet purposes, used Classic ASP in the majority).

i already have a form which updates other fields in the database just fine (varchar, int, text etc etc), so there is no issue using the form for the expected purpose, the only issue i have is working out how to capture the image and have that inserted into the database.

i was able to create a basic signature draw script (using signature-pad), which lets me draw the signature on screen, but i'm at a loss from that point as to how to convert that into what would be sent to the UPDATE SQL query.

this is what i've been using for the existing part of the form (which works as expected), to update the other fields

Code: [Select]
<%
form_outcome = Encode(cstr(request.form("outcome")))
form_engineersreport = Encode(cstr(request.form("engineersreport")))
form_time1 = Encode(cstr(request.form("travelstart")))
form_time2 = Encode(cstr(request.form("onsite")))
form_time3 = Encode(cstr(request.form("offsite")))
form_ctsuser = Encode(cstr(request.form("ctsuser")))
form_callref = Encode(cstr(request.form("callref")))
form_ceid = Encode(cstr(request.form("ceid")))

OpenDB()

With Server.CreateObject("ADODB.Command")
  Set .ActiveConnection = dbConn
  .CommandText = "sp_engineerportal_TradesUpdateJob"
  .CommandType = adCmdStoredProc
    .Parameters.Append .CreateParameter( _
    "@newStatus", adVarWChar, adParamInput, 20, form_outcome _
  )
    .Parameters.Append .CreateParameter( _
    "@memo", adVarWChar, adParamInput, 4000, form_engineersreport _
  )
    .Parameters.Append .CreateParameter( _
    "@travelStart", adDBTimeStamp, adParamInput, , form_travelstart _
  )
    .Parameters.Append .CreateParameter( _
    "@onSite", adDBTimeStamp, adParamInput, , form_onsite _
  )
    .Parameters.Append .CreateParameter( _
    "@offSite", adDBTimeStamp, adParamInput, , form_offsite _
  )
    .Parameters.Append .CreateParameter( _
    "@subCon", adVarWChar, adParamInput, 128, form_ctsuser _
  )  
    .Parameters.Append .CreateParameter( _
    "@callRef", adInteger , adParamInput, , form_callref _
  )
    .Parameters.Append .CreateParameter( _
    "@ceid", adInteger , adParamInput, , form_ceid _
  )
  Set update_job = .Execute
End With

Call CloseDB()
%>

the alternate option would be for the signature to be saved as an image file (JPG, PNG etc) in a folder on the webserver, and then a server side script runs later on to insert it into the database.
« Last Edit: October 25, 2022, 03:07:26 PM by chenks »
Logged

licquorice

  • Reg Member
  • ***
  • Posts: 977

No idea if this makes sense, its from my SQL savvy son.

Think some weirdities about the IMAGE data type, better off using VARBINARY(MAX) from memory. But essentially just need to convert into binary and then insert like any other field. Probably need to do a bit in JavaScript on the front end and pass it on to the form as base64 encoded. 

Otherwise SQL server will let you read from a file stored on disk easily enough.
Logged

chenks

  • Kitizen
  • ****
  • Posts: 1106

i have no control over the SQL field type, it's in table that's already in use, i can't change the field type.



yes, the issue i have it trying to work out how to change the captured signature to what i need it to be allow it to be inserted

example, this is how one looks that is already in the table (inserted via another tool)

Code: [Select]
0xFFD8FFE000104A46494600010101006000600000FFE1003A4578696600004D4D002A00000008000351100001000000010100000051110004000000010000000051120004000000010000000000000000FFDB004300080606070605080707070909080A0C140D0C0B0B0C1912130F141D1A1F1E1D1A1C1C20242E2720222C231C1C2837292C30313434341F27393D38323C2E333432FFDB0043010909090C0B0C180D0D1832211C213232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232FFC000110800B402F203012200021101031101FFC4001F0000010501010101010100000000000000000102030405060708090A0BFFC400B5100002010303020403050504040000017D01020300041105122131410613516107227114328191A1082342B1C11552D1F02433627282090A161718191A25262728292A3435363738393A434445464748494A535455565758595A636465666768696A737475767778797A838485868788898A92939495969798999AA2A3A4A5A6A7A8A9AAB2B3B4B5B6B7B8B9BAC2C3C4C5C6C7C8C9CAD2D3D4D5D6D7D8D9DAE1E2E3E4E5E6E7E8E9EAF1F2F3F4F5F6F7F8F9FAFFC4001F0100030101010101010101010000000000000102030405060708090A0BFFC400B51100020102040403040705040400010277000102031104052131061241510761711322328108144291A1B1C109233352F0156272D10A162434E125F11718191A262728292A35363738393A434445464748494A535455565758595A636465666768696A737475767778797A82838485868788898A92939495969798999AA2A3A4A5A6A7A8A9AAB2B3B4B5B6B7B8B9BAC2C3C4C5C6C7C8C9CAD2D3D4D5D6D7D8D9DAE2E3E4E5E6E7E8E9EAF2F3F4F5F6F7F8F9FAFFDA000C03010002110311003F00F7FA28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A2B3F53D7748D1115F55D52CAC55F3B4DCCEB1EEC7A6E233F8573E9F1174DBFF2BFB0B4CD675B5958A096CAC5961523D6597627E393401D8515C7A5E78FF53F29A2D2746D0E22E449F6DB97BC942F62123DABF86F34B1F83353BCF29B5DF196B378D1B96315932D844C0FF09110DE7FEFBA00E8352D6F4AD1511F54D4ECEC55F211AEA7588363D37119AC4B7F889A05F43E769C355D4210C57CDB3D26EA54C8EDB963C1FC0D59D27C0BE16D0DD65B0D0ACD2747F316E248FCD9837AF98F96FD6BA1A00E59BC79623A68DE256FA68773FF00C45447E205A0E9E1FF00149FA6893FFF00135D751401C71F8896C3A7867C587E9A2CDFE14C3F11E11D3C29E2E3FF0070692BB4A2803893F1223EDE10F181FF00B83BFF008D27FC2C95EDE0DF189FFB8437FF00155DBD1401C3FF00C2C9F4F0578CBFF055FF00D951FF000B20FF00D093E31FFC160FFE2EBB8A280388FF00858CE7A7823C63FF0082E5FF00E3957B49F19C9AAEA70D91F0A7892C84B9FF0048BCB344893009F9887246718E9D48AEA68A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A2B2EFFC4BA0E933793A8EB7A6D9CBFDCB8BB48DBF2622803528AE423F89DE14B99A4834FBDB9D4A7404F97A7D8CF705B1E85108FD714D5F1AEAB7D6F23E95E06D7E5914E00BE10D9A9FC5DF77FE3B401D8D15C7ADC7C40D4FCA29A7E87A1C4D912FDA2792F655F4215022FE6C684F04DFDEF94DAF78BF5ABF64CEE8AD5D6C61707B1588063F8B9A00DFD535FD1F43556D5755B2B10C095FB4CEB196C7A0279FC2B013E22E9F7FE57F60E95AD6B6B292AB35A59324208F5965D89F8826B4748F03F85F4264934ED0ECA2991B72CED1F99303EBE6365BF5ADFA00E3D2EFE206A9E5347A668BA14449127DB2E1EF2603B10B1EC4FC379A13C15A8DE794DAF78C75ABD64624C566EB630B83D8888073F8BD761450073FA4781BC2FA13A49A7E85651CE8DBD6E1E3F32607D7CC7CB7EB5D05145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145158D73E2FF000CD94A62BAF11693048BC1496F63523F02D401B34571F17C50F085CDC9B6B3D4E5BD9FA04B2B29E727E9B1083443E3C9AEEE1A1B3F06F8A656E76BCB6496E87F195D71401D8515C7C1AEF8DEEE668D7C136D66983B65BDD6131ED95891CD1043F11AE2475BABCF0C58C441DAD6F6D3DCBAFF00DF4E82803B0A2B8F83C2FE2990B8D4BC7D7B246E31B6CB4FB7B723E8CCAE6883E1DD90122DFEBDE25D4A39061A3BAD5E555FCA3282803AC9E786DA179AE2548A2419679182AA8F726B9CBEF88DE0CD3A3DF3F8974D6E71B609C4CF9FF75327F4A8ACBE19782AC199A3F0E58CACDD4DD29B83FF00910B574563A65869709874FB1B6B4889C94B789635FC801401CCC9F116C1D21934CD13C47AAC728CAC969A54AA9FF7D4A107EB4EFF00848BC5D7178B1DA7819E3B66C627D4354862C7D56312115D751401C7C707C45BB7952E2FBC35A6C4C0EC7B7B79AEA45FFBE9907E9F8522F83F5EBBB568756F1E6B1292D9074F820B3C7B642337FE3D5D8D1401C73FC31F0E5DC5126AA353D5DA3E8FA86A73CA7F2DFB7F4AD7B2F07F8674D9124B2F0F6956F2C78DB247671AB8C7FB58CE7DEB6A8A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A00C8D5B5AB8D36E6082DF42D535232A93BECC45B131D98C922E2B0E6F13F8CBCCC5B7C3D9D93B34FAB5B27E8A5ABB3A2803958F52F1CDCC04AF86B47B393B0B9D61DFF004480FF003AA6C7E283BFCABE0F897DDAE643FC96BB6A2803955B1F1DDC5B959F5ED06D243DEDF4A964C7E2D381FA553FF8467C72EF97F886157D22D1611FFA116AEDA8A00E57FE114D627B7F2EF3C73AE3B7F7ADE2B583F9424FEB55A2F878AB3079FC5DE2DB8507251F556453FF007EC29FD6BB3A2803905F85DE0CFB67DAE6D145D4D9C96BCB996E327DC48EC0FE35B365E17F0F69B32CD61A16996B2A9C8782CE3461F8815AD4500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145007FFD900
« Last Edit: October 26, 2022, 08:01:57 AM by chenks »
Logged

chenks

  • Kitizen
  • ****
  • Posts: 1106

i'm not sure it's base64 though, as when i used an online base64 to image site, it fails to show the image from the blob.

as an example, here's the script i use to read an image blob already in the table to display it on a webpage

Code: [Select]
<%@ LANGUAGE="VBSCRIPT" %>

<%Option Explicit
Dim Rs, sSQL, OBJdbConnection

Response.Expires = 0
Response.Buffer = TRUE
Response.Clear
Response.ContentType = "IMAGE/GIF"

Set OBJdbConnection = Server.CreateObject("ADODB.Connection")
OBJdbConnection.Open "Driver={SQL Server}; Server=SQLSERVER; Database=DB UID=user; PWD=pass; Option=4"

sSQL = "Select * from call_events where ce_id = " & request.querystring("ID")
set rs = OBJdbConnection.Execute(sSql)

If not rs.eof then
Response.BinaryWrite rs("ce_technicians_signature_image")
      Response.End
End If
CloseRecordset(rs)%>

<%Set OBJDbConnection = nothing%>

an example here, if the actual signature is saved as a file first, this would update the field with the correct format BLOB

Code: [Select]
SELECT * FROM OPENROWSET(BULK 'G:\sigtemp\test.jpg', SINGLE_BLOB) AS import
so, even if i could get the signature canvas to just save it as a jpg in a folder, i could then use a server side task to update the field in the table
« Last Edit: October 26, 2022, 08:54:27 AM by chenks »
Logged

chenks

  • Kitizen
  • ****
  • Posts: 1106

i've put together a test page showing what i'm trying to achieve.
as a starting point i'd be happy to just get this to save the signature as a file.

https://test.chenks.co.uk/index.asp
Logged

johnson

  • Reg Member
  • ***
  • Posts: 838

The blob starting 0xFFD8... is hex representaion of binary. I can get an image out of it in javascript by converting to base64 and adding the "data:image/png;base64,..." string to it, which is what signature_pad puts out. I guess you need to strip that part off and convert it to binary to get it into a format suitable for the database.

Maybe this helps from:
https://github.com/szimek/signature_pad#handling-data-uri-encoded-images-on-the-server-side
Code: [Select]
var dataUri = "data:image/png;base64,iVBORw0K...";
var encodedImage = dataUri.Split(',')[1];
var decodedImage = Convert.FromBase64String(encodedImage);
System.IO.File.WriteAllBytes("signature.png", decodedImage);
Logged

burakkucat

  • Respected
  • Senior Kitizen
  • *
  • Posts: 38300
  • Over the Rainbow Bridge
    • The ELRepo Project

I took a copy of the data from Reply #2 and put it into a file (named zxc).

Quote
[bcat ~]$ file zxc
zxc: ASCII text, with very long lines, with no line terminators
[bcat ~]$

After removing the opening "0x" of the ASCII text, I transformed that stream of hexadecimal characters back to the binary bits from which it had been created.

Quote
[bcat ~]$ fromhex zxc > foo
[bcat ~]$

Usage of the "file" utility states that "foo" contains a JPEG image.

Quote
[bcat ~]$ file foo
foo: JPEG image data, JFIF standard 1.01, resolution (DPI), density 96x96, segment length 16, Exif Standard: [TIFF image data, big-endian, direntries=3], baseline, precision 8, 754x180, components 3
[bcat ~]$

So, working in the "other direction", take the image file, convert it to a ASCII string of hexadecimal. Add a "0x" prefix to the hexadecimal ASCII string and that will be the data to insert into the record's field.
Logged
:cat:  100% Linux and, previously, Unix. Co-founder of the ELRepo Project.

Please consider making a donation to support the running of this site.

johnson

  • Reg Member
  • ***
  • Posts: 838

I mocked up some a page and some VB script to test.

Code: [Select]
<!DOCTYPE html>
<html>
<head> 
<script src="https://cdn.jsdelivr.net/npm/signature_pad@4.0.0/dist/signature_pad.umd.min.js"></script>
</head>
<body>

<form method="POST" action="/cgi-bin/publish/newconsole" onsubmit="addSig()">
  <label>First name:</label><br>
  <input type="text" id="fname" name="fname" value="John"><br>
  <label>Last name:</label><br>
  <input type="text" id="lname" name="lname" value="Doe"><br><br>
  <input type="hidden" id="sig" name="sig" value="">
  <label>Signature:</label><br>
  <canvas style="border: 1px solid black;"></canvas><br>
  <input type="submit" value="Submit">
  <button type="button" id="clear">Clear</Button>
</form>

<script>

const canvas = document.querySelector("canvas");
const signaturePad = new SignaturePad(canvas, {backgroundColor: 'rgb(255, 255, 255)'});
document.getElementById("clear").addEventListener("click", function (event) {
  signaturePad.clear();
});
function addSig(){
  let data = signaturePad.toDataURL("image/jpeg");
  let base64part = data.split(",")[1]
  document.getElementById("sig").value = base64part;
}
</script>

</body>
</html>

There are probably other ways of doing it, but:
  • Add a canvas in the page with a border, the background needs to be set to white or you just get a black image with jpegs (no transparency).
  • Add a hidden field to the form for inserting the signature data
  • Bind to onsubmit a function that strips the "data:image/" part and adds the remaining base64 to the hidden field
  • Forms action is a POST to /cgi-bin.. will be something.asp for you
  • A clear button

Code: [Select]
Imports System

Module Program
    Sub Main(args As String())

        Dim s As String = Console.ReadLine()
        Dim words As String() = s.Split(New Char() {"="c})
        Dim requestData As String = words(3)
        'e.g Dim r = request.form("sig")

        Dim base64Sig As String = System.Net.WebUtility.UrlDecode(requestData)
        Dim binarySig = Convert.FromBase64String(base64Sig)
        System.IO.File.WriteAllBytes("test.jpeg", binarySig)

        Console.WriteLine("")
        Console.WriteLine("Done.")
    End Sub
End Module

This just reads the post data from stdin as its running as a cgi program, for you getting the base64 string from the post will be something like Dim requestData = request.form("sig").
  • Decodes the base64 string from the html escaped form (%20 etc). I used System.Net.WebUtility, reading here it could be different on other versions.
  • Base64 to binary
  • Write to file test.jpeg

Maybe this is no help as its not the same as your environment, but simple console applications is all dotnet core on linux seems to support for VB script. I wouldnt have known about needing to set the background white or converting from escaped html before FromBase64String without trying it out though.
Logged

chenks

  • Kitizen
  • ****
  • Posts: 1106

all good info.
i will have a play and see what i can get working

preference would be to just get it to insert the blob directly, but if that becomes too troublesome then simply saving the signature as a JPG or PNG i can then use an external process to convert and insert into the database.
Logged

johnson

  • Reg Member
  • ***
  • Posts: 838

The ADO data type for an 'image' column is apparently 'adLongVarBinary' so maybe something like this
Code: [Select]
    .Parameters.Append .CreateParameter( _
    "@sig", adLongVarBinary , adParamInput, , form_sig _
  )
added to existing form, with 'form_sig' as the decoded base64.
Logged

chenks

  • Kitizen
  • ****
  • Posts: 1106

i finally got the time to sit and work on this, and thought i had a working version.
this page does capture the signature and update the required field in the db, but it seems the format of it doesn't match when i compare it to other signatures captured (inserted via another tool)

this is the form i've created
https://pastebin.com/nTFKRrnB

what is has entered is
Quote
0x405369676E6174757265426C6F62

but comparing it to the signature updated by the other tool
Quote
0xFFD8FFE000104A46494600010101006000600000FFE1005A4578696600004D4D002A00000008000503010005000000010000004A03030001000000010000000051100001000000010100000051110004000000010000000051120004000000010000000000000000000186A00000B18FFFDB004300080606070605080707070909080A0C140D0C0B0B0C1912130F141D1A1F1E1D1A1C1C20242E2720222C231C1C2837292C30313434341F27393D38323C2E333432FFDB0043010909090C0B0C180D0D1832211C213232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232FFC000110800B402F203012200021101031101FFC4001F0000010501010101010100000000000000000102030405060708090A0BFFC400B5100002010303020403050504040000017D01020300041105122131410613516107227114328191A1082342B1C11552D1F02433627282090A161718191A25262728292A3435363738393A434445464748494A535455565758595A636465666768696A737475767778797A838485868788898A92939495969798999AA2A3A4A5A6A7A8A9AAB2B3B4B5B6B7B8B9BAC2C3C4C5C6C7C8C9CAD2D3D4D5D6D7D8D9DAE1E2E3E4E5E6E7E8E9EAF1F2F3F4F5F6F7F8F9FAFFC4001F0100030101010101010101010000000000000102030405060708090A0BFFC400B51100020102040403040705040400010277000102031104052131061241510761711322328108144291A1B1C109233352F0156272D10A162434E125F11718191A262728292A35363738393A434445464748494A535455565758595A636465666768696A737475767778797A82838485868788898A92939495969798999AA2A3A4A5A6A7A8A9AAB2B3B4B5B6B7B8B9BAC2C3C4C5C6C7C8C9CAD2D3D4D5D6D7D8D9DAE2E3E4E5E6E7E8E9EAF2F3F4F5F6F7F8F9FAFFDA000C03010002110311003F00F7FA28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A86EAEEDAC6D64BABBB88ADEDE31979667088A3D493C0A009A8AE40F8E86A72343E15D22EF5D6538374A7C8B3521B69FDFB8C363AFEEC3E688FC39E23D5D925F11F889E08C10DF60D0CB5B47904FDE98FEF5810474283DA803A4BFD4F4FD2ADFCFD46FADACE1CE3CCB899635CFD58815CE3FC4AF0D48F710E993DDEB37100CB43A559CB739E71C32AECFC4B62B12E2DFE12F8467952E934637825F9D66CDEDCABFD0EF9056D0F1C9B89BECFA3F857C437C3CBDD14A6C85AC2DC647CD394C0FC3E99A0007893C55A848834CF05CB04122645C6AF7D1DBEC3EF1C7E63FE1C1FA557C7C522787F070F6D97271FA8A9BEDFF0010B508237B6D0F43D21B790EB7F7CF72FB7D42C4AABFF8FD39BC33E27BE967FED2F1BDCC76F28C0874BB18ADB67D1DFCC7FD73EF40106DF8A3FF003DBC1FFF007EAE7FF8AAD7D017C5E2E653E2297436B7D9FBB1A7472AB6ECF72EC46319AA23E1FDA0B758CF883C50CEA3998EB53866FA80DB7F202AB37C3742729E30F1827D35763FCC1A00EDA8AE323F87F344729E37F177FC0AF637FF00D0A3358FAA6A96DA44CDA75AFC41D7EFB545DD8B1B3B5B5BD9F2BD415580953FEF102803D2E9090AA5988000C927B57976976FF166EAEA795752B6B7D3D908846B36F09B8E5786D96E36A9CF66638EE0F4AAB27857C5C36CFE28D222F19CA665711AEB261823DA3008B668D223D7B96FE7900ED6FBE22F8374E8CBCFE25D35B0705209C4CF9FF75327F4AAD27C44B19042DA6687E23D563986565B5D2A454FFBEA5D83F5AAF61E28D374377B37F05EB5A244ABBE5921D284900C0CFDEB72E0FD715A361F11BC1BA92E60F1269E8C1B6ECB89440F9FF764DA7F4A0083FB7FC637376D15AF8256DE039DB71A86AB127D3291090FE19A808F89E54B07F08236788CA5CB0C7FBD91FF00A0D7668EB222BA306461956539047A8A75007250DDFC41B781DAEF47F0EDE381F2ADAEA33424FF00DF70B0FD6A18FC4DE3412EDB8F87D26CCF2D6FABDBBFE8DB6BB3A28039887C75A4A5E2D96B11DD68578EC5638B54411ACB8C7DC94131BFDE0301C9F6AE9EA0BBB3B5D42D24B5BDB686E6DA41878668C3A30EBC83C1AE58F82AE74601FC23ACCFA5AAF234FB9CDCD9372C70118EE8F24F54603D8D007614561F86F5D7D620BAB6BD8A3B7D5B4F97ECF7D6E8C4856C655D738251D70CA48E871D41ADCA0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A2B9ED63C6BA3E91766C15E6D4354C6469DA746679FB7DE51C20C303972A3DE803A1ACAD67C4BA3787D233AA6A1140F2902287979652481848D72CE7247DD06B17ECDE31F11211777117866C5B830DA32DC5EB0F98106523CB8FF84FCA1CFF00B42B5743F0A68DE1E7926B1B4CDE4DFEBEF67732DC4D9C67748D9639201C6719ED40190BAA78BBC443FE255A647A058B0C0BCD593CCB82083CA5BA9C29071F7D87FBBDA9E9E07D1A3FF898F892EA6D6EE200D2B5C6AD286861E06E2B171146BF2E721723D6A4BAF155C6A579269BE13B68B50B989CC7717F2922CAD580C90CE3991F91F227AFCC56996FE02B5BA952EBC4F7D71E22BA521956F005B68CE08CA5BAFC8383D5831E339A000F8EA3D4A4783C2BA65CEBD2236D6B988886CD48600833B70D807388C39A8C785B5BD7509F15EBAE6071F3699A416B7831820ABC99F3640411C6547B575E88B1A2A2285451855518007A0A750051D2F46D3343B416BA5585B59C000F9208C203EE71D4FB9E6AF51450014553D4F55B0D174F96FF0053BC86D2D6219696560A07B7B93D80E4D738755F137893FE4036A9A3E9AC180D4B5384B4D27DE01A2B7C82064290642BC1FB847500E9AFB50B2D32D1AEB50BCB7B4B64C069AE2511A0CF4C92715CB8F186A3AF0DBE11D124BA8597E5D4F51DD6B6832A482A08F3251918F9540FF6875AB7A7F81B4AB7BF5D4F517B8D6B5453B92F352712988E41FDDA602478238DAA08F5AE9A8038F6F03CBAC6F6F15EB97BAA2C9906CADD9AD2CC024103CB43B9F1EAECD5D2E9FA5E9FA45AFD974DB1B6B2B7DDBBCAB689635C9EA70A00CD5BA2800A28A2800AA97FA5E9FAAC020D46C6D6F2207223B885645CFD181AB74500724FF0EB4486579B4596FF00419A49048EDA55D3428E474062398C8E7FB94C5B6F1EE918F2EFB4AF10C0A1D996EA33657078F9543A068CFE28BF5F4EC28A00E3BFE160C3A72B7FC24BA1EADA1EC40D24F2DBFDA2D8127181343B87FDF5B6BA4D3758D335980CFA5EA3697D0A9C33DB4CB2007D0952706AED73DAAF86879EDAAE802DB4FD6D4973208F6C7779EB1CE179607B372CA791DD5803A1A2B2340F1041AEC1329864B4D42D1C477B63311E65BBE33838E1948E55870C3915AF401C8F88F3A778C7C37A8D89637D7D7074EB883CC0166B6D924A5883DE32BB811FDE65FE2E3AEAE3A331F883E2625D42B14D63E1FB596033A96F96F262BB901E84A46BCFA1931D738EC6800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28AE5F50F16BCF7B71A4F866D06ADAA424A4CFBB65ADA3640FDF4BEA339D89B9B83903AD007515C95CF8F6CEE2E24B3F0D59DC788AF538616240B78CE3204970DFBB5FA02C7DA9A9E0A9756904FE2ED5A6D5CEEDC2C23060B24E4301E5039930475919B23B57556D6D059DB476D6B0470411AED8E28902AA8F40070050072AFE1CF106BF216F11EB7F65B3DDFF0020CD199A2561938124E7123E54E085118F6AE8348D174CD06C56CB49B0B7B3B7183B2140BB8E00CB1EAC700649C9357EAAEA5A959E91A6DC6A3A85C25BDA5BA192595FA281FA93E80724F028020D6B5CB0D02C3ED77F232AB388A28E342F24D237DD48D072CC7D07A13D0135CF9D2B5AF1802DAE99749D15C305D2A09713DC29E07DA2453F28233FBB43FC5CB1E956BC3FA75C6A17EDE28D5E3992F2642963673A85FB05B93C0DB93895F019CF51C2F45E7A7A0086D6D2DAC6D63B5B4B78ADEDE21B638A1408883D001C01535145001451450015CE6B5AF5FAEA8BA1F87ECE2BAD55A1F3E596E5996DECE3390AD21032C59948545E4E1892A066B535BD62D740D1AEB54BCDE61B74DC5635CBB9270A8A3BB312001EA4566F84745B8D334E9AF353DADAD6A727DAAFD87F0B9000894E4FC91AE1073D89EE68023D37C1F0457B1EA7ADDDC9ADEAF192D1DCDCA811DB93B7FD4C43E58FEE8E4658F7635D2D14500145145001451450014514500145145001451450014514500607883C3D25FDC43ABE933A596BD68A560B86525264CE4C3301F7A327F153F32E0F5C36F1BCBAEDA47A3E8A3EC9E269A692DAE61917CEFECDF2C812CAD8F9594646C2701CB2F1F780DCD7FC452585CC3A46956EB7DAEDD2EE86D8B61224CE0CD330FB9183F8B1F95413D307C13A75CE8DE36F16595ECC97371702CEFBED66148DE6DE8E8DC2F440F1B6D524E33D4924900EC348D2AD743D26DB4DB3561040BB417396724E5998F76624927B924D5DA28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A002B275DF1269BE1D8237BE958CD392B6D6B0A1927B861FC31A0E58F23D864648153EB3ABDB685A3DCEA777E618605CEC89773BB1202A28EECCC4281DC91597E17D0EE2DFCDD6F5A457F105F8CCED90C2DA3CE56DE323A22F19C7DE6CB1CE6802949A4EBBE2B671AEC8FA468E4B28D2ED261E7CEB91FEBE653C0201F9233FC5CB9E95D4D958DA69B671D9D8DAC36B6D10C470C2811179CF007039353D140051451400571F0B9F1878A27633E345D06F3CA1005C1B9BD4018B3E7F823DC368EEFF37455CF615C87856748FC69E36D3238822C57D6F7791DCCB6D183FAC64FE3401D7D1451400514514005145140195E26D122F12786B50D1E560A2EA1288FCFEEDFAA3F1DD582B7E1597E1EF18DB5E0B4D2B5963A7788C44A27B2BA4F28C920CAB3424FCB22165620A13C75C575354756D1F4DD76C1AC755B182F2D9B931CC8180382323D0F2704722802F515C847E14D7749995740F15CD158AE48B1D52DFEDAABE8AB2165902818182C714D8EEBE225924CF75A5F87754007EED2D2F25B673F83A3AFFE3C2803B1A2B8E6F1A6AF636A926ADE05D7A291988C58186F147BFC8FBBFF001DA9D7E21683E62C3226AF15C9009B77D1AEFCC5CFA8119A00EAA8AE4AE7C7F6901222D03C5173EF16897033FF007D28AAA3E23B3B613C13E316F73A605FFD09C50076F4572D0F8B751BA8CB41E09F11640E04DF658B3FF7D4F55A4F13F8C013E4FC3DBB61DB7EAB6AA7F463401D9515C41F1478E3B7C3993F1D66DE93FE127F1DFF00D13A03EBADC1FF00C4D00771457123C49E3C3FF34F621F5D722FFE22A9EAFE3AF15E83A6C9A86A7E0CB2B6B68FEF33EBD18C9C7403CBF998F60324F6A00F42AC1D475F91F546D0F4448AE754550D70EF930D8A1190D2E0E493FC318219BD5572C387BDD7BE24788EDEDFECDE0DBDD2B4D95499FC9D4614BB90104001A4C1879E4FCBBB8E0AF5ADED06F753D12C52C6D3E1BDED8DB2F256DEF6D1CB1C00598994166381962727B9A00E8F44D0ADB458E764792E2F6E9FCCBBBD9B065B87C6016238000E028C2A8E0015836E05DFC64BDB8B63B92C7458ED6F0EEE04924A648D71EA143927FDB5A76A3E3D9B49B59EEAF7C1DE248EDE04692590476CEA8AA32492B31E0015CF7823C5F35969F2CBAC786FC4F15EEA77525F5CDC0D3649A152F808176EE6DAB1AC6A38FE1A00F52A2B92B6F89FE0BBAB86B7FEDFB6B7957AADEABDB63FEFE85AE834FD634BD5959B4DD4ACEF557A9B69D6403FEF926802ED1451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051456478A75AFF8477C31A86AAB1F9B2C117EE22DA4F992B10B1A6073F33951F8D0062DB6DF17F8BE6BA93CB7D27C3F72D05BC6413E75E851BE439E31186D8BC1F98B9CF0B5D8D63F85B453E1EF0C5869724A669A18F33CBB8B7993312D23E4F3CBB31FC6B62800A28A2800A28A2800AE498C7A1FC4A79E64096FAFDA450473738FB4C0643B0F1805A37CAE4F3E530F4CF5B597E21D121F10E8B3E9F2BB432361EDEE133BEDE65398E55C1072AC01EBCE31D09A00D4A2B17C2FACDC6B3A496BFB716DAA5A4A6D6FE00A42A4CA013B73D51815753CFCAE39ADAA0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A2B335BF1168FE1CB5171AC6A56F671B676095F0D263A855EAC791C004F3401A74571EFE26F10EB2193C35E1C923889651A86B44DB45C630562C195C1078C84FAD0FE079B582EDE2AD7AF7558DCB7FA0C04DA5A0524100C68773E31FC6ED4016350F16BDC5E4DA4F862D5755D523CACB26FDB6B687207EFA4F5E73B172C70781D6A6D37C291C5A92EAFACDDB6ADABAB398A69536C56C1B1F2C116488C6001BB25CF7635B7656569A75A4769636B05ADB479090C118445C9C9C28E07249A9E800A28AC4F126BA747B5860B348E7D62F9FC8D3ED5B3FBC93BB363911A0F998F603D48040327C5463F136A10F83EDCF988648AE757214958AD95B708CB0230F2B28503AEDDE7D33D8D65787F451A1E9A607B97BCBC9A433DDDDC8A15AE266C6E6C0E14700051C2AAA8ED5AB400C9238E689A39515E361865619047B8AE7AF3E1FF83EFE364B8F0CE95F3F578ED5237FFBE9403FAD749450071DFF000AD746B7B516FA4DF6B9A4283BBFD07559D47FDF2CCCBFA52BE91E38D33CC6D33C4B65AA21204706B167B195475FDEC3B727EA86BB0A2803907F16EBBA6993FB67C19A888D640893E932A5F230FEF6DF96403FE006B7F48D734DD7AD5EE34DB9132C6E63914A323C4E3AABA300C87D980E307A1AD0AC1D67C331DFDF45AAE9F72DA66B50A954BD89037989FF003CE64E0489EC7041E54A9E68037A8AE7746F12CB25EC5A36BD6834ED6D958AA025A0BB0BF79E07FE218C12870EB9E46393D150014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450014514500145145001451450015C87C478593C3D6BAB859248F45D420D4E58635C99238DBE7EE3EEAB338F7415D7D473C115D5BCB6F3C6B2C32A14911C6432918208F422801C8E92C6B246CAE8C032B29C820F420D3AB93F87F3CB0E85368375233DDE8570DA7B33A852F12E0C2F81D9A264E7D41AEB2800A28A2800A28A2800A28A28039CD5BC3B75FDACDAF787EEA2B3D59A2F2E78E642D6F7AA01D8B280410CA4F122F20120861F2D49A3F8A60D42F4E977F6F2697AD222B3D85CB292E08C96898712A704657918F9829E2B7EB3F58D134FD7AD16DB5083CC58E459627562924322F2AE8EB86461EA083401A14571E2F3C49E154686F2CEEFC49A6A21F26EECD53ED8983C2CB196559383F7D393B795E7349FF0B37C376EB08D55B50D1A59BEEC7A9E9F341FF8F15D9FF8F5007634567E9BAF68FAC961A5EAD637C506585ADCA4B81EFB49AD0A0028A6C92470C6D24AEA91A8CB331C003DCD60DC78EBC256A1CCDE27D1D4A0E57EDB196FC81C9A00E828AE19BE2F78319C4369A85C5F5D3E4436D696333BCCC3F853E4C13F8D73F378A3C67E29BC963B6F0B78874CD3A220C70A2C76D35D609E249E565F247DDC84566EBF35007ACD15C795F881AAEE064D13408248C63687BEB88DBF1F2E3FD1BF1A0F8023BFDC7C41E20D6F58124612581EEBECD6EDEFE5C21076EE4D006B6B3E2FF0EF87CBAEABAD58DACA8A18C2F30F3483D3118F98FE02B29BC7335F6F5F0FF85F5BD50F96248A69201676F2038E8F3153DFB29FEB5B5A4786342D000FEC9D1EC6C9B66C2F040AAEC3DDB193F89AD5A00E3CE97E31D7B3FDA9ABC1A159B641B5D207997054AF46B89061483FDC41F5EF5A7A3783B41D0AE1AEACEC11AF9C967BEB86335C392304995C96E7D338F6ADDA2800A28A2800A28AE7B57F13986F9F47D16D4EA7AD0D9BE1562B15A86C90F3C98210601217966E30A7A800D3D5B58B0D12C4DE6A170B0C5908A0F2D239E888A39663D94649ACAF0E69B7D25CCDE21D6E38D354BC8C2456EA01FB0DBE72B086EEC49DCE7A16C01C2AD3B48F0C182F9358D6AE8EA7AD02FB26652B15A86C029047921060005B966E72C7A0E86800A28A2800A28A2800A2B3751F11689A44823D4F59D3ECA423216E6E9233F9311584BF137C2D7124B0E9B7575AA4F1024C5A758CD704FD0AA15FD71401D7D15C6FFC265AEDF5BAC9A3F813589096DA7FB4A586C801EB82CCDFF8ED3CC7F10AFA6915A7F0EE916CEBF218D26BC990FE26353F91A00DED6F44B2F1069A6CAF55C00C248A689B64B048BF7648DBAAB03D0FE07209159BE06D5EF35CF0BC37B7924739F3658A2BB44D82EE3472AB36CFE0DC0671D3B8C03819EFE07D4B51B748F5CF1A6B976413BD2CCC5651BA9FE12235DC47D5ABADB4B482C2CA0B3B58962B7B78D628A35E888A3000FA01401351451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451401CA788ACE7D17521E2DD2EDA49A48E3F2F54B585B06EAD8670C17A34B1F257A12BB973CAE3A6B5B982F6D21BBB69565B79E35922910E43AB0C823D88352D714B2C5E00D4E48E65483C2B7D2EF8A6DC4269D70C7E646078589CFCC0F0158B0380CB401DAD14D8E449A249627578DD432BA9C8607A107B8A750014514500145145001451450014514500606A5E07F0AEAFE69BEF0F69B2C92FDF97ECCAB21F7DE00607F1AA51FC3AD0A18D6DE197588AC8215FB1C7AC5D2C473FECF99FD71ED5D651401C959FC2FF04D94A644F0ED9CCEDD4DDEEB8FFD185AB621D034ED2ADA73A1E99A6585D18D844F1DA2AA86C71B8260919C64022B568A00E0342F0778A74A69EEDF5AD0DB55B97DD737EFA5492CF374F94B99D70830004501463802AF5CC7F126390FD96EBC273A7632DB5CC44FE4ED5D8D1401C9DBDD7C4082266BBD23C3974C070B6DA8CD113FF7D42C3F5A80F883C760F1E04B56FA6B89FF00C6EBB3A2803893E23F1E0FF9A7F01FA6B91FFF001149FF0009378F3FE89E467E9AE43FFC4D76F4500711FF00093F8EC7FCD3A07E9ADC1FE147FC251E39EFF0E5FF000D6ADEBB7ACDD67C41A47876D3ED5ABEA36F6711CEDF35F05C8ECABD58FB004D007363C51E36EFF0E66FC358B6FF001A65CF8CBC55656B25D5E780E4B7B78977492C9ACDAAA20F524B00055B1E20F11EB736CF0FE85F63B40D83A8EB4AD10601B0765B8C48D91C8DC63A7D9F81E07BA86FFC45A8DD6BF7D1307437785B789C02331C0BF203CF5218E46739A00E4AF3C55E3FF166956F2683E11BBB0D32E9497B9FB7431DCC8878FDDEFF00F5791FC6558E082B8E0D6A68F79E2BD16C96CB4CF8676D696E0EE23FB723CB31EACC7612CC7BB1249EE6BD128A00E560D5BC6D311BFC27A641FF005D35B27FF4180D13DC78FDB3F67D33C331FA799A84EFFCA115D551401C7DAC5F12259317977E15B68CF786D6E2623F391298FE1CF1C4B36E7F1FA4499FB96FA2C43F5766AECE8A00E46E7C137D7CABF6BF1BF898B81826DA582DC1FC1221FCE987E19E85736A20D5AE759D6143647F686AB3B81FF010C17F4AEC68A00C2B0F05F85F4C68DACBC3BA5C1247F7245B44DE3FE058CE7DF35BB45140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140051451400514514005145140053648D258DA39115E3705595864303D4114EA2803917F06CFA34925CF83AFC696CC4B369D32992C656C37FCB3C8311248E632071F74D4B078DA0B5BD4D3FC4B66FA15EBB1589E770F6B707271E5CF80A4E003B58237238AEA6A1BBB4B6BFB592D6F2DE2B8B7946248A640E8E3D083C1A009A8AE423F0BEA7E1C21BC27A80FB18233A3EA2ECF0632B91149CBC2701B8F9D727EE8A69F881169AADFF093687AB689B1033CF241F68B6049C00258770FFBE82D007634552D3757D335980CFA5EA3697B129C33DB4CB2007D0952706AED00145145001451450014514500145145001451515CDD5BD95B4973773C504118CBCB2B85551EA49E05004B45724FF117449A4787468EFB5E9A3916375D26D9A64527A1329C44071FDFA62DC78F757C79763A5787A060EACD7321BDB81C7CAC110AC63F176FA1EE01D85737AAF8EB42D2EE5AC92E5F51D4816034FD350DC5C657A82ABF7319EAC547BD523F0FADF51527C4BAD6ADAE17550F0CD71E45B647710C5B57FEFADD5D2E9DA4E9BA3C0D0699A7DA5942C7718EDA158D49F5C281401CE14F1A6BD20DED6FE19B0DDCAA15BABD7018F7E628F2B8E9E6107BD6868DE0DD1744BAFB7456EF75A99501F51BE90CF72D81B7EFB64AF1D9703DAB7E8A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A0028A28A00E7753F02F86B55BC17B36951437C1CC82F2D19ADE7DE7F8BCC8CAB13F526A87FC23BE2BD2231FD87E2B37B1C71ED5B5D760136E6CE73E747B1C71EBBFF00C3B1A28039487C41E2B82568B50F054B284E0CFA76A10488FC7502568D87D08AAF37C4096DDF6CBE09F168C774B18E41FF008E486BB3A280394B7F881A7C91B4973A4788EC954649B8D16E71F9A230AAAFF16BC1113EC9B58785BD26B2B88FFF0042415DAD1401C7CBF153C0D140B29F1259B2B1C058F73BFF00DF2A09FD295FE23E9325AADC69BA76BFAA46C700D9E8F7047FDF4EAA3F5AEBE8A00E43FE130D6EEED3CED33C09ADC8D9C6DBD96DED7FF4290B7FE3B426A7E3EBDB4630F86747D366CF1F6DD55A5FD238BFF66AEBE8A00E3A3D2BC79A92A0D53C45A6E97186F9D347B32EF22FA7993160A7DC254D6DF0EBC3A92C571A8DBCFADDE468505C6B13B5DB6339E15CEC5EBFC2A2BABA2801A889146B1C68A88802AAA8C000740053A8A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2800A28A2803FFFD900

so i think i've maybe got the conversion format wrong?
Logged

johnson

  • Reg Member
  • ***
  • Posts: 838

Why not do the conversion from base64 to hexadecimal in javascript given its so annoying to do in ASP:

Code: [Select]
<!DOCTYPE html>
 
<html>
 
<head>
  <title>Signature Capture Form</title>
  <script src="https://unpkg.com/signature_pad"></script>
  <script>
    // Initialize the signature pad
    var signaturePad;
 
    window.onload = function() {
      var canvas = document.getElementById('signatureCanvas');
      signaturePad = new SignaturePad(canvas , {backgroundColor: 'rgb(255, 255, 255)'});
    };

    function base64ToHex(str) {
      const raw = atob(str);
      let result = '';
      for (let i = 0; i < raw.length; i++) {
        const hex = raw.charCodeAt(i).toString(16);
        result += (hex.length === 2 ? hex : '0' + hex);
      }
      return result.toUpperCase();
    }
 
    // Function to handle form submission
    function handleSubmit(event) {
      event.preventDefault(); // Prevent form submission
 
      // Get the signature as a data URL
      var signatureDataUrl = signaturePad.toDataURL("image/jpeg");
      let base64part = signatureDataUrl.split(",")[1];

      //Not sure if you need the "0x" prefix or not:
      //let binString = "0x" + base64ToHex(base64part);
      let binString = base64ToHex(base64part);
 
      // Set the signature data as a hidden form field
      document.getElementById('signatureData').value = binString;
 
      // Submit the form
      document.getElementById('signatureForm').submit();
    }
  </script>
  <style>
    #signatureCanvas {
      border: 1px solid #000;
    }
  </style>
</head>
 
<body>
 
  <h1>Signature Capture Form</h1>
  <form id="signatureForm" method="post" action="">
    <label for="signatureCanvas">Please sign below:</label><br>
    <canvas id="signatureCanvas" width="400" height="200"></canvas><br>
    <input type="hidden" id="signatureData" name="signatureData" value="">
    <button type="submit" onclick="handleSubmit(event)">Submit</button>
  </form>
 
</body>
 
</html>


and just skip the DataURIToBlob() function.

Notice I specified the format as "image/jpeg" and set the background white - this produces binary strings that begin with "0xFFD8FFE000" as your examples do, so I assume is what the original tool does.
Logged

chenks

  • Kitizen
  • ****
  • Posts: 1106

Why not do the conversion from base64 to hexadecimal in javascript given its so annoying to do in ASP:

 i still need the ASP part to add the contents to the SQL database though.
so when SUBMIT is clicked is still need it to do this (or a version of this)

Code: [Select]
<%
' Check if the form is submitted
If Request.ServerVariables("REQUEST_METHOD") = "POST" Then
    ' Retrieve the signature data from the request
    Dim signatureData
    signatureData = Request.Form("signatureData")

    ' Convert the data URL to a blob
    Dim signatureBlob
    signatureBlob = DataURIToBlob(signatureData)

    ' Connect to the SQL database
    Dim conn
    Set conn = Server.CreateObject("ADODB.Connection")
    conn.Open "Driver={SQL Server}; Server=ctech-gla-sql03; Database=SIC30_CTS_LIVE; UID=webuser; PWD=webuser; Option=4"

    ' Prepare an SQL INSERT statement to save the blob
    Dim sql
    sql = "UPDATE call_events SET ce_technicians_signature_image = '@SignatureBlob' WHERE ce_Id = '56729908'"

    ' Create a parameterized command and set the blob value
    Dim cmd
    Set cmd = Server.CreateObject("ADODB.Command")
    cmd.ActiveConnection = conn
    cmd.CommandText = sql

    ' Create a parameter and assign the blob value
    Dim param
    Set param = cmd.CreateParameter("@SignatureBlob", 205, 1, LenB(signatureBlob), signatureBlob)
    cmd.Parameters.Append param

    ' Execute the INSERT statement
    cmd.Execute

    ' Cleanup
    Set param = Nothing
    Set cmd = Nothing
    conn.Close
    Set conn = Nothing

    ' Display a success message
    Response.Write "Signature successfully saved."
End If
%>

Logged

johnson

  • Reg Member
  • ***
  • Posts: 838

Yeah just skip this line:
Code: [Select]

'signatureBlob = DataURIToBlob(signatureData)

and use signatureData instead of signatureBlob in the SQL statement:
Code: [Select]
Set param = cmd.CreateParameter("@SignatureBlob", 205, 1, LenB(signatureData), signatureData)

Since all the code in DataURIToBlob and Base64Decode was constructing a hexadecimal string, thats what you were putting in the database before, just now its in that format when the form is submitted.
Logged
Pages: [1] 2
 

anything