diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/QuickTour/hello.exe b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/QuickTour/hello.exe new file mode 100644 index 0000000..1f25673 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/QuickTour/hello.exe differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/QuickTour/quicktour.dapfj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/QuickTour/quicktour.dapfj new file mode 100644 index 0000000..34463c9 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/QuickTour/quicktour.dapfj @@ -0,0 +1,88 @@ +{ + "Notes": "Protects the hello.exe program as part of the Quick Tour", + "Models": ["Pro Plus"], + "ProductCode": "DEMO", + "NetUserType": "per product", + "ProductMaxNetUsers": 2, + + "Advanced": { + "DongleNumbers": "all", + "DongleNumberRangeMin": null, + "DongleNumberRangeMax": null, + "DataEncKeyProductCode": null, + "LockDongleToComputer": false, + "AllowUSBOverNetwork": true, + "AllowSoftwareKeys": true + }, + + "Licences": [ + { + "Name": "hello", + "Executions": 5, + "ExecutionWarning": null, + "ExpiryDate": "no limit", + "MaxDays": "no limit", + "ExpiryWarning": null, + "Features": 0, + "LicenceMaxNetUsers": null + } + ], + + "Files": [ + { + "InputName": "", + "OutputName": "", + "CallingProgram": null, + "Licence": "hello", + "Method": "Shell", + "ShellOptions": { + "DecrementExecution": true, + "StartNetworkUser": true, + "BackgroundCheck": 5, + "DataFileEncryption": false, + "DataFileTypes": null, + "DataFileExceptions": null, + "ExtraAntiDebug": true, + "ExtraAntiPiracy": 6 + } + } + ], + + "DataArea": { + "ZeroDataSize": null, + "DataFile": "" + }, + + "ShellMessages": { + "Success": "", + "DongleNotFound": "Error! A valid dongle for MyProduct has not been detected.", + "ExpiryError": "MyProduct has expired!", + "ExecsLimit": "MyProduct has used up all of its allowed executions.", + "ExpiryWarning": "Warning! MyProduct will expire in %1 days.", + "ExecsWarning": "Warning! You will only be able to run MyProduct %1 more times.", + "NetUserLimit": "The maximum number of permitted network users has been exceeded.", + "OtherError": "The error %1/%2 has occurred checking the dongle in MyProduct.", + "Background": "This program will terminate in 30 seconds.\r\nPlease save your work or attach a valid dongle.", + "NetNoServer": "Error! Cannot detect DinkeyServer on the network." + }, + + "Algorithms": [ + ], + + "ExtraSecurity": { + "DRISEncryptionKeys": null, + "DataEncryptionKeys": null, + "RWAlgorithm": null, + "SecureUpdatesOnly": false + }, + + "Actions": { + "ProgramDongle": true, + "LockSoftware": true + }, + + "DataFileEncryptionTool": { + "Files": [ + ] + } +} \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/QuickTour/quicktour.drpfj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/QuickTour/quicktour.drpfj new file mode 100644 index 0000000..82f54c5 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/QuickTour/quicktour.drpfj @@ -0,0 +1,47 @@ +{ + "Notes": "Used by the Quick Tour to add 5 executions to the dongle so that the protected hello.exe program can run 5 more times.", + + "DongleInfo": { + "ProductCode": "DEMO", + "DongleNumber": 123456789, + "UpdateNumber": 1 + }, + + "Licences": [ + { + "Name": "*.*", + "Action": "change", + "AddExecutions": 5, + "ExecutionWarning": null, + "ExpiryDate": null, + "SetMaxDays": null, + "ExpiryWarning": null, + "Features": null, + "LicenceMaxNetUsers": null + } + ], + + "DataArea": { + "DataAreaSize": null, + "DataChanges": [ + ] + }, + + "Algorithms": { + }, + + "OtherInfo": { + "NetUserType": null, + "ProductMaxNetUsers": null, + "LastUsedDate": null, + "DataEncKeyProductCode": null, + "SecureUpdatesOnly": null, + "LockDongleToComputer": null, + "ResetDongleLock": null + }, + + "UpdateCode": { + "OutputFileName": null, + "Type": "short" + } +} \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/4D/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/4D/README.txt new file mode 100644 index 0000000..a13599b --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/4D/README.txt @@ -0,0 +1,123 @@ +sample - sample code for DinkeyPro/FD in 4D +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This sample code is written using 4D v12 but will work with later versions of 4D. + +The sample code calls a 4D plugin which we provide. This plugin is compatible with +4D versions 11 and higher. It is called ddpro.bundle. This is a series of directories +and files. The most important are shown here: + +ddpro.bundle + Contents + Windows + ddpro.4dx + Windows64 + ddpro.4dx + MacOS + ddpro + Resources + +This same bundle is provided in the Windows and Mac OSX SDKs and will support Mac OS X and +Windows 32-bit and 64-bit Operating Systems. + +For Mac OS X this directory structure is recognised as a single file: ddpro.bundle. You can +explore the contents of the bundle by choosing "Show Package Contents". + +For the sample database to work properly you need to have a Plugins folder (located in the same +place as the sample database) and include the protected ddpro.bundle in the Plugins folder. + +For Mac machines you just place ddpro.bundle in this folder. For Windows you need to copy +the whole structure to the Plugins folder. + +Note - the actual Plugin file you need to protect is the file in Contents\. +For Windows it is called ddpro.4dx. For Mac OSX it is called ddpro. You need to protect +this file (and not your database) with DinkeyAdd with the API Method. You should protect +the relevant file for each Operating System you want to support. So, for example, if you +want to support MacOSX and 32-bit, 64-bit Windows you should protect these files: +ddpro.bundle\Contents\Windows\ddpro.4dx +ddpro.bundle\Contents\Windows64\ddpro.4dx +ddpro.bundle\Contents\MacOS\ddpro + +If you don't want to support a particular operating system you can delete that folder. + +Because your database is dependent on the protected plugin then it is itself protected. + +You can then supply the whole protected bundle to your customers. + +The sample code contains many Project Methods. However, there are 10 main functions +that you can use in your code. You will not need to use all these functions in your +code. Just use which ever functions are most appropriate and customise in your own way. +The sample code is just a guide. You should implement the protection in a stronger way +using the techniques described in the "Increasing your Protection" chapter of the manual. + +For example you can call one (or more) of these functions when your database opens. +(Database Methods | On Startup). This has been implemented in the sample code but has +been commented out otherwise you would need a correctly programmed dongle to open it! +For this reason it is probably best to keep an unprotected copy of your database before +you start adding protection. + +The 10 main functions are: + +// this file contains 10 protection-check functions. +ProtCheck a standard protection check +ProtCheckWithAlg a protection check & executing an Algorithm +WriteBytes a protection check & write data to the dongle +ReadBytes a protection check & read data from the dongle +EncryptUserData a protection check & encrypting data and then decrypting the data +// these functions are the same as the functions listed above but encrypting all parameters passed to our API +ProtCheckEnc a standard protection check +ProtCheckWithAlgEnc a protection check & executing an Algorithm +WriteBytesEnc a protection check & write data to the dongle +ReadBytesEnc a protection check & read data from the dongle +EncryptUserDataEnc a protection check & encrypting data and then decrypting the data + +If you are using Dinkey Lite then you can only use 4 functions: +ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + +These functions also depend on some other simpler functions (check to see which functions +are references and also include those in your code). For example, you will always need +to include: + +InitialiseDris +SetDrisFunction +SetDrisFlags +DisplayError +GetDrisSDSN +GetDrisExtErr + +The sample code has been implemented so that you build up the DRIS as a BLOB variable. +We have provided SetDris... functions to set various values in the DRIS and GetDris... +functions to get values fro the Dris. So you will also need to include all the GetDris... +and SetDris... functions that you need. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the SDSN value from 10101 to the value of your SDSN in the 10 main functions. +* Change the Product Code value from DEMO if you are using ProtCheck or ProtCheckEnc functions. +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages (DisplayError) with your own. + +Note: + +When you first use the plug-in you will get error 413. This is because you have not +protected it. To do this run DinkeyAdd and protect the plug-in file specifying the API Method. +Note - you should protect our 4D plugin and not your program. Because your program depends +on the 4D plugin it is also protected. See notes at the beginning of this file for more details. + +Note: + +We needed to insert an extra line of code into the sample just before the protection check: + +// this line is only required because of a bug in 4D (see readme.txt for more info) +SET BLOB SIZE($dris;DRIS SIZE;0) + +This is due to a bug in 4D which causes 4D to crash if the database is running in compiled +mode (or as a 4DC file). This bug existed in 4D v12.6. It may have been fixed in later versions +in which case you can remove this line. However, there is no harm in continuing to include +this line in your code. + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/4D/sample.4db b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/4D/sample.4db new file mode 100644 index 0000000..97386cb Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/4D/sample.4db differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/4D/sample.4dd b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/4D/sample.4dd new file mode 100644 index 0000000..8b28239 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/4D/sample.4dd differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Access/DPSample.bas b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Access/DPSample.bas new file mode 100644 index 0000000..39e887f --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Access/DPSample.bas @@ -0,0 +1,905 @@ +Attribute VB_Name = "DPSample" +Option Compare Database + +' The sample code contains 12 functions. You will not need to use all these +' functions in your code. Just use which ever functions are most appropriate +' and customise in your own way. The sample code is just a guide. You should +' implement the protection in a stronger way using the techniques described in +' the "Increasing your Protection" chapter of the manual. +' +' The 12 functions are: +' ProtCheck a standard protection check +' ProtCheckWithAlg a protection check & executing an Algorithm +' WriteString a protection check & write data to the dongle +' ReadString a protection check & read data from the dongle +' WriteBytes a protection check & write data to the dongle +' ReadBytes a protection check & read data from the dongle +' EncryptUserData a protection check,& encrypting data and then decrypting the data +' +' these functions are the same as some of the functions listed above but encrypting all parameters passed to our API +' ProtCheckEnc a standard protection check +' ProtCheckWithAlgEnc a protection check & executing an Algorithm +' WriteBytesEnc a protection check & write data to the dongle +' ReadBytesEnc a protection check & read data from the dongle +' EncryptUserDataEnc a protection check & encrypting data and then decrypting the data + +' If you are using Dinkey Lite then you can only use 4 functions: +' ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + +' !!!! +Public Const MY_SDSN = 10101 ' !!!! change this value to be the value of your SDSN (demo = 10101) +Public Const MY_PRODCODE = "DEMO" ' !!!! change this value to match the Product Code in the dongle + +' Used in OnOpen property of Startup form. +Function OpenStartup() As Boolean +On Error GoTo open_failure + +' call the function(s) of your choice here +' here I have chosen a standard protection check +If ProtCheck() <> 0 Then + Call CloseCurrentDatabase + Exit Function +End If + +Exit Function + +open_failure: + 'DLL failed to load + MsgBox "Cannot find Dinkey Pro Runtime Module (dpwin32.dll / dpwin64.dll). This should be in the Windows System directory", vbOKOnly, "Error" + Call CloseCurrentDatabase +End Function + +Function ProtCheck() As Long +Dim mydris As DRIS +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = PROTECTION_CHECK ' standard protection check +mydris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + +ret_code = DDProtCheck(mydris, 0) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ProtCheck = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ProtCheck = -1 + Exit Function +End If + +'NB to access product code you will need to use the TrimCString function +If (TrimCString(mydris.prodcode) <> MY_PRODCODE) Then + MsgBox "Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", vbOKOnly, "Error" + ProtCheck = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ProtCheck = -1 + Exit Function +End If + +' NB to access the dongle number you will need to use the ConvertToUnsigned function like this: +'ConvertToUnsigned(mydris.dongle_number) + +ProtCheck = 0 +End Function + +' !!!! You should replace this function with the one generated by the +' "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) +' or from DinkeyLook if you are using Dinkey Lite dongles. +' see readme.txt notes concerning using the algorithm in VB +Private Function MyAlgorithm(ByVal a As Long, ByVal b As Long, ByVal c As Long, ByVal d As Long, ByVal e As Long, ByVal f As Long, ByVal g As Long, ByVal h As Long) As Long + MyAlgorithm = a + b + c + d + e + f + g + h +End Function + +' NB for this to work you must program at least "user algorithm" into the dongle +' NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +' sample code generated by DinkeyAdd for the algorithm that you are using. +Function ProtCheckWithAlg() As Long +Dim mydris As DRIS +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = EXECUTE_ALGORITHM ' standard protection check & execute an algorithm +mydris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... +mydris.alg_number = 1 ' execute first algorithm (you do not need to specify this field for Dinkey Lite dongles) +' you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random +mydris.var_a = 1 ' sample values +mydris.var_b = 2 +mydris.var_c = 3 +mydris.var_d = 4 +mydris.var_e = 5 +mydris.var_f = 6 +mydris.var_g = 7 +mydris.var_h = 8 + +ret_code = DDProtCheck(mydris, 0) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ProtCheckWithAlg = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ProtCheckWithAlg = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ProtCheckWithAlg = -1 + Exit Function +End If + +' if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code +' !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd +If MyAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) <> mydris.alg_answer Then + MsgBox "Dinkey Dongle protection error / You have not patched your algorithm in the MyAlgorithm routine", vbOKOnly, "Error" + ProtCheckWithAlg = -1 + Exit Function +End If + +ProtCheckWithAlg = 0 +End Function + + +' This writes the String "Hello, World" to the dongle data area at offset 7 +' In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +' If you want to write data that isn't a string use the WriteBytes function +Function WriteString() As Long +Dim mydris As DRIS +Dim StringToWrite As String * 13 +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = WRITE_DATA_AREA ' standard protection check and write data provided +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 13 + +StringToWrite = "Hello, World!" + +ret_code = DDProtCheckString(mydris, StringToWrite) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + WriteString = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + WriteString = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + WriteString = -1 + Exit Function +End If + +WriteString = 0 +End Function + + +' This writes the data 0,1,2,...19 to the dongle data area at offset 7 +' In order for this function to work you will need to have a data area in your dongle that is at least 28 bytes long. +' If you want to write strings it is easier to use the WriteString function +Function WriteData() As Long +Dim mydris As DRIS +Dim DataToWrite As FixedByteArray +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = WRITE_DATA_AREA ' standard protection check and write data provided +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 20 + +For i = 0 To 19 + DataToWrite.Data(i) = i +Next + +ret_code = DDProtCheckData(mydris, DataToWrite) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + WriteData = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + WriteData = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + WriteData = -1 + Exit Function +End If + +WriteData = 0 +End Function + + +' This reads 13 bytes of data from offset 7 in the dongle data area +' In order for this function to work you will need to have a data area in your dongle that is at least 20 bytes long. +' In order for the data to be displayed properly by this routine it will need to be text data +Function ReadString() As Long +Dim mydris As DRIS +Dim StringToRead As String * 13 +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = READ_DATA_AREA ' standard protection check and read data +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 13 + +ret_code = DDProtCheckString(mydris, StringToRead) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ReadString = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ReadString = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ReadString = -1 + Exit Function +End If + +MsgBox "Dinkey Data Area at offset 7 contains: " + StringToRead, vbOKOnly + +ReadString = 0 +End Function + + +' This reads 20 bytes of data from offset 7 in the dongle data area +' In order for this function to work you will need to have a data area in your dongle that is at least 27 bytes long. +Function ReadData() As Long +Dim mydris As DRIS +Dim DataToRead As FixedByteArray +Dim ret_code As Long +Dim DisplayString As String + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = READ_DATA_AREA ' standard protection check and write data provided +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 20 + +ret_code = DDProtCheckData(mydris, DataToRead) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ReadData = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ReadData = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ReadData = -1 + Exit Function +End If + +DisplayString = "Dinkey Data Area at offset 7 contains: " +For i = 0 To 19 + DisplayString = DisplayString + Str(DataToRead.Data(i)) +Next + +MsgBox DisplayString, vbOKOnly +ReadData = 0 +End Function + +' This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +' It will then do another protection check & decrypt the data +' The data used in this example is 0,1,2...19. If you wanted to encrypt and/or decrypt Strings +' then you could use a technique similar to that employed in WriteString & ReadString +Function EncryptUserData() As Long +Dim mydris As DRIS +Dim MyData As FixedByteArray +Dim DisplayString As String +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = ENCRYPT_USER_DATA ' standard protection check & encrypt data +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.data_crypt_key_num = 1 +mydris.rw_length = 20 + +For i = 0 To 19 ' initialise data + MyData.Data(i) = i +Next + +ret_code = DDProtCheckData(mydris, MyData) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + EncryptUserData = ret_code + Exit Function +End If + +' ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn as per previous example functions + +' Now decrypt the same data to get the original values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = DECRYPT_USER_DATA ' standard protection check & decrypt data +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.data_crypt_key_num = 1 +mydris.rw_length = 20 + +ret_code = DDProtCheckData(mydris, MyData) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + EncryptUserData = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + EncryptUserData = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + EncryptUserData = -1 + Exit Function +End If + +DisplayString = "Decrypted Data is : " +For i = 0 To 19 + DisplayString = DisplayString + Str(MyData.Data(i)) +Next + +MsgBox DisplayString, vbOKOnly +EncryptUserData = 0 +End Function + +' !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! +' In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" +' in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm +' but the code can be modified easily to use the 3 encryption parameters. + +' !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm +Private Function MyRWAlgorithm(ByVal a As Long, ByVal b As Long, ByVal c As Long, ByVal d As Long, ByVal e As Long, ByVal f As Long, ByVal g As Long, ByVal h As Long) As Long + MyRWAlgorithm = a Xor b Xor c Xor d Xor e Xor f + MyRWAlgorithm = MyRWAlgorithm And &HFFFFFF ' we only use bottom 3 bytes and -ve numbers can cause problems with CryptApiData +End Function + +' !!!! please overwrite this function with the one generated by DinkeyAdd +Private Sub CryptDRIS(mydris As DRIS) + Dim i, j, k, t As Integer + Dim bigseed(256) As Byte + Dim S(256) As Byte + Dim temp As Byte + Dim temp_dris(Len(mydris)) As Byte + + Call CopyMemory(temp_dris(0), mydris, Len(mydris)) + For i = 0 To 255 Step 8 + Call CopyMemory(bigseed(i), mydris.seed1, 4) + Call CopyMemory(bigseed(i + 4), mydris.seed2, 4) + Next + For i = 0 To 255 + S(i) = i + Next + j = 0 + For i = 0 To 255 + j = (j + CInt(S(i)) + CInt(bigseed(i)) + 123) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + Next + i = 0 + j = 0 + For k = 16 To Len(mydris) - 1 + i = (i + 1) Mod 256 + j = (j + CInt(S(i)) + 212) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + t = (CInt(S(i)) + CInt(S(j)) + 97) Mod 256 + temp_dris(k) = temp_dris(k) Xor S(t) + Next + + Call CopyMemory(mydris, temp_dris(0), Len(mydris)) +End Sub + +' !!!! please overwrite this function with the one generated by DinkeyAdd +Private Sub CryptApiData(ByRef Data() As Byte, ByVal length As Long, ByVal seed1 As Long, ByVal seed2 As Long, ByVal AlgAnswer As Long) + Dim i, j, k, t As Integer + Dim bigseed(256) As Byte + Dim S(256) As Byte + Dim temp As Byte + + For i = 0 To 255 Step 8 + Call CopyMemory(bigseed(i), seed1, 4) + Call CopyMemory(bigseed(i + 4), seed2, 4) + Next + For i = 0 To 255 + S(i) = i + Next + j = 0 + For i = 0 To 255 + j = (j + CInt(S(i)) + CInt(bigseed(i)) + (AlgAnswer And &HFF)) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + Next + i = 0 + j = 0 + For k = 0 To length - 1 + i = (i + 1) Mod 256 + j = (j + CInt(S(i)) + ((AlgAnswer \ &H100) And &HFF)) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + t = (CInt(S(i)) + CInt(S(j)) + ((AlgAnswer \ &H10000) And &HFF)) Mod 256 + Data(k) = Data(k) Xor S(t) + Next +End Sub + +' We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +Function ProtCheckEnc() As Long +Dim mydris As DRIS +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = PROTECTION_CHECK ' standard protection check +mydris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheck(mydris, 0) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ProtCheckEnc = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ProtCheckEnc = -1 + Exit Function +End If + +'NB to access product code you will need to use the TrimCString function +If (TrimCString(mydris.prodcode) <> MY_PRODCODE) Then + MsgBox "Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", vbOKOnly, "Error" + ProtCheckEnc = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ProtCheckEnc = -1 + Exit Function +End If + +ProtCheckEnc = 0 +End Function + + +' NB for this to work you must program at least "user algorithm" into the dongle +' NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +' sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite copy source from DinkeyLook. +' We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +Function ProtCheckWithAlgEnc() As Long +Dim mydris As DRIS +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = EXECUTE_ALGORITHM ' standard protection check & execute an algorithm +mydris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... +mydris.alg_number = 1 ' execute first algorithm - you do not need to specify this field if you are only using Lite models +' you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random +mydris.var_a = 1 ' sample values +mydris.var_b = 2 +mydris.var_c = 3 +mydris.var_d = 4 +mydris.var_e = 5 +mydris.var_f = 6 +mydris.var_g = 7 +mydris.var_h = 8 + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheck(mydris, 0) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ProtCheckWithAlgEnc = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ProtCheckWithAlgEnc = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ProtCheckWithAlgEnc = -1 + Exit Function +End If + +' if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code +' !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd +If MyAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) <> mydris.alg_answer Then + MsgBox "Dinkey Dongle protection error / You have not patched your algorithm in the MyAlgorithm routine", vbOKOnly, "Error" + ProtCheckWithAlgEnc = -1 + Exit Function +End If + +ProtCheckWithAlgEnc = 0 +End Function + + +' This writes the data 0,1,2,...19 to the dongle data area at offset 7 +' In order for this function to work you will need to have a data area in your dongle that is at least 28 bytes long. +' We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +Function WriteDataEnc() As Long +Dim mydris As DRIS +Dim DataToWrite As FixedByteArray +Dim ret_code As Long +Dim alg_ans As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = WRITE_DATA_AREA ' standard protection check and write data provided +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 20 +' NB we restrict the algorithm variables to be 24-bit values to avoid any possible overruns in the algorithm +mydris.var_a = Rand(&HFFFFFF) ' random values +mydris.var_b = Rand(&HFFFFFF) +mydris.var_c = Rand(&HFFFFFF) +mydris.var_d = Rand(&HFFFFFF) +mydris.var_e = Rand(&HFFFFFF) +mydris.var_f = Rand(&HFFFFFF) +mydris.var_g = Rand(&HFFFFFF) +mydris.var_h = Rand(&HFFFFFF) + +For i = 0 To 19 ' initialise data to write + DataToWrite.Data(i) = i +Next + +' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm +alg_ans = MyRWAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) + +' encrypt data we want to write. +Call CryptApiData(DataToWrite.Data, 20, mydris.seed1, mydris.seed2, alg_ans) + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheckData(mydris, DataToWrite) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + WriteDataEnc = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + WriteDataEnc = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + WriteDataEnc = -1 + Exit Function +End If + +WriteDataEnc = 0 +End Function + + +' This reads 20 bytes of data from offset 7 in the dongle data area +' In order for this function to work you will need to have a data area in your dongle that is at least 27 bytes long. +' We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +Function ReadDataEnc() As Long +Dim mydris As DRIS +Dim DataToRead As FixedByteArray +Dim ret_code As Long +Dim DisplayString As String + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = READ_DATA_AREA ' standard protection check and write data provided +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 20 +' NB we restrict the algorithm variables to be 24-bit values to avoid any possible overruns in the algorithm +mydris.var_a = Rand(&HFFFFFF) ' random values +mydris.var_b = Rand(&HFFFFFF) +mydris.var_c = Rand(&HFFFFFF) +mydris.var_d = Rand(&HFFFFFF) +mydris.var_e = Rand(&HFFFFFF) +mydris.var_f = Rand(&HFFFFFF) +mydris.var_g = Rand(&HFFFFFF) +mydris.var_h = Rand(&HFFFFFF) + +' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm +alg_ans = MyRWAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheckData(mydris, DataToRead) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ReadDataEnc = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ReadDataEnc = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ReadDataEnc = -1 + Exit Function +End If + +' encrypt data we want to write. +Call CryptApiData(DataToRead.Data, 20, mydris.seed1, mydris.seed2, alg_ans) + +DisplayString = "Dinkey Data Area at offset 7 contains: " +For i = 0 To 19 + DisplayString = DisplayString + Str(DataToRead.Data(i)) +Next + +MsgBox DisplayString, vbOKOnly +ReadDataEnc = 0 +End Function + +' This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +' It will then do another protection & decrypt the data +' We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +Function EncryptUserDataEnc() As Long +Dim mydris As DRIS +Dim MyData As FixedByteArray +Dim DisplayString As String +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = ENCRYPT_USER_DATA ' standard protection check & encrypt data +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.data_crypt_key_num = 1 +mydris.rw_length = 20 +' NB we restrict the algorithm variables to be 24-bit values to avoid any possible overruns in the algorithm +mydris.var_a = Rand(&HFFFFFF) ' random values +mydris.var_b = Rand(&HFFFFFF) +mydris.var_c = Rand(&HFFFFFF) +mydris.var_d = Rand(&HFFFFFF) +mydris.var_e = Rand(&HFFFFFF) +mydris.var_f = Rand(&HFFFFFF) +mydris.var_g = Rand(&HFFFFFF) +mydris.var_h = Rand(&HFFFFFF) + +For i = 0 To 19 ' initialise data + MyData.Data(i) = i +Next + +' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm +alg_ans = MyRWAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) + +' encrypt data we want to pass. +Call CryptApiData(MyData.Data, 20, mydris.seed1, mydris.seed2, alg_ans) + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheckData(mydris, MyData) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + EncryptUserDataEnc = ret_code + Exit Function +End If + +' ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn as per previous example functions + +' Now decrypt the same data to get the original values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = DECRYPT_USER_DATA ' standard protection check & decrypt data +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.data_crypt_key_num = 1 +mydris.rw_length = 20 +' NB we restrict the algorithm variables to be 24-bit values to avoid any possible overruns in the algorithm +mydris.var_a = Rand(&HFFFFFF) ' random values +mydris.var_b = Rand(&HFFFFFF) +mydris.var_c = Rand(&HFFFFFF) +mydris.var_d = Rand(&HFFFFFF) +mydris.var_e = Rand(&HFFFFFF) +mydris.var_f = Rand(&HFFFFFF) +mydris.var_g = Rand(&HFFFFFF) +mydris.var_h = Rand(&HFFFFFF) + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheckData(mydris, MyData) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + EncryptUserDataEnc = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + EncryptUserDataEnc = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + EncryptUserDataEnc = -1 + Exit Function +End If + +' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm +alg_ans = MyRWAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) + +' decrypt data passed to us from the API. +Call CryptApiData(MyData.Data, 20, mydris.seed1, mydris.seed2, alg_ans) + +DisplayString = "Decrypted Data is : " +For i = 0 To 19 + DisplayString = DisplayString + Str(MyData.Data(i)) +Next + +MsgBox DisplayString, vbOKOnly +EncryptUserDataEnc = 0 +End Function + +' look at the error code and try to display an appropriate message +' !!!! you will want to replace these error messages with your own messages. +Public Sub DisplayError(ret_code As Long, extended_error As Long) + Select Case ret_code + Case 401 + MsgBox "Error! No dongles detected!", vbOKOnly, "Error" + Case 403 + MsgBox "Error! A dongle was detected but it was a different type to the one specified in DinkeyAdd.", vbOKOnly, "Error" + Case 404 + MsgBox "Error! A dongle was detected but it was a different model to those specified in DinkeyAdd.", vbOKOnly, "Error" + Case 409 + MsgBox "Error! The dongle detected has not been programmed by DinkeyAdd.", vbOKOnly, "Error" + Case 410 + MsgBox "Error! A dongle was detected but it has a different Product Code to the one specified in DinkeyAdd.", vbOKOnly, "Error" + Case 411 + MsgBox "Error! The dongle detected does not contain the licence associated with this program.", vbOKOnly, "Error" + Case 413 + MsgBox "Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual.", vbOKOnly, "Error" + Case 417 + MsgBox "Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.", vbOKOnly, "Error" + Case 423 + MsgBox "Error! The number of network users has been exceeded.", vbOKOnly, "Error" + Case 435 + MsgBox "Error! DinkeyServer has not been detected on the network.", vbOKOnly, "Error" + Case 922 + MsgBox "Error! The Software Key has expired.", vbOKOnly, "Error" + Case Else + MsgBox "An error occurred checking the dongle. Error: " + Str(ret_code) + ". Extended Error: " + str$(extended_error) + ".", vbOKOnly, "Error" + End Select +End Sub diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Access/DinkeyPro.bas b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Access/DinkeyPro.bas new file mode 100644 index 0000000..523408f --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Access/DinkeyPro.bas @@ -0,0 +1,163 @@ +' A VBA Interface to the Dinkey Pro/FD API + + +Attribute VB_Name = "DinkeyPro" +' API functions +' DDProtCheck - so we can ignore the second argument +' DDProtCheckString - so we can pass data as a String +' DDProtCheckData - so we can pass data in any format + +#If VBA7 Then + ' For Office 2010 and newer + #If Win64 Then + Declare PtrSafe Function DDProtCheck Lib "dpwin64.dll" (mydris As DRIS, Data As String) As Long + Declare PtrSafe Function DDProtCheckString Lib "dpwin64.dll" Alias "DDProtCheck" (mydris As DRIS, ByVal String1 As Any) As Long + Declare PtrSafe Function DDProtCheckData Lib "dpwin64.dll" Alias "DDProtCheck" (mydris As DRIS, Data As FixedByteArray) As Long + #Else + Declare PtrSafe Function DDProtCheck Lib "dpwin32.dll" (mydris As DRIS, Data As String) As Long + Declare PtrSafe Function DDProtCheckString Lib "dpwin32.dll" Alias "DDProtCheck" (mydris As DRIS, ByVal String1 As Any) As Long + Declare PtrSafe Function DDProtCheckData Lib "dpwin32.dll" Alias "DDProtCheck" (mydris As DRIS, Data As FixedByteArray) As Long + #End If +#Else + ' For versions of Office before 2010 + Declare Function DDProtCheck Lib "dpwin32.dll" (myDris As DRIS, Data As String) As Long + Declare Function DDProtCheckString Lib "dpwin32.dll" Alias "DDProtCheck" (myDris As DRIS, ByVal String1 As Any) As Long + Declare Function DDProtCheckData Lib "dpwin32.dll" Alias "DDProtCheck" (myDris As DRIS, Data As FixedByteArray) As Long +#End If + +'Dinkey Runtime Information Structure (DRIS) +Type DRIS + ' the first 4 fields are never encrypted + header As String * 4 ' should be set to DRIS + ' inputs + size As Long ' size of this structure + seed1 As Long ' seed for data/dris encryption + seed2 As Long ' as above + function As Long ' specify only one function + flags As Long ' options for the function selected. To use more than one OR them together: OPTION1 Or OPTION2... + execs_decrement As Long ' amount by which to dec execs if we use flag: DEC_MANY_EXECS + data_crypt_key_num As Long ' number of the key (1-3) that the dongle uses to encrypt or decrypt user data + rw_offset As Long ' offset in the dongle data area to read or write data + rw_length As Long ' length of data are to read/write/encrypt/decrypt +#If VBA7 Then + not_used As LongPtr ' This field is a pointer used in other programming languages. 4 bytes in 32-bit Access, 8 bytes in 64-bit Access +#Else + not_used As Long +#End If + alt_licence_name As String * 256 ' protection check for different licence instead of this one, must be null-terminated ascii + var_a As Long ' variable values for user algorithms + var_b As Long + var_c As Long + var_d As Long + var_e As Long + var_f As Long + var_g As Long + var_h As Long + alg_number As Long ' the number of the user algorithm that you want to execute + + ' outputs + ret_code As Long ' the return code from the protection check + ext_err As Long ' extended error + type As Long ' type of dongle detected. 1 = Pro, 2 = FD + model As Long ' model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + sdsn As Long ' Software Developer's Serial Number + prodcode As String * 12 ' product code (null-terminated) + dongle_number As Long ' dongle number. This number should be converted to a Double before being displayed otherwise it my appear as a negative number. + update_number As Long + data_area_size As Long ' size of the data area in the dongle detected + max_alg_num As Long ' the maximum algorithm number in the dongle detected + execs As Long ' executions left: -1 indicates 'no limit' + exp_day As Long ' expiry day: -1 indicates 'no limit' + exp_month As Long ' expiry month: -1 indicates 'no limit' + exp_year As Long ' expiry year: -1 indicates 'no limit' + features As Long ' features value + net_users As Long ' maximum number of network users for the dongle detected: -1 indicates 'mo limit' + alg_answer As Long ' answer to the user algorithm executed with the given variable values + fd_capacity As Long ' capacity of the data area in FD dongle. Currently fixed at ~10MB but may change in the future. + fd_drive As String * 128 ' drive letter of FD dongle detected e.g. 'f:\' + swkey_type As Long ' 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + swkey_exp_day As Long ' software key expiry date (if software key detected) + swkey_exp_month As Long + swkey_exp_year As Long +End Type + +' We need a structure for an array of bytes because otherwise the VB runtime can move the data in-between function calls +Type FixedByteArray + Data(0 To 1023) As Byte +End Type + +' Functions +Public Const PROTECTION_CHECK = 1 ' checks for dongle, check program params... +Public Const EXECUTE_ALGORITHM = 2 ' protection check + calculate answer for specified algorithm with specified inputs +Public Const WRITE_DATA_AREA = 3 ' protection check + writes dongle data area +Public Const READ_DATA_AREA = 4 ' protection check + reads dongle data area +Public Const ENCRYPT_USER_DATA = 5 ' protection check + the dongle will encrypt user data +Public Const DECRYPT_USER_DATA = 6 ' protection check + the dongle will decrypt user data +Public Const FAST_PRESENCE_CHECK = 7 ' checks for the presence of the correct dongle only with minimal security, no flags allowed +Public Const STOP_NET_USER = 8 ' stops a network user (a protection check is NOT performed) + +' Flags +Public Const DEC_ONE_EXEC = 1 ' decrement execs by 1 +Public Const DEC_MANY_EXECS = 2 ' decrement execs by number specified in execs +Public Const START_NET_USER = 4 ' starts a network user +Public Const USE_FUNCTION_ARGUMENT = 16 ' use the extra argument in the function for pointers +Public Const CHECK_LOCAL_FIRST = 32 ' always look in local ports before looking in network ports +Public Const CHECK_NETWORK_FIRST = 64 ' always look on the network before looking in local ports +Public Const USE_ALT_LICENCE_NAME = 128 ' use name specified in alt_licence_name instead of the default one +Public Const DONT_SET_MAXDAYS_EXPIRY = 256 ' if the max days expiry date has not been calculated then do not do it this time +Public Const MATCH_DONGLE_NUMBER = 512 ' restrict the search to match the dongle number specified in the DRIS +Public Const DONT_RETURN_FD_DRIVE = 1024 ' if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + +' Useful functions +#If VBA7 Then + Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long) + Declare PtrSafe Function SetCurrentDirectory Lib "kernel32" Alias "SetCurrentDirectoryA" (ByVal lpPathName As String) As Long +#Else + Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long) + Declare Function SetCurrentDirectory Lib "kernel32" Alias "SetCurrentDirectoryA" (ByVal lpPathName As String) As Long +#End If + +' given the maximum possible value generate a random number between 0 and the maximum +Public Function Rand(ByVal High As Long) As Long + Rand = Int((High + 1) * Rnd) +End Function + +' initialise the DRIS with random values +Public Sub RandomSet(myDris As DRIS) + Dim tempDris(Len(myDris)) As Byte + + Call Randomize + Call CopyMemory(tempDris(0), myDris, Len(myDris)) + + For i = 0 To Len(myDris) - 1 + tempDris(i) = Rand(255) + Next + + Call CopyMemory(myDris, tempDris(0), Len(myDris)) +End Sub + +' This function will convert the C string returned in the DRIS to a VB string +' e.g. to access the product code use TrimCString(mydris.prodcode) +Function TrimCString(s As String) As String + Dim i As Integer + Dim length As Integer + + length = Len(s) + + For i = 1 To length + If Mid(s, i, 1) = Chr(0) Then + TrimCString = Left(s, i - 1) ' Take off null and rest of string + Exit For + End If + Next + +End Function + +' this function should be used if you want to display the dongle_number. It will always display as a positive value +Public Function ConvertToUnsigned(number As Long) As Double +If (number >= 0) Then + ConvertToUnsigned = number +Else + ConvertToUnsigned = number + 4294967296# +End If +End Function diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Access/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Access/README.txt new file mode 100644 index 0000000..f727e7e --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Access/README.txt @@ -0,0 +1,73 @@ +Notes for protecting Access Databases with Dinkey Pro/FD +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Before doing anything it is a good idea to make a back-up of your database. It is + possible to protect your database so well that you may have trouble accessing + it yourself! + +1. For Access 2007 and newer, view your form and then chose design view and view + the properties for your form (choose the event tab). + + For versions before Access 2007, open your form in Design View. Now click on + View > Properties and choose the "Event" tab. + +2. You should now see the list of events associated with your form. Set the + "On Open" entry to "=OpenStartup()". This will cause your database to launch + this function when it is first loaded. + +3. For Access 2007 and higher in the Database Tools tab launch the Visual Basic editor. + +4. In the editor, select File > Import File... and choose the file DinkeyPro.bas + to add this module to your project. + Repeat this step to add DPSample.bas to your project as well. + This VBA code will check for the Dinkey Pro/FD Dongle. If a dongle is found your + database will continue to load. If a dongle is not found then it will display + an error message and your database will not be loaded. + +5. You will need to supply a locked copy of dpwin32.dll with your database. To + support 64-bit versions of Access, you will also need to supply a locked dpwin64.dll. + These DLLs should be located in the same directory as your database. If the + relevant DLL is not found an error will occur. It is recommended that you rename + the DLLs with names individual to you. In this case you must also modify the + references to dpwin32.dll and dpwin64.dll in DinkeyPro.bas to use the new names. + + If you load your database at this point and dpwin32.dll is found it will + return error 413: program not protected. + +6. Lock the DLL(s) using the API method of protection using DinkeyAdd. You can + specify the output path to be the folder that contains your database so that + the locked DLLs are in the correct location. + +7. You now have to do one more thing. Currently the user could load your + database and then remove the call to check the protection and therefore have + an unprotected copy. You must stop them doing this by saving your database + as an ACCDE file (MDE file for Access prior to 2007). This compiles all the + VBA code and stops it from being editable by an end user. You must save a + copy of your original database otherwise you will not be able to make any + changes either! You will distribute the ACCDE (MDE) file to your customers. + + To save your database as an ACCDE file, choose the Database Tools tab and choose + "Make ACCDE". (for versions prior to 2007 choose "Save As" and change the type + to a MDE file). + +Note - the VBA code in this sample is the same as the Visual Basic sample code we + provide, except that we need to catch whether the DLL is missing or not (VB + will terminate the program if the DLL is not found but VBA will display an error + but continue to load the database). + +Note - You only need to copy the relevant sample code functions that you need. All + comments in your VBA code are visible in your spreadsheet file so be careful + what you say! You should remove all our comments. + +Note - Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the SDSN value from 10101 to the value of your SDSN in the 10 main functions. +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages (DisplayError) with your own. + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Ada/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Ada/README.txt new file mode 100644 index 0000000..6a491ba --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Ada/README.txt @@ -0,0 +1,51 @@ +ApiTest - Runtime sample code in Ada +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tested with GNAT gnatmake command-line utility 2011 but should work +with other Ada Compilers. + +The dris.ads file contains the DRIS structure definition and other useful constants +The apitest.adb file is the main sample code file. You can compile it like this: + +gnatmake apitest.adb + +The sample code contains 12 functions: + +DDProtCheck +DDProtCheckWithAlg +WriteBytes +ReadBytes +EncryptUserData + +(There are also encrypted versions of these functions where the parameters passed +to and from our API are encrypted for greater security). + +The best approach is to compile the sample code and see how it works and then to take +the appropriate code and apply it to your own project. You should include the dris.ads +file in your project and use/modify which ever functions from apitest.adb you feel are +appropriate. The dris.ads file should not be modified. + +You will not need to use all these functions in your code. Just use which ever +functions are most appropriate and customise in your own way. The sample code +is just a guide. You should implement the protection in a stronger way using +the techniques described in the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. + +Note - you should use DinkeyAdd to protect dpwin32.dll and not your program. +Because your program is linked to the DLL it is protected. + +Note - the protected dpwin32.dll should reside in the same folder as your compiled +code. + +Note - because of our strong anti-debug code you may not be able to debug your code +after calling our DLL. diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Ada/apitest.adb b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Ada/apitest.adb new file mode 100644 index 0000000..e1c28c8 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Ada/apitest.adb @@ -0,0 +1,830 @@ +with Interfaces; use Interfaces; +with Interfaces.C; use Interfaces.C; +with System; use System; +with DRIS; use DRIS; +with Ada.Text_IO; use Ada.Text_IO; +with Ada.Numerics.Discrete_Random; + +-- !! We strongly recommend that you read the "readme.txt" file in the sample code folder. +-- !! It contains important instructions on how to use the sample code + +procedure apitest is + + MY_SDSN : constant int32 := 10101; + -- !!!! change this value to be the value of your SDSN (demo = 10101) + + -- The sample code contains 10 functions. You will not need to use all these + -- functions in your code. Just use which ever functions are most appropriate + -- and customise in your own way. The sample code is just a guide. You should + -- implement the protection in a stronger way using the techniques described in + -- the "Increasing your Protection" chapter of the manual. + -- + -- If you are using Dinkey Lite then you can only use 4 functions: + -- ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + + -- this file contains 10 protection-check functions. + -- ProtCheck a standard protection check + -- ProtCheckWithAlg a protection check & executing an Algorithm + -- WriteBytes a protection check & write data to the dongle + -- ReadBytes a protection check & read data from the dongle + -- EncryptUserData a protection check & encrypting data and then decrypting the data + + -- these functions are the same as the functions listed above but encrypting all parameters passed to our API + -- ProtCheckEnc a standard protection check + -- ProtCheckWithAlgEnc a protection check & executing an Algorithm + -- WriteBytesEnc a protection check & write data to the dongle + -- ReadBytesEnc a protection check & read data from the dongle + -- EncryptUserDataEnc a protection check & encrypting data and then decrypting the data + + -- useful routines that are called by our functions - implemented at the end of this file + procedure random_set(dris : t_DRIS_access); + procedure DisplayError(ret_code : int32; extended_error : int32); + + -- ************************* our 10 functions ********************************** + + dris : t_DRIS_access := new t_DRIS; + + ---------------------------------- + -- ProtCheck + ---------------------------------- + function ProtCheck return int32 is + ret_code : int32; + begin + + -- set the DRIS to have random values + random_set(dris); + + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := PROTECTION_CHECK; -- standard protection check + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + ret_code := DDProtCheck(dris, System.Null_Address); + + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + -- later in your code you can check other values in the DRIS... + if (dris.sdsn /= MY_SDSN) then + Put_Line ("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + end if; + + -- later on in your program you can check the return code again + if (dris.ret_code /= 0) then + Put_Line ("Dinkey Dongle protection error"); + return -1; + end if; + + Put_Line ("ProtCheck worked"); + return 0; + end; + + ---------------------------------- + -- ProtCheckWithAlg + ---------------------------------- + -- !!!! You should replace this function with the one generated by the + -- "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) + -- or from DinkeyLook if you are using a Dinkey Lite dongle. + function MyAlgorithm(a,b,c,d,e,f,g,h : int32) return int32 is + begin + return (a + b + c + d + e + f + g + h); + end; + + -- NB for this to work you must program at least "user algorithm" into the dongle + -- NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + -- sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample + -- code from DinkeyLook + function ProtCheckWithAlg return int32 is + ret_code : int32; + begin + -- set the DRIS to have random values + random_set(dris); + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := EXECUTE_ALGORITHM; -- standard protection check & execute algorithm + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number := 1; -- execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + -- you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.var_a := 1; -- sample values + dris.var_b := 2; + dris.var_c := 3; + dris.var_d := 4; + dris.var_e := 5; + dris.var_f := 6; + dris.var_g := 7; + dris.var_h := 8; + + ret_code := DDProtCheck(dris, System.Null_Address); + + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + -- later in your code you can check other values in the DRIS... + + if (dris.sdsn /= MY_SDSN) then + Put_Line ("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + end if; + + -- ...later on in your program you can check the return code again + if (dris.ret_code /= 0) then + Put_Line ("Dinkey Dongle protection error"); + return -1; + end if; + + -- if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + -- !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) /= dris.alg_answer) then + Put_Line ("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine"); + return -1; + end if; + + Put_Line ("ProtCheckWithAlg worked"); + return 0; + end; + + ---------------------------------- + -- WriteBytes + ---------------------------------- + -- This writes the Data "Hello, World" to the dongle data area at offset 7 + -- In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. + function WriteBytes return int32 is + szDataToWrite : Interfaces.C.char_array := Interfaces.C.To_C ("Hello, World!", True); -- append null so we write that too! + ret_code : int32; + begin + + -- set the DRIS to have random values + random_set(dris); + + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := WRITE_DATA_AREA; -- standard protection check and write data + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset := 7; + dris.rw_length := szDataToWrite'Length; + dris.rw_data_ptr := szDataToWrite'Address; + + ret_code := DDProtCheck(dris, System.Null_Address); + + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + -- ...later in your code you can check other values in the DRIS... + if (dris.sdsn /= MY_SDSN) then + Put_Line ("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + end if; + + -- later on in your program you can check the return code again + if (dris.ret_code /= 0) then + Put_Line ("Dinkey Dongle protection error"); + return -1; + end if; + + Put_Line ("WriteBytes worked"); + return 0; + end; + + ---------------------------------- + -- ReadBytes + ---------------------------------- + -- This reads 14 bytes of data from offset 7 in the dongle data area + -- In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. + -- In order for the data to be displayed properly by this routine it will need to be text data + function ReadBytes return int32 is + szDataRead : Interfaces.C.char_array (1..14); + ret_code : int32; + begin + -- set the DRIS to have random values + random_set(dris); + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := READ_DATA_AREA; -- standard protection check & read data + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset := 7; + dris.rw_length := szDataRead'Length; -- it also should read the null + dris.rw_data_ptr := szDataRead'Address; + + ret_code := DDProtCheck(dris, System.Null_Address); + + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + -- ...later in your code you can check other values in the DRIS... + + if (dris.sdsn /= MY_SDSN) then + Put_Line ("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + end if; + + -- later on in your program you can check the return code again + if (dris.ret_code /= 0) then + Put_Line ("Dinkey Dongle protection error"); + return -1; + end if; + + Put_Line("ReadBytes worked! Dinkey Dongle Data area, offset 7 is: " & Interfaces.C.To_Ada(szDataRead)); + return 0; + end; + + ---------------------------------- + -- EncryptUserData + ---------------------------------- + -- This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 + -- It will then do another protection check & decrypt the data + function EncryptUserData return int32 is + szData : Interfaces.C.char_array := Interfaces.C.To_C ("Hello, World!"); + ret_code : int32; + begin + -- set the DRIS to have random values + random_set(dris); + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := ENCRYPT_USER_DATA; -- standard protection check & encrypt user data + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num := 1; + dris.rw_length := szData'Length; + dris.rw_data_ptr := szData'Address; + + ret_code := DDProtCheck(dris, System.Null_Address); + + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + -- ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + -- Now decrypt the same data to get the original values + random_set(dris); + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := DECRYPT_USER_DATA; -- standard protection check & decrypt user data + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num := 1; + dris.rw_length := szData'Length; + dris.rw_data_ptr := szData'Address; + + ret_code := DDProtCheck(dris, System.Null_Address); + + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + -- ...later in your code you can check other values in the DRIS... + + if (dris.sdsn /= MY_SDSN) then + Put_Line ("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + end if; + + -- later on in your program you can check the return code again + if (dris.ret_code /= 0) then + Put_Line ("Dinkey Dongle protection error"); + return -1; + end if; + + Put_Line("EncryptUserData worked. Data decrypted is: " & Interfaces.C.To_Ada (szData)); + return 0; + end; + + + + -- !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! + -- In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" + -- in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm + -- but the code can be modified easily to use the 3 encryption parameters. + + ---------------------------------- + -- MyRWAlgorithm + ---------------------------------- + -- !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm + -- NB The logical operators xor, or, and only work on unsigned integers so you may have to convert signed to unsigned + function MyRWAlgorithm(a,b,c,d,e,f,g,h : int32) return uint32 is + a2,b2,c2,d2,e2,f2 : uint32; + for a2'Address use a'Address; + for b2'Address use b'Address; + for c2'Address use c'Address; + for d2'Address use d'Address; + for e2'Address use e'Address; + for f2'Address use f'Address; + begin + return a2 xor b2 xor c2 xor d2 xor e2 xor f2; + end; + + ---------------------------------- + -- CryptDRIS + ---------------------------------- + -- !!!! please overwrite the 3 parameters with the parameters specfied in DinkeyAdd + -- NB seed32, seed64 and bigseed64 are a clever way of initialising the bigseed array + procedure CryptDRIS(dris : t_DRIS_access; seed1, seed2 : uint32) is + i,j,k : uint32; + + type t_seed32 is array (1..2) of uint32; + type t_seed64 is array (1..1) of uint64; + seed32 : t_seed32; + seed64 : t_seed64; + for seed32'Address use seed64'Address; + + type t_uint64_array is array (1..32) of uint64; + bigseed64 : t_uint64_array; + + type t_uint8_array is array (uint8(0)..255) of uint8; + bigseed : t_uint8_array; + for bigseed'Address use bigseed64'Address; + + S : t_uint8_array; + temp, t : uint8; + + dris_size : uint32 := t_DRIS'Size/8; + type t_array is array (0..dris_size-1) of Interfaces.Unsigned_8; + dris_array : t_array; + for dris_array'Address use dris.all'Address; + + begin + + seed32 := (1=> seed1, 2 => seed2); + bigseed64 := (others => seed64(1)); + + for i in S'Range loop + S(i) := i; + end loop; + + j := 0; + for i in S'Range loop + j := (j + uint32(S(i)) + uint32(bigseed(i)) + 123) mod 256; -- !!!! parameter 1 (123) + temp := S(i); + S(i) := S(uint8(j)); + S(uint8(j)) := temp; + end loop; + + i := 0; + j := 0; + k := 16; + + while k < dris_size loop + i := (i + 1) mod 256; + j := (j + uint32(S(uint8(i))) + 212) mod 256; -- !!!! parameter 2 (212) + temp := S(uint8(i)); + S(uint8(i)) := S(uint8(j)); + S(uint8(j)) := temp; + t := uint8 (uint32(S(uint8(i)) + S(uint8(j)) + 97) mod 256); -- !!!! parameter 3 (97) + dris_array(k) := dris_array(k) xor S(t); + k := k + 1; + end loop; + end; + + + ---------------------------------- + -- CryptApiData + ---------------------------------- + -- !!!! if you specify parameters then you need to overwrite the parameters in this function. + -- However, if you use the R/W algorithm then you can use this function as it is. + -- NB seed32, seed64 and bigseed64 are a clever way of initialising the bigseed array + procedure CryptApiData (data : System.Address; + length : int32; + seed1, seed2 : uint32; + alg_answer : uint32) + is + i,j : uint32; + + type t_seed32 is array (1..2) of uint32; + type t_seed64 is array (1..1) of uint64; + seed32 : t_seed32; + seed64 : t_seed64; + for seed32'Address use seed64'Address; + + + type t_uint64_array is array (1..32) of uint64; + bigseed64 : t_uint64_array; + + type t_uint8_array is array (uint8(0)..255) of uint8; + bigseed : t_uint8_array; + for bigseed'Address use bigseed64'Address; + + S : t_uint8_array; + temp, t : uint8; + + type t_array is array (0..length-1) of Interfaces.Unsigned_8; + data_array : t_array; + for data_array'Address use data; + + begin + + seed32 := (1=> seed1, 2 => seed2); + bigseed64 := (others => seed64(1)); + + for i in S'Range loop + S(i) := i; + end loop; + + j := 0; + for i in S'Range loop + j := (j + uint32(S(i)) + uint32(bigseed(i)) + (uint32(alg_answer) and uint32(255))) mod 256; -- parameter 1 + temp := S(i); + S(i) := S(uint8(j)); + S(uint8(j)) := temp; + end loop; + + i := 0; + j := 0; + for k in data_array'Range loop + i := (i + 1) mod 256; + j := (j + uint32(S(uint8(i))) + (Shift_Right(uint32(alg_answer),8) and 255)) mod 256; -- parameter 2 + temp := S(uint8(i)); + S(uint8(i)) := S(uint8(j)); + S(uint8(j)) := temp; + t := uint8 ((uint32(S(uint8(i))) + uint32(S(uint8(j))) + uint32(Shift_Right(uint32(alg_answer),16) and 255)) mod 256); -- parameter 3 + data_array(k) := data_array(k) xor S(t); + end loop; + end; + + ---------------------------------- + -- ProtCheckEnc + ---------------------------------- + -- We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. + -- NB if you are using the debug module then do not call CryptDRIS as DRIS encryption is not supported. See notes in C readme.txt + function ProtCheckEnc return int32 is + ret_code : int32; + begin + + -- set the DRIS to have random values + random_set(dris); -- NB this also fills seed1, seed2 with random values + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := PROTECTION_CHECK; -- standard protection check + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + CryptDRIS(dris, dris.seed1, dris.seed2); -- encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code := DDProtCheck(dris, System.Null_Address); + + CryptDRIS(dris, dris.seed1, dris.seed2); -- decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + -- later in your code you can check other values in the DRIS... + + if (dris.sdsn /= MY_SDSN) then + Put_Line ("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + end if; + + -- later on in your program you can check the return code again + if (dris.ret_code /= 0) then + Put_Line ("Dinkey Dongle protection error"); + return -1; + end if; + + Put_Line ("ProtCheckEnc worked"); + return 0; + end; + + ---------------------------------- + -- ProtCheckWithAlgEnc + ---------------------------------- + -- NB for this to work you must program at least "user algorithm" into the dongle + -- NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + -- sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample code from DinkeyLook. + -- We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. + function ProtCheckWithAlgEnc return int32 is + ret_code : int32; + begin + -- set the DRIS to have random values + random_set(dris); -- NB this also fills seed1, seed2 with random values + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := EXECUTE_ALGORITHM; -- standard protection check & execute algorithm + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number := 1; -- execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + -- you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.var_a := 1; -- sample values + dris.var_b := 2; + dris.var_c := 3; + dris.var_d := 4; + dris.var_e := 5; + dris.var_f := 6; + dris.var_g := 7; + dris.var_h := 8; + + CryptDRIS(dris, dris.seed1, dris.seed2); -- encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code := DDProtCheck(dris, System.Null_Address); + + CryptDRIS(dris, dris.seed1, dris.seed2); -- decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + -- later in your code you can check other values in the DRIS... + + if (dris.sdsn /= MY_SDSN) then + Put_Line ("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + end if; + + -- ...later on in your program you can check the return code again + if (dris.ret_code /= 0) then + Put_Line ("Dinkey Dongle protection error"); + return -1; + end if; + + -- if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + -- !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) /= dris.alg_answer) then + Put_Line ("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine"); + return -1; + end if; + + Put_Line ("ProtCheckWithAlgEnc worked"); + return 0; + end; + + + ---------------------------------- + -- WriteBytesEnc + ---------------------------------- + -- This writes the Data "Hello, World!" to the dongle data area at offset 7 + -- In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. + -- We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + function WriteBytesEnc return int32 is + szDataToWrite : Interfaces.C.char_array := Interfaces.C.To_C ("Hello, World!", True); -- append null so we write that too! + ret_code : int32; + alg_ans : uint32; + begin + + -- set the DRIS to have random values + random_set(dris); -- NB this also fills seed1, seed2, var_a...var_h with random values + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := WRITE_DATA_AREA; -- standard protection check & write data + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset := 7; + dris.rw_length := szDataToWrite'Length; + dris.rw_data_ptr := szDataToWrite'Address; + + -- calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + -- encrypt data we want to write. + CryptApiData(szDataToWrite'Address, szDataToWrite'Length, dris.seed1, dris.seed2, alg_ans); + + CryptDRIS(dris, dris.seed1, dris.seed2); -- encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code := DDProtCheck(dris, System.Null_Address); + + CryptDRIS(dris, dris.seed1, dris.seed2); -- decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + -- ...later in your code you can check other values in the DRIS... + + if (dris.sdsn /= MY_SDSN) then + Put_Line ("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + end if; + + -- later on in your program you can check the return code again + if (dris.ret_code /= 0) then + Put_Line ("Dinkey Dongle protection error"); + return -1; + end if; + + Put_Line ("WriteBytesEnc worked"); + return 0; + end; + + ---------------------------------- + -- ReadBytesEnc + ---------------------------------- + -- This reads 14 bytes of data from offset 7 in the dongle data area + -- In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. + -- In order for the data to be displayed properly by this routine it will need to be text data + -- We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + function ReadBytesEnc return int32 is + szDataRead : Interfaces.C.char_array (1..14); + ret_code : int32; + alg_ans : uint32; + begin + -- set the DRIS to have random values + random_set(dris); -- NB this also fills seed1, seed2, var_a...var_h with random values + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := READ_DATA_AREA; -- standard protection check & read data + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset := 7; + dris.rw_length := szDataRead'Length; + dris.rw_data_ptr := szDataRead'Address; + + -- calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + CryptDRIS(dris, dris.seed1, dris.seed2); -- encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code := DDProtCheck(dris, System.Null_Address); + + CryptDRIS(dris, dris.seed1, dris.seed2); -- decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + -- ...later in your code you can check other values in the DRIS... + + if (dris.sdsn /= MY_SDSN) then + Put_Line ("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + end if; + + -- later on in your program you can check the return code again + if (dris.ret_code /= 0) then + Put_Line ("Dinkey Dongle protection error"); + return -1; + end if; + + -- decrypt data that was read. + CryptApiData(szDataRead'Address, szDataRead'Length, dris.seed1, dris.seed2, alg_ans); + + Put_Line("It worked! Dinkey Dongle Data area, offset 7 is: " & Interfaces.C.To_Ada(szDataRead)); + return 0; + end; + + + + ---------------------------------- + -- EncryptUserDataEnc + ---------------------------------- +-- ************************* EncryptUserDataEnc ****************************** +-- This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +-- It will then do another protection & decrypt the data +-- We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + function EncryptUserDataEnc return int32 is + szData : Interfaces.C.char_array := Interfaces.C.To_C ("Hello, World!"); + ret_code : int32; + alg_ans : uint32; + begin + -- set the DRIS to have random values + random_set(dris); + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := ENCRYPT_USER_DATA; -- standard protection check & encrypt user data + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num := 1; + dris.rw_length := szData'Length; + dris.rw_data_ptr := szData'Address; + + -- calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + -- encrypt data we want to pass. + CryptApiData(szData'Address, szData'Length, dris.seed1, dris.seed2, alg_ans); + + CryptDRIS(dris, dris.seed1, dris.seed2); -- encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code := DDProtCheck(dris, System.Null_Address); + + CryptDRIS(dris, dris.seed1, dris.seed2); -- decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + -- ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + -- Now decrypt the same data to get the original values + random_set(dris); + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := DECRYPT_USER_DATA; -- standard protection check & decrypt user data + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num := 1; + dris.rw_length := szData'Length; + dris.rw_data_ptr := szData'Address; + + CryptDRIS(dris, dris.seed1, dris.seed2); -- encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code := DDProtCheck(dris, System.Null_Address); + + CryptDRIS(dris, dris.seed1, dris.seed2); -- decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + -- ...later in your code you can check other values in the DRIS... + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + if (dris.sdsn /= MY_SDSN) then + Put_Line ("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + end if; + + -- later on in your program you can check the return code again + if (dris.ret_code /= 0) then + Put_Line ("Dinkey Dongle protection error"); + return -1; + end if; + + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + -- decrypt data that was passed to us by the API + CryptApiData(szData'Address, szData'Length, dris.seed1, dris.seed2, alg_ans); + + Put_Line("It worked. Data decrypted is: " & Interfaces.C.To_Ada(szData)); + return 0; + end; + + -- ************* useful routines that are called from our functions ********** + + ---------------------------------- + -- random_set + ---------------------------------- + -- fills the buffer with length bytes of random data + -- NB there are better ways of doing this (for example with the Windows Crypto API calls) + procedure random_set(dris : t_DRIS_access) + is + package p_rand is new Ada.Numerics.Discrete_Random (Interfaces.Unsigned_8); + + G : p_rand.Generator; + size : Natural := t_DRIS'Size/8; + type t_array is array (1..size) of Interfaces.Unsigned_8; + T : t_array; + for T'Address use dris.all'Address; + begin + p_rand.Reset (G); + for i in T'Range loop + T(i) := p_rand.Random (G); + end loop; + end; + + ---------------------------------- + -- DisplayError + ---------------------------------- + -- displays messages for the most common errors. You will want to change this for your code + procedure DisplayError(ret_code : int32; extended_error : int32) + is + use Ada.Text_IO; + begin + case ret_code is + when 401 => Put_Line ("Error! No dongles detected!"); + when 403 => Put_Line ("Error! The dongle detected has a different type to the one specified in DinkeyAdd."); + when 404 => Put_Line ("Error! The dongle detected has a different model to those specified in DinkeyAdd."); + when 409 => Put_Line ("Error! The dongle detected has not been programmed by DinkeyAdd."); + when 410 => Put_Line ("Error! The dongle detected has a different Product Code to the one specified in DinkeyAdd."); + when 411 => Put_Line ("Error! The dongle detected does not contain the licence associated with this program."); + when 413 => Put_Line ("Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual."); + when 417 => Put_Line ("Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa."); + when 423 => Put_Line ("Error! The number of network users has been exceeded."); + when 435 => Put_Line ("Error! DinkeyServer has not been detected on the network."); + when 922 => Put_Line ("Error! The Software Key has expired."); + when others => + Put_Line ("An error occurred checking the dongle."); + Put_Line ("Error:" & int32'Image(ret_code) & ", Extended Error:" & int32'Image(extended_error) ); + end case; + end; + + ---------------------------------- + -- main + ---------------------------------- + +begin + -- call the function(s) of your choice here + -- by default I have chosen a standard protection check + + if (ProtCheck /= 0) then + return; -- terminate your program + end if; + + -- continue your program + +end apitest; diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Ada/dris.ads b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Ada/dris.ads new file mode 100644 index 0000000..85cf512 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Ada/dris.ads @@ -0,0 +1,110 @@ +-- dris.ads +-- Dinkey Runtime Information Structure (DRIS) +-- !! this file should not be modified + +with System; +with Interfaces; + +package dris is + + pragma linker_options ("-ldpwin32"); + + subtype uint8 is Interfaces.Unsigned_8; + subtype int32 is Interfaces.Integer_32; + subtype uint32 is Interfaces.Unsigned_32; + subtype uint64 is Interfaces.Unsigned_64; + + type t_DRIS; + + type t_DRIS_access is access all t_DRIS; + + -- functions - must specify only one + type t_functions is + (NONE, + PROTECTION_CHECK, -- checks for dongle, check program params... + EXECUTE_ALGORITHM, -- protection check + calculate answer for specified algorithm with specified inputs + WRITE_DATA_AREA, -- protection check + writes dongle data area + READ_DATA_AREA, -- protection check + reads dongle data area + ENCRYPT_USER_DATA, -- protection check + the dongle will encrypt user data + DECRYPT_USER_DATA, -- protection check + the dongle will decrypt user data + FAST_PRESENCE_CHECK, -- checks for the presence of the correct dongle only with minimal security, no flags allowed. + STOP_NET_USER -- stops a network user (a protection check is NOT performed) + ); + for t_functions'Size use 32; + + -- flags - can specify as many as you like + type t_flag is new int32; + DEC_ONE_EXEC : t_flag := 1; -- decrement execs by 1 + DEC_MANY_EXECS : t_flag := 2; -- decrement execs by number specified in execs_decrement + START_NET_USER : t_flag := 4; -- starts a network user + USE_FUNCTION_ARGUMENT : t_flag := 16; -- use the extra argument in the function for pointers + CHECK_LOCAL_FIRST : t_flag := 32; -- always look in local ports before looking in network ports + CHECK_NETWORK_FIRST : t_flag := 64; -- always look on the network before looking in local ports + USE_ALT_PROG_NAME : t_flag := 128; -- use name specified in prog_name instead of this program name + DONT_SET_MAXDAYS_EXPIRY : t_flag := 256; -- if the max days expiry date has not been calculated then do not do it this time + MATCH_DONGLE_NUMBER : t_flag := 512; -- restrict the search to match the dongle number specified in the DRIS + DONT_RETURN_FD_DRIVE : t_flag := 1024; -- if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + + -- DDProtCheck + function DDProtCheck (dris : t_DRIS_access; data : System.Address) return int32; + pragma import (StdCall, DDProtCheck, "DDProtCheck"); + + type t_array_4_char is array (0..3) of Character; + type t_array_12_char is array (0..11) of Character; + type t_array_128_char is array (0..127) of Character; + type t_array_256_char is array (0..255) of Character; + + type t_DRIS is record + -- the first 4 fields are never encrypted + header : t_array_4_char; + + -- inputs + size : int32; -- size of this structure + seed1 : uint32; -- seed for data/dris encryption + seed2 : uint32; -- as above + -- (maybe encrypted from now on) + funct : t_functions; -- specify only one function + flags : int32; -- options for the function selected. To use more than one OR them together: OPTION1 | OPTION2... + execs_decrement : uint32; -- amount by which to dec execs if we use flag: DEC_MANY_EXECS + data_crypt_key_num : int32; -- number of the key (1-3) that the dongle uses to encrypt or decrypt user data + rw_offset : int32; -- offset in the dongle data area to read or write data + rw_length : int32; -- length of data are to read/write/encrypt/decrypt + rw_data_ptr : System.Address; -- pointer to data to write / be read + alt_prog_name : t_array_256_char; -- protection check for different program instead of this one, must be null-terminated + var_a : int32; -- variable values for user algorithm + var_b : int32; + var_c : int32; + var_d : int32; + var_e : int32; + var_f : int32; + var_g : int32; + var_h : int32; + alg_number : int32; -- the number of the user algorithm that you want to execute + + -- outputs + ret_code : int32; -- return code from the protection check + ext_err : int32; -- extended error + dongle_type : int32; -- type of dongle detected. 1 = Pro, 2 = FD + model : int32; -- model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + sdsn : int32; -- Software Developer's Serial Number + prodcode : t_array_12_char; -- Product Code (null-terminated) + dongle_number : uint32; + update_number : int32; + data_area_size : uint32; -- size of the data area used in the dongle detected + max_alg_num : int32; -- the maximum algorithm number in the dongle detected + execs : int32; -- executions left: -1 indicates 'no limit' + exp_day : int32; -- expiry day: -1 indicates 'no limit' + exp_month : int32; -- expiry month: -1 indicates 'no limit' + exp_year : int32; -- expiry year: -1 indicates 'no limit' + features : uint32; -- features value + net_users : int32; -- maximum number of network users for the dongle detected: -1 indicates 'no limit' + alg_answer : int32; -- answer to the user algorithm executed with the given variable values + fd_capacity : uint32; -- capacity of the data area in FD dongle. + fd_drive : t_array_128_char; -- drive letter of FD dongle detected e.g. 'f:\' (or mount name under Linux) + swkey_type : int32; -- 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + swkey_exp_day : int32; -- software key expiry date (if software key detected) + swkey_exp_month : int32; + swkey_exp_year : int32; + end record; + +end dris; diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/AutoCAD/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/AutoCAD/README.txt new file mode 100644 index 0000000..2eff74d --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/AutoCAD/README.txt @@ -0,0 +1,196 @@ +Notes on using AutoCAD with Dinkey Pro/FD +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To access a Dinkey Pro or FD dongle from AutoCAD, you must call an ActiveX DLL +using Visual LISP (AutoLISP). It is called dpcom32.dll (for 32-bit AutoCAD) and +dpcom64.dll (for 64-bit AutoCAD). These files are located in the Modules folder of +your SDK installation directory. + +This ActiveX control is an intermediary layer that calls the normal dpwin32.dll (32-bit) +or dpwin64.dll (64-bit) Runtime module. To protect your application, you should add +protection to dpwin32.dll (or dpwin64.dll) using DinkeyAdd specifying the API method +of protection. You should not protect dpcom32.dll (dpcom64.dll). [if you used a version +of the SDK previous to v7.0 please read the notes at the end of this file]. + +On 64-bit operating systems AutoCAD will always be 64-bit and on 32-bit operating +systems AutoCAD will always be 32-bit. You need to use the appropriate protected +ActiveX control (dpcom32.dll or dpcom64.dll) and protected Runtime module (dpwin32.dll +or dpwin64.dll) depending on whether 32-bit AutoCAD or 64-bit AutoCAD is being used. + +We recommend that you rename the protected runtime module. (reason: you may have more than +one Autocad product you want to protect. In this case, for each product, you can protect +our Runtime module (renamed in each case to a different filename) to different protection +parameters). + +To use the ActiveX control you must first register it with Windows: + +go to Start > All Programs > Accessories, right-click Command Prompt and choose +"Run As Administrator". Then enter: + + regsvr32 "\dpcom32.dll" + +To unregister it enter: + + regsvr32 /U "\dpcom32.dll" + +[For 64-bit Windows, replace dpcom32.dll with dpcom64.dll]. + +The ActiveX control needs to be registered on your end-users's machines. +Most installation programs allow you to do this automatically so that your +customers do not have to. + +The ActiveX control internally contains a DRIS structure. The idea is that, +after calling the initialisation function, you call one of the protection check +functions and then call as many of the Get... functions as you like to get the +parameters normally filled-in to the DRIS. These values remain valid until the +next protection check call when they are updated. + +Protecting AutoCAD programs using this ActiveX is not as secure compared to other +languages because of limitations of the AutoLISP programming language. For example +you cannot encrypt the DRIS or data passed to and from the API. To increase +security you can use an algorithm (see the ProtCheckWithAlg function). + +The API provided by dpcom32.dll / dpcom64.dll is listed below. There is also some +very simple sample code - dpsample.lsp. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in the +"Increasing your Protection" chapter of the manual. + +(See "Structures > DRIS Structure" in the user manual for an explanation of the parameters). + +** You must call the Initialisation Function, InitDPCOM, first ** + +InitDPCOM +~~~~~~~~~ +syntax: + (InitDPCOM bsDllName) +return: + return code (0 is success, otherwise one of the following errors can be returned: + 9003 - dll you specified cannot be loaded. Either not present in the correct + folder or you specified the wrong name / path. + 9004 - dll is loaded correctly but is not our runtime module! +notes: + this function must be called first to initialise the COM control + the parameter you pass is the renamed version of the protected runtime module + this module should be in the same folder as the COM control (if not you need + to specify the relative path and the filename). A typical call would be: + "InitDPCOM" "my_protected_dpwin32.dll" + +** Then you should call one of the Protection Check Functions listed below. ** +** In addition to the normal runtime errors returned by our runtime modules ** +** they can also return the error 9000 (InitDPCom not called). + +ProtCheck +~~~~~~~~~ +syntax: + (ProtCheck flags execs_decrement alt_licence_name) +returns: + return code (0 = success, otherwise an error number is returned) +notes: + performs a standard protection check. + see table below for details of flags values. You must specify execs_decrement + and alt_licence_name even if they are not used. A typical call would be: + "ProtCheck" 0 0 "" + +ProtCheckWithAlg +~~~~~~~~~~~~~~~~ +syntax: + (ProtCheckWithAlg flags alg_number var_a var_b var_c var_d var_e var_f var_g var_h ) +returns: + return code (0 = success, o.w. error number) +notes: + Performs a protection check and executes the user algorithm 'alg_number' + with variable values 'var_a'...'var_h'. + Call (GetAlgAnswer) to get the result of this algorithm after successfully calling + this function. + +WriteString +~~~~~~~~~~~ +syntax: + (WriteString flags offset DataString) +returns: + return code (0 = success, o.w. error number) +notes: + Performs a protection check and writes the string "DataString" to the dongle + data area at the offset specified. + +ReadString +~~~~~~~~~~~ +syntax: + (ReadString flags offset length) +returns: + return code (0 = success, o.w. error number) +notes: + Performs a protection check and reads data from the dongle data area. + Call (GetDataRead) to read the data string after successfully calling this function. + + +** After you have called either the ProtCheck or ProtCheckWithAlg or WriteString or ** +** ReadString functions you can call one of the following functions to get data from ** +** the DRIS. These functions will all return -2 (or "-2") if a protection check has ** +** not been performed. They will return -3 (or "-3") if a protection check has been ** +** performed but failed. Refer to the documentation regarding the DRIS for more ** +** information on each of these fields. + +None of these methods require input parameters. + +GetExtendedError - returns the extended error (only set if one of the protection check functions has failed) +GetType - returns the type of dongle detected. Numerical value - see DRIS documentation. +GetModel - returns the model of the dongle detected. Numerical value - see documentation on DRIS. +GetSDSN - returns the SDSN. +GetProdCode - returns the Product Code as a string. +GetDongleNumber - returns the donglenumber as a string. +GetUpdateNumber - returns the update number +GetDataAreaSize - returns the size of the data are +GetMaxAlgNum - returns the maximum algorithm number in the dongle detected +GetExecs - returns the execs left (-1 is "no limit") +GetExpDay - returns the expiry day (-1 is "no limit") +GetExpMonth - returns the expiry month (-1 is "no limit") +GetExpYear - returns the expiry year (-1 is "no limit") +GetFeatures - returns the features value. +GetNetUsers - returns the maximum number of simultaneous network user allowed by the dongle (-1 is "no lmiit") +GetAlgAnswer - returns the answer of the Algorithm (only valid if ProtCheckWithAlg previously called) +GetFDCapacity - returns the maximum capacity for the data area if an FD dongle is detected +GetFDDrive - returns the drive letter (mount name) of FD dongle detected e.g. f:\ +GetDataRead - returns the read read from the dongle data area (only valid if ReadString previously called). +GetSWKeyType - returns whether a software key was detected and what type it is +GetSWKeyExpDay - software key expiry day (if a software key was detected) +GetSWKeyExpMonth - software key expiry month +GetSWKeyExpYear - software key expiry year + +Visual LISP Code Example +~~~~~~~~~~~~~~~~~~~~~~~~ +dpsample.lsp gives a simple example of using the Dinkey Pro/FD API from Visual LISP. +To run dpsample.lsp: + +1. Enter 'vlisp' (without the quotes) on the AutoCAD command line to open the Visual LISP editor. +2. Open dpsample.lsp (and then click on the Window that contains the script to give it focus). +3. Use the toolbar or the menu 'Tools > Load Text in Editor' to load the dpsample function. +4. Enter '(dpsample)' (without the quotes) on the command line to execute the function. + +DRIS Flags Values +~~~~~~~~~~~~~~~~~ +In general the flags value will be 0. If you want to use more than one flag then add the values. + +Value Name in Manual Description +1 DEC_ONE_EXEC decrement executions by 1 +2 DEC_MANY_EXECS decrement executions by number specified in execs_decrement +4 START_NET_USER start a network user +8 STOP_NET_USER stops a network user (a protection check is NOT performed) +16 USE_FUNCTION_ARGUMENT use the extra argument in the function to pass data +32 CHECK_LOCAL_FIRST always look for a dongle locally before looking in network ports +64 CHECK_NETWORK_FIRST always look for a network dongle before looking for a dongle locally +128 USE_ALT_LICENCE_NAME use name specified in alt_licence_name instead of the default one +256 DONT_SET_MAXDAYS_EXPIRY if the max days expiry date has not been calculated then do not do it this time +512 MATCH_DONGLE_NUMBER restrict the search to match the dongle number specified in the DRIS +1024 DONT_RETURN_FD_DRIVE if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + +Notes on Changes Made to the ActiveX Control since version previous to 7.0 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The ActiveX controls we provided with versions of the SDK previous to 7.0 did not depend on +the runtime module and had to be protected directly. However, you can only register one of these +COMs per machine (renaming the file does not help in this case because it is identified by an internal +GUID which cannot be change). + +This meant that you could only protect one Product per machine. These old COM controls were loaded +using "DPro.DPro.1". The new COM controls can be loaded using "DPro.DPro.2". You can register both +COM controls on one machine at the same time if you need too as they have different internal GUIDs. diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/AutoCAD/dpsample.lsp b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/AutoCAD/dpsample.lsp new file mode 100644 index 0000000..eab743c --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/AutoCAD/dpsample.lsp @@ -0,0 +1,27 @@ +; Note - this code is provided only to illustrate the syntax of calling methods in dpcom32.dll / dpcom64.dll. +; You should modify it to use the Dinkey Pro/FD Visual LISP API to best suit your own needs. +; See the Dinkey Pro/FD Manual for more information on how best to use the API to improve the level of protection. + +(defun dpsample() + (vl-load-com) ; You MUST call this command first, to load all external COM objects including dpcom32.dll or dpcom64.dll + + (setq dinkeyobject (vlax-create-object "DPro.DPro.2")) ; Get a reference to the Dinkey Pro object + + (setq retvalue (vlax-invoke-method dinkeyobject "InitDPCOM" "my_renamed_dpwin32or64.dll")) + (if (= retvalue 0) ; Check the return value of intialisation + (princ "Initialisation worked OK") ; init successful + (princ (strcat "Initialisation failed with error " (itoa retvalue))) ; init failed - dll not in correct place, or wrong name specified? + ) + + (princ "\n") + + (setq retvalue (vlax-invoke-method dinkeyobject "ProtCheck" 0 0 "")) ; Call this object's 'ProtCheck' method + (if (= retvalue 0) ; Check the return value of the protection check + (princ "It worked!") ; Protection check successful + (princ (strcat "Protection check failed with error " (itoa retvalue))) ; Protection check failed, display an error message + ) + + (vlax-release-object dinkeyobject) ; Release the Dinkey object reference + + (princ) +) diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyAdd/App.ico b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyAdd/App.ico new file mode 100644 index 0000000..3a5525f Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyAdd/App.ico differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyAdd/AssemblyInfo.cs b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyAdd/AssemblyInfo.cs new file mode 100644 index 0000000..9f89a32 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyAdd/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyAdd/Form1.cs b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyAdd/Form1.cs new file mode 100644 index 0000000..4eb8d1c --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyAdd/Form1.cs @@ -0,0 +1,548 @@ +// !! We strongly recommend that you read the "readme.txt" file in the sample code folder. +// !! It contains important instructions on how to use the sample code + +using System; +using System.Drawing; +using System.Collections; +using System.ComponentModel; +using System.Windows.Forms; +using System.Data; +using System.Runtime.InteropServices; // so we can marshal our structures in dapf.cs + +namespace dapfTest +{ + /// + /// Summary description for Form1. + /// + public class Form1 : System.Windows.Forms.Form + { + /// + /// Required designer variable. + /// + private System.ComponentModel.Container components = null; + + public Form1() + { + // + // Required for Windows Form Designer support + // + InitializeComponent(); + + // + // TODO: Add any constructor code after InitializeComponent call + // + } + + /// + /// Clean up any resources being used. + /// + protected override void Dispose( bool disposing ) + { + if( disposing ) + { + if (components != null) + { + components.Dispose(); + } + } + base.Dispose( disposing ); + } + + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.TextBox machineIDText; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.TextBox expdayText; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.TextBox expmonthText; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.TextBox expyearText; + private GroupBox groupBox2; + private Label label9; + private TextBox maxDaysText; + private Button demoSoftwareKey; + + public string AppName = "dapfTest"; + + #region Windows Form Designer generated code + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.dapfFile = new System.Windows.Forms.TextBox(); + this.programDongle = new System.Windows.Forms.Button(); + this.programDongleMod = new System.Windows.Forms.Button(); + this.lockSoftware = new System.Windows.Forms.Button(); + this.tempSoftwareKey = new System.Windows.Forms.Button(); + this.encryptShellData = new System.Windows.Forms.Button(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.expyearText = new System.Windows.Forms.TextBox(); + this.label5 = new System.Windows.Forms.Label(); + this.expmonthText = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.expdayText = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.machineIDText = new System.Windows.Forms.TextBox(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.label9 = new System.Windows.Forms.Label(); + this.maxDaysText = new System.Windows.Forms.TextBox(); + this.demoSoftwareKey = new System.Windows.Forms.Button(); + this.groupBox1.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.SuspendLayout(); + // + // label1 + // + this.label1.Location = new System.Drawing.Point(16, 24); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(416, 16); + this.label1.TabIndex = 0; + this.label1.Text = "Full path of dapf file:"; + // + // dapfFile + // + this.dapfFile.Location = new System.Drawing.Point(16, 40); + this.dapfFile.Name = "dapfFile"; + this.dapfFile.Size = new System.Drawing.Size(344, 20); + this.dapfFile.TabIndex = 1; + // + // programDongle + // + this.programDongle.Location = new System.Drawing.Point(84, 88); + this.programDongle.Name = "programDongle"; + this.programDongle.Size = new System.Drawing.Size(208, 23); + this.programDongle.TabIndex = 2; + this.programDongle.Text = "Program Dongle"; + this.programDongle.Click += new System.EventHandler(this.programDongle_Click); + // + // programDongleMod + // + this.programDongleMod.Location = new System.Drawing.Point(84, 128); + this.programDongleMod.Name = "programDongleMod"; + this.programDongleMod.Size = new System.Drawing.Size(208, 23); + this.programDongleMod.TabIndex = 3; + this.programDongleMod.Text = "Program Dongle with modification"; + this.programDongleMod.Click += new System.EventHandler(this.programDongleMod_Click); + // + // lockSoftware + // + this.lockSoftware.Location = new System.Drawing.Point(84, 168); + this.lockSoftware.Name = "lockSoftware"; + this.lockSoftware.Size = new System.Drawing.Size(208, 23); + this.lockSoftware.TabIndex = 4; + this.lockSoftware.Text = "Lock Software"; + this.lockSoftware.Click += new System.EventHandler(this.lockSoftware_Click); + // + // tempSoftwareKey + // + this.tempSoftwareKey.Location = new System.Drawing.Point(64, 88); + this.tempSoftwareKey.Name = "tempSoftwareKey"; + this.tempSoftwareKey.Size = new System.Drawing.Size(208, 23); + this.tempSoftwareKey.TabIndex = 5; + this.tempSoftwareKey.Text = "Create Software Key"; + // + // encryptShellData + // + this.encryptShellData.Location = new System.Drawing.Point(84, 208); + this.encryptShellData.Name = "encryptShellData"; + this.encryptShellData.Size = new System.Drawing.Size(208, 23); + this.encryptShellData.TabIndex = 6; + this.encryptShellData.Text = "Encrypt Shell Data Files"; + this.encryptShellData.Click += new System.EventHandler(this.encryptShellData_Click); + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.expyearText); + this.groupBox1.Controls.Add(this.label5); + this.groupBox1.Controls.Add(this.expmonthText); + this.groupBox1.Controls.Add(this.label4); + this.groupBox1.Controls.Add(this.expdayText); + this.groupBox1.Controls.Add(this.label3); + this.groupBox1.Controls.Add(this.label2); + this.groupBox1.Controls.Add(this.machineIDText); + this.groupBox1.Controls.Add(this.tempSoftwareKey); + this.groupBox1.Location = new System.Drawing.Point(16, 256); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(336, 128); + this.groupBox1.TabIndex = 7; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Temporary Software Key"; + // + // expyearText + // + this.expyearText.Location = new System.Drawing.Point(240, 56); + this.expyearText.Name = "expyearText"; + this.expyearText.Size = new System.Drawing.Size(32, 20); + this.expyearText.TabIndex = 13; + this.expyearText.Text = "yyyy"; + // + // label5 + // + this.label5.Location = new System.Drawing.Point(224, 56); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(8, 20); + this.label5.TabIndex = 12; + this.label5.Text = "/"; + this.label5.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // expmonthText + // + this.expmonthText.Location = new System.Drawing.Point(184, 56); + this.expmonthText.Name = "expmonthText"; + this.expmonthText.Size = new System.Drawing.Size(32, 20); + this.expmonthText.TabIndex = 11; + this.expmonthText.Text = "mm"; + // + // label4 + // + this.label4.Location = new System.Drawing.Point(168, 56); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(8, 20); + this.label4.TabIndex = 10; + this.label4.Text = "/"; + this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // expdayText + // + this.expdayText.Location = new System.Drawing.Point(128, 56); + this.expdayText.Name = "expdayText"; + this.expdayText.Size = new System.Drawing.Size(32, 20); + this.expdayText.TabIndex = 9; + this.expdayText.Text = "dd"; + // + // label3 + // + this.label3.Location = new System.Drawing.Point(24, 56); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(100, 20); + this.label3.TabIndex = 8; + this.label3.Text = "Expiry Date:"; + this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // label2 + // + this.label2.Location = new System.Drawing.Point(24, 24); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(100, 20); + this.label2.TabIndex = 7; + this.label2.Text = "Machine ID:"; + this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // machineIDText + // + this.machineIDText.Location = new System.Drawing.Point(128, 24); + this.machineIDText.Name = "machineIDText"; + this.machineIDText.Size = new System.Drawing.Size(184, 20); + this.machineIDText.TabIndex = 6; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.label9); + this.groupBox2.Controls.Add(this.maxDaysText); + this.groupBox2.Controls.Add(this.demoSoftwareKey); + this.groupBox2.Location = new System.Drawing.Point(19, 400); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(336, 99); + this.groupBox2.TabIndex = 14; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Demo Software Key"; + // + // label9 + // + this.label9.Location = new System.Drawing.Point(24, 24); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(100, 20); + this.label9.TabIndex = 7; + this.label9.Text = "Max Days:"; + this.label9.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // maxDaysText + // + this.maxDaysText.Location = new System.Drawing.Point(128, 24); + this.maxDaysText.Name = "maxDaysText"; + this.maxDaysText.Size = new System.Drawing.Size(184, 20); + this.maxDaysText.TabIndex = 6; + // + // demoSoftwareKey + // + this.demoSoftwareKey.Location = new System.Drawing.Point(61, 59); + this.demoSoftwareKey.Name = "demoSoftwareKey"; + this.demoSoftwareKey.Size = new System.Drawing.Size(208, 23); + this.demoSoftwareKey.TabIndex = 5; + this.demoSoftwareKey.Text = "Create Demo Template"; + this.demoSoftwareKey.Click += new System.EventHandler(this.demoSoftwareKey_Click); + // + // Form1 + // + this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); + this.ClientSize = new System.Drawing.Size(376, 523); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.encryptShellData); + this.Controls.Add(this.lockSoftware); + this.Controls.Add(this.programDongleMod); + this.Controls.Add(this.programDongle); + this.Controls.Add(this.dapfFile); + this.Controls.Add(this.label1); + this.Name = "Form1"; + this.Text = "Form1"; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox dapfFile; + private System.Windows.Forms.Button programDongle; + private System.Windows.Forms.Button programDongleMod; + private System.Windows.Forms.Button lockSoftware; + private System.Windows.Forms.Button tempSoftwareKey; + private System.Windows.Forms.Button encryptShellData; + + /* The sample code contains 5 functions. You will not need to use all these functions in your code. + Just use which ever functions are most appropriate and customise in your own way. The sample code + is just a guide. + + There are two methods to loading a DAPF file. These are shown in the first two functions + programDongle_Click and programDongleMod_Click: + + programDongle_Click: we load the DAPF file from disk and get a handle and use it "as is" using the API + call LoadDAPFFromFile. You can make some limited changes to overwrite the default + behaviour by using API flags. + + programDongleMod_Click: we load the DAPF file from disk and load into structures. We can then modify the + DAPF settings by modifying this structure. This method uses the API calls + ReadDAPFEx and LoadDAPF. + + The other functions use the first method (as it is simpler) but you can use the second method instead if + you prefer. + + Note - an alternative to using the programDongleMod_Click technique is to modify the DAPF file on disk + and then use the programDongle_Click technique. To modify a binary DAPF you would use the binary structures + that are defined in dapf.h. To modify JSON DAPF you would need to use a JSON parser. + + lockSoftware_Click : locks software (protect it) to a dongle as specified by the DAPF file. + + encryptShellData_Click: encrypts the shell data files specified in the DAPF file (this is used with encrypting + data file if you use the Shell Method with "Data File Encryption" enabled). + + tempSoftwareKey_Click: creates a Temporary Software Key based on the DAPF file and settings the user has entered. + + demoSoftwareKey_Click: creates a Demo Software Key Template based on the DAPF file and settings the user has entered. + + */ + + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.Run(new Form1()); + } + + // load a DAPF file from disk and program the dongle as specified by the DAPF file + private void programDongle_Click(object sender, System.EventArgs e) + { + IntPtr dapfHandle; + int err_code; + uint dongle_number; + + // load DAPF from File into memory + dapfHandle = DinkeyAdd.LoadDAPFFromFile(dapfFile.Text, out err_code); + if (dapfHandle == IntPtr.Zero) + { + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + // program dongle as specified by the DAPF file + err_code = DinkeyAdd.AddProtection(dapfHandle, DinkeyAdd.ACTION_PROGRAM_DONGLE, 0, 0, out dongle_number); + + // Unload DAPF from memory + DinkeyAdd.UnloadDAPF(ref dapfHandle); + + // display message (error or success) + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + + // load a DAPF file from disk, modify it in memory and then program the dongle + private void programDongleMod_Click(object sender, System.EventArgs e) + { + IntPtr dapfHandle; + int dummy1, dummy2, err_code; + uint dongle_number; + DINKEYINFO DinkeyInfo; + LICENCEINFO[] LicenceInfo; + FILEINFO[] FileInfo; + ALGORITHM[] Algorithms; + DATAFILEENC[] DataFileEnc; + + // in this case we need to read the DAPF into our structures, so that the DAPF values can be modified + err_code = DinkeyAdd.ReadDAPFEx(dapfFile.Text, out DinkeyInfo, out LicenceInfo, out FileInfo, out Algorithms, out DataFileEnc, out dummy1, out dummy2); + if (err_code != 0) + { + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + // patch new values + LicenceInfo[0].Features = 12345; + LicenceInfo[0].Execs = 100; + LicenceInfo[0].LicenceName = "fred"; + + // get DAPF handle + dapfHandle = DinkeyAdd.LoadDAPF(DinkeyInfo, LicenceInfo, FileInfo, Algorithms, DataFileEnc, out err_code); + if (dapfHandle == IntPtr.Zero) + { + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + // program dongle + err_code = DinkeyAdd.AddProtection(dapfHandle, DinkeyAdd.ACTION_PROGRAM_DONGLE, 0, 0, out dongle_number); + + // Unload DAPF from memory + DinkeyAdd.UnloadDAPF(ref dapfHandle); + + // display message (error or success) + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + + // load a DAPF file from disk and protect the files specified + // (in practice it is better to protect the files one at a time and output messages as you go along, similar to DinkeyAdd.exe) + // In this example we specify the flag to overwrite any existing output file that might exist. + private void lockSoftware_Click(object sender, System.EventArgs e) + { + IntPtr dapfHandle; + int err_code; + uint dummy; + + // load DAPF from File into memory + dapfHandle = DinkeyAdd.LoadDAPFFromFile(dapfFile.Text, out err_code); + if (dapfHandle == IntPtr.Zero) + { + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + // protect all the files listed in the DAPF file + err_code = DinkeyAdd.AddProtection(dapfHandle, DinkeyAdd.ACTION_PROTECT_SOFTWARE, -1, DinkeyAdd.FLAGS_OVERWRITE_OUTPUT, out dummy); + + // Unload DAPF from memory + DinkeyAdd.UnloadDAPF(ref dapfHandle); + + // display message (error or success) + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + + // load a DAPF file from disk and encrypt the shell data files specified + // (in practice it is better to encrypt the files one at a time and output messages as you go along, similar to DinkeyAdd.exe) + // In this example we specify the flag to overwrite any existing output file that might exist. + private void encryptShellData_Click(object sender, System.EventArgs e) + { + IntPtr dapfHandle; + int err_code; + + // load DAPF from File into memory + dapfHandle = DinkeyAdd.LoadDAPFFromFile(dapfFile.Text, out err_code); + if (dapfHandle == IntPtr.Zero) + { + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + // encrypt all the shell data files listed in the DAPF file + err_code = DinkeyAdd.EncryptShellDataFiles(dapfHandle, -1, DinkeyAdd.FLAGS_OVERWRITE_OUTPUT); + + // Unload DAPF from memory + DinkeyAdd.UnloadDAPF(ref dapfHandle); + + // display message (error or success) + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + + // load a DAPF file from disk and create a Temporary Software Key using the info that the user entered + private void tempSoftwareKey_Click(object sender, System.EventArgs e) + { + IntPtr dapfHandle; + int err_code; + TEMP_SWKEY_INFO swkey_info = new TEMP_SWKEY_INFO(); + + // load DAPF from File into memory + dapfHandle = DinkeyAdd.LoadDAPFFromFile(dapfFile.Text, out err_code); + if (dapfHandle == IntPtr.Zero) + { + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + // fill out the SWKEY structure from the values the user entered + swkey_info.size = Marshal.SizeOf(typeof(TEMP_SWKEY_INFO)); + swkey_info.machineID = Convert.ToUInt32(machineIDText.Text, 16); + swkey_info.expiry_day = Convert.ToInt32(expdayText.Text, 10); + swkey_info.expiry_month = Convert.ToInt32(expmonthText.Text, 10); + swkey_info.expiry_year = Convert.ToInt32(expyearText.Text, 10); + // !!!! in this case we just choose Pro Plus. You could load the DAPF file into structures and see which model is selected. + // If there is more than one model selected you can ask the customer to choose which model they want. + swkey_info.dongle_model = DinkeyAdd.SWKEY_MODEL_PRO_PLUS; + swkey_info.dongle_number = 0; + + // attempt to create the Temporary Software Key + err_code = DinkeyAdd.CreateTempSoftwareKey(dapfHandle, swkey_info, 0); + + // Unload DAPF from memory + DinkeyAdd.UnloadDAPF(ref dapfHandle); + + // display message (error or success) + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + + private void demoSoftwareKey_Click(object sender, EventArgs e) + { + IntPtr dapfHandle; + int err_code; + DEMO_SWKEY_INFO swkey_info = new DEMO_SWKEY_INFO(); + + // load DAPF from File into memory + dapfHandle = DinkeyAdd.LoadDAPFFromFile(dapfFile.Text, out err_code); + if (dapfHandle == IntPtr.Zero) + { + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + // fill out the SWKEY structure from the values the user entered + swkey_info.size = Marshal.SizeOf(typeof(DEMO_SWKEY_INFO)); + swkey_info.max_days = Convert.ToInt32(maxDaysText.Text, 10); + // !!!! in this case we just choose the default model (assuming you only selected one in the DAPF file). + // If you want to specify more than one model then OR the flags together. e.g. DinkeyAdd.SWKEY_BITMAP_PRO_LITE | DinkeyAdd.SWKEY_BITMAP_PRO_PLUS + swkey_info.models = DinkeyAdd.SWKEY_BITMAP_DEFAULT; + + // attempt to create the Temporary Software Key + err_code = DinkeyAdd.CreateDemoSoftwareKeyTemplate(dapfHandle, swkey_info, 0); + + // Unload DAPF from memory + DinkeyAdd.UnloadDAPF(ref dapfHandle); + + // display message (error or success) + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + + } +} diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyAdd/Form1.resx b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyAdd/Form1.resx new file mode 100644 index 0000000..19dc0dd --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyAdd/Form1.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyAdd/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyAdd/README.txt new file mode 100644 index 0000000..6f54b94 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyAdd/README.txt @@ -0,0 +1,50 @@ +dapfTest - sample code to call DinkeyAdd Module in C# +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 2002 but will work in more recent +versions of Visual Studio (they will upgrade the Project to the latest version. +If prompted you should also upgrade the .NET framework the project requires). + +For users of Visual Studio 2005 or higher, the default setting to projects is to +compile for the Target Platform "Any". This means that on 32-bit Windows, your +code will run as 32-bit code (and needs to call DinkeyAdd32.dll) and under 64-bit +Windows your code will run as 64-bit code (and needs to call DinkeyAdd64.dll). +The sample code works this out automatically. If you select the target platform as "x86" +then it will always be 32-bit and so you only need to use DinkeyAdd32.dll. If you +select "x64" then your code will be 64-bit and you only need to use DinkeyAdd64.dll. + +The main source files in the project are: + +dapf.cs - the source file contains declarations of our API. We automatically + work out whether your code is running in 32-bit or 64-bit and load + the appropriate DinkeyAdd module. + +Form1.cs - this is the sample code giving an example on how you can call our API. + It contains 5 functions. Just use which ever functions are most appropriate + and customise in your own way. + +The best approach is to compile the sample code and see how it works and then to take +the appropriate code and apply it to your own project. You should include the dapf.cs +file in your project and use/modify which ever functions from Form1.cs you feel are +appropriate. The dapf.cs file should not be modified. + +The sample code is just a guide. As none of the parameters are security sensitive then +there is no need to implement strong security in calling DinkeyAdd. + +Make sure you remember to do the following when creating your own project: + +1) Insert the following namespaces in your code file: +using System.Runtime.InteropServices; + +2) Insert the dapf.cs file in your project. + +3) You need to put DinkeyAdd32.dll and/or DinkeyAdd64.dll into the folder that +contains dapfTest. Otherwise the System.DllNotFoundException error will appear +when you run dapfTest. + +Notes on Debugging 64-bit Code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +When you use the 64-bit module (DinkeyAdd64.dll) the anti-debug code is so strong +that if you are debugging your code, after calling our API then it will crash with +an SEH exception. There are no debug modules for DinkeyAdd so you will have to find +other ways of debugging your code (for example taking out the call altogether). diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyAdd/dapf.cs b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyAdd/dapf.cs new file mode 100644 index 0000000..bc2f08a --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyAdd/dapf.cs @@ -0,0 +1,552 @@ +// !! this file should not be modified + +// DAPF file is in the following format: +// DINKEYINFO +// LICENCEINFO (however many are needed) +// FILEINFO (however many are needed) +// ALGORITHM (however many are needed) +// DATAFILEENC (however many are needed) + +using System; +using System.Runtime.InteropServices; // so we can marshal the structures as a block of memory +using System.Text; // for StringBuilder class for GetLastMessage API + +// *********** define structures that make up the DAPF file ******************* + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct DINKEYINFO +{ + public byte Header1; // should be set to "DAPF" + public byte Header2; + public byte Header3; + public byte Header4; + public int Version; // version of this structure. Currently 9. + public int SelectedModels; // BIT0 = Dinkey Pro Lite, BIT1 = Dinkey Pro Plus, BIT2 = Dinkey Pro Net etc... + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=12)] + public string ProdCode; + public int PerLicence; // 1 = per licence, 0 = per product (default) + public int MaxNetUsers; // product net users, unlimited = -1, no entry = -2 + public int RangeSettings; // 0 = any number, 1 = dongle in computer, 2 = range + public uint RangeMin; + public uint RangeMax; + public int NumLicences; // number of LICENCEINFO structures in this DAPF file + public int NumProgs; // number of FILEINFO structures in this DAPF file + public int NumAlgs; + public int DataSizeType; // 1 = set the zero data size, 0 = use file to initialise data area + public int ZeroDataSize; // size of the data area area in bytes + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string DataFile; // path to data file (0 = no data file) + public int DataAreaSize; // file size in bytes, -1 = file not found + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string ShellSuccessMsg; // Shell Method messages... + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string ShellNoDongleMsg; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string ShellExpiryDateMsg; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string ShellExpiryExecsMsg; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string ShellWarnDateMsg; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string ShellWarnExecsMsg; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string ShellNetUserLimitMsg; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string ShellOtherErrorMsg; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string ShellBackgroundMsg; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string NetNoServerMsg; + [MarshalAs(UnmanagedType.ByValArray, SizeConst=12)] + public byte[] rwalg; // coded form of rw algorithm (0 = no algorithm) + public int SecOptions; // BIT0: DRIS encryption, BIT1: Data encryption, BIT2: Data enc with alg, BIT3: only secure update codes + public byte SecDRISEncKey1; // DRIS encryption parameters + public byte SecDRISEncKey2; + public byte SecDRISEncKey3; + public byte Ignored1; // this byte is ignored + public byte SecDataEncKey1; // API Data encryption parameters + public byte SecDataEncKey2; + public byte SecDataEncKey3; + public byte Ignored2; // this byte is ignored + public int ProtectionType; // 0 = software + dongle, 1 = dongle only, 2 = program only + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=12)] + public string DataEncKeyProdCode; // Alternative Product Code used to generate internal encryption keys. Normally set to 0. + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string Notes; // user-defined notes + public int LockDongle; // 0 = don't lock (default), 1 = lock dongle to user's computer + public int Reserved1; // must be 0 + public int Reserved2; // must be 0 + public int AdvancedOptions; // BIT0 = do not allow usb-over-network for non-Net dongles, BIT1 = do not check for Software Key at Runtime. + public int NumDataFileEnc; // Number of data files in our encryption list +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct LICENCEINFO +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string LicenceName; + public int MaxDays; // -1 = no limit + public int ExpiryDay; // -1 = no limit, 0 = no change + public int ExpiryMonth; + public int ExpiryYear; + public int Execs; // -1 = no limit + public int ExecsWarn; // 0 = no warning (just for Shell method) + public int DaysWarn; // 0 = no warning (just for Shell method) + public uint Features; + public int LicenceNetUsers; // unlimited = -1 (-2 = not needed (this is for display only)) +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct FILEINFO +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string InputName; // input file (full path) + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string OutputName; // output file/folder + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string CallingProg; // calling program name + public int LicenceIndex; // index (of licence) in the LicenceInfo structure (1-based index. 0 = no selection) + public int Method; // 0-api, 1-shell, 2-shell & api + public int ShellFlags; // same bit flag values as in dris. i.e. 1 = DEC_ONE_EXEC, 4 = START_NET_USER + public int BackGround; // 0=no background, 1=1min, 2=5min, 3=10min, 4=30min, 5=60min + public int OtherShellOptions; // BIT0 = Shell Data Encryption is enabled, BIT1: Extra Anti-Debug is disabled, BIT2: Extra Anti-Piracy is disabled + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string EncFileList; // files (or file types) that the Shell-protected program will treat as encrypted (separated by ':') + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string ExceptList; // files (or file types) that are exceptions to the above list (separated by ':') + public int ExtraAntiPiracy; // 0 = off, 1=min, 10=max +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct ALGORITHM +{ + [MarshalAs(UnmanagedType.ByValArray, SizeConst=12)] + public byte[] alg; +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct DATAFILEENC +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string InputName; // file name, wild cards are allowed + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string OutputName; // file name (or folder name if input is a wildcard) +} + +// this structure is used for creating temporary software keys +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct TEMP_SWKEY_INFO +{ + public int size; // size of this structure (must be initialised) + public uint machineID; // machine ID in (hex) integer form + public int expiry_day; // expiry date of the Software Key + public int expiry_month; + public int expiry_year; + public int dongle_model; // model of the Software Key. See constant values below + public uint dongle_number; // dongle number of the Software Key. 0 = default (random) +} + +// this structure is used for creating demo software key templates +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct DEMO_SWKEY_INFO +{ + public int size; // size of this structure (must be initialised) + public int max_days; // max days demo swkey installation is valid (0-60) + public int models; // bitmap of valid dongle models. See constant values below. 0 = default (only use if only one model is selected in DINKEYINFO) +} + + +// ********************** API functions ************************ +// we declare classes for all the API functions for each bitness + +// Loads DAPF from disk and returns handle +class LoadDAPFFromFile32 +{ + [DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)] + public static extern IntPtr LoadDAPFFromFile(string dapf_file, out int err_code); +} + +class LoadDAPFFromFile64 +{ + [DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)] + public static extern IntPtr LoadDAPFFromFile(string dapf_file, out int err_code); +} + +// Loads DAPF from disk into structures supplied (so we can modify DAPF in memory) +class ReadDAPFEx32 +{ + [DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)] + public static extern int ReadDAPFEx(string dapf_file, out DINKEYINFO DinkeyInfo, byte[] licence_bytes, byte[] fileinfo_bytes, byte[] alg_bytes, byte[] datafile_bytes, out int dapf_version, out int dapf_format); +} + +class ReadDAPFEx64 +{ + [DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)] + public static extern int ReadDAPFEx(string dapf_file, out DINKEYINFO DinkeyInfo, byte[] licence_bytes, byte[] fileinfo_bytes, byte[] alg_bytes, byte[] datafile_bytes, out int dapf_version, out int dapf_format); +} + +// Loads DAPF from structures and returns a handle +class LoadDAPF32 +{ + [DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)] + public static extern IntPtr LoadDAPF(ref DINKEYINFO DinkeyInfo, byte[] licence_bytes, byte[] fileinfo_bytes, byte[] alg_bytes, byte[] datafile_bytes, out int ret_code); +} + +class LoadDAPF64 +{ + [DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)] + public static extern IntPtr LoadDAPF(ref DINKEYINFO DinkeyInfo, byte[] licence_bytes, byte[] fileinfo_bytes, byte[] alg_bytes, byte[] datafile_bytes, out int ret_code); +} + +// saves the DAPF file to disk +class WriteDAPFEx32 +{ + [DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)] + public static extern int WriteDAPFEx(IntPtr dapf_handle, string dapf_file, int dapf_format, int dapf_version, int flags); +} + +class WriteDAPFEx64 +{ + [DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)] + public static extern int WriteDAPFEx(IntPtr dapf_handle, string dapf_file, int dapf_format, int dapf_version, int flags); +} + +// unloads the DAPF file +class UnloadDAPF32 +{ + [DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)] + public static extern void UnloadDAPF(ref IntPtr dapf_handle); +} + +class UnloadDAPF64 +{ + [DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)] + public static extern void UnloadDAPF(ref IntPtr dapf_handle); +} + +class AddProtection32 +{ + [DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)] + public static extern int AddProtection(IntPtr dapf_handle, int action, int file_num, int flags, out uint dongle_number); +} + +class AddProtection64 +{ + [DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)] + public static extern int AddProtection(IntPtr dapf_handle, int action, int file_num, int flags, out uint dongle_number); +} + +class CreateTempSoftwareKey32 +{ + [DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)] + public static extern int CreateTempSoftwareKey(IntPtr dapf_handle, ref TEMP_SWKEY_INFO swkey_info, int flags); +} + +class CreateTempSoftwareKey64 +{ + [DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)] + public static extern int CreateTempSoftwareKey(IntPtr dapf_handle, ref TEMP_SWKEY_INFO swkey_info, int flags); +} + +class CreateDemoSoftwareKeyTemplate32 +{ + [DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)] + public static extern int CreateDemoSoftwareKeyTemplate(IntPtr dapf_handle, ref DEMO_SWKEY_INFO swkey_info, int flags); +} + +class CreateDemoSoftwareKeyTemplate64 +{ + [DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)] + public static extern int CreateDemoSoftwareKeyTemplate(IntPtr dapf_handle, ref DEMO_SWKEY_INFO swkey_info, int flags); +} + +class EncryptShellDataFiles32 +{ + [DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)] + public static extern int EncryptShellDataFiles(IntPtr dapf_handle, int file_num, int flags); +} + +class EncryptShellDataFiles64 +{ + [DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)] + public static extern int EncryptShellDataFiles(IntPtr dapf_handle, int file_num, int flags); +} + +class GetLastMessage32 +{ + [DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)] + public static extern void GetLastMessage(StringBuilder message, int buffer_size, out int message_length); +} + +class GetLastMessage64 +{ + [DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)] + public static extern void GetLastMessage(StringBuilder message, int buffer_size, out int message_length); +} + +class GetLastExtendedError32 +{ + [DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)] + public static extern int GetLastExtendedError(); +} + +class GetLastExtendedError64 +{ + [DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)] + public static extern int GetLastExtendedError(); +} + +// ********************* DinkeyAdd class ********************** +class DinkeyAdd +{ + // constants + public const int DAPF_VERSION = 9; // current DAPF version + + // WriteDAPFEx API flags + public const int FLAGS_LOSE_FEATURES = 1; // means that you can save the DAPF file to an earlier version even if it means losing some new features that have been currently set + + // AddProtection API action values + public const int ACTION_USE_DAPF_SETTINGS = 0; // means you just ignore the action value and use the default dapf settings + public const int ACTION_PROGRAM_DONGLE = 1; // program the dongle only + public const int ACTION_PROTECT_SOFTWARE = 2; // protect a software file (index indicated by separate parameter) + public const int ACTION_PROGRAM_AND_PROTECT = 3; // program the dongle and protect software + + // AddProtection API flags values + public const int FLAGS_OVERWRITE_OUTPUT = 1; // overwrite the output file if it already exists (default is to give an error) + + // SoftwareKey API flags + public const int FLAGS_OVERWRITE_SWKEY = 1; // overwrite an existing swkey with the new one + public const int FLAGS_EXPIRY_DONTCARE = 2; // create the Software Key even though the expiry date (or max days) is less than the expiry date of the key itself. + + // constants for dapf_format in ReadDAPFEx and WriteDAPFEx functions + public const int DAPF_FORMAT_BINARY = 1; + public const int DAPF_FORMAT_JSON = 2; + public const int DAPF_FORMAT_JSON_MIN = 3; // this value is only used with WriteDAPEx. ReadDAPFEx cannot return this value. + + // constants for values for model in the TEMP_SWKEY_INFO structure + public const int SWKEY_MODEL_PRO_LITE = 0; + public const int SWKEY_MODEL_PRO_PLUS = 1; + public const int SWKEY_MODEL_PRO_NET = 2; + public const int SWKEY_MODEL_FD_LITE = 3; + public const int SWKEY_MODEL_FD_PLUS = 4; + public const int SWKEY_MODEL_FD_NET = 5; + + // constants for models bitmap in the DEMO_SWKEY_INFO structure + public const int SWKEY_BITMAP_DEFAULT = 0; // use default value set in DINKEYINFO.SelectedModels + public const int SWKEY_BITMAP_PRO_LITE = 1; // BIT0 + public const int SWKEY_BITMAP_PRO_PLUS = 2; // BIT1 + public const int SWKEY_BITMAP_PRO_NET = 4; // BIT2 + public const int SWKEY_BITMAP_FD_LITE = 8; // BIT3 + public const int SWKEY_BITMAP_FD_PLUS = 16; // BIT4 + public const int SWKEY_BITMAP_FD_NET = 32; // BIT5 + + // private constants + private const int MAX_LICENCES = 255; // max number of licences in a DAPF file + private const int MAX_FILE_INFO = 1000; // theoretically unlimited but in practice it is easier if we limit it + private const int MAX_USER_ALGS = 20; // max number of user algs in DAPF file + private const int MAX_DATA_ENCS = 255; // max number of Shell data encryption files in DAPF file + + // **** main API + // We only want to load the correct DLL for the bit-ness of the computer. The other DLL may not exist. + // if the appropriate DLL does not exist in the same directory as this test program you will receive a DllNotFoundException + + public static IntPtr LoadDAPFFromFile(string dapf_file, out int err_code) + { + if (IntPtr.Size == 4) + return LoadDAPFFromFile32.LoadDAPFFromFile(dapf_file, out err_code); + return LoadDAPFFromFile64.LoadDAPFFromFile(dapf_file, out err_code); + } + + // we have to do some marshalling of arrays of bytes into arrays of structures + public static int ReadDAPFEx(string dapf_file, out DINKEYINFO DinkeyInfo, out LICENCEINFO[] LicenceInfo, out FILEINFO[] FileInfo, out ALGORITHM[] Algorithms, out DATAFILEENC[] DataFileEnc, out int dapf_version, out int dapf_format) + { + int ret_code, i; + byte[] licence_bytes = new byte[MAX_LICENCES * Marshal.SizeOf(typeof(LICENCEINFO))]; + byte[] licence_bytes_one_struct = new byte[Marshal.SizeOf(typeof(LICENCEINFO))]; + byte[] fileinfo_bytes = new byte[MAX_FILE_INFO * Marshal.SizeOf(typeof(FILEINFO))]; + byte[] fileinfo_bytes_one_struct = new byte[Marshal.SizeOf(typeof(FILEINFO))]; + byte[] alg_bytes = new byte[MAX_USER_ALGS * Marshal.SizeOf(typeof(ALGORITHM))]; + byte[] alg_bytes_one_struct = new byte[Marshal.SizeOf(typeof(ALGORITHM))]; + byte[] datafile_bytes = new byte[MAX_DATA_ENCS * Marshal.SizeOf(typeof(DATAFILEENC))]; + byte[] datafile_bytes_one_struct = new byte[Marshal.SizeOf(typeof(DATAFILEENC))]; + GCHandle MyGC; + DinkeyInfo = new DINKEYINFO(); + LicenceInfo = null; + FileInfo = null; + Algorithms = null; + DataFileEnc = null; + + if (IntPtr.Size == 4) + ret_code = ReadDAPFEx32.ReadDAPFEx(dapf_file, out DinkeyInfo, licence_bytes, fileinfo_bytes, alg_bytes, datafile_bytes, out dapf_version, out dapf_format); + else + ret_code = ReadDAPFEx64.ReadDAPFEx(dapf_file, out DinkeyInfo, licence_bytes, fileinfo_bytes, alg_bytes, datafile_bytes, out dapf_version, out dapf_format); + + if (ret_code != 0) + return ret_code; + + // convert byte array to an array of structs + LicenceInfo = new LICENCEINFO[DinkeyInfo.NumLicences]; + for (i=0; i + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyAdd/dapfTest.sln b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyAdd/dapfTest.sln new file mode 100644 index 0000000..12dca26 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyAdd/dapfTest.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dapfTest", "dapfTest.csproj", "{6535AF22-2AF4-4401-BFE2-889CD40C8F2F}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {6535AF22-2AF4-4401-BFE2-889CD40C8F2F}.Debug.ActiveCfg = Debug|.NET + {6535AF22-2AF4-4401-BFE2-889CD40C8F2F}.Debug.Build.0 = Debug|.NET + {6535AF22-2AF4-4401-BFE2-889CD40C8F2F}.Release.ActiveCfg = Release|.NET + {6535AF22-2AF4-4401-BFE2-889CD40C8F2F}.Release.Build.0 = Release|.NET + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyChange/App.ico b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyChange/App.ico new file mode 100644 index 0000000..3a5525f Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyChange/App.ico differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyChange/AssemblyInfo.cs b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyChange/AssemblyInfo.cs new file mode 100644 index 0000000..9f89a32 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyChange/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyChange/ChangeTest.csproj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyChange/ChangeTest.csproj new file mode 100644 index 0000000..bc40a2e --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyChange/ChangeTest.csproj @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyChange/ChangeTest.sln b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyChange/ChangeTest.sln new file mode 100644 index 0000000..c8c1896 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyChange/ChangeTest.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChangeTest", "ChangeTest.csproj", "{1B4F9D4B-2045-4A7D-9007-1FBDB9E30F2C}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {1B4F9D4B-2045-4A7D-9007-1FBDB9E30F2C}.Debug.ActiveCfg = Debug|.NET + {1B4F9D4B-2045-4A7D-9007-1FBDB9E30F2C}.Debug.Build.0 = Debug|.NET + {1B4F9D4B-2045-4A7D-9007-1FBDB9E30F2C}.Release.ActiveCfg = Release|.NET + {1B4F9D4B-2045-4A7D-9007-1FBDB9E30F2C}.Release.Build.0 = Release|.NET + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyChange/DinkeyChange.cs b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyChange/DinkeyChange.cs new file mode 100644 index 0000000..bb9bfbd --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyChange/DinkeyChange.cs @@ -0,0 +1,203 @@ +// !! this file should not be modified + +using System; +using System.Runtime.InteropServices; // so we can import DLL functions +using System.Text; // so we can extract prodcode from array + +// classes to load the correct 32-bit/64-bit DinkeyChange.dll functions - used by DinkeyChange class + +// loads DCGetInfo from the 32-bit DinkeyChange.dll +class DCGetInfo32 +{ + [DllImport("DinkeyChange.dll", CharSet = CharSet.Ansi)] + public static extern int DCGetInfo(int type_mask, int model_mask, string prodcode_mask, int array_length, out int num_found, int[] type, int[] model, byte[] prodcode, uint[] dongle_number, int[] update_number); +} + +// loads DCGetInfo from the 64-bit DinkeyChange64.dll +class DCGetInfo64 +{ + [DllImport("DinkeyChange64.dll", CharSet = CharSet.Ansi)] + public static extern int DCGetInfo(int type_mask, int model_mask, string prodcode_mask, int array_length, out int num_found, int[] type, int[] model, byte[] prodcode, uint[] dongle_number, int[] update_number); +} + +// loads DCGetDiagnosticInfo from the 32-bit DinkeyChange.dll +class DCGetDiagnosticInfo32 +{ + [DllImport("DinkeyChange.dll", CharSet = CharSet.Ansi)] + public static extern int DCGetDiagnosticInfo(string filename); +} + +// loads DCGetDiagnosticInfo from the 64-bit DinkeyChange64.dll +class DCGetDiagnosticInfo64 +{ + [DllImport("DinkeyChange64.dll", CharSet = CharSet.Ansi)] + public static extern int DCGetDiagnosticInfo(string filename); +} + +// loads DCDoUpdateCodeString from the 32-bit DinkeyChange.dll +class DCDoUpdateCodeString32 +{ + [DllImport("DinkeyChange.dll", CharSet = CharSet.Ansi)] + public static extern int DCDoUpdateCodeString(string update_code_string, out int confirmation_code, out int extended_error); +} + +// loads DCDoUpdateCodeString from the 64-bit DinkeyChange64.dll +class DCDoUpdateCodeString64 +{ + [DllImport("DinkeyChange64.dll", CharSet = CharSet.Ansi)] + public static extern int DCDoUpdateCodeString(string update_code_string, out int confirmation_code, out int extended_error); +} + +// loads DCDoUpdateCodeFromFile from the 32-bit DinkeyChange.dll +class DCDoUpdateCodeFromFile32 +{ + [DllImport("DinkeyChange.dll", CharSet = CharSet.Ansi)] + public static extern int DCDoUpdateCodeFromFile(string update_code_file, out int confirmation_code, out int extended_error); +} + +// loads DCDoUpdateCodeFromFile from the 64-bit DinkeyChange64.dll +class DCDoUpdateCodeFromFile64 +{ + [DllImport("DinkeyChange64.dll", CharSet = CharSet.Ansi)] + public static extern int DCDoUpdateCodeFromFile(string update_code_file, out int confirmation_code, out int extended_error); +} + +// loads DCRestoreDinkeyFDLite from the 32-bit DinkeyChange.dll +class DCRestoreDinkeyFDLite32 +{ + [DllImport("DinkeyChange.dll", CharSet = CharSet.Ansi)] + public static extern int DCRestoreDinkeyFDLite(); +} + +// loads DCRestoreDinkeyFDLite from the 64-bit DinkeyChange64.dll +class DCRestoreDinkeyFDLite64 +{ + [DllImport("DinkeyChange64.dll", CharSet = CharSet.Ansi)] + public static extern int DCRestoreDinkeyFDLite(); +} + +// loads DCGetMachineID from the 32-bit DinkeyChange.dll +class DCGetMachineID32 +{ + [DllImport("DinkeyChange.dll", CharSet = CharSet.Ansi)] + public static extern int DCGetMachineID(out uint machineID, out int extended_error); +} + +// loads DCGetMachineID from the 64-bit DinkeyChange64.dll +class DCGetMachineID64 +{ + [DllImport("DinkeyChange64.dll", CharSet = CharSet.Ansi)] + public static extern int DCGetMachineID(out uint machineID, out int extended_error); +} + +// loads DCDownloadTempSoftwareKey from the 32-bit DinkeyChange.dll +class DCDownloadTempSoftwareKey32 +{ + [DllImport("DinkeyChange.dll", CharSet = CharSet.Ansi)] + public static extern int DCDownloadTempSoftwareKey(uint machineID, out int extended_error); +} + +// loads DCDownloadTempSoftwareKey from the 64-bit DinkeyChange64.dll +class DCDownloadTempSoftwareKey64 +{ + [DllImport("DinkeyChange64.dll", CharSet = CharSet.Ansi)] + public static extern int DCDownloadTempSoftwareKey(uint machineID, out int extended_error); +} + +// loads DCDownloadDemoSoftwareKey from the 32-bit DinkeyChange.dll +class DCDownloadDemoSoftwareKey32 +{ + [DllImport("DinkeyChange.dll", CharSet = CharSet.Ansi)] + public static extern int DCDownloadDemoSoftwareKey(uint machineID, string prodcode, int model, out int extended_error); +} + +// loads DCDownloadDemoSoftwareKey from the 64-bit DinkeyChange64.dll +class DCDownloadDemoSoftwareKey64 +{ + [DllImport("DinkeyChange64.dll", CharSet = CharSet.Ansi)] + public static extern int DCDownloadDemoSoftwareKey(uint machineID, string prodcode, int model, out int extended_error); +} + +class DinkeyChange +{ + + // **** main API + // We only want to load the correct DLL for the bit-ness of the computer. The other DLL may not exist. + // if the appropriate DLL does not exist in the same directory as this test program you will receive a DllNotFoundException + + // detects whether running 32-bit code or 64-bit code and loads appropriate Dll. + public static int DCGetInfo(int type_mask, int model_mask, string prodcode_mask, int array_length, out int num_found, int[] type, int[] model, byte[] prodcode, uint[] dongle_number, int[] update_number) + { + if (IntPtr.Size == 4) + return DCGetInfo32.DCGetInfo(type_mask, model_mask, prodcode_mask, array_length, out num_found, type, model, prodcode, dongle_number, update_number); + return DCGetInfo64.DCGetInfo(type_mask, model_mask, prodcode_mask, array_length, out num_found, type, model, prodcode, dongle_number, update_number); + } + + public static int DCGetDiagnosticInfo(string filename) + { + if (IntPtr.Size == 4) + return DCGetDiagnosticInfo32.DCGetDiagnosticInfo(filename); + return DCGetDiagnosticInfo64.DCGetDiagnosticInfo(filename); + } + + public static int DCDoUpdateCodeString(string update_code_string, out int confirmation_code, out int extended_error) + { + if (IntPtr.Size == 4) + return DCDoUpdateCodeString32.DCDoUpdateCodeString(update_code_string, out confirmation_code, out extended_error); + return DCDoUpdateCodeString64.DCDoUpdateCodeString(update_code_string, out confirmation_code, out extended_error); + } + + public static int DCDoUpdateCodeFromFile(string update_code_string, out int confirmation_code, out int extended_error) + { + if (IntPtr.Size == 4) + return DCDoUpdateCodeFromFile32.DCDoUpdateCodeFromFile(update_code_string, out confirmation_code, out extended_error); + return DCDoUpdateCodeFromFile64.DCDoUpdateCodeFromFile(update_code_string, out confirmation_code, out extended_error); + } + + public static int DCRestoreDinkeyFDLite() + { + if (IntPtr.Size == 4) + return DCRestoreDinkeyFDLite32.DCRestoreDinkeyFDLite(); + return DCRestoreDinkeyFDLite64.DCRestoreDinkeyFDLite(); + } + + public static int DCGetMachineID(out uint machineID, out int extended_error) + { + if (IntPtr.Size == 4) + return DCGetMachineID32.DCGetMachineID(out machineID, out extended_error); + return DCGetMachineID64.DCGetMachineID(out machineID, out extended_error); + } + + public static int DCDownloadTempSoftwareKey(uint machineID, out int extended_error) + { + if (IntPtr.Size == 4) + return DCDownloadTempSoftwareKey32.DCDownloadTempSoftwareKey(machineID, out extended_error); + return DCDownloadTempSoftwareKey64.DCDownloadTempSoftwareKey(machineID, out extended_error); + } + + public static int DCDownloadDemoSoftwareKey(uint machineID, string prodcode, int model, out int extended_error) + { + if (IntPtr.Size == 4) + return DCDownloadDemoSoftwareKey32.DCDownloadDemoSoftwareKey(machineID, prodcode, model, out extended_error); + return DCDownloadDemoSoftwareKey64.DCDownloadDemoSoftwareKey(machineID, prodcode, model, out extended_error); + } + + // **** general purpose routines + + // routine to extract product code string from array of product codes + public static string GetProductCode(byte[] prodcode, int index) + { + int i; + StringBuilder sb = new StringBuilder(8); + + for (i=index*9; i<(index+1)*9; i++) + { + if (prodcode[i] == 0) + return sb.ToString(); + else + sb.Append((char)prodcode[i]); + } + return sb.ToString(); + } + +} diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyChange/Form1.cs b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyChange/Form1.cs new file mode 100644 index 0000000..4ff5c5c --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyChange/Form1.cs @@ -0,0 +1,581 @@ +// !! We strongly recommend that you read the "readme.txt" file in the sample code folder. +// !! It contains important instructions on how to use the sample code + +using System; +using System.Drawing; +using System.Collections; +using System.ComponentModel; +using System.Windows.Forms; +using System.Data; + +namespace ChangeTest +{ + + /// + /// Summary description for Form1. + /// + public class Form1 : System.Windows.Forms.Form + { + private System.Windows.Forms.Button get_dongle_info; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox diag_filename; + private System.Windows.Forms.Button write_diag_file; + private System.Windows.Forms.Button do_update_code_string; + private System.Windows.Forms.TextBox update_code_string; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Button do_update_code_file; + private System.Windows.Forms.TextBox update_code_file; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Button restore_fd_lite; + private System.Windows.Forms.Button get_machine_id; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.TextBox swkey_prod_code; + private System.Windows.Forms.Button download_temp_swkey; + private System.Windows.Forms.Button download_demo_swkey; + private System.Windows.Forms.TextBox machine_id; + /// + /// Required designer variable. + /// + private System.ComponentModel.Container components = null; + + public Form1() + { + // + // Required for Windows Form Designer support + // + InitializeComponent(); + + // + // TODO: Add any constructor code after InitializeComponent call + // + } + + /// + /// Clean up any resources being used. + /// + protected override void Dispose( bool disposing ) + { + if( disposing ) + { + if (components != null) + { + components.Dispose(); + } + } + base.Dispose( disposing ); + } + + // maximum number of USB devices that can be attached to a machine at any time + public const int MAX_USB_DEVICES = 128; + public const int MAX_PRODCODE_LEN = 9; // including terminating null + + public string AppName = "ChangeTest"; + + // mask values + public const int TYPE_MASK_PRO = 1; + public const int TYPE_MASK_FD = 2; + public const int TYPE_MASK_ALL = (TYPE_MASK_PRO | TYPE_MASK_FD); + + public const int MODEL_MASK_LITE = 1; + public const int MODEL_MASK_PLUS = 2; + public const int MODEL_MASK_NET = 4; + public const int MODEL_MASK_ALL = (MODEL_MASK_LITE | MODEL_MASK_PLUS | MODEL_MASK_NET); + public const int MODEL_MASK_DEFAULT = (MODEL_MASK_PLUS | MODEL_MASK_NET); + + // type values for DCGetInfo (returned in the array) + public const int TYPE_PRO = 1; + public const int TYPE_FD = 2; + + // model values for DCGetInfo (returned in the array) + public const int MODEL_LITE = 1; + public const int MODEL_PLUS = 2; + public const int MODEL_NET5 = 4; + public const int MODEL_NETU = 7; + + // model values for DCDownloadDemoSoftwareKey + public const int SWKEY_MODEL_DEFAULT = -1; // NB this assumes that the Demo Software Key Template was created with only one valid dongle model + public const int SWKEY_MODEL_PRO_LITE = 0; + public const int SWKEY_MODEL_PRO_PLUS = 1; + public const int SWKEY_MODEL_PRO_NET = 2; + public const int SWKEY_MODEL_FD_LITE = 3; + public const int SWKEY_MODEL_FD_PLUS = 4; + public const int SWKEY_MODEL_FD_NET = 5; + + private void InitializeComponent() + { + this.get_dongle_info = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.diag_filename = new System.Windows.Forms.TextBox(); + this.write_diag_file = new System.Windows.Forms.Button(); + this.do_update_code_string = new System.Windows.Forms.Button(); + this.update_code_string = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.do_update_code_file = new System.Windows.Forms.Button(); + this.update_code_file = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.restore_fd_lite = new System.Windows.Forms.Button(); + this.get_machine_id = new System.Windows.Forms.Button(); + this.machine_id = new System.Windows.Forms.TextBox(); + this.download_temp_swkey = new System.Windows.Forms.Button(); + this.label4 = new System.Windows.Forms.Label(); + this.swkey_prod_code = new System.Windows.Forms.TextBox(); + this.download_demo_swkey = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // get_dongle_info + // + this.get_dongle_info.Location = new System.Drawing.Point(48, 24); + this.get_dongle_info.Name = "get_dongle_info"; + this.get_dongle_info.Size = new System.Drawing.Size(224, 24); + this.get_dongle_info.TabIndex = 0; + this.get_dongle_info.Text = "Get Dongle Information"; + this.get_dongle_info.Click += new System.EventHandler(this.get_dongle_info_Click); + // + // label1 + // + this.label1.Location = new System.Drawing.Point(16, 72); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(280, 16); + this.label1.TabIndex = 1; + this.label1.Text = "Enter diagnostic filename:"; + // + // diag_filename + // + this.diag_filename.Location = new System.Drawing.Point(16, 88); + this.diag_filename.Name = "diag_filename"; + this.diag_filename.Size = new System.Drawing.Size(288, 20); + this.diag_filename.TabIndex = 2; + this.diag_filename.Text = ""; + // + // write_diag_file + // + this.write_diag_file.Location = new System.Drawing.Point(48, 120); + this.write_diag_file.Name = "write_diag_file"; + this.write_diag_file.Size = new System.Drawing.Size(224, 24); + this.write_diag_file.TabIndex = 3; + this.write_diag_file.Text = "Write Diagnostics to File"; + this.write_diag_file.Click += new System.EventHandler(this.write_diag_file_Click); + // + // label2 + // + this.label2.Location = new System.Drawing.Point(16, 168); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(280, 16); + this.label2.TabIndex = 4; + this.label2.Text = "Enter short Update Code here:"; + // + // update_code_string + // + this.update_code_string.Location = new System.Drawing.Point(16, 184); + this.update_code_string.Name = "update_code_string"; + this.update_code_string.Size = new System.Drawing.Size(288, 20); + this.update_code_string.TabIndex = 5; + this.update_code_string.Text = ""; + // + // do_update_code_string + // + this.do_update_code_string.Location = new System.Drawing.Point(48, 216); + this.do_update_code_string.Name = "do_update_code_string"; + this.do_update_code_string.Size = new System.Drawing.Size(224, 24); + this.do_update_code_string.TabIndex = 6; + this.do_update_code_string.Text = "Make Changes"; + this.do_update_code_string.Click += new System.EventHandler(this.do_update_code_string_Click); + // + // do_update_code_file + // + this.do_update_code_file.Location = new System.Drawing.Point(48, 312); + this.do_update_code_file.Name = "do_update_code_file"; + this.do_update_code_file.Size = new System.Drawing.Size(224, 24); + this.do_update_code_file.TabIndex = 9; + this.do_update_code_file.Text = "Make Changes"; + this.do_update_code_file.Click += new System.EventHandler(this.do_update_code_file_Click); + // + // update_code_file + // + this.update_code_file.Location = new System.Drawing.Point(16, 280); + this.update_code_file.Name = "update_code_file"; + this.update_code_file.Size = new System.Drawing.Size(288, 20); + this.update_code_file.TabIndex = 8; + this.update_code_file.Text = ""; + // + // label3 + // + this.label3.Location = new System.Drawing.Point(16, 264); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(280, 16); + this.label3.TabIndex = 7; + this.label3.Text = "Enter path to Update Code file:"; + // + // restore_fd_lite + // + this.restore_fd_lite.Location = new System.Drawing.Point(48, 368); + this.restore_fd_lite.Name = "restore_fd_lite"; + this.restore_fd_lite.Size = new System.Drawing.Size(224, 24); + this.restore_fd_lite.TabIndex = 10; + this.restore_fd_lite.Text = "Restore Dinkey FD Lite"; + this.restore_fd_lite.Click += new System.EventHandler(this.restore_fd_lite_Click); + // + // get_machine_id + // + this.get_machine_id.Location = new System.Drawing.Point(16, 424); + this.get_machine_id.Name = "get_machine_id"; + this.get_machine_id.Size = new System.Drawing.Size(144, 24); + this.get_machine_id.TabIndex = 11; + this.get_machine_id.Text = "Get Machine ID"; + this.get_machine_id.Click += new System.EventHandler(this.get_machine_id_Click); + // + // machine_id + // + this.machine_id.Location = new System.Drawing.Point(168, 424); + this.machine_id.Name = "machine_id"; + this.machine_id.Size = new System.Drawing.Size(136, 20); + this.machine_id.TabIndex = 12; + this.machine_id.Text = ""; + // + // download_temp_swkey + // + this.download_temp_swkey.Location = new System.Drawing.Point(48, 480); + this.download_temp_swkey.Name = "download_temp_swkey"; + this.download_temp_swkey.Size = new System.Drawing.Size(224, 24); + this.download_temp_swkey.TabIndex = 13; + this.download_temp_swkey.Text = "Download Temporary Software Key"; + this.download_temp_swkey.Click += new System.EventHandler(this.download_temp_swkey_Click); + // + // label4 + // + this.label4.Location = new System.Drawing.Point(16, 528); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(280, 16); + this.label4.TabIndex = 14; + this.label4.Text = "Demo Software Key Product Code:"; + // + // swkey_prod_code + // + this.swkey_prod_code.Location = new System.Drawing.Point(16, 544); + this.swkey_prod_code.Name = "swkey_prod_code"; + this.swkey_prod_code.Size = new System.Drawing.Size(288, 20); + this.swkey_prod_code.TabIndex = 15; + this.swkey_prod_code.Text = ""; + // + // download_demo_swkey + // + this.download_demo_swkey.Location = new System.Drawing.Point(48, 576); + this.download_demo_swkey.Name = "download_demo_swkey"; + this.download_demo_swkey.Size = new System.Drawing.Size(224, 24); + this.download_demo_swkey.TabIndex = 16; + this.download_demo_swkey.Text = "Download Demo Software Key"; + this.download_demo_swkey.Click += new System.EventHandler(this.download_demo_swkey_Click); + // + // Form1 + // + this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); + this.ClientSize = new System.Drawing.Size(320, 624); + this.Controls.Add(this.download_demo_swkey); + this.Controls.Add(this.swkey_prod_code); + this.Controls.Add(this.label4); + this.Controls.Add(this.machine_id); + this.Controls.Add(this.download_temp_swkey); + this.Controls.Add(this.get_machine_id); + this.Controls.Add(this.restore_fd_lite); + this.Controls.Add(this.do_update_code_file); + this.Controls.Add(this.update_code_file); + this.Controls.Add(this.label3); + this.Controls.Add(this.do_update_code_string); + this.Controls.Add(this.update_code_string); + this.Controls.Add(this.label2); + this.Controls.Add(this.write_diag_file); + this.Controls.Add(this.diag_filename); + this.Controls.Add(this.label1); + this.Controls.Add(this.get_dongle_info); + this.Name = "Form1"; + this.Text = "ChangeTest"; + this.ResumeLayout(false); + + } + + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.Run(new Form1()); + } + + // routine to get & display information for all dongles attached + private void get_dongle_info_Click(object sender, System.EventArgs e) + { + int ret_code, i, num_found; + string DisplayString = null; + string Type, Model, ProdCodeString; + // return arrays of dongle details filedin by DCGetInfo + int[] type = new int[MAX_USB_DEVICES]; + int[] model = new int[MAX_USB_DEVICES]; + byte[] prodcode = new Byte[MAX_USB_DEVICES*MAX_PRODCODE_LEN]; + uint[] dongle_number = new uint[MAX_USB_DEVICES]; + int[] update_number = new int[MAX_USB_DEVICES]; + + // find dongle information for all dongle types, Plus & Net models, for all product codes + // NB In practice you will probably want to set the prodcode_mask to the value of your product code + ret_code = DinkeyChange.DCGetInfo(TYPE_MASK_ALL, MODEL_MASK_DEFAULT, null, MAX_USB_DEVICES, out num_found, type, model, prodcode, dongle_number, update_number); + + // check error code and display error if an error occurs + if (ret_code == 401) + { + MessageBox.Show("No dongles detected matching the search criteria specified", AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + else if (ret_code != 0) + { + DisplayString = "An error occurred getting dongle information. Error: " + String.Format("{0:D}", ret_code); + MessageBox.Show(DisplayString, AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + // display info for dongle(s) detected + for (i=0; i + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Form1 + + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyChange/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyChange/README.txt new file mode 100644 index 0000000..df7e9b5 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyChange/README.txt @@ -0,0 +1,64 @@ +ChangeTest - sample code to call DinkeyChange Module in C# +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 2003 but will work in more recent versions of +Visual Studio (they will upgrade the Project to the latest version. If prompted you +should also upgrade the .NET framework the project requires). + +For users of Visual Studio 2005 or higher, the default setting to projects is to compile +for the Target Platform "Any". This means that on 32-bit Windows, your code will run as +32-bit code (and needs to call DinkeyChange.dll) and under 64-bit Windows your code will +run as 64-bit code (and needs to call DinkeyChange64.dll). The sample code works this out +automatically. If you select the target platform as "x86" then it will always be 32-bit +and so you only need to use DinkeyChange.dll. If you select "x64" then your code will be +64-bit and you only need to use DinkeyChange64.dll. + +The main source files in the project are: + +DinkeyChange.cs - the source file contains declarations of our API. We automatically + work out whether your code is running in 32-bit or 64-bit and load the + appropriate DinkeyChange module. + +Form1.cs - this is the sample code giving an example on how you can call our API. + It contains 7 functions. Just use which ever functions are most appropriate + and customise in your own way. + +The best approach is to compile the sample code and see how it works and then to take the +appropriate code and apply it to your own project. You should include the DinkeyChange.cs +file in your project and use/modify which ever functions from Form1.cs you feel are +appropriate. The DinkeyChange.cs file should not be modified. + +The sample code is just a guide. As none of the parameters are security sensitive then +there is no need to implement strong security in calling DinkeyChange. + +Make sure you remember to do the following when creating your own project: + +1) Insert the DinkeyChange.cs file in your project. + +2) You need to put DinkeyChange.dll and/or DinkeyChange64.dll into the folder that +contains your EXE file. Otherwise the System.DllNotFoundException error will appear +when you run ChangeTest. + +You can rename DinkeyChange.dll (DinkeyChange64.dll) to a name of your choice. In this +case you will need to modify the dll names specified in the DinkeyChange.cs file. + +Notes on Debugging 64-bit Code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +When you use the 64-bit module (DinkeyChange64.dll) the anti-debug code is so strong that +if you are debugging your code, after calling our API then it will crash with an SEH +exception. If you want to be able to debug your code then you can setup your project so +that your code calls the debug module (DinkeyChange64Debug.dll) in your "debug" build and +the standard module (DinkeyChange64.dll) in your release build. In this case you will +need to modify the declarations of our API in DinkeyChange.cs. This is an example for +DCDoUpdateCodeFromFile64: + +class DCDoUpdateCodeFromFile64 +{ +#if DEBUG ' debug module + [DllImport("DinkeyChange64Debug.dll", CharSet = CharSet.Ansi)] + public static extern int DCDoUpdateCodeFromFile(string update_code_file, out int confirmation_code, out int extended_error); +#else ' standard module + [DllImport("DinkeyChange64.dll", CharSet = CharSet.Ansi)] + public static extern int DCDoUpdateCodeFromFile(string update_code_file, out int confirmation_code, out int extended_error); +#endif +} diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyRemote/App.ico b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyRemote/App.ico new file mode 100644 index 0000000..3a5525f Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyRemote/App.ico differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyRemote/AssemblyInfo.cs b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyRemote/AssemblyInfo.cs new file mode 100644 index 0000000..9f89a32 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyRemote/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyRemote/Form1.cs b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyRemote/Form1.cs new file mode 100644 index 0000000..6da931c --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyRemote/Form1.cs @@ -0,0 +1,214 @@ +// !! We strongly recommend that you read the "readme.txt" file in the sample code folder. +// !! It contains important instructions on how to use the sample code + +using System; +using System.Drawing; +using System.Collections; +using System.ComponentModel; +using System.Windows.Forms; +using System.Data; +using System.IO; // for file I/O +using System.Runtime.InteropServices; // so we can marshal our structures in drpf.cs + +namespace drpfTest +{ + /// + /// Summary description for Form1. + /// + public class Form1 : System.Windows.Forms.Form + { + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox drpfFile; + private System.Windows.Forms.Button updatecode; + private System.Windows.Forms.Button updatecodeMod; + /// + /// Required designer variable. + /// + private System.ComponentModel.Container components = null; + + public string AppName = "drpfTest"; + + public Form1() + { + // + // Required for Windows Form Designer support + // + InitializeComponent(); + + // + // TODO: Add any constructor code after InitializeComponent call + // + } + + /// + /// Clean up any resources being used. + /// + protected override void Dispose( bool disposing ) + { + if( disposing ) + { + if (components != null) + { + components.Dispose(); + } + } + base.Dispose( disposing ); + } + + #region Windows Form Designer generated code + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.drpfFile = new System.Windows.Forms.TextBox(); + this.updatecode = new System.Windows.Forms.Button(); + this.updatecodeMod = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.Location = new System.Drawing.Point(16, 24); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(440, 16); + this.label1.TabIndex = 0; + this.label1.Text = "Full path of drpf file:"; + // + // drpfFile + // + this.drpfFile.Location = new System.Drawing.Point(16, 40); + this.drpfFile.Name = "drpfFile"; + this.drpfFile.Size = new System.Drawing.Size(424, 20); + this.drpfFile.TabIndex = 1; + this.drpfFile.Text = ""; + // + // updatecode + // + this.updatecode.Location = new System.Drawing.Point(96, 88); + this.updatecode.Name = "updatecode"; + this.updatecode.Size = new System.Drawing.Size(264, 23); + this.updatecode.TabIndex = 2; + this.updatecode.Text = "Generate Update Code"; + this.updatecode.Click += new System.EventHandler(this.updatecode_Click); + // + // updatecodeMod + // + this.updatecodeMod.Location = new System.Drawing.Point(96, 128); + this.updatecodeMod.Name = "updatecodeMod"; + this.updatecodeMod.Size = new System.Drawing.Size(264, 23); + this.updatecodeMod.TabIndex = 3; + this.updatecodeMod.Text = "Generate Update Code with modifications "; + this.updatecodeMod.Click += new System.EventHandler(this.updatecodeMod_Click); + // + // Form1 + // + this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); + this.ClientSize = new System.Drawing.Size(456, 174); + this.Controls.Add(this.updatecodeMod); + this.Controls.Add(this.updatecode); + this.Controls.Add(this.drpfFile); + this.Controls.Add(this.label1); + this.Name = "Form1"; + this.Text = "Form1"; + this.ResumeLayout(false); + + } + #endregion + + /* The sample code contains 2 functions. Use which ever functions are most appropriate and customise + in your own way. The sample code is just a guide. + + There are two methods to loading a DRPF file. These are shown in the these two functions + updatecode_Click and updatecodeMod_Click: + + updatecode_Click: we load the DRPF file from disk and get a handle and use it "as is" using the API + call LoadDRPFFromFile. You can make some limited changes to overwrite the default + behaviour by using API flags. + + updatecodeMod_Click: we load the DRPF file from disk and load into structures. We can then modify the + DRPF settings by modifying this structure. This method uses the API calls + ReadDRPFEx and LoadDRPF. + + */ + + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.Run(new Form1()); + } + + private void updatecode_Click(object sender, System.EventArgs e) + { + IntPtr drpfHandle; + int err_code; + UPDATE_CODE_OUTPUTS Outputs = new UPDATE_CODE_OUTPUTS(); + + // load DRPF from File into memory + drpfHandle = DinkeyRemote.LoadDRPFFromFile(drpfFile.Text, out err_code); + if (drpfHandle == IntPtr.Zero) + { + MessageBox.Show(DinkeyRemote.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + // generate update code as specified by the DRPF file + err_code = DinkeyRemote.GenerateUpdateCode(drpfHandle, 0, 0, null, null, out Outputs); + + // Unload DRPF from memory + DinkeyRemote.UnloadDRPF(ref drpfHandle); + + // display message (error or success) + MessageBox.Show(DinkeyRemote.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Information); + + } + + private void updatecodeMod_Click(object sender, System.EventArgs e) + { + IntPtr drpfHandle; + int dummy1, dummy2, err_code; + REMOTEINFO RemoteInfo; + LICENCEINFO[] LicenceInfo; + ALGCHANGE[] AlgChanges; + DATACHANGE[] DataChanges; + UPDATE_CODE_OUTPUTS Outputs = new UPDATE_CODE_OUTPUTS(); + + // in this case we need to read the DRPF into our structures, so that the DRPF values can be modified + err_code = DinkeyRemote.ReadDRPFEx(drpfFile.Text, out RemoteInfo, out LicenceInfo, out AlgChanges, out DataChanges, out dummy1, out dummy2); + if (err_code != 0) + { + MessageBox.Show(DinkeyRemote.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + // patch new values in the RemoteInfo, LicenceInfo, AlgChanges, DataChanges structures + LicenceInfo[0].FeaturesFlag = 1; // so that the features value below will be recognised + LicenceInfo[0].Features = 12345; + LicenceInfo[0].AddSetExecs = 1; // so the executions will be added to existing + LicenceInfo[0].Execs = 100; + + // get DRPF handle + drpfHandle = DinkeyRemote.LoadDRPF(RemoteInfo, LicenceInfo, AlgChanges, DataChanges, out err_code); + if (drpfHandle == IntPtr.Zero) + { + MessageBox.Show(DinkeyRemote.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + // generate update code as specified by the modified DRPF file + err_code = DinkeyRemote.GenerateUpdateCode(drpfHandle, 0, 0, null, null, out Outputs); + + // Unload DRPF from memory + DinkeyRemote.UnloadDRPF(ref drpfHandle); + + // display message (error or success) + MessageBox.Show(DinkeyRemote.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + + } +} diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyRemote/Form1.resx b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyRemote/Form1.resx new file mode 100644 index 0000000..ec14cef --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyRemote/Form1.resx @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + False + + + Private + + + Private + + + Private + + + False + + + Private + + + False + + + Private + + + Private + + + False + + + Private + + + Private + + + False + + + Form1 + + + (Default) + + + False + + + False + + + 8, 8 + + + True + + + 80 + + + True + + + Private + + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyRemote/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyRemote/README.txt new file mode 100644 index 0000000..122c464 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyRemote/README.txt @@ -0,0 +1,50 @@ +drpfTest - sample code to call DinkeyRemote Module in C# +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 2002 but will work in more recent +versions of Visual Studio (they will upgrade the Project to the latest version. +If prompted you should also upgrade the .NET framework the project requires). + +For users of Visual Studio 2005 or higher, the default setting to projects is to +compile for the Target Platform "Any". This means that on 32-bit Windows, your +code will run as 32-bit code (and needs to call DinkeyRemote32.dll) and under 64-bit +Windows your code will run as 64-bit code (and needs to call DinkeyRemote64.dll). +The sample code works this out automatically. If you select the target platform as "x86" +then it will always be 32-bit and so you only need to use DinkeyRemote32.dll. If you +select "x64" then your code will be 64-bit and you only need to use DinkeyRemote64.dll. + +The main source files in the project are: + +drpf.cs - the source file contains declarations of our API. We automatically + work out whether your code is running in 32-bit or 64-bit and load + the appropriate DinkeyRemote module. + +Form1.cs - this is the sample code giving an example on how you can call our API. + It contains 2 functions. Just use the function most appropriate for you + and customise in your own way. + +The best approach is to compile the sample code and see how it works and then to take +the appropriate code and apply it to your own project. You should include the drpf.cs +file in your project and use/modify which ever functions from Form1.cs you feel are +appropriate. The drpf.cs file should not be modified. + +The sample code is just a guide. As none of the parameters are security sensitive then +there is no need to implement strong security in calling DinkeyRemote. + +Make sure you remember to do the following when creating your own project: + +1) Insert the following namespaces in your code file: +using System.Runtime.InteropServices; + +2) Insert the drpf.cs file in your project. + +3) You need to put DinkeyRemote32.dll and/or DinkeyRemote64.dll into the folder that +contains drpfTest. Otherwise the System.DllNotFoundException error will appear +when you run drpfTest. + +Notes on Debugging 64-bit Code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +When you use the 64-bit module (DinkeyRemote64.dll) the anti-debug code is so strong +that if you are debugging your code, after calling our API then it will crash with +an SEH exception. There are no debug modules for DinkeyRemote so you will have to +find other ways of debugging your code (for example taking out the call altogether). diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyRemote/drpf.cs b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyRemote/drpf.cs new file mode 100644 index 0000000..b71c877 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyRemote/drpf.cs @@ -0,0 +1,385 @@ +// !! this file should not be modified + +// DRPF file is in the following format: +// REMOTEINFO +// LICENCEINFO (however many are needed) +// ALGCHANGE (however many are needed) +// DATACHANGE (however many are needed) - may refer to external files. + +// Remember: you only need to specify a value if you want to change it. Otherwise you +// specify the default "no change" setting. For most entries this is indicated by 0. +// However, for MaxNetUsers and LicenceNetUsers it is "-2" because 0 is a valid value to change to. + +using System; +using System.Runtime.InteropServices; // so we can marshal the structures as a block of memory +using System.Text; // for StringBuilder class for GetLastMessage API + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct REMOTEINFO +{ + public byte Header1; // Should be set to "DRPF" = DinkeyRemote Parameter File + public byte Header2; + public byte Header3; + public byte Header4; + public int Version; // version of this structure - currently 2 + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=12)] + public string ProdCode; // Product Code + public uint DongleNumber; + public int UpdateNumber; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string Notes; // user-defined notes + public int NumLicences; + public int NumAlgs; // number of algs to set (incl r/w alg) + public int NumDataChanges; // number of data change blocks specified + public int DataAreaSize; // -1 = increase as necessary. specifies the new size of the data area + public int PerLicence; // 0 = no change, 1 = per licence net users, 2 = per product net users + public int MaxNetUsers; // product net users, unlimited = -1, no change = -2 + public int LastUsedDay; // Day = 0 (only) -> no change + public int LastUsedMonth; + public int LastUsedYear; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=12)] + public string DataEncKeyProdCode; + public int ChangeCodeType; // 0 = no change, bit0 = only accept secure codes, bit1 = accept secure & short codes + public int CodeType; // type of code to generate. 0 = secure code, 1 = short code + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string OutputFileName; // name of file to output code to. Null (default) -> UpdateCode.ducf + public int LockDongle; // 1 = lock dongle to user's computer + public int ResetDongleLock; // 1 = reset the dongle lock so that the dongle can be locked to a new machine +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct LICENCEINFO +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string LicenceName; // name of the licence + public int Action; // 0 = change, 1 = delete, 2 = add + public int AddSetExecs; // 0 = no change to execs, 1 = add, 2 = set + public int Execs; // -1 = no limit + public int ExecsWarn; // 0 = remove warning, -1 = no change + public int ExpiryDay; // -1 = no limit, 0 = no change + public int ExpiryMonth; + public int ExpiryYear; + public int AddSetMaxDays; // 0 = no change, 1 = add, 2 = set + public int MaxDays; // -1 = no limit + public int DaysWarn; // 0 = remove warning, -1 = no change + public int FeaturesFlag; // 0 = don't change features, 1 = change features + public uint Features; // all values OK + public int LicenceNetUsers; // unlimited = -1, no change = -2 +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct ALGCHANGE +{ + public int alg_number; // number of algorithm to set (0 = r/w algorithm) + [MarshalAs(UnmanagedType.ByValArray, SizeConst=12)] + public byte[] alg; // algorithm +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct DATACHANGE +{ + public int type; // 1 = file, 2 = hex data, 3 = ascii, 4 = ascii null-term string + public int offset; // offset in dongle data memory to write data + public int length; // length of data to change + [MarshalAs(UnmanagedType.ByValArray, SizeConst=256)] + public byte[] data; // data to write OR name of data file depending on which method set +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct UPDATE_CODE_OUTPUTS +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128*3)] + public string ShortCode; // the update code (for short update codes only) + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string UpdateCodeFile; // the output ducf that contains the update code + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=8)] + public string ConfirmationCode; // the confirmation code +} + + + +// ********************** API functions ************************ +// we declare classes for all the API functions for each bitness + +// Loads DRPF from disk and returns handle +class LoadDRPFFromFile32 +{ + [DllImport("DinkeyRemote32.dll", CharSet = CharSet.Ansi)] + public static extern IntPtr LoadDRPFFromFile(string drpf_file, out int err_code); +} + +class LoadDRPFFromFile64 +{ + [DllImport("DinkeyRemote64.dll", CharSet = CharSet.Ansi)] + public static extern IntPtr LoadDRPFFromFile(string drpf_file, out int err_code); +} + +// Loads DRPF from disk into structures supplied (so we can modify DRPF in memory) +class ReadDRPFEx32 +{ + [DllImport("DinkeyRemote32.dll", CharSet = CharSet.Ansi)] + public static extern int ReadDRPFEx(string drpf_file, out REMOTEINFO RemoteInfo, byte[] licence_bytes, byte[] algchange_bytes, byte[] datachange_bytes, out int drpf_version, out int drpf_format); +} + +class ReadDRPFEx64 +{ + [DllImport("DinkeyRemote64.dll", CharSet = CharSet.Ansi)] + public static extern int ReadDRPFEx(string drpf_file, out REMOTEINFO RemoteInfo, byte[] licence_bytes, byte[] algchange_bytes, byte[] datachange_bytes, out int drpf_version, out int drpf_format); +} + +// Loads DRPF from structures and returns a handle +class LoadDRPF32 +{ + [DllImport("DinkeyRemote32.dll", CharSet = CharSet.Ansi)] + public static extern IntPtr LoadDRPF(ref REMOTEINFO RemoteInfo, byte[] licence_bytes, byte[] algchange_bytes, byte[] datachange_bytes, out int ret_code); +} + +class LoadDRPF64 +{ + [DllImport("DinkeyRemote64.dll", CharSet = CharSet.Ansi)] + public static extern IntPtr LoadDRPF(ref REMOTEINFO RemoteInfo, byte[] licence_bytes, byte[] algchange_bytes, byte[] datachange_bytes, out int ret_code); +} + +// saves the DRPF file to disk +class WriteDRPFEx32 +{ + [DllImport("DinkeyRemote32.dll", CharSet = CharSet.Ansi)] + public static extern int WriteDRPFEx(IntPtr drpf_handle, string drpf_file, int drpf_format, int drpf_version, int flags); +} + +class WriteDRPFEx64 +{ + [DllImport("DinkeyRemote64.dll", CharSet = CharSet.Ansi)] + public static extern int WriteDRPFEx(IntPtr drpf_handle, string drpf_file, int drpf_format, int drpf_version, int flags); +} + +// unloads the DRPF file +class UnloadDRPF32 +{ + [DllImport("DinkeyRemote32.dll", CharSet = CharSet.Ansi)] + public static extern void UnloadDRPF(ref IntPtr drpf_handle); +} + +class UnloadDRPF64 +{ + [DllImport("DinkeyRemote64.dll", CharSet = CharSet.Ansi)] + public static extern void UnloadDRPF(ref IntPtr drpf_handle); +} + +class GenerateUpdateCode32 +{ + [DllImport("DinkeyRemote32.dll", CharSet = CharSet.Ansi)] + public static extern int GenerateUpdateCode(IntPtr drpf_handle, uint dongle_number, int update_number, string ducf_file, string logfile, out UPDATE_CODE_OUTPUTS Outputs); +} + +class GenerateUpdateCode64 +{ + [DllImport("DinkeyRemote64.dll", CharSet = CharSet.Ansi)] + public static extern int GenerateUpdateCode(IntPtr drpf_handle, uint dongle_number, int update_number, string ducf_file, string logfile, out UPDATE_CODE_OUTPUTS Outputs); +} + +class GetLastMessage32 +{ + [DllImport("DinkeyRemote32.dll", CharSet = CharSet.Ansi)] + public static extern void GetLastMessage(StringBuilder message, int buffer_size, out int message_length); +} + +class GetLastMessage64 +{ + [DllImport("DinkeyRemote64.dll", CharSet = CharSet.Ansi)] + public static extern void GetLastMessage(StringBuilder message, int buffer_size, out int message_length); +} + +class GetLastExtendedError32 +{ + [DllImport("DinkeyRemote32.dll", CharSet = CharSet.Ansi)] + public static extern int GetLastExtendedError(); +} + +class GetLastExtendedError64 +{ + [DllImport("DinkeyRemote64.dll", CharSet = CharSet.Ansi)] + public static extern int GetLastExtendedError(); +} + +// ********************* DinkeyRemote class ********************** +class DinkeyRemote +{ + // constants + public const int DRPF_VERSION = 2; // current DRPF version + + // WriteDRPFEx API flags + public const int FLAGS_LOSE_FEATURES = 1; // means that you can save the DRPF file to an earlier version even if it means losing some new features that have been currently set + + // constants for drpf_format in ReadDRPFEx and WriteDRPFEx functions + public const int DRPF_FORMAT_BINARY = 1; + public const int DRPF_FORMAT_JSON = 2; + public const int DRPF_FORMAT_JSON_MIN = 3; // this value is only used with WriteDRPFEx. ReadDRPFEx cannot return this value. + + // private constants + private const int MAX_LICENCES = 255; // max number of licence changes in a DRPF file (theoretically unlimited but easier if we limit it) + private const int MAX_ALG_CHANGES = 21; // max number of alg changes in DRPF file + private const int MAX_DATA_CHANGES = 127; // max number of data area changes in DRPF file + + // **** main API + // We only want to load the correct DLL for the bit-ness of the computer. The other DLL may not exist. + // if the appropriate DLL does not exist in the same directory as this test program you will receive a DllNotFoundException + + public static IntPtr LoadDRPFFromFile(string drpf_file, out int err_code) + { + if (IntPtr.Size == 4) + return LoadDRPFFromFile32.LoadDRPFFromFile(drpf_file, out err_code); + return LoadDRPFFromFile64.LoadDRPFFromFile(drpf_file, out err_code); + } + + // we have to do some marshalling of arrays of bytes into arrays of structures + public static int ReadDRPFEx(string drpf_file, out REMOTEINFO RemoteInfo, out LICENCEINFO[] LicenceInfo, out ALGCHANGE[] AlgChanges, out DATACHANGE[] DataChanges, out int drpf_version, out int drpf_format) + { + int ret_code, i; + byte[] licence_bytes = new byte[MAX_LICENCES * Marshal.SizeOf(typeof(LICENCEINFO))]; + byte[] licence_bytes_one_struct = new byte[Marshal.SizeOf(typeof(LICENCEINFO))]; + byte[] algchange_bytes = new byte[MAX_ALG_CHANGES * Marshal.SizeOf(typeof(ALGCHANGE))]; + byte[] algchange_bytes_one_struct = new byte[Marshal.SizeOf(typeof(ALGCHANGE))]; + byte[] datachange_bytes = new byte[MAX_DATA_CHANGES * Marshal.SizeOf(typeof(DATACHANGE))]; + byte[] datachange_bytes_one_struct = new byte[Marshal.SizeOf(typeof(DATACHANGE))]; + GCHandle MyGC; + RemoteInfo = new REMOTEINFO(); + LicenceInfo = null; + AlgChanges = null; + DataChanges = null; + + if (IntPtr.Size == 4) + ret_code = ReadDRPFEx32.ReadDRPFEx(drpf_file, out RemoteInfo, licence_bytes, algchange_bytes, datachange_bytes, out drpf_version, out drpf_format); + else + ret_code = ReadDRPFEx64.ReadDRPFEx(drpf_file, out RemoteInfo, licence_bytes, algchange_bytes, datachange_bytes, out drpf_version, out drpf_format); + + if (ret_code != 0) + return ret_code; + + // convert byte array to an array of structs + LicenceInfo = new LICENCEINFO[RemoteInfo.NumLicences]; + for (i=0; i + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyRemote/drpfTest.sln b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyRemote/drpfTest.sln new file mode 100644 index 0000000..3d22dc3 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/DinkeyRemote/drpfTest.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "drpfTest", "drpfTest.csproj", "{7C474B2E-28FA-4821-8FF0-FD2181A0B242}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {7C474B2E-28FA-4821-8FF0-FD2181A0B242}.Debug.ActiveCfg = Debug|.NET + {7C474B2E-28FA-4821-8FF0-FD2181A0B242}.Debug.Build.0 = Debug|.NET + {7C474B2E-28FA-4821-8FF0-FD2181A0B242}.Release.ActiveCfg = Release|.NET + {7C474B2E-28FA-4821-8FF0-FD2181A0B242}.Release.Build.0 = Release|.NET + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2002/App.ico b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2002/App.ico new file mode 100644 index 0000000..3a5525f Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2002/App.ico differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2002/AssemblyInfo.cs b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2002/AssemblyInfo.cs new file mode 100644 index 0000000..9f89a32 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2002/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2002/DllTest.csproj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2002/DllTest.csproj new file mode 100644 index 0000000..16051cf --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2002/DllTest.csproj @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2002/DllTest.sln b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2002/DllTest.sln new file mode 100644 index 0000000..5e14c3b --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2002/DllTest.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DllTest", "DllTest.csproj", "{8199C796-57A5-4EA6-B0E0-41022918FCC2}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {8199C796-57A5-4EA6-B0E0-41022918FCC2}.Debug.ActiveCfg = Debug|.NET + {8199C796-57A5-4EA6-B0E0-41022918FCC2}.Debug.Build.0 = Debug|.NET + {8199C796-57A5-4EA6-B0E0-41022918FCC2}.Release.ActiveCfg = Release|.NET + {8199C796-57A5-4EA6-B0E0-41022918FCC2}.Release.Build.0 = Release|.NET + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2002/Form1.cs b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2002/Form1.cs new file mode 100644 index 0000000..19e659d --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2002/Form1.cs @@ -0,0 +1,874 @@ +// !! We strongly recommend that you read the "readme.txt" file in the sample code folder. +// !! It contains important instructions on how to use the sample code + +using System; +using System.Drawing; +using System.Collections; +using System.ComponentModel; +using System.Windows.Forms; +using System.Data; +using System.Runtime.InteropServices; + +namespace DllTest +{ + /// + /// Summary description for Form1. + /// + public class Form1 : System.Windows.Forms.Form + { + private System.Windows.Forms.Label label1; + /// + /// Required designer variable. + /// + private System.ComponentModel.Container components = null; + + public Form1() + { + // + // Required for Windows Form Designer support + // + InitializeComponent(); + + // + // TODO: Add any constructor code after InitializeComponent call + // + } + + /// + /// Clean up any resources being used. + /// + protected override void Dispose( bool disposing ) + { + if( disposing ) + { + if (components != null) + { + components.Dispose(); + } + } + base.Dispose( disposing ); + } + + #region Windows Form Designer generated code + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // label1 + // + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 21.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0))); + this.label1.Location = new System.Drawing.Point(72, 72); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(160, 40); + this.label1.TabIndex = 0; + this.label1.Text = "It Worked!"; + // + // Form1 + // + this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); + this.ClientSize = new System.Drawing.Size(296, 205); + this.Controls.AddRange(new System.Windows.Forms.Control[] { + this.label1}); + this.Name = "Form1"; + this.Text = "Form1"; + this.ResumeLayout(false); + + } + #endregion + + public const int MY_SDSN = 10101; // !!!! change this value to be the value of your SDSN (demo = 10101) + public const string MY_PRODCODE = "DEMO"; // !!!! change this value to match the Product Code in the dongle + + /// + /// The main entry point for the application. + /// + /* The sample code contains 11 functions. You will not need to use all these + functions in your code. Just use which ever functions are most appropriate + and customise in your own way. The sample code is just a guide. You should + implement the protection in a stronger way using the techniques described in + the "Increasing your Protection" chapter of the manual. + + ProtCheck // a standard protection check + ProtCheckWithAlg // a protection check & executing an Algorithm + WriteBytes // a protection check & write data to the dongle + ReadBytes // a protection check & read data from the dongle + EncryptUserData // a protection check & encrypting data and then decrypting the data + // these functions are the same as the functions listed above but encrypting all parameters passed to our API + ProtCheckEnc // a standard protection check + ProtCheckWithAlgEnc // a protection check & executing an Algorithm + WriteBytesEnc // a protection check & write data to the dongle + ReadBytesEnc // a protection check & read data from the dongle + EncryptUserDataEnc // a protection check & encrypting data and then decrypting the data + // this function displays the current network users + DisplayNetUsers + + If you are using Dinkey Lite then you can only use 4 functions: + ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + */ + + [STAThread] + static void Main() + { + // call the function(s) of your choice here + // in this example I have chosen a standard protection check + if (ProtCheck() != 0) + return; // check fails - exit program + Application.Run(new Form1()); + } + + // ************************* our 10 functions follow ************************* + + // **************************** ProtCheck ********************************* + // standard protection check + public static int ProtCheck() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.PROTECTION_CHECK; // standard protection check + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + ret_code = DinkeyPro.DDProtCheck(dris, null); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + if (dris.prodcode != MY_PRODCODE) + { + MessageBox.Show("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // if you are using a network dongle and you want to list the network users then use this function: + // DisplayNetUsers(dris); + + return 0; + } + + // **************************** ProtCheckWithAlg **************************** + + // !!!! You should replace this function with the one generated by the + // "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) + // or from DinkeyLook if you are using a Dinkey Lite dongle. + private static int MyAlgorithm(int a, int b, int c, int d, int e, int f, int g, int h) + { + return a + b + c + d + e + f + g + h; + } + + // NB for this to work you must program at least "user algorithm" into the dongle + // NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + // sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite copy the sample code from DinkeyLook + public static int ProtCheckWithAlg() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.EXECUTE_ALGORITHM; // standard protection check & execute algorithm + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number = 1; // execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + // you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.var_a = 1; // sample values + dris.var_b = 2; + dris.var_c = 3; + dris.var_d = 4; + dris.var_e = 5; + dris.var_f = 6; + dris.var_g = 7; + dris.var_h = 8; + + ret_code = DinkeyPro.DDProtCheck(dris, null); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + // !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) != dris.alg_answer) + { + MessageBox.Show("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + return 0; + } + + // ************************** WriteBytes ****************************** + // This writes the Data 0,1,2,3,4,5,6,7,8,9 to the dongle data area at offset 7 + // In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + // if you want to write a string then you need to convert it to a byte array first: + // encoding.GetBytes(your_string, 0, your_string.Length, data, 0) where encoding is of ASCIIEncoding type. + public static int WriteBytes() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + byte[] DataToWrite = {0,1,2,3,4,5,6,7,8,9}; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.WRITE_DATA_AREA; // standard protection check & write data to dongle + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris.rw_offset = 7; + dris.rw_length = DataToWrite.GetLength(0); + + ret_code = DinkeyPro.DDProtCheck(dris, DataToWrite); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + return 0; + } + + // ************************ ReadBytes ************************************ + // This reads 10 bytes of data from offset 7 in the dongle data area + // In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + // if you want to read a string then you need to convert it from a byte array (via an array of char) + // CharArray = encoding.GetChars(data); where CharArray is of type char[] and encoding is of type ASCIIEncoding + // your_string = new String(CharArray, 0, your_string_length); + public static int ReadBytes() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + byte[] DataToRead = new byte[10]; + string DisplayString; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.READ_DATA_AREA; // standard protection check & read data + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris.rw_offset = 7; + dris.rw_length = DataToRead.GetLength(0); + + ret_code = DinkeyPro.DDProtCheck(dris, DataToRead); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + DisplayString = "Dinkey Dongle data area, offset 7: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}", + DataToRead[0], DataToRead[1], DataToRead[2], DataToRead[3], DataToRead[4], DataToRead[5], DataToRead[6], DataToRead[7], DataToRead[8], DataToRead[9]); + MessageBox.Show(DisplayString, "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return 0; + } + + // ************************** EncryptUserData ************************************ + // This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 + // It will then do another protection check & decrypt the data + // if you want to encrypt of decrypt string then see comment for WriteBytes and ReadBytes + public static int EncryptUserData() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + byte[] Data = {0,1,2,3,4,5,6,7,8,9}; + string DisplayString; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.ENCRYPT_USER_DATA; // standard protection check & encrypt data + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; + dris.rw_length = Data.GetLength(0); + dris.data_crypt_key_num = 1; + + ret_code = DinkeyPro.DDProtCheck(dris, Data); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + // Now decrypt the same data to get the original values + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.DECRYPT_USER_DATA; // standard protection check & read data + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris.rw_length = Data.GetLength(0); + dris.data_crypt_key_num = 1; + + ret_code = DinkeyPro.DDProtCheck(dris, Data); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + DisplayString = "decrypted data is: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}", + Data[0], Data[1], Data[2], Data[3], Data[4], Data[5], Data[6], Data[7], Data[8], Data[9]); + MessageBox.Show(DisplayString, "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return 0; + } + + // !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! + // In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" + // in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm + // but the code can be modified easily to use the 3 encryption parameters. + + // !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm + private static int MyRWAlgorithm(int a, int b, int c, int d, int e, int f, int g, int h) + { + return a ^ b ^ c ^ d ^ e ^ f; + } + + + // !!!! please overwrite this function with the one generated by DinkeyAdd + private static void CryptDRIS(DRIS dris) + { + int i, j, k; + byte[] bigseed = new byte[256]; + byte[] S = new byte[256]; + byte temp, t; + byte[] dris_bytes = new byte[Marshal.SizeOf(dris)]; + + dris.DrisToByteArray(dris, dris_bytes); // convert DRIS to byte array so we can encrypt it + + for (i=0; i<256; i+=8) + { + dris.Set4Bytes(bigseed, i, dris.seed1); + dris.Set4Bytes(bigseed, i+4, dris.seed2); + } + for (i=0; i<256; i++) + S[i] = (byte)i; + for (i=0, j=0; i<256; i++) + { + j = (j + S[i] + bigseed[i] + 123) % 256; + temp = S[i]; + S[i] = S[j]; + S[j] = temp; + } + for (i=0, j=0, k=16; k> 8) & 0xff)) % 256; + temp = S[i]; + S[i] = S[j]; + S[j] = temp; + t = (byte)(S[i] + S[j] + ((alg_answer >> 16) & 0xff)); + data[k] ^= S[t]; + } + return; + } + + // **************************** ProtCheckEnc ****************************** + // We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. + public static int ProtCheckEnc() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.PROTECTION_CHECK; // standard protection check + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris, null); + + CryptDRIS(dris); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + if (dris.prodcode != MY_PRODCODE) + { + MessageBox.Show("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + return 0; + } + + // **************************** ProtCheckWithAlgEnc ************************* + // NB for this to work you must program at least "user algorithm" into the dongle + // NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + // sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite copy source from DinkeyLook. + // We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. + public static int ProtCheckWithAlgEnc() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.EXECUTE_ALGORITHM; // standard protection check & execute algorithm + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number = 1; // execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + // you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.var_a = 1; // sample values + dris.var_b = 2; + dris.var_c = 3; + dris.var_d = 4; + dris.var_e = 5; + dris.var_f = 6; + dris.var_g = 7; + dris.var_h = 8; + + CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris, null); + + CryptDRIS(dris); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + // !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) != dris.alg_answer) + { + MessageBox.Show("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + return 0; + } + + // ************************** WriteBytesEnc *************************** + // This writes the Data 0,1,2,3,4,5,6,7,8,9 to the dongle data area at offset 7 + // In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + // We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + // if you want to write strings then see comment for WriteBytes + public static int WriteBytesEnc() + { + int ret_code, alg_ans; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + byte[] DataToWrite = {0,1,2,3,4,5,6,7,8,9}; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.WRITE_DATA_AREA; // standard protection check & write data to dongle + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris.rw_offset = 7; + dris.rw_length = DataToWrite.GetLength(0); + + // calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + // encrypt data we want to write. + CryptApiData(dris, DataToWrite, DataToWrite.GetLength(0), alg_ans); + + CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris, DataToWrite); + + CryptDRIS(dris); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + return 0; + } + + // ************************ ReadBytesEnc ********************************* + // This reads 10 bytes of data from offset 7 in the dongle data area + // In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + // We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + // if you want to read strings then see comment for ReadBytes + public static int ReadBytesEnc() + { + int ret_code, alg_ans; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + byte[] DataRead = new byte[10]; + string DisplayString; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.READ_DATA_AREA; // standard protection check & read data + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris.rw_offset = 7; + dris.rw_length = DataRead.GetLength(0); + + // calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris, DataRead); + + CryptDRIS(dris); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // decrypt data that was read. + CryptApiData(dris, DataRead, DataRead.GetLength(0), alg_ans); + + DisplayString = "Dinkey Dongle data area, offset 7: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}", + DataRead[0], DataRead[1], DataRead[2], DataRead[3], DataRead[4], DataRead[5], DataRead[6], DataRead[7], DataRead[8], DataRead[9]); + MessageBox.Show(DisplayString, "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return 0; + } + + // ************************** EncryptUserDataEnc ********************************* + // This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 + // It will then do another protection & decrypt the data + // We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + // if you want to encrypt of decrypt strings then see comment for WriteBytes and ReadBytes + public static int EncryptUserDataEnc() + { + int ret_code, alg_ans; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + DRIS dris2 = new DRIS(); // initialise the DRIS with random values & set the header + byte[] Data = {0,1,2,3,4,5,6,7,8,9}; + string DisplayString; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.ENCRYPT_USER_DATA; // standard protection check & encrypt data + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; + dris.rw_length = Data.GetLength(0); + dris.data_crypt_key_num = 1; + + // calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + // encrypt data we pass to our API. + CryptApiData(dris, Data, Data.GetLength(0), alg_ans); + + CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris, Data); + + CryptDRIS(dris); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + // NB use another dris so that we can ensure elements are initialised to different random numbers + dris2.size = Marshal.SizeOf(dris2); + dris2.function = DRIS.DECRYPT_USER_DATA; // standard protection check & read data + dris2.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris2.rw_length = Data.GetLength(0); + dris2.data_crypt_key_num = 1; + + CryptDRIS(dris2); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris2, Data); + + CryptDRIS(dris2); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris2.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris2.sdsn != MY_SDSN) + { + MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // later on in your program you can check the return code again + if (dris2.ret_code != 0) + { + MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + alg_ans = MyRWAlgorithm(dris2.var_a, dris2.var_b, dris2.var_c, dris2.var_d, dris2.var_e, dris2.var_f, dris2.var_g, dris2.var_h); + // decrypt data that was passed to us by the API. + CryptApiData(dris2, Data, Data.GetLength(0), alg_ans); + + DisplayString = "decrypted data is: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}", + Data[0], Data[1], Data[2], Data[3], Data[4], Data[5], Data[6], Data[7], Data[8], Data[9]); + MessageBox.Show(DisplayString, "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return 0; + } + + // *********************** DisplayNetUsers ******************************* + // This function displays the current network users (for DinkeyNet only). + // The DDProtCheck function must be called before this function is called. + // (Normally you would use DinkeyServer to view the network users but this enables you to do it from the client if you want) + public static int DisplayNetUsers(DRIS dris) + { + string DisplayString; + int num_net_users, extended_error, ret_code, i, max_net_users; + NU_INFO[] nu_info; + + if (dris.net_users == -1) + max_net_users = 100; // if unlimited network users are allowed then display up to 100 users (for example) + else + max_net_users = dris.net_users; + + if (max_net_users == 0) // no network users are allowed, so nothing to do! + return 0; + + if (dris.model < 3) { + MessageBox.Show("A network dongle has not been detected. Therefore you cannot display the network users.", "Net Users", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + ret_code = DinkeyPro.DDGetNetUserList(null, out num_net_users, out nu_info, max_net_users, out extended_error); + + if (ret_code != 0) + { + MessageBox.Show(String.Format("Error {0}/{1} finding network user information.", ret_code, extended_error), "Net Users", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + else + { + DisplayString = String.Format("number of net users: {0}", num_net_users) + Environment.NewLine; + for (i=0; i + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Form1 + + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2002/dris.cs b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2002/dris.cs new file mode 100644 index 0000000..51e14b2 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2002/dris.cs @@ -0,0 +1,287 @@ +// !! this file should not be modified + +using System; +using System.Runtime.InteropServices; // so we can marshal the DRIS as a block of memory +using System.Text; // so we can extract / set strings in the DRIS +using System.Windows.Forms; // for MessageBox + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public class DRIS +{ + // the first 4 fields are never encrypted + public byte header1; // should be set to "DRIS" + public byte header2; + public byte header3; + public byte header4; + // inputs + public int size; // size of this structure + public int seed1; // seed for data/dris encryption + public int seed2; // as above + // (maybe encrypted from now on) + public int function; // specify only one function + public int flags; // options for the function selected. To use more than one OR them together: OPTION1 | OPTION2... + public uint execs_decrement; // amount by which to dec execs if we use flag: DEC_MANY_EXECS + public int data_crypt_key_num; // number of the key (1-3) that the dongle uses to encrypt or decrypt user data + public int rw_offset; // offset in the dongle data area to read or write data + public int rw_length; // length of data are to read/write/encrypt/decrypt + public IntPtr DoNotUse; // do not use the rw_data_ptr element use the "Data" argument of the DDProtCheck function + [MarshalAs(UnmanagedType.ByValArray, SizeConst=256)] // NB access this field by using alg_licence_name (see below) + private byte[] _alt_licence_name = null; // protection check for different licence instead of this one + public int var_a; // variable values for user algorithm + public int var_b; + public int var_c; + public int var_d; + public int var_e; + public int var_f; + public int var_g; + public int var_h; + public int alg_number; // the number of the user algorithm that you want to execute + + // outputs + public int ret_code; // return code from the protection check + public int ext_err; // extended error + public int type; // type of dongle detected. 1 = Pro, 2 = FD + public int model; // model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + public int sdsn; // Software Developer's Serial Number + [MarshalAs(UnmanagedType.ByValArray, SizeConst=12)] // NB access this field by using prodcode (see below) + private byte[] _prodcode = null; // product code (null-terminated) + public uint dongle_number; + public int update_number; + public uint data_area_size; // size of the data area in the dongle detected + public int max_alg_num; // number of algorithms in the dongle detected + public int execs; // executions left: -1 indicates 'no limit' + public int exp_day; // expiry day: -1 indicates 'no limit' + public int exp_month; // expiry month: -1 indicates 'no limit' + public int exp_year; // expiry year: -1 indicates 'no limit' + public uint features; // features value + public int net_users; // maximum number of network users for the dongle detected: -1 indicates 'mo limit' + public int alg_answer; // answer to the user algorithm executed with the given variable values + public uint fd_capacity; // capacity of the data area in FD dongle. Currently fixed at ~10MB but may change in the future. + [MarshalAs(UnmanagedType.ByValArray, SizeConst=128)] // NB access this field by using fd_drive (see below) + private byte[] _fd_drive = null; // fd drive letter (null-terminated) + public int swkey_type; // 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + public int swkey_exp_day; // software key expiry date (if software key detected) + public int swkey_exp_month; + public int swkey_exp_year; + + // NB we have to do it this way because we cannot encrypt strings correctly unless they are byte arrays + public string prodcode + { + get + { + StringBuilder sb = new StringBuilder(12); + foreach (byte b in _prodcode) + { + if (b == 0) + return sb.ToString(); + else + sb.Append((char)b); + } + return sb.ToString(); + } + } + + public string fd_drive + { + get + { + StringBuilder sb = new StringBuilder(128); + foreach (byte b in _fd_drive) + { + if (b == 0) + return sb.ToString(); + else + sb.Append((char)b); + } + return sb.ToString(); + } + } + + // NB we have to do it this way because we cannot encrypt strings correctly unless they are byte arrays + public string alt_licence_name + { + set + { + int i; + StringBuilder sb = new StringBuilder(value, 256); + for (i=0; i> 8) & 0xff); + data[offset+2] = (byte)((value >> 16) & 0xff); + data[offset+3] = (byte)((value >> 24) & 0xff); + return; + } + + // converts to DRIS structure to a byte array (so we can do encryption) + public void DrisToByteArray(DRIS dris, byte[] data) + { + GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned); + Marshal.StructureToPtr(dris, MyGC.AddrOfPinnedObject(), false); + MyGC.Free(); + return; + } + + // converts a byte array to the DRIS structure (so we can do encryption) + public void ByteArrayToDris(byte[] data, DRIS dris) + { + GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned); + Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), dris); + MyGC.Free(); + return; + } + + // to make a new instance of this class, initialise every element to a random value and then set the header + public DRIS() + { + Random rnd = new Random(); + Byte[] temp = new Byte[Marshal.SizeOf(this)]; + rnd.NextBytes(temp); + ByteArrayToDris(temp, this); + this.header1 = (byte)'D'; + this.header2 = (byte)'R'; + this.header3 = (byte)'I'; + this.header4 = (byte)'S'; + } + + // functions - must specify only one + public const int PROTECTION_CHECK = 1; // checks for dongle, check program params... + public const int EXECUTE_ALGORITHM = 2; // protection check + calculate answer for specified algorithm with specified inputs + public const int WRITE_DATA_AREA = 3; // protection check + writes dongle data area + public const int READ_DATA_AREA = 4; // protection check + reads dongle data area + public const int ENCRYPT_USER_DATA = 5; // protection check + the dongle will encrypt user data + public const int DECRYPT_USER_DATA = 6; // protection check + the dongle will decrypt user data + public const int FAST_PRESENCE_CHECK = 7; // checks for the presence of the correct dongle only with minimal security, no flags allowed. + public const int STOP_NET_USER = 8; // stops a network user (a protection check is NOT performed) + + // flags - can specify as many as you like + public const int DEC_ONE_EXEC = 1; // decrement execs by 1 + public const int DEC_MANY_EXECS = 2; // decrement execs by number specified in execs_decrement + public const int START_NET_USER = 4; // starts a network user + public const int USE_FUNCTION_ARGUMENT = 16; // use the extra argument in the function for pointers + public const int CHECK_LOCAL_FIRST = 32; // always look in local ports before looking in network ports + public const int CHECK_NETWORK_FIRST = 64; // always look on the network before looking in local ports + public const int USE_ALT_LICENCE_NAME = 128; // use name specified in alt_licence_name instead of the default one + public const int DONT_SET_MAXDAYS_EXPIRY = 256; // if the max days expiry date has not been calculated then do not do it this time + public const int MATCH_DONGLE_NUMBER = 512; // restrict the search to match the dongle number specified in the DRIS + public const int DONT_RETURN_FD_DRIVE = 1024; // if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct NU_INFO +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string licenceName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=50)] + public string userName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string computerName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=16)] + public string ipAddress; +} + +// 32-bit protection check (loads 32-bit DLL) +class DDProtCheck32 +{ + [DllImport("dpwin32.dll", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// 64-bit protection check (loads 64-bit DLL) +class DDProtCheck64 +{ + [DllImport("dpwin64.dll", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// 32-bit get network user info (loads 32-bit DLL) +class DDGetNetUserList32 +{ + [DllImport("dpwin32.dll", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// 64-bit get network user info (loads 64-bit DLL) +class DDGetNetUserList64 +{ + [DllImport("dpwin64.dll", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// call our API - we only want to load the correct DLL for the bit-ness of the computer. The other DLL may not exist. +class DinkeyPro +{ + // calls the DDProtCheck function in the appropriate DLL + public static int DDProtCheck(DRIS dris, byte[] data) + { + int ret_code = -1; + + if (IntPtr.Size == 4) + { + try + { + ret_code = DDProtCheck32.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dpwin32.dll. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + else { + try + { + ret_code = DDProtCheck64.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dpwin64.dll. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + return ret_code; + } + + public static int DDGetNetUserList(string licence_name, out int num_net_users, out NU_INFO[] nu_info, int num_info_structs, out int extended_error) + { + int ret_code = -1; + int i; + extended_error = num_net_users = 0; + byte[] nu_info_bytes = new byte[num_info_structs * Marshal.SizeOf(typeof(NU_INFO))]; + byte[] nu_info_one_struct = new byte[Marshal.SizeOf(typeof(NU_INFO))]; + GCHandle MyGC; + nu_info = null; + + // call the function and get info as a byte array + if (IntPtr.Size == 4) + ret_code = DDGetNetUserList32.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + else + ret_code = DDGetNetUserList64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + + if (ret_code != 0) + return ret_code; + + // convert byte array to an array of structs + nu_info = new NU_INFO[num_net_users]; + for (i=0; i> 8) & 0xff); + data[offset+2] = (byte)((value >> 16) & 0xff); + data[offset+3] = (byte)((value >> 24) & 0xff); + return; + } + + // converts to DRIS structure to a byte array (so we can do encryption) + public void DrisToByteArray(DRIS dris, byte[] data) + { + GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned); + Marshal.StructureToPtr(dris, MyGC.AddrOfPinnedObject(), false); + MyGC.Free(); + return; + } + + // converts a byte array to the DRIS structure (so we can do encryption) + public void ByteArrayToDris(byte[] data, DRIS dris) + { + GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned); + Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), dris); + MyGC.Free(); + return; + } + + // to make a new instance of this class, initialise every element to a random value and then set the header + public DRIS() + { + Random rnd = new Random(); + Byte[] temp = new Byte[Marshal.SizeOf(this)]; + rnd.NextBytes(temp); + ByteArrayToDris(temp, this); + this.header1 = (byte)'D'; + this.header2 = (byte)'R'; + this.header3 = (byte)'I'; + this.header4 = (byte)'S'; + } + + // functions - must specify only one + public const int PROTECTION_CHECK = 1; // checks for dongle, check program params... + public const int EXECUTE_ALGORITHM = 2; // protection check + calculate answer for specified algorithm with specified inputs + public const int WRITE_DATA_AREA = 3; // protection check + writes dongle data area + public const int READ_DATA_AREA = 4; // protection check + reads dongle data area + public const int ENCRYPT_USER_DATA = 5; // protection check + the dongle will encrypt user data + public const int DECRYPT_USER_DATA = 6; // protection check + the dongle will decrypt user data + public const int FAST_PRESENCE_CHECK = 7; // checks for the presence of the correct dongle only with minimal security, no flags allowed. + public const int STOP_NET_USER = 8; // stops a network user (a protection check is NOT performed) + + // flags - can specify as many as you like + public const int DEC_ONE_EXEC = 1; // decrement execs by 1 + public const int DEC_MANY_EXECS = 2; // decrement execs by number specified in execs_decrement + public const int START_NET_USER = 4; // starts a network user + public const int USE_FUNCTION_ARGUMENT = 16; // use the extra argument in the function for pointers + public const int CHECK_LOCAL_FIRST = 32; // always look in local ports before looking in network ports + public const int CHECK_NETWORK_FIRST = 64; // always look on the network before looking in local ports + public const int USE_ALT_LICENCE_NAME = 128; // use name specified in alt_licence_name instead of the default one + public const int DONT_SET_MAXDAYS_EXPIRY = 256; // if the max days expiry date has not been calculated then do not do it this time + public const int MATCH_DONGLE_NUMBER = 512; // restrict the search to match the dongle number specified in the DRIS + public const int DONT_RETURN_FD_DRIVE = 1024; // if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct NU_INFO +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string licenceName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=50)] + public string userName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string computerName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=16)] + public string ipAddress; +} + +// DDProtCheck + +// Windows 32-bit protection check (loads 32-bit DLL) +class DDProtCheckWin32 +{ + [DllImport("dpwin32.dll", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// Windows 64-bit protection check (loads 64-bit DLL) +class DDProtCheckWin64 +{ + [DllImport("dpwin64.dll", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// Linux 64-bit protection check (loads 64-bit so) (NB only 64-bit Linux is supported by .NET Core) +class DDProtCheckLin64 +{ + [DllImport("dplin64.so", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// Mac 64-bit protection check (loads 64-bit dylib) (NB only 64-bit Mac code is supported by .NET Core) (NB we found that the release module dpmac64.dylib crashed) +class DDProtCheckMac64 +{ + [DllImport("dpmac64debug.dylib", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// DDGetNetUserList + +// Windows 32-bit get network user info (loads 32-bit DLL) +class DDGetNetUserListWin32 +{ + [DllImport("dpwin32.dll", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// Windows 64-bit get network user info (loads 64-bit DLL) +class DDGetNetUserListWin64 +{ + [DllImport("dpwin64.dll", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// Linux 64-bit get network user info (loads 64-bit DLL) +class DDGetNetUserListLin64 +{ + [DllImport("dplin64.so", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// call our API - we only want to load the correct DLL for the OS and bit-ness of the computer. The other DLLs may not exist. +class DinkeyPro +{ + // calls the DDProtCheck function in the appropriate DLL + public static int DDProtCheck(DRIS dris, byte[] data) + { + int ret_code = -1; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // method valid from .NET Core 1.0 and .NET framework 4.7 + { + if (Environment.Is64BitProcess) // method valid from .NET Core 2.0 and .NET framework 4.0 + { + try + { + ret_code = DDProtCheckWin64.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dpwin64.dll. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + else + { + try + { + ret_code = DDProtCheckWin32.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dpwin32.dll. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + try + { + ret_code = DDProtCheckLin64.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dplin64.so. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + try + { + ret_code = DDProtCheckMac64.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dpmac64debug.dylib. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + else + { + MessageBox.Show("Error! Dinkey Pro/FD not supported on this OS.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + return ret_code; + } + + public static int DDGetNetUserList(string licence_name, out int num_net_users, out NU_INFO[] nu_info, int num_info_structs, out int extended_error) + { + int ret_code = -1; + int i; + extended_error = num_net_users = 0; + byte[] nu_info_bytes = new byte[num_info_structs * Marshal.SizeOf(typeof(NU_INFO))]; + byte[] nu_info_one_struct = new byte[Marshal.SizeOf(typeof(NU_INFO))]; + GCHandle MyGC; + nu_info = null; + + // call the function and get info as a byte array + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + if (Environment.Is64BitProcess) + ret_code = DDGetNetUserListWin64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + else + ret_code = DDGetNetUserListWin32.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + ret_code = DDGetNetUserListLin64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + MessageBox.Show("Error! This function is not supported in the Mac debug module.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + + if (ret_code != 0) + return ret_code; + + // convert byte array to an array of structs + nu_info = new NU_INFO[num_net_users]; + for (i=0; i> 8) & 0xff); + data[offset+2] = (byte)((value >> 16) & 0xff); + data[offset+3] = (byte)((value >> 24) & 0xff); + return; + } + + // converts to DRIS structure to a byte array (so we can do encryption) + public void DrisToByteArray(DRIS dris, byte[] data) + { + GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned); + Marshal.StructureToPtr(dris, MyGC.AddrOfPinnedObject(), false); + MyGC.Free(); + return; + } + + // converts a byte array to the DRIS structure (so we can do encryption) + public void ByteArrayToDris(byte[] data, DRIS dris) + { + GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned); + Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), dris); + MyGC.Free(); + return; + } + + // to make a new instance of this class, initialise every element to a random value and then set the header + public DRIS() + { + Random rnd = new Random(); + Byte[] temp = new Byte[Marshal.SizeOf(this)]; + rnd.NextBytes(temp); + ByteArrayToDris(temp, this); + this.header1 = (byte)'D'; + this.header2 = (byte)'R'; + this.header3 = (byte)'I'; + this.header4 = (byte)'S'; + } + + // functions - must specify only one + public const int PROTECTION_CHECK = 1; // checks for dongle, check program params... + public const int EXECUTE_ALGORITHM = 2; // protection check + calculate answer for specified algorithm with specified inputs + public const int WRITE_DATA_AREA = 3; // protection check + writes dongle data area + public const int READ_DATA_AREA = 4; // protection check + reads dongle data area + public const int ENCRYPT_USER_DATA = 5; // protection check + the dongle will encrypt user data + public const int DECRYPT_USER_DATA = 6; // protection check + the dongle will decrypt user data + public const int FAST_PRESENCE_CHECK = 7; // checks for the presence of the correct dongle only with minimal security, no flags allowed. + public const int STOP_NET_USER = 8; // stops a network user (a protection check is NOT performed) + + // flags - can specify as many as you like + public const int DEC_ONE_EXEC = 1; // decrement execs by 1 + public const int DEC_MANY_EXECS = 2; // decrement execs by number specified in execs_decrement + public const int START_NET_USER = 4; // starts a network user + public const int USE_FUNCTION_ARGUMENT = 16; // use the extra argument in the function for pointers + public const int CHECK_LOCAL_FIRST = 32; // always look in local ports before looking in network ports + public const int CHECK_NETWORK_FIRST = 64; // always look on the network before looking in local ports + public const int USE_ALT_LICENCE_NAME = 128; // use name specified in alt_licence_name instead of the default one + public const int DONT_SET_MAXDAYS_EXPIRY = 256; // if the max days expiry date has not been calculated then do not do it this time + public const int MATCH_DONGLE_NUMBER = 512; // restrict the search to match the dongle number specified in the DRIS + public const int DONT_RETURN_FD_DRIVE = 1024; // if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct NU_INFO +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string licenceName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=50)] + public string userName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string computerName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=16)] + public string ipAddress; +} + +// DDProtCheck + +// Windows 32-bit protection check (loads 32-bit DLL) +class DDProtCheckWin32 +{ + [DllImport("dpwin32.dll", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// Windows 64-bit protection check (loads 64-bit DLL) +class DDProtCheckWin64 +{ + [DllImport("dpwin64.dll", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// Linux 32-bit protection check (loads 32-bit so) +class DDProtCheckLin32 +{ + [DllImport("dplin32.so", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// Linux 64-bit protection check (loads 64-bit so) +class DDProtCheckLin64 +{ + [DllImport("dplin64.so", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// Mac 32-bit protection check (loads 32-bit dylib) +class DDProtCheckMac32 +{ + [DllImport("dpmac32.dylib", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// Mac 64-bit protection check (loads 64-bit dylib) +class DDProtCheckMac64 +{ + [DllImport("dpmac64.dylib", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// DDGetNetUserList + +// Windows 32-bit get network user info (loads 32-bit DLL) +class DDGetNetUserListWin32 +{ + [DllImport("dpwin32.dll", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// Windows 64-bit get network user info (loads 64-bit DLL) +class DDGetNetUserListWin64 +{ + [DllImport("dpwin64.dll", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// Linux 32-bit get network user info (loads 32-bit so) +class DDGetNetUserListLin32 +{ + [DllImport("dplin32.so", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// Linux 64-bit get network user info (loads 64-bit so) +class DDGetNetUserListLin64 +{ + [DllImport("dplin64.so", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// Mac 32-bit get network user info (loads 32-bit dylib) +class DDGetNetUserListMac32 +{ + [DllImport("dpmac32.dylib", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// Mac 64-bit get network user info (loads 64-bit dylib) +class DDGetNetUserListMac64 +{ + [DllImport("dpmac64.dylib", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// call our API - we only want to load the correct DLL for the OS and bit-ness of the computer. The other DLLs may not exist. +class DinkeyPro +{ + // calls the DDProtCheck function in the appropriate DLL + public static int DDProtCheck(DRIS dris, byte[] data) + { + int ret_code = -1; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // method valid from .NET Core 1.0 and .NET framework 4.7 + { + if (Environment.Is64BitProcess) // method valid from .NET Core 2.0 and .NET framework 4.0 + { + try + { + ret_code = DDProtCheckWin64.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dpwin64.dll. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + else + { + try + { + ret_code = DDProtCheckWin32.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dpwin32.dll. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + if (Environment.Is64BitProcess) + { + try + { + ret_code = DDProtCheckLin64.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dplin64.do. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + else + { + try + { + ret_code = DDProtCheckLin32.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dplin32.so. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + if (Environment.Is64BitProcess) + { + try + { + ret_code = DDProtCheckMac64.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dpmac64.dylib. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + else + { + try + { + ret_code = DDProtCheckMac32.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dpmac32.dylib. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + } + else + { + MessageBox.Show("Error! Dinkey Pro/FD not supported on this OS.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + return ret_code; + } + + public static int DDGetNetUserList(string licence_name, out int num_net_users, out NU_INFO[] nu_info, int num_info_structs, out int extended_error) + { + int ret_code = -1; + int i; + extended_error = num_net_users = 0; + byte[] nu_info_bytes = new byte[num_info_structs * Marshal.SizeOf(typeof(NU_INFO))]; + byte[] nu_info_one_struct = new byte[Marshal.SizeOf(typeof(NU_INFO))]; + GCHandle MyGC; + nu_info = null; + + // call the function and get info as a byte array + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + if (Environment.Is64BitProcess) + ret_code = DDGetNetUserListWin64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + else + ret_code = DDGetNetUserListWin32.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + if (Environment.Is64BitProcess) + ret_code = DDGetNetUserListLin64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + else + ret_code = DDGetNetUserListLin32.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + if (Environment.Is64BitProcess) + ret_code = DDGetNetUserListMac64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + else + ret_code = DDGetNetUserListMac32.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + } + + if (ret_code != 0) + return ret_code; + + // convert byte array to an array of structs + nu_info = new NU_INFO[num_net_users]; + for (i=0; i". + +If you publish a "single-file executable" file then although this file can be protected we do not recommend +it because it is not secure. (The single-file executable just comprises a stub loader with your compiled +assemblies and configuration files appended to the end of the executable. These files are just considered as +data appended to the executable file in a custom format and therefore are not protected. When you shell +protect your executable you are just protecting the loader but not your assemblies). Instead you need to +build your code and then add protection before publishing. You should protect your assemblies in the obj +directory (and in the platform type you specified) e.g. obj/Release/net5.0/win-x64, because the publish +process takes your assemblies from this location when it builds the single-file executable. You will also +need to distribute all the extra files that DinkeyAdd generates. e.g. .dp64.dll. + +If you publish using the ReadytoRun compilation this will not work because it includes mixtures of .NET +assemblies and native code and the .NET Shell Method does not support that. + +Mono +~~~~ + +The sample code provided also works with Mono. However, Mono also supports Linux and macOS, and so if you want +to support those OS then please replace dris.cs with dris_mono.cs. Note, dris_mono.cs is very similar to +dris_dotnetcore.cs (see above) but with Mono, 32-bit Linux and 32-bit Mac are also supported and you don't +need to use the debug modules (for release) under macOS. + +Visual Studio Installer Projects Extension +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can use this extension to create a project in your solution that will create an installation program / msi +file. Please note that after your application has been built you need to protect it with DinkeyAdd before you +can invoke the installer project. You can do this manually by building your application project (not the entire +solution); then adding protection to your application using DinkeyAdd; then building your installer project. +Or you can automate this by executing DinkeyAddCmd as a post-build step. For example: +"c:\program files (x86)\Dinkey Pro 7.6.0\DinkeyAdd\DinkeyAddCmd.exe" c:\adir\mydapf.dapfj /a2 + +Note - if you specify "primary output" in your installer project then it will take the files from +obj\Release\net5.0 (for example), rather than bin\Release\net5.0. So, you need to add protection to your files +in this folder. + +Note - if you use the API Method you will also need to include the protected runtime modules that you use +(e.g. dpwin64.dll). If you use the Shell Method you will also need to include in your installer project all +of the output files mentioned by DinkeyAdd. e.g. .dp64.dll diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2022/DllTest.csproj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2022/DllTest.csproj new file mode 100644 index 0000000..74abf5c --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2022/DllTest.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2022/DllTest.sln b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2022/DllTest.sln new file mode 100644 index 0000000..15551a7 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2022/DllTest.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DllTest", "DllTest.csproj", "{EDCD7B70-034F-417C-B7C0-E86583C2FC5C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EDCD7B70-034F-417C-B7C0-E86583C2FC5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EDCD7B70-034F-417C-B7C0-E86583C2FC5C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EDCD7B70-034F-417C-B7C0-E86583C2FC5C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EDCD7B70-034F-417C-B7C0-E86583C2FC5C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {02BA6556-AD6D-40BD-A7EE-65BEE2095E5C} + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2022/Program.cs b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2022/Program.cs new file mode 100644 index 0000000..528a671 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2022/Program.cs @@ -0,0 +1,808 @@ +// See https://aka.ms/new-console-template for more information + +using System; +using System.Runtime.InteropServices; + + +namespace DllTest +{ + public class Program + { + public const int MY_SDSN = 10101; // !!!! change this value to be the value of your SDSN (demo = 10101) + public const string MY_PRODCODE = "DEMO"; // !!!! change this value to match the Product Code in the dongle + + /* The sample code contains 11 functions. You will not need to use all these + functions in your code. Just use which ever functions are most appropriate + and customise in your own way. The sample code is just a guide. You should + implement the protection in a stronger way using the techniques described in + the "Increasing your Protection" chapter of the manual. + + ProtCheck // a standard protection check + ProtCheckWithAlg // a protection check & executing an Algorithm + WriteBytes // a protection check & write data to the dongle + ReadBytes // a protection check & read data from the dongle + EncryptUserData // a protection check & encrypting data and then decrypting the data + // these functions are the same as the functions listed above but encrypting all parameters passed to our API + ProtCheckEnc // a standard protection check + ProtCheckWithAlgEnc // a protection check & executing an Algorithm + WriteBytesEnc // a protection check & write data to the dongle + ReadBytesEnc // a protection check & read data from the dongle + EncryptUserDataEnc // a protection check & encrypting data and then decrypting the data + // this function displays the current network users + DisplayNetUsers + + If you are using Dinkey Lite then you can only use 4 functions: + ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + */ + + public static void Main(string[] args) + { + // call the function(s) of your choice here + // in this example I have chosen a standard protection check + if (ProtCheck() == 0) + { + DisplayMessage("It worked!"); // NB on failure a message will have already been displayed + } + } + + // **************************** ProtCheck ********************************* + // standard protection check + public static int ProtCheck() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.PROTECTION_CHECK; // standard protection check + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + ret_code = DinkeyPro.DDProtCheck(dris, null); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + DisplayMessage("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + } + + if (dris.prodcode != MY_PRODCODE) + { + DisplayMessage("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle."); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + DisplayMessage("Dinkey Dongle protection error"); + return -1; + } + + // if you are using a network dongle and you want to list the network users then use this function: + //DisplayNetUsers(dris); + + return 0; + } + + // **************************** ProtCheckWithAlg **************************** + + // !!!! You should replace this function with the one generated by the + // "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) + // or from DinkeyLook if you are using a Dinkey Lite dongle. + private static int MyAlgorithm(int a, int b, int c, int d, int e, int f, int g, int h) + { + return a + b + c + d + e + f + g + h; + } + + // NB for this to work you must program at least "user algorithm" into the dongle + // NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + // sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite copy the sample code from DinkeyLook + public static int ProtCheckWithAlg() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.EXECUTE_ALGORITHM; // standard protection check & execute algorithm + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number = 1; // execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + // you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.var_a = 1; // sample values + dris.var_b = 2; + dris.var_c = 3; + dris.var_d = 4; + dris.var_e = 5; + dris.var_f = 6; + dris.var_g = 7; + dris.var_h = 8; + + ret_code = DinkeyPro.DDProtCheck(dris, null); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + DisplayMessage("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + DisplayMessage("Dinkey Dongle protection error"); + return -1; + } + + // if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + // !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) != dris.alg_answer) + { + DisplayMessage("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine"); + return -1; + } + return 0; + } + + // ************************** WriteBytes ****************************** + // This writes the Data 0,1,2,3,4,5,6,7,8,9 to the dongle data area at offset 7 + // In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + // if you want to write a string then you need to convert it to a byte array first: + // encoding.GetBytes(your_string, 0, your_string.Length, data, 0) where encoding is of ASCIIEncoding type. + public static int WriteBytes() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + byte[] DataToWrite = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.WRITE_DATA_AREA; // standard protection check & write data to dongle + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris.rw_offset = 7; + dris.rw_length = DataToWrite.GetLength(0); + + ret_code = DinkeyPro.DDProtCheck(dris, DataToWrite); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + DisplayMessage("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + DisplayMessage("Dinkey Dongle protection error"); + return -1; + } + return 0; + } + + // ************************ ReadBytes ************************************ + // This reads 10 bytes of data from offset 7 in the dongle data area + // In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + // if you want to read a string then you need to convert it from a byte array (via an array of char) + // CharArray = encoding.GetChars(data); where CharArray is of type char[] and encoding is of type ASCIIEncoding + // your_string = new String(CharArray, 0, your_string_length); + public static int ReadBytes() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + byte[] DataToRead = new byte[10]; + string DisplayString; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.READ_DATA_AREA; // standard protection check & read data + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris.rw_offset = 7; + dris.rw_length = DataToRead.GetLength(0); + + ret_code = DinkeyPro.DDProtCheck(dris, DataToRead); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + DisplayMessage("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + DisplayMessage("Dinkey Dongle protection error"); + return -1; + } + + DisplayString = "Dinkey Dongle data area, offset 7: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}", + DataToRead[0], DataToRead[1], DataToRead[2], DataToRead[3], DataToRead[4], DataToRead[5], DataToRead[6], DataToRead[7], DataToRead[8], DataToRead[9]); + DisplayMessage(DisplayString); + return 0; + } + + // ************************** EncryptUserData ************************************ + // This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 + // It will then do another protection check & decrypt the data + // if you want to encrypt of decrypt string then see comment for WriteBytes and ReadBytes + public static int EncryptUserData() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + byte[] Data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + string DisplayString; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.ENCRYPT_USER_DATA; // standard protection check & encrypt data + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; + dris.rw_length = Data.GetLength(0); + dris.data_crypt_key_num = 1; + + ret_code = DinkeyPro.DDProtCheck(dris, Data); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + // Now decrypt the same data to get the original values + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.DECRYPT_USER_DATA; // standard protection check & read data + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris.rw_length = Data.GetLength(0); + dris.data_crypt_key_num = 1; + + ret_code = DinkeyPro.DDProtCheck(dris, Data); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + DisplayMessage("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + DisplayMessage("Dinkey Dongle protection error"); + return -1; + } + + DisplayString = "decrypted data is: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}", + Data[0], Data[1], Data[2], Data[3], Data[4], Data[5], Data[6], Data[7], Data[8], Data[9]); + DisplayMessage(DisplayString); + return 0; + } + + // !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! + // In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" + // in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm + // but the code can be modified easily to use the 3 encryption parameters. + + // !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm + private static int MyRWAlgorithm(int a, int b, int c, int d, int e, int f, int g, int h) + { + return a ^ b ^ c ^ d ^ e ^ f; + } + + + // !!!! please overwrite this function with the one generated by DinkeyAdd + private static void CryptDRIS(DRIS dris) + { + int i, j, k; + byte[] bigseed = new byte[256]; + byte[] S = new byte[256]; + byte temp, t; + byte[] dris_bytes = new byte[Marshal.SizeOf(dris)]; + + dris.DrisToByteArray(dris, dris_bytes); // convert DRIS to byte array so we can encrypt it + + for (i = 0; i < 256; i += 8) + { + dris.Set4Bytes(bigseed, i, dris.seed1); + dris.Set4Bytes(bigseed, i + 4, dris.seed2); + } + for (i = 0; i < 256; i++) + S[i] = (byte)i; + for (i = 0, j = 0; i < 256; i++) + { + j = (j + S[i] + bigseed[i] + 123) % 256; + temp = S[i]; + S[i] = S[j]; + S[j] = temp; + } + for (i = 0, j = 0, k = 16; k < Marshal.SizeOf(dris); k++) + { + i = (i + 1) % 256; + j = (j + S[i] + 212) % 256; + temp = S[i]; + S[i] = S[j]; + S[j] = temp; + t = (byte)(S[i] + S[j] + 97); + dris_bytes[k] ^= S[t]; + } + dris.ByteArrayToDris(dris_bytes, dris); // convert it back again + return; + } + + // !!!! please overwrite this function with the one generated by DinkeyAdd + private static void CryptApiData(DRIS dris, byte[] data, int length, int alg_answer) + { + int i, j, k; + byte[] bigseed = new byte[256]; + byte[] S = new byte[256]; + byte temp, t; + + for (i = 0; i < 256; i += 8) + { + dris.Set4Bytes(bigseed, i, dris.seed1); + dris.Set4Bytes(bigseed, i + 4, dris.seed2); + } + for (i = 0; i < 256; i++) + S[i] = (byte)i; + for (i = 0, j = 0; i < 256; i++) + { + j = (j + S[i] + bigseed[i] + (alg_answer & 0xff)) % 256; + temp = S[i]; + S[i] = S[j]; + S[j] = temp; + } + for (i = 0, j = 0, k = 0; k < length; k++) + { + i = (i + 1) % 256; + j = (j + S[i] + ((alg_answer >> 8) & 0xff)) % 256; + temp = S[i]; + S[i] = S[j]; + S[j] = temp; + t = (byte)(S[i] + S[j] + ((alg_answer >> 16) & 0xff)); + data[k] ^= S[t]; + } + return; + } + + // **************************** ProtCheckEnc ****************************** + // We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. + public static int ProtCheckEnc() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.PROTECTION_CHECK; // standard protection check + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris, null); + + CryptDRIS(dris); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + DisplayMessage("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + } + + if (dris.prodcode != MY_PRODCODE) + { + DisplayMessage("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle."); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + DisplayMessage("Dinkey Dongle protection error"); + return -1; + } + return 0; + } + + // **************************** ProtCheckWithAlgEnc ************************* + // NB for this to work you must program at least "user algorithm" into the dongle + // NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + // sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite copy source from DinkeyLook. + // We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. + public static int ProtCheckWithAlgEnc() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.EXECUTE_ALGORITHM; // standard protection check & execute algorithm + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number = 1; // execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + // you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.var_a = 1; // sample values + dris.var_b = 2; + dris.var_c = 3; + dris.var_d = 4; + dris.var_e = 5; + dris.var_f = 6; + dris.var_g = 7; + dris.var_h = 8; + + CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris, null); + + CryptDRIS(dris); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + DisplayMessage("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + DisplayMessage("Dinkey Dongle protection error"); + return -1; + } + + // if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + // !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) != dris.alg_answer) + { + DisplayMessage("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine"); + return -1; + } + return 0; + } + + // ************************** WriteBytesEnc *************************** + // This writes the Data 0,1,2,3,4,5,6,7,8,9 to the dongle data area at offset 7 + // In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + // We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + // if you want to write strings then see comment for WriteBytes + public static int WriteBytesEnc() + { + int ret_code, alg_ans; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + byte[] DataToWrite = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.WRITE_DATA_AREA; // standard protection check & write data to dongle + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris.rw_offset = 7; + dris.rw_length = DataToWrite.GetLength(0); + + // calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + // encrypt data we want to write. + CryptApiData(dris, DataToWrite, DataToWrite.GetLength(0), alg_ans); + + CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris, DataToWrite); + + CryptDRIS(dris); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + DisplayMessage("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + DisplayMessage("Dinkey Dongle protection error"); + return -1; + } + return 0; + } + + // ************************ ReadBytesEnc ********************************* + // This reads 10 bytes of data from offset 7 in the dongle data area + // In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + // We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + // if you want to read strings then see comment for ReadBytes + public static int ReadBytesEnc() + { + int ret_code, alg_ans; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + byte[] DataRead = new byte[10]; + string DisplayString; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.READ_DATA_AREA; // standard protection check & read data + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris.rw_offset = 7; + dris.rw_length = DataRead.GetLength(0); + + // calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris, DataRead); + + CryptDRIS(dris); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + DisplayMessage("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + DisplayMessage("Dinkey Dongle protection error"); + return -1; + } + + // decrypt data that was read. + CryptApiData(dris, DataRead, DataRead.GetLength(0), alg_ans); + + DisplayString = "Dinkey Dongle data area, offset 7: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}", + DataRead[0], DataRead[1], DataRead[2], DataRead[3], DataRead[4], DataRead[5], DataRead[6], DataRead[7], DataRead[8], DataRead[9]); + DisplayMessage(DisplayString); + return 0; + } + + // ************************** EncryptUserDataEnc ********************************* + // This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 + // It will then do another protection & decrypt the data + // We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + // if you want to encrypt of decrypt strings then see comment for WriteBytes and ReadBytes + public static int EncryptUserDataEnc() + { + int ret_code, alg_ans; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + DRIS dris2 = new DRIS(); // initialise the DRIS with random values & set the header + byte[] Data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + string DisplayString; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.ENCRYPT_USER_DATA; // standard protection check & encrypt data + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; + dris.rw_length = Data.GetLength(0); + dris.data_crypt_key_num = 1; + + // calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + // encrypt data we pass to our API. + CryptApiData(dris, Data, Data.GetLength(0), alg_ans); + + CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris, Data); + + CryptDRIS(dris); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + // NB use another dris so that we can ensure elements are initialised to different random numbers + dris2.size = Marshal.SizeOf(dris2); + dris2.function = DRIS.DECRYPT_USER_DATA; // standard protection check & read data + dris2.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris2.rw_length = Data.GetLength(0); + dris2.data_crypt_key_num = 1; + + CryptDRIS(dris2); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris2, Data); + + CryptDRIS(dris2); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris2.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris2.sdsn != MY_SDSN) + { + DisplayMessage("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + } + + // later on in your program you can check the return code again + if (dris2.ret_code != 0) + { + DisplayMessage("Dinkey Dongle protection error"); + return -1; + } + + alg_ans = MyRWAlgorithm(dris2.var_a, dris2.var_b, dris2.var_c, dris2.var_d, dris2.var_e, dris2.var_f, dris2.var_g, dris2.var_h); + // decrypt data that was passed to us by the API. + CryptApiData(dris2, Data, Data.GetLength(0), alg_ans); + + DisplayString = "decrypted data is: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}", + Data[0], Data[1], Data[2], Data[3], Data[4], Data[5], Data[6], Data[7], Data[8], Data[9]); + DisplayMessage(DisplayString); + return 0; + } + + // *********************** DisplayNetUsers ******************************* + // This function displays the current network users (for DinkeyNet only). + // The DDProtCheck function must be called before this function is called. + // (Normally you would use DinkeyServer to view the network users but this enables you to do it from the client if you want) + public static int DisplayNetUsers(DRIS dris) + { + string DisplayString; + int num_net_users, extended_error, ret_code, i, max_net_users; + NU_INFO[]? nu_info; + + if (dris.net_users == -1) + max_net_users = 100; // if unlimited network users are allowed then display up to 100 users (for example) + else + max_net_users = dris.net_users; + + if (max_net_users == 0) // no network users are allowed, so nothing to do! + return 0; + + if (dris.model < 3) + { + DisplayMessage("A network dongle has not been detected. Therefore you cannot display the network users."); + return -1; + } + + ret_code = DinkeyPro.DDGetNetUserList(null, out num_net_users, out nu_info, max_net_users, out extended_error); + + if (ret_code != 0) + { + DisplayMessage(String.Format("Error {0}/{1} finding network user information.", ret_code, extended_error)); + } + else + { + DisplayString = String.Format("number of net users: {0}", num_net_users) + Environment.NewLine; + if (nu_info != null) + { + for (i = 0; i < num_net_users; i++) + { + DisplayString += String.Format("{0}. licence: {1}, user: {2}, computer: {3}, ip address: {4}", i + 1, + nu_info[i].licenceName, nu_info[i].userName, nu_info[i].computerName, nu_info[i].ipAddress); + DisplayString += Environment.NewLine; + } + } + DisplayMessage(DisplayString); + } + + return ret_code; + } + + // to display common errors that occur - !!!! you will want to change these messages + private static void DisplayError(int ret_code, int ext_err) + { + string DisplayString; + + switch (ret_code) + { + case 401: + DisplayMessage("Error! No dongles detected!"); + break; + + case 403: + DisplayMessage("Error! A dongle was detected but it was a different type to the one specified in DinkeyAdd."); + break; + + case 404: + DisplayMessage("Error! A dongle was detected but it was a different model to those specified in DinkeyAdd."); + break; + + case 409: + DisplayMessage("Error! The dongle detected has not been programmed by DinkeyAdd."); + break; + + case 410: + DisplayMessage("Error! A dongle was detected but it has a different Product Code to the one specified in DinkeyAdd."); + break; + + case 411: + DisplayMessage("Error! The dongle detected does not contain the licence associated with this program."); + break; + + case 413: + DisplayMessage("Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual."); + break; + + case 417: + DisplayMessage("Error! One or more of the parameters set in the DRIS is incorrect.\nIt could also be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa."); + break; + + case 423: + DisplayMessage("Error! The number of network users has been exceeded."); + break; + + case 435: + DisplayMessage("Error! DinkeyServer has not been detected on the network."); + break; + + case 922: + DisplayMessage("Error! The Software Key has expired."); + break; + + // internal error - cannot load DLL + case -1: + DisplayMessage("Error! Cannot call protection check because DLL is not loaded."); + break; + + default: + DisplayString = "An error occurred checking the dongle. Error: " + String.Format("{0:D}", ret_code) + "\nExtended Error: " + String.Format("{0:D}", ext_err); + DisplayMessage(DisplayString); + break; + } + return; + } + private static void DisplayMessage(string my_message) + { + // !!!! for Console programs use this line + Console.WriteLine(my_message); + // !!!! for Windows programs use this line + // MessageBox.Show(my_message, "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + } +} diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2022/dris.cs b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2022/dris.cs new file mode 100644 index 0000000..0082a03 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/Visual Studio 2022/dris.cs @@ -0,0 +1,361 @@ +// !! this file should not be modified + +using System; +using System.Runtime.InteropServices; // so we can marshal the DRIS as a block of memory +using System.Text; // so we can extract / set strings in the DRIS + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public class DRIS +{ + // the first 4 fields are never encrypted + public byte header1; // should be set to "DRIS" + public byte header2; + public byte header3; + public byte header4; + // inputs + public int size; // size of this structure + public int seed1; // seed for data/dris encryption + public int seed2; // as above + // (maybe encrypted from now on) + public int function; // specify only one function + public int flags; // options for the function selected. To use more than one OR them together: OPTION1 | OPTION2... + public uint execs_decrement; // amount by which to dec execs if we use flag: DEC_MANY_EXECS + public int data_crypt_key_num; // number of the key (1-3) that the dongle uses to encrypt or decrypt user data + public int rw_offset; // offset in the dongle data area to read or write data + public int rw_length; // length of data are to read/write/encrypt/decrypt + public IntPtr DoNotUse; // do not use the rw_data_ptr element use the "Data" argument of the DDProtCheck function + [MarshalAs(UnmanagedType.ByValArray, SizeConst=256)] // NB access this field by using alg_licence_name (see below) + private byte[] _alt_licence_name = { 0 }; // protection check for different licence instead of this one + public int var_a; // variable values for user algorithm + public int var_b; + public int var_c; + public int var_d; + public int var_e; + public int var_f; + public int var_g; + public int var_h; + public int alg_number; // the number of the user algorithm that you want to execute + + // outputs + public int ret_code; // return code from the protection check + public int ext_err; // extended error + public int type; // type of dongle detected. 1 = Pro, 2 = FD + public int model; // model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + public int sdsn; // Software Developer's Serial Number + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] // NB access this field by using prodcode (see below) + private byte[] _prodcode = { 0 }; // product code (null-terminated) + public uint dongle_number; + public int update_number; + public uint data_area_size; // size of the data area in the dongle detected + public int max_alg_num; // number of algorithms in the dongle detected + public int execs; // executions left: -1 indicates 'no limit' + public int exp_day; // expiry day: -1 indicates 'no limit' + public int exp_month; // expiry month: -1 indicates 'no limit' + public int exp_year; // expiry year: -1 indicates 'no limit' + public uint features; // features value + public int net_users; // maximum number of network users for the dongle detected: -1 indicates 'mo limit' + public int alg_answer; // answer to the user algorithm executed with the given variable values + public uint fd_capacity; // capacity of the data area in FD dongle. Currently fixed at ~10MB but may change in the future. + [MarshalAs(UnmanagedType.ByValArray, SizeConst=128)] // NB access this field by using fd_drive (see below) + private byte[] _fd_drive = { 0 }; // fd drive letter (null-terminated) + public int swkey_type; // 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + public int swkey_exp_day; // software key expiry date (if software key detected) + public int swkey_exp_month; + public int swkey_exp_year; + + // NB we have to do it this way because we cannot encrypt strings correctly unless they are byte arrays + public string prodcode + { + get + { + StringBuilder sb = new StringBuilder(12); + foreach (byte b in _prodcode) + { + if (b == 0) + return sb.ToString(); + else + sb.Append((char)b); + } + return sb.ToString(); + } + } + + public string fd_drive + { + get + { + StringBuilder sb = new StringBuilder(128); + foreach (byte b in _fd_drive) + { + if (b == 0) + return sb.ToString(); + else + sb.Append((char)b); + } + return sb.ToString(); + } + } + + // NB we have to do it this way because we cannot encrypt strings correctly unless they are byte arrays + public string alt_licence_name + { + set + { + int i; + StringBuilder sb = new StringBuilder(value, 256); + for (i=0; i> 8) & 0xff); + data[offset+2] = (byte)((value >> 16) & 0xff); + data[offset+3] = (byte)((value >> 24) & 0xff); + return; + } + + // converts to DRIS structure to a byte array (so we can do encryption) + public void DrisToByteArray(DRIS dris, byte[] data) + { + GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned); + Marshal.StructureToPtr(dris, MyGC.AddrOfPinnedObject(), false); + MyGC.Free(); + return; + } + + // converts a byte array to the DRIS structure (so we can do encryption) + public void ByteArrayToDris(byte[] data, DRIS dris) + { + GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned); + Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), dris); + MyGC.Free(); + return; + } + + // to make a new instance of this class, initialise every element to a random value and then set the header + public DRIS() + { + Random rnd = new Random(); + Byte[] temp = new Byte[Marshal.SizeOf(this)]; + rnd.NextBytes(temp); + ByteArrayToDris(temp, this); + this.header1 = (byte)'D'; + this.header2 = (byte)'R'; + this.header3 = (byte)'I'; + this.header4 = (byte)'S'; + } + + // functions - must specify only one + public const int PROTECTION_CHECK = 1; // checks for dongle, check program params... + public const int EXECUTE_ALGORITHM = 2; // protection check + calculate answer for specified algorithm with specified inputs + public const int WRITE_DATA_AREA = 3; // protection check + writes dongle data area + public const int READ_DATA_AREA = 4; // protection check + reads dongle data area + public const int ENCRYPT_USER_DATA = 5; // protection check + the dongle will encrypt user data + public const int DECRYPT_USER_DATA = 6; // protection check + the dongle will decrypt user data + public const int FAST_PRESENCE_CHECK = 7; // checks for the presence of the correct dongle only with minimal security, no flags allowed. + public const int STOP_NET_USER = 8; // stops a network user (a protection check is NOT performed) + + // flags - can specify as many as you like + public const int DEC_ONE_EXEC = 1; // decrement execs by 1 + public const int DEC_MANY_EXECS = 2; // decrement execs by number specified in execs_decrement + public const int START_NET_USER = 4; // starts a network user + public const int USE_FUNCTION_ARGUMENT = 16; // use the extra argument in the function for pointers + public const int CHECK_LOCAL_FIRST = 32; // always look in local ports before looking in network ports + public const int CHECK_NETWORK_FIRST = 64; // always look on the network before looking in local ports + public const int USE_ALT_LICENCE_NAME = 128; // use name specified in alt_licence_name instead of the default one + public const int DONT_SET_MAXDAYS_EXPIRY = 256; // if the max days expiry date has not been calculated then do not do it this time + public const int MATCH_DONGLE_NUMBER = 512; // restrict the search to match the dongle number specified in the DRIS + public const int DONT_RETURN_FD_DRIVE = 1024; // if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct NU_INFO +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string licenceName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=50)] + public string userName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string computerName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=16)] + public string ipAddress; +} + +// DDProtCheck + +// Windows 32-bit protection check (loads 32-bit DLL) +class DDProtCheckWin32 +{ + [DllImport("dpwin32.dll", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[]? data); +} + +// Windows 64-bit protection check (loads 64-bit DLL) +class DDProtCheckWin64 +{ + [DllImport("dpwin64.dll", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[]? data); +} + +// Linux 64-bit protection check (loads 64-bit so) (NB only 64-bit Linux is supported by .NET Core) +class DDProtCheckLin64 +{ + [DllImport("dplin64.so", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[]? data); +} + +// Mac 64-bit protection check (loads 64-bit dylib) (NB only x64 Mac code is supported by .NET Core) (NB we found that the release module dpmac64.dylib crashed) +class DDProtCheckMac64 +{ + [DllImport("dpmac64debug.dylib", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[]? data); +} + +// DDGetNetUserList + +// Windows 32-bit get network user info (loads 32-bit DLL) +class DDGetNetUserListWin32 +{ + [DllImport("dpwin32.dll", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string? licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// Windows 64-bit get network user info (loads 64-bit DLL) +class DDGetNetUserListWin64 +{ + [DllImport("dpwin64.dll", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string? licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// Linux 64-bit get network user info (loads 64-bit DLL) +class DDGetNetUserListLin64 +{ + [DllImport("dplin64.so", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string? licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// call our API - we only want to load the correct DLL for the OS and bit-ness of the computer. The other DLLs may not exist. +class DinkeyPro +{ + // calls the DDProtCheck function in the appropriate DLL + public static int DDProtCheck(DRIS dris, byte[]? data) + { + int ret_code = -1; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // method valid from .NET Core 1.0 and .NET framework 4.7 + { + if (Environment.Is64BitProcess) // method valid from .NET Core 2.0 and .NET framework 4.0 + { + try + { + ret_code = DDProtCheckWin64.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + DisplayMessage("Error! Cannot find dpwin64.dll. This should be in the same folder as DllTest."); + } + } + else + { + try + { + ret_code = DDProtCheckWin32.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + DisplayMessage("Error! Cannot find dpwin32.dll. This should be in the same folder as DllTest."); + } + } + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + try + { + ret_code = DDProtCheckLin64.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + DisplayMessage("Error! Cannot find dplin64.so. This should be in the same folder as DllTest."); + } + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + try + { + ret_code = DDProtCheckMac64.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + DisplayMessage("Error! Cannot find dpmac64debug.dylib. This should be in the same folder as DllTest."); + } + } + else + { + DisplayMessage("Error! Dinkey Pro/FD not supported on this OS."); + } + return ret_code; + } + + public static int DDGetNetUserList(string? licence_name, out int num_net_users, out NU_INFO[]? nu_info, int num_info_structs, out int extended_error) + { + int ret_code = -1; + int i; + extended_error = num_net_users = 0; + byte[] nu_info_bytes = new byte[num_info_structs * Marshal.SizeOf(typeof(NU_INFO))]; + byte[] nu_info_one_struct = new byte[Marshal.SizeOf(typeof(NU_INFO))]; + GCHandle MyGC; + nu_info = null; + + // call the function and get info as a byte array + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + if (Environment.Is64BitProcess) + ret_code = DDGetNetUserListWin64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + else + ret_code = DDGetNetUserListWin32.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + ret_code = DDGetNetUserListLin64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + DisplayMessage("Error! This function is not supported in the Mac debug module."); + } + + if (ret_code != 0) + return ret_code; + + // convert byte array to an array of structs + nu_info = new NU_INFO[num_net_users]; + for (i=0; i". + +If you publish a "single-file executable" file then although this file can be protected we do not recommend +it because it is not secure. (The single-file executable just comprises a stub loader with your compiled +assemblies and configuration files appended to the end of the executable. These files are just considered as +data appended to the executable file in a custom format and therefore are not protected. When you shell +protect your executable you are just protecting the loader but not your assemblies). Instead you need to +build your code and then add protection before publishing. You should protect your assemblies in the obj +directory (and in the platform type you specified) e.g. obj/Release/net6.0/win-x64, because the publish +process takes your assemblies from this location when it builds the single-file executable. You will also +need to distribute all the extra files that DinkeyAdd generates. e.g. .dp64.dll. + +If you publish using the ReadytoRun compilation this will not work because it includes mixtures of .NET +assemblies and native code and the .NET Shell Method does not support that. + + +Visual Studio Installer Projects Extension +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can use this extension to create a project in your solution that will create an installation program / msi +file. Please note that after your application has been built you need to protect it with DinkeyAdd before you +can invoke the installer project. You can do this manually by building your application project (not the entire +solution); then adding protection to your application using DinkeyAdd; then building your installer project. +Or you can automate this by executing DinkeyAddCmd as a post-build step. For example: +"c:\program files (x86)\Dinkey Pro 7.6.0\DinkeyAdd\DinkeyAddCmd.exe" c:\adir\mydapf.dapfj /a2 + +Note - if you specify "primary output" in your installer project then it will take the files from +obj\Release\net5.0 (for example), rather than bin\Release\net5.0. So, you need to add protection to your files +in this folder. + +Note - you will also need to include in your installer project all of the output files mentioned by DinkeyAdd. +e.g. .dp64.dll diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/which project should I use.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/which project should I use.txt new file mode 100644 index 0000000..4f29c54 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C#/Runtime/which project should I use.txt @@ -0,0 +1,23 @@ +Which Project should I use? +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Visual Studio 2002 project will work for any version of Visual Studio from +Visual Studio 2002 to Visual Studio 2019. This project is a Windows Form +application targeting the .NET 4 Framework. However, it can be easily adapted to +target .NET Core or .NET 5 (and higher). The C# code is written in C# version 1. + +The Visual Studio 2022 project will work with Visual Studio 2022 (and higher). +It is a Console application targeting .NET 6 and using C# version 10. If you want +to target earlier versions of .NET or C# then use the Visual Studio 2002 project. + +The C# code is very similar in both projects. However, C# v8 required changes to +account for possible Null reference exceptions. + +Visual Studio 2019 was the first version of VS to support C# v8. However, null +reference warnings are turned off by default, so you will get warnings if you +compile the VS2022 C# code. + +On the other hand in Visual Studio 2022 null reference warnings are turned on by +default so you will get warnings if you compile the VS2002 C# code. + +Whichever project you use always read the "readme" file for important instructions. \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder XE3/DinkeyChange/ChangeTest.cbproj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder XE3/DinkeyChange/ChangeTest.cbproj new file mode 100644 index 0000000..45d5ece --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder XE3/DinkeyChange/ChangeTest.cbproj @@ -0,0 +1,224 @@ + + + {2960c946-f28b-4c7c-9c85-55a82b8728d0} + Release + None + 14.4 + True + Win32 + 3 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + true + Cfg_2 + true + true + + + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + exe + System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) + 2057 + true + JPHNE + true + ..\..\..\C;..\..\Visual Studio 5\DinkeyChange;..\..\C++Builder\DinkeyChange;$(ILINK_ObjectSearchPath) + true + true + CppGuiApplication + vcl.bpi;rtl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;$(PackageImports) + false + ..\..\;$(BDS)\include;..\..\..\C;..\..\Visual Studio 5\DinkeyChange;..\..\C++Builder\DinkeyChange;$(IncludePath) + rtl.lib;vcl.lib + ..\..\;$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\..\..\C;..\..\Visual Studio 5\DinkeyChange;$(ILINK_LibraryPath) + + + true + $(BDS)\bin\default_app.manifest + 1033 + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + NO_STRICT;$(Defines) + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + + + $(BDS)\bin\default_app.manifest + 1033 + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + true + + + false + false + true + true + false + true + None + DEBUG;$(DCC_Define) + true + Debug + true + true + $(BDS)\lib\debug;$(ILINK_LibraryPath) + true + Full + true + + + _DEBUG;$(Defines) + + + _DEBUG;$(Defines) + + + Release + $(BDS)\lib\release;$(ILINK_LibraryPath) + None + + + rtl.bpi;vcl.bpi + NDEBUG;$(Defines) + + + rtl.bpi;vcl.bpi + NDEBUG;$(Defines) + + + CPlusPlusBuilder.Personality.12 + CppGuiApplication + + + + False + False + 1 + 0 + 0 + 0 + False + False + False + False + False + 2057 + 1252 + + + + + 1.0.0.0 + + + + + + 1.0.0.0 + + + + + + + + + False + + + + + + + False + + False + + True + False + + + + + + + + False + True + True + + + + False + True + True + + + 12 + + + + +
ChangeTest.res
+ 1 +
+ + 2 + + + 0 + + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + +
+ +
diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder XE3/DinkeyChange/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder XE3/DinkeyChange/README.txt new file mode 100644 index 0000000..1bf7531 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder XE3/DinkeyChange/README.txt @@ -0,0 +1,50 @@ +ChangeTest - sample code to call DinkeyChange.dll in C++ Builder XE3 (and more recent) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in C++ Builder XE3 but will work in more recent +versions (they will upgrade the Project to the latest version). For earlier versions +you should use the project in the C++Builder folder. + +The source files in the project are: + +File name Folder Description +changetest.c Samples\c main source code file for C +changetest.h Samples\c contains some useful constants +DinkeyChange_borland.lib Samples\c\import_libs contains the function definitions for DinkeyChange.dll +DinkeyChange64_borland.a Samples\c\import_libs contains the function definitions for DinkeyChange64.dll +changetest_imports.c Samples\c\C++Builder XE3\DinkeyChange contains code to link the correct import library +changetest.rc Samples\c\C++Builder\DinkeyChange resource for main dialog +resource.h Samples\c\C++Builder\DinkeyChange header file for resource + +Note that the source paths are structured to minimise files. If you want to +move this project the references to these files will probably be no longer valid. + +The project can compile to both 32-bit and 64-bit platforms and will link the appropriate +import library. For 32-bit you will call DinkeyChange.dll and for 64-bit you will call +DinkeyChange64.dll. + +The sample code contains 7 functions. Just use which ever functions are most +appropriate and customise in your own way. The sample code is just a guide. +As none of the parameters are sensitive then there is no need to implement +strong security in calling DinkeyChange. + +Note - you will not be able to debug your program after DinkeyChange has been called. +Our strong anti-debug code will cause the debugger to throw an exception. However, +if you do need to debug your code you can use our debug module for DinkeyChange: +DinkeyChangeDebug.dll (or 64-bit version). So, you can use DinkeyChange.dll +for your release build and DinkeyChangeDebug.dll for your debug build. + +Note - the 32-bit DinkeyChange_borland.lib was created using Borland's IMPLIB tool. If there is a problem +with the file we provide you can create your own by running (for example): + +c:\program files\CodeGear\Rad Studio 5.0\bin\implib import_libs\DinkeyChange_borland.lib DinkeyChange.dll + +(This assumes that the current directory is the Samples\C directory). + +Note - the 64-bit DinkeyChange64_borland.a was created using Borland's MKEXP tool. If there is a problem +with the file we provide you can create your own by running (for example): +(from a RAD Studio Command Prompt) + +mklib import_libs\DinkeyChange64_borland.a DinkeyChange64.dll + +(This assumes that the current directory is the Samples\C directory). \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder XE3/DinkeyChange/changetest_imports.c b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder XE3/DinkeyChange/changetest_imports.c new file mode 100644 index 0000000..c2f940b --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder XE3/DinkeyChange/changetest_imports.c @@ -0,0 +1,12 @@ +// this file exists just to conditionally link in the correct import library +// (32-bit or 64-bit depending on the build) +// It is not very elegant but we cannot see any other way of doing it. +// If you know a better way of doing this then please let us know! + +#ifdef __BORLANDC__ + #ifdef __clang__ + #pragma link "..\\..\\import_libs\\DinkeyChange64_borland.a" // link 64-bit import library + #else + #pragma link "..\\..\\import_libs\\DinkeyChange_borland.lib" // link 32-bit import library + #endif +#endif diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder XE3/Runtime/DllTest.cbproj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder XE3/Runtime/DllTest.cbproj new file mode 100644 index 0000000..9eeadc1 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder XE3/Runtime/DllTest.cbproj @@ -0,0 +1,229 @@ + + + {139221f8-7474-4beb-9d31-ff91c75d2342} + Release + None + 14.4 + True + Win64 + 3 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + true + Cfg_2 + true + true + + + System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + exe + 2057 + true + JPHNE + true + ..\..\..\C;$(ILINK_ObjectSearchPath) + true + true + CppGuiApplication + vcl.bpi;rtl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;$(PackageImports) + false + ..\..\;$(BDS)\include;..\..\..\C;$(IncludePath) + rtl.lib;vcl.lib + ..\..\;$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\..\..\C;$(ILINK_LibraryPath) + + + true + NO_STRICT;$(Defines) + 1033 + $(BDS)\bin\default_app.manifest + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + + + true + 1033 + $(BDS)\bin\default_app.manifest + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + + + false + false + true + true + false + true + None + DEBUG;$(DCC_Define) + true + Debug + true + true + $(BDS)\lib\debug;$(ILINK_LibraryPath) + true + Full + true + + + 1033 + true + rtl.bpi;vcl.bpi + _DEBUG;$(Defines) + + + _DEBUG;$(Defines) + + + Release + $(BDS)\lib\release;$(ILINK_LibraryPath) + None + + + rtl.bpi;vcl.bpi + NDEBUG;$(Defines) + + + rtl.bpi;vcl.bpi + NDEBUG;$(Defines) + + + CPlusPlusBuilder.Personality.12 + CppGuiApplication + + + + False + False + 1 + 0 + 0 + 0 + False + False + False + False + False + 2057 + 1252 + + + + + 1.0.0.0 + + + + + + 1.0.0.0 + + + + + + + + + False + + + + + + + False + + False + + True + False + + + + + + + + False + True + True + + + Embarcadero C++Builder Office 2000 Servers Package + Embarcadero C++Builder Office XP Servers Package + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + False + True + True + + + 12 + + + + + 0 + + + 3 + + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + + + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder XE3/Runtime/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder XE3/Runtime/README.txt new file mode 100644 index 0000000..11ca64c --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder XE3/Runtime/README.txt @@ -0,0 +1,71 @@ +Sample code to call Runtime Modules in C++ Builder XE3 (or more recent) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in C++ Builder XE3 but will work in more recent +versions (they will upgrade the Project to the latest version). For earlier versions +you should use the C++ Builder sample. + +The source files in the project are: + +File name Folder Description +apitest.c Samples\c main source code file for C +dris.h Samples\c contains the DRIS structure +dlltest_imports.c Samples\c\C++Builder\Runtime contains code to link the correct import library +dpwin32_borland.lib Samples\c\import_libs contains the function definitions for dpwin32.dll +dpwin64_borland.a Samples\c\import_libs contains the function definitions for dpwin64.dll + +Note that the source paths are structured to minimise files. If you want to +move this project the references to these files will probably be no longer valid. + +The DllTest project uses the dynamic runtime library (e.g. dpwin32.dll or dpwin64.dll). + +NB There is no ObjTest project because currently there is no 64-bit static module for 64-bit C++ Builder. + +The project can compile to both 32-bit and 64-bit platforms and will link the appropriate +import library. For 32-bit builds you need to protect dpwin32.dll and for 64-bit builds you +need to protect dpwin64.dll. The protected DLL will need to be in the same folder as your +compiled program for it to run correctly. + +The sample code contains 10 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. + +NB You need to protect dpwin32.dll (dpwin64.dll) and *not* your program. +Because your program is linked to the DLL it is protected. + +Note - once dpwin32.dll (dpwin64.dll) is protected you will not be able to debug your program - +after our API has been called. Our strong anti-debug code will cause the debugger to +throw an exception. If you do want to debug your code then you can use the debug module: +dpwin32debug.dll (dpwin64debug.dll), but this should not be used for release. NB You will need +to link to the dpwin32debug_borland.lib (dpwin64debug_borland.a) import library if you use the +debug module. Edit dlltest_imports.c to do this. +(See readme.txt in samples\c for restrictions concerning the debug module). + +Note - the 32-bit dpwin32_borland.lib was created using Borland's IMPLIB tool. If there is a problem +with the file we provide you can create your own by running (for example): + +c:\program files\CodeGear\Rad Studio\5.0\bin\implib import_libs\dpwin32_borland.lib dpwin32.dll + +(This assumes that the current directory is the Samples\C directory). + +Note - the 64-bit dpwin64_borland.a was created using Borland's MKEXP tool. If there is a problem +with the file we provide you can create your own by running (for example): +(from a RAD Studio Command Prompt) + +mklib import_libs\dpwin64_borland.lib dpwin64.dll + +(This assumes that the current directory is the Samples\C directory). diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder XE3/Runtime/dlltest_imports.c b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder XE3/Runtime/dlltest_imports.c new file mode 100644 index 0000000..b9d92c5 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder XE3/Runtime/dlltest_imports.c @@ -0,0 +1,12 @@ +// this file exists just to conditionally link in the correct import library +// (32-bit or 64-bit depending on the build) +// It is not very elegent but we cannot see any other way of doing it. +// If you know a better then please let us know! + +#ifdef __BORLANDC__ + #ifdef __clang__ + #pragma link "..\\..\\import_libs\\dpwin64_borland.a" // link 64-bit import library + #else + #pragma link "..\\..\\import_libs\\dpwin32_borland.lib" // link 32-bit import library + #endif +#endif diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder/DinkeyChange/ChangeTest.cbproj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder/DinkeyChange/ChangeTest.cbproj new file mode 100644 index 0000000..7ec1574 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder/DinkeyChange/ChangeTest.cbproj @@ -0,0 +1,143 @@ + + + + {2960c946-f28b-4c7c-9c85-55a82b8728d0} + Debug + + + true + + + true + true + Base + + + true + true + Base + + + true + NO_STRICT + JPHNE + true + ..\..\..\C;..\..\Visual Studio 5\DinkeyChange + true + true + CppGuiApplication + vcl.bpi;rtl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi + false + $(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\..\..\C;..\..\Visual Studio 5\DinkeyChange + rtl.lib;vcl.lib + $(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\..\..\C;..\..\Visual Studio 5\DinkeyChange + + + false + false + _DEBUG;$(Defines) + true + true + false + true + None + DEBUG + true + Debug + true + true + $(BDS)\lib\debug;$(ILINK_LibraryPath) + true + Full + true + + + NDEBUG;$(Defines) + Release + $(BDS)\lib\release;$(ILINK_LibraryPath) + None + + + CPlusPlusBuilder.Personality + CppGuiApplication + + + False + False + 1 + 0 + 0 + 0 + False + False + False + False + False + 2057 + 1252 + + + + + 1.0.0.0 + + + + + + 1.0.0.0 + + + + + + + + + False + + + + + + + False + + False + + True + False + + + + + + + + False + True + True + + + + + + + 0 + + + ChangeTest.rc +
ChangeTest.res
+ 1 +
+ + 2 + + + Cfg_1 + + + Cfg_2 + +
+
\ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder/DinkeyChange/ChangeTest.rc b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder/DinkeyChange/ChangeTest.rc new file mode 100644 index 0000000..53a76c2 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder/DinkeyChange/ChangeTest.rc @@ -0,0 +1,35 @@ +#include "resource.h" + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 215, 358 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "ChangeTest" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "Get Dongle Information...",IDC_DONGLEINFO,45,14,119,14 + LTEXT "Enter Diagnostic filename:",IDC_STATIC,7,40,201,8 + EDITTEXT IDC_DIAG_PATH,7,49,201,14,ES_AUTOHSCROLL + PUSHBUTTON "Write Diagnostics to File",IDC_GETDIAGS,45,68,119,14 + LTEXT "Enter short Update Code here:",IDC_STATIC,7,96,201,8 + EDITTEXT IDC_UPDATE_CODE_STRING,7,106,201,14,ES_AUTOHSCROLL + PUSHBUTTON "Make Changes",IDC_DO_UPDATE_CODE_STRING,69,125,68,14 + LTEXT "Enter path to Update Code file:",IDC_STATIC,7,153,201,8 + EDITTEXT IDC_UPDATE_CODE_FILE,7,163,201,14,ES_AUTOHSCROLL + PUSHBUTTON "Make Changes",IDC_DO_UPDATE_CODE_FILE,68,183,68,14 + PUSHBUTTON "Restore Dinkey FD Lite",IDC_RESTORE_FD_LITE,45,215,119,14 + PUSHBUTTON "Get Machine ID",IDC_GET_MACHINE_ID,7,245,95,14 + EDITTEXT IDC_MACHINE_ID,110,245,98,14,ES_UPPERCASE + PUSHBUTTON "Download Temporary Software Key",IDC_GET_TEMP_SWKEY,35,275,139,14 + LTEXT "Demo Software Key Product Code:",IDC_STATIC,7,305,201,8 + EDITTEXT IDC_SWKEY_PRODCODE,7,314,201,14,ES_AUTOHSCROLL | ES_UPPERCASE + PUSHBUTTON "Download Demo Software Key",IDC_GET_DEMO_SWKEY,35,333,139,14 +END \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder/DinkeyChange/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder/DinkeyChange/README.txt new file mode 100644 index 0000000..4ed0d7e --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder/DinkeyChange/README.txt @@ -0,0 +1,35 @@ +ChangeTest - sample code to call DinkeyChange.dll in C++ Builder +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in C++ Builder 2007 but will work in more recent +versions (they will upgrade the Project to the latest version). For earlier versions +you can make your own project using the files listed below. + +The source files in the project are: + +File name Folder Description +changetest.c Samples\c main source code file for C +changetest.h Samples\c contains some useful constants +DinkeyChange_borland.lib Samples\c\import_libs contains the function definitions for DinkeyChange.dll +ChangeTest.rc Samples\c\C++Builder\DinkeyChange resource for main dialog + +Note that the source paths are structured to minimise files. If you want to +move this project the references to these files will probably be no longer valid. + +The sample code contains 7 functions. Just use which ever functions are most +appropriate and customise in your own way. The sample code is just a guide. +As none of the parameters are sensitive then there is no need to implement +strong security in calling DinkeyChange. + +Note - you will not be able to debug your program after DinkeyChange has been called. +Our strong anti-debug code will cause the debugger to throw an exception. However, +if you do need to debug your code you can use our debug module for DinkeyChange: +DinkeyChangeDebug.dll. So, you can use DinkeyChange.dll for your release build +and DinkeyChangeDebug.dll for your debug build. + +Note - the DinkeyChange_borland.lib was created using Borland's IMPLIB tool. If there is a problem +with the file we provide you can create your own by running (for example): + +c:\program files\CodeGear\Rad Studio 5.0\bin\implib import_libs\DinkeyChange_borland.lib DinkeyChange.dll + +(This assumes that the current directory is the Samples\C directory). diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder/DinkeyChange/resource.h b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder/DinkeyChange/resource.h new file mode 100644 index 0000000..422b9b5 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder/DinkeyChange/resource.h @@ -0,0 +1,16 @@ +// Used by ChangeTest.rc + +#define IDD_DIALOG1 101 +#define IDC_DONGLEINFO 1000 +#define IDC_UPDATE_CODE_STRING 1001 +#define IDC_DO_UPDATE_CODE_STRING 1002 +#define IDC_DIAG_PATH 1003 +#define IDC_GETDIAGS 1004 +#define IDC_UPDATE_CODE_FILE 1005 +#define IDC_DO_UPDATE_CODE_FILE 1006 +#define IDC_RESTORE_FD_LITE 1007 +#define IDC_GET_MACHINE_ID 1008 +#define IDC_MACHINE_ID 1009 +#define IDC_GET_TEMP_SWKEY 1010 +#define IDC_SWKEY_PRODCODE 1011 +#define IDC_GET_DEMO_SWKEY 1012 diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder/Runtime/DllTest.cbproj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder/Runtime/DllTest.cbproj new file mode 100644 index 0000000..f989234 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder/Runtime/DllTest.cbproj @@ -0,0 +1,138 @@ + + + + {139221f8-7474-4beb-9d31-ff91c75d2342} + Debug + + + true + + + true + true + Base + + + true + true + Base + + + true + NO_STRICT + JPHNE + true + ..\..\..\C + true + true + CppGuiApplication + vcl.bpi;rtl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi + false + $(BDS)\include;$(BDS)\include\dinkumware;..\..\..\C + rtl.lib;vcl.lib + $(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\..\..\C + + + false + false + _DEBUG;$(Defines) + true + true + false + true + None + DEBUG + true + Debug + true + true + $(BDS)\lib\debug;$(ILINK_LibraryPath) + true + Full + true + + + NDEBUG;$(Defines) + Release + $(BDS)\lib\release;$(ILINK_LibraryPath) + None + + + CPlusPlusBuilder.Personality + CppGuiApplication + + + False + False + 1 + 0 + 0 + 0 + False + False + False + False + False + 2057 + 1252 + + + + + 1.0.0.0 + + + + + + 1.0.0.0 + + + + + + + + + False + + + + + + + False + + False + + True + False + + + + + + + + False + True + True + + + + + + + 0 + + + 1 + + + Cfg_1 + + + Cfg_2 + + + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder/Runtime/ObjTest.cbproj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder/Runtime/ObjTest.cbproj new file mode 100644 index 0000000..4f52f86 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder/Runtime/ObjTest.cbproj @@ -0,0 +1,138 @@ + + + + {e6943fc9-7514-48ab-91bc-57e69cb8cb4f} + Debug + + + true + + + true + true + Base + + + true + true + Base + + + true + NO_STRICT + JPHNE + true + ..\..\..\C + true + true + CppGuiApplication + vcl.bpi;rtl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi + false + $(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\..\..\C + rtl.lib;vcl.lib + $(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\..\..\C + + + false + false + _DEBUG;$(Defines) + true + true + false + true + None + DEBUG + true + Debug + true + true + $(BDS)\lib\debug;$(ILINK_LibraryPath) + true + Full + true + + + NDEBUG;$(Defines) + Release + $(BDS)\lib\release;$(ILINK_LibraryPath) + None + + + CPlusPlusBuilder.Personality + CppGuiApplication + + + False + False + 1 + 0 + 0 + 0 + False + False + False + False + False + 2057 + 1252 + + + + + 1.0.0.0 + + + + + + 1.0.0.0 + + + + + + + + + False + + + + + + + False + + False + + True + False + + + + + + + + False + True + True + + + + + + + 0 + + + 1 + + + Cfg_1 + + + Cfg_2 + + + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder/Runtime/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder/Runtime/README.txt new file mode 100644 index 0000000..58a31ee --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/C++Builder/Runtime/README.txt @@ -0,0 +1,57 @@ +Sample code to call Runtime Modules in C++ Builder +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in C++ Builder 2007 but will work in more recent +versions (they will upgrade the Project to the latest version). For earlier versions +you can make your own project using the files listed below. + +The source files in the project are: + +File name Folder Description +apitest.c Samples\c main source code file for C +dris.h Samples\c contains the DRIS structure +dpwin32_omf.obj Samples\c\object_modules static object modules +dpwin32_borland.lib Samples\c\import_libs contains the function definitions for dpwin32.dll + +Note that the source paths are structured to minimise files. If you want to +move this project the references to these files will probably be no longer valid. + +The ObjTest project links to the static runtime library module (e.g dpwin32_omf.obj) + +The DllTest project uses the dynamic runtime library (e.g. dpwin32.dll). + +The sample code contains 10 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. + +Note - if you are link the static module dpwin32_omf.obj then you should protect your program. +If you are linking to dpwin32.dll then you need to protect dpwin32.dll and *not* your program. +Because your program is linked to the DLL it is protected. The protected DLL will need to be +in the same folder as your compiled program for it to run correctly. + +Note - once your program (or dpwin32.dll) is protected you will not be able to debug +your program - after our API has been called. Our strong anti-debug code will cause +the debugger to throw an exception. If you do want to debug your code then you can +use our debug module: dpwin32_omf_debug.obj (or dpwin32debug.dll), but these should not be +used for release. See readme.txt in samples\c for restrictions concerning the debug module. + +Note - the dpwin32_borland.lib was created using Borland's IMPLIB tool. If there is a problem +with the file we provide you can create your own by running (for example): + +c:\program files\CodeGear\Rad Studio\5.0\bin\implib import_libs\dpwin32_borland.lib dpwin32.dll + +(This assumes that the current directory is the Samples\C directory). diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Dev-C++/DinkeyChange/ChangeTest.dev b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Dev-C++/DinkeyChange/ChangeTest.dev new file mode 100644 index 0000000..97e70da --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Dev-C++/DinkeyChange/ChangeTest.dev @@ -0,0 +1,68 @@ +[Project] +FileName=ChangeTest.dev +Name=ChangeTest +UnitCount=2 +Type=1 +Ver=1 +ObjFiles= +Includes= +Libs= +PrivateResource=ChangeTest_private.rc +ResourceIncludes= +MakeIncludes= +Compiler= +CppCompiler= +Linker=../../import_libs/libDinkeyChange.a_@@_ +IsCpp=0 +Icon= +ExeOutput= +ObjectOutput= +OverrideOutput=0 +OverrideOutputName=ChangeTest.exe +HostApplication= +Folders= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000000000000000000 + +[Unit1] +FileName=..\..\changetest.c +CompileCpp=0 +Folder=ChangeTest +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + +[Unit2] +FileName=..\..\Visual Studio 5\DinkeyChange\ChangeTest.rc +Folder=ChangeTest +Compile=1 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Dev-C++/DinkeyChange/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Dev-C++/DinkeyChange/README.txt new file mode 100644 index 0000000..9946688 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Dev-C++/DinkeyChange/README.txt @@ -0,0 +1,30 @@ +ChangeTest - sample code to call DinkeyChange.dll in Dev-C++ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written using Dev C++ 4.9.9.2 but should also work in other +versions (for olders version you may have to create the project yourself). + +The source files in the project are: + +File name Folder Description +changetest.c Samples\c main source code file for C +changetest.h Samples\c contains some useful constants +libDinkeyChange.a Samples\c\import_libs contains the function definitions for DinkeyChange.dll +changetest.rc Samples\c\Visual Studio 5\DinkeyChange resource for main dialog + +Note that the source paths are structured to minimise files. If you want to +move this project the references to these files will probably be no longer valid. + +The sample code contains 7 functions. Just use which ever functions are most +appropriate and customise in your own way. The sample code is just a guide. +As none of the parameters are sensitive then there is no need to implement +strong security in calling DinkeyChange. + +Note - you will not be able to debug your program after DinkeyChange has been called. +Our strong anti-debug code will cause the debugger to throw an exception. However, +if you do need to debug your code you can use our debug module for DinkeyChange: +DinkeyChangeDebug.dll. So, you can use DinkeyChange.dll for your release build +and DinkeyChangeDebug.dll for your debug build. + +Note - if you are interested in creating the libDinkeyChange.a import library yourself +then read the notes in the MinGW\Runtime\readme.txt file (Dev-C++ uses the minGW compiler). diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Dev-C++/Runtime/DllTest.dev b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Dev-C++/Runtime/DllTest.dev new file mode 100644 index 0000000..a6d0c6f --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Dev-C++/Runtime/DllTest.dev @@ -0,0 +1,59 @@ +[Project] +FileName=DllTest.dev +Name=DllTest +UnitCount=1 +Type=1 +Ver=1 +ObjFiles= +Includes= +Libs= +PrivateResource= +ResourceIncludes= +MakeIncludes= +Compiler= +CppCompiler= +Linker=../../import_libs/libdpwin32.a_@@_ +IsCpp=0 +Icon= +ExeOutput= +ObjectOutput= +OverrideOutput=0 +OverrideOutputName=DllTest.exe +HostApplication= +Folders= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000000000000000000 + +[Unit1] +FileName=..\..\apitest.c +CompileCpp=0 +Folder=DllTest +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Dev-C++/Runtime/ObjTest.dev b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Dev-C++/Runtime/ObjTest.dev new file mode 100644 index 0000000..9866aec --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Dev-C++/Runtime/ObjTest.dev @@ -0,0 +1,59 @@ +[Project] +FileName=ObjTest.dev +Name=ObjTest +UnitCount=1 +Type=1 +Ver=1 +ObjFiles= +Includes= +Libs= +PrivateResource= +ResourceIncludes= +MakeIncludes= +Compiler= +CppCompiler= +Linker=../../object_modules/dpwin32_coff.obj_@@_ +IsCpp=0 +Icon= +ExeOutput= +ObjectOutput= +OverrideOutput=0 +OverrideOutputName=ObjTest.exe +HostApplication= +Folders= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000000000000000000 + +[Unit1] +FileName=..\..\apitest.c +CompileCpp=0 +Folder=DllTest +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Dev-C++/Runtime/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Dev-C++/Runtime/README.txt new file mode 100644 index 0000000..fe93c27 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Dev-C++/Runtime/README.txt @@ -0,0 +1,53 @@ +Sample code to call dpwin32_coff.obj OR dpwin32.dll using Dev C++ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written using Dev C++ 4.9.9.2 but should also work in other +versions (for olders version you may have to create the project yourself). + +The source files in the project are: + +File name Folder Description +apitest.c Samples\c main source code file for C +dris.h Samples\c contains the DRIS structure +dpwin32_coff.obj Samples\c\object_modules static object modules e.g. dpwin32_coff.obj +libdpwin32.a Samples\c\import_libs contains the function definitions for dpwin32.dll + +Note that the source paths are structured to minimise files. If you want to +move this project the references to these files will probably be no longer valid. + +The ObjTest project links to the static runtime library module (e.g dpwin32_coff.obj) + +The DllTest project uses the dynamic runtime library (e.g. dpwin32.dll). + +The sample code contains 10 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. + +Note - if you are link the static module dpwin32_coff.obj then you should protect your program. +If you are linking to dpwin32.dll then you need to protect dpwin32.dll and *not* your program. +Because your program is linked to the DLL it is protected. The protected DLL will need to be +in the same folder as your compiled program for it to run correctly. + +Note - once your program (or dpwin32.dll) is protected you will not be able to debug +your program - after our API has been called. Our strong anti-debug code will cause +the debugger to throw an exception. If you do want to debug your code then you can +use our debug module: dpwin32_coff_debug.obj (or dpwin32debug.dll), but these should not be +used for release. See readme.txt in samples\c for restrictions concerning the debug module. + +Note - if you are interested in creating the libdpwin32.a import library yourself then +read the notes in the MinGW\Runtime\readme.txt file (Dev-C++ uses the minGW compiler). + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/MinGW/DinkeyChange/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/MinGW/DinkeyChange/README.txt new file mode 100644 index 0000000..4d6be62 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/MinGW/DinkeyChange/README.txt @@ -0,0 +1,40 @@ +ChangeTest - sample code to call DinkeyChange in MinGW +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tested using minGW 3.4.2 and 4.8.1 and minGW-w64 4.8.1 + +The source files in the project are: + +File name Folder Description +changetest.c Samples\c main source code file for C +changetest.h Samples\c contains some useful constants +libDinkeyChange.a Samples\c\import_libs contains the function definitions for DinkeyChange.dll +libDinkeyChangeDebug.a Samples\c\import_libs contains the function definitions for DinkeyChangeDebug.dll +libDinkeyChange64.a Samples\c\import_libs contains the function definitions for DinkeyChange64.dll +libDinkeyChangeDebug64.a Samples\c\import_libs contains the function definitions for DinkeyChangeDebug64.dll +changetest.rc Samples\c\Visual Studio 5\DinkeyChange resource for main dialog + +(NB for compiling you will also need to compile the resources) + +To compile for 32-bit: +gcc -m32 ..\..\changetest.c -L..\..\import_libs -lDinkeyChange -o ChangeTest.exe + +To compile for 64-bit: +gcc -m64 ..\..\changetest.c -L..\..\import_libs -lDinkeyChange64 -o ChangeTest64.exe + +Note that the source paths are structured to minimise files. If you want to +move this project the references to these files will probably be no longer valid. + +The sample code contains 7 functions. Just use which ever functions are most +appropriate and customise in your own way. The sample code is just a guide. +As none of the parameters are sensitive then there is no need to implement +strong security in calling DinkeyChange. + +Note - you will not be able to debug your program after DinkeyChange has been called. +Our strong anti-debug code will cause the debugger to throw an exception. However, +if you do need to debug your code you can use our debug module for DinkeyChange: +DinkeyChangeDebug.dll. So, you can use DinkeyChange.dll for your release build +and DinkeyChangeDebug.dll for your debug build. + +Note - if you are interested in creating the libDinkeyChange.a import library yourself +then read the notes in the MinGW\Runtime\readme.txt file. diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/MinGW/Runtime/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/MinGW/Runtime/README.txt new file mode 100644 index 0000000..45b8f48 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/MinGW/Runtime/README.txt @@ -0,0 +1,84 @@ +Sample code to call static or dynamic runtime modules using MinGW +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tested using minGW 3.4.2 and 4.8.1 and minGW-w64 4.8.1 + +The source files you need are: + +File name Folder Description +apitest.c Samples\c main source code file for C +dris.h Samples\c contains the DRIS structure +dpwin32_coff.obj Samples\c\object_modules static object modules e.g. dpwin32_coff.obj, dpwin64.obj +libdpwin32.a Samples\c\import_libs contains the function definitions for dpwin32.dll + +To link the static runtime module compile like this: + +32-bit: +gcc -m32 ..\..\apitest.c ..\..\object_modules\dpwin32_coff.obj -o ObjTest.exe + +64-bit: +gcc -m64 ..\..\apitest.c ..\..\object_modules\dpwin64.obj -o ObjTest64.exe +(please ignore the warning about uuid.lib) + +Alternatively to link with the dynamic runtime module compile like this: + +32-bit: +gcc -m32 ..\..\apitest.c -L..\..\import_libs -ldpwin32 -o DllTest.exe + +64-bit: +gcc -m64 ..\..\apitest.c -L..\..\import_libs -ldpwin64 -o DllTest64.exe + +The sample code contains 10 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. + +Note - if you are link the static module dpwin32_coff.obj then you should protect your program. +If you are linking to dpwin32.dll then you need to protect dpwin32.dll and *not* your program. +Because your program is linked to the DLL it is protected. The protected DLL will need to be +in the same folder as your compiled program for it to run correctly. + +Note - once your program (or dpwin32.dll) is protected you will not be able to debug +your program - after our API has been called. Our strong anti-debug code will cause +the debugger to throw an exception. If you do want to debug your code then you can +use our debug module: dpwin32_coff_debug.obj (or dpwin32debug.dll), but these should not be +used for release. See readme.txt in samples\c for restrictions concerning the debug module. + +Creating your own import library +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +In order for MinGW to call functions in dpwin32.dll you need to link the import library +libdpwin32.a. We have created these for you, but if for some reason you need to create it +yourself then you should do the following: + +1) Create a dpwin32.def file with the following format: + LIBRARY dpwin32.dll + EXPORTS + + + + where etc.. are the function names that the linker complains about when you + don't link with the import library. e.g. for dpwin32.dll you just need two functions: + DDProtCheck@8 + DDGetNetUserList@20 + + (you do not need to specify the @n part for 64-bit modules) + +2) Now use dlltool to create the import library: + dlltool --input-def dpwin32.def --output-lib libdpwin32.a -k + + Note: for our DLLs you need to use the -k option otherwise you will get an "file format + not recognised error" when you link the import library. + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Qt Creator/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Qt Creator/README.txt new file mode 100644 index 0000000..e71d1b8 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Qt Creator/README.txt @@ -0,0 +1,18 @@ +Using the Runtime Protection Check API in Qt Creator Projects +============================================================= + +The runtime protection API sample code (apitest.c and dris.h) has been tested with Qt Creator 4.10.2 on Windows, +using MinGW as the compiler and qmake as the build system. +As Qt Creator supports such a wide variety of different compilers and build systems, no project files are included in this sample code. +It is better to create your own project using your preferred toolchain, and then use 'Add Existing Files...' to add apitest.c and dris.h. + +Qt Creator may complain about the symbols BYTE and WINAPI in dris.h. +If it does, insert "#include " at the top of dris.h. + +Qt Creator projects are Unicode by default, it may complain about the use of C strings in calls to MessageBox() in apitest.c. +To solve this issue, either set your project explicitly as an ANSI project, or change all occurrences of MessageBox() to MessageBoxA(). + +You will need to add a reference to the relevant static library (OBJ file) for your compiler. +For projects that use qmake, add the following to your *.pro project file: + + LIBS += path\to\object_module.obj diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/README.txt new file mode 100644 index 0000000..0dbdf57 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/README.txt @@ -0,0 +1,117 @@ +C and C++ Sample Code +===================== + +The source files in this folder are common to all C/C++ implementations: + +apitest.c examples of calling the runtime protection API, e.g. protection checks, reading/writing the dongle secure data area. +dris.h defines structures, constants and function prototypes for the runtime protection API. + +changetest.c examples of calling the DinkeyChange API. +changetest.h defines structures, constants and function prototypes for the DinkeyChange API. + +dapftest.c examples of calling the DinkeyAdd API. +dapf.h defines structures, constants and function prototypes for the DinkeyAdd API. + +drpftest.c examples of calling the DinkeyRemote API. +drpf.h defines structures, constants and function prototypes for the DinkeyRemote API. + +In order for the projects to compile without modification we have also included the folders: + +import_libs import libraries that contain the function definitions for the dynamic API libraries (e.g. dpwin32.dll). +object_modules static API libraries: + Use dpwin32_coff.obj for Visual Studio, MinGW and other compilers that expect the COFF object module format. + Use dpwin32_omf.obj for C++ Builder and other compilers that expects an OMF object module. + There is only one 64-bit object module because in 64-bit Windows only the COFF format exists. + +The subfolders contain projects for different IDEs and/or compilers: + +Visual Studio 2008 for all version of Visual Studio from 2008 onwards. 32-bit and 64-bit. +Visual Studio 5 for earlier versions of Visual Studio. 32-bit only. + +C++ Builder XE3 for versions of C++ Builder from XE3 onwards. +C++ Builder for versions of C++ Builder from 2007 to XE2. If you are using a version earlier than this then please read the README.txt file in that folder. + +Within the subfolders are different projects: + +The ObjTest project checks the dongle by calling the appropriate static library (object module). + +The DllTest project checks the dongle by calling the dynamic library dpwin32.dll (or dpwin64.dll for 64-bit code). + +The ChangeTest project calls the DinkeyChange API which accepts update codes generated by DinkeyRemote. + +The dapfTest project calls the DinkeyAdd API to program dongles and lock your software. + +The drpfTest project calls the DinkeyRemote API to generate remote update codes. + + +Notes concerning Debug Modules +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The debug modules are: + +dpwin32_coff_debug.obj dpwin32_omf_debug.obj dpwin64debug.obj +dpwin32debug.dll dpwin64debug.dll +DinkeyChangeDebug.dll DinkeyChange64Debug.dll + +Note - the DinkeyAdd and DinkeyRemote modules have no debug versions. + +When you use a normal runtime module (e.g. dpwin32.dll) to protect your software the anti-debug code is +so strong that if you are debugging your code after the call DDProtCheck then it will crash. If you want to +be able to debug your code then you can setup your project so that your code calls one of the debug modules +when you are producing your debug code and one of the standard runtime modules when you produce your release +code. The Runtime debug module has the following restrictions: + +1) It will not correctly start a network user (network dongles only). However, other than that the protection check + will function correctly and return success. +2) You will not be able to encrypt the DRIS. (If you do encrypt the DRIS in your release build then you should make + sure that CryptDRIS does not get called in your debug build). +3) The protection check will take slightly longer than normal. +4) The DDGetNetUserList function will return error 428 (not implemented). +5) A temporary subprocess is created which may be (falsely) detected as malicious by anti-virus programs. + +Note: the debug DinkeyChange modules have no restrictions (except for number 5 above). + + +Loading Runtime module using LoadLibrary +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you want to control when the DLL is loaded / unloaded or you want to rename dpwin32.dll +(but cannot change the import library, e.g. with Microsoft Visual Studio), +then you should use LoadLibrary / GetProcAddress to load our library instead of linking the relevant import library. +The DLL is normally placed in the same folder as the program that is calling it. +This code snippet shows how you can do this: + +#include "dris.h" + +// declare function type +typedef int (__stdcall * TypeDDProtCheck)(DRIS*, BYTE *); + +HMODULE hProtLib; +TypeDDProtCheck DDProtCheck; + +hProtLib = LoadLibrary("dpwin32.dll"); // if you have renamed the dll then you should use the new name. + +DDProtCheck = (TypeDDProtCheck)GetProcAddress(hProtLib, "DDProtCheck"); + +// use function as normal (see sample code) + +// free handle when you no longer need to call the DLL (typically the end of your program) +FreeLibrary(hProtLib); + + +Unresolved External Symbol Errors +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you using a static runtime module (e.g. dpwin64.obj) then in rare cases you can receive errors like this: +dpwin64.obj : error LNK2019: unresolved external symbol __imp_SetSecurityDescriptorDacl referenced in function +fatal error LNK1120: 6 unresolved externals + +To fix this problem you need to make sure the following libraries are included in your project: +User32.lib +Advapi32.lib +ws2_32.lib + +Normally these libraries are included as standard by your C/C++ IDE (e.g Visual Studio). However, in rare cases, +such as using the Qt platform or if you are using a C/C++ compiler/linker on the command line, these +libraries may not be included by default so you have include them yourself. + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyAdd/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyAdd/README.txt new file mode 100644 index 0000000..174c5e0 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyAdd/README.txt @@ -0,0 +1,31 @@ +dapfTest - Sample code for calling the DinkeyAdd Module in C +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 2008 but will work in more recent +versions of Visual Studio (they will upgrade the Project to the latest version). + +The main source files in the project are: + +dapf.h - the source file contains declarations of our API. + +dapftest.c - this is the sample code giving an example on how you can call our API. + It contains 5 functions. Just use which ever functions are most appropriate + and customise in your own way. + +Note that the source paths of this project are structured to minimise files. If you +want to move this project the references to these files will probably be no longer valid. + +The solutions have been modified to link in the correct library file (DinkeyAdd32.lib, +DinkeyAdd64.lib) depending on whether the output is 32-bit or 64-bit. They have also +been modified to assume Unicode characters are not the default (this sample uses ascii +characters because that is what the Dinkey dongle SDK requires). + +Note - you will not be able to debug your program after the DinkeyAdd Module has been +called. Our strong anti-debug code will cause the debugger to throw an exception. +There are no debug modules for DinkeyAdd so you will have to find other ways of +debugging your code (for example taking out the call altogether). + +Note - If you are using Visual Studio 2012 or higher then you may get the linker error +"LNK2026: module unsafe for SAFESEH image". To stop this please turn off SAFESEH by +going to your project properties > Linker > Advanced and setting +"Image Has Safe Exception Handlers" to "No". diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyAdd/dapfTest.sln b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyAdd/dapfTest.sln new file mode 100644 index 0000000..b3e5a7e --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyAdd/dapfTest.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dapfTest", "dapfTest.vcproj", "{4FDBE0B2-9115-4CF3-ABCC-786CBE7DB7E0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4FDBE0B2-9115-4CF3-ABCC-786CBE7DB7E0}.Debug|Win32.ActiveCfg = Debug|Win32 + {4FDBE0B2-9115-4CF3-ABCC-786CBE7DB7E0}.Debug|Win32.Build.0 = Debug|Win32 + {4FDBE0B2-9115-4CF3-ABCC-786CBE7DB7E0}.Debug|x64.ActiveCfg = Debug|x64 + {4FDBE0B2-9115-4CF3-ABCC-786CBE7DB7E0}.Debug|x64.Build.0 = Debug|x64 + {4FDBE0B2-9115-4CF3-ABCC-786CBE7DB7E0}.Release|Win32.ActiveCfg = Release|Win32 + {4FDBE0B2-9115-4CF3-ABCC-786CBE7DB7E0}.Release|Win32.Build.0 = Release|Win32 + {4FDBE0B2-9115-4CF3-ABCC-786CBE7DB7E0}.Release|x64.ActiveCfg = Release|x64 + {4FDBE0B2-9115-4CF3-ABCC-786CBE7DB7E0}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyAdd/dapfTest.vcproj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyAdd/dapfTest.vcproj new file mode 100644 index 0000000..290d30a --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyAdd/dapfTest.vcproj @@ -0,0 +1,351 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyChange/ChangeTest.sln b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyChange/ChangeTest.sln new file mode 100644 index 0000000..ee0ad72 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyChange/ChangeTest.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ChangeTest", "ChangeTest.vcproj", "{4DB5C093-DFF8-4EF9-92AF-73CAC5A2E0D6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4DB5C093-DFF8-4EF9-92AF-73CAC5A2E0D6}.Debug|Win32.ActiveCfg = Debug|Win32 + {4DB5C093-DFF8-4EF9-92AF-73CAC5A2E0D6}.Debug|Win32.Build.0 = Debug|Win32 + {4DB5C093-DFF8-4EF9-92AF-73CAC5A2E0D6}.Debug|x64.ActiveCfg = Debug|x64 + {4DB5C093-DFF8-4EF9-92AF-73CAC5A2E0D6}.Debug|x64.Build.0 = Debug|x64 + {4DB5C093-DFF8-4EF9-92AF-73CAC5A2E0D6}.Release|Win32.ActiveCfg = Release|Win32 + {4DB5C093-DFF8-4EF9-92AF-73CAC5A2E0D6}.Release|Win32.Build.0 = Release|Win32 + {4DB5C093-DFF8-4EF9-92AF-73CAC5A2E0D6}.Release|x64.ActiveCfg = Release|x64 + {4DB5C093-DFF8-4EF9-92AF-73CAC5A2E0D6}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyChange/ChangeTest.vcproj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyChange/ChangeTest.vcproj new file mode 100644 index 0000000..317d61e --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyChange/ChangeTest.vcproj @@ -0,0 +1,346 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyChange/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyChange/README.txt new file mode 100644 index 0000000..acac4d0 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyChange/README.txt @@ -0,0 +1,35 @@ +ChangeTest - sample code to call DinkeyChange Module in Visual Studio 2008 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 2008 but will work in more recent +versions of Visual Studio (they will upgrade the Project to the latest version). + +The main source files in the project are: + +changetest.c Samples\c main source code file for C +changetest.h Samples\c contains some useful constants + +Note that the source paths are structured to minimise files. If you want to +move this project the references to these files will probably be no longer valid. + +The solutions have been modified to link in the correct library file (DinkeyChange.lib, +DinkeyChange64.lib) depending on whether the output is 32-bit or 64-bit. They have also +been modified to assume Unicode characters are not the default (this sample uses ascii +characters because that is what the Dinkey dongle SDK requires). + +The sample code contains 7 functions. Just use which ever functions are most +appropriate and customise in your own way. The sample code is just a guide. +As none of the parameters are sensitive then there is no need to implement +strong security in calling DinkeyChange. + +Note - you will not be able to debug your program after DinkeyChange has been called. +Our strong anti-debug code will cause the debugger to throw an exception. However, +if you do need to debug your code you can use our debug module for DinkeyChange: +DinkeyChangeDebug.dll. So, you can use DinkeyChange.dll for your release build +and DinkeyChangeDebug.dll for your debug build. (64-bit versions of these files +also exist). + +Note - If you are using Visual Studio 2012 or higher then you may get the linker error +"LNK2026: module unsafe for SAFESEH image". To stop this please turn off SAFESEH by +going to your project properties > Linker > Advanced and setting +"Image Has Safe Exception Handlers" to "No". diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyRemote/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyRemote/README.txt new file mode 100644 index 0000000..361d8c9 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyRemote/README.txt @@ -0,0 +1,31 @@ +drpfTest - Sample code for calling the DinkeyRemote Module in C +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 2008 but will work in more recent +versions of Visual Studio (they will upgrade the Project to the latest version). + +The main source files in the project are: + +drpf.h - the source file contains declarations of our API. + +drpftest.c - this is the sample code giving an example on how you can call our API. + It contains 2 functions. Just use which ever functions are most appropriate + and customise in your own way. + +Note that the source paths of this project are structured to minimise files. If you +want to move this project the references to these files will probably be no longer valid. + +The solutions have been modified to link in the correct library file (DinkeyRemote32.lib, +DinkeyRemote64.lib) depending on whether the output is 32-bit or 64-bit. They have also +been modified to assume Unicode characters are not the default (this sample uses ascii +characters because that is what the Dinkey dongle SDK requires). + +Note - you will not be able to debug your program after the DinkeyRemote Module has been +called. Our strong anti-debug code will cause the debugger to throw an exception. +There are no debug modules for DinkeyRemote so you will have to find other ways of +debugging your code (for example taking out the call altogether). + +Note - If you are using Visual Studio 2012 or higher then you may get the linker error +"LNK2026: module unsafe for SAFESEH image". To stop this please turn off SAFESEH by +going to your project properties > Linker > Advanced and setting +"Image Has Safe Exception Handlers" to "No". diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyRemote/drpfTest.sln b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyRemote/drpfTest.sln new file mode 100644 index 0000000..022bd5c --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyRemote/drpfTest.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "drpfTest", "drpfTest.vcproj", "{C56A2849-1C1D-4307-937F-D7DF9EA56CB0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C56A2849-1C1D-4307-937F-D7DF9EA56CB0}.Debug|Win32.ActiveCfg = Debug|Win32 + {C56A2849-1C1D-4307-937F-D7DF9EA56CB0}.Debug|Win32.Build.0 = Debug|Win32 + {C56A2849-1C1D-4307-937F-D7DF9EA56CB0}.Debug|x64.ActiveCfg = Debug|x64 + {C56A2849-1C1D-4307-937F-D7DF9EA56CB0}.Debug|x64.Build.0 = Debug|x64 + {C56A2849-1C1D-4307-937F-D7DF9EA56CB0}.Release|Win32.ActiveCfg = Release|Win32 + {C56A2849-1C1D-4307-937F-D7DF9EA56CB0}.Release|Win32.Build.0 = Release|Win32 + {C56A2849-1C1D-4307-937F-D7DF9EA56CB0}.Release|x64.ActiveCfg = Release|x64 + {C56A2849-1C1D-4307-937F-D7DF9EA56CB0}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyRemote/drpfTest.vcproj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyRemote/drpfTest.vcproj new file mode 100644 index 0000000..262c126 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/DinkeyRemote/drpfTest.vcproj @@ -0,0 +1,351 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/Runtime/DllTest/DllTest.vcproj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/Runtime/DllTest/DllTest.vcproj new file mode 100644 index 0000000..e92941d --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/Runtime/DllTest/DllTest.vcproj @@ -0,0 +1,341 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/Runtime/ObjTest/ObjTest.vcproj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/Runtime/ObjTest/ObjTest.vcproj new file mode 100644 index 0000000..fafbb97 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/Runtime/ObjTest/ObjTest.vcproj @@ -0,0 +1,341 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/Runtime/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/Runtime/README.txt new file mode 100644 index 0000000..e8f1cf8 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/Runtime/README.txt @@ -0,0 +1,69 @@ +Sample code to call Runtime modules in Visual Studio 2008 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 2008 but will work in more recent versions of +Visual Studio (they will upgrade the Project to the latest version). + +The source files in the project are: + +File name Folder Description +apitest.c Samples\c main source code file for C +dris.h Samples\c contains the DRIS structure +dpwin32.lib Samples\c\import_libs contains the function definitions for dpwin32.dll +dpwin64.lib Samples\c\import_libs contains the function definitions for dpwin64.dll +dpwin32_coff.obj Samples\c\object_modules static object module +dpwin64.obj Samples\c\object_modules static object module + +Note that the source paths are structured to minimise files. If you want to move this +project the references to these files will probably be no longer valid. + +The ObjTest project links to the static runtime library module (e.g dpwin32_coff.obj or dpwin64.obj) + +The DllTest project uses the dynamic runtime library (e.g. dpwin32.dll or dpwin64.obj). + +The solutions have been modified to assume Unicode characters are not the default +(this sample uses ascii characters because that is what the Dinkey dongle SDK requires). + +The DllTest solution has been modified to link in the correct library file (dpwin32.lib, dpwin64.lib) +depending on whether the output is 32-bit or 64-bit. + +The sample code contains 10 functions. You will not need to use all these functions in your +code. Just use which ever functions are most appropriate and customise in your own way. +The sample code is just a guide. You should implement the protection in a stronger way using +the techniques described in the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. + +Note - if you are link the static module dpwin32_coff.obj (dpwin64.obj) then you should protect +your program. If you are linking to dpwin32.dll (dpwin64.dll) then you need to protect dpwin32.dll +(dpwin64.dll) and *not* your program. Because your program is linked to the DLL it is protected. +The protected DLL will need to be in the same folder as your compiled program for it to run correctly. + +Note - once your program (or dpwin32.dll / dpwin64.dll) is protected you will not be able to debug +your program - after our API has been called. Our strong anti-debug code will cause the debugger +to throw an exception. If you do want to debug your code then you can use our debug module: +dpwin32_coff_debug.obj or dpwin32debug.dll (or 64-bit equivalents), but these should not be used +for release. See readme.txt in samples\c for restrictions concerning the debug module. + +Note - If you are using Visual Studio 2012 or higher then you may get the linker error +"LNK2026: module unsafe for SAFESEH image". To stop this please turn off SAFESEH by +going to your project properties > Linker > Advanced and setting +"Image Has Safe Exception Handlers" to "No". + +Important Note for Windows Store App Developers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Windows Store Apps (Metro Apps) are not compatible with Lite or Plus dongles because the restrictions +imposed by these applications. However, you can protect these Apps with network dongles (because the +restrictive access is performed by the non-Metro DinkeyServer process). If you do this you will need +to enable the "Private Networks (Client and Server)" Capability in your package manifest. diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/Runtime/Runtime.sln b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/Runtime/Runtime.sln new file mode 100644 index 0000000..a698644 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 2008/Runtime/Runtime.sln @@ -0,0 +1,50 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DllTest", "DllTest\DllTest.vcproj", "{F0F1232C-ECAB-47CB-97EB-91D0C18316FF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ObjTest", "ObjTest\ObjTest.vcproj", "{C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Debug|Any CPU.ActiveCfg = Debug|x64 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Debug|Mixed Platforms.ActiveCfg = Debug|x64 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Debug|Mixed Platforms.Build.0 = Debug|x64 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Debug|Win32.ActiveCfg = Debug|Win32 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Debug|Win32.Build.0 = Debug|Win32 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Debug|x64.ActiveCfg = Debug|x64 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Debug|x64.Build.0 = Debug|x64 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Release|Any CPU.ActiveCfg = Release|x64 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Release|Mixed Platforms.ActiveCfg = Release|x64 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Release|Mixed Platforms.Build.0 = Release|x64 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Release|Win32.ActiveCfg = Release|Win32 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Release|Win32.Build.0 = Release|Win32 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Release|x64.ActiveCfg = Release|x64 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Release|x64.Build.0 = Release|x64 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Debug|Mixed Platforms.ActiveCfg = Debug|x64 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Debug|Mixed Platforms.Build.0 = Debug|x64 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Debug|Win32.ActiveCfg = Debug|Win32 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Debug|Win32.Build.0 = Debug|Win32 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Debug|x64.ActiveCfg = Debug|Win32 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Release|Any CPU.ActiveCfg = Release|Win32 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Release|Mixed Platforms.Build.0 = Release|Win32 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Release|Win32.ActiveCfg = Release|Win32 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Release|Win32.Build.0 = Release|Win32 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Release|x64.ActiveCfg = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyAdd/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyAdd/README.txt new file mode 100644 index 0000000..00968c2 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyAdd/README.txt @@ -0,0 +1,23 @@ +dapfTest - Sample code for calling the DinkeyAdd Module in C +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 5.0 but will work in more recent +versions of Visual Studio (they will upgrade the Project to the latest version). +For Visual Studio 2008 and higher please use the Visual Studio 2008 sample code. + +The main source files in the project are: + +dapf.h - the source file contains declarations of our API. + +dapftest.c - this is the sample code giving an example on how you can call our API. + It contains 5 functions. Just use which ever functions are most appropriate + and customise in your own way. + +Note that the source paths of this project are structured to minimise files. If you +want to move this project the references to these files will probably be no longer valid. + +Note - you will not be able to debug your program after the DinkeyAdd Module has been +called. Our strong anti-debug code will cause the debugger to throw an exception. +There are no debug modules for DinkeyAdd so you will have to find other ways of +debugging your code (for example taking out the call altogether). + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyAdd/dapfTest.dsp b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyAdd/dapfTest.dsp new file mode 100644 index 0000000..f0f840f --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyAdd/dapfTest.dsp @@ -0,0 +1,100 @@ +# Microsoft Developer Studio Project File - Name="dapfTest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=dapfTest - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "dapfTest.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "dapfTest.mak" CFG="dapfTest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "dapfTest - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "dapfTest - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "dapfTest - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "dapfTest - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "dapfTest - Win32 Release" +# Name "dapfTest - Win32 Debug" +# Begin Source File + +SOURCE=..\..\dapftest.c +# End Source File +# Begin Source File + +SOURCE=.\dapftest.rc +# End Source File +# Begin Source File + +SOURCE=..\..\import_libs\DinkeyAdd32.lib +# End Source File +# End Target +# End Project diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyAdd/dapfTest.dsw b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyAdd/dapfTest.dsw new file mode 100644 index 0000000..5064319 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyAdd/dapfTest.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 5.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "dapfTest"=".\dapfTest.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyAdd/dapftest.rc b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyAdd/dapftest.rc new file mode 100644 index 0000000..7520188 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyAdd/dapftest.rc @@ -0,0 +1,117 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 252, 328 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Full path of dapf file:",IDC_STATIC,7,15,238,8 + EDITTEXT IDC_DAPF_PATH,7,25,238,14,ES_AUTOHSCROLL + PUSHBUTTON "Program Dongle",IDC_PROGRAM_DONGLE,53,56,145,14 + PUSHBUTTON "Program Dongle with Modification", + IDC_PROGRAM_DONGLE_MOD,53,84,145,14 + PUSHBUTTON "Lock Software",IDC_LOCK_SOFTWARE,53,112,145,14 + PUSHBUTTON "Encrypt Shell Data Files",IDC_ENCRYPT_SHELL_DATA_FILES, + 53,140,145,14 + GROUPBOX "Temporary Software Key",IDC_STATIC,7,170,238,82 + LTEXT "Machine ID:",IDC_STATIC,22,189,40,8 + EDITTEXT IDC_MACHINEID,91,187,132,14,ES_AUTOHSCROLL + LTEXT "Expiry Date:",IDC_STATIC,22,209,39,8 + EDITTEXT IDC_TEMP_EXP_DAY,91,208,18,14,ES_AUTOHSCROLL + LTEXT "/",IDC_STATIC,114,210,8,8 + EDITTEXT IDC_TEMP_EXP_MONTH,123,208,18,14,ES_AUTOHSCROLL + LTEXT "/",IDC_STATIC,148,210,8,8 + EDITTEXT IDC_TEMP_EXP_YEAR,158,208,28,14,ES_AUTOHSCROLL + PUSHBUTTON "Create Software Key",IDC_CREATE_TEMP_SWKEY,53,230,145,14 + GROUPBOX "Demo Software Key",IDC_STATIC,7,260,238,61 + LTEXT "Max Days:",IDC_STATIC,22,279,40,8 + EDITTEXT IDC_DEMO_MAX_DAYS,91,277,132,14,ES_AUTOHSCROLL + PUSHBUTTON "Create Demo Template",IDC_CREATE_DEMO_SWKEY,53,299,145,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_DIALOG1, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 245 + TOPMARGIN, 7 + BOTTOMMARGIN, 321 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyAdd/resource.h b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyAdd/resource.h new file mode 100644 index 0000000..1b771bc --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyAdd/resource.h @@ -0,0 +1,18 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by dapftest.rc +// +#define IDD_DIALOG1 101 +#define IDC_DAPF_PATH 1000 +#define IDC_PROGRAM_DONGLE 1001 +#define IDC_PROGRAM_DONGLE_MOD 1002 +#define IDC_LOCK_SOFTWARE 1003 +#define IDC_ENCRYPT_SHELL_DATA_FILES 1004 +#define IDC_MACHINEID 1005 +#define IDC_TEMP_EXP_DAY 1006 +#define IDC_TEMP_EXP_MONTH 1007 +#define IDC_TEMP_EXP_YEAR 1008 +#define IDC_CREATE_TEMP_SWKEY 1009 +#define IDC_DEMO_MAX_DAYS 1010 +#define IDC_CREATE_DEMO_SWKEY 1011 +#define IDC_STATIC -1 diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyChange/ChangeTest.dsp b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyChange/ChangeTest.dsp new file mode 100644 index 0000000..cd68a78 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyChange/ChangeTest.dsp @@ -0,0 +1,100 @@ +# Microsoft Developer Studio Project File - Name="ChangeTest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=ChangeTest - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ChangeTest.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ChangeTest.mak" CFG="ChangeTest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ChangeTest - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "ChangeTest - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ChangeTest - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "ChangeTest - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "ChangeTest - Win32 Release" +# Name "ChangeTest - Win32 Debug" +# Begin Source File + +SOURCE=..\..\changetest.c +# End Source File +# Begin Source File + +SOURCE=.\ChangeTest.rc +# End Source File +# Begin Source File + +SOURCE=..\..\import_libs\DinkeyChange.lib +# End Source File +# End Target +# End Project diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyChange/ChangeTest.dsw b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyChange/ChangeTest.dsw new file mode 100644 index 0000000..f02e931 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyChange/ChangeTest.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 5.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "ChangeTest"=".\ChangeTest.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyChange/ChangeTest.rc b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyChange/ChangeTest.rc new file mode 100644 index 0000000..c380995 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyChange/ChangeTest.rc @@ -0,0 +1,112 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "windows.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 215, 358 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "ChangeTest" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "Get Dongle Information...",IDC_DONGLEINFO,45,14,119,14 + LTEXT "Enter Diagnostic filename:",IDC_STATIC,7,40,201,8 + EDITTEXT IDC_DIAG_PATH,7,49,201,14,ES_AUTOHSCROLL + PUSHBUTTON "Write Diagnostics to File",IDC_GETDIAGS,45,68,119,14 + LTEXT "Enter short Update Code here:",IDC_STATIC,7,96,201,8 + EDITTEXT IDC_UPDATE_CODE_STRING,7,106,201,14,ES_AUTOHSCROLL + PUSHBUTTON "Make Changes",IDC_DO_UPDATE_CODE_STRING,69,125,68,14 + LTEXT "Enter path to Update Code file:",IDC_STATIC,7,153,201,8 + EDITTEXT IDC_UPDATE_CODE_FILE,7,163,201,14,ES_AUTOHSCROLL + PUSHBUTTON "Make Changes",IDC_DO_UPDATE_CODE_FILE,68,183,68,14 + PUSHBUTTON "Restore Dinkey FD Lite",IDC_RESTORE_FD_LITE,45,215,119,14 + PUSHBUTTON "Get Machine ID",IDC_GET_MACHINE_ID,7,245,95,14 + EDITTEXT IDC_MACHINE_ID,110,245,98,14,ES_UPPERCASE + PUSHBUTTON "Download Temporary Software Key",IDC_GET_TEMP_SWKEY,35,275,139,14 + LTEXT "Demo Software Key Product Code:",IDC_STATIC,7,305,201,8 + EDITTEXT IDC_SWKEY_PRODCODE,7,314,201,14,ES_AUTOHSCROLL | ES_UPPERCASE + PUSHBUTTON "Download Demo Software Key",IDC_GET_DEMO_SWKEY,35,333,139,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_DIALOG1, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 208 + TOPMARGIN, 7 + BOTTOMMARGIN, 347 + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""windows.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyChange/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyChange/README.txt new file mode 100644 index 0000000..d8c6d78 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyChange/README.txt @@ -0,0 +1,29 @@ +ChangeTest - sample code to call DinkeyChange.dll in Visual Studio +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 5.0 but will work in more recent +versions of Visual Studio (they will upgrade the Project to the latest version). +For Visual Studio 2008 and higher please use the Visual Studio 2008 sample code. + +The source files in the project are: + +File name Folder Description +changetest.c Samples\c main source code file for C +changetest.h Samples\c contains some useful constants +DinkeyChange.lib Samples\c\import_libs contains the function definitions for DinkeyChange.dll +changetest.rc Samples\c\Visual Studio\DinkeyChange resource for main dialog + + +Note that the source paths are structured to minimise files. If you want to +move this project the references to these files will probably be no longer valid. + +The sample code contains 7 functions. Just use which ever functions are most +appropriate and customise in your own way. The sample code is just a guide. +As none of the parameters are sensitive then there is no need to implement +strong security in calling DinkeyChange. + +Note - you will not be able to debug your program after DinkeyChange has been called. +Our strong anti-debug code will cause the debugger to throw an exception. However, +if you do need to debug your code you can use our debug module for DinkeyChange: +DinkeyChangeDebug.dll. So, you can use DinkeyChange.dll for your release build +and DinkeyChangeDebug.dll for your debug build. diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyChange/resource.h b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyChange/resource.h new file mode 100644 index 0000000..e8fd0a7 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyChange/resource.h @@ -0,0 +1,31 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by ChangeTest.rc +// +#define IDD_DIALOG1 101 +#define IDC_DONGLEINFO 1000 +#define IDC_UPDATE_CODE_STRING 1001 +#define IDC_DO_UPDATE_CODE_STRING 1002 +#define IDC_DIAG_PATH 1003 +#define IDC_GETDIAGS 1004 +#define IDC_UPDATE_CODE_FILE 1005 +#define IDC_DO_UPDATE_CODE_FILE 1006 +#define IDC_RESTORE_FD_LITE 1007 +#define IDC_GET_MACHINE_ID 1008 +#define IDC_MACHINE_ID 1009 +#define IDC_GET_TEMP_SWKEY 1010 +#define IDC_SWKEY_PRODCODE 1011 +#define IDC_GET_DEMO_SWKEY 1012 + +#define IDC_STATIC (-1) + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1013 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyRemote/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyRemote/README.txt new file mode 100644 index 0000000..77d562c --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyRemote/README.txt @@ -0,0 +1,23 @@ +drpfTest - Sample code for calling the DinkeyRemote Module in C +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 5 but will work in more recent +versions of Visual Studio (they will upgrade the Project to the latest version). +For Visual Studio 2008 and higher please use the Visual Studio 2008 sample code. + +The main source files in the project are: + +drpf.h - the source file contains declarations of our API. + +drpftest.c - this is the sample code giving an example on how you can call our API. + It contains 2 functions. Just use which ever functions are most appropriate + and customise in your own way. + +Note that the source paths of this project are structured to minimise files. If you +want to move this project the references to these files will probably be no longer valid. + +Note - you will not be able to debug your program after the DinkeyRemote Module has been +called. Our strong anti-debug code will cause the debugger to throw an exception. +There are no debug modules for DinkeyRemote so you will have to find other ways of +debugging your code (for example taking out the call altogether). + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyRemote/drpfTest.dsp b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyRemote/drpfTest.dsp new file mode 100644 index 0000000..bd2d5d3 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyRemote/drpfTest.dsp @@ -0,0 +1,100 @@ +# Microsoft Developer Studio Project File - Name="drpfTest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=drpfTest - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "drpfTest.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "drpfTest.mak" CFG="drpfTest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "drpfTest - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "drpfTest - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "drpfTest - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "drpfTest - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "drpfTest - Win32 Release" +# Name "drpfTest - Win32 Debug" +# Begin Source File + +SOURCE=..\..\import_libs\DinkeyRemote32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\drpftest.c +# End Source File +# Begin Source File + +SOURCE=.\drpftest.rc +# End Source File +# End Target +# End Project diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyRemote/drpfTest.dsw b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyRemote/drpfTest.dsw new file mode 100644 index 0000000..c05dc95 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyRemote/drpfTest.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 5.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "drpfTest"=".\drpfTest.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyRemote/drpftest.rc b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyRemote/drpftest.rc new file mode 100644 index 0000000..9fc2873 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyRemote/drpftest.rc @@ -0,0 +1,100 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 343, 111 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Full path of drpf file:",IDC_STATIC,7,14,329,10 + EDITTEXT IDC_DRPF_PATH,7,26,329,14,ES_AUTOHSCROLL + PUSHBUTTON "Generate Update Code",IDC_UPDATE_CODE,90,54,164,14 + PUSHBUTTON "Generate Update Code with Modifications", + IDC_UPDATE_CODE_MOD,90,82,164,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_DIALOG1, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 336 + TOPMARGIN, 7 + BOTTOMMARGIN, 104 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyRemote/resource.h b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyRemote/resource.h new file mode 100644 index 0000000..f251426 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/DinkeyRemote/resource.h @@ -0,0 +1,20 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by drpftest.rc +// +#define IDD_DIALOG1 101 +#define IDC_DRPF_PATH 1000 +#define IDC_UPDATE_CODE 1001 +#define IDC_UPDATE_CODE_MOD 1002 +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1003 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/Runtime/DllTest.dsp b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/Runtime/DllTest.dsp new file mode 100644 index 0000000..df1bae8 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/Runtime/DllTest.dsp @@ -0,0 +1,104 @@ +# Microsoft Developer Studio Project File - Name="DllTest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=DllTest - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "DllTest.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "DllTest.mak" CFG="DllTest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "DllTest - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "DllTest - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "DllTest - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "DllTest - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "DllTest - Win32 Release" +# Name "DllTest - Win32 Debug" +# Begin Source File + +SOURCE=..\..\apitest.c +# End Source File +# Begin Source File + +SOURCE=..\..\import_libs\dpwin32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\dris.h +# End Source File +# Begin Source File + +SOURCE=.\readme.txt +# End Source File +# End Target +# End Project diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/Runtime/ObjTest.dsp b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/Runtime/ObjTest.dsp new file mode 100644 index 0000000..82da5dc --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/Runtime/ObjTest.dsp @@ -0,0 +1,96 @@ +# Microsoft Developer Studio Project File - Name="ObjTest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=ObjTest - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ObjTest.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ObjTest.mak" CFG="ObjTest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ObjTest - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "ObjTest - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ObjTest - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "ObjTest - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "ObjTest - Win32 Release" +# Name "ObjTest - Win32 Debug" +# Begin Source File + +SOURCE=..\..\apitest.c +# End Source File +# Begin Source File + +SOURCE=..\..\object_modules\dpwin32_coff.obj +# End Source File +# End Target +# End Project diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/Runtime/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/Runtime/README.txt new file mode 100644 index 0000000..477b64a --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/Runtime/README.txt @@ -0,0 +1,50 @@ +Sample code to call Runtime Modules in Visual Studio +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 5.0 but will work in more recent +versions of Visual Studio (they will upgrade the Project to the latest version). +For Visual Studio 2008 and higher please use the Visual Studio 2008 sample code. + +The source files in the project are: + +File name Folder Description +apitest.c Samples\c main source code file for C +dris.h Samples\c contains the DRIS structure +dpwin32_coff.obj Samples\c\object_modules static object modules +dpwin32.lib Samples\c\import_libs contains the function definitions for dpwin32.dll + +Note that the source paths are structured to minimise files. If you want to +move this project the references to these files will probably be no longer valid. + +The ObjTest project links to the static runtime library module (e.g dpwin32_coff.obj) + +The DllTest project uses the dynamic runtime library (e.g. dpwin32.dll). + +The sample code contains 10 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. + +Note - if you are link the static module dpwin32_coff.obj then you should protect your program. +If you are linking to dpwin32.dll then you need to protect dpwin32.dll and *not* your program. +Because your program is linked to the DLL it is protected. The protected DLL will need to be +in the same folder as your compiled program for it to run correctly. + +Note - once your program (or dpwin32.dll) is protected you will not be able to debug +your program - after our API has been called. Our strong anti-debug code will cause +the debugger to throw an exception. If you do want to debug your code then you can +use our debug module: dpwin32_coff_debug.obj (or dpwin32debug.dll), but these should not be +used for release. See readme.txt in samples\c for restrictions concerning the debug module. diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/Runtime/Runtime.dsw b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/Runtime/Runtime.dsw new file mode 100644 index 0000000..22ef930 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/Visual Studio 5/Runtime/Runtime.dsw @@ -0,0 +1,41 @@ +Microsoft Developer Studio Workspace File, Format Version 5.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "DllTest"=".\DllTest.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "ObjTest"=".\ObjTest.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/apitest.c b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/apitest.c new file mode 100644 index 0000000..f525abb --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/apitest.c @@ -0,0 +1,823 @@ +// !! We strongly recommend that you read the "readme.txt" file for this sample. +// !! It contains important instructions on how to use the sample code + +#include // for windows programs +#include // for sprintf +#include // for memset +#include "dris.h" // for DRIS definition + +#define MY_SDSN 10101 // !!!! change this value to be the value of your SDSN (demo = 10101) +#define MY_PRODCODE "DEMO" // !!!! change this value to match the Product Code in the dongle + +#ifdef _MSC_VER + #pragma warning(disable:4996) // to disable warnings about sprintf etc... means we can use the same source for all compilers +#endif + +/* The sample code contains 11 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +If you are using Dinkey Lite then you can only use 4 functions: +ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc +*/ + +// this file contains 10 protection-check functions. +int ProtCheck(void); // a standard protection check +int ProtCheckWithAlg(void); // a protection check & executing an Algorithm +int WriteBytes(void); // a protection check & write data to the dongle +int ReadBytes(void); // a protection check & read data from the dongle +int EncryptUserData(void); // a protection check & encrypting data and then decrypting the data +// these functions are the same as the functions listed above but encrypting all parameters passed to our API +int ProtCheckEnc(void); // a standard protection check +int ProtCheckWithAlgEnc(void); // a protection check & executing an Algorithm +int WriteBytesEnc(void); // a protection check & write data to the dongle +int ReadBytesEnc(void); // a protection check & read data from the dongle +int EncryptUserDataEnc(void); // a protection check & encrypting data and then decrypting the data +// this function displays the current network users +int DisplayNetUsers(DRIS *dris); + +// useful routines that are called by our functions - implemented at the end of this file +void random_set(void *buffer, int length); +void DisplayError(int ret_code, int extended_error); + +char g_szAppName[] = "test program"; + +// *************************** WinMain *************************************** + +int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdParam, int nCmdShow) { + // call the function(s) of your choice here + // by default I have chosen a standard protection check + ProtCheck(); + return 0; +} + + +// ************************* 10 protection check functions ********************************** + +// ************************** ProtCheck *************************************** +int ProtCheck(void) { + DRIS dris; + int ret_code; + + // set the DRIS to have random values + random_set(&dris, sizeof(DRIS)); + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = PROTECTION_CHECK; // standard protection check + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + ret_code = DDProtCheck(&dris, NULL); + + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + // later in your code you can check other values in the DRIS... + + if (dris.sdsn != MY_SDSN) { + MessageBox(NULL, "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", NULL, MB_OK); + return -1; + } + + if (strcmp(dris.prodcode, MY_PRODCODE) != 0) { + MessageBox(NULL, "Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", NULL, MB_OK); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) { + MessageBox(NULL, "Dinkey Dongle protection error", NULL, MB_OK); + return -1; + } + + MessageBox(NULL, "It worked", g_szAppName, MB_OK); + + // if you are using a network dongle and you want to list the network users then use this function: +// DisplayNetUsers(&dris); + + return 0; +} + +// ************************** ProtCheckWithAlg ****************************** + +// !!!! You should replace this function with the one generated by the +// "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) +// or from DinkeyLook if you are using a Dinkey Lite dongle. +int MyAlgorithm(int a, int b, int c, int d, int e, int f, int g, int h) { + return a + b + c + d + e + f + g + h; +} + +// NB for this to work you must program at least "user algorithm" into the dongle +// NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +// sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +// code from DinkeyLook +int ProtCheckWithAlg(void) { + DRIS dris; + int ret_code; + + // set the DRIS to have random values + random_set(&dris, sizeof(DRIS)); + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = EXECUTE_ALGORITHM; // standard protection check & execute algorithm + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number = 1; // execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + // you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.var_a = 1; // sample values + dris.var_b = 2; + dris.var_c = 3; + dris.var_d = 4; + dris.var_e = 5; + dris.var_f = 6; + dris.var_g = 7; + dris.var_h = 8; + + ret_code = DDProtCheck(&dris, NULL); + + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + // later in your code you can check other values in the DRIS... + + if (dris.sdsn != MY_SDSN) { + MessageBox(NULL, "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", NULL, MB_OK); + return -1; + } + + // ...later on in your program you can check the return code again + if (dris.ret_code != 0) { + MessageBox(NULL, "Dinkey Dongle protection error", NULL, MB_OK); + return -1; + } + + // if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + // !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) != dris.alg_answer) { + MessageBox(NULL, "Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine", NULL, MB_OK); + return -1; + } + + MessageBox(NULL, "It worked", g_szAppName, MB_OK); + return 0; +} + +// ************************** WriteBytes ****************************** +// This writes the Data "Hello, World" to the dongle data area at offset 7 +// In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +int WriteBytes(void) { + DRIS dris; + char szDataToWrite[] = "Hello, World!"; + int ret_code; + + // set the DRIS to have random values + random_set(&dris, sizeof(DRIS)); + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = WRITE_DATA_AREA; // standard protection check and write data + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset = 7; + dris.rw_length = sizeof(szDataToWrite); + dris.rw_data_ptr = szDataToWrite; + + ret_code = DDProtCheck(&dris, NULL); + + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + // ...later in your code you can check other values in the DRIS... + + if (dris.sdsn != MY_SDSN) { + MessageBox(NULL, "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", NULL, MB_OK); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) { + MessageBox(NULL, "Dinkey Dongle protection error", NULL, MB_OK); + return -1; + } + + MessageBox(NULL, "It worked", g_szAppName, MB_OK); + return 0; +} + + +// ************************ ReadBytes ************************************ +// This reads 14 bytes of data from offset 7 in the dongle data area +// In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +// In order for the data to be displayed properly by this routine it will need to be text data +int ReadBytes(void) { + DRIS dris; + char szDataRead[14], szBuffer[200]; + int ret_code; + + // set the DRIS to have random values + random_set(&dris, sizeof(DRIS)); + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = READ_DATA_AREA; // standard protection check & read data + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset = 7; + dris.rw_length = sizeof(szDataRead)-1; + dris.rw_data_ptr = szDataRead; + + ret_code = DDProtCheck(&dris, NULL); + + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + // ...later in your code you can check other values in the DRIS... + + if (dris.sdsn != MY_SDSN) { + MessageBox(NULL, "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", NULL, MB_OK); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) { + MessageBox(NULL, "Dinkey Dongle protection error", NULL, MB_OK); + return -1; + } + + szDataRead[sizeof(szDataRead)-1] = 0; // null - terminate string so it displays OK. NB we assume that we are reading text that can be displayed + sprintf(szBuffer, "It worked! Dinkey Dongle Data area, offset 7 is: %s", szDataRead); + MessageBox(NULL, szBuffer, g_szAppName, MB_OK); + return 0; +} + + +// ************************** EncryptUserData ************************************ +// This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +// It will then do another protection check & decrypt the data +int EncryptUserData(void) { + DRIS dris; + char szBuffer[100]; + char szData[16] = "Hello, World!"; // pad message so it is multiple of 8-bytes long i.e. make array 16 bytes long (improves encryption) + int ret_code; + + // set the DRIS to have random values + random_set(&dris, sizeof(DRIS)); + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = ENCRYPT_USER_DATA; // standard protection check & encrypt user data + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num = 1; + dris.rw_length = sizeof(szData); + dris.rw_data_ptr = szData; + + ret_code = DDProtCheck(&dris, NULL); + + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + // ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + // Now decrypt the same data to get the original values + random_set(&dris, sizeof(DRIS)); + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = DECRYPT_USER_DATA; // standard protection check & decrypt user data + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num = 1; + dris.rw_length = sizeof(szData); + dris.rw_data_ptr = szData; + + ret_code = DDProtCheck(&dris, NULL); + + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + // ...later in your code you can check other values in the DRIS... + + if (dris.sdsn != MY_SDSN) { + MessageBox(NULL, "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", NULL, MB_OK); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) { + MessageBox(NULL, "Dinkey Dongle protection error", NULL, MB_OK); + return -1; + } + + sprintf(szBuffer, "It worked. Data decrypted is: %s", szData); + MessageBox(NULL, szBuffer, g_szAppName, MB_OK); + return 0; +} + + +// !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! +// In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" +// in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm +// but the code can be modified easily to use the 3 encryption parameters. + +// !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm +int MyRWAlgorithm(int a, int b, int c, int d, int e, int f, int g, int h) { + return a ^ b ^ c ^ d ^ e ^ f; +} + +// !!!! please overwrite this function with the one generated by DinkeyAdd +void CryptDRIS(DRIS *dris, unsigned int seed1, unsigned int seed2) { + int i, j, k; + unsigned char bigseed[256], S[256]; + unsigned char temp, t; + + for (i=0; i<256; i+=8) { + memcpy(bigseed+i, &seed1, 4); + memcpy(bigseed+i+4, &seed2, 4); + } + for (i=0; i<256; i++) + S[i] = i; + for (i=0, j=0; i<256; i++) { + j = (j + S[i] + bigseed[i] + 123) % 256; + temp = S[i]; + S[i] = S[j]; + S[j] = temp; + } + for (i=0, j=0, k=16; k<(int)sizeof(DRIS); k++) { + i = (i + 1) % 256; + j = (j + S[i] + 212) % 256; + temp = S[i]; + S[i] = S[j]; + S[j] = temp; + t = (S[i] + S[j] + 97) % 256; + ((unsigned char *)dris)[k] ^= S[t]; + } + return; +} + +// !!!! please overwrite this function with the one generated by DinkeyAdd +void CryptApiData(unsigned char *data, int length, unsigned int seed1, unsigned int seed2, int alg_answer) { + int i, j, k; + unsigned char bigseed[256], S[256]; + unsigned char temp, t; + + for (i=0; i<256; i+=8) { + memcpy(bigseed+i, &seed1, 4); + memcpy(bigseed+i+4, &seed2, 4); + } + for (i=0; i<256; i++) + S[i] = i; + for (i=0, j=0; i<256; i++) { + j = (j + S[i] + bigseed[i] + (alg_answer & 0xFF)) % 256; + temp = S[i]; + S[i] = S[j]; + S[j] = temp; + } + for (i=0, j=0, k=0; k> 8) & 0xFF)) % 256; + temp = S[i]; + S[i] = S[j]; + S[j] = temp; + t = (S[i] + S[j] + ((alg_answer >> 16) & 0xFF)) % 256; + data[k] ^= S[t]; + } + return; +} + +// **************************** ProtCheckEnc *************************** +// We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +// NB if you are using the debug module then do not call CryptDRIS as DRIS encryption is not supported. See notes in C readme.txt +int ProtCheckEnc(void) { + DRIS dris; + int ret_code; + + // set the DRIS to have random values + random_set(&dris, sizeof(DRIS)); // NB this also fills seed1, seed2 with random values + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = PROTECTION_CHECK; // standard protection check + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + CryptDRIS(&dris, dris.seed1, dris.seed2); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL); + + CryptDRIS(&dris, dris.seed1, dris.seed2); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + // later in your code you can check other values in the DRIS... + + if (dris.sdsn != MY_SDSN) { + MessageBox(NULL, "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", NULL, MB_OK); + return -1; + } + + if (strcmp(dris.prodcode, MY_PRODCODE) != 0) { + MessageBox(NULL, "Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", NULL, MB_OK); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) { + MessageBox(NULL, "Dinkey Dongle protection error", NULL, MB_OK); + return -1; + } + + MessageBox(NULL, "It worked", g_szAppName, MB_OK); + return 0; +} + +// ************************* ProtCheckWithAlgEnc ***************************** +// NB for this to work you must program at least "user algorithm" into the dongle +// NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +// sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample code from DinkeyLook. +// We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +int ProtCheckWithAlgEnc(void) { + DRIS dris; + int ret_code; + + // set the DRIS to have random values + random_set(&dris, sizeof(DRIS)); // NB this also fills seed1, seed2 with random values + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = EXECUTE_ALGORITHM; // standard protection check & execute algorithm + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number = 1; // execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + // you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.var_a = 1; // sample values + dris.var_b = 2; + dris.var_c = 3; + dris.var_d = 4; + dris.var_e = 5; + dris.var_f = 6; + dris.var_g = 7; + dris.var_h = 8; + + CryptDRIS(&dris, dris.seed1, dris.seed2); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL); + + CryptDRIS(&dris, dris.seed1, dris.seed2); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + // later in your code you can check other values in the DRIS... + + if (dris.sdsn != MY_SDSN) { + MessageBox(NULL, "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", NULL, MB_OK); + return -1; + } + + // ...later on in your program you can check the return code again + if (dris.ret_code != 0) { + MessageBox(NULL, "Dinkey Dongle protection error", NULL, MB_OK); + return -1; + } + + // if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + // !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) != dris.alg_answer) { + MessageBox(NULL, "Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine", NULL, MB_OK); + return -1; + } + + MessageBox(NULL, "It worked", g_szAppName, MB_OK); + return 0; +} + +// **************************** WriteBytesEnc ******************************** +// This writes the Data "Hello, World" to the dongle data area at offset 7 +// In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +// We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +int WriteBytesEnc(void) { + DRIS dris; + char szDataToWrite[] = "Hello, World!"; + int ret_code, alg_ans; + + // set the DRIS to have random values + random_set(&dris, sizeof(DRIS)); // NB this also fills seed1, seed2, var_a...var_h with random values + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = WRITE_DATA_AREA; // standard protection check & write data + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset = 7; + dris.rw_length = sizeof(szDataToWrite); + dris.rw_data_ptr = szDataToWrite; + + // calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + // encrypt data we want to write. + CryptApiData((BYTE *)szDataToWrite, sizeof(szDataToWrite), dris.seed1, dris.seed2, alg_ans); + + CryptDRIS(&dris, dris.seed1, dris.seed2); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL); + + CryptDRIS(&dris, dris.seed1, dris.seed2); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + // ...later in your code you can check other values in the DRIS... + + if (dris.sdsn != MY_SDSN) { + MessageBox(NULL, "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", NULL, MB_OK); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) { + MessageBox(NULL, "Dinkey Dongle protection error", NULL, MB_OK); + return -1; + } + + MessageBox(NULL, "It worked", g_szAppName, MB_OK); + return 0; +} + +// **************************** ReadBytesEnc ********************************* +// This reads 14 bytes of data from offset 7 in the dongle data area +// In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +// In order for the data to be displayed properly by this routine it will need to be text data +// We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +int ReadBytesEnc(void) { + DRIS dris; + char szDataRead[14], szBuffer[200]; + int ret_code, alg_ans; + + // set the DRIS to have random values + random_set(&dris, sizeof(DRIS)); // NB this also fills seed1, seed2, var_a...var_h with random values + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = READ_DATA_AREA; // standard protection check & read data + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset = 7; + dris.rw_length = sizeof(szDataRead)-1; + dris.rw_data_ptr = szDataRead; + + // calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + CryptDRIS(&dris, dris.seed1, dris.seed2); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL); + + CryptDRIS(&dris, dris.seed1, dris.seed2); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + // ...later in your code you can check other values in the DRIS... + + if (dris.sdsn != MY_SDSN) { + MessageBox(NULL, "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", NULL, MB_OK); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) { + MessageBox(NULL, "Dinkey Dongle protection error", NULL, MB_OK); + return -1; + } + + // decrypt data that was read. + CryptApiData((BYTE *)szDataRead, sizeof(szDataRead)-1, dris.seed1, dris.seed2, alg_ans); + + szDataRead[sizeof(szDataRead)-1] = 0; // null - terminate string so it displays OK. NB we assume that we are reading text that can be displayed + sprintf(szBuffer, "It worked! Dinkey Dongle Data area, offset 7 is: %s", szDataRead); + MessageBox(NULL, szBuffer, g_szAppName, MB_OK); + return 0; +} + +// ************************* EncryptUserDataEnc ****************************** +// This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +// It will then do another protection & decrypt the data +// We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +int EncryptUserDataEnc(void) { + DRIS dris; + char szBuffer[100]; + char szData[16] = "Hello, World!"; // pad message so it is multiple of 8-bytes long i.e. make array 16 bytes long (improves encryption) + int ret_code, alg_ans; + + // set the DRIS to have random values + random_set(&dris, sizeof(DRIS)); + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = ENCRYPT_USER_DATA; // standard protection check & encrypt user data + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num = 1; + dris.rw_length = sizeof(szData); + dris.rw_data_ptr = szData; + + // calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + // encrypt data we want to pass. + CryptApiData((BYTE *)szData, sizeof(szData), dris.seed1, dris.seed2, alg_ans); + + CryptDRIS(&dris, dris.seed1, dris.seed2); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL); + + CryptDRIS(&dris, dris.seed1, dris.seed2); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + // ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + // Now decrypt the same data to get the original values + random_set(&dris, sizeof(DRIS)); + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = DECRYPT_USER_DATA; // standard protection check & decrypt user data + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num = 1; + dris.rw_length = sizeof(szData); + dris.rw_data_ptr = szData; + + CryptDRIS(&dris, dris.seed1, dris.seed2); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL); + + CryptDRIS(&dris, dris.seed1, dris.seed2); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + // ...later in your code you can check other values in the DRIS... + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + if (dris.sdsn != MY_SDSN) { + MessageBox(NULL, "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", NULL, MB_OK); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) { + MessageBox(NULL, "Dinkey Dongle protection error", NULL, MB_OK); + return -1; + } + + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + // decrypt data that was passed to us by the API + CryptApiData((BYTE *)szData, sizeof(szData), dris.seed1, dris.seed2, alg_ans); + + sprintf(szBuffer, "It worked. Data decrypted is: %s", szData); + MessageBox(NULL, szBuffer, g_szAppName, MB_OK); + return 0; +} + +// ********************* DisplayNetUsers *********************** +// This function displays the current network users (for DinkeyNet only). +// The DDProtCheck function must be called before this function is called. +// (Normally you would use DinkeyServer to view the network users but this enables you to do it from the client if you want) + +char net_user_display_msg[] = "%d. licence: %s, user: %s, computer: %s, ipaddress: %s\n"; +#define MAX_MESSAGE_SIZE (sizeof(NU_INFO) + sizeof(net_user_display_msg)) + +// !!!! NB You should check for errors when dynamic allocating memory +int DisplayNetUsers(DRIS *dris) { + int ret_code, extended_error, max_net_users, num_net_users, i; + char szBuffer[MAX_MESSAGE_SIZE]; + char *szMsg; + NU_INFO *nu_info; + + if (dris->net_users == -1) + max_net_users = 100; // if unlimited network users are allowed then display up to 100 users (for example) + else + max_net_users = dris->net_users; + + if (max_net_users == 0) // no network users are allowed, so nothing to do! + return 0; + + if (dris->model < 3) { + MessageBox(NULL, "A network dongle has not been detected. Therefore you cannot display the network users.", "Net Users", MB_OK); + return -1; + } + + // allocate memory for array of network user information structures and also to display the message to users + nu_info = (NU_INFO *)malloc(sizeof(NU_INFO) * max_net_users); + szMsg = (char *)malloc(MAX_MESSAGE_SIZE * max_net_users); + + // get network user information + ret_code = DDGetNetUserList(NULL, &num_net_users, nu_info, max_net_users, &extended_error); + + if (ret_code != 0) { + sprintf(szMsg, "Error %d/%d finding network user information.", ret_code, extended_error); + MessageBox(NULL, szMsg, "Net Users", MB_OK); + } + else { + sprintf(szMsg, "number of net users: %d\n", num_net_users); + for (i=0; i +#include + +#include "Visual Studio 5\DinkeyChange\resource.h" +#include "ChangeTest.h" + +#ifdef _MSC_VER + #pragma warning(disable:4996) // to disable warnings about sprintf etc... means we can use the same source for all compilers +#endif + +char g_szAppName[] = "ChangeTest"; +void DisplayError(int ret_code, int extended_error); + + +// routine for main dialog box +BOOL CALLBACK MainDlgProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { + int ret_code, i, num_found, confirmation_code, extended_error; + char szType[4], szModel[5]; + char szDisplayMsg[12800], szBuffer[257], szProdCode[9]; + // these are the arrays that are filled-in by DCGetInfo + int type[MAX_USB_DEVICES]; + int model[MAX_USB_DEVICES]; + char prodcode[MAX_USB_DEVICES][MAX_PRODCODE_LEN]; + unsigned int dongle_number[MAX_USB_DEVICES]; + int update_number[MAX_USB_DEVICES]; + unsigned int machineID; + + switch (message) + { + case WM_INITDIALOG: + // nothing to do + break; + + case WM_COMMAND: + // *** Get Dongle Information button clicked *** + if (LOWORD(wParam) == IDC_DONGLEINFO && HIWORD(wParam) == BN_CLICKED) { + + // find dongle information for all dongle types, Plus & Net models, for all product codes + // NB In practice you will probably want to set the prodcode_mask to the value of your product code + ret_code = DCGetInfo(TYPE_MASK_ALL, MODEL_MASK_DEFAULT, NULL, MAX_USB_DEVICES, &num_found, type, model, prodcode, dongle_number, update_number); + + // check error code and display error if an error occurs + if (ret_code == 401) { + MessageBox(hwnd, "No dongles detected matching the search criteria specified", g_szAppName, MB_OK); + return 0; + } + else if (ret_code != 0) { + sprintf(szDisplayMsg, "Error %d getting dongle information", ret_code); + MessageBox(hwnd, szDisplayMsg, g_szAppName, MB_OK); + return 0; + } + + // display info from dongle(s) detected + szDisplayMsg[0] = 0; // null string + for (i=0; i +#include + +#include "Visual Studio 5\DinkeyAdd\resource.h" +#include "dapf.h" + +#ifdef _MSC_VER + #pragma warning(disable:4996) // to disable warnings about sprintf etc... means we can use the same source for all compilers +#endif + + +char g_szAppName[] = "dapfTest"; + +void DisplayLastMessage(void); // gets & displays the message from the DinkeyAdd Module + + +// load a DAPF file from disk and program the dongle as specified by the DAPF file +int DoProgramDongle(char *szFileDAPF) { + DAPF_HANDLE dapfHandle; + int err_code; + unsigned int dongle_number; + + // load DAPF from File into memory + dapfHandle = LoadDAPFFromFile(szFileDAPF, &err_code); + if (dapfHandle == NULL) { + DisplayLastMessage(); + return err_code; + } + + // program dongle as specified by the DAPF file + err_code = AddProtection(dapfHandle, ACTION_PROGRAM_DONGLE, 0, 0, &dongle_number); + + // Unload DAPF from memory + UnloadDAPF(&dapfHandle); + + // display message (error or success) + DisplayLastMessage(); + return err_code; +} + + +// load a DAPF file from disk, modify it in memory and then program the dongle +int DoProgramDongleWithMod(char *szFileDAPF) { + DAPF_HANDLE dapfHandle; + int dummy1, dummy2, err_code; + unsigned int dongle_number; + DINKEYINFO DinkeyInfo; + LICENCEINFO LicenceInfo[MAX_LICENCES]; + FILEINFO FileInfo[10]; + ALGORITHM Algorithms[MAX_USER_ALGS]; + DATAFILEENC DataFileEnc[MAX_DATA_ENCS]; + + // in this case we need to read the DAPF into our structures, so that the DAPF values can be modified + err_code = ReadDAPFEx(szFileDAPF, &DinkeyInfo, (LICENCEINFO *)&LicenceInfo, (FILEINFO *)&FileInfo, (ALGORITHM *)&Algorithms, (DATAFILEENC *)&DataFileEnc, &dummy1, &dummy2); + if (err_code != 0) { + DisplayLastMessage(); + return err_code; + } + + // patch new values + LicenceInfo[0].Features = 12345; + LicenceInfo[0].Execs = 100; + strcpy(LicenceInfo[0].LicenceName, "fred"); + + // get DAPF handle + dapfHandle = LoadDAPF(&DinkeyInfo, LicenceInfo, FileInfo, Algorithms, DataFileEnc, &err_code); + if (dapfHandle == NULL) { + DisplayLastMessage(); + return err_code; + } + + // program dongle + err_code = AddProtection(dapfHandle, ACTION_PROGRAM_DONGLE, 0, 0, &dongle_number); + + // Unload DAPF from memory + UnloadDAPF(&dapfHandle); + + // display message (error or success) + DisplayLastMessage(); + return err_code; +} + + +// load a DAPF file from disk and protect the files specified +// (in practice it is better to protect the files one at a time and output messages as you go along, similar to DinkeyAdd.exe) +// In this example we specify the flag to overwrite any existing output file that might exist. +int DoLockSoftware(char *szFileDAPF) { + DAPF_HANDLE dapfHandle; + int err_code; + unsigned int dummy; + + // load DAPF from File into memory + dapfHandle = LoadDAPFFromFile(szFileDAPF, &err_code); + if (dapfHandle == NULL) { + DisplayLastMessage(); + return err_code; + } + + // program dongle as specified by the DAPF file + err_code = AddProtection(dapfHandle, ACTION_PROTECT_SOFTWARE, -1, FLAGS_OVERWRITE_OUTPUT, &dummy); + + // Unload DAPF from memory + UnloadDAPF(&dapfHandle); + + // display message (error or success) + DisplayLastMessage(); + return err_code; +} + + +// load a DAPF file from disk and encrypt the shell data files specified +// (in practice it is better to encrypt the files one at a time and output messages as you go along, similar to DinkeyAdd.exe) +// In this example we specify the flag to overwrite any existing output file that might exist. +int DoEncryptShellDataFiles(char *szFileDAPF) { + DAPF_HANDLE dapfHandle; + int err_code; + + // load DAPF from File into memory + dapfHandle = LoadDAPFFromFile(szFileDAPF, &err_code); + if (dapfHandle == NULL) { + DisplayLastMessage(); + return err_code; + } + + // program dongle as specified by the DAPF file + err_code = EncryptShellDataFiles(dapfHandle, -1, FLAGS_OVERWRITE_OUTPUT); + + // Unload DAPF from memory + UnloadDAPF(&dapfHandle); + + // display message (error or success) + DisplayLastMessage(); + return err_code; +} + + +// load a DAPF file from disk and create a Temporary Software Key using the info that the user entered +int DoCreateTempSoftwareKey(char *szFileDAPF, char *szMachineID, char *szExpDay, char *szExpMonth, char *szExpYear) { + DAPF_HANDLE dapfHandle; + TEMP_SWKEY_INFO swkey_info; + int err_code; + unsigned int machineID = 0; + + // load DAPF from File into memory + dapfHandle = LoadDAPFFromFile(szFileDAPF, &err_code); + if (dapfHandle == NULL) { + DisplayLastMessage(); + return err_code; + } + + // fill out the SWKEY structure from the values the user entered + swkey_info.size = sizeof(TEMP_SWKEY_INFO); + if (szMachineID != NULL) + sscanf(szMachineID, "%x", &machineID); + swkey_info.machineID = machineID; + swkey_info.expiry_day = atoi(szExpDay); + swkey_info.expiry_month = atoi(szExpMonth); + swkey_info.expiry_year = atoi(szExpYear); + + // !!!! in this case we just choose Pro Plus. You could load the DAPF file into structures and see which model is selected. + // If there is more than one model selected you can ask the customer to choose which model they want. + swkey_info.dongle_model = SWKEY_MODEL_PRO_PLUS; + swkey_info.dongle_number = 0; // default + + // create the Temporary Software Key + err_code = CreateTempSoftwareKey(dapfHandle, &swkey_info, 0); + + // Unload DAPF from memory + UnloadDAPF(&dapfHandle); + + // display message (error or success) + DisplayLastMessage(); + return err_code; +} + +// load a DAPF file from disk and create a Demo Software Key Template using the info that the user entered +int DoCreateDemoSoftwareTemplate(char *szFileDAPF, char *szMaxDays) { + DAPF_HANDLE dapfHandle; + DEMO_SWKEY_INFO swkey_info; + int err_code; + + // load DAPF from File into memory + dapfHandle = LoadDAPFFromFile(szFileDAPF, &err_code); + if (dapfHandle == NULL) { + DisplayLastMessage(); + return err_code; + } + + // fill out the SWKEY structure from the values the user entered + swkey_info.size = sizeof(DEMO_SWKEY_INFO); + swkey_info.max_days = atoi(szMaxDays); + + // !!!! in this case we just choose the default model (assuming you only selected one in the DAPF file). + // If you want to specify more than one model then OR the flags together. e.g. SWKEY_BITMAP_PRO_LITE | SWKEY_BITMAP_PRO_PLUS + swkey_info.models = SWKEY_BITMAP_DEFAULT; + + // create the Temporary Software Key + err_code = CreateDemoSoftwareKeyTemplate(dapfHandle, &swkey_info, 0); + + // Unload DAPF from memory + UnloadDAPF(&dapfHandle); + + // display message (error or success) + DisplayLastMessage(); + return err_code; +} + + +// routine for main dialog box +BOOL CALLBACK MainDlgProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { + char szFileDAPF[256]; + char szMachineID[9], szMaxDays[3]; + char szExpDay[3], szExpMonth[3], szExpYear[5]; + + switch (message) + { + case WM_INITDIALOG: + SetDlgItemText(hwnd, IDC_TEMP_EXP_DAY, "dd"); + SetDlgItemText(hwnd, IDC_TEMP_EXP_MONTH, "mm"); + SetDlgItemText(hwnd, IDC_TEMP_EXP_YEAR, "yyyy"); + break; + + case WM_COMMAND: + GetDlgItemText(hwnd, IDC_DAPF_PATH, szFileDAPF, sizeof(szFileDAPF)); + + // *** Program Dongle button clicked *** + if (LOWORD(wParam) == IDC_PROGRAM_DONGLE && HIWORD(wParam) == BN_CLICKED) { + DoProgramDongle(szFileDAPF); + } + + // *** Program Dongle with Modification button clicked *** + if (LOWORD(wParam) == IDC_PROGRAM_DONGLE_MOD && HIWORD(wParam) == BN_CLICKED) { + DoProgramDongleWithMod(szFileDAPF); + } + + // *** Lock Software button clicked *** + if (LOWORD(wParam) == IDC_LOCK_SOFTWARE && HIWORD(wParam) == BN_CLICKED) { + DoLockSoftware(szFileDAPF); + } + + // *** Encrypt Shell Data Files button clicked *** + if (LOWORD(wParam) == IDC_ENCRYPT_SHELL_DATA_FILES && HIWORD(wParam) == BN_CLICKED) { + DoEncryptShellDataFiles(szFileDAPF); + } + + // *** Create Temporary Software Key button clicked *** + if (LOWORD(wParam) == IDC_CREATE_TEMP_SWKEY && HIWORD(wParam) == BN_CLICKED) { + GetDlgItemText(hwnd, IDC_MACHINEID, szMachineID, sizeof(szMachineID)); + GetDlgItemText(hwnd, IDC_TEMP_EXP_DAY, szExpDay, sizeof(szExpDay)); + GetDlgItemText(hwnd, IDC_TEMP_EXP_MONTH, szExpMonth, sizeof(szExpMonth)); + GetDlgItemText(hwnd, IDC_TEMP_EXP_YEAR, szExpYear, sizeof(szExpYear)); + DoCreateTempSoftwareKey(szFileDAPF, szMachineID, szExpDay, szExpMonth, szExpYear); + } + + // *** Create Demo Software Key Template button clicked *** + if (LOWORD(wParam) == IDC_CREATE_DEMO_SWKEY && HIWORD(wParam) == BN_CLICKED) { + GetDlgItemText(hwnd, IDC_DEMO_MAX_DAYS, szMaxDays, sizeof(szMaxDays)); + DoCreateDemoSoftwareTemplate(szFileDAPF, szMaxDays); + } + + break; + + case WM_CLOSE: + EndDialog(hwnd, TRUE); + return TRUE; + } + + return FALSE; +} + + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow ) { + // display dialog allow user to enter code + DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, (DLGPROC)MainDlgProc); // display main screen + return 0; +} + + +// gets & displays the message from the last API call to the DinkeyAdd Module +void DisplayLastMessage(void) { + char *szMessage; + int msg_len; + + GetLastMessage(NULL, 0, &msg_len); + + szMessage = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, msg_len); + + if (szMessage != NULL) { + GetLastMessage(szMessage, msg_len, NULL); + MessageBox(NULL, szMessage, g_szAppName, MB_OK); + HeapFree(GetProcessHeap(), 0, szMessage); + } + return; +} diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/dris.h b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/dris.h new file mode 100644 index 0000000..a3a7229 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/dris.h @@ -0,0 +1,101 @@ +// dris.h +// Dinkey Runtime Information Structure (DRIS) +// !! this file should not be modified + +#pragma pack(1) + +typedef struct DRIS { + // the first 4 fields are never encrypted + char header[4]; // should be set to DRIS + // inputs + int size; // size of this structure + int seed1; // seed for data/dris encryption + int seed2; // as above + // (maybe encrypted from now on) + int function; // specify only one function + int flags; // options for the function selected. To use more than one OR them together: OPTION1 | OPTION2... + unsigned int execs_decrement; // amount by which to dec execs if we use flag: DEC_MANY_EXECS + int data_crypt_key_num; // number of the key (1-3) that the dongle uses to encrypt or decrypt user data + int rw_offset; // offset in the dongle data area to read or write data + int rw_length; // length of data are to read/write/encrypt/decrypt + char *rw_data_ptr; // pointer to data to write / be read + char alt_licence_name[256]; // protection check for different licence instead of the default one, must be null-terminated + int var_a; // variable values for user algorithm + int var_b; + int var_c; + int var_d; + int var_e; + int var_f; + int var_g; + int var_h; + int alg_number; // the number of the user algorithm that you want to execute + + // outputs + int ret_code; // return code from the protection check + int ext_err; // extended error + int type; // type of dongle detected. 1 = Pro, 2 = FD + int model; // model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + int sdsn; // Software Developer's Serial Number + char prodcode[12]; // Product Code (null-terminated) + unsigned int dongle_number; + int update_number; + unsigned int data_area_size; // size of the data area used in the dongle detected + int max_alg_num; // the maximum algorithm number in the dongle detected + int execs; // executions left: -1 indicates 'no limit' + int exp_day; // expiry day: -1 indicates 'no limit' + int exp_month; // expiry month: -1 indicates 'no limit' + int exp_year; // expiry year: -1 indicates 'no limit' + unsigned int features; // features value + int net_users; // maximum number of network users for the dongle detected: -1 indicates 'no limit' + int alg_answer; // answer to the user algorithm executed with the given variable values + unsigned int fd_capacity; // capacity of the data area in FD dongle. + char fd_drive[128]; // drive letter of FD dongle detected e.g. 'f:\' (or mount name under Linux) + int swkey_type; // 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + int swkey_exp_day; // software key expiry date (if software key detected) + int swkey_exp_month; + int swkey_exp_year; +} DRIS; + +typedef struct NU_INFO { + char licenceName[256]; + char userName[50]; + char computerName[256]; + char ipAddress[16]; +} NU_INFO; + +#pragma pack() + +// functions - must specify only one +#define PROTECTION_CHECK 1 // checks for dongle, check program params... +#define EXECUTE_ALGORITHM 2 // protection check + calculate answer for specified algorithm with specified inputs +#define WRITE_DATA_AREA 3 // protection check + writes dongle data area +#define READ_DATA_AREA 4 // protection check + reads dongle data area +#define ENCRYPT_USER_DATA 5 // protection check + the dongle will encrypt user data +#define DECRYPT_USER_DATA 6 // protection check + the dongle will decrypt user data +#define FAST_PRESENCE_CHECK 7 // checks for the presence of the correct dongle only with minimal security, no flags allowed. +#define STOP_NET_USER 8 // stops a network user (a protection check is NOT performed) + +// flags - can specify as many as you like +#define DEC_ONE_EXEC 1 // decrement execs by 1 +#define DEC_MANY_EXECS 2 // decrement execs by number specified in execs_decrement +#define START_NET_USER 4 // starts a network user +#define USE_FUNCTION_ARGUMENT 16 // use the extra argument in the function for pointers +#define CHECK_LOCAL_FIRST 32 // always look in local ports before looking in network ports +#define CHECK_NETWORK_FIRST 64 // always look on the network before looking in local ports +#define USE_ALT_LICENCE_NAME 128 // use name specified in alt_licence_name instead of the default one +#define DONT_SET_MAXDAYS_EXPIRY 256 // if the max days expiry date has not been calculated then do not do it this time +#define MATCH_DONGLE_NUMBER 512 // restrict the search to match the dongle number specified in the DRIS +#define DONT_RETURN_FD_DRIVE 1024 // if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + + +// Runtime module API declarations +#ifdef __cplusplus + extern "C" { +#endif + +int WINAPI DDProtCheck(DRIS *dris, unsigned char *data); +int WINAPI DDGetNetUserList(char *licence_name, int *num_net_users, NU_INFO *nu_info, int num_info_structs, int *extended_error); + +#ifdef __cplusplus +} +#endif diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/drpf.h b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/drpf.h new file mode 100644 index 0000000..313190f --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/drpf.h @@ -0,0 +1,117 @@ +// drpf.h +// !! this file should not be modified + +// NB DRPF file is: +// REMOTEINFO +// LICENCEINFO (however many are needed) +// ALGCHANGE (however many are needed) +// DATACHANGE (however many are needed) - may refer to external files. + +// Remember: you only need to specify a value if you want to change it. Otherwise you +// specify the default "no change" setting. For most entries this is indicated by 0. +// However, for MaxNetUsers and LicenceNetUsers it is "-2" because 0 is a valid value to change to. + +#pragma pack (push,1) // so it is byte-aligned + +typedef struct REMOTEINFO { + char Header[4]; // Should be set to "DRPF" = DinkeyRemote Parameter File + unsigned int Version; // version of this structure - currently 2 + char ProdCode[12]; + unsigned int DongleNumber; + int UpdateNumber; + char Notes[256]; // user-defined notes + unsigned int NumLicences; + unsigned int NumAlgs; // number of algs to set (incl r/w alg) + unsigned int NumDataChanges; // number of data change blocks specified + unsigned int DataAreaSize; // -1 = increase as necessary. specifies the new size of the data area + int PerLicence; // 0 = no change, 1 = per licence net users, 2 = per product net users + int MaxNetUsers; // product net users, unlimited = -1, no change = -2 + unsigned int LastUsedDay; // Day = 0 (only) -> no change + unsigned int LastUsedMonth; + unsigned int LastUsedYear; + char DataEncKeyProdCode[12]; + unsigned int ChangeCodeType; // 0 = no change, bit0 = only accept secure codes, bit1 = accept secure & short codes + int CodeType; // type of code to generate. 0 = secure code, 1 = short code + char OutputFileName[256];// name of file to output code to. Null (default) -> UpdateCode.ducf + int LockDongle; // 1 = lock dongle to user's computer + int ResetDongleLock; // 1 = reset the dongle lock so that the dongle can be locked to a new machine +} REMOTEINFO; + +typedef struct LICENCEINFO { + char LicenceName[256]; + unsigned int Action; // 0 = change, 1 = delete, 2 = add + unsigned int AddSetExecs; // 0 = no change to execs, 1 = add, 2 = set + int Execs; // -1 = no limit + int ExecsWarn; // 0 = remove warning, -1 = no change + int ExpiryDay; // -1 = no limit, 0 = no change + int ExpiryMonth; + int ExpiryYear; + unsigned int AddSetMaxDays; // 0 = no change, 1 = add, 2 = set + int MaxDays; // -1 = no limit + int DaysWarn; // 0 = remove warning, -1 = no change + int FeaturesFlag; // 0 = don't change features, 1 = change features + unsigned int Features; // all values OK + int LicenceNetUsers; // unlimited = -1, no change = -2 +} LICENCEINFO; + +typedef struct ALGCHANGE { + int alg_number; // number of algorithm to set (0 = r/w algorithm) + unsigned char algorithm[12]; // algorithm +} ALGCHANGE; + +typedef struct DATACHANGE { + unsigned int type; // 1 = file, 2 = hex data, 3 = ascii, 4 = ascii null-term string + unsigned int offset; // offset in dongle data memory to write data + int length; // length of data to change + unsigned char data[256]; // data to write OR name of data file depending on which method set +} DATACHANGE; + +typedef struct UPDATE_CODE_OUTPUTS { + char szShortCode[128*3]; // the update code (for short update codes only) + char szUpdateCodeFile[256]; // the output ducf that contains the update code + char szConfirmationCode[8]; // the confirmation code +} UPDATE_CODE_OUTPUTS; + +typedef void *DRPF_HANDLE; // for DinkeyRemote Module API functions + +#pragma pack (pop) + +// constants +#define DRPF_VERSION 2 // current DRPF version + +// WriteDRPF API flags +#define FLAGS_LOSE_FEATURES 1 // means that you can save the DRPF file to an earlier version even if it means losing some new features that have been currently set + +// constants for drpf_format in ReadDRPFEx and WriteDRPFEx functions +#define DRPF_FORMAT_BINARY 1 +#define DRPF_FORMAT_JSON 2 +#define DRPF_FORMAT_JSON_MIN 3 // this value is only used with WriteDRPEx. ReadDRPFEx cannot return this value. + +#define MAX_LICENCES 255 // max number of licence changes in a DRPF file (theoretically unlimited but easier if we limit it) +#define MAX_ALG_CHANGES 21 // max number of alg changes in DRPF file +#define MAX_DATA_CHANGES 127 // max number of data area changes in DRPF file + +// DinkeyRemote module API declarations +#ifdef __cplusplus + extern "C" { +#endif + +int WINAPI ReadDRPFEx(char *szFileDRPF, REMOTEINFO *pRemoteInfo, LICENCEINFO *pLicenceInfo, ALGCHANGE *pAlgChanges, DATACHANGE *pDataChanges, int *drpf_version, int *drpf_format); + +DRPF_HANDLE WINAPI LoadDRPF(REMOTEINFO *pRemoteInfo, LICENCEINFO *pLicenceInfo, ALGCHANGE *pAlgChanges, DATACHANGE *pDataChanges, int *err_code); + +DRPF_HANDLE WINAPI LoadDRPFFromFile(char *szFileDRPF, int *err_code); + +int WINAPI WriteDRPFEx(DRPF_HANDLE handle, char *szFileDRPF, int drpf_format, int drpf_version, int flags); + +void WINAPI UnloadDRPF(DRPF_HANDLE *handle); + +int WINAPI GenerateUpdateCode(DRPF_HANDLE handle, unsigned int dongle_number, int update_number, char *ducf_file, char *logfile, UPDATE_CODE_OUTPUTS *pOutputs); + +void WINAPI GetLastMessage(char *szMessage, int buffer_size, int *message_length); + +int WINAPI GetLastExtendedError(void); + +#ifdef __cplusplus +} +#endif diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/drpftest.c b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/drpftest.c new file mode 100644 index 0000000..4276065 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/drpftest.c @@ -0,0 +1,156 @@ +// drpfTest + +// Sample code for calling the DinkeyRemote module + +// The sample code contains 2 functions. The sample code is just a guide. + +// There are two methods to loading a DRPF file. These are shown in the first two functions: +// DoUpdateCode and DoUpdateCodewithMod + +// DoUpdateCode: we load the DRPF file from disk and get a handle and use it "as is" using the API +// call LoadDRPFFromFile. You can make some limited changes to overwrite the default +// behaviour by using API flags. + +// DoUpdateCodewithMod: we load the DRPF file from disk and load into structures. We can then modify the +// DRPF settings by modifying this structure. This method uses the API calls +// ReadDRPFEx and LoadDRPF. + +#include +#include + +#include "Visual Studio 5\DinkeyRemote\resource.h" +#include "drpf.h" + +#ifdef _MSC_VER + #pragma warning(disable:4996) // to disable warnings about sprintf etc... means we can use the same source for all compilers +#endif + + +char g_szAppName[] = "drpfTest"; + +void DisplayLastMessage(void); // gets & displays the message from the DinkeyRemote Module + + +// load a DRPF file from disk and generate an update code as specified by the DRPF file +int DoUpdateCode(char *szFileDRPF) { + DRPF_HANDLE drpfHandle; + UPDATE_CODE_OUTPUTS Outputs; + int err_code; + + // load DRPF from File into memory + drpfHandle = LoadDRPFFromFile(szFileDRPF, &err_code); + if (drpfHandle == NULL) { + DisplayLastMessage(); + return err_code; + } + + // generate the update code as specified by the DRPF file + err_code = GenerateUpdateCode(drpfHandle, 0, 0, NULL, NULL, &Outputs); + + // Unload DRPF from memory + UnloadDRPF(&drpfHandle); + + // display message (error or success) + DisplayLastMessage(); + return err_code; +} + + +// load a DRPF file from disk, modify it in memory and then generate the update code +int DoUpdateCodeWithMod(char *szFileDRPF) { + DRPF_HANDLE drpfHandle; + int dummy1, dummy2, err_code; + REMOTEINFO RemoteInfo; + LICENCEINFO LicenceInfo[MAX_LICENCES]; + ALGCHANGE AlgChanges[MAX_ALG_CHANGES]; + DATACHANGE DataChanges[MAX_DATA_CHANGES]; + UPDATE_CODE_OUTPUTS Outputs; + + // in this case we need to read the DRPF into our structures, so that the DRPF values can be modified + err_code = ReadDRPFEx(szFileDRPF, &RemoteInfo, (LICENCEINFO *)&LicenceInfo, (ALGCHANGE *)&AlgChanges, (DATACHANGE *)&DataChanges, &dummy1, &dummy2); + if (err_code != 0) { + DisplayLastMessage(); + return err_code; + } + + // patch new values in the RemoteInfo, LicenceInfo, AlgChanges, DataChanges structures + LicenceInfo[0].FeaturesFlag = 1; // so that the features value below will be recognised + LicenceInfo[0].Features = 12345; + LicenceInfo[0].AddSetExecs = 1; // so the executions will be added to existing + LicenceInfo[0].Execs = 100; + + // get DRPF handle + drpfHandle = LoadDRPF(&RemoteInfo, LicenceInfo, AlgChanges, DataChanges, &err_code); + if (drpfHandle == NULL) { + DisplayLastMessage(); + return err_code; + } + + // generate the update code as specified by the DRPF file + err_code = GenerateUpdateCode(drpfHandle, 0, 0, NULL, NULL, &Outputs); + + // Unload DRPF from memory + UnloadDRPF(&drpfHandle); + + // display message (error or success) + DisplayLastMessage(); + return err_code; +} + + +// routine for main dialog box +BOOL CALLBACK MainDlgProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { + char szFileDRPF[256]; + + switch (message) + { + case WM_INITDIALOG: + break; + + case WM_COMMAND: + GetDlgItemText(hwnd, IDC_DRPF_PATH, szFileDRPF, sizeof(szFileDRPF)); + + // *** Generate Update Code button clicked *** + if (LOWORD(wParam) == IDC_UPDATE_CODE && HIWORD(wParam) == BN_CLICKED) { + DoUpdateCode(szFileDRPF); + } + + // *** Generate Update Code with Modification button clicked *** + if (LOWORD(wParam) == IDC_UPDATE_CODE_MOD && HIWORD(wParam) == BN_CLICKED) { + DoUpdateCodeWithMod(szFileDRPF); + } + + break; + + case WM_CLOSE: + EndDialog(hwnd, TRUE); + return TRUE; + } + + return FALSE; +} + + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow ) { + // display dialog allow user to enter code + DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, (DLGPROC)MainDlgProc); // display main screen + return 0; +} + + +// gets & displays the message from the last API call to the DinkeyRemote Module +void DisplayLastMessage(void) { + char *szMessage; + int msg_len; + + GetLastMessage(NULL, 0, &msg_len); + + szMessage = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, msg_len); + + if (szMessage != NULL) { + GetLastMessage(szMessage, msg_len, NULL); + MessageBox(NULL, szMessage, g_szAppName, MB_OK); + HeapFree(GetProcessHeap(), 0, szMessage); + } + return; +} diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyAdd32.lib b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyAdd32.lib new file mode 100644 index 0000000..ed2fde6 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyAdd32.lib differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyAdd32_borland.lib b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyAdd32_borland.lib new file mode 100644 index 0000000..b8555c6 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyAdd32_borland.lib differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyAdd64.lib b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyAdd64.lib new file mode 100644 index 0000000..b85a461 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyAdd64.lib differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyAdd64_borland.lib b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyAdd64_borland.lib new file mode 100644 index 0000000..307c511 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyAdd64_borland.lib differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyChange.lib b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyChange.lib new file mode 100644 index 0000000..7fc1bc4 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyChange.lib differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyChange64.lib b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyChange64.lib new file mode 100644 index 0000000..3dc35b7 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyChange64.lib differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyChange64Debug.lib b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyChange64Debug.lib new file mode 100644 index 0000000..5a4f3d7 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyChange64Debug.lib differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyChangeDebug.lib b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyChangeDebug.lib new file mode 100644 index 0000000..256c39d Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyChangeDebug.lib differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyChangeDebug_borland.lib b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyChangeDebug_borland.lib new file mode 100644 index 0000000..b3dd1b6 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyChangeDebug_borland.lib differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyChange_borland.lib b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyChange_borland.lib new file mode 100644 index 0000000..61a7187 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyChange_borland.lib differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyRemote32.lib b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyRemote32.lib new file mode 100644 index 0000000..b1af486 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyRemote32.lib differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyRemote32_borland.lib b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyRemote32_borland.lib new file mode 100644 index 0000000..579b9cd Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyRemote32_borland.lib differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyRemote64.lib b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyRemote64.lib new file mode 100644 index 0000000..25e44d7 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyRemote64.lib differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyRemote64_borland.lib b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyRemote64_borland.lib new file mode 100644 index 0000000..307c511 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/DinkeyRemote64_borland.lib differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/README.txt new file mode 100644 index 0000000..d2ea6aa --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/README.txt @@ -0,0 +1,31 @@ +Import Libraries +~~~~~~~~~~~~~~~~ + +These are used with C/C++ languages so that the compiler knows what functions +can be found in which DLLs. You need to link the appropriate import library to +your source code so that the DLL can be called correctly. + +Microsoft import libraries +~~~~~~~~~~~~~~~~~~~~~~~~~~ +dpwin32.lib +dpwin32debug.lib +DinkeyChange.lib +DinkeyChangeDebug.lib + +Borland C++ Builder import libraries +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +dpwin32_borland.lib +dpwin32debug_borland.lib +DinkeyChange_borland.lib +DinkeyChangeDebug_borland.lib + +Dev C++ and MinGW import libraries +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +libdpwin32.a +libdpwin32debug.a +libDinkeyChange.a +libDinkeyChangeDebug.a + +If you look at the sample code for the relevant language / compiler then it +will tell you how to use these import libraries. + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/dpwin32.lib b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/dpwin32.lib new file mode 100644 index 0000000..912ecf0 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/dpwin32.lib differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/dpwin32_borland.lib b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/dpwin32_borland.lib new file mode 100644 index 0000000..f718ac2 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/dpwin32_borland.lib differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/dpwin32debug.lib b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/dpwin32debug.lib new file mode 100644 index 0000000..404b47c Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/dpwin32debug.lib differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/dpwin32debug_borland.lib b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/dpwin32debug_borland.lib new file mode 100644 index 0000000..1d248bc Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/dpwin32debug_borland.lib differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/dpwin64.lib b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/dpwin64.lib new file mode 100644 index 0000000..0f71232 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/dpwin64.lib differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/dpwin64debug.lib b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/dpwin64debug.lib new file mode 100644 index 0000000..fe890fd Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/import_libs/dpwin64debug.lib differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/object_modules/dpwin32_coff.obj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/object_modules/dpwin32_coff.obj new file mode 100644 index 0000000..9963519 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/object_modules/dpwin32_coff.obj differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/object_modules/dpwin32_omf.obj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/object_modules/dpwin32_omf.obj new file mode 100644 index 0000000..bbf3f76 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/object_modules/dpwin32_omf.obj differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/object_modules/dpwin64.obj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/object_modules/dpwin64.obj new file mode 100644 index 0000000..2d34def Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/C/object_modules/dpwin64.obj differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/FireMonkey/Runtime/DllTest.dpr b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/FireMonkey/Runtime/DllTest.dpr new file mode 100644 index 0000000..af34fe8 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/FireMonkey/Runtime/DllTest.dpr @@ -0,0 +1,15 @@ +program DllTest; + +uses + System.StartUpCopy, + FMX.Forms, + apitest in 'apitest.pas' {Form1}, + dris in 'dris.pas'; + +{$R *.res} + +begin + Application.Initialize; + Application.CreateForm(TForm1, Form1); + Application.Run; +end. diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/FireMonkey/Runtime/DllTest.dproj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/FireMonkey/Runtime/DllTest.dproj new file mode 100644 index 0000000..aab5059 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/FireMonkey/Runtime/DllTest.dproj @@ -0,0 +1,1106 @@ + + + {D7AD8AB7-4781-4244-99BD-D52E35E152EA} + 18.8 + FMX + DllTest.dpr + True + Debug + OSX64 + 4103 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Cfg_1 + true + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + true + Cfg_2 + true + true + + + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) + $(BDS)\bin\delphi_PROJECTICON.ico + $(BDS)\bin\delphi_PROJECTICNS.icns + DllTest + + + DBXSqliteDriver;IndyIPCommon;RESTComponents;bindcompdbx;DBXInterBaseDriver;IndyIPServer;IndySystem;tethering;fmxFireDAC;FireDAC;bindcompfmx;FireDACSqliteDriver;FireDACPgDriver;inetdb;soaprtl;DbxCommonDriver;fmx;FireDACIBDriver;fmxdae;xmlrtl;soapmidas;fmxobj;rtl;DbxClientDriver;CustomIPTransport;dbexpress;IndyCore;bindcomp;dsnap;FireDACCommon;IndyIPClient;RESTBackendComponents;soapserver;dbxcds;bindengine;DBXMySQLDriver;CloudService;dsnapxml;FireDACMySQLDriver;dbrtl;IndyProtocols;inetdbxpress;FireDACCommonODBC;FireDACCommonDriver;inet;fmxase;$(DCC_UsePackage) + CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts + Debug + true + + + DBXSqliteDriver;IndyIPCommon;RESTComponents;bindcompdbx;DBXInterBaseDriver;IndyIPServer;IndySystem;tethering;fmxFireDAC;FireDAC;bindcompfmx;FireDACSqliteDriver;FireDACPgDriver;inetdb;soaprtl;DbxCommonDriver;fmx;FireDACIBDriver;fmxdae;xmlrtl;soapmidas;fmxobj;rtl;DbxClientDriver;CustomIPTransport;dbexpress;IndyCore;bindcomp;dsnap;FireDACCommon;IndyIPClient;RESTBackendComponents;soapserver;dbxcds;bindengine;DBXMySQLDriver;CloudService;dsnapxml;FireDACMySQLDriver;dbrtl;IndyProtocols;inetdbxpress;FireDACCommonODBC;FireDACCommonDriver;inet;fmxase;$(DCC_UsePackage) + CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts + Debug + true + + + DBXSqliteDriver;IndyIPCommon;RESTComponents;bindcompdbx;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;vclFireDAC;IndySystem;tethering;svnui;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;vclimg;FireDAC;vcltouch;vcldb;bindcompfmx;svn;FireDACSqliteDriver;FireDACPgDriver;inetdb;soaprtl;DbxCommonDriver;fmx;FireDACIBDriver;fmxdae;xmlrtl;soapmidas;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;dbexpress;IndyCore;vclx;bindcomp;appanalytics;dsnap;FireDACCommon;IndyIPClient;bindcompvcl;RESTBackendComponents;VCLRESTComponents;soapserver;dbxcds;VclSmp;adortl;vclie;bindengine;DBXMySQLDriver;CloudService;dsnapxml;FireDACMySQLDriver;dbrtl;IndyProtocols;inetdbxpress;FireDACCommonODBC;FireDACCommonDriver;inet;fmxase;$(DCC_UsePackage) + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + Debug + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + $(BDS)\bin\default_app.manifest + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + + + DBXSqliteDriver;IndyIPCommon;RESTComponents;bindcompdbx;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;vclFireDAC;IndySystem;tethering;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;vclimg;FireDAC;vcltouch;vcldb;bindcompfmx;FireDACSqliteDriver;FireDACPgDriver;inetdb;soaprtl;DbxCommonDriver;fmx;FireDACIBDriver;fmxdae;xmlrtl;soapmidas;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;dbexpress;IndyCore;vclx;bindcomp;appanalytics;dsnap;FireDACCommon;IndyIPClient;bindcompvcl;RESTBackendComponents;VCLRESTComponents;soapserver;dbxcds;VclSmp;adortl;vclie;bindengine;DBXMySQLDriver;CloudService;dsnapxml;FireDACMySQLDriver;dbrtl;IndyProtocols;inetdbxpress;FireDACCommonODBC;FireDACCommonDriver;inet;fmxase;$(DCC_UsePackage) + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + Debug + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + $(BDS)\bin\default_app.manifest + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + /usr/X11/bin/xterm -e "%debuggee%" + true + (None) + + + false + true + PerMonitorV2 + + + true + PerMonitorV2 + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + true + PerMonitorV2 + + + true + PerMonitorV2 + + + + MainSource + + +
Form1
+ fmx +
+ + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + +
+ + Delphi.Personality.12 + Application + + + + DllTest.dpr + + + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + + + true + + + + + Info.plist + true + + + + + Info.plist + true + + + + + DllTest.icns + true + + + + + true + + + + + true + + + + + true + + + + + true + + + + + DllTest.icns + true + + + + + DllTest.exe + true + + + + + DllTest + true + + + + + DllTest + true + + + + + DllTest + true + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + classes + 1 + + + classes + 1 + + + + + res\xml + 1 + + + res\xml + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\armeabi + 1 + + + library\lib\armeabi + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\mips + 1 + + + library\lib\mips + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-v21 + 1 + + + res\values-v21 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-ldpi + 1 + + + res\drawable-ldpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-small + 1 + + + res\drawable-small + 1 + + + + + res\drawable-normal + 1 + + + res\drawable-normal + 1 + + + + + res\drawable-large + 1 + + + res\drawable-large + 1 + + + + + res\drawable-xlarge + 1 + + + res\drawable-xlarge + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + Contents\MacOS + 1 + .framework + + + Contents\MacOS + 1 + .framework + + + 0 + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .dll;.bpl + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .bpl + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + 1 + + + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + Contents + 1 + + + Contents + 1 + + + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + Contents\MacOS + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + + + + + + + + + + + True + True + True + True + + + 12 + + + + +
diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/FireMonkey/Runtime/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/FireMonkey/Runtime/README.txt new file mode 100644 index 0000000..9c6a599 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/FireMonkey/Runtime/README.txt @@ -0,0 +1,105 @@ +Sample code to call Runtime modules in Delphi +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Delphi 10.3 but should also work in other versions. +If you want to create traditional Delphi applications under Windows please +use the VCL projects instead. + +The source files in the project are: + +File name Description +apitest.pas main source code file +dris.pas contains DRIS structure definition and other definitions. +apitest.fmx form design +DllTest.dpr project file +DllTest.dproj project file + +The idea is to include the dris.pas file in your project and use/modify which ever +functions from apitest.pas you feel are appropriate. + +This sample has been tested under Win32, Win64, Mac32 and Mac64 environments. In order +to build and deploy under MacOS you need to setup a remote Mac machine using profile. + +The sample code contains 11 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. However, you should +still display or log any error codes returned by the protection check otherwise you will not +be able to identify the cause of the error. (You can look up error codes in our knowledge +base: microcosm.com/kb). + +This project calls the appropriate dynamic runtime module for the OS. +(Note, in Windows you could link with the static module instead (we do this for the ObjTest +project in the VCL samples). However, we do not supply the correct static libraries for MacOS. +This is because Delphi requires the object modules to be in its own custom format.) + +Note - you should run DinkeyAdd and protect all the runtime modules that you require +(for each platform that you want to support. e.g. dpwin64.dll for Windows 64-bit). +Do not protect your program directly. Because your program is linked to this library it is +protected. + +The protected library will need to be in the same folder as your compiled program +for it to run correctly (in the Mac of MacOS it needs to reside in the Contents/MacOS directory +of your application bundle). You can add the protected library to the list of deployment files +(Project | Deployment) so that it is copied to the correct location when you deploy it. + +The Delphi compile has a few quirks under 64-bit MacOS build: +1) You need to have the runtime dynamic module dpmac64.dylib to be present in the project folder + for the project to build correctly (this is not necessary under the other build platforms). +2) There is a bug in the linker so that the dpmac64.dylib is not referenced correctly from the + deployed application (if you run otool -L on the application you will see that it only + references dpmac64.dylib. It should be @rpath/dpmac64.dylib.) The linker does this correctly for + the 32-bit build. After deploying you need to open a terminal, change directory to the application + /Contents/MacOS directory and then run the following command: + + install_name_tool -change dpmac64.dylib @rpath/dpmac64.dylib + + Ideally you would modify the deployment under MacOS64 so that a script executes this each time. + Unfortunately, there doesn't seem to be a way of doing this. + +Debug Modules +~~~~~~~~~~~~~~ +Note - once the runtime module is protected you will not be able to debug +your program - after our API has been called. Our strong anti-debug code will cause +the debugger to throw an exception. If you do want to debug your code +then you can use our debug modules: e.g. dpwin64debug.dll for 64-bit Windows, but these +should not be used for release. + +You could setup your project so that your code links the debug module during your debug build +and the standard module when you produce your release code. + +Note: the debug module has the following restrictions: + +1) It will not correctly start a network user (network dongles only). However, other than that + the protection check will function correctly and return success. +2) You will not be able to encrypt the DRIS. (If you do encrypt the DRIS in your release build + then you should make sure that CryptDRIS does not get called in your debug build). +3) The protection check will take slightly longer than normal. +4) The DDGetNetUserList function will return error 428 (not implemented). +5) A temporary subprocess is created which may be (falsely) detected as malicious by anti-virus + programs. + +Differences with the VCL code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +DRIS: + The longint type is changed to FixedInt because longint can be 8-bytes in some platforms + The longword type is change to FixedUInt because longword can be 8-bytes in some platforms + More conditional code to call native dynamic library on different platforms + Uses the dynamic modules and does not link with the static modules + +APITEST: + Uses ShowMessage rather than MessageDlg (now deprecated) + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/FireMonkey/Runtime/apitest.Macintosh.fmx b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/FireMonkey/Runtime/apitest.Macintosh.fmx new file mode 100644 index 0000000..3d1ea0e --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/FireMonkey/Runtime/apitest.Macintosh.fmx @@ -0,0 +1,3 @@ +inherited Form1_Macintosh: TForm1_Macintosh + DesignerMasterStyle = 0 +end diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/FireMonkey/Runtime/apitest.fmx b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/FireMonkey/Runtime/apitest.fmx new file mode 100644 index 0000000..885bc4d --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/FireMonkey/Runtime/apitest.fmx @@ -0,0 +1,22 @@ +object Form1: TForm1 + Left = 0 + Top = 0 + Caption = 'Form1' + ClientHeight = 197 + ClientWidth = 306 + FormFactor.Width = 320 + FormFactor.Height = 480 + FormFactor.Devices = [Desktop] + DesignerMasterStyle = 0 + object Label1: TLabel + StyledSettings = [Family, Style, FontColor] + Position.X = 80.000000000000000000 + Position.Y = 72.000000000000000000 + Size.Width = 145.000000000000000000 + Size.Height = 33.000000000000000000 + Size.PlatformDefault = False + TextSettings.Font.Size = 30.000000000000000000 + Text = 'It worked!' + TabOrder = 1 + end +end diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/FireMonkey/Runtime/apitest.pas b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/FireMonkey/Runtime/apitest.pas new file mode 100644 index 0000000..95490a1 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/FireMonkey/Runtime/apitest.pas @@ -0,0 +1,876 @@ +unit apitest; + +interface + +uses + System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, + FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, + FMX.Controls.Presentation, FMX.StdCtrls, + dris; + +type + TForm1 = class(TForm) + Label1: TLabel; + private + { Private declarations } + public + { Public declarations } + end; + +var + Form1: TForm1; + +implementation + +{$R *.fmx} +{$R *.Macintosh.fmx MACOS} + +{ !! We strongly recommend that you read the "readme.txt" file in the sample code folder. + !! It contains important instructions on how to use the sample code } + +{ The sample code contains 11 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. To choose which function +this code uses see the startup code at the bottom of this file. + +this file contains 11 protection-check functions. + longint ProtCheck(); a standard protection check + longint ProtCheckWithAlg(); a protection check & executing an Algorithm + longint WriteBytes(); a protection check & write data to the dongle + longint ReadBytes(); a protection check & read data from the dongle + longint EncryptUserData(); a protection check & encrypting data and then decrypting the data + +these functions are the same as the functions listed above but encrypting all parameters passed to our API + longint ProtCheckEnc(); a standard protection check + longint ProtCheckWithAlgEnc(); a protection check & executing an Algorithm + longint WriteBytesEnc(); a protection check & write data to the dongle + longint ReadBytesEnc(); a protection check & read data from the dongle + longint EncryptUserDataEnc(); a protection check & encrypting data and then decrypting the data + + longint DisplayNetUsers(net_users, model); this function displays the current network users + + If you are using Dinkey Lite then you can only use 4 functions: +ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + } + +const MY_SDSN = 10101; { !!!! change this value to be the value of your SDSN (demo = 10101) } +const MY_PRODCODE = 'DEMO'; + +{ this procedure initialises the DRIS with random bytes } +procedure random_set(data: PByte; length: integer); +var + i : integer; +begin + Randomize(); + for i := 0 to length-1 do + begin + data^ := Random(256); + Inc(data); { increment the pointer so we can access the next byte } + end; +end; + +{ displays messages for the most common errors. You will want to change this for your code } +procedure DisplayError(ret_code, extended_error:integer); +var + display : string; +begin + case ret_code of + 401: display := 'Error! No dongles detected!'; + 403: display := 'Error! The dongle detected has a different type to the one specified in DinkeyAdd.'; + 404: display := 'Error! The dongle detected has a different model to those specified in DinkeyAdd.'; + 409: display := 'Error! The dongle detected has not been programmed by DinkeyAdd.'; + 410: display := 'Error! The dongle detected has a different Product Code to the one specified in DinkeyAdd.'; + 411: display := 'Error! The dongle detected does not contain the licence associated with this program.'; + 413: display := 'Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual.'; + 417: display := 'Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.'; + 423: display := 'Error! The number of network users has been exceeded.'; + 435: display := 'Error! DinkeyServer has not been detected on the network.'; + 922: display := 'Error! The Software Key has expired.'; + else + display := 'An error occurred checking the dongle. Error: ' + IntToStr(ret_code) + '. Extended Error code: ' + IntToStr(extended_error); + end; + ShowMessage(display); +end; + +{ ************************* our 11 functions follow *************************** } + +{ *********************** DisplayNetUsers ******************************* } +{ This function displays the current network users (for DinkeyNet only). + The DDProtCheck function must be called before this function is called. + (Normally you would use DinkeyServer to view the network users but this enables you to do it from the client if you want) } +Function DisplayNetUsers (net_users, model : LongInt) : LongInt; +var + display : string; + nu_info: packed array[0..99] of nu_infoType; { !!!! this assumes that you will display max. 100 net users } + i, max_net_users, num_net_users, extended_error : LongInt; + +begin + if (net_users = -1) then + begin + max_net_users := 100; { if unlimited network users are allowed then display up to 100 users (for example) If you want more than 1000 net users you need to change the value above} + end + else + begin + max_net_users := net_users; + end; + + if (net_users = 0) then { no network users are allowed, so nothing to do! } + begin + result := 0; + exit; + end; + + if (model < 3) then + begin + ShowMessage('A network dongle has not been detected. Therefore you cannot display the network users.'); + result := -1; + exit; + end; + + { now get net users } + result := DDGetNetUserList(NIL, @num_net_users, @nu_info, max_net_users, @extended_error); + + if (result <> 0) then + begin + ShowMessage('Error ' + IntToStr(result) + '/' + IntToStr(extended_error) + ' finding network user information.'); + end + else + begin + display:= 'number of net users: ' + IntToStr(num_net_users) + #13#10; + for i := 0 to num_net_users-1 do + begin + display := display + IntToStr(i+1) + '. licence: ' + String(nu_info[i].licenceName) + ', user: ' + String(nu_info[i].userName) + + ', computer: ' + String(nu_info[i].computerName) + ', ipaddress: ' + String(nu_info[i].ipAddress) + #13#10; + end; + ShowMessage(display); + end; +end; + +{ ************************** ProtCheck *************************************** } +Function ProtCheck : LongInt; +var + dris: drisType; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= PROTECTION_CHECK; { standard protection check } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + ShowMessage('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.'); + result := -1; + exit; + end; + + if (dris.prodcode <> AnsiString(MY_PRODCODE)) then + begin + ShowMessage('Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.'); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + ShowMessage('Dinkey Dongle protection error.'); + result := -1; + exit; + end; + + { if you are using a network dongle and you want to list the network users then use this function: } + { DisplayNetUsers(dris.net_users, dris.model); } +end; + +{ ************************** ProtCheckWithAlg ******************************** } +{ !!!! You should replace this function with the one generated by the + "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm). +If you are using Dinkey Lite the copy the source code from DinkeyLook } +Function MyAlgorithm(a,b,c,d,e,f,g,h:LongInt):LongInt; +begin + MyAlgorithm:= a + b + c + d + e + f + g + h; +end; + +{ NB for this to work you must program at least "user algorithm" into the dongle + NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite copy source code from DinkeyLook} +Function ProtCheckWithAlg : LongInt; +var + dris: drisType; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= EXECUTE_ALGORITHM; { standard protection check & execute algorithm } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.alg_number := 1; { execute algorithm 1 (you do not need to specify this field if you are only using Lite models) } + { you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random } + dris.var_a := 1; { sample values } + dris.var_b := 2; + dris.var_c := 3; + dris.var_d := 4; + dris.var_e := 5; + dris.var_f := 6; + dris.var_g := 7; + dris.var_h := 8; + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + ShowMessage('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.'); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + ShowMessage('Dinkey Dongle protection error.'); + result := -1; + exit; + end; + + { if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd } + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) <> dris.alg_answer) then + begin + ShowMessage('Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine'); + result := -1; + exit; + end; +end; + +{ ************************** WriteBytes *************************************** } +{ This writes the Data "Hello, World" to the dongle data area at offset 7 + In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. } + +Function WriteBytes : LongInt; +var + dris: drisType; + DataToWrite : array[0..13] of AnsiChar; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= WRITE_DATA_AREA; { standard protection check & write data} + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.rw_offset := 7; + dris.rw_length := 13; + DataToWrite := 'Hello, World!'; { string to write } + dris.rw_data_ptr := Addr(DataToWrite); + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + ShowMessage('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.'); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + ShowMessage('Dinkey Dongle protection error.'); + result := -1; + exit; + end; +end; + +{ ************************** ReadBytes *************************************** } +{ This reads 14 bytes of data from offset 7 in the dongle data area + In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. + In order for the data to be displayed properly by this routine it will need to be text data } +Function ReadBytes : LongInt; +var + dris: drisType; + DataToRead : array[0..13] of AnsiChar; + display : string; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= READ_DATA_AREA; { standard protection check & write data} + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.rw_offset := 7; + dris.rw_length := 13; { we will add null termination after reading } + dris.rw_data_ptr := Addr(DataToRead); + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + ShowMessage('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.'); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + ShowMessage('Dinkey Dongle protection error.'); + result := -1; + exit; + end; + + DataToRead[13] := Chr(0); { null end of string } + display := 'Dinkey Dongle data area contains: ' + DataToRead; + ShowMessage(display); +end; + +{ ************************** EncryptUserData ********************************** } +{ This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 + It will then do another protection check & decrypt the data } +Function EncryptUserData : LongInt; +var + dris: drisType; + display : string; + DataString : array[0..13] of AnsiChar; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= ENCRYPT_USER_DATA; { standard protection check & encrypt data } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.data_crypt_key_num := 1; + dris.rw_length := 13; + DataString := 'Hello, World!'; { string to encrypt } + dris.rw_data_ptr := Addr(DataString); + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... } + + { Now decrypt the same data to get the original values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= DECRYPT_USER_DATA; { standard protection check & decrypt data } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.data_crypt_key_num := 1; + dris.rw_length := 13; + dris.rw_data_ptr := Addr(DataString); + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + ShowMessage('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.'); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + ShowMessage('Dinkey Dongle protection error.'); + result := -1; + exit; + end; + + DataString[13] := Chr(0); { null end of string } + display := 'Decrypted data is: ' + DataString; + ShowMessage(display); +end; + +{!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! + In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" + in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm + but the code can be modified easily to use the 3 encryption parameters. } + +{ !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm } +Function MyRWAlgorithm(a,b,c,d,e,f,g,h:LongInt):LongInt; +begin + MyRWAlgorithm:= a xor b xor c xor d xor e xor f; +end; + +{ !!!! please overwrite this function with the one generated by DinkeyAdd } +procedure CryptDRIS(dris : PByte; seed1,seed2 : Longword); +var + i,j,k : Integer; + bigseed,S : packed array[0..255] of byte; + temp,t : byte; +begin + i := 0; + while (i < 255) do + begin + Move(seed1, bigseed[i], 4); {NB move actually copies data} + Move(seed2, bigseed[i+4], 4); + i := i + 8; + end; + + for i := 0 to 255 do S[i]:= i; + + j := 0; + for i := 0 to 255 do + begin + j := (j + S[i] + bigseed[i] + 123) Mod 256; + temp := S[i]; + S[i] := S[j]; + S[j] := temp; + end; + i := 0; + j := 0; + Inc(dris, 16); {the first part of the DRIS is not encrypted} + for k := 16 to SizeOf(drisType)-1 do + begin + i := (i + 1) Mod 256; + j := (j + S[i] + 212) Mod 256; + temp := S[i]; + S[i] := S[j]; + S[j] := temp; + t := (S[i] + S[j] + 97) Mod 256; + dris^ := dris^ xor S[t]; + Inc(dris); + end; +end; +{ !!!! please overwrite this function with the one generated by DinkeyAdd } +procedure CryptApiData(data : pbyte; length : integer; seed1,seed2 : Longword; alg_answer: LongInt); +var + i,j,k : Integer; + bigseed,S : packed array[0..255] of byte; + temp,t : byte; +begin + i := 0; + while (i < 255) do + begin + Move(seed1, bigseed[i], 4); {NB move actually copies data} + Move(seed2, bigseed[i+4], 4); + i := i + 8; + end; + + for i := 0 to 255 do S[i]:= i; + + j := 0; + for i := 0 to 255 do + begin + j := (j + S[i] + bigseed[i] + (alg_answer And $FF)) Mod 256; + temp := S[i]; + S[i] := S[j]; + S[j] := temp; + end; + i := 0; + j := 0; + for k := 0 to length-1 do + begin + i := (i + 1) Mod 256; + j := (j + S[i] + ((alg_answer shr 8) And $FF)) Mod 256; + temp := S[i]; + S[i] := S[j]; + S[j] := temp; + t := (S[i] + S[j] + ((alg_answer shr 16) And $FF)) Mod 256; + data^ := data^ xor S[t]; + Inc(data); + end; +end; + +{ ************************** ProtCheckEnc ************************************ } +{ We encrypt the DRIS passed to the API. + Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. } +Function ProtCheckEnc : LongInt; +var + dris: drisType; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); { NB this also fills seed1, seed2 with random values } + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= PROTECTION_CHECK; { standard protection check } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!! you should separate from DDProtCheck for greater security } + + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!! you should separate from DDProtCheck for greater security } + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + ShowMessage('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.'); + result := -1; + exit; + end; + + if (dris.prodcode <> AnsiString(MY_PRODCODE)) then + begin + ShowMessage('Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.'); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + ShowMessage('Dinkey Dongle protection error.'); + result := -1; + exit; + end; +end; + +{ ************************** ProtCheckWithAlgEnc ******************************** } +{ NB for this to work you must program at least "user algorithm" into the dongle + NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite copy source code from DinkeyLook. + We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd.} +Function ProtCheckWithAlgEnc : LongInt; +var + dris: drisType; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); { NB this also fills seed1, seed2, var_a...var_h with random values } + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= EXECUTE_ALGORITHM; { standard protection check & execute algorithm } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.alg_number := 1; { execute algorithm 1 - you do not need to specify this field if you are only using Lite models} + { you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random } + dris.var_a := 1; { sample values } + dris.var_b := 2; + dris.var_c := 3; + dris.var_d := 4; + dris.var_e := 5; + dris.var_f := 6; + dris.var_g := 7; + dris.var_h := 8; + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + ShowMessage('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.'); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + ShowMessage('Dinkey Dongle protection error.'); + result := -1; + exit; + end; + + { if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd } + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) <> dris.alg_answer) then + begin + ShowMessage('Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine'); + result := -1; + exit; + end; +end; + +{ ************************** WriteBytesEnc************************************** } +{ This writes the Data 012...9 to the dongle data area at offset 7 + In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd.} +Function WriteBytesEnc : LongInt; +var + dris: drisType; + DataToWrite : packed array[0..9] of byte; + alg_ans, i: longint; + +begin + for i := 0 to 9 do + DataToWrite[i] := i; + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); { NB this also fills seed1, seed2, var_a...var_h with random values } + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= WRITE_DATA_AREA; { standard protection check & write data} + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.rw_offset := 7; + dris.rw_length := SizeOf(DataToWrite); + dris.rw_data_ptr := Addr(DataToWrite); + + { calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm } + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + { encrypt data we want to write } + CryptApiData(@DataToWrite, SizeOf(DataToWrite), dris.seed1, dris.seed2, alg_ans); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + ShowMessage('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.'); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + ShowMessage('Dinkey Dongle protection error.'); + result := -1; + exit; + end; +end; + +{ ************************** ReadBytesEnc *************************************** } +{ This reads 10 bytes of data from offset 7 in the dongle data area + In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd.} +Function ReadBytesEnc : LongInt; +var + dris: drisType; + DataToRead : packed array[0..9] of byte; + display : string; + alg_ans, i: longint; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); { NB this also fills seed1, seed2, var_a...var_h with random values } + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= READ_DATA_AREA; { standard protection check & write data} + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.rw_offset := 7; + dris.rw_length := SizeOf(DataToRead); + dris.rw_data_ptr := Addr(DataToRead); + + { calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm } + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + ShowMessage('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.'); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + ShowMessage('Dinkey Dongle protection error.'); + result := -1; + exit; + end; + + { decrypt data that was read } + CryptApiData(@DataToRead, SizeOf(DataToRead), dris.seed1, dris.seed2, alg_ans); + display := 'Dinkey Dongle data area contains: '; + for i:=0 to 9 do + display := display + IntToStr(DataToRead[i]) + ' '; + ShowMessage(display); +end; + +{ ************************** EncryptUserDataEnc ******************************* } +{ This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 + It will then do another protection & decrypt the data. + We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd.} +Function EncryptUserDataEnc : LongInt; +var + dris: drisType; + display : string; + DataBytes : packed array[0..9] of byte; + alg_ans,i : LongInt; + +begin + for i := 0 to 9 do + DataBytes[i] := i; { initialise data to 0,1,2,3,4,5,6,7,8,9} + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); { NB this also fills seed1, seed2, var_a...var_h with random values } + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= ENCRYPT_USER_DATA; { standard protection check & encrypt data } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.data_crypt_key_num := 1; + dris.rw_length := SizeOf(DataBytes); + dris.rw_data_ptr := Addr(DataBytes); + + { calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm } + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + { encrypt data we want to write } + CryptApiData(@DataBytes, Sizeof(DataBytes), dris.seed1, dris.seed2, alg_ans); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... } + + { Now decrypt the same data to get the original values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= DECRYPT_USER_DATA; { standard protection check & decrypt data } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.data_crypt_key_num := 1; + dris.rw_length := SizeOf(DataBytes); + dris.rw_data_ptr := Addr(DataBytes); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + ShowMessage('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.'); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + ShowMessage('Dinkey Dongle protection error.'); + result := -1; + exit; + end; + + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + { decrypt data that was read } + CryptApiData(@DataBytes, SizeOf(DataBytes), dris.seed1, dris.seed2, alg_ans); + display := 'Data decrypted by dongle is: '; + for i:=0 to 9 do + display := display + IntToStr(DataBytes[i]) + ' '; + ShowMessage(display); +end; + +{ *************** code that gets executed on startup *********************** } +begin + {call the function(s) of your choice here - in this example I have chosen a standard protection check} + if (ProtCheck() <> 0) then + halt; +end. + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/FireMonkey/Runtime/dris.pas b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/FireMonkey/Runtime/dris.pas new file mode 100644 index 0000000..1c777d8 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/FireMonkey/Runtime/dris.pas @@ -0,0 +1,108 @@ +{ !! this file should not be modified } +unit dris; + +interface + + TYPE + drisType = packed record + { the first 4 fields are never encrypted } + header : array[0..3] of AnsiChar; { should be set to DRIS } + { inputs } + size : FixedInt; { size of this structure } + seed1 : FixedInt; { seed for data/dris encryption } + seed2 : FixedInt; { as above } + { maybe encrypted from now on } + myfunction : FixedInt; { specify only one function. NB can't name it "function" as it is a reserved keyword } + flags : FixedInt; { options for the function selected. To use more than one OR them together: OPTION1 or OPTION2... } + execs_decrement : FixedUint; { amount by which to dec execs if we use flag: DEC_MANY_EXECS } + data_crypt_key_num : FixedInt; { number of the key (1-3) that the dongle uses to encrypt or decrypt user data } + rw_offset : FixedInt; { offset in the dongle data area to read or write data } + rw_length : FixedInt; { length of data are to read/write/encrypt/decrypt } + rw_data_ptr : Pbyte; { pointer to data to write / be read } + alt_licence_name : array[0..255] of AnsiChar; { protection check for different licence instead of the default one, must be null-terminated } + var_a : FixedInt; { variable values for user algorithm } + var_b : FixedInt; + var_c : FixedInt; + var_d : FixedInt; + var_e : FixedInt; + var_f : FixedInt; + var_g : FixedInt; + var_h : FixedInt; + alg_number : FixedInt; { the number of the user algorithm that you want to execute } + { outputs } + ret_code : FixedInt; { return code from the protection check } + ext_err : FixedInt; { extended error } + dongle_type : FixedInt; { type of dongle detected. 1 = Pro, 2 = FD. NB "type" is a reserved word so I use dongle_type } + model : FixedInt; { model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited } + sdsn : FixedInt; { Software Developer's Serial Number } + prodcode : array[0..11] of AnsiChar; { Product Code (null-terminated) } + dongle_number : FixedUInt; + update_number : FixedInt; + data_area_size : FixedUint; { size of the data area in the dongle detected } + max_alg_num : FixedInt; { the maximum algorithm number in the dongle detected } + execs : FixedInt; { executions left: -1 indicates 'no limit' } + exp_day : FixedInt; { expiry day: -1 indicates 'no limit' } + exp_month : FixedInt; { expiry month: -1 indicates 'no limit' } + exp_year : FixedInt; { expiry year: -1 indicates 'no limit' } + features : FixedUint; { features value } + net_users : FixedInt; { maximum number of network users for the dongle detected: -1 indicates 'no limit' } + alg_answer : FixedInt; { answer to the user algorithm executed with the given variable values } + fd_capacity : FixedUint; { capacity of the data area in FD dongle. Currently fixed at ~10MB but may change in the future. } + fd_drive : array[0..127] of AnsiChar; { drive letter of FD dongle detected (if any) 'f:\' } + swkey_type : FixedInt; { 0 = no swkey detected, 1 = temporary software key, 2 = demo software key } + swkey_exp_day : FixedInt; { software key expiry date (if software key detected) } + swkey_exp_month : FixedInt; + swkey_exp_year : FixedInt; + end; + + TYPE + nu_infoType = packed record + licenceName : array[0..255] of AnsiChar; + userName : array[0..49] of AnsiChar; + computerName : array[0..255] of AnsiChar; + ipAddress : array[0..15] of AnsiChar; + end; + + { function constants - specify one only } + const PROTECTION_CHECK = 1; { checks for dongle, check program params... } + const EXECUTE_ALGORITHM = 2; { protection check + calculate answer for specified algorithm with specified inputs } + const WRITE_DATA_AREA = 3; { protection check + writes dongle data area } + const READ_DATA_AREA = 4; { protection check + reads dongle data area } + const ENCRYPT_USER_DATA = 5; { protection check + the dongle will encrypt user data } + const DECRYPT_USER_DATA = 6; { protection check + the dongle will decrypt user data } + const FAST_PRESENCE_CHECK = 7; { checks for the presence of the correct dongle only with minimal security, no flags allowed. } + const STOP_NET_USER = 8; { stops a network user (a protection check is NOT performed) } + + { flag constants - can specify more than one } + const DEC_ONE_EXEC = 1; { decrement execs by 1 } + const DEC_MANY_EXECS = 2; { decrement execs by number specified in execs_decrement } + const START_NET_USER = 4; { starts a network user } + const USE_FUNCTION_ARGUMENT = 16; { use the extra argument in the function for pointers } + const CHECK_LOCAL_FIRST = 32; { always look in local ports before looking in network ports } + const CHECK_NETWORK_FIRST = 64; { always look on the network before looking in local ports } + const USE_ALT_LICENCE_NAME = 128; { use name specified in alt_licence_name instead of the default one } + const DONT_SET_MAXDAYS_EXPIRY = 256; { if the max days expiry date has not been calculated then do not do it this time } + const MATCH_DONGLE_NUMBER = 512; { restrict the search to match the dongle number specified in the DRIS } + const DONT_RETURN_FD_DRIVE = 1024; { if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS } + +{$IFDEF WIN32} + function DDProtCheck( dris, data:pointer ):FixedInt; stdcall; external 'dpwin32.dll'; + function DDGetNetUserList(licence_name:PAnsiChar; num_net_users:PFixedInt; nu_info:pointer; num_info_structs:FixedInt; extended_error:PFixedInt):FixedInt; stdcall; external 'dpwin32.dll'; +{$ENDIF} +{$IFDEF WIN64} + function DDProtCheck( dris, data:pointer ):FixedInt; stdcall; external 'dpwin64.dll'; + function DDGetNetUserList(licence_name:PAnsiChar; num_net_users:PFixedInt; nu_info:pointer; num_info_structs:FixedInt; extended_error:PFixedInt):FixedInt; stdcall; external 'dpwin64.dll'; +{$ENDIF} +{$IFDEF MACOS32} + function DDProtCheck( dris, data:pointer ):FixedInt; cdecl; external 'dpmac32.dylib' name '_DDProtCheck'; + function DDGetNetUserList(licence_name:PAnsiChar; num_net_users:PFixedInt; nu_info:pointer; num_info_structs:FixedInt; extended_error:PFixedInt):FixedInt; cdecl; external 'dpmac32.dylib' name '_DDGetNetUserList'; +{$ENDIF} +{$IFDEF MACOS64} + function DDProtCheck( dris, data:pointer ):FixedInt; cdecl; external 'dpmac64.dylib'; + function DDGetNetUserList(licence_name:PAnsiChar; num_net_users:PFixedInt; nu_info:pointer; num_info_structs:FixedInt; extended_error:PFixedInt):FixedInt; cdecl; external 'dpmac64.dylib'; +{$ENDIF} + +implementation + +end. + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/DinkeyChange/Change.dfm b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/DinkeyChange/Change.dfm new file mode 100644 index 0000000..e0f9177 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/DinkeyChange/Change.dfm @@ -0,0 +1,151 @@ +object ChangeForm: TChangeForm + Left = 192 + Top = 107 + Width = 345 + Height = 658 + Caption = 'ChangeTest' + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + OldCreateOrder = False + PixelsPerInch = 96 + TextHeight = 13 + object Label1: TLabel + Left = 16 + Top = 72 + Width = 123 + Height = 13 + Caption = 'Enter Diagnostic filename:' + end + object Label2: TLabel + Left = 16 + Top = 168 + Width = 120 + Height = 13 + Caption = 'Enter short Update Code:' + end + object Label3: TLabel + Left = 16 + Top = 264 + Width = 146 + Height = 13 + Caption = 'Enter path to Update Code file:' + end + object Label4: TLabel + Left = 8 + Top = 528 + Width = 165 + Height = 13 + Caption = 'Demo Software Key Product Code:' + end + object DiagInfo: TButton + Left = 64 + Top = 24 + Width = 209 + Height = 25 + Caption = 'Get Dongle Information' + TabOrder = 0 + OnClick = DiagInfoClick + end + object DiagFilename: TEdit + Left = 16 + Top = 88 + Width = 305 + Height = 21 + TabOrder = 1 + end + object WriteDiags: TButton + Left = 72 + Top = 120 + Width = 193 + Height = 25 + Caption = 'Write Diagnostics to File' + TabOrder = 2 + OnClick = WriteDiagsClick + end + object UpdateCodeString: TEdit + Left = 16 + Top = 184 + Width = 305 + Height = 21 + TabOrder = 3 + end + object DoUpdateCodeString: TButton + Left = 72 + Top = 216 + Width = 193 + Height = 25 + Caption = 'Make Changes' + TabOrder = 4 + OnClick = DoUpdateCodeStringClick + end + object UpdateCodeFile: TEdit + Left = 16 + Top = 280 + Width = 305 + Height = 21 + TabOrder = 5 + end + object DoUpdateCodeFile: TButton + Left = 72 + Top = 312 + Width = 193 + Height = 25 + Caption = 'Make Changes' + TabOrder = 6 + OnClick = DoUpdateCodeFileClick + end + object RestoreFDLite: TButton + Left = 72 + Top = 368 + Width = 193 + Height = 25 + Caption = 'Restore FD Lite' + TabOrder = 7 + OnClick = DoRestoreFDLiteClick + end + object GetMachineID: TButton + Left = 16 + Top = 424 + Width = 145 + Height = 25 + Caption = 'Get Machine ID' + TabOrder = 8 + OnClick = DoGetMachineIDClick + end + object DownloadTempSWKey: TButton + Left = 56 + Top = 480 + Width = 225 + Height = 25 + Caption = 'Download Temporary Software Key' + TabOrder = 9 + OnClick = DoDownloadTempSWKeyClick + end + object ShowMachineID: TEdit + Left = 168 + Top = 424 + Width = 153 + Height = 21 + TabOrder = 10 + end + object DownloadDemoSWKey: TButton + Left = 56 + Top = 576 + Width = 225 + Height = 25 + Caption = 'Download Demo Software Key' + TabOrder = 11 + OnClick = DoDownloadDemoSWKeyClick + end + object SwkeyProdCode: TEdit + Left = 8 + Top = 544 + Width = 305 + Height = 21 + TabOrder = 12 + end +end diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/DinkeyChange/Change.pas b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/DinkeyChange/Change.pas new file mode 100644 index 0000000..036a8bb --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/DinkeyChange/Change.pas @@ -0,0 +1,340 @@ +unit Change; + +interface + +uses + Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, + Dialogs, StdCtrls; + +type + TChangeForm = class(TForm) + DiagInfo: TButton; + Label1: TLabel; + DiagFilename: TEdit; + WriteDiags: TButton; + UpdateCodeString: TEdit; + Label2: TLabel; + DoUpdateCodeString: TButton; + UpdateCodeFile: TEdit; + Label3: TLabel; + DoUpdateCodeFile: TButton; + RestoreFDLite: TButton; + GetMachineID: TButton; + DownloadTempSWKey: TButton; + ShowMachineID: TEdit; + DownloadDemoSWKey: TButton; + SwkeyProdCode: TEdit; + Label4: TLabel; + procedure DiagInfoClick(Sender: TObject); + procedure WriteDiagsClick(Sender: TObject); + procedure DoUpdateCodeStringClick(Sender: TObject); + procedure DoUpdateCodeFileClick(Sender: TObject); + procedure DoRestoreFDLiteClick(Sender: TObject); + procedure DoGetMachineIDClick(Sender: TObject); + procedure DoDownloadTempSWKeyClick(Sender: TObject); + procedure DoDownloadDemoSWKeyClick(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + ChangeForm: TChangeForm; + + { constants } + const MAX_USB_DEVICES = 128; { maximum number of USB devices that can be attached to the system at one time } + const MAX_PRODCODE_LEN = 8; { maximum length of a Product Code } + + { mask values } + const TYPE_MASK_PRO = 1; + const TYPE_MASK_FD = 2; + const TYPE_MASK_ALL = TYPE_MASK_PRO or TYPE_MASK_FD; + + const MODEL_MASK_LITE = 1; + const MODEL_MASK_PLUS = 2; + const MODEL_MASK_NET = 4; + const MODEL_MASK_ALL = MODEL_MASK_LITE or MODEL_MASK_PLUS or MODEL_MASK_NET; + const MODEL_MASK_DEFAULT = MODEL_MASK_PLUS or MODEL_MASK_NET; + + { type values for DCGetInfo (returned in the array) } + const TYPE_PRO = 1; + const TYPE_FD = 2; + + { model values for DCGetInfo (returned in the array) } + const MODEL_LITE = 1; + const MODEL_PLUS = 2; + const MODEL_NET5 = 4; + const MODEL_NETU = 7; + + { model values for DCDownloadDemoSoftwareKey } + const SWKEY_MODEL_DEFAULT = -1; { NB this assumes that the Demo Software Key Template was created with only one valid dongle model } + const SWKEY_MODEL_PRO_LITE = 0; + const SWKEY_MODEL_PRO_PLUS = 1; + const SWKEY_MODEL_PRO_NET = 2; + const SWKEY_MODEL_FD_LITE = 3; + const SWKEY_MODEL_FD_PLUS = 4; + const SWKEY_MODEL_FD_NET = 5; + + { functions exported by DinkeyChange.dll } +{$IFDEF WIN32} + function DCGetInfo(type_mask, model_mask:LongInt; prodcode_mask:PAnsiChar; array_length:LongInt; num_found:PLongInt; type_array,model_array:pointer; prodcode_array:pointer; dongle_number_array:pointer; update_number_array: pointer) : LongInt; stdcall; external 'DinkeyChange.dll'; + function DCGetDiagnosticInfo(filename: PAnsiChar): LongInt; stdcall; external 'DinkeyChange.dll'; + function DCDoUpdateCodeString(UpdateCodeString: PAnsiChar; confirmation_code, extended_error: PLongInt): LongInt; stdcall; external 'DinkeyChange.dll'; + function DCDoUpdateCodeFromFile(filename: PAnsiChar; confirmation_code, extended_error: PLongInt): LongInt; stdcall; external 'DinkeyChange.dll'; + function DCRestoreDinkeyFDLite(): LongInt; stdcall; external 'DinkeyChange.dll'; + function DCGetMachineID(machineID:PLongWord; extended_error:PLongInt): LongInt; stdcall; external 'DinkeyChange.dll'; + function DCDownloadTempSoftwareKey(machineID:LongWord; extended_error:PLongInt): LongInt; stdcall; external 'DinkeyChange.dll'; + function DCDownloadDemoSoftwareKey(machineID:LongWord; prodcode: PAnsiChar; model: LongInt; extended_error:PLongInt): LongInt; stdcall; external 'DinkeyChange.dll'; +{$ELSE} + function DCGetInfo(type_mask, model_mask:LongInt; prodcode_mask:PAnsiChar; array_length:LongInt; num_found:PLongInt; type_array,model_array:pointer; prodcode_array:pointer; dongle_number_array:pointer; update_number_array: pointer) : LongInt; stdcall; external 'DinkeyChange64.dll'; + function DCGetDiagnosticInfo(filename: PAnsiChar): LongInt; stdcall; external 'DinkeyChange64.dll'; + function DCDoUpdateCodeString(UpdateCodeString: PAnsiChar; confirmation_code, extended_error: PLongInt): LongInt; stdcall; external 'DinkeyChange64.dll'; + function DCDoUpdateCodeFromFile(filename: PAnsiChar; confirmation_code, extended_error: PLongInt): LongInt; stdcall; external 'DinkeyChange64.dll'; + function DCRestoreDinkeyFDLite(): LongInt; stdcall; external 'DinkeyChange64.dll'; + function DCGetMachineID(machineID:PLongWord; extended_error:PLongInt): LongInt; stdcall; external 'DinkeyChange64.dll'; + function DCDownloadTempSoftwareKey(machineID:LongWord; extended_error:PLongInt): LongInt; stdcall; external 'DinkeyChange64.dll'; + function DCDownloadDemoSoftwareKey(machineID:LongWord; prodcode: PAnsiChar; model: LongInt; extended_error:PLongInt): LongInt; stdcall; external 'DinkeyChange64.dll'; +{$ENDIF} + +implementation + +{$R *.dfm} + +{ displays messages for the most common errors when updating the code. + You will want to change this for your code } +procedure DisplayError(ret_code, extended_error:integer); +var + display : string; +begin + case ret_code of + 401: display := 'Error! No dongles detected that meet the search criteria.'; + 409: display := 'Error! The dongle detected has not been programmed by DinkeyAdd.'; + 758: display := 'Error! Cannot open the Update Code file specified.'; + 759: display := 'Error! The file specified is not a valid Update Code file.'; + 762..764: display := 'Error! Update Code is not in a correct format / update code file is corrupt.'; + 765: display := 'Error! The Update Code does not match any dongle attached to your machine.'; + 766: display := 'Error! The update number for this Update Code is too high. You need to first enter an update code that was previously sent to you.'; + 767: display := 'Error! You have already entered this Update Code.'; + 1905: display := 'Error! There is no Software Key available for download.'; + 1907: display := 'Error! The Temporary Software Key has expired. Cannot download it.'; + 1910: display := 'Error! The Software Key has already been downloaded.'; + 1921: display := 'Error! You specified the default model but there is more than one model available. You need to specify a specific dongle model.'; + 1922: display := 'Error! The model you requested is not available.'; + 1923: display := 'Error! The Demo Software Key Template has been disabled.'; + 1924: display := 'Error! You have run out of Demo Software Key activations. You need to order some more.'; + else + display := 'An error occurred checking the dongle. Error: ' + IntToStr(ret_code) + '. Extended Error code: ' + IntToStr(extended_error); + end; + messagedlg(display, mtError, [mbok], 0); +end; + +procedure TChangeForm.DiagInfoClick(Sender: TObject); +var + i : Integer; + sType, sModel, sProdCode, display : string; + ret_code, num_found : LongInt; + type_array, model_array, update_number_array: packed array[0..(MAX_USB_DEVICES-1)] of LongInt; + dongle_number_array: packed array[0..(MAX_USB_DEVICES-1)] of LongWord; + prodcode_array: packed array[0..(MAX_USB_DEVICES-1)] of packed array[0..MAX_PRODCODE_LEN] of AnsiChar; +begin + +{ find dongle information for all dongle types, Plus & Net models, for all product codes + NB In practice you will probably want to set the prodcode_mask to the value of your product code } + + ret_code := DCGetInfo(TYPE_MASK_ALL, MODEL_MASK_DEFAULT, nil, MAX_USB_DEVICES, @num_found, @type_array, @model_array, @prodcode_array, @dongle_number_array, @update_number_array); + +{ check error code and display error if an error occurs } + if (ret_code = 401) then + begin + messagedlg('No dongles detected matching the search criteria specified', mtError, [mbok], 0); + exit; + end + else if (ret_code <> 0) then + begin + messagedlg('Error ' + IntToStr(ret_code) + ' getting dongle information', mtError, [mbok], 0); + exit; + end; + +{ display info from the dongle detected } + display := ''; + for i := 0 to num_found-1 do + begin + { get type of dongle } + if (type_array[i] = TYPE_PRO) then + sType := 'Pro' + else + sType := 'FD'; + + { get model of dongle } + if (model_array[i] = MODEL_LITE) then + sModel := 'Lite' + else if (model_array[i] = MODEL_PLUS) then + sModel := 'Plus' + else + sModel := 'Net'; + + sProdCode := String(prodcode_array[i]); + + display := display + IntToStr(i+1) + '. Dinkey ' + sType + ' ' + sModel + ' with dongle number: ' + IntToStr(dongle_number_array[i]) + + ', product code: ' + sProdCode + ', update number: ' + IntToStr(update_number_array[i]) + #13#10; + end; + messagedlg(display, mtInformation, [mbok], 0); + +end; + +{ write dongle diagnostics to file } +procedure TChangeForm.WriteDiagsClick(Sender: TObject); +var + ret_code: longInt; + diag_file : array[0..255] of AnsiChar; + +begin + StrPCopy(diag_file, AnsiString(DiagFilename.Text)); { to get a null-terminated string } + ret_code := DCGetDiagnosticInfo(@diag_file); + + { check error code and display error if an error occurs } + if (ret_code = 754) then + begin + messagedlg('Could not create the diagnostic file. Please check that the path exists: ' + DiagFileName.Text, mtError, [mbok], 0); + exit; + end + else if (ret_code <> 0) then + begin + messagedlg('Error ' + IntToStr(ret_code) + 'writing diagnostic file.', mtError, [mbok], 0); + exit; + end; + + { display success } + messagedlg('Diagnostic file written successfully.', mtInformation, [mbok], 0); +end; + +{ update dongle with short update code string typed-in } +procedure TChangeForm.DoUpdateCodeStringClick(Sender: TObject); +var + ret_code, confirmation_code, extended_error: LongInt; + update_code : array[0..255] of AnsiChar; +begin + StrPCopy(update_code, AnsiString(UpdateCodeString.Text)); { to get a null-terminated string } + ret_code := DCDoUpdateCodeString(@update_code, @confirmation_code, @extended_error); + + if (ret_code <> 0) then + begin + DisplayError(ret_code, extended_error); + exit; + end; + + messagedlg('Dongle updated successfully!' + #13#10 + 'Confirmation code is : ' + IntToHex(confirmation_code, 4), mtInformation, [mbok], 0); +end; + +{ update dongle with update code in file specified } +procedure TChangeForm.DoUpdateCodeFileClick(Sender: TObject); +var + ret_code, confirmation_code, extended_error: LongInt; + update_code_file : array[0..255] of AnsiChar; +begin + StrPCopy(update_code_file, AnsiString(UpdateCodeFile.Text)); { to get a null-terminated string } + ret_code := DCDoUpdateCodeFromFile(@update_code_file, @confirmation_code, @extended_error); + + if (ret_code <> 0) then + begin + DisplayError(ret_code, extended_error); + exit; + end; + + messagedlg('Dongle updated successfully!' + #13#10 + 'Confirmation code is : ' + IntToHex(confirmation_code, 4), mtInformation, [mbok], 0); +end; + +{ attempt to restore Dinkey FD Lite dongle } +procedure TChangeForm.DoRestoreFDLiteClick(Sender: TObject); +var + ret_code: LongInt; +begin + ret_code := DCRestoreDinkeyFDlite(); + + if (ret_code <> 0) then + begin + DisplayError(ret_code, 0); + exit; + end; + + messagedlg('Dinkey FD Lite dongle restored successfully!', mtInformation, [mbok], 0); +end; + +{ Get Machine ID (for use with Temporary Software Key) } +procedure TChangeForm.DoGetMachineIDClick(Sender: TObject); +var + ret_code, extended_error: LongInt; + machineID: LongWord; +begin + ret_code := DCGetMachineID(@machineID, @extended_error); + + if (ret_code <> 0) then + begin + DisplayError(ret_code, extended_error); + exit; + end; + {don't display mesage, just display the Machine ID } + ShowMachineID.Text := IntToHex(machineID, 8); +end; + +{ Download Temporary Software Key } +procedure TChangeForm.DoDownloadTempSWKeyClick(Sender: TObject); +var + ret_code, extended_error: LongInt; + machineID: LongWord; +begin + { first get the machine ID... } + ret_code := DCGetMachineID(@machineID, @extended_error); + + if (ret_code <> 0) then + begin + DisplayError(ret_code, extended_error); + exit; + end; + + { ... then try to download the temporary software key } + ret_code := DCDownloadTempSoftwareKey(machineID, @extended_error); + + if (ret_code <> 0) then + begin + DisplayError(ret_code, extended_error); + exit; + end; + + messagedlg('Temporary Software Key Downloaded Successfully!', mtInformation, [mbok], 0); +end; + +{ Download Demo Software Key } +procedure TChangeForm.DoDownloadDemoSWKeyClick(Sender: TObject); +var + ret_code, extended_error: LongInt; + machineID: LongWord; + prodcode : array[0..9] of AnsiChar; +begin + { first get the machine ID... } + ret_code := DCGetMachineID(@machineID, @extended_error); + + if (ret_code <> 0) then + begin + DisplayError(ret_code, extended_error); + exit; + end; + + { ... then try to download the demo software key } + { NB we are assuming only one dongle model is set in the Demo Software Template. } + { If multiple models are set you will also need to specify the exact model } + StrPCopy(prodcode, AnsiString(SwkeyProdCode.Text)); { to get a null-terminated string } + ret_code := DCDownloadDemoSoftwareKey(machineID, @prodcode, SWKEY_MODEL_DEFAULT, @extended_error); + + if (ret_code <> 0) then + begin + DisplayError(ret_code, extended_error); + exit; + end; + + messagedlg('Demo Software Key Downloaded Successfully!', mtInformation, [mbok], 0); +end; + +end. + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/DinkeyChange/ChangeTest.dpr b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/DinkeyChange/ChangeTest.dpr new file mode 100644 index 0000000..ded649e --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/DinkeyChange/ChangeTest.dpr @@ -0,0 +1,13 @@ +program ChangeTest; + +uses + Forms, + Change in 'Change.pas' {ChangeForm}; + +{$R *.res} + +begin + Application.Initialize; + Application.CreateForm(TChangeForm, ChangeForm); + Application.Run; +end. diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/DinkeyChange/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/DinkeyChange/README.txt new file mode 100644 index 0000000..7cdd06e --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/DinkeyChange/README.txt @@ -0,0 +1,22 @@ +ChangeTest - sample code to call DinkeyChange.dll in Delphi +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Delphi 6 but will also work in more recent versions +(they will upgrade the Project to the latest version). + +The sample code contains 7 functions. Just use which ever functions are most +appropriate and customise in your own way. The sample code is just a guide. +As none of the parameters are sensitive then there is no need to implement +strong security in calling DinkeyChange. + +It is also recommended that you rename DinkeyChange.dll to a name of your choice. In +this case you will need to modify the dll name in the change.pas file. + +Important Note - you will not be able to debug your program after our API has been called. +Our strong anti-debug code will cause the debugger to throw an exception. You will also +not be able to run your program from the development platform either as Delphi still has +the Debugger running. You should run it instead from My Computer or from the command line. + +However, if you do need to debug your code you can use our debug module for DinkeyChange: +DinkeyChangeDebug.dll. So, you can use DinkeyChange.dll for your release build +and DinkeyChangeDebug.dll for your debug build. \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/ObjTest.dpr b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/ObjTest.dpr new file mode 100644 index 0000000..2f81441 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/ObjTest.dpr @@ -0,0 +1,14 @@ +program ObjTest; + +uses + Forms, + apitest in 'apitest.pas' {Form1}, + dris in 'dris.pas'; + +{$R *.res} + +begin + Application.Initialize; + Application.CreateForm(TForm1, Form1); + Application.Run; +end. diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/README.txt new file mode 100644 index 0000000..8768650 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/README.txt @@ -0,0 +1,97 @@ +Sample code to call Runtime modules in Delphi +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Delphi 6 but will work in more recent versions +(they will upgrade the Project to the latest version. For Delphi XE or earlier +you will need to delete the reference to System.UITypes). + +If you want to create multi-platform or multi-device applications please use +the FireMonkey projects instead. + +The source files in the project are: + +File name Description +apitest.pas main source code file for Delphi +dris.pas contains DRIS structure definition and other definitions. +apitest.dfm +ObjTest.dpr project file + +The idea is to include the dris.pas file in your project and use/modify which ever +functions from apitest.pas you feel are appropriate. + +This sample can also compile to 64-bit code (if your version of Delphi supports 64-bit +code i.e. Delphi XE2 and higher). Just Add the 64-bit Platform to the project. + +In order for the projects to compile without modification we have also installed in +this folder the relevant object modules for Delphi: + +dpwin32_omf.obj for 32-bit builds +dpwin64_delphi.obj for 64-bit builds + +The sample code will detect whether you are building in 32-bit or 64-bit and compile +the appropriate Windows module. + +The sample code contains 11 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. However, you should +still display or log any error codes returned by the protection check otherwise you will not +be able to identify the cause of the error. (You can look up error codes in our knowledge +base: microcosm.com/kb). + +The project currently links with our static protection modules. If you want to link to +our dynamic protection modules instead (dpwin32.dll or dpwin64.dll) then you need +to modify dris.pas as follows: + +1) Modify the declarations of DDProtCheck and DDGetNetUserList so that they refer + to the appropriate runtime DLL. + +2) Delete the code that links the object module. + +We have made these changes and put them in a file called dris_for_dll.pas. +Use this in your project instead of dris.pas. + +It is also recommended that you rename dpwin32.dll to a name of your choice. In +this case you will need to modify the dll name in the dris.pas file. + +Note - if you link the static module dpwin32_omf.obj then you should protect your program. +If you are linking to dpwin32.dll then you need to protect dpwin32.dll and *not* your program. +Because your program is linked to the DLL it is protected. The protected DLL will need to be +in the same folder as your compiled program for it to run correctly. + +Debug Modules +~~~~~~~~~~~~~~ +Note - once your program (or dpwin32.dll) is protected you will not be able to debug +your program - after our API has been called. Our strong anti-debug code will cause +the debugger to throw an exception. You will also not be able to run your program from +the development platform either as Delphi still has the Debugger running. You should run +it instead from My Computer or from the command line. If you do want to debug your code +then you can use our debug module: dpwin32_omf_debug.obj (or dpwin32debug.dll), but these +should not be used for release. + +You could setup your project so that your code links the debug module during your debug build +and the standard module when you produce your release code. + +Note: the debug module has the following restrictions: + +1) It will not correctly start a network user (network dongles only). However, other than that + the protection check will function correctly and return success. +2) You will not be able to encrypt the DRIS. (If you do encrypt the DRIS in your release build + then you should make sure that CryptDRIS does not get called in your debug build). +3) The protection check will take slightly longer than normal. +4) The DDGetNetUserList function will return error 428 (not implemented). +5) A temporary subprocess is created which may be (falsely) detected as malicious by anti-virus + programs. diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/apitest.dfm b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/apitest.dfm new file mode 100644 index 0000000..206c931 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/apitest.dfm @@ -0,0 +1,29 @@ +object Form1: TForm1 + Left = 386 + Top = 317 + Width = 372 + Height = 265 + Caption = 'Form1' + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + OldCreateOrder = False + PixelsPerInch = 96 + TextHeight = 13 + object Label1: TLabel + Left = 104 + Top = 88 + Width = 146 + Height = 37 + Caption = 'It Worked!' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -32 + Font.Name = 'MS Sans Serif' + Font.Style = [] + ParentFont = False + end +end diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/apitest.pas b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/apitest.pas new file mode 100644 index 0000000..dd6889a --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/apitest.pas @@ -0,0 +1,874 @@ +unit apitest; + +interface + +uses + Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, + Dialogs, StdCtrls, System.UITypes, { !!!! for Delphi XE and earlier remove System.UITypes } + dris; { contains the DRIS structure declaration } + +type + TForm1 = class(TForm) + Label1: TLabel; + private + { Private declarations } + public + { Public declarations } + end; + +var + Form1: TForm1; + +implementation + +{$R *.dfm} + +{ !! We strongly recommend that you read the "readme.txt" file in the sample code folder. + !! It contains important instructions on how to use the sample code } + +{ The sample code contains 11 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. To choose which function +this code uses see the startup code at the bottom of this file. + +this file contains 11 protection-check functions. + longint ProtCheck(); a standard protection check + longint ProtCheckWithAlg(); a protection check & executing an Algorithm + longint WriteBytes(); a protection check & write data to the dongle + longint ReadBytes(); a protection check & read data from the dongle + longint EncryptUserData(); a protection check & encrypting data and then decrypting the data + +these functions are the same as the functions listed above but encrypting all parameters passed to our API + longint ProtCheckEnc(); a standard protection check + longint ProtCheckWithAlgEnc(); a protection check & executing an Algorithm + longint WriteBytesEnc(); a protection check & write data to the dongle + longint ReadBytesEnc(); a protection check & read data from the dongle + longint EncryptUserDataEnc(); a protection check & encrypting data and then decrypting the data + + longint DisplayNetUsers(net_users, model); this function displays the current network users + + If you are using Dinkey Lite then you can only use 4 functions: +ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + } + +const MY_SDSN = 10101; { !!!! change this value to be the value of your SDSN (demo = 10101) } +const MY_PRODCODE = 'DEMO'; + +{ this procedure initialises the DRIS with random bytes } +procedure random_set(data: PByte; length: integer); +var + i : integer; +begin + Randomize(); + for i := 0 to length-1 do + begin + data^ := Random(256); + Inc(data); { increment the pointer so we can access the next byte } + end; +end; + +{ displays messages for the most common errors. You will want to change this for your code } +procedure DisplayError(ret_code, extended_error:integer); +var + display : string; +begin + case ret_code of + 401: display := 'Error! No dongles detected!'; + 403: display := 'Error! The dongle detected has a different type to the one specified in DinkeyAdd.'; + 404: display := 'Error! The dongle detected has a different model to those specified in DinkeyAdd.'; + 409: display := 'Error! The dongle detected has not been programmed by DinkeyAdd.'; + 410: display := 'Error! The dongle detected has a different Product Code to the one specified in DinkeyAdd.'; + 411: display := 'Error! The dongle detected does not contain the licence associated with this program.'; + 413: display := 'Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual.'; + 417: display := 'Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.'; + 423: display := 'Error! The number of network users has been exceeded.'; + 435: display := 'Error! DinkeyServer has not been detected on the network.'; + 922: display := 'Error! The Software Key has expired.'; + else + display := 'An error occurred checking the dongle. Error: ' + IntToStr(ret_code) + '. Extended Error code: ' + IntToStr(extended_error); + end; + messagedlg(display, mtError, [mbok], 0); +end; + +{ ************************* our 11 functions follow *************************** } + +{ *********************** DisplayNetUsers ******************************* } +{ This function displays the current network users (for DinkeyNet only). + The DDProtCheck function must be called before this function is called. + (Normally you would use DinkeyServer to view the network users but this enables you to do it from the client if you want) } +Function DisplayNetUsers (net_users, model : LongInt) : LongInt; +var + display : string; + nu_info: packed array[0..99] of nu_infoType; { !!!! this assumes that you will display max. 100 net users } + i, max_net_users, num_net_users, extended_error : LongInt; + +begin + if (net_users = -1) then + begin + max_net_users := 100; { if unlimited network users are allowed then display up to 100 users (for example) If you want more than 1000 net users you need to change the value above} + end + else + begin + max_net_users := net_users; + end; + + if (net_users = 0) then { no network users are allowed, so nothing to do! } + begin + result := 0; + exit; + end; + + if (model < 3) then + begin + messagedlg('A network dongle has not been detected. Therefore you cannot display the network users.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { now get net users } + result := DDGetNetUserList(NIL, @num_net_users, @nu_info, max_net_users, @extended_error); + + if (result <> 0) then + begin + messagedlg('Error ' + IntToStr(result) + '/' + IntToStr(extended_error) + ' finding network user information.', mtError, [mbok], 0); + end + else + begin + display:= 'number of net users: ' + IntToStr(num_net_users) + #13#10; + for i := 0 to num_net_users-1 do + begin + display := display + IntToStr(i+1) + '. licence: ' + String(nu_info[i].licenceName) + ', user: ' + String(nu_info[i].userName) + + ', computer: ' + String(nu_info[i].computerName) + ', ipaddress: ' + String(nu_info[i].ipAddress) + #13#10; + end; + messagedlg(display, mtInformation, [mbok], 0); + end; +end; + +{ ************************** ProtCheck *************************************** } +Function ProtCheck : LongInt; +var + dris: drisType; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= PROTECTION_CHECK; { standard protection check } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + messagedlg('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.', mtError, [mbok], 0); + result := -1; + exit; + end; + + if (dris.prodcode <> AnsiString(MY_PRODCODE)) then + begin + messagedlg('Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + messagedlg('Dinkey Dongle protection error.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { if you are using a network dongle and you want to list the network users then use this function: } + { DisplayNetUsers(dris.net_users, dris.model); } +end; + +{ ************************** ProtCheckWithAlg ******************************** } +{ !!!! You should replace this function with the one generated by the + "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm). +If you are using Dinkey Lite the copy the source code from DinkeyLook } +Function MyAlgorithm(a,b,c,d,e,f,g,h:LongInt):LongInt; +begin + MyAlgorithm:= a + b + c + d + e + f + g + h; +end; + +{ NB for this to work you must program at least "user algorithm" into the dongle + NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite copy source code from DinkeyLook} +Function ProtCheckWithAlg : LongInt; +var + dris: drisType; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= EXECUTE_ALGORITHM; { standard protection check & execute algorithm } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.alg_number := 1; { execute algorithm 1 (you do not need to specify this field if you are only using Lite models) } + { you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random } + dris.var_a := 1; { sample values } + dris.var_b := 2; + dris.var_c := 3; + dris.var_d := 4; + dris.var_e := 5; + dris.var_f := 6; + dris.var_g := 7; + dris.var_h := 8; + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + messagedlg('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + messagedlg('Dinkey Dongle protection error.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd } + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) <> dris.alg_answer) then + begin + messagedlg('Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine', mtError, [mbok], 0); + result := -1; + exit; + end; +end; + +{ ************************** WriteBytes *************************************** } +{ This writes the Data "Hello, World" to the dongle data area at offset 7 + In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. } + +Function WriteBytes : LongInt; +var + dris: drisType; + DataToWrite : array[0..13] of AnsiChar; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= WRITE_DATA_AREA; { standard protection check & write data} + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.rw_offset := 7; + dris.rw_length := 13; + DataToWrite := 'Hello, World!'; { string to write } + dris.rw_data_ptr := Addr(DataToWrite); + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + messagedlg('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + messagedlg('Dinkey Dongle protection error.', mtError, [mbok], 0); + result := -1; + exit; + end; +end; + +{ ************************** ReadBytes *************************************** } +{ This reads 14 bytes of data from offset 7 in the dongle data area + In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. + In order for the data to be displayed properly by this routine it will need to be text data } +Function ReadBytes : LongInt; +var + dris: drisType; + DataToRead : array[0..13] of AnsiChar; + display : string; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= READ_DATA_AREA; { standard protection check & write data} + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.rw_offset := 7; + dris.rw_length := 13; { we will add null termination after reading } + dris.rw_data_ptr := Addr(DataToRead); + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + messagedlg('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + messagedlg('Dinkey Dongle protection error.', mtError, [mbok], 0); + result := -1; + exit; + end; + + DataToRead[13] := Chr(0); { null end of string } + display := 'Dinkey Dongle data area contains: ' + DataToRead; + messagedlg(display, mtInformation, [mbok], 0); +end; + +{ ************************** EncryptUserData ********************************** } +{ This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 + It will then do another protection check & decrypt the data } +Function EncryptUserData : LongInt; +var + dris: drisType; + display : string; + DataString : array[0..13] of AnsiChar; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= ENCRYPT_USER_DATA; { standard protection check & encrypt data } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.data_crypt_key_num := 1; + dris.rw_length := 13; + DataString := 'Hello, World!'; { string to encrypt } + dris.rw_data_ptr := Addr(DataString); + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... } + + { Now decrypt the same data to get the original values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= DECRYPT_USER_DATA; { standard protection check & decrypt data } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.data_crypt_key_num := 1; + dris.rw_length := 13; + dris.rw_data_ptr := Addr(DataString); + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + messagedlg('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + messagedlg('Dinkey Dongle protection error.', mtError, [mbok], 0); + result := -1; + exit; + end; + + DataString[13] := Chr(0); { null end of string } + display := 'Decrypted data is: ' + DataString; + messagedlg(display, mtInformation, [mbok], 0); +end; + +{!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! + In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" + in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm + but the code can be modified easily to use the 3 encryption parameters. } + +{ !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm } +Function MyRWAlgorithm(a,b,c,d,e,f,g,h:LongInt):LongInt; +begin + MyRWAlgorithm:= a xor b xor c xor d xor e xor f; +end; + +{ !!!! please overwrite this function with the one generated by DinkeyAdd } +procedure CryptDRIS(dris : PByte; seed1,seed2 : Longword); +var + i,j,k : Integer; + bigseed,S : packed array[0..255] of byte; + temp,t : byte; +begin + i := 0; + while (i < 255) do + begin + Move(seed1, bigseed[i], 4); {NB move actually copies data} + Move(seed2, bigseed[i+4], 4); + i := i + 8; + end; + + for i := 0 to 255 do S[i]:= i; + + j := 0; + for i := 0 to 255 do + begin + j := (j + S[i] + bigseed[i] + 123) Mod 256; + temp := S[i]; + S[i] := S[j]; + S[j] := temp; + end; + i := 0; + j := 0; + Inc(dris, 16); {the first part of the DRIS is not encrypted} + for k := 16 to SizeOf(drisType)-1 do + begin + i := (i + 1) Mod 256; + j := (j + S[i] + 212) Mod 256; + temp := S[i]; + S[i] := S[j]; + S[j] := temp; + t := (S[i] + S[j] + 97) Mod 256; + dris^ := dris^ xor S[t]; + Inc(dris); + end; +end; +{ !!!! please overwrite this function with the one generated by DinkeyAdd } +procedure CryptApiData(data : pbyte; length : integer; seed1,seed2 : Longword; alg_answer: LongInt); +var + i,j,k : Integer; + bigseed,S : packed array[0..255] of byte; + temp,t : byte; +begin + i := 0; + while (i < 255) do + begin + Move(seed1, bigseed[i], 4); {NB move actually copies data} + Move(seed2, bigseed[i+4], 4); + i := i + 8; + end; + + for i := 0 to 255 do S[i]:= i; + + j := 0; + for i := 0 to 255 do + begin + j := (j + S[i] + bigseed[i] + (alg_answer And $FF)) Mod 256; + temp := S[i]; + S[i] := S[j]; + S[j] := temp; + end; + i := 0; + j := 0; + for k := 0 to length-1 do + begin + i := (i + 1) Mod 256; + j := (j + S[i] + ((alg_answer shr 8) And $FF)) Mod 256; + temp := S[i]; + S[i] := S[j]; + S[j] := temp; + t := (S[i] + S[j] + ((alg_answer shr 16) And $FF)) Mod 256; + data^ := data^ xor S[t]; + Inc(data); + end; +end; + +{ ************************** ProtCheckEnc ************************************ } +{ We encrypt the DRIS passed to the API. + Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. } +Function ProtCheckEnc : LongInt; +var + dris: drisType; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); { NB this also fills seed1, seed2 with random values } + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= PROTECTION_CHECK; { standard protection check } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!! you should separate from DDProtCheck for greater security } + + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!! you should separate from DDProtCheck for greater security } + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + messagedlg('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.', mtError, [mbok], 0); + result := -1; + exit; + end; + + if (dris.prodcode <> AnsiString(MY_PRODCODE)) then + begin + messagedlg('Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + messagedlg('Dinkey Dongle protection error.', mtError, [mbok], 0); + result := -1; + exit; + end; +end; + +{ ************************** ProtCheckWithAlgEnc ******************************** } +{ NB for this to work you must program at least "user algorithm" into the dongle + NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite copy source code from DinkeyLook. + We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd.} +Function ProtCheckWithAlgEnc : LongInt; +var + dris: drisType; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); { NB this also fills seed1, seed2, var_a...var_h with random values } + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= EXECUTE_ALGORITHM; { standard protection check & execute algorithm } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.alg_number := 1; { execute algorithm 1 - you do not need to specify this field if you are only using Lite models} + { you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random } + dris.var_a := 1; { sample values } + dris.var_b := 2; + dris.var_c := 3; + dris.var_d := 4; + dris.var_e := 5; + dris.var_f := 6; + dris.var_g := 7; + dris.var_h := 8; + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + messagedlg('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + messagedlg('Dinkey Dongle protection error.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd } + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) <> dris.alg_answer) then + begin + messagedlg('Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine', mtError, [mbok], 0); + result := -1; + exit; + end; +end; + +{ ************************** WriteBytesEnc************************************** } +{ This writes the Data 012...9 to the dongle data area at offset 7 + In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd.} +Function WriteBytesEnc : LongInt; +var + dris: drisType; + DataToWrite : packed array[0..9] of byte; + alg_ans, i: longint; + +begin + for i := 0 to 9 do + DataToWrite[i] := i; + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); { NB this also fills seed1, seed2, var_a...var_h with random values } + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= WRITE_DATA_AREA; { standard protection check & write data} + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.rw_offset := 7; + dris.rw_length := SizeOf(DataToWrite); + dris.rw_data_ptr := Addr(DataToWrite); + + { calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm } + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + { encrypt data we want to write } + CryptApiData(@DataToWrite, SizeOf(DataToWrite), dris.seed1, dris.seed2, alg_ans); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + messagedlg('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + messagedlg('Dinkey Dongle protection error.', mtError, [mbok], 0); + result := -1; + exit; + end; +end; + +{ ************************** ReadBytesEnc *************************************** } +{ This reads 10 bytes of data from offset 7 in the dongle data area + In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd.} +Function ReadBytesEnc : LongInt; +var + dris: drisType; + DataToRead : packed array[0..9] of byte; + display : string; + alg_ans, i: longint; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); { NB this also fills seed1, seed2, var_a...var_h with random values } + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= READ_DATA_AREA; { standard protection check & write data} + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.rw_offset := 7; + dris.rw_length := SizeOf(DataToRead); + dris.rw_data_ptr := Addr(DataToRead); + + { calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm } + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + messagedlg('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + messagedlg('Dinkey Dongle protection error.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { decrypt data that was read } + CryptApiData(@DataToRead, SizeOf(DataToRead), dris.seed1, dris.seed2, alg_ans); + display := 'Dinkey Dongle data area contains: '; + for i:=0 to 9 do + display := display + IntToStr(DataToRead[i]) + ' '; + messagedlg(display, mtInformation, [mbok], 0); +end; + +{ ************************** EncryptUserDataEnc ******************************* } +{ This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 + It will then do another protection & decrypt the data. + We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd.} +Function EncryptUserDataEnc : LongInt; +var + dris: drisType; + display : string; + DataBytes : packed array[0..9] of byte; + alg_ans,i : LongInt; + +begin + for i := 0 to 9 do + DataBytes[i] := i; { initialise data to 0,1,2,3,4,5,6,7,8,9} + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); { NB this also fills seed1, seed2, var_a...var_h with random values } + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= ENCRYPT_USER_DATA; { standard protection check & encrypt data } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.data_crypt_key_num := 1; + dris.rw_length := SizeOf(DataBytes); + dris.rw_data_ptr := Addr(DataBytes); + + { calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm } + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + { encrypt data we want to write } + CryptApiData(@DataBytes, Sizeof(DataBytes), dris.seed1, dris.seed2, alg_ans); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... } + + { Now decrypt the same data to get the original values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= DECRYPT_USER_DATA; { standard protection check & decrypt data } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.data_crypt_key_num := 1; + dris.rw_length := SizeOf(DataBytes); + dris.rw_data_ptr := Addr(DataBytes); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + messagedlg('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + messagedlg('Dinkey Dongle protection error.', mtError, [mbok], 0); + result := -1; + exit; + end; + + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + { decrypt data that was read } + CryptApiData(@DataBytes, SizeOf(DataBytes), dris.seed1, dris.seed2, alg_ans); + display := 'Data decrypted by dongle is: '; + for i:=0 to 9 do + display := display + IntToStr(DataBytes[i]) + ' '; + messagedlg(display, mtInformation, [mbok], 0); +end; + +{ *************** code that gets executed on startup *********************** } +begin + {call the function(s) of your choice here - in this example I have chosen a standard protection check} + if (ProtCheck() <> 0) then + halt; +end. + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/dpwin32_omf.obj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/dpwin32_omf.obj new file mode 100644 index 0000000..bbf3f76 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/dpwin32_omf.obj differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/dpwin64_delphi.obj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/dpwin64_delphi.obj new file mode 100644 index 0000000..6ff67c1 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/dpwin64_delphi.obj differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/dris.pas b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/dris.pas new file mode 100644 index 0000000..0eb91b3 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/dris.pas @@ -0,0 +1,102 @@ +{ !! this file should not be modified } +unit dris; + +interface + +uses Windows; + + TYPE + drisType = packed record + { the first 4 fields are never encrypted } + header : array[0..3] of AnsiChar; { should be set to DRIS } + { inputs } + size : longint; { size of this structure } + seed1 : longint; { seed for data/dris encryption } + seed2 : longint; { as above } + { maybe encrypted from now on } + myfunction : longint; { specify only one function. NB can't name it "function" as it is a reserved keyword } + flags : longint; { options for the function selected. To use more than one OR them together: OPTION1 or OPTION2... } + execs_decrement : longword; { amount by which to dec execs if we use flag: DEC_MANY_EXECS } + data_crypt_key_num : longint; { number of the key (1-3) that the dongle uses to encrypt or decrypt user data } + rw_offset : longint; { offset in the dongle data area to read or write data } + rw_length : longint; { length of data are to read/write/encrypt/decrypt } + rw_data_ptr : Pbyte; { pointer to data to write / be read } + alt_licence_name : array[0..255] of AnsiChar; { protection check for different licence instead of the default one, must be null-terminated } + var_a : longint; { variable values for user algorithm } + var_b : longint; + var_c : longint; + var_d : longint; + var_e : longint; + var_f : longint; + var_g : longint; + var_h : longint; + alg_number : longint; { the number of the user algorithm that you want to execute } + { outputs } + ret_code : longint; { return code from the protection check } + ext_err : longint; { extended error } + dongle_type : longint; { type of dongle detected. 1 = Pro, 2 = FD. NB "type" is a reserved word so I use dongle_type } + model : longint; { model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited } + sdsn : longint; { Software Developer's Serial Number } + prodcode : array[0..11] of AnsiChar; { Product Code (null-terminated) } + dongle_number : longword; + update_number : longint; + data_area_size : longword; { size of the data area in the dongle detected } + max_alg_num : longint; { the maximum algorithm number in the dongle detected } + execs : longint; { executions left: -1 indicates 'no limit' } + exp_day : longint; { expiry day: -1 indicates 'no limit' } + exp_month : longint; { expiry month: -1 indicates 'no limit' } + exp_year : longint; { expiry year: -1 indicates 'no limit' } + features : longword; { features value } + net_users : longint; { maximum number of network users for the dongle detected: -1 indicates 'no limit' } + alg_answer : longint; { answer to the user algorithm executed with the given variable values } + fd_capacity : longword; { capacity of the data area in FD dongle. Currently fixed at ~10MB but may change in the future. } + fd_drive : array[0..127] of AnsiChar; { drive letter of FD dongle detected (if any) 'f:\' } + swkey_type : longint; { 0 = no swkey detected, 1 = temporary software key, 2 = demo software key } + swkey_exp_day : longint; { software key expiry date (if software key detected) } + swkey_exp_month : longint; + swkey_exp_year : longint; + end; + + TYPE + nu_infoType = packed record + licenceName : array[0..255] of AnsiChar; + userName : array[0..49] of AnsiChar; + computerName : array[0..255] of AnsiChar; + ipAddress : array[0..15] of AnsiChar; + end; + + { function constants - specify one only } + const PROTECTION_CHECK = 1; { checks for dongle, check program params... } + const EXECUTE_ALGORITHM = 2; { protection check + calculate answer for specified algorithm with specified inputs } + const WRITE_DATA_AREA = 3; { protection check + writes dongle data area } + const READ_DATA_AREA = 4; { protection check + reads dongle data area } + const ENCRYPT_USER_DATA = 5; { protection check + the dongle will encrypt user data } + const DECRYPT_USER_DATA = 6; { protection check + the dongle will decrypt user data } + const FAST_PRESENCE_CHECK = 7; { checks for the presence of the correct dongle only with minimal security, no flags allowed. } + const STOP_NET_USER = 8; { stops a network user (a protection check is NOT performed) } + + { flag constants - can specify more than one } + const DEC_ONE_EXEC = 1; { decrement execs by 1 } + const DEC_MANY_EXECS = 2; { decrement execs by number specified in execs_decrement } + const START_NET_USER = 4; { starts a network user } + const USE_FUNCTION_ARGUMENT = 16; { use the extra argument in the function for pointers } + const CHECK_LOCAL_FIRST = 32; { always look in local ports before looking in network ports } + const CHECK_NETWORK_FIRST = 64; { always look on the network before looking in local ports } + const USE_ALT_LICENCE_NAME = 128; { use name specified in alt_licence_name instead of the default one } + const DONT_SET_MAXDAYS_EXPIRY = 256; { if the max days expiry date has not been calculated then do not do it this time } + const MATCH_DONGLE_NUMBER = 512; { restrict the search to match the dongle number specified in the DRIS } + const DONT_RETURN_FD_DRIVE = 1024; { if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS } + + { runtime api functions} + function DDProtCheck( dris, data:pointer ):LongInt; stdcall; external; + function DDGetNetUserList(licence_name:PAnsiChar; num_net_users:PLongInt; nu_info:pointer; num_info_structs:LongInt; extended_error:PLongInt):LongInt; stdcall; external; + +implementation + +{$IFDEF WIN32} + {$L dpwin32_omf.obj} +{$ELSE} + {$L dpwin64_delphi.obj} +{$ENDIF} + +end. diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/dris_for_dll.pas b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/dris_for_dll.pas new file mode 100644 index 0000000..dbf4646 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Delphi/VCL/Runtime/dris_for_dll.pas @@ -0,0 +1,100 @@ +{ !! this file should not be modified } +unit dris; + +interface + +uses Windows; + + TYPE + drisType = packed record + { the first 4 fields are never encrypted } + header : array[0..3] of AnsiChar; { should be set to DRIS } + { inputs } + size : longint; { size of this structure } + seed1 : longint; { seed for data/dris encryption } + seed2 : longint; { as above } + { maybe encrypted from now on } + myfunction : longint; { specify only one function. NB can't name it "function" as it is a reserved keyword } + flags : longint; { options for the function selected. To use more than one OR them together: OPTION1 or OPTION2... } + execs_decrement : longword; { amount by which to dec execs if we use flag: DEC_MANY_EXECS } + data_crypt_key_num : longint; { number of the key (1-3) that the dongle uses to encrypt or decrypt user data } + rw_offset : longint; { offset in the dongle data area to read or write data } + rw_length : longint; { length of data are to read/write/encrypt/decrypt } + rw_data_ptr : Pbyte; { pointer to data to write / be read } + alt_licence_name : array[0..255] of AnsiChar; { protection check for different licence instead of the default one, must be null-terminated } + var_a : longint; { variable values for user algorithm } + var_b : longint; + var_c : longint; + var_d : longint; + var_e : longint; + var_f : longint; + var_g : longint; + var_h : longint; + alg_number : longint; { the number of the user algorithm that you want to execute } + { outputs } + ret_code : longint; { return code from the protection check } + ext_err : longint; { extended error } + dongle_type : longint; { type of dongle detected. 1 = Pro, 2 = FD. NB "type" is a reserved word so I use dongle_type } + model : longint; { model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited } + sdsn : longint; { Software Developer's Serial Number } + prodcode : array[0..11] of AnsiChar; { Product Code (null-terminated) } + dongle_number : longword; + update_number : longint; + data_area_size : longword; { size of the data area in the dongle detected } + max_alg_num : longint; { the maximum algorithm number in the dongle detected } + execs : longint; { executions left: -1 indicates 'no limit' } + exp_day : longint; { expiry day: -1 indicates 'no limit' } + exp_month : longint; { expiry month: -1 indicates 'no limit' } + exp_year : longint; { expiry year: -1 indicates 'no limit' } + features : longword; { features value } + net_users : longint; { maximum number of network users for the dongle detected: -1 indicates 'no limit' } + alg_answer : longint; { answer to the user algorithm executed with the given variable values } + fd_capacity : longword; { capacity of the data area in FD dongle. Currently fixed at ~10MB but may change in the future. } + fd_drive : array[0..127] of AnsiChar; { drive letter of FD dongle detected (if any) 'f:\' } + swkey_type : longint; { 0 = no swkey detected, 1 = temporary software key, 2 = demo software key } + swkey_exp_day : longint; { software key expiry date (if software key detected) } + swkey_exp_month : longint; + swkey_exp_year : longint; + end; + + TYPE + nu_infoType = packed record + licenceName : array[0..255] of AnsiChar; + userName : array[0..49] of AnsiChar; + computerName : array[0..255] of AnsiChar; + ipAddress : array[0..15] of AnsiChar; + end; + + { function constants - specify one only } + const PROTECTION_CHECK = 1; { checks for dongle, check program params... } + const EXECUTE_ALGORITHM = 2; { protection check + calculate answer for specified algorithm with specified inputs } + const WRITE_DATA_AREA = 3; { protection check + writes dongle data area } + const READ_DATA_AREA = 4; { protection check + reads dongle data area } + const ENCRYPT_USER_DATA = 5; { protection check + the dongle will encrypt user data } + const DECRYPT_USER_DATA = 6; { protection check + the dongle will decrypt user data } + const FAST_PRESENCE_CHECK = 7; { checks for the presence of the correct dongle only with minimal security, no flags allowed. } + const STOP_NET_USER = 8; { stops a network user (a protection check is NOT performed) } + + { flag constants - can specify more than one } + const DEC_ONE_EXEC = 1; { decrement execs by 1 } + const DEC_MANY_EXECS = 2; { decrement execs by number specified in execs_decrement } + const START_NET_USER = 4; { starts a network user } + const USE_FUNCTION_ARGUMENT = 16; { use the extra argument in the function for pointers } + const CHECK_LOCAL_FIRST = 32; { always look in local ports before looking in network ports } + const CHECK_NETWORK_FIRST = 64; { always look on the network before looking in local ports } + const USE_ALT_LICENCE_NAME = 128; { use name specified in alt_licence_name instead of the default one } + const DONT_SET_MAXDAYS_EXPIRY = 256; { if the max days expiry date has not been calculated then do not do it this time } + const MATCH_DONGLE_NUMBER = 512; { restrict the search to match the dongle number specified in the DRIS } + const DONT_RETURN_FD_DRIVE = 1024; { if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS } + +{$IFDEF WIN32} + function DDProtCheck( dris, data:pointer ):LongInt; stdcall; external 'dpwin32.dll'; + function DDGetNetUserList(licence_name:PAnsiChar; num_net_users:PLongInt; nu_info:pointer; num_info_structs:LongInt; extended_error:PLongInt):LongInt; stdcall; external 'dpwin32.dll'; +{$ELSE} + function DDProtCheck( dris, data:pointer ):LongInt; stdcall; external 'dpwin64.dll'; + function DDGetNetUserList(licence_name:PAnsiChar; num_net_users:PLongInt; nu_info:pointer; num_info_structs:LongInt; extended_error:PLongInt):LongInt; stdcall; external 'dpwin64.dll'; +{$ENDIF} + +implementation + +end. diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Excel/DPSample.xls b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Excel/DPSample.xls new file mode 100644 index 0000000..11e3985 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Excel/DPSample.xls differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Excel/DinkeyPro.bas b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Excel/DinkeyPro.bas new file mode 100644 index 0000000..8edd116 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Excel/DinkeyPro.bas @@ -0,0 +1,149 @@ +Attribute VB_Name = "DinkeyPro" + +' A VBA Interface to the Dinkey Pro/FD API + +' *********************** +' DO NOT MODIFY THIS FILE +' *********************** + +Option Explicit + +' ------------------------------------------------------------------------------ +' Windows API functions used by this module + +#If VBA7 Then + Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long) +#Else + Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long) +#End If + +' ------------------------------------------------------------------------------ +' Dinkey Runtime Information Structure (DRIS) + +Type DRIS + header As String * 4 ' should be set to "DRIS" + ' Inputs + size As Long ' size of this structure + seed1 As Long ' seed for data/dris encryption + seed2 As Long ' as above + function As Long ' specify only one function + flags As Long ' options for the function selected. To use more than one OR them together: OPTION1 Or OPTION2... + execs_decrement As Long ' amount by which to decrement execs if the DEC_MANY_EXECS flag is used + data_crypt_key_num As Long ' number of the key (1-3) that the dongle uses to encrypt or decrypt user data + rw_offset As Long ' offset in the dongle data area to read or write data + rw_length As Long ' length of data to read/write/encrypt/decrypt +#If VBA7 Then + not_used As LongPtr ' This field is a pointer used in other programming languages. 4 bytes in 32-bit Excel, 8 bytes in 64-bit Excel +#Else + not_used As Long +#End If + alt_licence_name As String * 256 ' protection check for different licence instead of this one, must be null-terminated ASCII + var_a As Long ' variable values for user algorithms + var_b As Long + var_c As Long + var_d As Long + var_e As Long + var_f As Long + var_g As Long + var_h As Long + alg_number As Long ' the number of the user algorithm that you want to execute + + ' Outputs + ret_code As Long ' the return code from the protection check + ext_err As Long ' extended error + type As Long ' type of dongle detected. Possible values shown below + model As Long ' model of dongle detected. Possible values shown below + sdsn As Long ' Software Developer's Serial Number + prodcode As String * 12 ' product code (null-terminated) + dongle_number As Long ' dongle serial number + update_number As Long + data_area_size As Long ' size of the data area in the dongle detected + max_alg_num As Long ' the maximum algorithm number in the dongle detected + execs As Long ' executions left: -1 indicates 'no limit' + exp_day As Long ' expiry day: -1 indicates 'no limit' + exp_month As Long ' expiry month: -1 indicates 'no limit' + exp_year As Long ' expiry year: -1 indicates 'no limit' + features As Long ' features value + net_users As Long ' maximum number of network users for the dongle detected: -1 indicates 'mo limit' + alg_answer As Long ' answer to the user algorithm executed with the given variable values + fd_capacity As Long ' FD dongles only- capacity of the data area. Currently fixed at ~8KB but may change in the future. + fd_drive As String * 128 ' FD dongles only - drive letter of the dongle's flash drive, e.g. "F:\" + swkey_type As Long ' 0 = no software key detected, 1 = temporary software key, 2 = demo software key + swkey_exp_day As Long ' software key expiry date (if software key detected) + swkey_exp_month As Long + swkey_exp_year As Long +End Type + +' ------------------------------------------------------------------------------ +' Useful Constants + +' Possible dris.function values +Public Const PROTECTION_CHECK = 1 ' Standard protection check +Public Const EXECUTE_ALGORITHM = 2 ' Protection check + execute an algorithm stored in the dongle +Public Const WRITE_DATA_AREA = 3 ' Protection check + write to the dongle data area +Public Const READ_DATA_AREA = 4 ' Protection check + read from the dongle data area +Public Const ENCRYPT_USER_DATA = 5 ' Protection check + use the dongle's encryption engine to encrypt your own data +Public Const DECRYPT_USER_DATA = 6 ' Protection check + the dongle will decrypt user data +Public Const FAST_PRESENCE_CHECK = 7 ' Checks for the presence of a valid dongle. Very quick but weaker security +Public Const STOP_NET_USER = 8 ' Stop a network user (a protection check is NOT performed) + +' Possible dris.flags values +Public Const DEC_ONE_EXEC = 1 ' Decrement execs by 1 +Public Const DEC_MANY_EXECS = 2 ' Decrement execs by number specified in execs +Public Const START_NET_USER = 4 ' Start a network user +Public Const USE_FUNCTION_ARGUMENT = 16 ' Use the extra argument in the function for pointers +Public Const CHECK_LOCAL_FIRST = 32 ' Force the API to look for a local dongle before a network dongle +Public Const CHECK_NETWORK_FIRST = 64 ' Force the API to look for a dongle on the network before looking in local ports +Public Const USE_ALT_LICENCE_NAME = 128 ' Use name specified in alt_licence_name instead of the default one +Public Const DONT_SET_MAXDAYS_EXPIRY = 256 ' If the max days expiry date has not been calculated then do not do it this time +Public Const MATCH_DONGLE_NUMBER = 512 ' Restrict the search to match the dongle number specified in the DRIS +Public Const DONT_RETURN_FD_DRIVE = 1024 ' if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + + +' Possible dris.type values +Public Const DONGLE_TYPE_PRO = 1 ' Dinkey Pro dongle +Public Const DONGLE_TYPE_FD = 2 ' Dinkey FD dongle + +' Possible dris.model values +Public Const DONGLE_MODEL_LITE = 1 ' Lite dongle +Public Const DONGLE_MODEL_PLUS = 2 ' Plus dongle +Public Const DONGLE_MODEL_NET5 = 4 ' Net dongle, 5 users +Public Const DONGLE_MODEL_NETU = 7 ' Net dongle, unlimited users + +' ------------------------------------------------------------------------------ +' A function to initialise the DRIS with random values + +Public Sub RandomSetDrisElements(DrisToSet As DRIS) + Dim TempDris(Len(DrisToSet)) As Byte + Dim I As Integer + + Call Randomize + + For I = 0 To Len(DrisToSet) - 1 + TempDris(I) = Int(256 * Rnd()) ' The int part of a random float 0 <= N < 256, i.e. an int between 0 and 255 + Next + + Call CopyMemory(DrisToSet, TempDris(0), Len(DrisToSet)) +End Sub + +' ------------------------------------------------------------------------------ +' This function will convert a C string returned in the DRIS to a VB string + +Function TrimCString(CString As String) As String + Dim I As Integer + I = InStr(CString, vbNullChar) ' Find position of terminating null character + TrimCString = Left(CString, I - 1) ' Return everything before that position +End Function + +' ------------------------------------------------------------------------------ +' Visual Basic for Applications only supports signed integers, +' but some DRIS fields such as dongle_number are stored as unsigned integers. +' Use this function to convert those fields to Double values + +Public Function UnsignedLongToDouble(Number As Long) As Double + If (Number < 0) Then + UnsignedLongToDouble = Number + 4294967296# + Else + UnsignedLongToDouble = Number + End If +End Function diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Excel/README.html b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Excel/README.html new file mode 100644 index 0000000..f536f5f --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Excel/README.html @@ -0,0 +1,267 @@ + + + + + Using Dinkey Pro/FD with Excel + + + +

Using Dinkey Pro/FD with Excel

+
+

+ The Shell protection method supports Windows executables produced by the DoneEx XCell Compiler. +

+

+ API protection checks in Excel are implemented by adding Visual Basic for Applications (VBA) code to your workbook. + The VBA module DinkeyPro.bas is used to communicate with the dongle via the appropriate API DLL + (dpwin32.dll on 32-bit Windows, dpwin64.dll on 64-bit Windows). + You should lock these DLLs with the API method using DinkeyAdd as described in the user manual, and distribute the locked DLLs with your software. +

+
+

+ Using the DoneEx XCell Compiler and the Shell method is the preferred option for most Excel users, + as it does not require you to write any VBA macro code, and so is easier to implement. +

+ +

XCell Compiler and the Shell Method

+

+ The DoneEx XCell Compiler converts an Excel workbook into an executable file (a program). + All of your data, formulas and VBA macro code are stored encrypted, which makes this method very secure. + XCell Compiler is a separate tool that must be purchased separately. + A free trial is available to allow you to evaluate its functionality before buying. +

+

+ There are a few things that you should be aware of when protecting your workbook with XCell Compiler and Dinkey Pro/FD: +

+
    +
  • +

    + You must use the XCell Compiler option Save into external storage (XSTG file). + This option means that your protected workbook's data is encrypted and securely stored in a separate file, not in the executable. + This is necessary to allow changes to your workbook to be saved, as Shell-protected executables cannot be modified. +

    +
  • +
  • +

    + If you use the Shell method background check (recommended and enabled by default), + if a background protection check fails then your protected workbook will be immediately closed without any warning messages, and any unsaved changes will be lost. +

    +
  • +
  • +

    + When a user closes your protected workbook, Excel will always ask the user if they want to save changes, even if no changes have been made. +

    +
  • +
+ +

VBA Code and the API Method

+
+

+ For a good level of security, your workbook should rely heavily on VBA code (macros). + See below for more information. +

+

+ Before you distribute your protected workbook, you must protect your VBA code against modification. + To do this: +

+
    +
  1. Open your project in the Visual Basic Editor.
  2. +
  3. Go to Tools > VBAProject Properties in the menu.
  4. +
  5. Select the Protection tab.
  6. +
  7. Enable Lock project for viewing and enter a strong password, then click OK.
  8. +
+

+ Now the workbook's VBA code cannot be viewed or modified without entering the password. +

+
+

+ Even if you have never written code before, you will probably be familiar with macros: sequences of commands and functions that you can use to automate tasks in Excel. + Excel macros are stored in modules that contain sequences of instructions in a code language known as Visual Basic for Applications, or VBA. + The terms macros and VBA are often used interchangeably. +

+

+ VBA code is a powerful and flexible tool with many uses. Unfortunately, the power of VBA means that macros created with malicious intentions can cause harm to your documents or your system. + As a result, Excel makes it possible for users to open and use workbooks with macros disabled, and to only allow the VBA code to be executed if the user trusts the owner of the workbook. + Obviously, this also prevents dongle checking code from running. + To prevent someone using this safety feature to work around the dongle protection, you should ensure that the functionality of your workbook relies heavily on macros. + That way if your workbook is opened with macros disabled, its functionality will be severely limited. +

+

+ Legitimate users of your workbook may be concerned about executing the VBA code in your workbook. + Excel allows you to certify your macros with a digital signature so that users can verify that they are from a trustworthy source (i.e. you), + and that the code has not been modified since you wrote it. See the Excel documentation for more information. +

+ +

Excel Example Files

+
    +
  • DinkeyPro.bas - a module that provides a VBA interface to the Dinkey Pro/FD API.
  • +
  • DPSample.xls - various examples of using DinkeyPro.bas.
  • +
+

+ DinkeyPro.bas should be used, without modification, in your own project. + Use File > Import File in the Visual Basic Editor to add DinkeyPro.bas + to your VBA code. +

+ +

Supported Versions

+

+ The Excel sample workbook and VBA code provided with the Dinkey Pro/FD SDK was created using Excel 2007, + and tested using Excel 2007 (32-bit) and Excel 2013 (64-bit). + All newer versions should be backwards compatible. The sample code should also work with older versions, + but no guarantees can be made, and support for older versions is likely to be very limited. +

+ +

Try It Yourself

+
+

+ The sample code is designed to teach you how to use the Dinkey Pro/FD API in Excel workbooks. + Do not copy the examples verbatim into your own code. Experiment with the sample code to understand how the API works, + and read the chapter Increasing Your Protection in the user manual for many suggestions on how to + make the best use of the API features. +

+
+

+ DPSample.xls gives simple examples of performing a protection check, + as well as using various other features of Dinkey Pro/FD. + To use DPSample.xls you will first need to use DinkeyAdd to produce a locked copy of the DLL for your platform, + and program a dongle (if you are using Plus or Net dongles). Place the locked DLL in the same folder as the example files. +

+

+ Open DPSample.xls in Excel, then open the Visual Basic Editor by pressing ALT+F11. + Browse the examples in the DPSample module to see how different features can be used. + All the examples follow the same basic pattern: +

+
    +
  1. Set up the DRIS structure with the relevant information.
  2. +
  3. Call the API.
  4. +
  5. Use the information returned in the DRIS.
  6. +
+

+ Uncomment the function calls in the RunExampleButton_Click() procedure + in the DPSample module to enable the examples of different features, + then click the Run Example button on Sheet1 of the workbook to run the examples. +

+

+ The DPSample module also demonstrates loading the appropriate DLL for your platform. +

+

+ Parts of the sample code are marked with !!!! must be customised with your own functions or values + for some features to work correctly. Not all features are supported by all dongle models. + See the user manual for more information. +

+ + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/FileMaker/DinkeyPro Test.fmp12 b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/FileMaker/DinkeyPro Test.fmp12 new file mode 100644 index 0000000..b8689f0 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/FileMaker/DinkeyPro Test.fmp12 differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/FileMaker/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/FileMaker/README.txt new file mode 100644 index 0000000..5bcc48c --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/FileMaker/README.txt @@ -0,0 +1,205 @@ +Filemaker Plug-In +~~~~~~~~~~~~~~~~~ + +We provide a Filemaker plug-in so that you can communicate with the dongle from your +filemaker database. The filemaker plugin in the Filemaker\v7 directory is compatible +with Filemaker 7-13 (and also Filemaker 14 in 32-bit mode). The plug-in in the +Filemaker\v14 directory is compatible with Filemaker 14 (64-bit only for Mac) and +higher. + +The plug-in is called: + +DinkeyPro.fmx (for 32-bit Windows) +DinkeyPro.fmx64 (for 64-bit Windows) +DinkeyPro.fmplugin (for Mac) + +To use the plug-in (as with any plug-in) you must: + +1)a) For versions of Filemaker previous to version 12: + Copy the DinkeyPro plug-in to the Extensions folder (located in the FileMaker folder) + and then launch Filemaker. + + b) For Filemaker 12 (and later) you must install the plug-in by creating a container + and running an installation script. See the DinkeyPro Test.fmp12 solution for an + example of how to do this. You should also read the Filemaker documentation on + installing plug-ins. + +2) From the menu choose Preferences (under Windows it is Edit | Preferences and + under Mac OS X it is FileMaker Pro | Preferences). Then choose the plug-ins tab. + Make sure the box "Dinkey Dongle Pro/FD Plugin" is listed and ticked. If there is a + tock box that says "All solutions to install files" then make sure it is ticked. + +3) You may want to modify the startup script (file | file options | perform script) + to check the dongle or create a field (of type calculation) that displays a value + returned by the protection check. View "external function" to see a list of all the + functions that the plug-in exports. Note - every function returns a text value. + +4) When you first use the plug-in you may get error 413. This is because you + have not protected it. To do this run DinkeyAdd and protect the plug-in file + specifying API Method. + +5) When you have finished make sure that you add FileMaker security so that a + user cannot view or modify the scripts you have added. This step does rely on + the security of the Filemaker password system, however. A better solution would + be to produce a runtime database file (you need FileMaker Advanced (used to be called + Developer Edition) to do this). + +Here is an example of some script you can use to check the protection (Please change the +version number to the current version). It is included in the DinkeyPro Test example +solution. Note: <> signifies 'not equals'. Filemaker has its own symbol for this. +You may want to do more than this so please look at all the functions in the PlugIn, +listed below): + +If [DinkeyProVersion("long") <> "Dinkey Dongle Pro/FD Plug-in 7.2.0"] + Show Custom Dialog ["Dinkey Dongle error"; "Missing or incorrect version of Plug-In."] + Exit Application +Else + #check dongle and look to see if returned values are correct + Set Variable [$ret_code; Value: DDprotCheck(0;0;"")] + If [$ret_code <> "0"] + Show Custom Dialog ["Error Detecting Dongle"; "Error " & $ret_code & " detecting dongle"] + Exit Application + Else If [DDGetSDSN(0) <> "10101"] + Show Custom Dialog ["Incorrect dongle detected"; "Contact your administrator to correct this error."] + Exit Application + Else If [DDGetProdCode(0) <> "DEMO"] + Show Custom Dialog ["Incorrect dongle detected"; "Contact your administrator to correct this error."] + Exit Application + Else + Show Custom Dialog ["Success!"; "Dongle checked successfully!"] + End If +End If + +Note you should make sure that the user cannot abort your scripts: +Allow User Abort[Off] +This is the default value anyway. + +The plug-in exports many functions. Here is a description of each function: + +Note - every function returns a "text" value. +Note - some of the functions expect dummy parameters. This is because there is + a bug with Filemaker 7 so that it will not accept functions with no parameters. +Note - you must call one of the DDProtCheck or DDProtCheckWithAlg or + DDWriteData or DDReadData functions before calling the DDGet... functions. + +DinkeyProVersion +~~~~~~~~~~~~~~~~ +Input: + string - if set to "long" returns the long description of version info + if set to "short" or the string is empty - version info + if set to "platform" - tells you if you are calling "Windows" or "Mac OS X" plug-in + +Returns version information about this plug-in. You must call this function +first to verify the Plug-In is present. This is very important because if the +Plug-In is not present then Filemaker forces the function to return 0 - which +for some functions indicates success. + + +DDProtCheck +~~~~~~~~~~~ +Input: + integer: flags (see DRIS description and flags values listed below) + integer: execs_decrement (optional) (see DRIS description) + text: alt_licence_name (optional) (see DRIS description) +Returns: + text: return code (0 = success, o.w. error number) + +This performs a standard protection check with the flags specified and is the function you +are most likely to use. Although 2 of the parameters are optional, Filemaker 7 (at least) +insists that you enter all 3 parameters. +It will return 0 for success or the dongle error code if there is a failure. + +DDProtCheckWithAlg +~~~~~~~~~~~~~~~~~~ +Input: + integer: flags (see DRIS description and flags values listed below) + integer: alg_number (number of user-defined algorithm to execute) + integers: var_a...var_h (variable values for user defined algorithm) +Returns: + text: return code (0 = success, o.w. error number) + +This performs a basic protection check and executes the specified algorithm with the +specified variable values. It will return 0 for success or the dongle error code if there is a +failure. NB to get the algorithm answer you should call DDGetAlgAnswer. + + +DDWriteData +~~~~~~~~~~~ +Input: + integer: flags (see DRIS description and flags values listed below) + integer: offset (of data area to write to) + integer: length (of data you want to write) + text: data you want to write +Returns: + text: return code (0 is success) + +This allows you to write a string to the dongle data area at the offset specified (for Dinkey 2/DinkeyNet). + + +DDReadData +~~~~~~~~~~ +Input: + integer: flags (see DRIS description and flags values listed below) + integer: offset (of data area you want to read from) + integer: length (of data you want to read) +Returns: + text: The data read (if success), otherwise it is the error code. +return code (0 is success) + +This allows you to read data from the dongle data area (for Dinkey 2/DinkeyNet). + + +After you have called either the DDProtCheck or DDProtCheckWithAlg or DDWriteData or +DDReadData functions you can call one of the following functions to get data from +the DRIS. These functions will all return -1 if a protection check has not been +performed. They will return -2 if a protection check has been performed but failed. +They all take a dummy parameter (integer) which can be any value you like (it is +ignored). They all have text outputs. Refer to the documentation regarding the DRIS +for more information on each of these fields. + +DDGetExtendedError - returns the extended error (only set if one of the protection check function has failed) +DDGetType - returns the type of dongle detected ("Pro" or "FD") +DDGetModel - returns the model of the dongle detected. Numerical value - see documentation on DRIS. +DDGetSDSN - returns the SDSN. +DDGetProdCode - returns the Product Code. +DDGetDongleNumber - returns the donglenumber +DDGetUpdateNumber - returns the update number +DDGetDataAreaSize - returns the size of the data are +DDGetMaxAlgNum - returns the maximum algorithm number in the dongle detected +DDGetExecs - returns the execs left (number or "no limit") +DDGetExpDay - returns the expiry day (number or "no limit") +DDGetExpMonth - returns the expiry month (number or "no limit") +DDGetExpYear - returns the expiry year (number or "no limit") +DDGetFeatures - returns the features value. +DDGetNetUsers - returns the maximum number of simultaneous network user allowed by the dongle (number or "no limit") +DDGetAlgAnswer - returns the answer of the Algorithm (if specified) +DDGetFDCapacity - returns the maximum capacity for the data area if an FD dongle is detected +DDGetFDDrive - returns the drive letter (mount name) of FD dongle detected e.g. f:\ +DDGetSWKeyType - returns whether a software key has been detected and what type it is +DDGetSWKeyExpDay - returns the expiry day of the swkey detected (if one has been detected) +DDGetSWKeyExpMonth - returns the expiry month of the swkey detected (if one has been detected) +DDGetSWKeyExpYear - returns the expiry year of the swkey detected (if one has been detected) + +Note - because of the limitations of the Filemaker scripting language you cannot encrypt +the DRIS or data passed to the API. + +DRIS Flags Values +~~~~~~~~~~~~~~~~~ +In general the flags value will be 0. If you want to use more than one flag then add the values. + +Value Name in Manual Description +1 DEC_ONE_EXEC decrement executions by 1 +2 DEC_MANY_EXECS decrement executions by number specified in execs_decrement +4 START_NET_USER start a network user +8 STOP_NET_USER stops a network user (a protection check is NOT performed) +16 USE_FUNCTION_ARGUMENT use the extra argument in the function to pass data +32 CHECK_LOCAL_FIRST always look for a dongle locally before looking in network ports +64 CHECK_NETWORK_FIRST always look for a network dongle before looking for a dongle locally +128 USE_ALT_LICENCE_NAME use name specified in alt_licence_name instead of the default one +256 DONT_SET_MAXDAYS_EXPIRY if the max days expiry date has not been calculated then do not do it this time +512 MATCH_DONGLE_NUMBER restrict the search to match the dongle number specified in the DRIS +1024 DONT_RETURN_FD_DRIVE if you have protected your solution to a Dinkey FD dongle then this flag + means that the flash disk drive letter or mount name will not be returned + +Filemaker7 plugin tested on filemaker version 7 (Mac and Windows 32-bit). +Filemaker14 plugin tested on Filemaker 15 (Mac and 64-bit Windows) and on Filemaker 14 (Mac 64-bit mode and Windows 32-bit) diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/DllTest.lfproj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/DllTest.lfproj new file mode 100644 index 0000000..fa2e3fb --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/DllTest.lfproj @@ -0,0 +1,69 @@ + + + + Debug + 2.0 + {76ddb05e-4dea-4d83-98ce-e740d0bc7426} + Exe + DllTest + C:\Program Files (x86)\Lahey-Fujitsu Fortran\v7.2\Visual Studio 2008\Packages + DllTest.exe + False + DllTest + + + bin\Debug\ + O0 + True + False + True + True + True + MSVC + O0 + default + ..\..\C\import_libs + dpwin32.lib + -g|-ndal|-ml MSVC|-o0|-pause|-stchk|-trace|-libpath "..\..\C\import_libs"|"dpwin32.lib" + False + + + False + False + False + + + True + DllTest.exe + LF95 + + + bin\Release\ + False + True + False + MSVC + default + ..\..\C\import_libs + dpwin32.lib + -ndal|-ml MSVC|-nw|-pause|-libpath "..\..\C\import_libs"|dpwin32.lib + + + + Code + .obj + -g|-ndal|-ml MSVC|-o0|-pause|-stchk|-trace + 1 + + + + + + + + + + + + + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/DllTest.sln b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/DllTest.sln new file mode 100644 index 0000000..d2a7b01 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/DllTest.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{B7CA1DD7-A797-4295-BB4F-1411A8008584}") = "DllTest", "DllTest.lfproj", "{76DDB05E-4DEA-4D83-98CE-E740D0BC7426}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {76DDB05E-4DEA-4D83-98CE-E740D0BC7426}.Debug|Win32.ActiveCfg = Debug|Win32 + {76DDB05E-4DEA-4D83-98CE-E740D0BC7426}.Debug|Win32.Build.0 = Debug|Win32 + {76DDB05E-4DEA-4D83-98CE-E740D0BC7426}.Release|Win32.ActiveCfg = Release|Win32 + {76DDB05E-4DEA-4D83-98CE-E740D0BC7426}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/README.txt new file mode 100644 index 0000000..8a25789 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/README.txt @@ -0,0 +1,76 @@ +Fortran Sample Code notes +~~~~~~~~~~~~~~~~~~~~~~~~~ + +We supply separate sample code for different compilers as they all seem to compile Fortran +slightly differently! In general the code is the same. The differences are in defining the +DDProtCheck function in our runtime dll and in using random_set and CryptDris functions. +The Intel compiler is much stricter and so the code is more complicated in this case +(we must use "equivalence" so we can treat the DRIS type as a byte array in some cases). + +Lahey Fortran Sample Code tested using 32-bit Lahey Fortran 7.2 and Visual Studio 2008 +Intel Fortran Sample Code tested using 32-bit and 64-bit Intel Fortran XE 2011 compiler & VS 2008 +(also tested with Intel Fortran 10.1 compiler but see note at the bottom of this file). + +g95 has some unusual restrictions such as 132 characters for a line length. Only tested +with 32-bit code. + +We have not tested with GFortran but the code should be similar to g95. + +Description of files: + +dlltest.f90 Fortran sample code for Lahey Fortran +DllTest.lfproj Visual Studio 2008 Project using Lahey Fortran +Dlltest.sln Visual Studio 2008 Solution for Lahey Fortran + +idlltest.f90 Fortran sample code for Intel Fortran +iDllTest.vfproj Visual Studio 2008 Project using Intel Fortran +iDlltest.sln Visual Studio 2008 Solution for Intel Fortran + +gdlltest.f90 Fortan code using by g95 compiler. + +The sample code contains 10 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. + +Note - you should protect dpwin32.dll and not your program. Because your program +is linked to the DLL it is protected. The protected DLL will need to be in the +same folder as your compiled program for it to run correctly. + +Note - once dpwin32.dll is protected you will not be able to debug your program - +after our API has been called. Our strong anti-debug code will cause the debugger +to throw an exception. If you do want to debug your code then you can use our debug +module: dpwin32debug.dll, but this should not be used for release. See readme.txt +in samples\c for restrictions concerning the debug module. + +Note - if you do not use Lahey/Intel Fortran or you use an earlier version of Visual Studio then +you will have to create the solution & project yourself. (Newer versions of Visual Studio will +update the project for you). It is not difficult. You have to link with the import library +(which is in Microsoft format) dpwin32.lib (so your program knows how our API functions are +formatted and the DLL name). For 64-bit compilations you link with dpwin64.lib. Both of these +files are in the Modules\import_libs folder (also in Samples\C\import_libs). You should list +this files in Project Settings | Linker | Input | Addition Dependencies. + +Note - the Lahey sample only works with 32-bit Fortran (because that is all Lahey supports currently). +The code should work with 64-bit Fortran also. However, you will have to change the "unused" element +in the DRIS to be integer(8). i.e. 8 bytes and change DRIS_SIZE to 548. + +Note - there appears to be a small bug in the 64-bit Intel 10.1 Fortran compiler. If you use this +then you need to remove the word DECORATE in the DDProtCheck function declaration. This keyword is +needed for the 32-bit compiler. + +Note - For g95 you should compile like this (for example): +g95 -Wno=101 gdlltest.f90 -B c:\c95\lib dpwin32.dll -o gDllTest.exe +(the -Wno=101 removes warnings about the EQUIVALENCE statement we have to use in the sample) diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/dlltest.f90 b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/dlltest.f90 new file mode 100644 index 0000000..28031db --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/dlltest.f90 @@ -0,0 +1,797 @@ +! dlltest - sample program to call DinkeyPro/FD runtime module (dpwin32.dll) +! +! this sample code has been compiled and tested using Lahey Fortran v7.2 + +! The sample code contains 10 functions. You will not need to use all these +! functions in your code. Just use which ever functions are most appropriate +! and customise in your own way. The sample code is just a guide. You should +! implement the protection in a stronger way using the techniques described in +! the "Increasing your Protection" chapter of the manual. + +!If you are using Dinkey Lite then you can only use 4 functions: +!ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + +! this file contains 10 protection-check functions. +! ProtCheck a standard protection check +! ProtCheckWithAlg a protection check & executing an algorithm +! WriteBytes a protection check & write data to the dongle +! ReadBytes a protection check & read data from the dongle +! EncryptUserData a protection check & encrypting data and then decrypting the data +! these functions are the same as the functions listed above but encrypting all parameters passed to our API +! ProtCheckEnc a standard protection check +! ProtCheckWithAlgEnc a protection check & executing an Algorithm +! WriteBytesEnc a protection check & write data to the dongle +! ReadBytesEnc a protection check & read data from the dongle +! EncryptUserDataEnc a protection check & encrypting data and then decrypting the data + +PROGRAM main + ! call the function(s) of your choice here + ! by default I have chosen a standard protection check + if (ProtCheck() == 0) then + print *,"It worked!" + end if +END PROGRAM main + +! this module contains the DRIS structure declaration and also declares important constants +MODULE DinkeyPro + + integer,parameter :: MY_SDSN = 10101 !!!! change this value to be the value of your SDSN (demo = 10101) + + ! declare dris data type + TYPE DRIS + sequence + ! the first 4 fields are never encrypted + character(len=4) :: header ! should be set to 'DRIS' + ! inputs + integer(4) :: size ! size of this structure + integer(4) :: seed1 ! seed for data/dris encryption + integer(4) :: seed2 ! as above + ! (maybe encrypted from now on) + integer(4) :: function ! specify only one function + integer(4) :: flags ! options for the function selected. To use more than one OR them together e.g. OR(OPTION1, OPTION2) + integer(4) :: execs_decrement ! amount by which to dec execs if we use flag: DEC_MANY_EXECS + integer(4) :: data_crypt_key_num ! number of the key (1-3) that the dongle uses to encrypt or decrypt user data + integer(4) :: rw_offset ! offset in the dongle data area to read or write data + integer(4) :: rw_length ! length of data are to read/write/encrypt/decrypt + integer(4) :: unused ! pass data by function parameter instead. This field should be 8 bytes long for 64-bit Fortran code + character(len=256) :: alt_licence_name ! protection check for different licence instead of the default one, must be null-terminated + integer(4) :: var_a ! variable values for user algorithm + integer(4) :: var_b + integer(4) :: var_c + integer(4) :: var_d + integer(4) :: var_e + integer(4) :: var_f + integer(4) :: var_g + integer(4) :: var_h + integer(4) :: alg_number ! the number of the user algorithm that you want to execute + + ! outputs + integer(4) :: ret_code ! return code from the protection check + integer(4) :: ext_err ! extended error + integer(4) :: type ! type of dongle detected. 1 = Pro, 2 = FD + integer(4) :: model ! model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + integer(4) :: sdsn ! Software Developer's Serial Number + character(len=12) :: prodcode ! Product Code (null-terminated) + integer(4) :: dongle_number ! NB this should be an unsigned value really + integer(4) :: update_number + integer(4) :: data_area_size ! size of the data area used in the dongle detected + integer(4) :: max_alg_num ! the maximum algorithm number in the dongle detected + integer(4) :: execs ! executions left: -1 indicates 'no limit' + integer(4) :: exp_day ! expiry day: -1 indicates 'no limit' + integer(4) :: exp_month ! expiry month: -1 indicates 'no limit' + integer(4) :: exp_year ! expiry year: -1 indicates 'no limit' + integer(4) :: features ! features value + integer(4) :: net_users ! maximum number of network users for the dongle detected: -1 indicates 'no limit' + integer(4) :: alg_answer ! answer to the user algorithm executed with the given variable values + integer(4) :: fd_capacity ! capacity of the data area in FD dongle. + character(len=128) :: fd_drive ! drive letter of FD dongle detected e.g. 'f:\' (or mount name under Linux) + integer(4) :: swkey_type ! 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + integer(4) :: swkey_exp_day ! software key expiry date (if software key detected) + integer(4) :: swkey_exp_month + integer(4) :: swkey_exp_year + END TYPE DRIS + + integer,parameter :: DRIS_SIZE = 560 ! I am sure there should be a way to get this programatically! + + ! functions - must specify only one + integer,parameter :: PROTECTION_CHECK = 1 ! checks for dongle, check program params... + integer,parameter :: EXECUTE_ALGORITHM = 2 ! protection check + calculate answer for specified algorithm with specified inputs + integer,parameter :: WRITE_DATA_AREA = 3 ! protection check + writes dongle data area + integer,parameter :: READ_DATA_AREA = 4 ! protection check + reads dongle data area + integer,parameter :: ENCRYPT_USER_DATA = 5 ! protection check + the dongle will encrypt user data + integer,parameter :: DECRYPT_USER_DATA = 6 ! protection check + the dongle will decrypt user data + integer,parameter :: FAST_PRESENCE_CHECK = 7 ! checks for the presence of the correct dongle only with minimal security, no flags allowed. + integer,parameter :: STOP_NET_USER = 8 ! stops a network user (a protection check is NOT performed) + + ! flags - can specify as many as you like + integer,parameter :: DEC_ONE_EXEC = 1 ! decrement execs by 1 + integer,parameter :: DEC_MANY_EXECS = 2 ! decrement execs by number specified in execs_decrement + integer,parameter :: START_NET_USER = 4 ! starts a network user + integer,parameter :: STOP_NET_USER = 8 ! stops a network user (a protection check is NOT performed) + integer,parameter :: USE_FUNCTION_ARGUMENT = 16 ! use the extra argument in the function for pointers + integer,parameter :: CHECK_LOCAL_FIRST = 32 ! always look in local ports before looking in network ports + integer,parameter :: CHECK_NETWORK_FIRST = 64 ! always look on the network before looking in local ports + integer,parameter :: USE_ALT_LICENCE_NAME = 128 ! use name specified in alt_licence_name instead of this program name + integer,parameter :: DONT_SET_MAXDAYS_EXPIRY = 256 ! if the max days expiry date has not been calculated then do not do it this time + integer,parameter :: MATCH_DONGLE_NUMBER = 512 ! restrict the search to match the dongle number specified in the DRIS + integer,parameter :: DONT_RETURN_FD_DRIVE = 1024 ! if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + + ! declare the protection check function in the Dinkey Pro/FD runtime module + DLL_IMPORT DDProtCheck + type (DRIS) mydris + integer DDProtCheck + +END MODULE DinkeyPro + +! ************************* our 10 functions ********************************** + +! ************************** ProtCheck *************************************** +FUNCTION ProtCheck() + use DinkeyPro + integer :: ret_code + + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = PROTECTION_CHECK ! standard protection check + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + ret_code = DDProtCheck(mydris, 0) + ProtCheck = ret_code + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn <> MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheck = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code <> 0) then + print *,"Dinkey Dongle protection error." + ProtCheck = -1 + return + end if + + ! sample to show how to display dongle number (this is the only value in the dris that should be an unsigned integer) + integer(8) :: display_dongle_number + display_dongle_number = mydris%dongle_number + call ConvertDongleNumber(display_dongle_number) + print *,"Dongle Check successful. Dongle Number is: ",display_dongle_number +END FUNCTION ProtCheck + +! ************************** ProtCheckWithAlg ****************************** + +! !!!! You should replace this function with the one generated by the +! "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) +! or from DinkeyLook if you are using a Dinkey Lite dongle. +FUNCTION MyAlgorithm(a, b, c, d, e, f, g, h) + integer :: a,b,c,d,e,f,g,h,MyAlgorithm + MyAlgorithm = a + b + c + d + e + f + g + h + return +END FUNCTION MyAlgorithm + +! NB for this to work you must program at least "user algorithm" into the dongle +! NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +! sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +! code from DinkeyLook +FUNCTION ProtCheckWithAlg() + use DinkeyPro + integer :: ret_code + + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = EXECUTE_ALGORITHM ! standard protection check & execute algorithm + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + mydris%alg_number = 1 ! execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + ! you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + mydris%var_a = 1 ! sample values + mydris%var_b = 2 + mydris%var_c = 3 + mydris%var_d = 4 + mydris%var_e = 5 + mydris%var_f = 6 + mydris%var_g = 7 + mydris%var_h = 8 + + ret_code = DDProtCheck(mydris, 0) + ProtCheckWithAlg = ret_code + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn <> MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheckWithAlg = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code <> 0) then + print *,"Dinkey Dongle protection error." + ProtCheckWithAlg = -1 + return + end if + + ! if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + ! !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) <> mydris%alg_answer) then + print *,"Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine" + ProtCheckWithAlg = -1 + return + end if +END FUNCTION ProtCheckWithAlg + +! ************************** WriteBytes *************************************** +! This writes the Data "Hello, World" to the dongle data area at offset 7 +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +FUNCTION WriteBytes() + use DinkeyPro + integer :: ret_code + character(len=*),parameter :: WriteData = "Hello, World!" + + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = WRITE_DATA_AREA ! standard protection check and write data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(WriteData) + + ret_code = DDProtCheck(mydris, WriteData) + WriteBytes = ret_code + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn <> MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + WriteBytes = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code <> 0) then + print *,"Dinkey Dongle protection error." + WriteBytes = -1 + return + end if +END FUNCTION WriteBytes + +! ************************** ReadBytes *************************************** +! This reads 14 bytes of data from offset 7 in the dongle data area +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +! In order for the data to be displayed properly by this routine it will need to be text data +FUNCTION ReadBytes() + use DinkeyPro + integer :: ret_code + character(len=14) :: ReadData + + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = READ_DATA_AREA ! standard protection check and read data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(ReadData) + + ret_code = DDProtCheck(mydris, ReadData) + ReadBytes = ret_code + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn <> MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ReadBytes = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code <> 0) then + print *,"Dinkey Dongle protection error." + ReadBytes = -1 + return + end if + + print *,"Dinkey Dongle Data area, offset 7 is: ",ReadData +END FUNCTION ReadBytes + +! ************************** EncryptUserData *************************************** +! This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +! It will then do another protection check & decrypt the data +FUNCTION EncryptUserData() + use DinkeyPro + integer :: ret_code + character(len=13) :: Data = "Hello, World!" + + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = ENCRYPT_USER_DATA ! standard protection check and encrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(Data) + + ret_code = DDProtCheck(mydris, Data) + EncryptUserData = ret_code + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + ! ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + print *,"Encrypted data is: ",Data + + ! Now decrypt the same data to get the original values + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = DECRYPT_USER_DATA ! standard protection check and decrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(Data) + + ret_code = DDProtCheck(mydris, Data) + EncryptUserData = ret_code + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn <> MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + EncryptUserData = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code <> 0) then + print *,"Dinkey Dongle protection error." + EncryptUserData = -1 + return + end if + + print *,"Decrypted data is: ",Data +END FUNCTION EncryptUserData + +! !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! +! In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" +! in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm +! but the code can be modified easily to use the 3 encryption parameters. + +! !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm +FUNCTION MyRWAlgorithm(a, b, c, d, e, f, g, h) + integer :: a,b,c,d,e,f,g,h,MyAlgorithm + MyRWAlgorithm = IEOR(IEOR(IEOR(IEOR(IEOR(a,b),c),d),e),f) + return +END FUNCTION MyRWAlgorithm + +! !!!! please patch the 3 parameters specified below with the 3 parameters specified in DinkeyAdd +SUBROUTINE CryptDRIS(dris_byte_array) + use DinkeyPro + integer(1), dimension(DRIS_SIZE) :: dris_byte_array + integer :: i,j,k,temp,t + integer, dimension(256) :: bigseed,S + + do i=1,256 + bigseed(i) = dris_byte_array(9 + modulo(i-1,8)) ! this takes the values from seed1, seed2 directly + end do + + do i=1,256 + S(i) = i-1 + end do + + j = 0 + do i=1,256 + j = IAND(j + S(i) + bigseed(i) + 123, 255) ! first parameter patched here + temp = S(i) + S(i) = S(j+1) + S(j+1) = temp + end do + + i = 0 + j = 0 + do k=17,DRIS_SIZE + i = IAND(i + 1, 255) + j = IAND(j + S(i+1) + 212, 255) ! second parameter patched here + temp = S(i+1) + S(i+1) = S(j+1) + S(j+1) = temp + t = IAND(S(i+1) + S(j+1) + 97,255) ! third parameter patched here + dris_byte_array(k) = IEOR(dris_byte_array(k),S(t+1)) + end do + return +END SUBROUTINE CryptDRIS + +! !!!! please patch the 3 parameters specified below with the 3 parameters specified in DinkeyAdd +! if you are using the r/w algorithm then there is no need to change this function +! NB we pass the whole of the DRIS but we only need it for seed1 and seed2 values +SUBROUTINE CryptApiData(data, length, dris_byte_array, alg_answer) + use DinkeyPro + integer :: length, alg_answer, seed1, seed2 + integer(1), dimension(length) :: data + integer(1), dimension(DRIS_SIZE) :: dris_byte_array + integer :: i,j,k,temp,t + integer, dimension(256) :: bigseed,S + + do i=1,256 + bigseed(i) = dris_byte_array(9 + modulo(i-1,8)) ! this takes the values from seed1, seed2 directly + end do + + do i=1,256 + S(i) = i-1 + end do + + j = 0 + do i=1,256 + j = IAND(j + S(i) + bigseed(i) + IAND(alg_answer, 255), 255) ! first parameter patched here + temp = S(i) + S(i) = S(j+1) + S(j+1) = temp + end do + + i = 0 + j = 0 + do k=1,length + i = IAND(i + 1, 255) + j = IAND(j + S(i+1) + IAND(ISHFT(alg_answer, -8),255), 255) ! second parameter patched here + temp = S(i+1) + S(i+1) = S(j+1) + S(j+1) = temp + t = IAND(S(i+1) + S(j+1) + IAND(ISHFT(alg_answer, -16),255),255) ! third parameter patched here + data(k) = IEOR(data(k),S(t+1)) + end do + return +END SUBROUTINE CryptApiData + +! ************************** ProtCheckEnc *************************************** +! We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +FUNCTION ProtCheckEnc() + use DinkeyPro + integer :: ret_code + + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = PROTECTION_CHECK ! standard protection check + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + call CryptDRIS(mydris) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, 0) + ProtCheckEnc = ret_code + + call CryptDRIS(mydris) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn <> MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheckEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code <> 0) then + print *,"Dinkey Dongle protection error." + ProtCheckEnc = -1 + return + end if +END FUNCTION ProtCheckEnc + +! ************************** ProtCheckWithAlgEnc ****************************** +! NB for this to work you must program at least "user algorithm" into the dongle +! NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +! sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +! code from DinkeyLook +! We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +FUNCTION ProtCheckWithAlgEnc() + use DinkeyPro + integer :: ret_code + + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = EXECUTE_ALGORITHM ! standard protection check & execute algorithm + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + mydris%alg_number = 1 ! execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + ! you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + mydris%var_a = 1 ! sample values + mydris%var_b = 2 + mydris%var_c = 3 + mydris%var_d = 4 + mydris%var_e = 5 + mydris%var_f = 6 + mydris%var_g = 7 + mydris%var_h = 8 + + call CryptDRIS(mydris) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, 0) + ProtCheckWithAlgEnc = ret_code + + call CryptDRIS(mydris) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn <> MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheckWithAlgEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code <> 0) then + print *,"Dinkey Dongle protection error." + ProtCheckWithAlgEnc = -1 + return + end if + + ! if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + ! !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) <> mydris%alg_answer) then + print *,"Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine" + ProtCheckWithAlgEnc = -1 + return + end if +END FUNCTION ProtCheckWithAlgEnc + +! ************************** WriteBytesEnc *************************************** +! This writes the Data "Hello, World" to the dongle data area at offset 7 +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +! We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +FUNCTION WriteBytesEnc() + use DinkeyPro + integer :: ret_code,alg_ans + character(len=*),parameter :: WriteData = "Hello, World!" + + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = WRITE_DATA_AREA ! standard protection check and write data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(WriteData) + + ! calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) + + ! encrypt data we want to write. + call CryptApiData(WriteData, len(WriteData), mydris, alg_ans); + + call CryptDRIS(mydris) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, WriteData) + WriteBytesEnc = ret_code + + call CryptDRIS(mydris) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn <> MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + WriteBytesEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code <> 0) then + print *,"Dinkey Dongle protection error." + WriteBytesEnc = -1 + return + end if +END FUNCTION WriteBytesEnc + +! ************************** ReadBytesEnc *************************************** +! This reads 14 bytes of data from offset 7 in the dongle data area +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +! In order for the data to be displayed properly by this routine it will need to be text data +! We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +FUNCTION ReadBytesEnc() + use DinkeyPro + integer :: ret_code,alg_ans + character(len=14) :: ReadData + + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = READ_DATA_AREA ! standard protection check and read data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(ReadData) + + ! calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) + + call CryptDRIS(mydris) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, ReadData) + ReadBytesEnc = ret_code + + call CryptDRIS(mydris) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn <> MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ReadBytesEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code <> 0) then + print *,"Dinkey Dongle protection error." + ReadBytesEnc = -1 + return + end if + + ! decrypt data we have just read. + call CryptApiData(ReadData, len(ReadData), mydris, alg_ans); + print *,"Dinkey Dongle Data area, offset 7 is: ",ReadData +END FUNCTION ReadBytesEnc + +! ************************** EncryptUserDataEnc *************************************** +! This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +! It will then do another protection check & decrypt the data +! We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +FUNCTION EncryptUserDataEnc() + use DinkeyPro + integer :: ret_code,alg_ans + character(len=13) :: Data = "Hello, World!" + + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = ENCRYPT_USER_DATA ! standard protection check and encrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(Data) + + ! calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) + + ! encrypt data we want to pass. + call CryptApiData(Data, len(Data), mydris, alg_ans); + + call CryptDRIS(mydris) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, Data) + EncryptUserDataEnc = ret_code + + call CryptDRIS(mydris) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + ! ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + print *,"Encrypted data is: ",Data + + ! Now decrypt the same data to get the original values + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = DECRYPT_USER_DATA ! standard protection check and decrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(Data) + + call CryptDRIS(mydris) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, Data) + EncryptUserDataEnc = ret_code + + call CryptDRIS(mydris) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn <> MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + EncryptUserDataEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code <> 0) then + print *,"Dinkey Dongle protection error." + EncryptUserDataEnc = -1 + return + end if + + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) + ! decrypt data that was passed to us by the API. + call CryptApiData(Data, len(Data), mydris, alg_ans); + print *,"Decrypted data is: ",Data +END FUNCTION EncryptUserDataEnc + + +! ************************** useful subroutines ******************************* +! subroutine to randomise each element of the DRIS +SUBROUTINE set_random(dris_byte_array) + use DinkeyPro + integer(1), dimension(DRIS_SIZE) :: dris_byte_array + real,dimension(DRIS_SIZE) :: temp + + call random_seed() + call random_number(temp) + do i=1,DRIS_SIZE + dris_byte_array(i) = temp(i)*256 + end do + return +END SUBROUTINE set_random + +! subroutine to convert an unsigned integer (stored as a signed integer) to the correct unsigned value (for display purposes) +! e.g. the dongle_number value in the dris - should be an unsigned integer but Fortran 90 does not support them +SUBROUTINE ConvertDongleNumber(value) + integer(8) :: value + + if (value < 0) then + value = value + 4294967296 ! make the -ve value a +ve value + end if + return +END SUBROUTINE ConvertDongleNumber + +! displays messages for the most common errors. You will want to change this for your code +SUBROUTINE DisplayError(ret_code, extended_error) + integer :: ret_code, extended_error + + select case (ret_code) + case (401) + print *,"Error! No dongles detected!" + case (403) + print *,"Error! The dongle detected has a different type to the one specified in DinkeyAdd." + case (404) + print *,"Error! The dongle detected has a different model to those specified in DinkeyAdd." + case (409) + print *,"Error! The dongle detected has not been programmed by DinkeyAdd." + case (410) + print *,"Error! The dongle detected has a different Product Code to the one specified in DinkeyAdd." + case (411) + print *,"Error! The dongle detected does not contain the licence associated with this program." + case (413) + print *,"Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual." + case (417) + print *,"Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa." + case (423) + print *,"Error! The number of network users has been exceeded." + case (435) + print *,"Error! DinkeyServer has not been detected on the network." + case (922) + print *,"Error! The Software Key has expired." + case default + print *,"An error occurred checking the dongle. Error: ", ret_code, " Extended Error: ", extended_error + end select + return +END SUBROUTINE DisplayError \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/gdlltest.f90 b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/gdlltest.f90 new file mode 100644 index 0000000..96f383a --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/gdlltest.f90 @@ -0,0 +1,862 @@ +! dlltest - sample program to call DinkeyPro/FD runtime module (dpwin32.dll) +! +! this sample code has been compiled and tested using g95. It should also work for GFortran +! but this has not been tested + +! The sample code contains 10 functions. You will not need to use all these +! functions in your code. Just use which ever functions are most appropriate +! and customise in your own way. The sample code is just a guide. You should +! implement the protection in a stronger way using the techniques described in +! the "Increasing your Protection" chapter of the manual. + +!If you are using Dinkey Lite then you can only use 4 functions: +!ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + +! this file contains 10 protection-check functions. +! ProtCheck a standard protection check +! ProtCheckWithAlg a protection check & executing an algorithm +! WriteBytes a protection check & write data to the dongle +! ReadBytes a protection check & read data from the dongle +! EncryptUserData a protection check & encrypting data and then decrypting the data +! these functions are the same as the functions listed above but encrypting all parameters passed to our API +! ProtCheckEnc a standard protection check +! ProtCheckWithAlgEnc a protection check & executing an Algorithm +! WriteBytesEnc a protection check & write data to the dongle +! ReadBytesEnc a protection check & read data from the dongle +! EncryptUserDataEnc a protection check & encrypting data and then decrypting the data + +PROGRAM main + ! call the function(s) of your choice here + ! by default I have chosen a standard protection check + if (ProtCheck() == 0) then + print *,"It worked!" + end if +END PROGRAM main + +! this module contains the DRIS structure declaration and also declares important constants +MODULE DinkeyPro + + integer,parameter :: MY_SDSN = 10101 !!!! change this value to be the value of your SDSN (demo = 10101) + + ! declare dris data type + ! It would be nice if there were a compiler directive ensuring byte alignment for this type. I can't find one but it seems to be byte aligned anyway ;) + TYPE DRIS + sequence + ! the first 4 fields are never encrypted + character(len=4) :: header ! should be set to 'DRIS' + ! inputs + integer(4) :: size ! size of this structure + integer(4) :: seed1 ! seed for data/dris encryption + integer(4) :: seed2 ! as above + ! (maybe encrypted from now on) + integer(4) :: function ! specify only one function + integer(4) :: flags ! options for the function selected. To use more than one OR them together e.g. OR(OPTION1, OPTION2) + integer(4) :: execs_decrement ! amount by which to dec execs if we use flag: DEC_MANY_EXECS + integer(4) :: data_crypt_key_num ! number of the key (1-3) that the dongle uses to encrypt or decrypt user data + integer(4) :: rw_offset ! offset in the dongle data area to read or write data + integer(4) :: rw_length ! length of data are to read/write/encrypt/decrypt + integer(4) :: unused ! pass data by function parameter instead. 4 bytes long for 32-bit Fortran code. + character(len=256) :: alt_licence_name ! protection check for different licence instead of the default one, must be null-terminated + integer(4) :: var_a ! variable values for user algorithm + integer(4) :: var_b + integer(4) :: var_c + integer(4) :: var_d + integer(4) :: var_e + integer(4) :: var_f + integer(4) :: var_g + integer(4) :: var_h + integer(4) :: alg_number ! the number of the user algorithm that you want to execute + + ! outputs + integer(4) :: ret_code ! return code from the protection check + integer(4) :: ext_err ! extended error + integer(4) :: type ! type of dongle detected. 1 = Pro, 2 = FD + integer(4) :: model ! model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + integer(4) :: sdsn ! Software Developer's Serial Number + character(len=12) :: prodcode ! Product Code (null-terminated) + integer(4) :: dongle_number ! NB this should be an unsigned value really + integer(4) :: update_number + integer(4) :: data_area_size ! size of the data area used in the dongle detected + integer(4) :: max_alg_num ! the maximum algorithm number in the dongle detected + integer(4) :: execs ! executions left: -1 indicates 'no limit' + integer(4) :: exp_day ! expiry day: -1 indicates 'no limit' + integer(4) :: exp_month ! expiry month: -1 indicates 'no limit' + integer(4) :: exp_year ! expiry year: -1 indicates 'no limit' + integer(4) :: features ! features value + integer(4) :: net_users ! maximum number of network users for the dongle detected: -1 indicates 'no limit' + integer(4) :: alg_answer ! answer to the user algorithm executed with the given variable values + integer(4) :: fd_capacity ! capacity of the data area in FD dongle. + character(len=128) :: fd_drive ! drive letter of FD dongle detected e.g. 'f:\' (or mount name under Linux) + integer(4) :: swkey_type ! 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + integer(4) :: swkey_exp_day ! software key expiry date (if software key detected) + integer(4) :: swkey_exp_month + integer(4) :: swkey_exp_year + END TYPE DRIS + + integer,parameter :: DRIS_SIZE = 560 ! I am sure there should be a way to get this programatically! + + ! functions - must specify only one + integer,parameter :: PROTECTION_CHECK = 1 ! checks for dongle, check program params... + integer,parameter :: EXECUTE_ALGORITHM = 2 ! protection check + calculate answer for specified algorithm with specified inputs + integer,parameter :: WRITE_DATA_AREA = 3 ! protection check + writes dongle data area + integer,parameter :: READ_DATA_AREA = 4 ! protection check + reads dongle data area + integer,parameter :: ENCRYPT_USER_DATA = 5 ! protection check + the dongle will encrypt user data + integer,parameter :: DECRYPT_USER_DATA = 6 ! protection check + the dongle will decrypt user data + integer,parameter :: FAST_PRESENCE_CHECK = 7 ! checks for the presence of the correct dongle only with minimal security, no flags allowed. + integer,parameter :: STOP_NET_USER = 8 ! stops a network user (a protection check is NOT performed) + + ! flags - can specify as many as you like + integer,parameter :: DEC_ONE_EXEC = 1 ! decrement execs by 1 + integer,parameter :: DEC_MANY_EXECS = 2 ! decrement execs by number specified in execs_decrement + integer,parameter :: START_NET_USER = 4 ! starts a network user + integer,parameter :: USE_FUNCTION_ARGUMENT = 16 ! use the extra argument in the function for pointers + integer,parameter :: CHECK_LOCAL_FIRST = 32 ! always look in local ports before looking in network ports + integer,parameter :: CHECK_NETWORK_FIRST = 64 ! always look on the network before looking in local ports + integer,parameter :: USE_ALT_LICENCE_NAME = 128 ! use name specified in alt_licence_name instead of the default one + integer,parameter :: DONT_SET_MAXDAYS_EXPIRY = 256 ! if the max days expiry date has not been calculated then do not do it this time + integer,parameter :: MATCH_DONGLE_NUMBER = 512 ! restrict the search to match the dongle number specified in the DRIS + integer,parameter :: DONT_RETURN_FD_DRIVE = 1024 ! if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + + ! this is an instance of the dris. We make an equivalence between the derived-type + ! and a byte_array because for encryption we need to access the memory as a byte array + type (DRIS) :: mydris + integer(1), dimension(DRIS_SIZE) :: mydris_byte_array + equivalence(mydris, mydris_byte_array) + +END MODULE DinkeyPro + +! There is just the one function exported by dpwin32.dll +MODULE DDFunctions + use ISO_C_BINDING + implicit none + private + + ! declare the protection check function in the Dinkey Pro/FD runtime module + public DDProtCheck + INTERFACE + FUNCTION DDProtCheck(my_dris, my_data) BIND (C, name="DDProtCheck") + use iso_c_binding + use DinkeyPro +!GCC$ ATTRIBUTES STDCALL :: DDProtCheck + integer(C_INT) DDProtCheck + type (DRIS) my_dris + character(kind=C_CHAR) my_data (*) + END FUNCTION DDProtCheck + END INTERFACE +END MODULE DDFunctions + +! ************************* our 10 functions ********************************** + +! ************************** ProtCheck *************************************** +FUNCTION ProtCheck() + use DinkeyPro + use DDFunctions + integer :: ret_code + integer(8) :: display_dongle_number + + call set_random(mydris_byte_array) ! we have to call this function using the byte array equivalence of the dris type + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = PROTECTION_CHECK ! standard protection check + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + ret_code = DDProtCheck(mydris, "dummy") + ProtCheck = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheck = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ProtCheck = -1 + return + end if + + ! sample to show how to display dongle number (this is the only value in the dris that should be an unsigned integer) + display_dongle_number = mydris%dongle_number + call ConvertDongleNumber(display_dongle_number) + print *,"Dongle Check successful. Dongle Number is: ",display_dongle_number +END FUNCTION ProtCheck + +! ************************** ProtCheckWithAlg ****************************** + +! !!!! You should replace this function with the one generated by the +! "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) +! or from DinkeyLook if you are using a Dinkey Lite dongle. +FUNCTION MyAlgorithm(a, b, c, d, e, f, g, h) + integer :: a,b,c,d,e,f,g,h,MyAlgorithm + MyAlgorithm = a + b + c + d + e + f + g + h + return +END FUNCTION MyAlgorithm + +! NB for this to work you must program at least "user algorithm" into the dongle +! NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +! sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +! code from DinkeyLook +FUNCTION ProtCheckWithAlg() + use DinkeyPro + use DDFunctions + integer :: ret_code, my_alg_answer, a, b, c, d, e, f, g, h + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = EXECUTE_ALGORITHM ! standard protection check & execute algorithm + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + mydris%alg_number = 1 ! execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + ! you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + mydris%var_a = 1 ! sample values + mydris%var_b = 2 + mydris%var_c = 3 + mydris%var_d = 4 + mydris%var_e = 5 + mydris%var_f = 6 + mydris%var_g = 7 + mydris%var_h = 8 + + ret_code = DDProtCheck(mydris, "dummy") + ProtCheckWithAlg = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheckWithAlg = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ProtCheckWithAlg = -1 + return + end if + + ! if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + ! !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + a = mydris%var_a ! for some reason g95 does not execute MyAlgorithm correctly unless it is all on one line so you have to do stupid things like this + b = mydris%var_b + c = mydris%var_c + d = mydris%var_d + e = mydris%var_e + f = mydris%var_f + g = mydris%var_g + h = mydris%var_h + my_alg_answer = MyAlgorithm(a, b, c, d, e, f, g, h) + if (my_alg_answer /= mydris%alg_answer) then + print *,"Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine" + ProtCheckWithAlg = -1 + return + end if +END FUNCTION ProtCheckWithAlg + +! ************************** WriteBytes *************************************** +! This writes the Data "Hello, World" to the dongle data area at offset 7 +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +FUNCTION WriteBytes() + use DinkeyPro + use DDFunctions + integer :: ret_code + character(len=14) :: WriteData = "Hello, World!"//CHAR(0) ! it should be a null-terminated string + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = WRITE_DATA_AREA ! standard protection check and write data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(WriteData) + + ret_code = DDProtCheck(mydris, WriteData) + WriteBytes = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + WriteBytes = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + WriteBytes = -1 + return + end if +END FUNCTION WriteBytes + +! ************************** ReadBytes *************************************** +! This reads 14 bytes of data from offset 7 in the dongle data area +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +! In order for the data to be displayed properly by this routine it will need to be text data +FUNCTION ReadBytes() + use DinkeyPro + use DDFunctions + integer :: ret_code + character(len=14) :: ReadData + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = READ_DATA_AREA ! standard protection check and read data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(ReadData) + + ret_code = DDProtCheck(mydris, ReadData) + ReadBytes = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ReadBytes = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ReadBytes = -1 + return + end if + + print *,"Dinkey Dongle Data area, offset 7 is: ",ReadData +END FUNCTION ReadBytes + +! ************************** EncryptUserData *************************************** +! This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +! It will then do another protection check & decrypt the data +FUNCTION EncryptUserData() + use DinkeyPro + use DDFunctions + integer :: ret_code + character(len=14) :: MyData = "Hello, World!"//CHAR(0) + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = ENCRYPT_USER_DATA ! standard protection check and encrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(MyData) + + ret_code = DDProtCheck(mydris, MyData) + EncryptUserData = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + ! ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + print *,"Encrypted data is: ",MyData + + ! Now decrypt the same data to get the original values + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = DECRYPT_USER_DATA ! standard protection check and decrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(MyData) + + ret_code = DDProtCheck(mydris, MyData) + EncryptUserData = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + EncryptUserData = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + EncryptUserData = -1 + return + end if + + print *,"Decrypted data is: ",MyData +END FUNCTION EncryptUserData + +! !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! +! In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" +! in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm +! but the code can be modified easily to use the 3 encryption parameters. + +! !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm +FUNCTION MyRWAlgorithm(a, b, c, d, e, f, g, h) + integer :: a,b,c,d,e,f,g,h,MyAlgorithm + MyRWAlgorithm = IEOR(IEOR(IEOR(IEOR(IEOR(a,b),c),d),e),f) + return +END FUNCTION MyRWAlgorithm + +! !!!! please patch the 3 parameters specified below with the 3 parameters specified in DinkeyAdd +SUBROUTINE CryptDRIS(dris_byte_array) + use DinkeyPro + integer(1), dimension(DRIS_SIZE) :: dris_byte_array + integer :: i,j,k,temp,t + integer(1) :: temp2 + integer, dimension(256) :: bigseed,S + + do i=1,256 + bigseed(i) = dris_byte_array(9 + modulo(i-1,8)) ! this takes the values from seed1, seed2 directly + end do + + do i=1,256 + S(i) = i-1 + end do + + j = 0 + do i=1,256 + j = IAND(j + S(i) + bigseed(i) + 123, 255) ! first parameter patched here + temp = S(i) + S(i) = S(j+1) + S(j+1) = temp + end do + + i = 0 + j = 0 + do k=17,DRIS_SIZE + i = IAND(i + 1, 255) + j = IAND(j + S(i+1) + 212, 255) ! second parameter patched here + temp = S(i+1) + S(i+1) = S(j+1) + S(j+1) = temp + t = IAND(S(i+1) + S(j+1) + 97,255) ! third parameter patched here + temp2 = S(t+1) + dris_byte_array(k) = IEOR(dris_byte_array(k),temp2) + end do + return +END SUBROUTINE CryptDRIS + +! !!!! please patch the 3 parameters specified below with the 3 parameters specified in DinkeyAdd +! if you are using the r/w algorithm then there is no need to change this function +! NB we pass the whole of the DRIS but we only need it for seed1 and seed2 values +SUBROUTINE CryptApiData(mydata, length, dris_byte_array, alg_answer) + use DinkeyPro + integer :: length, alg_answer, seed1, seed2 + integer(1), dimension(length) :: mydata + integer(1), dimension(DRIS_SIZE) :: dris_byte_array + integer(1) :: temp2 + integer :: i,j,k,temp,t + integer, dimension(256) :: bigseed,S + + do i=1,256 + bigseed(i) = dris_byte_array(9 + modulo(i-1,8)) ! this takes the values from seed1, seed2 directly + end do + + do i=1,256 + S(i) = i-1 + end do + + j = 0 + do i=1,256 + j = IAND(j + S(i) + bigseed(i) + IAND(alg_answer, 255), 255) ! first parameter patched here + temp = S(i) + S(i) = S(j+1) + S(j+1) = temp + end do + + i = 0 + j = 0 + do k=1,length + i = IAND(i + 1, 255) + j = IAND(j + S(i+1) + IAND(ISHFT(alg_answer, -8),255), 255) ! second parameter patched here + temp = S(i+1) + S(i+1) = S(j+1) + S(j+1) = temp + t = IAND(S(i+1) + S(j+1) + IAND(ISHFT(alg_answer, -16),255),255) ! third parameter patched here + temp2 = S(t+1) + mydata(k) = IEOR(mydata(k),temp2) + end do + return +END SUBROUTINE CryptApiData + +! ************************** ProtCheckEnc *************************************** +! We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +FUNCTION ProtCheckEnc() + use DinkeyPro + use DDFunctions + integer :: ret_code + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = PROTECTION_CHECK ! standard protection check + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, "dummy") + ProtCheckEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheckEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ProtCheckEnc = -1 + return + end if +END FUNCTION ProtCheckEnc + +! ************************** ProtCheckWithAlgEnc ****************************** +! NB for this to work you must program at least "user algorithm" into the dongle +! NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +! sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +! code from DinkeyLook +! We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +FUNCTION ProtCheckWithAlgEnc() + use DinkeyPro + use DDFunctions + integer :: ret_code, my_alg_answer, a, b, c, d, e, f, g, h + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = EXECUTE_ALGORITHM ! standard protection check & execute algorithm + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + mydris%alg_number = 1 ! execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + ! you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + mydris%var_a = 1 ! sample values + mydris%var_b = 2 + mydris%var_c = 3 + mydris%var_d = 4 + mydris%var_e = 5 + mydris%var_f = 6 + mydris%var_g = 7 + mydris%var_h = 8 + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, "dummy") + ProtCheckWithAlgEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheckWithAlgEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ProtCheckWithAlgEnc = -1 + return + end if + + ! if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + ! !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + a = mydris%var_a ! for some reason g95 does not execute MyAlgorithm correctly unless it is all on one line so you have to do stupid things like this + b = mydris%var_b + c = mydris%var_c + d = mydris%var_d + e = mydris%var_e + f = mydris%var_f + g = mydris%var_g + h = mydris%var_h + my_alg_answer = MyAlgorithm(a, b, c, d, e, f, g, h) + if (my_alg_answer /= mydris%alg_answer) then + print *,"Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine" + ProtCheckWithAlgEnc = -1 + return + end if +END FUNCTION ProtCheckWithAlgEnc + +! ************************** WriteBytesEnc *************************************** +! This writes the Data "Hello, World" to the dongle data area at offset 7 +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +! We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +FUNCTION WriteBytesEnc() + use DinkeyPro + use DDFunctions + integer :: ret_code,alg_ans + character(len=14) :: WriteData = "Hello, World!"//CHAR(0) + integer(1), dimension(14) :: WriteDataByteArray + equivalence(WriteData, WriteDataByteArray) ! to encrypt it we need to pass it as a byte array + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = WRITE_DATA_AREA ! standard protection check and write data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(WriteData) + + ! calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g,& + mydris%var_h) + + ! encrypt data we want to write. + call CryptApiData(WriteDataByteArray, len(WriteData), mydris_byte_array, alg_ans); + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, WriteData) + WriteBytesEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + WriteBytesEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + WriteBytesEnc = -1 + return + end if +END FUNCTION WriteBytesEnc + +! ************************** ReadBytesEnc *************************************** +! This reads 14 bytes of data from offset 7 in the dongle data area +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +! In order for the data to be displayed properly by this routine it will need to be text data +! We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +FUNCTION ReadBytesEnc() + use DinkeyPro + use DDFunctions + integer :: ret_code,alg_ans + character(len=14) :: ReadData + integer(1), dimension(14) :: ReadDataByteArray + equivalence(ReadData, ReadDataByteArray) ! to encrypt it we need to pass it as a byte array + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = READ_DATA_AREA ! standard protection check and read data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(ReadData) + + ! calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g,& + mydris%var_h) + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, ReadData) + ReadBytesEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ReadBytesEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ReadBytesEnc = -1 + return + end if + + ! decrypt data we have just read. + call CryptApiData(ReadDataByteArray, len(ReadData), mydris_byte_array, alg_ans); + print *,"Dinkey Dongle Data area, offset 7 is: ",ReadData +END FUNCTION ReadBytesEnc + +! ************************** EncryptUserDataEnc *************************************** +! This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +! It will then do another protection check & decrypt the data +! We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +FUNCTION EncryptUserDataEnc() + use DinkeyPro + use DDFunctions + integer :: ret_code,alg_ans + character(len=14) :: MyData = "Hello, World!"//CHAR(0) + integer(1), dimension(14) :: MyDataByteArray + equivalence(MyData, MyDataByteArray) ! to encrypt it we need to pass it as a byte array + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = ENCRYPT_USER_DATA ! standard protection check and encrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(MyData) + + ! calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g,& + mydris%var_h) + + ! encrypt data we want to pass. + call CryptApiData(MyDataByteArray, len(MyData), mydris_byte_array, alg_ans); + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, MyData) + EncryptUserDataEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + ! ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + print *,"Encrypted data is: ",MyData + + ! Now decrypt the same data to get the original values + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = DECRYPT_USER_DATA ! standard protection check and decrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(MyData) + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, MyData) + EncryptUserDataEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + EncryptUserDataEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + EncryptUserDataEnc = -1 + return + end if + + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g,& + mydris%var_h) + ! decrypt data that was passed to us by the API. + call CryptApiData(MyDataByteArray, len(MyData), mydris_byte_array, alg_ans); + print *,"Decrypted data is: ",MyData +END FUNCTION EncryptUserDataEnc + +! ************************** useful subroutines ******************************* +! subroutine to randomise each element of the DRIS (expects you to pass the DRIS as a byte array +SUBROUTINE set_random(dris_byte_array) + use DinkeyPro + integer(1), dimension(DRIS_SIZE) :: dris_byte_array + real,dimension(DRIS_SIZE) :: temp + + call random_seed() + call random_number(temp) + do i=1,DRIS_SIZE + dris_byte_array(i) = temp(i)*256 + end do + return +END SUBROUTINE set_random + +! subroutine to convert an unsigned integer (stored as a signed integer) to the correct unsigned value (for display purposes) +! e.g. the dongle_number value in the dris - should be an unsigned integer but Fortran 90 does not support them +SUBROUTINE ConvertDongleNumber(value) + integer(8) :: value + + if (value < 0) then + value = value + 4294967296 _8 ! make the -ve value a +ve value + end if + return +END SUBROUTINE ConvertDongleNumber + +! displays messages for the most common errors. You will want to change this for your code +SUBROUTINE DisplayError(ret_code, extended_error) + integer :: ret_code, extended_error + + select case (ret_code) + case (401) + print *,"Error! No dongles detected!" + case (403) + print *,"Error! The dongle detected has a different type to the one specified in DinkeyAdd." + case (404) + print *,"Error! The dongle detected has a different model to those specified in DinkeyAdd." + case (409) + print *,"Error! The dongle detected has not been programmed by DinkeyAdd." + case (410) + print *,"Error! The dongle detected has a different Product Code to the one specified in DinkeyAdd." + case (411) + print *,"Error! The dongle detected does not contain the licence associated with this program." + case (413) + print *,"Error! This program has not been protected by DinkeyAdd." + print *,"For guidance please read the DinkeyAdd chapter of the Dinkey manual." + case (417) + print *,"Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the" + print *," DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa." + case (423) + print *,"Error! The number of network users has been exceeded." + case (435) + print *,"Error! DinkeyServer has not been detected on the network." + case (922) + print *,"Error! The Software Key has expired." + case default + print *,"An error occurred checking the dongle. Error: ", ret_code, " Extended Error: ", extended_error + end select + return +END SUBROUTINE DisplayError diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/iDllTest.sln b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/iDllTest.sln new file mode 100644 index 0000000..4976889 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/iDllTest.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = "iDllTest", "iDllTest.vfproj", "{99DA52B5-1568-4A3F-B7D1-CD1813A2CF94}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {99DA52B5-1568-4A3F-B7D1-CD1813A2CF94}.Debug|Win32.ActiveCfg = Debug|Win32 + {99DA52B5-1568-4A3F-B7D1-CD1813A2CF94}.Debug|Win32.Build.0 = Debug|Win32 + {99DA52B5-1568-4A3F-B7D1-CD1813A2CF94}.Debug|x64.ActiveCfg = Debug|x64 + {99DA52B5-1568-4A3F-B7D1-CD1813A2CF94}.Debug|x64.Build.0 = Debug|x64 + {99DA52B5-1568-4A3F-B7D1-CD1813A2CF94}.Release|Win32.ActiveCfg = Release|Win32 + {99DA52B5-1568-4A3F-B7D1-CD1813A2CF94}.Release|Win32.Build.0 = Release|Win32 + {99DA52B5-1568-4A3F-B7D1-CD1813A2CF94}.Release|x64.ActiveCfg = Release|x64 + {99DA52B5-1568-4A3F-B7D1-CD1813A2CF94}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/iDllTest.vfproj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/iDllTest.vfproj new file mode 100644 index 0000000..cb277f4 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/iDllTest.vfproj @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/idlltest.f90 b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/idlltest.f90 new file mode 100644 index 0000000..487d7c3 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Fortran/Runtime/idlltest.f90 @@ -0,0 +1,826 @@ +! dlltest - sample program to call DinkeyPro/FD runtime module (dpwin32.dll) +! +! this sample code has been compiled and tested using Intel Fortran XE 2011 +! but should work with earlier versions. + +! The sample code contains 10 functions. You will not need to use all these +! functions in your code. Just use which ever functions are most appropriate +! and customise in your own way. The sample code is just a guide. You should +! implement the protection in a stronger way using the techniques described in +! the "Increasing your Protection" chapter of the manual. + +!If you are using Dinkey Lite then you can only use 4 functions: +!ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + +! this file contains 10 protection-check functions. +! ProtCheck a standard protection check +! ProtCheckWithAlg a protection check & executing an algorithm +! WriteBytes a protection check & write data to the dongle +! ReadBytes a protection check & read data from the dongle +! EncryptUserData a protection check & encrypting data and then decrypting the data +! these functions are the same as the functions listed above but encrypting all parameters passed to our API +! ProtCheckEnc a standard protection check +! ProtCheckWithAlgEnc a protection check & executing an Algorithm +! WriteBytesEnc a protection check & write data to the dongle +! ReadBytesEnc a protection check & read data from the dongle +! EncryptUserDataEnc a protection check & encrypting data and then decrypting the data + +PROGRAM main + ! call the function(s) of your choice here + ! by default I have chosen a standard protection check + if (ProtCheck() == 0) then + print *,"It worked!" + end if +END PROGRAM main + +! this module contains the DRIS structure declaration and also declares important constants +MODULE DinkeyPro + + integer,parameter :: MY_SDSN = 10101 !!!! change this value to be the value of your SDSN (demo = 10101) + + ! declare dris data type + !DEC$ PACK:1 ! this needs to be byte aligned + TYPE DRIS + sequence + ! the first 4 fields are never encrypted + character(len=4) :: header ! should be set to 'DRIS' + ! inputs + integer(4) :: size ! size of this structure + integer(4) :: seed1 ! seed for data/dris encryption + integer(4) :: seed2 ! as above + ! (maybe encrypted from now on) + integer(4) :: function ! specify only one function + integer(4) :: flags ! options for the function selected. To use more than one OR them together e.g. OR(OPTION1, OPTION2) + integer(4) :: execs_decrement ! amount by which to dec execs if we use flag: DEC_MANY_EXECS + integer(4) :: data_crypt_key_num ! number of the key (1-3) that the dongle uses to encrypt or decrypt user data + integer(4) :: rw_offset ! offset in the dongle data area to read or write data + integer(4) :: rw_length ! length of data are to read/write/encrypt/decrypt +!DEC$ IF DEFINED (_M_X64) + integer(8) :: unused ! pass data by function parameter instead. 8 bytes long for 64-bit Fortran code. +!DEC$ ELSE + integer(4) :: unused ! pass data by function parameter instead. 4 bytes long for 32-bit Fortran code. +!DEC$ ENDIF + character(len=256) :: alt_licence_name ! protection check for different licence instead of the default one, must be null-terminated + integer(4) :: var_a ! variable values for user algorithm + integer(4) :: var_b + integer(4) :: var_c + integer(4) :: var_d + integer(4) :: var_e + integer(4) :: var_f + integer(4) :: var_g + integer(4) :: var_h + integer(4) :: alg_number ! the number of the user algorithm that you want to execute + + ! outputs + integer(4) :: ret_code ! return code from the protection check + integer(4) :: ext_err ! extended error + integer(4) :: type ! type of dongle detected. 1 = Pro, 2 = FD + integer(4) :: model ! model of dongle detected. 1= Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + integer(4) :: sdsn ! Software Developer's Serial Number + character(len=12) :: prodcode ! Product Code (null-terminated) + integer(4) :: dongle_number ! NB this should be an unsigned value really + integer(4) :: update_number + integer(4) :: data_area_size ! size of the data area used in the dongle detected + integer(4) :: max_alg_num ! the maximum algorithm number in the dongle detected + integer(4) :: execs ! executions left: -1 indicates 'no limit' + integer(4) :: exp_day ! expiry day: -1 indicates 'no limit' + integer(4) :: exp_month ! expiry month: -1 indicates 'no limit' + integer(4) :: exp_year ! expiry year: -1 indicates 'no limit' + integer(4) :: features ! features value + integer(4) :: net_users ! maximum number of network users for the dongle detected: -1 indicates 'no limit' + integer(4) :: alg_answer ! answer to the user algorithm executed with the given variable values + integer(4) :: fd_capacity ! capacity of the data area in FD dongle. + character(len=128) :: fd_drive ! drive letter of FD dongle detected e.g. 'f:\' (or mount name under Linux) + integer(4) :: swkey_type ! 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + integer(4) :: swkey_exp_day ! software key expiry date (if software key detected) + integer(4) :: swkey_exp_month + integer(4) :: swkey_exp_year + END TYPE DRIS + !DEC$ PACK + +!DEC$ IF DEFINED (_M_X64) + integer,parameter :: DRIS_SIZE = 564 ! I am sure there should be a way to get this programatically! +!DEC$ ELSE + integer,parameter :: DRIS_SIZE = 560 ! I am sure there should be a way to get this programatically! +!DEC$ ENDIF + + ! functions - must specify only one + integer,parameter :: PROTECTION_CHECK = 1 ! checks for dongle, check program params... + integer,parameter :: EXECUTE_ALGORITHM = 2 ! protection check + calculate answer for specified algorithm with specified inputs + integer,parameter :: WRITE_DATA_AREA = 3 ! protection check + writes dongle data area + integer,parameter :: READ_DATA_AREA = 4 ! protection check + reads dongle data area + integer,parameter :: ENCRYPT_USER_DATA = 5 ! protection check + the dongle will encrypt user data + integer,parameter :: DECRYPT_USER_DATA = 6 ! protection check + the dongle will decrypt user data + integer,parameter :: FAST_PRESENCE_CHECK = 7 ! checks for the presence of the correct dongle only with minimal security, no flags allowed. + integer,parameter :: STOP_NET_USER = 8 ! stops a network user (a protection check is NOT performed) + + ! flags - can specify as many as you like + integer,parameter :: DEC_ONE_EXEC = 1 ! decrement execs by 1 + integer,parameter :: DEC_MANY_EXECS = 2 ! decrement execs by number specified in execs_decrement + integer,parameter :: START_NET_USER = 4 ! starts a network user + integer,parameter :: USE_FUNCTION_ARGUMENT = 16 ! use the extra argument in the function for pointers + integer,parameter :: CHECK_LOCAL_FIRST = 32 ! always look in local ports before looking in network ports + integer,parameter :: CHECK_NETWORK_FIRST = 64 ! always look on the network before looking in local ports + integer,parameter :: USE_ALT_LICENCE_NAME = 128 ! use name specified in alt_licence_name instead of the default one + integer,parameter :: DONT_SET_MAXDAYS_EXPIRY = 256 ! if the max days expiry date has not been calculated then do not do it this time + integer,parameter :: MATCH_DONGLE_NUMBER = 512 ! restrict the search to match the dongle number specified in the DRIS + integer,parameter :: DONT_RETURN_FD_DRIVE = 1024 ! if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + + ! declare the protection check function in the Dinkey Pro/FD runtime module + INTERFACE + FUNCTION DDProtCheck(mydris, mydata) + !DEC$ ATTRIBUTES STDCALL, DECORATE, ALIAS:'DDProtCheck', DLLIMPORT :: DDProtCheck + import + type (DRIS) :: mydris + !DEC$ ATTRIBUTES REFERENCE :: mydris + character(len=*) :: mydata + !DEC$ ATTRIBUTES REFERENCE, ALLOW_NULL :: mydata + integer :: DDProtCheck + END FUNCTION DDProtCheck + END INTERFACE + + ! this is an instance of the dris. We make an equivalence between the derived-type + ! and a byte_array because for encryption we need to access the memory as a byte array + type (DRIS) :: mydris + integer(1), dimension(DRIS_SIZE) :: mydris_byte_array + equivalence(mydris, mydris_byte_array) + +END MODULE DinkeyPro + +! ************************* our 10 functions ********************************** + +! ************************** ProtCheck *************************************** +FUNCTION ProtCheck() + use DinkeyPro + integer :: ret_code + integer(8) :: display_dongle_number + + call set_random(mydris_byte_array) ! we have to call this function using the byte array equivalence of the dris type + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = PROTECTION_CHECK ! standard protection check + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + ret_code = DDProtCheck(mydris, 0) + ProtCheck = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheck = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ProtCheck = -1 + return + end if + + ! sample to show how to display dongle number (this is the only value in the dris that should be an unsigned integer) + display_dongle_number = mydris%dongle_number + call ConvertDongleNumber(display_dongle_number) + print *,"Dongle Check successful. Dongle Number is: ",display_dongle_number +END FUNCTION ProtCheck + +! ************************** ProtCheckWithAlg ****************************** + +! !!!! You should replace this function with the one generated by the +! "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) +! or from DinkeyLook if you are using a Dinkey Lite dongle. +FUNCTION MyAlgorithm(a, b, c, d, e, f, g, h) + integer :: a,b,c,d,e,f,g,h,MyAlgorithm + MyAlgorithm = a + b + c + d + e + f + g + h + return +END FUNCTION MyAlgorithm + +! NB for this to work you must program at least "user algorithm" into the dongle +! NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +! sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +! code from DinkeyLook +FUNCTION ProtCheckWithAlg() + use DinkeyPro + integer :: ret_code + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = EXECUTE_ALGORITHM ! standard protection check & execute algorithm + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + mydris%alg_number = 1 ! execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + ! you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + mydris%var_a = 1 ! sample values + mydris%var_b = 2 + mydris%var_c = 3 + mydris%var_d = 4 + mydris%var_e = 5 + mydris%var_f = 6 + mydris%var_g = 7 + mydris%var_h = 8 + + ret_code = DDProtCheck(mydris, 0) + ProtCheckWithAlg = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheckWithAlg = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ProtCheckWithAlg = -1 + return + end if + + ! if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + ! !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) /= mydris%alg_answer) then + print *,"Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine" + ProtCheckWithAlg = -1 + return + end if +END FUNCTION ProtCheckWithAlg + +! ************************** WriteBytes *************************************** +! This writes the Data "Hello, World" to the dongle data area at offset 7 +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +FUNCTION WriteBytes() + use DinkeyPro + integer :: ret_code + character(len=14) :: WriteData = "Hello, World!"c ! it should be a null-terminated string + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = WRITE_DATA_AREA ! standard protection check and write data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(WriteData) + + ret_code = DDProtCheck(mydris, WriteData) + WriteBytes = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + WriteBytes = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + WriteBytes = -1 + return + end if +END FUNCTION WriteBytes + +! ************************** ReadBytes *************************************** +! This reads 14 bytes of data from offset 7 in the dongle data area +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +! In order for the data to be displayed properly by this routine it will need to be text data +FUNCTION ReadBytes() + use DinkeyPro + integer :: ret_code + character(len=14) :: ReadData + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = READ_DATA_AREA ! standard protection check and read data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(ReadData) + + ret_code = DDProtCheck(mydris, ReadData) + ReadBytes = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ReadBytes = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ReadBytes = -1 + return + end if + + print *,"Dinkey Dongle Data area, offset 7 is: ",ReadData +END FUNCTION ReadBytes + +! ************************** EncryptUserData *************************************** +! This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +! It will then do another protection check & decrypt the data +FUNCTION EncryptUserData() + use DinkeyPro + integer :: ret_code + character(len=14) :: MyData = "Hello, World!"c + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = ENCRYPT_USER_DATA ! standard protection check and encrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(MyData) + + ret_code = DDProtCheck(mydris, MyData) + EncryptUserData = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + ! ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + print *,"Encrypted data is: ",MyData + + ! Now decrypt the same data to get the original values + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = DECRYPT_USER_DATA ! standard protection check and decrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(MyData) + + ret_code = DDProtCheck(mydris, MyData) + EncryptUserData = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + EncryptUserData = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + EncryptUserData = -1 + return + end if + + print *,"Decrypted data is: ",MyData +END FUNCTION EncryptUserData + +! !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! +! In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" +! in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm +! but the code can be modified easily to use the 3 encryption parameters. + +! !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm +FUNCTION MyRWAlgorithm(a, b, c, d, e, f, g, h) + integer :: a,b,c,d,e,f,g,h,MyRWAlgorithm + MyRWAlgorithm = IEOR(IEOR(IEOR(IEOR(IEOR(a,b),c),d),e),f) + return +END FUNCTION MyRWAlgorithm + +! !!!! please patch the 3 parameters specified below with the 3 parameters specified in DinkeyAdd +SUBROUTINE CryptDRIS(dris_byte_array) + use DinkeyPro + integer(1), dimension(DRIS_SIZE) :: dris_byte_array + integer :: i,j,k,temp,t + integer, dimension(256) :: bigseed,S + + do i=1,256 + bigseed(i) = dris_byte_array(9 + modulo(i-1,8)) ! this takes the values from seed1, seed2 directly + end do + + do i=1,256 + S(i) = i-1 + end do + + j = 0 + do i=1,256 + j = IAND(j + S(i) + bigseed(i) + 123, 255) ! first parameter patched here + temp = S(i) + S(i) = S(j+1) + S(j+1) = temp + end do + + i = 0 + j = 0 + do k=17,DRIS_SIZE + i = IAND(i + 1, 255) + j = IAND(j + S(i+1) + 212, 255) ! second parameter patched here + temp = S(i+1) + S(i+1) = S(j+1) + S(j+1) = temp + t = IAND(S(i+1) + S(j+1) + 97,255) ! third parameter patched here + dris_byte_array(k) = IEOR(dris_byte_array(k),S(t+1)) + end do + return +END SUBROUTINE CryptDRIS + +! !!!! please patch the 3 parameters specified below with the 3 parameters specified in DinkeyAdd +! if you are using the r/w algorithm then there is no need to change this function +! NB we pass the whole of the DRIS but we only need it for seed1 and seed2 values +SUBROUTINE CryptApiData(mydata, length, dris_byte_array, alg_answer) + use DinkeyPro + integer :: length, alg_answer, seed1, seed2 + integer(1), dimension(length) :: mydata + integer(1), dimension(DRIS_SIZE) :: dris_byte_array + integer :: i,j,k,temp,t + integer, dimension(256) :: bigseed,S + + do i=1,256 + bigseed(i) = dris_byte_array(9 + modulo(i-1,8)) ! this takes the values from seed1, seed2 directly + end do + + do i=1,256 + S(i) = i-1 + end do + + j = 0 + do i=1,256 + j = IAND(j + S(i) + bigseed(i) + IAND(alg_answer, 255), 255) ! first parameter patched here + temp = S(i) + S(i) = S(j+1) + S(j+1) = temp + end do + + i = 0 + j = 0 + do k=1,length + i = IAND(i + 1, 255) + j = IAND(j + S(i+1) + IAND(ISHFT(alg_answer, -8),255), 255) ! second parameter patched here + temp = S(i+1) + S(i+1) = S(j+1) + S(j+1) = temp + t = IAND(S(i+1) + S(j+1) + IAND(ISHFT(alg_answer, -16),255),255) ! third parameter patched here + mydata(k) = IEOR(mydata(k),S(t+1)) + end do + return +END SUBROUTINE CryptApiData + +! ************************** ProtCheckEnc *************************************** +! We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +FUNCTION ProtCheckEnc() + use DinkeyPro + integer :: ret_code + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = PROTECTION_CHECK ! standard protection check + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, 0) + ProtCheckEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheckEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ProtCheckEnc = -1 + return + end if +END FUNCTION ProtCheckEnc + +! ************************** ProtCheckWithAlgEnc ****************************** +! NB for this to work you must program at least "user algorithm" into the dongle +! NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +! sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +! code from DinkeyLook +! We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +FUNCTION ProtCheckWithAlgEnc() + use DinkeyPro + integer :: ret_code + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = EXECUTE_ALGORITHM ! standard protection check & execute algorithm + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + mydris%alg_number = 1 ! execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + ! you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + mydris%var_a = 1 ! sample values + mydris%var_b = 2 + mydris%var_c = 3 + mydris%var_d = 4 + mydris%var_e = 5 + mydris%var_f = 6 + mydris%var_g = 7 + mydris%var_h = 8 + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, 0) + ProtCheckWithAlgEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheckWithAlgEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ProtCheckWithAlgEnc = -1 + return + end if + + ! if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + ! !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) /= mydris%alg_answer) then + print *,"Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine" + ProtCheckWithAlgEnc = -1 + return + end if +END FUNCTION ProtCheckWithAlgEnc + +! ************************** WriteBytesEnc *************************************** +! This writes the Data "Hello, World" to the dongle data area at offset 7 +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +! We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +FUNCTION WriteBytesEnc() + use DinkeyPro + integer :: ret_code,alg_ans + character(len=14) :: WriteData = "Hello, World!"c + integer(1), dimension(14) :: WriteDataByteArray + equivalence(WriteData, WriteDataByteArray) ! to encrypt it we need to pass it as a byte array + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = WRITE_DATA_AREA ! standard protection check and write data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(WriteData) + + ! calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) + + ! encrypt data we want to write. + call CryptApiData(WriteDataByteArray, len(WriteData), mydris_byte_array, alg_ans); + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, WriteData) + WriteBytesEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + WriteBytesEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + WriteBytesEnc = -1 + return + end if +END FUNCTION WriteBytesEnc + +! ************************** ReadBytesEnc *************************************** +! This reads 14 bytes of data from offset 7 in the dongle data area +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +! In order for the data to be displayed properly by this routine it will need to be text data +! We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +FUNCTION ReadBytesEnc() + use DinkeyPro + integer :: ret_code,alg_ans + character(len=14) :: ReadData + integer(1), dimension(14) :: ReadDataByteArray + equivalence(ReadData, ReadDataByteArray) ! to encrypt it we need to pass it as a byte array + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = READ_DATA_AREA ! standard protection check and read data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(ReadData) + + ! calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, ReadData) + ReadBytesEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ReadBytesEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ReadBytesEnc = -1 + return + end if + + ! decrypt data we have just read. + call CryptApiData(ReadDataByteArray, len(ReadData), mydris_byte_array, alg_ans); + print *,"Dinkey Dongle Data area, offset 7 is: ",ReadData +END FUNCTION ReadBytesEnc + +! ************************** EncryptUserDataEnc *************************************** +! This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +! It will then do another protection check & decrypt the data +! We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +FUNCTION EncryptUserDataEnc() + use DinkeyPro + integer :: ret_code,alg_ans + character(len=14) :: MyData = "Hello, World!"c + integer(1), dimension(14) :: MyDataByteArray + equivalence(MyData, MyDataByteArray) ! to encrypt it we need to pass it as a byte array + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = ENCRYPT_USER_DATA ! standard protection check and encrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(MyData) + + ! calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) + + ! encrypt data we want to pass. + call CryptApiData(MyDataByteArray, len(MyData), mydris_byte_array, alg_ans); + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, MyData) + EncryptUserDataEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + ! ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + print *,"Encrypted data is: ",MyData + + ! Now decrypt the same data to get the original values + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = DECRYPT_USER_DATA ! standard protection check and decrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(MyData) + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, MyData) + EncryptUserDataEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + EncryptUserDataEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + EncryptUserDataEnc = -1 + return + end if + + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) + ! decrypt data that was passed to us by the API. + call CryptApiData(MyDataByteArray, len(MyData), mydris_byte_array, alg_ans); + print *,"Decrypted data is: ",MyData +END FUNCTION EncryptUserDataEnc + +! ************************** useful subroutines ******************************* +! subroutine to randomise each element of the DRIS (expects you to pass the DRIS as a byte array +SUBROUTINE set_random(dris_byte_array) + use DinkeyPro + integer(1), dimension(DRIS_SIZE) :: dris_byte_array + real,dimension(DRIS_SIZE) :: temp + + call random_seed() + call random_number(temp) + do i=1,DRIS_SIZE + dris_byte_array(i) = temp(i)*256 + end do + return +END SUBROUTINE set_random + +! subroutine to convert an unsigned integer (stored as a signed integer) to the correct unsigned value (for display purposes) +! e.g. the dongle_number value in the dris - should be an unsigned integer but Fortran 90 does not support them +SUBROUTINE ConvertDongleNumber(value) + integer(8) :: value + + if (value < 0) then + value = value + 4294967296 ! make the -ve value a +ve value + end if + return +END SUBROUTINE ConvertDongleNumber + +! displays messages for the most common errors. You will want to change this for your code +SUBROUTINE DisplayError(ret_code, extended_error) + integer :: ret_code, extended_error + + select case (ret_code) + case (401) + print *,"Error! No dongles detected!" + case (403) + print *,"Error! The dongle detected has a different type to the one specified in DinkeyAdd." + case (404) + print *,"Error! The dongle detected has a different model to those specified in DinkeyAdd." + case (409) + print *,"Error! The dongle detected has not been programmed by DinkeyAdd." + case (410) + print *,"Error! The dongle detected has a different Product Code to the one specified in DinkeyAdd." + case (411) + print *,"Error! The dongle detected does not contain the licence associated with this program." + case (413) + print *,"Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual." + case (417) + print *,"Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa." + case (423) + print *,"Error! The number of network users has been exceeded." + case (435) + print *,"Error! DinkeyServer has not been detected on the network." + case (922) + print *,"Error! The Software Key has expired." + case default + print *,"An error occurred checking the dongle. Error: ", ret_code, " Extended Error: ", extended_error + end select + return +END SUBROUTINE DisplayError \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/FoxPro/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/FoxPro/README.txt new file mode 100644 index 0000000..5b1a53f --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/FoxPro/README.txt @@ -0,0 +1,45 @@ +FoxPro Sample Code Notes +~~~~~~~~~~~~~~~~~~~~~~~~ + +Runtime.prg was tested in FoxPro6 but will also work with all later versions of PoxPro + +The sample code contains 10 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. + +Note - you should protect dpwin32.dll and not your program. Because your program +is linked to the DLL it is protected. The protected DLL will need to be in the +same folder as your compiled program for it to run correctly. + +Note - you should place dpwin32.dll either in the 32-bit Windows System folder* or in +the project folder (if you do this you should "CD" to this folder in the command window). + +Note - Output text from this program is displayed in the main Visual FoxPro Window. + +Note - You would normally want to QUIT if the protection check failed. We do not do that +in this sample code so you can see error messages being displayed. + +Note - you can debug your code (our anti-debug code sometimes stops this but not for FoxPro) + +Note - For reading data or decrypting data you must initialise the data variable you pass to +contain at least the number of bytes that you want to read. After you have read the data you +must adjust the size of the string to be the size of the data you have read as our API does +not do this. + +* Windows System folder for 32-bit dlls is: +c:\windows\system32 32-bit Windows OS +c:\windows\syswow64 64-bit Windows OS \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/FoxPro/runtime.prg b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/FoxPro/runtime.prg new file mode 100644 index 0000000..3c342ab --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/FoxPro/runtime.prg @@ -0,0 +1,929 @@ +* Sample code for Visual Foxpro +* Compiled and tested with Microsoft Visual Foxpro 6.0 +SET TALK On +CLEAR DLLS + +* declare functions in Dinkey Pro module dpwin32.dll +Declare INTEGER DDProtCheck IN "dpwin32.dll" STRING @dris, STRING @data + +* The sample code contains 10 functions. You will not need to use all these +* functions in your code. Just use which ever functions are most appropriate +* and customise in your own way. The sample code is just a guide. You should +* implement the protection in a stronger way using the techniques described in +* the "Increasing your Protection" chapter of the manual. +* +* Sample Code Functions: +* ProtCheck, ProtCheckWithAlg, WriteBytes, ReadBytes, EncryptUserData +* +* and also these functions but encrypting all parameters passed to our API: +* ProtCheckEnc, ProtCheckWithAlgEnc, WriteBytesEnc, ReadBytesEnc, EncryptUserDataEnc +* +* If you are using Dinkey Lite then you can only use 4 functions: +* ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc +* + +#define MY_SDSN 10101 && !!!! change this value to be the value of your SDSN (demo = 10101) +#define MY_PRODCODE "DEMO" && !!!! change this value to match the Product Code in the dongle + +#define DRIS_SIZE 560 + +* functions constants - must specify only one +#define PROTECTION_CHECK 1 && checks for dongle, check program params... +#define EXECUTE_ALGORITHM 2 && protection check + calculate answer for specified algorithm with specified inputs +#define WRITE_DATA_AREA 3 && protection check + writes dongle data area +#define READ_DATA_AREA 4 && protection check + reads dongle data area +#define ENCRYPT_USER_DATA 5 && protection check + the dongle will encrypt user data +#define DECRYPT_USER_DATA 6 && protection check + the dongle will decrypt user data +#define FAST_PRESENCE_CHECK 7 && checks for the presence of the correct dongle only with minimal security, no flags allowed. +#define STOP_NET_USER 8 && stops a network user (a protection check is NOT performed) + +* flags constants - can specify as many as you like +#define DEC_ONE_EXEC 1 && decrement execs by 1 +#define DEC_MANY_EXECS 2 && decrement execs by number specified in execs_decrement +#define START_NET_USER 4 && starts a network user +#define USE_FUNCTION_ARGUMENT 16 && use the extra argument in the function for pointers +#define CHECK_LOCAL_FIRST 32 && always look in local ports before looking in network ports +#define CHECK_NETWORK_FIRST 64 && always look on the network before looking in local ports +#define USE_ALT_LICENCE_NAME 128 && use name specified in alt_licence_name instead of the default one +#define DONT_SET_MAXDAYS_EXPIRY 256 && if the max days expiry date has not been calculated then do not do it this time +#define MATCH_DONGLE_NUMBER 512 && restrict the search to match the dongle number specified in the DRIS +#define DONT_RETURN_FD_DRIVE 1024 && if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + +********************** entry point ******************************* +* call the function of your choice: + +IF ProtCheck() == 0 + ? "It Worked!" +ELSE + && QUIT && you would probably want to QUIT if the protection check failed. We don't do that here so you can see display error messages +ENDIF + +clear dlls + + +********************* protection check functions ******************* +*** ProtCheck +FUNCTION ProtCheck + * create & initialise DRIS to random values & set header + dris = random_dris() + + * set DRIS values to be what we want to use + SetDrisSize(@dris) + SetDrisFunction(@dris, PROTECTION_CHECK) && standard protection check + SetDrisFlags(@dris, 0) && no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + ret_code = DDProtCheck(@dris, NULL) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * later in your code you can check other values in the DRIS... + IF GetDrisSDSN(dris) != MY_SDSN + ? "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + RETURN -1 + ENDIF + + IF GetDrisProdCode(dris) != MY_PRODCODE + ? "Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle." + RETURN -1 + ENDIF + + * later on in your program you can check the return code again + IF GetDrisRetCode(@dris) != 0 + ? "Dinkey Dongle protection error" + RETURN -1 + ENDIF + + * It worked! + RETURN 0 +ENDFUNC + +*** ProtCheckWithAlg +* !!!! You should replace this function with the one generated by the +* "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) +* or from DinkeyLook if you are using a Dinkey Lite dongle. You will have to translate this from another language e.g. C +FUNCTION MyAlgorithm(a, b, c, d, e, f, g, h) + RETURN a + b + c + d + e + f + g + h +ENDFUNC + +* NB for this to work you must program at least "user algorithm" into the dongle +* NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +* sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +* code from DinkeyLook +FUNCTION ProtCheckWithAlg + * create & initialise DRIS to random values & set header + dris = random_dris() + + * set DRIS values to be what we want to use + SetDrisSize(@dris) + SetDrisFunction(@dris, EXECUTE_ALGORITHM) && standard protection check & execute specified algorithm + SetDrisFlags(@dris, 0) && no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + SetDrisAlgNumber(@dris, 1) && execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + && set variables for algorithm + SetDrisAlgVars(@dris, 1, 2, 3, 4 , 5, 6, 7, 8) && you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + + ret_code = DDProtCheck(@dris, NULL) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * later in your code you can check other values in the DRIS... + IF GetDrisSDSN(dris) != MY_SDSN + ? "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + RETURN -1 + ENDIF + + * later on in your program you can check the return code again + IF GetDrisRetCode(@dris) != 0 + ? "Dinkey Dongle protection error" + RETURN -1 + ENDIF + + * if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + * !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + IF MyAlgorithm(GetDrisVarA(dris), GetDrisVarB(dris), GetDrisVarC(dris), GetDrisVarD(dris), GetDrisVarE(dris), ; + GetDrisVarF(dris), GetDrisVarG(dris), GetDrisVarH(dris)) != GetDrisAlgAnswer(dris) + ? "Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine" + RETURN -1 + ENDIF + + * It worked! + RETURN 0 +ENDFUNC + +*** WriteBytes +* This writes the string "Hello, World" to the dongle data area at offset 7 +* In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +FUNCTION WriteBytes + DataToWrite = "Hello, World!" + + * create & initialise DRIS to random values & set header + dris = random_dris() + + * set DRIS values to be what we want to use + SetDrisSize(@dris) + SetDrisFunction(@dris, WRITE_DATA_AREA) && standard protection check and write the dongle data area + SetDrisFlags(@dris, USE_FUNCTION_ARGUMENT) && we need to set this as we are passing the data to write as an extra parameter to DDProtCheck + SetDrisRWOffset(@dris, 7) + SetDrisRWLength(@dris, LEN(DataToWrite)) + + ret_code = DDProtCheck(@dris, @DataToWrite) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * later in your code you can check other values in the DRIS... + IF GetDrisSDSN(dris) != MY_SDSN + ? "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + RETURN -1 + ENDIF + + * later on in your program you can check the return code again + IF GetDrisRetCode(@dris) != 0 + ? "Dinkey Dongle protection error" + RETURN -1 + ENDIF + + * It worked! + RETURN 0 +ENDFUNC + +*** ReadBytes +* This reads 13 bytes of data from offset 7 in the dongle data area +* In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +* In order for the data to be displayed properly by this routine it will need to be text data +FUNCTION ReadBytes + DataRead = "Data Read goes here" && we must initialise this to something that is at least as long as the data we are reading + data_length = 13 + + * create & initialise DRIS to random values & set header + dris = random_dris() + + * set DRIS values to be what we want to use + SetDrisSize(@dris) + SetDrisFunction(@dris, READ_DATA_AREA) && standard protection check and read the dongle data area + SetDrisFlags(@dris, USE_FUNCTION_ARGUMENT) && we need to set this as we are passing the data to read as an extra parameter to DDProtCheck + SetDrisRWOffset(@dris, 7) + SetDrisRWLength(@dris, data_length) + + ret_code = DDProtCheck(@dris, @DataRead) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * later in your code you can check other values in the DRIS... + IF GetDrisSDSN(dris) != MY_SDSN + ? "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + RETURN -1 + ENDIF + + * later on in your program you can check the return code again + IF GetDrisRetCode(@dris) != 0 + ? "Dinkey Dongle protection error" + RETURN -1 + ENDIF + + DataRead = SUBSTR(DataRead, 1, data_length) && shorten string so it just contains the data read + ? "Dinkey Dongle Data area, offset 7 is: " + DataRead + + * It worked! + RETURN 0 +ENDFUNC + +*** EncryptUserData +* This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +* It will then do another protection check & decrypt the data +FUNCTION EncryptUserData + MyData = "Hello, World!" && this is the data that we are going to encrypt + + * create & initialise DRIS to random values & set header + dris = random_dris() + + * set DRIS values to be what we want to use + SetDrisSize(@dris) + SetDrisFunction(@dris, ENCRYPT_USER_DATA) && standard protection check and encrypt data + SetDrisFlags(@dris, USE_FUNCTION_ARGUMENT) && we need to set this as we are passing the data to encrypt as an extra parameter to DDProtCheck + SetDrisDataCryptKeyNum(@dris, 1) + SetDrisRWLength(@dris, Len(MyData)) + + ret_code = DDProtCheck(@dris, @MyData) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + * Now decrypt this encrypted data to get the original + dris = random_dris() + SetDrisSize(@dris) + SetDrisFunction(@dris, DECRYPT_USER_DATA) && standard protection check and decrypt data + SetDrisFlags(@dris, USE_FUNCTION_ARGUMENT) && we need to set this as we are passing the data to encrypt as an extra parameter to DDProtCheck + SetDrisDataCryptKeyNum(@dris, 1) + SetDrisRWLength(@dris, Len(MyData)) + + ret_code = DDProtCheck(@dris, @MyData) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * later in your code you can check other values in the DRIS... + IF GetDrisSDSN(dris) != MY_SDSN + ? "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + RETURN -1 + ENDIF + + * later on in your program you can check the return code again + IF GetDrisRetCode(@dris) != 0 + ? "Dinkey Dongle protection error" + RETURN -1 + ENDIF + + ? "Decrypted data is: " + MyData + + * It worked! + RETURN 0 +ENDFUNC + +* !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! +* In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" +* in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm +* but the code can be modified easily to use the 3 encryption parameters. + +* !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm +* in this case you will have to translate from C or another programming language +FUNCTION MyRWAlgorithm(a, b, c, d, e, f, g, h) + RETURN BITXOR(BITXOR(BITXOR(BITXOR(BITXOR(a, b), c), d), e), f) +ENDFUNC + +* !!!! please overwrite this function with the one generated by DinkeyAdd +* in this case you will have to just patch the parameter values in the code +FUNCTION CryptDRIS(mydris, seed1, seed2) + DECLARE bigseed[256] As Integer + DECLARE S[256] As Integer + + FOR i=1 TO 256 STEP 8 + SETARRAY4BYTES(@bigseed, i, seed1) + SETARRAY4BYTES(@bigseed, i+4, seed2) + ENDFOR + + FOR i=1 TO 256 + S[i] = i-1 + ENDFOR + + j = 0 + FOR i = 0 TO 255 + j = BITAND(j + S[i+1]+ bigseed[i+1] + 123, 255) && parameter 1 is 123 + temp = S[i+1] + S[i+1] = S[j+1] + S[j+1] = temp + ENDFOR + + i = 0 + j = 0 + FOR k=17 TO DRIS_SIZE + i = BITAND(i + 1, 255) + j = BITAND(j + S[i+1] + 212, 255) && parameter 2 is 212 + temp = S[i+1] + S[i+1] = S[j+1] + S[j+1] = temp + t = BITAND(S[i+1] + S[j+1] + 97, 255) && parameter 3 is 97 + temp = ASC(SUBSTR(mydris, k, 1)) + mydris = STUFF(mydris, k, 1, CHR(BITXOR(temp,S[t+1]))) + ENDFOR +ENDFUNC + +* !!!! please overwrite this function with the one generated by DinkeyAdd +* in this case you will have to just patch the parameter values in the code +FUNCTION CryptApiData(mydata, length, seed1, seed2, alg_answer) + DECLARE bigseed[256] As Integer + DECLARE S[256] As Integer + + FOR i=1 TO 256 STEP 8 + SETARRAY4BYTES(@bigseed, i, seed1) + SETARRAY4BYTES(@bigseed, i+4, seed2) + ENDFOR + + FOR i=1 TO 256 + S[i] = i-1 + ENDFOR + + j = 0 + FOR i = 0 TO 255 + j = BITAND(j + S[i+1]+ bigseed[i+1] + BITAND(alg_answer, 255), 255) && parameter 1 + temp = S[i+1] + S[i+1] = S[j+1] + S[j+1] = temp + ENDFOR + + i = 0 + j = 0 + FOR k=1 TO length + i = BITAND(i + 1, 255) + j = BITAND(j + S[i+1] + BITAND(BITRSHIFT(alg_answer, 8),255), 255) && parameter 2 + temp = S[i+1] + S[i+1] = S[j+1] + S[j+1] = temp + t = BITAND(S[i+1] + S[j+1] + BITAND(BITRSHIFT(alg_answer, 16),255), 255) && parameter 3 + temp = ASC(SUBSTR(mydata, k, 1)) + mydata = STUFF(mydata, k, 1, CHR(BITXOR(temp,S[t+1]))) + ENDFOR +ENDFUNC + +*** ProtCheckEnc +* We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +FUNCTION ProtCheckEnc + * create & initialise DRIS to random values & set header + dris = random_dris() + + * set DRIS values to be what we want to use + SetDrisSize(@dris) + SetDrisFunction(@dris, PROTECTION_CHECK) && standard protection check + SetDrisFlags(@dris, 0) && no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(@dris, NULL) + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * later in your code you can check other values in the DRIS... + IF GetDrisSDSN(dris) != MY_SDSN + ? "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + RETURN -1 + ENDIF + + IF GetDrisProdCode(dris) != MY_PRODCODE + ? "Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle." + RETURN -1 + ENDIF + + * later on in your program you can check the return code again + IF GetDrisRetCode(@dris) != 0 + ? "Dinkey Dongle protection error" + RETURN -1 + ENDIF + + * It worked! + RETURN 0 +ENDFUNC + +*** ProtCheckWithAlgEnc +* NB for this to work you must program at least "user algorithm" into the dongle +* NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +* sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +* code from DinkeyLook +* We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +FUNCTION ProtCheckWithAlgEnc + * create & initialise DRIS to random values & set header + dris = random_dris() + + * set DRIS values to be what we want to use + SetDrisSize(@dris) + SetDrisFunction(@dris, EXECUTE_ALGORITHM) && standard protection check & execute specified algorithm + SetDrisFlags(@dris, 0) && no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + SetDrisAlgNumber(@dris, 1) && execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + && set variables for algorithm + SetDrisAlgVars(@dris, 1, 2, 3, 4 , 5, 6, 7, 8) && you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(@dris, NULL) + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * later in your code you can check other values in the DRIS... + IF GetDrisSDSN(dris) != MY_SDSN + ? "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + RETURN -1 + ENDIF + + * later on in your program you can check the return code again + IF GetDrisRetCode(@dris) != 0 + ? "Dinkey Dongle protection error" + RETURN -1 + ENDIF + + * if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + * !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + IF MyAlgorithm(GetDrisVarA(dris), GetDrisVarB(dris), GetDrisVarC(dris), GetDrisVarD(dris), GetDrisVarE(dris), ; + GetDrisVarF(dris), GetDrisVarG(dris), GetDrisVarH(dris)) != GetDrisAlgAnswer(dris) + ? "Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine" + RETURN -1 + ENDIF + + * It worked! + RETURN 0 +ENDFUNC + +*** WriteBytes +* This writes the string "Hello, World" to the dongle data area at offset 7 +* In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +* We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +FUNCTION WriteBytesEnc + DataToWrite = "Hello, World!" + + * create & initialise DRIS to random values & set header + dris = random_dris() + + * set DRIS values to be what we want to use + SetDrisSize(@dris) + SetDrisFunction(@dris, WRITE_DATA_AREA) && standard protection check and write the dongle data area + SetDrisFlags(@dris, USE_FUNCTION_ARGUMENT) && we need to set this as we are passing the data to write as an extra parameter to DDProtCheck + SetDrisRWOffset(@dris, 7) + SetDrisRWLength(@dris, LEN(DataToWrite)) + + * calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(GetDrisVarA(dris), GetDrisVarB(dris), GetDrisVarC(dris), GetDrisVarD(dris), GetDrisVarE(dris), GetDrisVarF(dris), GetDrisVarG(dris), GetDrisVarH(dris)) + + * encrypt data we want to write. + CryptApiData(@DataToWrite, LEN(DataToWrite), GetDrisSeed1(dris), GetDrisSeed2(dris), alg_ans) + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(@dris, @DataToWrite) + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * later in your code you can check other values in the DRIS... + IF GetDrisSDSN(dris) != MY_SDSN + ? "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + RETURN -1 + ENDIF + + * later on in your program you can check the return code again + IF GetDrisRetCode(@dris) != 0 + ? "Dinkey Dongle protection error" + RETURN -1 + ENDIF + + * It worked! + RETURN 0 +ENDFUNC + +*** ReadBytesEnc +* This reads 13 bytes of data from offset 7 in the dongle data area +* In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +* In order for the data to be displayed properly by this routine it will need to be text data +FUNCTION ReadBytesEnc + DataRead = "Data Read goes here" && we must initialise this to something that is at least as long as the data we are reading + data_length = 13 + + * create & initialise DRIS to random values & set header + dris = random_dris() + + * set DRIS values to be what we want to use + SetDrisSize(@dris) + SetDrisFunction(@dris, READ_DATA_AREA) && standard protection check and read the dongle data area + SetDrisFlags(@dris, USE_FUNCTION_ARGUMENT) && we need to set this as we are passing the data to read as an extra parameter to DDProtCheck + SetDrisRWOffset(@dris, 7) + SetDrisRWLength(@dris, data_length) + + * calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(GetDrisVarA(dris), GetDrisVarB(dris), GetDrisVarC(dris), GetDrisVarD(dris), GetDrisVarE(dris), GetDrisVarF(dris), GetDrisVarG(dris), GetDrisVarH(dris)) + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(@dris, @DataRead) + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * later in your code you can check other values in the DRIS... + IF GetDrisSDSN(dris) != MY_SDSN + ? "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + RETURN -1 + ENDIF + + * later on in your program you can check the return code again + IF GetDrisRetCode(@dris) != 0 + ? "Dinkey Dongle protection error" + RETURN -1 + ENDIF + + * decrypt data we read + CryptApiData(@DataRead, data_length, GetDrisSeed1(dris), GetDrisSeed2(dris), alg_ans) + DataRead = SUBSTR(DataRead, 1, data_length) && shorten string so it just contains the data read + ? "Dinkey Dongle Data area, offset 7 is: " + DataRead + + * It worked! + RETURN 0 +ENDFUNC + +*** EncryptUserDataEnc +* This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +* It will then do another protection check & decrypt the data +FUNCTION EncryptUserDataEnc + MyData = "Hello, World!" && this is the data that we are going to encrypt + + * create & initialise DRIS to random values & set header + dris = random_dris() + + * set DRIS values to be what we want to use + SetDrisSize(@dris) + SetDrisFunction(@dris, ENCRYPT_USER_DATA) && standard protection check and encrypt data + SetDrisFlags(@dris, USE_FUNCTION_ARGUMENT) && we need to set this as we are passing the data to encrypt as an extra parameter to DDProtCheck + SetDrisDataCryptKeyNum(@dris, 1) + SetDrisRWLength(@dris, Len(MyData)) + + * calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(GetDrisVarA(dris), GetDrisVarB(dris), GetDrisVarC(dris), GetDrisVarD(dris), GetDrisVarE(dris), GetDrisVarF(dris), GetDrisVarG(dris), GetDrisVarH(dris)) + + * encrypt data we want to pass. + CryptApiData(@MyData, LEN(MyData), GetDrisSeed1(dris), GetDrisSeed2(dris), alg_ans) + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(@dris, @MyData) + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + * Now decrypt this encrypted data to get the original + dris = random_dris() + SetDrisSize(@dris) + SetDrisFunction(@dris, DECRYPT_USER_DATA) && standard protection check and decrypt data + SetDrisFlags(@dris, USE_FUNCTION_ARGUMENT) && we need to set this as we are passing the data to encrypt as an extra parameter to DDProtCheck + SetDrisDataCryptKeyNum(@dris, 1) + SetDrisRWLength(@dris, Len(MyData)) + + * calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(GetDrisVarA(dris), GetDrisVarB(dris), GetDrisVarC(dris), GetDrisVarD(dris), GetDrisVarE(dris), GetDrisVarF(dris), GetDrisVarG(dris), GetDrisVarH(dris)) + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(@dris, @MyData) + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * later in your code you can check other values in the DRIS... + IF GetDrisSDSN(dris) != MY_SDSN + ? "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + RETURN -1 + ENDIF + + * later on in your program you can check the return code again + IF GetDrisRetCode(@dris) != 0 + ? "Dinkey Dongle protection error" + RETURN -1 + ENDIF + + * decrypt data passed to us by API + CryptApiData(@MyData, Len(MyData), GetDrisSeed1(dris), GetDrisSeed2(dris), alg_ans) + ? "Decrypted data is: " + MyData + + * It worked! + RETURN 0 +ENDFUNC + + + +******************************** useful functions ********************************* + +* this function extract a 4-byte numeric field from the dris +FUNCTION GET4BYTES(mydris, offset) + value1 = ASC(SUBSTR(mydris, offset + 3)) * 16777216 + ; + ASC(SUBSTR(mydris, offset + 2)) * 65536 + ; + ASC(SUBSTR(mydris, offset + 1)) * 256 + ; + ASC(SUBSTR(mydris, offset)) + RETURN value1 +ENDFUNC + +* this function sets a 4-byte numeric field in the dris, you should pass dris by reference +FUNCTION SET4BYTES(mydris, offset, value1) + string_value = CHR(BITAND(value1, 255)) + CHR(BITAND(BITRSHIFT(value1, 8),255)) + CHR(BITAND(BITRSHIFT(value1, 16),255)) + CHR(BITAND(BITRSHIFT(value1, 24),255)) + mydris = STUFF(mydris, offset, 4, string_value) +ENDFUNC + +* this does the same thing but for an array +FUNCTION SETARRAY4BYTES(myArray, offset, value1) + myArray[offset] = BITAND(value1, 255) + myArray[offset+1] = BITAND(BITRSHIFT(value1, 8),255) + myArray[offset+2] = BITAND(BITRSHIFT(value1, 16),255) + myArray[offset+3] = BITAND(BITRSHIFT(value1, 24),255) +ENDFUNC + +* this function will initialise the DRIS to random values and set the first four bytes to 'DRIS' +FUNCTION random_dris + RAND(-1) && seeds using time + dris = "DRIS" + FOR i = 5 TO DRIS_SIZE + dris = dris + CHR(RAND() * 255) + ENDFOR + RETURN dris +ENDFUNC + +*** these functions let you set values in the DRIS (NB offsets are 1-based) +* NB you should pass dris by reference when you call these functions. e.g. SetDrisSize(@dris) +FUNCTION SetDrisSize(mydris) + SET4BYTES(@mydris, 5, DRIS_SIZE) +ENDFUNC + +FUNCTION SetDrisFunction(mydris, myfunction) + SET4BYTES(@mydris, 17, myfunction) +ENDFUNC + +FUNCTION SetDrisFlags(mydris, myflags) + SET4BYTES(@mydris, 21, myflags) +ENDFUNC + +FUNCTION SetDrisExecsDecrement(mydris, myexecs) + SET4BYTES(@mydris, 25, myexecs) +ENDFUNC + +FUNCTION SetDrisDataCryptKeyNum(mydris, mykey) + SET4BYTES(@mydris, 29, mykey) +ENDFUNC + +FUNCTION SetDrisRWOffset(mydris, myoffset) + SET4BYTES(@mydris, 33, myoffset) +ENDFUNC + +FUNCTION SetDrisRWLength(mydris, mylength) + SET4BYTES(@mydris, 37, mylength) +ENDFUNC + +FUNCTION SetDrisAltLicenceName(mydris, alt_licence_name) + alt_licence_name = alt_licence_name + Chr(0) && null-terminate this string + mydris = STUFF(mydris, 45, 256, alt_licence_name) +ENDFUNC + +FUNCTION SetDrisAlgVars(mydris, var_a, var_b, var_c, var_d, var_e, var_f, var_g, var_h) + SET4BYTES(@mydris, 301, var_a) + SET4BYTES(@mydris, 305, var_b) + SET4BYTES(@mydris, 309, var_c) + SET4BYTES(@mydris, 313, var_d) + SET4BYTES(@mydris, 317, var_e) + SET4BYTES(@mydris, 321, var_f) + SET4BYTES(@mydris, 325, var_g) + SET4BYTES(@mydris, 329, var_h) +ENDFUNC + +FUNCTION SetDrisAlgNumber(mydris, alg_num) + SET4BYTES(@mydris, 333, alg_num) +ENDFUNC + +*** these functions let you get values from the DRIS (NB offsets are 1-based) +FUNCTION GetDrisVarA(mydris) && you may want to use these functions if you set dris vars to be random + RETURN GET4BYTES(mydris, 301) +ENDFUNC + +FUNCTION GetDrisVarB(mydris) + RETURN GET4BYTES(mydris, 305) +ENDFUNC + +FUNCTION GetDrisVarC(mydris) + RETURN GET4BYTES(mydris, 309) +ENDFUNC + +FUNCTION GetDrisVarD(mydris) + RETURN GET4BYTES(mydris, 313) +ENDFUNC + +FUNCTION GetDrisVarE(mydris) + RETURN GET4BYTES(mydris, 317) +ENDFUNC + +FUNCTION GetDrisVarF(mydris) + RETURN GET4BYTES(mydris, 321) +ENDFUNC + +FUNCTION GetDrisVarG(mydris) + RETURN GET4BYTES(mydris, 325) +ENDFUNC + +FUNCTION GetDrisVarH(mydris) + RETURN GET4BYTES(mydris, 329) +ENDFUNC + +FUNCTION GetDrisSeed1(mydris) && you will want to use these functions if you set the seed values to be random + RETURN GET4BYTES(mydris, 9) +ENDFUNC + +FUNCTION GetDrisSeed2(mydris) + RETURN GET4BYTES(mydris, 13) +ENDFUNC + +FUNCTION GetDrisRetCode(mydris) + RETURN GET4BYTES(mydris, 337) +ENDFUNC + +FUNCTION GetDrisExtErr(mydris) + RETURN GET4BYTES(mydris, 341) +ENDFUNC + +FUNCTION GetDrisType(mydris) + RETURN GET4BYTES(mydris, 345) +ENDFUNC + +FUNCTION GetDrisModel(mydris) + RETURN GET4BYTES(mydris, 349) +ENDFUNC + +FUNCTION GetDrisSDSN(mydris) + RETURN GET4BYTES(mydris, 353) +ENDFUNC + +FUNCTION GetDrisProdCode(mydris) + * first find the length of the Product Code + FOR len = 0 TO 11 + c = SUBSTR(mydris, 357+len, 1) + IF c = CHR(0) + EXIT + ENDIF + ENDFOR + RETURN SUBSTR(mydris, 357, len) +ENDFUNC + +FUNCTION GetDrisDongleNumber(mydris) + RETURN GET4BYTES(mydris, 369) +ENDFUNC + +FUNCTION GetDrisUpdateNumber(mydris) + RETURN GET4BYTES(mydris, 373) +ENDFUNC + +FUNCTION GetDrisDataAreaSize(mydris) + RETURN GET4BYTES(mydris, 377) +ENDFUNC + +FUNCTION GetDrisMaxAlgNum(mydris) + RETURN GET4BYTES(mydris, 381) +ENDFUNC + +FUNCTION GetDrisExecs(mydris) + RETURN GET4BYTES(mydris, 385) +ENDFUNC + +FUNCTION GetDrisExpDay(mydris) + RETURN GET4BYTES(mydris, 389) +ENDFUNC + +FUNCTION GetDrisExpMonth(mydris) + RETURN GET4BYTES(mydris, 393) +ENDFUNC + +FUNCTION GetDrisExpYear(mydris) + RETURN GET4BYTES(mydris, 397) +ENDFUNC + +FUNCTION GetDrisFeatures(mydris) + RETURN GET4BYTES(mydris, 401) +ENDFUNC + +FUNCTION GetDrisNetUsers(mydris) + RETURN GET4BYTES(mydris, 405) +ENDFUNC + +FUNCTION GetDrisAlgAnswer(mydris) + RETURN GET4BYTES(mydris, 409) +ENDFUNC + +FUNCTION GetDrisFDCapacity(mydris) + RETURN GET4BYTES(mydris, 413) +ENDFUNC + +FUNCTION GetDrisFDDrive(mydris) + RETURN SUBSTR(mydris, 417, 3) +ENDFUNC + +FUNCTION GetDrisSWKeyType(mydris) + RETURN GET4BYTES(mydris, 545) +ENDFUNC + +FUNCTION GetDrisSWKeyExpDay(mydris) + RETURN GET4BYTES(mydris, 549) +ENDFUNC + +FUNCTION GetDrisSWKeyExpMonth(mydris) + RETURN GET4BYTES(mydris, 553) +ENDFUNC + +FUNCTION GetDrisSWKeyExpYear(mydris) + RETURN GET4BYTES(mydris, 557) +ENDFUNC + + +*** displays messages for the most common errors. You will want to change this for your code +FUNCTION DisplayError(mydris, ret_code) + DO CASE + CASE ret_code = 401 + ? "Error! No dongles detected!" + + CASE ret_code = 403 + ? "Error! The dongle detected has a different type to the one specified in DinkeyAdd." + + CASE ret_code = 404 + ? "Error! The dongle detected has a different model to those specified in DinkeyAdd." + + CASE ret_code = 409 + ? "Error! The dongle detected has not been programmed by DinkeyAdd." + + CASE ret_code = 410 + ? "Error! The dongle detected has a different Product Code to the one specified in DinkeyAdd." + + CASE ret_code = 411 + ? "Error! The dongle detected does not contain the licence associated with this program." + + CASE ret_code = 413 + ? "Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual." + + CASE ret_code = 417 + ? "Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa." + + CASE ret_code = 423 + ? "Error! The number of network users has been exceeded." + + CASE ret_code = 435 + ? "Error! DinkeyServer has not been detected on the network." + + CASE ret_code = 922 + ? "Error! The Software Key has expired." + + OTHERWISE + ? "An error occurred checking the dongle. Error: " + STR(ret_code) + " Extended Error: " + STR(GetDrisExtErr(mydris)) + + ENDCASE + RETURN +ENDFUNC diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Java/DinkeyChange/DCSample.java b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Java/DinkeyChange/DCSample.java new file mode 100644 index 0000000..cbd86f9 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Java/DinkeyChange/DCSample.java @@ -0,0 +1,322 @@ +// A simple program illustrating how to use the DinkeyChange API in Java. +// Copyright 2018 Microcosm Ltd. + +import uk.microcosm.dinkeydongle.DinkeyChange; +import uk.microcosm.dinkeydongle.DinkeyChangeException; +import uk.microcosm.dinkeydongle.DongleToChange; + +import java.io.*; + +public class DCSample +{ + public static void main(String[] args) + { + String userChoice = ""; + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + + // Prompt the user for the DinkeyChange operation to perform + System.out.println(); + System.out.println("1) Display information about dongles attached to this computer"); + System.out.println("2) Save diagnostic information to a file"); + System.out.println("3) Apply an update code from a file"); + System.out.println("4) Apply a short update code"); + System.out.println("5) Restore a Dinkey FD Lite dongle"); + System.out.println("6) Display this computer's machine ID"); + System.out.println("7) Download and install a temporary software key"); + System.out.println("8) Download and install a demo software key"); + System.out.print("Enter an option 1 to 8. Enter anything else to exit: "); + try + { + userChoice = br.readLine(); + } + catch (IOException e) + { + System.err.println(e.getMessage()); + System.exit(1); + } + System.out.println(); + + if (userChoice.equals("1")) + { + /* DinkeyChange.getDongles() - get information about dongles attached to this computer. + This method returns an array of DongleToChange objects. You can use this method's arguments + to control which dongles it searches for - see README.html for more information. */ + + int i; + DongleToChange[] dongles; + + try + { // Search for all types and models of dongle, with any product code + dongles = DinkeyChange.getDongles(DinkeyChange.TYPE_MASK_ALL, DinkeyChange.MODEL_MASK_ALL, ""); + + for (i = 0; i < dongles.length; i++) + { + /* Display information about each dongle found that matched the search criteria. + This information is needed by DinkeyRemote to create update codes for these dongles. */ + + System.out.println((i+1) + ": Dinkey " + dongles[i].typeAsString + " " + dongles[i].modelAsString); + System.out.println("\tDongle Number: " + dongles[i].dongleNumber); + System.out.println("\tProduct Code: " + dongles[i].productCode); + System.out.println("\tUpdate Number: " + dongles[i].updateNumber); + } + } + catch (DinkeyChangeException e) + { + displayError(e); + } + } + + else if (userChoice.equals("2")) + { + /* DinkeyChange.writeDiagnosticsToFile() - this method creates an encrypted DLPF file containing diagnostics + and the parameters stored in each dongle currently attached to this computer. This file can be opened with DinkeyLook. + This method can take a String or File argument, i.e. DinkeyChange.writeDiagnosticsToFile("out.dlpf") + is exactly equivalent to DinkeyChange.writeDiagnosticsToFile(new File("out.dlpf")) */ + + String filename = null; + + // Prompt for the name of the DLPF file to create. + // This file's path can be absolute, or relative to the current working directory. + // If the name does not include a ".dlpf" extension, it will automatically be added. + System.out.print("Enter output filename: "); + try + { + filename = br.readLine(); + } + catch (IOException e) + { + System.err.println(e.getMessage()); + } + + try + { // If successful, DinkeyChange.writeDiagnosticsToFile() returns the full path to the file it created + System.out.println("Diagnostics written to " + DinkeyChange.writeDiagnosticsToFile(new File(filename))); + } + catch (DinkeyChangeException e) + { + displayError(e); + } + } + + else if (userChoice.equals("3")) + { + /* DinkeyChange.applyUpdate(File) - this method takes a File object representing + a secure update code file (DUCF file) and applies the code to the relevant dongle + attached to this computer, updating the parameters stored in that dongle. */ + + File f; + String filename = null; + String confirmationCode; + + // Prompt user for location of DUCF file. + // The path to the file can be absolute, or relative to the current working directory + System.out.print("Enter secure update code filename: "); + try + { + filename = br.readLine(); + } + catch (IOException e) + { + System.err.println(e.getMessage()); + } + + f = new File(filename); // Create a File object representing the DUCF file + try + { // If successful, DinkeyChange.applyUpdate() returns the confirmation code for this update + confirmationCode = Integer.toHexString(DinkeyChange.applyUpdate(f)); + System.out.println("Update code successfully applied. Confirmation code is " + confirmationCode); + } + catch (DinkeyChangeException e) + { + displayError(e); + } + } + + else if (userChoice.equals("4")) + { + /* DinkeyChange.applyUpdate(String) - this method takes a short secure update code + and applies it to the relevant dongle attached to this computer, updating the parameters + stored in that dongle. */ + + String updateCode = null; + String confirmationCode; + + // Prompt the user for the short update code + System.out.print("Enter update code: "); + try + { + updateCode = br.readLine(); + } + catch (IOException e) + { + System.err.println(e.getMessage()); + } + + try + { // If successful, DinkeyChange.applyUpdate() returns the confirmation code for this update + confirmationCode = Integer.toHexString(DinkeyChange.applyUpdate(updateCode)); + System.out.println("Update code successfully applied. Confirmation code is " + confirmationCode); + } + catch (DinkeyChangeException e) + { + displayError(e); + } + } + + else if (userChoice.equals("5")) + { + // DinkeyChange.restoreDinkeyFDLite() - restore a Dinkey FD Lite dongle + + try + { + DinkeyChange.restoreDinkeyFDLite(); + System.out.println("Dinkey FD Lite restored successfully."); + } + catch (DinkeyChangeException e) + { + displayError(e); + } + } + + else if (userChoice.equals("6")) + { + // DinkeyChange.getMachineID() - get this computer's machine ID + + String machineIDString; + + try + { + machineIDString = Long.toHexString(DinkeyChange.getMachineID()); + System.out.println("The Machine ID is " + machineIDString); + } + catch (DinkeyChangeException e) + { + displayError(e); + } + } + + else if (userChoice.equals("7")) + { + // DinkeyChange.downloadTempSoftwareKey() - download and install a temporary software key + + try + { + DinkeyChange.downloadTempSoftwareKey(); + System.out.println("The temporary software key has been downloaded successfully."); + } + catch (DinkeyChangeException e) + { + displayError(e); + } + } + + else if (userChoice.equals("8")) + { + // DinkeyChange.downloadDemoSoftwareKey() - download and install a demo software key + + String productCode = null; + + // Prompt for the product code to use + System.out.print("Enter product code of demo software key: "); + try + { + productCode = br.readLine(); + } + catch (IOException e) + { + System.err.println(e.getMessage()); + } + + try + { + // This examples assumes that exactly one dongle model is set in the demo template + // If multiple models are set in the template you will need to use the second parameter to specify which model to download and install + DinkeyChange.downloadDemoSoftwareKey(productCode, DinkeyChange.SWKEY_MODEL_DEFAULT); + System.out.println("The demo software key has been downloaded successfully."); + } + catch (DinkeyChangeException e) + { + displayError(e); + } + } + + System.exit(0); + + } // End of main() + + + // An example of error reporting + // Displays descriptions for some common error codes + static void displayError(DinkeyChangeException e) + { + switch (e.getError()) + { + case 401: + System.out.println("Error! No dongles detected that meet the search criteria!"); + break; + + case 409: + System.out.println("Error! The dongle detected has not been programmed by DinkeyAdd."); + break; + + case 758: + System.out.println("Error! Cannot open the update code file specified."); + break; + + case 759: + System.out.println("Error! The file specified is not a valid update code file."); + break; + + case 762: + case 763: + case 764: + System.out.println("Error! Update code is not in a correct format / update code file is corrupt."); + break; + + case 765: + System.out.println("Error! The update code does not match any dongle attached to your machine."); + break; + + case 766: + System.out.println("Error! The update number for this update code is too high. You need to first enter an update code that was previously sent to you."); + break; + + case 767: + System.out.println("Error! You have already entered this update code."); + break; + + case 1905: + System.out.println("Error! There is no software key available for download."); + break; + + case 1907: + System.out.println("Error! The temporary software key has expired. Cannot download it."); + break; + + case 1910: + System.out.println("Error! The software key has already been downloaded."); + break; + + case 1921: + System.out.println("Error! You specified the 'default model' but there is more than one model available. You need to specify a specific dongle model."); + break; + + case 1922: + System.out.println("Error! The model you requested is not available."); + break; + + case 1923: + System.out.println("Error! The demo software key template has been disabled."); + break; + + case 1924: + System.out.println("Error! You have run out of demo software key activations. You need to order some more."); + break; + + default: + System.err.println("DinkeyChange error " + e.getError() + ":" + e.getExtendedError()); + System.err.println(e.getMessage()); + } + } + +} // End of class DCSample diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Java/DinkeyChange/README.html b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Java/DinkeyChange/README.html new file mode 100644 index 0000000..6f47dee --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Java/DinkeyChange/README.html @@ -0,0 +1,335 @@ + + + + + Using the DinkeyChange API with Java + + + +

Using the DinkeyChange API with Java

+

+ The DinkeyChange API allows you apply secure update codes to modify the information + stored in Dinkey Pro and FD dongles directly from your Java application. + The API also allows you to view the information needed to create these codes, and produce + encrypted diagnostic files to help you troubleshoot any dongle-related problems your users might have. +

+

+ The DinkeyChange class provides a Java wrapper around the API, which is implemented by native libraries. + If you are not familiar with calling native libraries, it is recommended that you read the Java documentation on the subject, + especially the documentation for System.loadLibrary(), + and how Java uses the system property java.library.path to locate native libraries. +

+

+ The native libraries and the classes described below are part of the uk.microcosm.dinkeydongle package. + See the documentation for your development environment for details of how to include and reference this package in your project. + dinkeydongle.jar provides all of the Java classes in the uk.microcosm.dinkeydongle package in a single JAR file. + This allows you to import the package much more easily in many Java IDEs. Note that the native libraries are not included in the JAR file. + You will need to distribute with your software the native libraries for every platform that your software supports. +

+ +

The DinkeyChange Class

+

+ This class exposes the DinkeyChange API to Java programs. + It contains only static methods and fields, and cannot be instantiated. +

+ +

Fields

+

+ Useful constants you can use in your code: +

+
    +
  • static final int MAX_USB_DEVICES - maximum number of dongles that the API can return information about.
  • +
  • static final int MAX_PRODCODE_LEN - maximum length of a product code string.
  • +
+

+ Possible values to use as the typeMask parameter of DinkeyChange.getDongles(): +

+
    +
  • static final int TYPE_MASK_PRO - search for Dinkey Pro dongles only.
  • +
  • static final int TYPE_MASK_FD - search for Dinkey FD dongles only.
  • +
  • static final int TYPE_MASK_ALL - search for both Dinkey Pro and FD dongles.
  • +
+

+ Possible values to use as the modelMask parameter of DinkeyChange.getDongles(): +

+
    +
  • static final int MODEL_MASK_LITE - search for Lite dongles only.
  • +
  • static final int MODEL_MASK_PLUS - search for Plus dongles only.
  • +
  • static final int MODEL_MASK_NET - search for Net dongles only.
  • +
  • static final int MODEL_MASK_ALL - search for all models of dongle.
  • +
  • static final int MODEL_MASK_DEFAULT - search only for models that can be modified using update codes (i.e. ignore Lite dongles.)
  • +
+

+ Possible values to use as the model parameter of DinkeyChange.downloadDemoSoftwareKey(): +

+
    +
  • static final int SWKEY_MODEL_DEFAULT - download the default model (valid only if exactly one model is set in the demo key template).
  • +
  • static final int SWKEY_MODEL_PRO_LITE - download a Pro Lite demo software key.
  • +
  • static final int SWKEY_MODEL_PRO_PLUS - download a Pro Plus demo software key.
  • +
  • static final int SWKEY_MODEL_PRO_NET - download a Pro Net demo software key.
  • +
  • static final int SWKEY_MODEL_FD_LITE - download an FD Lite demo software key.
  • +
  • static final int SWKEY_MODEL_FD_PLUS - download an FD Plus demo software key.
  • +
  • static final int SWKEY_MODEL_FD_NET - download an FD Net demo software key.
  • +
+ +

Methods

+

+ All methods in this class throw a DinkeyChangeException if the underlying native API call fails. + The DinkeyChangeException contains the error code and extended error code returned by the native API function. +

+ +

static DongleToChange[] getDongles(int typeMask, int modelMask, String productCodeMask)

+

+ Returns a list of the dongles attached to this computer that match the search criteria specified by the method's arguments. + typeMask and modelMask should be set to one of the possible values listed above. + If productCodeMask is specified, only dongles with a product code that exactly matches (case is not important) this string will be returned. + In most cases this string will be the product code of your protected application. + Use null or the empty string as this parameter to search for dongles with any product code. +

+ +

static String writeDiagnosticsToFile(String filename)

+

+ Writes diagnostic information about all dongles connnected to this computer to the file specified by filename. + The output file is encrypted, and its contents can only be viewed using DinkeyLook. + The path to the file can be absolute, or relative to the current working directory. + If the filename does not end in ".dlpf" this extension will be added automatically. + This method returns the absolute path to the file created. +

+ +

static String writeDiagnosticsToFile(java.io.File file)

+

+ Writes diagnostic information about all dongles connnected to this computer to the file represented by file. + The output file is encrypted, and its contents can only be viewed using DinkeyLook. + The path to the file can be absolute, or relative to the current working directory. + If the filename does not end in ".dlpf" this extension will be added automatically. + This method returns the absolute path to the file created. +

+ +

static int applyUpdate(String updateCode)

+

+ Applies a short secure update code to a dongle connected to this computer. + Returns the confirmation code for this update. +

+ +

static int applyUpdate(java.io.File updateFile)

+

+ Applies the secure update code in the file represented by updateFile to a dongle connected to this computer. + Returns the confirmation code for this update. +

+ +

static void restoreDinkeyFDLite()

+

+ Restores the hidden .DO NOT DELETE.dat on a Dinkey FD Lite dongle. +

+ +

static long getmachineID()

+

+ Returns the machine ID required to generate a temporary software key for this computer. +

+ +

static void downloadTempSoftwareKey()

+

+ Downloads and installs a temporary software key that was created by DinkeyAdd. +

+ +

static void downloadDemoSoftwareKey(String productCode, int model)

+

+ Downloads and installs a demo software key from a demo template that was created by DinkeyAdd. + productCode specifies the product code of the demo template to download the key from. + model specifies the model of demo key to download, and should be set to one of the values listed above. +

+ +

The DongleToChange Class

+

+ An instance of DongleToChange represents one dongle found by DinkeyChange.getDongles(). +

+ +

Fields

+

+ Possible values for type: +

+
    +
  • static final int TYPE_PRO - a Dinkey Pro dongle.
  • +
  • static final int TYPE_FD - a Dinkey FD dongle.
  • +
+

+ Possible values for mask: +

+
    +
  • static final int MODEL_LITE - a Lite dongle.
  • +
  • static final int MODEL_PLUS - a Plus dongle.
  • +
  • static final int MODEL_NET5 - a Net dongle (5 users).
  • +
  • static final int MODEL_NETU - a Net dongle (unlimited users).
  • +
+

+ Fields that provide information needed to create an update code for this dongle: +

+
    +
  • final int type - integer representation of the dongle type.
  • +
  • final String typeAsString - string representation of the dongle type.
  • +
  • final int model - integer representation of the dongle model.
  • +
  • final String modelAsString - string representation of the dongle model.
  • +
  • final String productCode - the dongle's product code.
  • +
  • final long dongleNumber - the dongle's dongle number (sometimes called dongle serial number).
  • +
  • final int updateNumber - the dongle's update number.
  • +
+ +

The DinkeyChangeException Class

+

+ An instance of this Exception subclass is thrown if a call to the DinkeyChange API fails. + The usual getMessage() method returns a string providing general information about the error. + If the problem occurred in Java code, getCause() will return the Java exception that caused the DinkeyChangeException. +

+ +

Methods

+

+ DinkeyChangeException's methods provide further details about the error that occurred. + It is strongly recommended that you display this information in the event of an error, + to help both you and us troubleshoot a recurring problem. + More information about Dinkey Pro/FD error numbers can be found in the user manual chapter Error Codes + and online in our knowledge base. +

+

int getError()

+

+ Returns an error code indicating the cause of the error. +

+

int getExtendedError()

+

+ Returns an extended error code providing additional information about the error. +

+ +

Java Example Files

+
    +
  • DCSample.java - various examples of using the DinkeyChange classes.
  • +
+ +

Supported Versions

+

+ All parts of the uk.microcosm.dinkeydongle package support Java platforms version 5 and newer. +

+ +

Try It Yourself

+

+ DCSample.java gives a simple example of calling each of the API functions. + To run the DCSample program you will need a copy of the appropriate shared library for your platform + (DinkeyChange.dll for 32-bit Windows, DinkeyChange64.so for 64-bit Linux etc.). + Place the library in one of the paths specified by your Java environment's java.library.path system property. + Browse the examples in DCSample.java to see how different features can be used. +

+ + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Java/Runtime/DPSample.java b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Java/Runtime/DPSample.java new file mode 100644 index 0000000..3c93108 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Java/Runtime/DPSample.java @@ -0,0 +1,612 @@ +// Example use of the Dinkey Pro/FD API in Java. +// Copyright 2018 Microcosm Ltd. + +import uk.microcosm.dinkeydongle.DinkeyPro; +import java.util.Arrays; // For Arrays.toString() + +class DPSample +{ + static final String MY_PRODCODE = "DEMO"; // !!!! Replace "DEMO" with the product code that you specify when adding protection with DinkeyAdd. + static final int MY_SDSN = 10101; // !!!! "10101" is the SDSN used by the demo SDK and demo dongles. + // If not using a demo, replace "10101" with your own SDSN here. + + static final int DRIS_ENCRYPTION_PARAMETER_1 = 123; // !!!! If you enable DRIS encryption when adding protection with DinkeyAdd, + static final int DRIS_ENCRYPTION_PARAMETER_2 = 212; // replace these values with the encryption parameters that you specify. + static final int DRIS_ENCRYPTION_PARAMETER_3 = 97; + + public static void main(String[] args) + { + // Each of the methods below demonstrates different API functionality. + // Uncomment the appropriate methods to execute the examples. + // See the comments in each method for more details about the features that they demonstrate. + + protCheck(); + // protCheckWithAlg(); + // writeDataArea(); + // readDataArea(); + // encryptUserData(); + // protCheckEnc(); + // writeDataAreaEnc(); + // readDataAreaEnc(); + // encryptUserDataEnc(); + // displayNetUsers(); + } + + // An example of a basic protection check + static void protCheck() + { + int retCode; + + // Create a DinkeyPro instance that uses the default library name, DPJava. + // All DRIS fields are initialised to random values. + DinkeyPro ddpro = new DinkeyPro(); + + // You can use an alternative library name like this: + // DinkeyPro ddpro = new DinkeyPro("MyName"); + // The manner in which the library name is mapped to the actual system library is system dependent, + // but common behaviour is that Java will attempt to locate and load MyName.dll on Windows, libMyName.dylib on macOS, + // or libMyName.so on Linux. + + // You can also specify the full path to the library, if it is not located in one of the paths specified by java.library.path, + // or uses a non-standard filename: + // Dinkey ddpro = new DinkeyPro("~/Unusual Folder For Libraries/nonstandardname.jnilib"); + + // Initialise the DRIS + ddpro.function = DinkeyPro.PROTECTION_CHECK; + ddpro.flags = DinkeyPro.DEC_ONE_EXEC | DinkeyPro.START_NET_USER; + + // Call the API + retCode = ddpro.checkProtection(); + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + // ... + + // You can check other values from the DRIS in other parts of your program to improve security. + // For example: + + // Check the SDSN + if (ddpro.sdsn != MY_SDSN) + { + System.out.println("Incorrect SDSN! Have you replaced '10101' with your SDSN in the sample code?"); + return; + } + + // Check the product code + if (!(ddpro.getProdCode().equals(MY_PRODCODE))) + { + System.out.println("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle."); + return; + } + + System.out.println("Protection check successful."); + return; + } + + // An example of a protection check that also executes an algorithm stored in the dongle. + // The best way to use this feature is to identify lines of code in your program + // that can be represented by algorithms stored in the dongle, + // and replace these lines with calls to the API. + // Lite dongle users cannot change the algorithm stored in the dongles, + // so should calculate the algorithm in their own code and compare the result with the one returned by the API, + // as in this example. + static void protCheckWithAlg() + { + int retCode; + DinkeyPro ddpro = new DinkeyPro(); + + // Initialise the DRIS + ddpro.function = DinkeyPro.EXECUTE_ALGORITHM; + ddpro.flags = 0; + ddpro.alg_number = 1; // The algorithm to execute. Lite dongles ignore this field, as they contain only 1 algorithm + ddpro.var_a = 1; // The input variables to use in the algorithm + ddpro.var_b = 2; + ddpro.var_c = 3; + ddpro.var_d = 4; + ddpro.var_e = 5; + ddpro.var_f = 6; + ddpro.var_g = 7; + ddpro.var_h = 8; + + // Call the API + retCode = ddpro.checkProtection(); + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + // ... + + // Check the algorithm result in another part of your program to improve security. + // !!!! Ensure the myAlgorithm() method matches the algorithm that was executed by the protection check! + if (myAlgorithm(ddpro.var_a, ddpro.var_b, ddpro.var_c, ddpro.var_d, ddpro.var_e, ddpro.var_f, ddpro.var_g, ddpro.var_h) != ddpro.alg_answer) + { + System.out.println("Error! The algorithm result was not as expected."); + return; + } + + System.out.println("Protection check with algorithm successful."); + return; + } + + // An example of a protection check that also writes data to the dongle's secure data area. + // This feature is not supported by Lite dongles. + // Make sure you specify a large enough data area size when adding protection with DinkeyAdd! + static void writeDataArea() + { + int retCode; + DinkeyPro ddpro = new DinkeyPro(); + byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // Data to write + + // Initialise the DRIS + ddpro.function = DinkeyPro.WRITE_DATA_AREA; + ddpro.flags = DinkeyPro.USE_FUNCTION_ARGUMENT; // Java uses DDProtCheck()'s data parameter, so this flag must be set + ddpro.rw_offset = 0; // Index to start writing at. Indices start at zero + ddpro.rw_length = data.length; // The number of bytes to be written + + // Call the API + retCode = ddpro.checkProtection(data); + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + // You can inspect the dongle with DinkeyLook to see that the data has been written to the dongle + + System.out.println("Writing data successful."); + return; + } + + // An example of a protection check that also reads data from the dongle's secure data area. + // This feature is not supported by Lite dongles. + // Make sure you specify a large enough data area size when adding protection with DinkeyAdd! + static void readDataArea() + { + int retCode; + DinkeyPro ddpro = new DinkeyPro(); + byte[] data = new byte[10]; + + // Initialise the DRIS + ddpro.function = DinkeyPro.READ_DATA_AREA; + ddpro.flags = DinkeyPro.USE_FUNCTION_ARGUMENT; // Java uses DDProtCheck()'s data parameter, so this flag must be set + ddpro.rw_offset = 0; // Index to start reading from. Indices start at zero + ddpro.rw_length = data.length; // The number of bytes to read + + // Call the API + retCode = ddpro.checkProtection(data); + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + System.out.println("Reading data successful: " + Arrays.toString(data)); + return; + } + + // An example of protection checks that encrypt/decrypt your data. + // This feature is not supported by Lite dongles. + static void encryptUserData() + { + int retCode; + DinkeyPro ddpro = new DinkeyPro(); + byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // The data to be encrypted + byte[] originalData = data.clone(); // A copy of the data for displaying later + byte[] encryptedData; + + // Initialise the DRIS + ddpro.function = DinkeyPro.ENCRYPT_USER_DATA; + ddpro.flags = DinkeyPro.USE_FUNCTION_ARGUMENT; // Java uses DDProtCheck()'s data parameter, so this flag must be set + ddpro.rw_length = data.length; // The number of bytes to be encrypted + ddpro.data_crypt_key_num = 1; // The encryption key to use + + // Call the API + retCode = ddpro.checkProtection(data); + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + encryptedData = data.clone(); // A copy of the encrypted data for displaying later + + // Initialise the DRIS + ddpro.reset(); // Reset the DRIS fields with random values + ddpro.function = DinkeyPro.DECRYPT_USER_DATA; + ddpro.flags = DinkeyPro.USE_FUNCTION_ARGUMENT; // Java uses DDProtCheck()'s data parameter, so this flag must be set + ddpro.rw_length = data.length; + ddpro.data_crypt_key_num = 1; // This must be the same key used to encrypt the data + + // Call the API + retCode = ddpro.checkProtection(data); + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + System.out.println("Data encryption successful."); + System.out.println("Original data: " + Arrays.toString(originalData)); + System.out.println("Encrypted data: " + Arrays.toString(encryptedData)); + System.out.println("Decrypted data: " + Arrays.toString(data)); + return; + } + + // An example of a protection check that uses DRIS encryption for extra security. + static void protCheckEnc() + { + int retCode; + DinkeyPro ddpro = new DinkeyPro(); + + // Initialise the DRIS + ddpro.function = DinkeyPro.PROTECTION_CHECK; + ddpro.flags = 0; + + // Encrypt the DRIS + ddpro.cryptDris(DRIS_ENCRYPTION_PARAMETER_1, DRIS_ENCRYPTION_PARAMETER_2, DRIS_ENCRYPTION_PARAMETER_3); + + // Call the API + retCode = ddpro.checkProtection(); + + // Decrypt the DRIS + ddpro.cryptDris(DRIS_ENCRYPTION_PARAMETER_1, DRIS_ENCRYPTION_PARAMETER_2, DRIS_ENCRYPTION_PARAMETER_3); + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + // ... + + // You can check other values from the DRIS in other parts of your program to improve security. + // For example: + + // Check the SDSN + if (ddpro.sdsn != MY_SDSN) + { + System.out.println("Incorrect SDSN! Have you replaced '10101' with your SDSN in the sample code?"); + return; + } + + // Check the product code + if (!(ddpro.getProdCode().equals(MY_PRODCODE))) + { + System.out.println("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle."); + return; + } + + System.out.println("Protection check successful."); + return; + } + + // An example of a protection check that also writes data to the dongle's secure data area. + // This feature is not supported by Lite dongles. + // Make sure you specify a large enough data area size when adding protection with DinkeyAdd! + // This method also uses DRIS encryption and data encryption for extra security. + // You must select these options on the Extra Security tab of DinkeyAdd for this method to work correctly! + static void writeDataAreaEnc() + { + int retCode, algAnswer; + DinkeyPro ddpro = new DinkeyPro(); + byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // The data to be written + + // Initialise the DRIS + ddpro.function = DinkeyPro.WRITE_DATA_AREA; + ddpro.flags = DinkeyPro.USE_FUNCTION_ARGUMENT; // Java uses DDProtCheck()'s data parameter, so this flag must be set + ddpro.rw_offset = 0; // Index to start writing at. Indices start at zero + ddpro.rw_length = data.length; // The number of bytes to write + + // If taking data encryption parameters from the R/W algorithm: + // Calculate the R/W algorithm result + // The input variables were initialised to random values when ddpro was created + algAnswer = myRwAlgorithm(ddpro.var_a, ddpro.var_b, ddpro.var_c, ddpro.var_d, ddpro.var_e, ddpro.var_f, ddpro.var_g, ddpro.var_h); + + // Use the algorithm result to encrypt the data to be written to the dongle + ddpro.cryptApiData(data, algAnswer); + + // If using constant data encryption parameters: + // ddpro.cryptApiData(data, DATA_ENCRYPTION_PARAMETER_1, DATA_ENCRYPTION_PARAMETER_2, DATA_ENCRYPTION_PARAMETER_3); + + // Encrypt the DRIS + ddpro.cryptDris(DRIS_ENCRYPTION_PARAMETER_1, DRIS_ENCRYPTION_PARAMETER_2, DRIS_ENCRYPTION_PARAMETER_3); + + // Call the API + retCode = ddpro.checkProtection(data); + + // Decrypt the DRIS + ddpro.cryptDris(DRIS_ENCRYPTION_PARAMETER_1, DRIS_ENCRYPTION_PARAMETER_2, DRIS_ENCRYPTION_PARAMETER_3); + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + System.out.println("Writing data successful."); + return; + } + + // An example of a protection check that also reads data from the dongle's secure data area. + // This feature is not supported by Lite dongles. + // Make sure you specify a large enough data area size when adding protection with DinkeyAdd! + // This method also uses DRIS encryption and data encryption for extra security. + // You must select these options on the Extra Security tab of DinkeyAdd for this method to work correctly! + static void readDataAreaEnc() + { + int retCode, algAnswer; + DinkeyPro ddpro = new DinkeyPro(); + byte[] data = new byte[10]; + + // Initialise the DRIS + ddpro.function = DinkeyPro.READ_DATA_AREA; + ddpro.flags = DinkeyPro.USE_FUNCTION_ARGUMENT; // Java uses DDProtCheck()'s data parameter, so this flag must be set + ddpro.rw_offset = 0; // Index to start reading from. Indices start at zero + ddpro.rw_length = data.length; // The number of bytes to read + + // Encrypt the DRIS + ddpro.cryptDris(DRIS_ENCRYPTION_PARAMETER_1, DRIS_ENCRYPTION_PARAMETER_2, DRIS_ENCRYPTION_PARAMETER_3); + + // Call the API + retCode = ddpro.checkProtection(data); + + // Decrypt the DRIS + ddpro.cryptDris(DRIS_ENCRYPTION_PARAMETER_1, DRIS_ENCRYPTION_PARAMETER_2, DRIS_ENCRYPTION_PARAMETER_3); + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + // If taking data encryption parameters from the R/W algorithm: + // Calculate the R/W algorithm result + // The input variables were initialised to random values when ddpro was created + algAnswer = myRwAlgorithm(ddpro.var_a, ddpro.var_b, ddpro.var_c, ddpro.var_d, ddpro.var_e, ddpro.var_f, ddpro.var_g, ddpro.var_h); + + // Use the algorithm result to decrypt the data read from the dongle + ddpro.cryptApiData(data, algAnswer); + + // If using constant data encryption parameters: + // ddpro.cryptApiData(data, DATA_ENCRYPTION_PARAMETER_1, DATA_ENCRYPTION_PARAMETER_2, DATA_ENCRYPTION_PARAMETER_3); + + System.out.println("Reading data successful: " + Arrays.toString(data)); + return; + } + + // An example of protection checks that encrypt/decrypt your data. + // This feature is not supported by Lite dongles. + // This method also uses DRIS encryption and data encryption for extra security. + // You must select these options on the Extra Security tab of DinkeyAdd for this method to work correctly! + static void encryptUserDataEnc() + { + int retCode, algAnswer; + DinkeyPro ddpro = new DinkeyPro(); + byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // The data to be encrypted + byte[] originalData = data.clone(); // A copy of the data for displaying later + byte[] encryptedData; + + // Initialise the DRIS + ddpro.function = DinkeyPro.ENCRYPT_USER_DATA; + ddpro.flags = DinkeyPro.USE_FUNCTION_ARGUMENT; // Java uses DDProtCheck()'s data parameter, so this flag must be set + ddpro.rw_length = data.length; // The number of bytes to be encrypted + ddpro.data_crypt_key_num = 1; // The encryption key to use + + // If taking data encryption parameters from the R/W algorithm: + // Calculate the R/W algorithm result + // The input variables were initialised to random values when ddpro was created + algAnswer = myRwAlgorithm(ddpro.var_a, ddpro.var_b, ddpro.var_c, ddpro.var_d, ddpro.var_e, ddpro.var_f, ddpro.var_g, ddpro.var_h); + + // Use the algorithm result to encrypt the data passed to the API + ddpro.cryptApiData(data, algAnswer); + + // If using constant data encryption parameters: + // ddpro.cryptApiData(data, DATA_ENCRYPTION_PARAMETER_1, DATA_ENCRYPTION_PARAMETER_2, DATA_ENCRYPTION_PARAMETER_3); + + // Encrypt the DRIS + ddpro.cryptDris(DRIS_ENCRYPTION_PARAMETER_1, DRIS_ENCRYPTION_PARAMETER_2, DRIS_ENCRYPTION_PARAMETER_3); + + // Call the API + retCode = ddpro.checkProtection(data); + + // Decrypt the DRIS + ddpro.cryptDris(DRIS_ENCRYPTION_PARAMETER_1, DRIS_ENCRYPTION_PARAMETER_2, DRIS_ENCRYPTION_PARAMETER_3); + + // Do not call cryptApiData() here to decrypt the data received from the API! + // The data has been encrypted by the dongle hardware, so the API will not apply an unnecessary second layer of encryption + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + encryptedData = data.clone(); // A copy of the encrypted data for displaying later + + // Initialise the DRIS + ddpro.reset(); // Reset the DRIS fields with random values + ddpro.function = DinkeyPro.DECRYPT_USER_DATA; + ddpro.flags = DinkeyPro.USE_FUNCTION_ARGUMENT; // Java uses DDProtCheck()'s data parameter, so this flag must be set + ddpro.rw_length = data.length; + ddpro.data_crypt_key_num = 1; // This must be the same key used to encrypt the data + + // Encrypt the DRIS + ddpro.cryptDris(DRIS_ENCRYPTION_PARAMETER_1, DRIS_ENCRYPTION_PARAMETER_2, DRIS_ENCRYPTION_PARAMETER_3); + + // Do not call cryptApiData() here to encrypt the data passed to the API! + // The data is already encrypted, so the API does not expect an unnecessary second layer of encryption + + // Call the API + retCode = ddpro.checkProtection(data); + + // Decrypt the DRIS + ddpro.cryptDris(DRIS_ENCRYPTION_PARAMETER_1, DRIS_ENCRYPTION_PARAMETER_2, DRIS_ENCRYPTION_PARAMETER_3); + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + // If taking data encryption parameters from the R/W algorithm: + // Calculate the R/W algorithm result + // The input variables were initialised to random values when ddpro was created + algAnswer = myRwAlgorithm(ddpro.var_a, ddpro.var_b, ddpro.var_c, ddpro.var_d, ddpro.var_e, ddpro.var_f, ddpro.var_g, ddpro.var_h); + + // Use the algorithm result to decrypt the data received from the API + ddpro.cryptApiData(data, algAnswer); + + // If using constant data encryption parameters: + // ddpro.cryptApiData(data, DATA_ENCRYPTION_PARAMETER_1, DATA_ENCRYPTION_PARAMETER_2, DATA_ENCRYPTION_PARAMETER_3); + + System.out.println("Data encryption successful."); + System.out.println("Original data: " + Arrays.toString(originalData)); + System.out.println("Encrypted data: " + Arrays.toString(encryptedData)); + System.out.println("Decrypted data: " + Arrays.toString(data)); + return; + } + + // An example of a simple protection check and displaying information about the current users of a network dongle. + // This feature is supported by Dinkey Pro Net and Dinkey FD Net dongles only. + // queryNetUsers() will only work following a call to checkProtection() that established a connection to DinkeyServer. + static void displayNetUsers() + { + int retCode, maxNetUsersToQuery; + + DinkeyPro ddpro = new DinkeyPro(); // Create a DinkeyPro instance. All DRIS fields are initialised to random values + + // Initialise the DRIS + ddpro.function = DinkeyPro.PROTECTION_CHECK; + ddpro.flags = DinkeyPro.START_NET_USER; + + // Call the API + retCode = ddpro.checkProtection(); + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + // If you lock your software to multiple dongle models, + // you might want to check that a network dongle was found before trying to get network user information + if ((ddpro.model == DinkeyPro.MODEL_LITE) || (ddpro.model == DinkeyPro.MODEL_PLUS)) + { + System.out.println("Local dongle found. No network user information to display."); + return; + } + + // Set maxNetUsersToQuery to a sensible value! + // This example requests information about 10 users if there is no limit to the number of users supported by the dongle + if (ddpro.net_users == DinkeyPro.UNLIMITED_NET_USERS) + maxNetUsersToQuery = 10; + else + maxNetUsersToQuery = ddpro.net_users; + + // Call the API + retCode = ddpro.queryNetUsers(maxNetUsersToQuery); + + // Check the return value + if (retCode != 0) + { + System.out.println("An error occurred getting network user information."); + System.out.println("Error: " + retCode + "\nExtended Error: " + ddpro.queryNetUsersExtErr); + return; + } + + System.out.println(ddpro.numNetUsers + " current network users:\n"); + for (int i = 0; i < ddpro.num_net_users; i++) + { + System.out.println((i+1) + ") " + ddpro.userNames[i] + " @ " + ddpro.computerNames[i] + " (" + ddpro.ipAddresses[i] + ") using licence '" + ddpro.licenceNames[i] + "'"); + } + return; + } + + + // !!!! This method must match one stored in the dongle for protCheckWithAlg() to work correctly. + // For Lite dongles, use DinkeyLook to see the algorithm pre-programmed into the dongle. + // For Plus and Net dongles, ensure this algorithm matches one you specified in DinkeyAdd when adding protection. + static int myAlgorithm(int a, int b, int c, int d, int e, int f, int g, int h) + { + return a + b + c + d + e + f + g + h; + } + + // !!!! This method must match the R/W algorithm stored in the dongle for + // writeDataAreaEnc() and readDataAreaEnc() to work correctly. + static int myRwAlgorithm(int a, int b, int c, int d, int e, int f, int g, int h) + { + return a ^ b ^ c ^ d ^ e ^ f; + } + + + // An example of error reporting. Displays descriptions for some common error codes. + // IMPORTANT - THE MESSAGES DISPLAYED ARE TO HELP DEVELOPERS IMPLEMENT THE DINKEY PRO/FD API. + // THEY ARE NOT SUITABLE FOR DISPLAYING TO USERS! + static void displayError(int retCode, int extErr) + { + switch (retCode) + { + case 401: + System.out.println("Error! No dongles detected!"); + break; + case 403: + System.out.println("Error! The dongle is a different type to the one specified in DinkeyAdd."); + break; + case 404: + System.out.println("Error! The dongle is a different model to those specified in DinkeyAdd."); + break; + case 409: + System.out.println("Error! The dongle has not been programmed by DinkeyAdd."); + break; + case 410: + System.out.println("Error! The dongle has a different product code to the one specified in DinkeyAdd."); + break; + case 411: + System.out.println("Error! This software's licence was not found in the dongle."); + break; + case 413: + System.out.println("Error! This software has not been locked by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the user manual."); + break; + case 417: + System.out.println("Error! One or more of the parameters set in the DRIS is incorrect.\nCheck if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa."); + break; + case 423: + System.out.println("Error! The number of network users has been exceeded."); + break; + case 435: + System.out.println("Error! DinkeyServer has not been detected on the network."); + break; + case 922: + System.out.println("Error! The Software Key has expired."); + break; + default: + System.out.println("An error occurred checking the dongle.\nError: " + retCode + "\nExtended Error: " + extErr); + break; + } + return; + } + +} diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Java/Runtime/README.html b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Java/Runtime/README.html new file mode 100644 index 0000000..f207a27 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Java/Runtime/README.html @@ -0,0 +1,438 @@ + + + + + Using Dinkey Pro/FD with Java + + + +

Using Dinkey Pro/FD with Java

+
+

+ Protection checks in Java are implemented using DinkeyPro.class to communicate with the dongle via the appropriate native library + (DPJava.dll on 32-bit Windows, libDPJava64.so on 64-bit Linux, etc.). + You should lock these native libraries with the API method using DinkeyAdd as described in the user manual, and distribute the locked libraries with your software. +

+
+

+ The DinkeyPro class provides a Java wrapper around the Dinkey Pro/FD API, which is implemented by native libraries. + If you are not familiar with calling native libraries, it is recommended that you read the Java documentation on the subject, + especially the documentation for System.loadLibrary() and System.load(), + and how Java uses the system property java.library.path to locate native libraries. +

+

+ The native libraries and the DinkeyPro class are part of the uk.microcosm.dinkeydongle package. + See the documentation for your development environment for details of how to include and reference this package in your project. + dinkeydongle.jar provides all of the Java classes in the uk.microcosm.dinkeydongle package in a single JAR file. + This allows you to import the package much more easily in many Java IDEs. Note that the native libraries are not included in the JAR file. + You will need to distribute with your software locked copies of the native libraries for every platform that your software supports. +

+

+ Do not specify a calling program when locking the native libraries. + The calling program for Java software is the user's JVM, which will be different for different users. +

+

+ Java bytecode is more easily decompiled than native code. + For maximum security, it is recommended that you obfuscate your Java code using a third-party tool. +

+ +

The DinkeyPro Class

+

+ Instances of DinkeyPro contain an internal DRIS. + Most of this structure's members are exposed as public fields that can be directly accessed. + Others must be accessed via get...() and set...() methods: see below for details. + As Java does not have unsigned types, DRIS members that are documented as unsigned integers in the user manual + are represented by long fields in the DinkeyPro class. +

+
+

+ The header and size DRIS members are set automatically. + You do not need to set these fields in your code. +

+

+ rw_data_ptr is not used in Java. To use an API function that passes data to/from the dongle, + you must use the checkProtection(byte[] data) method and also set the USE_FUNCTION_ARGUMENT flag. +

+
+ +

Fields

+

+ Possible values for the function DRIS field, as documented in the user manual: +

+
    +
  • static final int PROTECTION_CHECK
  • +
  • static final int EXECUTE_ALGORITHM
  • +
  • static final int WRITE_DATA_AREA
  • +
  • static final int READ_DATA_AREA
  • +
  • static final int ENCRYPT_USER_DATA
  • +
  • static final int DECRYPT_USER_DATA
  • +
  • static final int FAST_PRESENCE_CHECK
  • +
  • static final int STOP_NET_USER
  • +
+

+ Possible values for the flags DRIS field, as documented in the user manual: +

+
    +
  • static final int DEC_ONE_EXEC
  • +
  • static final int DEC_MANY_EXECS
  • +
  • static final int START_NET_USER
  • +
  • static final int USE_FUNCTION_ARGUMENT
  • +
  • static final int CHECK_LOCAL_FIRST
  • +
  • static final int CHECK_NETWORK_FIRST
  • +
  • static final int USE_ALT_LICENCE_NAME
  • +
  • static final int DONT_SET_MAXDAYS_EXPIRY
  • +
  • static final int MATCH_DONGLE_NUMBER
  • +
  • static final int DONT_RETURN_FD_DRIVE
  • +
+

+ Possible values for the type DRIS field, as documented in the user manual: +

+
    +
  • static final int TYPE_PRO
  • +
  • static final int TYPE_FD
  • +
+

+ Possible values for the model DRIS field, as documented in the user manual: +

+
    +
  • static final int MODEL_LITE
  • +
  • static final int MODEL_PLUS
  • +
  • static final int MODEL_NET5
  • +
  • static final int MODEL_NETU
  • +
+

+ Possible values for the net_users DRIS field, as documented in the user manual: +

+
    +
  • static final int UNLIMITED_NET_USERS
  • +
+

+ Directly accessible DRIS fields, as documented in the user manual: +

+
    +
  • int seed1
  • +
  • int seed2
  • +
  • int function
  • +
  • int flags
  • +
  • long execs_decrement
  • +
  • int data_crypt_key_num
  • +
  • int rw_offset
  • +
  • int rw_length
  • +
  • int var_a
  • +
  • int var_b
  • +
  • int var_c
  • +
  • int var_d
  • +
  • int var_e
  • +
  • int var_f
  • +
  • int var_g
  • +
  • int var_h
  • +
  • int alg_number
  • +
  • int ret_code
  • +
  • int ext_err
  • +
  • int type
  • +
  • int model
  • +
  • int sdsn
  • +
  • long dongle_number
  • +
  • int update_number
  • +
  • long data_area_size
  • +
  • int max_alg_num
  • +
  • int execs
  • +
  • int exp_day
  • +
  • int exp_month
  • +
  • int exp_year
  • +
  • long features
  • +
  • int net_users
  • +
  • int alg_answer
  • +
  • long fd_capacity
  • +
  • int swkey_type
  • +
  • int swkey_exp_day
  • +
  • int swkey_exp_month
  • +
  • int swkey_exp_year
  • +
+

+ Fields used to access information returned by DDGetNetUserList(): +

+
    +
  • int numNetUsers - the current number of network users when DDGetNetUserList() was called.
  • +
  • int queryNetUsersExtErr - contains additional error information if DDGetNetUserList() returns failure.
  • +
  • String[] licenceNames - the names of the licences currently used by network users.
  • +
  • String[] userNames - the usernames of the current network users.
  • +
  • String[] computerNames - the computer names of the current network users.
  • +
  • String[] ipAddresses - the IP addresses of the current network users.
  • +
+

+ The string arrays should be used in combination, i.e. licenceNames[0], userNames[0], + computerNames[0] and ipAddresses[0] together describe a single network user. +

+ +

Constructors

+

+ These constructors can throw any exception thrown by System.loadLibrary() and System.load(). + See the documentation for those methods for details. +

+ +

DinkeyPro()

+

+ Creates a new DinkeyPro instance and calls System.loadLibrary() + to load the native library using the default filename. + The library must be located in one of the paths specified in the java.library.path system property. + The exact filename is implementation-dependent, but the most common names are: +

+
    +
  • 32-bit Windows - DPJava.dll
  • +
  • 64-bit Windows - DPJava64.dll
  • +
  • 32-bit Linux - libDPJava.so
  • +
  • 64-bit Linux - libDPJava64.so
  • +
  • 64-bit macOS - libDPJava64.dylib
  • +
+

+ The members of the instance's internal DRIS are initialised to random values. +

+ +

DinkeyPro(String libName)

+

+ Creates a new DinkeyPro instance and calls System.loadLibrary(libName) to load the native library. + The library must be located in one of the paths specified in the java.library.path system property. + If System.loadLibrary(libName) fails, it then calls System.load(libName). + Use this version of the constructor if you rename the native libraries (recommended), or if you need to specify the absolute + path to the library. +

+

+ The members of the instance's internal DRIS are initialised to random values. +

+ +

Methods

+ +

int checkProtection()

+

+ Calls DDProtCheck() in the native library using the internal DRIS. + Returns zero on success, or a value indicating the cause of the error on failure. +

+ +

int checkProtection(byte[] data)

+

+ Calls DDProtCheck() in the native library using the internal DRIS. + data is passed to the API (e.g. when writing to the dongle data area), + or acts as a buffer filled by the API (e.g. when reading from the dongle data area). + When using this method you must also set the USE_FUNCTION_ARGUMENT flag. + Returns zero on success, or a value indicating the cause of the error on failure. +

+ +

int queryNetUsers(int maxUsersToQuery)

+

+ Calls DDGetNetUserList() in the native library. + maxNetUsersToQuery specifies the maximum number of current network users to return information about. + Use this version of this method to get information about the current network users for the protected software's licence + (if protected with the per licence network users option), or all licences in the dongle + (if protected with the per product network users option). + Returns zero on success, or a value indicating the cause of the error on failure. +

+ +

int queryNetUsers(String licenceName, int maxUsersToQuery)

+

+ Calls DDGetNetUserList() in the native library. + maxNetUsersToQuery specifies the maximum number of current network users to return information about. + Use this version of this method to get information about the current network users for the licence specified by licenceName. + Returns zero on success, or a value indicating the cause of the error on failure. +

+ +

void reset()

+

+ Set all members of the internal DRIS to random values. +

+ +

String getProdCode()

+

+ Return the prodcode member of the internal DRIS as a Java string. +

+ +

String getFdDrive()

+

+ Return the fd_drive member of the internal DRIS as a Java string. +

+ +

void setAltLicenceName(String altLicenceName)

+

+ Assign the value of altLicenceName to the alt_licence_name member of the internal DRIS. +

+ +

void cryptDris(int encryptionParameter1, int encryptionParameter2, int encryptionParameter3)

+

+ Encrypt/decrypt the internal DRIS. + encryptionParameter1, encryptionParameter2 and encryptionParameter3 + must match the parameters specified for DRIS encryption in DinkeyAdd. +

+ +

void cryptApiData(byte[] data, int algAnswer)

+

+ Encrypt/decrypt checkProtection()'s data parameter using the result of the R/W algorithm. + The option to take data encryption parameters from the R/W algorithm must also be selected in DinkeyAdd when adding protection, + and algAnswer must be the result of an algorithm that matches the R/W algorithm specified there. +

+ +

void cryptApiData(byte[] data, int encryptionParameter1, int encryptionParameter2, int encryptionParameter3)

+

+ Encrypt/decrypt checkProtection()'s data parameter using constant parameters. + The option to use constant data encryption parameters must be selected in DinkeyAdd when adding protection, and + encryptionParameter1, encryptionParameter2 and encryptionParameter3 + must match the parameters specified there. +

+ +

Java Example Files

+
    +
  • DPSample.java - various examples of using the DinkeyPro class.
  • +
+ +

Supported Versions

+

+ All parts of the uk.microcosm.dinkeydongle package support Java platforms version 5 and newer. +

+ +

Try It Yourself

+
+

+ The sample code is designed to teach you how to use the Dinkey Pro/FD API in Java programs. + Do not copy the examples verbatim into your own code. Experiment with the sample code to understand how the API works, + and read the chapter Increasing Your Protection in the user manual for many suggestions on how to + make the best use of the API features. +

+
+

+ DPSample.java gives simple examples of performing a protection check, + as well as using various other features of Dinkey Pro/FD. + To run the DPSample program you will first need to use DinkeyAdd to produce a locked copy of the native library for your platform, + and program a dongle (if you are using Plus or Net dongles). + Place the locked library in one of the paths specified by your Java environment's java.library.path system property. + Browse the examples in DPSample.java to see how different features can be used. + All the examples follow the same basic pattern: +

+
    +
  1. Create a DinkeyPro instance and set up its internal DRIS with the relevant information.
  2. +
  3. Call the API.
  4. +
  5. Use the information returned in the internal DRIS.
  6. +
+

+ Uncomment the calls at the top of the main() method in DPSample.java + to enable the examples of different features, then recompile and run DPSample to run the examples. +

+

+ Parts of the sample code marked with !!!! must be customised with your own functions or values + for some features to work correctly. Not all features are supported by all dongle models. + See the user manual for more information. +

+ + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/LabVIEW/README.html b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/LabVIEW/README.html new file mode 100644 index 0000000..93f94ac --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/LabVIEW/README.html @@ -0,0 +1,295 @@ + + + + + Using Dinkey Pro/FD with LabVIEW + + + +

Using Dinkey Pro/FD with LabVIEW

+
+

+ The Shell protection method supports Windows executables (stand-alone applications) produced by the LabVIEW Application Builder. +

+

+ API protection checks in LabVIEW are implemented using the Virtual Instruments dp32.vi and dp64.vi + to communicate with the dongle via the appropriate shared library + (dpwin32.dll on 32-bit Windows, dplin64.so on 64-bit Linux, etc.). + You should lock these shared libraries with the API method using DinkeyAdd as described in the user manual, and distribute the locked libraries with your software. +

+
+

+ Using the Dinkey Pro/FD API in LabVIEW is very similar to using the API with text-based programming languages. + See Modifying Your Code in the user manual for information on using the API. +

+

+ In LabVIEW, the DRIS is a cluster with some slight differences to the DRIS + documented in Structures > DRIS Structure in the user manual. + These differences are: +

+
    +
  • + The fields header and size are set automatically by the dp32 and dp64 VIs. + You do not need to set these fields in your code. +
  • +
  • + rw_data_ptr is replaced by rw_data. + This field is an array of bytes representing the actual data passed to/received from the dongle (rather than a pointer to it). + Internally, the array is converted to a cluster. Because LabVIEW limits the number of elements in cluster to 256, + the maximum size of data that can be passed to/from the dongle in a single protection check is 256 bytes. + You must set the USE_FUNCTION_ARGUMENT flag when using this field. +
  • +
+

+ In the user manual, possible values for the function and flags fields are referred to by the + symbolic names used in other programming languages. Their literal values are provided here for your reference: +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FunctionValue
PROTECTION_CHECK1
EXECUTE_ALGORITHM2
WRITE_DATA_AREA3
READ_DATA_AREA4
ENCRYPT_USER_DATA5
DECRYPT_USER_DATA6
FAST_PRESENCE_CHECK7
STOP_NET_USER8
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FlagValue
DEC_ONE_EXEC1
DEC_MANY_EXECS2
START_NET_USER4
USE_FUNCTION_ARGUMENT16
CHECK_LOCAL_FIRST32
CHECK_NETWORK_FIRST64
USE_ALT_LICENCE_NAME128
DONT_SET_MAXDAYS_EXPIRY256
MATCH_DONGLE_NUMBER512
DONT_RETURN_FD_DRIVE1024
+
+
+

+ The VIs also have a Path input that must be used to specify the path to the locked API library. + See the LabVIEW documentation for the Call Library Function Node for more information on specifying paths to shared libraries. +

+

+ The dp32 and dp64 VIs do not support DRIS encryption or user data encryption/decryption. +

+ +
+

+ Before you distribute your application, you must protect it from modification. + In general, it is best to use the LabVIEW Application Builder to create a standalone application that can be run outside of LabVIEW. + If you are distributing your LabVIEW code as a module to be used in other LabVIEW VIs, + don't forget to remove the block diagram from the VI so that end users cannot modify the code! + For more information on this, see the LabVIEW documentation. +

+
+ +

LabVIEW Example Files

+
    +
  • dp32.vi - a VI that provides a 32-bit LabVIEW interface to the Dinkey Pro/FD API.
  • +
  • dp64.vi - a VI that provides a 64-bit LabVIEW interface to the Dinkey Pro/FD API.
  • +
  • sample.vi - a simple example of using dp32.vi.
  • +
+ +

Supported Versions

+

+ The LabVIEW sample code provided with the Dinkey Pro/FD SDK was written using LabVIEW 8.5 for Windows, + and tested using LabVIEW 8.5 on 32-bit Windows and LabVIEW 2018 on 64-bit Windows. + All newer versions should be backwards compatible. The sample code may also work with older versions, + but no guarantees can be made, and support for older versions is likely to be very limited. +

+

+ The sample code should also work without modification on macOS and Linux. + If you have problems calling our API from LabVIEW on macOS or Linux, + please contact us with full details of the platform and LabVIEW version that you are using. +

+ +

Try It Yourself

+
+

+ The sample code is designed to teach you how to use the Dinkey Pro/FD API in LabVIEW programs. + Experiment with the sample code to understand how the API works, + and read the chapter Increasing Your Protection in the user manual for many suggestions on how to + make the best use of the API features. +

+
+

+ sample.vi gives a simple example of using the dp32 VI to perform a protection check. + If you are using 64-bit LabVIEW, replace dp32 with the dp64 VI. + The VI calls the API and checks that the return code is 0 and that the SDSN of the dongle is 10101 (i.e. a demo dongle), + turning on the LED indicator if both are correct. +

+

+ Controls and indicators for the other input and output variables are included to allow you to experiment with other dongle features. + It is strongly recommended that you use these other features to improve the security of the dongle protection. + See the chapter Increasing Your Protection in the user manual for many suggestions on how to do this. +

+

+ To run sample.vi you will first need to use DinkeyAdd to produce a locked copy of the shared library for your platform, + and program a dongle (if you are using Plus or Net dongles). + Set the value of the Path control to the location of the locked library. +

+ + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/LabVIEW/dp32.vi b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/LabVIEW/dp32.vi new file mode 100644 index 0000000..b07827c Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/LabVIEW/dp32.vi differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/LabVIEW/dp64.vi b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/LabVIEW/dp64.vi new file mode 100644 index 0000000..635e423 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/LabVIEW/dp64.vi differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/LabVIEW/sample.vi b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/LabVIEW/sample.vi new file mode 100644 index 0000000..3690f46 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/LabVIEW/sample.vi differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/DinkeyChange64_thunk_pcwin64.dll b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/DinkeyChange64_thunk_pcwin64.dll new file mode 100644 index 0000000..0ca8e9c Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/DinkeyChange64_thunk_pcwin64.dll differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/README.html b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/README.html new file mode 100644 index 0000000..bef676e --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/README.html @@ -0,0 +1,273 @@ + + + + + Using the DinkeyChange API with MATLAB + + + +

Using the DinkeyChange API with MATLAB

+

+ If you are not already familiar with calling shared libraries from MATLAB code, + it is strongly recommended that you read the MATLAB documentation on this topic. + Depending on your version of MATLAB, you may need to install a C compiler and configure MATLAB to use it with the command mex -setup. + Again, refer to the MATLAB documentation for further information. +

+

+ See Remote Parameter Changing > DinkeyChange > DinkeyChange.dll in the user manual for information on using the DinkeyChange API. + Use the help command to see overviews of how each M-file interface to the DinkeyChange API is used in MATLAB. + Most of the DinkeyChange M-files are simple MATLAB wrappers for the shared library functions. + dcgetinfo.m however is quite different to the DCGetInfo() function described in the user manual: +

+
[retCode, dongleArray] = dcgetinfo(libName, typeMask, modelMask, prodcodeMask)
+

+ The inputs typeMask, modelMask and prodcodeMask + are used in the same way as the inputs of DCGetInfo(), as dcsample.m illustrates. + The outputs however are grouped together as dongleArray, a 1-by-N vector of MATLAB structures. + Each structure represents a dongle found by dcgetinfo's search, and each structure has the following fields: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldData TypeDescription
typeint32 + The dongle's type as a numeric value. Possible values: +
    +
  • 1 for Dinkey Pro dongles
  • +
  • 2 for Dinkey FD dongles
  • +
+
type_as_stringchar + The dongle's type as a string. Possible values: +
    +
  • "Pro"
  • +
  • "FD"
  • +
+
modelint32 + The dongle's model as a numeric value. Possible values: +
    +
  • 1 for Lite dongles
  • +
  • 2 for Plus dongles
  • +
  • 4 for Net dongles (5 users)
  • +
  • 7 for Net dongles (unlimited users)
  • +
+
model_as_stringchar + The dongle's model as a string. Possible values: +
    +
  • "Lite"
  • +
  • "Plus"
  • +
  • "Net (5 users)"
  • +
  • "Net (unlimited users)"
  • +
+
product_codecharThe dongle's product code
dongle_numberuint32The dongle's serial number (dongle number)
update_numberint32The dongle's update number
+ +

MATLAB Example Files

+
    +
  • dcgetinfo.m - an M-file that provides a MATLAB interface to the DCGetInfo() API function.
  • +
  • dcgetdiagnosticinfo.m - a MATLAB interface to the DCGetDiagnosticInfo() API function.
  • +
  • dcdoupdatecodestring.m - a MATLAB interface to the DCDoUpdateCodeString() API function.
  • +
  • dcdoupdatecodefromfile.m - a MATLAB interface to the DCDoUpdateCodeFromFile() API function.
  • +
  • dcrestoredinkeyfdlite.m - a MATLAB interface to the DCRestoreDinkeyFDLite() API function.
  • +
  • dcgetmachineid.m - a MATLAB interface to the DCGetMachineID() API function.
  • +
  • dcdownloadtempsoftwarekey.m - a MATLAB interface to the DCDownloadTempSoftwareKey() API function.
  • +
  • dcdownloaddemosoftwarekey.m - a MATLAB interface to the DCDownloadDemoSoftwareKey() API function.
  • +
  • dcsample.m - examples of using these M-files.
  • +
  • dinkeychangewin32proto.p - a prototype P-file that defines the signatures of the API functions for 32-bit MATLAB on Windows.
  • +
  • dinkeychange32proto.p - a prototype P-file that defines the signatures of the API functions for 32-bit MATLAB on all other supported platforms.
  • +
  • dinkeychange64proto.p - a prototype P-file that defines the signatures of the API functions for 64-bit MATLAB on all supported platforms.
  • +
  • DinkeyChange64_thunk_pcwin64.dll - a compatibility layer required by 64-bit MATLAB to use DinkeyChange64.dll.
  • +
+

+ The appropriate prototype P-file and any M-files that you call should be included, without modification, in your own project. + If you are using 64-bit MATLAB on Windows, you should also include DinkeyChange64_thunk_pcwin64.dll. + If you rename DinkeyChange64.dll, + you must change the DinkeyChange64 part of the thunking DLL's filename accordingly. +

+

+ Our M-files and P-files are compatible with MATLAB on macOS and Linux. + However, we do not currently provide the thunk files required by 64-bit MATLAB on these platforms. + If you want to use the DinkeyChange API on 64-bit macOS and/or 64-bit Linux, + please contact us with full details of the platform(s) and MATLAB versions that you want to use, + and we can provide compatible thunk files or instruct you on how to produce these files yourself. +

+ +

Supported Versions

+

+ The MATLAB sample code provided with the Dinkey Pro/FD SDK was written and tested using MATLAB R2013a. + All newer versions should be backwards compatible. The sample code may also work with older versions, + but no guarantees can be made, and support for older versions is likely to be very limited. +

+ +

Try It Yourself

+

+ dcsample.m gives a simple example of calling each of the API functions. + To run dcsample.m you will need a copy of the appropriate shared library for your platform + (DinkeyChange.dll for 32-bit Windows, DinkeyChange64.so for 64-bit Linux etc.). + Place the library in the same folder as the example files and change MATLAB's current directory to this folder. + Browse the examples in dcsample.m to see how different features can be used. +

+

+ Uncomment the function calls at the top of dcsample.m + to enable the examples of different features, then enter dcsample in the Command Window to run the examples. +

+

+ dcsample.m also demonstrates loading and unloading the appropriate shared library for your platform. +

+

+ Parts of the sample code marked with !!!! must be customised with your own functions or values + for some features to work correctly. Not all features are supported by all dongle models. + See the user manual for more information. +

+ + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcdoupdatecodefromfile.m b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcdoupdatecodefromfile.m new file mode 100644 index 0000000..54ead05 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcdoupdatecodefromfile.m @@ -0,0 +1,17 @@ +function [retCode, confirmationCode, extErr] = dcdoupdatecodefromfile(libName, filename) +%DCDOUPDATECODEFROMFILE Update a dongle attached to this computer using a +%strongly encrypted update code. +% [RETCODE,CONFIRMATIONCODE,EXTERR] = +% DCDOUPDATECODEFROMFILE(LIBNAME,FILENAME) calls the API via the external +% library LIBNAME. FILENAME is a file containing the update code to be +% applied. RETCODE is the return code of the API call. If the update +% succeeded, CONFIRMATIONCODE contains the update's confirmation code. If +% the update failed, EXTERR contains an additional error code that +% provides more information. + +% Copyright Microcosm Ltd. DO NOT MODIFY THIS FILE. + + confirmationCode = int32(0); + extErr = int32(0); + [retCode, filename, confirmationCode, extErr] = calllib(libName, 'DCDoUpdateCodeFromFile', filename, confirmationCode, extErr); +end diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcdoupdatecodestring.m b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcdoupdatecodestring.m new file mode 100644 index 0000000..e838ff6 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcdoupdatecodestring.m @@ -0,0 +1,17 @@ +function [retCode, confirmationCode, extErr] = dcdoupdatecodestring(libName, updateCode) +%%DCDOUPDATECODESTRING Update a dongle attached to this computer using a +%short update code. +% [RETCODE,CONFIRMATIONCODE,EXTERR] = +% DCDOUPDATECODESTRING(LIBNAME,UPDATECODE) calls the API via the external +% library LIBNAME. UPDATECODE is the short update code to be applied. +% RETCODE is the return code of the API call. If the update succeeded, +% CONFIRMATIONCODE contains the update's confirmation code. If the update +% failed, EXTERR contains an additional error code that provides more +% information. + +% Copyright Microcosm Ltd. DO NOT MODIFY THIS FILE. + + confirmationCode = int32(0); + extErr = int32(0); + [retCode, updateCode, confirmationCode, extErr] = calllib(libName, 'DCDoUpdateCodeString', updateCode, confirmationCode, extErr); +end diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcdownloaddemosoftwarekey.m b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcdownloaddemosoftwarekey.m new file mode 100644 index 0000000..7a87a40 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcdownloaddemosoftwarekey.m @@ -0,0 +1,15 @@ +function [retCode, extErr] = dcdownloaddemosoftwarekey(libName, machineId, productCode, model) +%DCDOWNLOADDEMOSOFTWAREKEY Download and install a demo software key. +% [RETCODE,EXTERR] = DCDOWNLOADDEMOSOFTWAREKEY(LIBNAME,MACHINEID,PRODUCTCODE,MODEL) +% calls the API via the external library LIBNAME. MACHINEID is the machine +% ID of this computer (you can obtain this by calling the API function +% DCGETMACHINEID). PRODUCTCODE and MODEL specify the product code and dongle +% model of the demo software key to be installed. RETCODE is the return code +% of the API call. If the update failed, EXTERR contains an additional error +% code that provides more information. + +% Copyright Microcosm Ltd. DO NOT MODIFY THIS FILE. + + extErr = int32(0); + [retCode, productCode, extErr] = calllib(libName, 'DCDownloadDemoSoftwareKey', machineId, productCode, model, extErr); +end diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcdownloadtempsoftwarekey.m b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcdownloadtempsoftwarekey.m new file mode 100644 index 0000000..e8b0758 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcdownloadtempsoftwarekey.m @@ -0,0 +1,14 @@ +function [retCode, extErr] = dcdownloadtempsoftwarekey(libName, machineId) +%DCDOWNLOADTEMPSOFTWAREKEY Download and install a temporary software key. +% [RETCODE,EXTERR] = DCDOWNLOADTEMPSOFTWAREKEY(LIBNAME,MACHINEID) calls the +% API via the external library LIBNAME. MACHINEID is the machine ID of +% this computer (you can obtain this by calling the API function +% DCGETMACHINEID). RETCODE is the return code of the API call. If the +% update failed, EXTERR contains an additional error code that provides +% more information. + +% Copyright Microcosm Ltd. DO NOT MODIFY THIS FILE. + + extErr = int32(0); + [retCode, extErr] = calllib(libName, 'DCDownloadTempSoftwareKey', machineId, extErr); +end diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcgetdiagnosticinfo.m b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcgetdiagnosticinfo.m new file mode 100644 index 0000000..9d35894 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcgetdiagnosticinfo.m @@ -0,0 +1,13 @@ +function retCode = dcgetdiagnosticinfo(libName, filename) +%DCGETDIAGNOSTICINFO Call the DinkeyChange API to write diagnostic +%information to a file. +% RETCODE = DCGETDIAGNOSTICINFO(LIBNAME,FILENAME) calls the API via the +% external library LIBNAME, writing diagnostic information to the file +% specified in FILENAME. FILENAME can be an absolute or relative path. If +% FILENAME does not end in '.dlpf', it will be appended automatically. +% RETCODE is the return code of the API call. + +% Copyright Microcosm Ltd. DO NOT MODIFY THIS FILE. + + retCode = calllib(libName, 'DCGetDiagnosticInfo', filename); +end diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcgetinfo.m b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcgetinfo.m new file mode 100644 index 0000000..bdbbd87 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcgetinfo.m @@ -0,0 +1,72 @@ +function [retCode, dongleArray] = dcgetinfo(libName, typeMask, modelMask, prodcodeMask) +%DCGETINFO Get information about Dinkey Pro/FD dongles attached to this +%computer. +% [RETCODE,DONGLEARRAY] = +% DCGETINFO(LIBNAME,TYPEMASK,MODELMASK,PRODCODEMASK) calls the API via +% the external library LIBNAME. TYPEMASK, MODELMASK and PRODCODEMASK can +% be used to restrict the search to dongles with specific +% characteristics. DONGLEARRAY is a vector of structures; each structure +% contains information about a dongle attached to this computer. RETCODE +% is the return code of the API call. + +% Copyright Microcosm Ltd. DO NOT MODIFY THIS FILE. + + MAX_USB_DEVICES = 128; + MAX_PRODCODE_LEN = 9; + + dongleArray = []; + numberFound = int32(0); + typeArray = zeros(1, MAX_USB_DEVICES, 'int32'); + modelArray = zeros(1, MAX_USB_DEVICES, 'int32'); + productCodeArray = zeros(1, MAX_USB_DEVICES * MAX_PRODCODE_LEN, 'uint8'); + dongleNumberArray = zeros(1, MAX_USB_DEVICES, 'uint32'); + updateNumberArray = zeros(1, MAX_USB_DEVICES, 'int32'); + + [retCode, prodcodeMask, numberFound, typeArray, modelArray, productCodeArray, dongleNumberArray, updateNumberArray] = ... + calllib(libName, 'DCGetInfo', typeMask, modelMask, prodcodeMask, MAX_USB_DEVICES, numberFound, typeArray, modelArray, productCodeArray, dongleNumberArray, updateNumberArray); + + for (i = 1:numberFound) + productCode = productCodeArray(((i-1)*MAX_PRODCODE_LEN)+1 : i*MAX_PRODCODE_LEN); % Get product codes out of array of bytes, 9 bytes at a time + productCode = deblank(char(productCode)); % Convert to string and remove any trailing NULLs + newDongle = createdonglestructure(typeArray(i), modelArray(i), productCode, dongleNumberArray(i), updateNumberArray(i)); + dongleArray = [dongleArray newDongle]; + end +end + +function dongle = createdonglestructure(type, model, productCode, dongleNumber, updateNumber) +% Create a structure representing a dongle detected by dcgetinfo() + + dongle.type = type; + switch type + case 1 + dongle.type_as_string = 'Pro'; + case 2 + dongle.type_as_string = 'FD'; + otherwise + dongle.type_as_string = ''; % Should never happen! + end + + dongle.model = model; + switch model + case 1 + dongle.model_as_string = 'Lite'; + case 2 + dongle.model_as_string = 'Plus'; + case 3 + dongle.model_as_string = 'Net (1 user)'; + case 4 + dongle.model_as_string = 'Net (5 users)'; + case 5 + dongle.model_as_string = 'Net (10 users)'; + case 6 + dongle.model_as_string = 'Net (50 users)'; + case 7 + dongle.model_as_string = 'Net (unlimited users)'; + otherwise + dongle.model_as_string = ''; % Should never happen! + end + + dongle.product_code = char(productCode); + dongle.dongle_number = uint32(dongleNumber); + dongle.update_number = int32(updateNumber); +end diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcgetmachineid.m b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcgetmachineid.m new file mode 100644 index 0000000..b998b81 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcgetmachineid.m @@ -0,0 +1,14 @@ +function [retCode, machineId, extErr] = dcgetmachineid(libName) +%DCGETMACHINEID Get the machine ID for this computer +% [RETCODE,MACHINEID,EXTERR] = DCGETMACHINEID(LIBNAME) calls the API via +% the external library LIBNAME. RETCODE is the return code of the API +% call. If the update succeeded, MACHINEID is the machine ID of the +% computer. If this call failed, EXTERR contains an additional error code +% that provides more information. + +% Copyright Microcosm Ltd. DO NOT MODIFY THIS FILE. + + machineId = uint32(0); + extErr = int32(0); + [retCode, machineId, extErr] = calllib(libName, 'DCGetMachineID', machineId, extErr); +end diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcrestorefdlite.m b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcrestorefdlite.m new file mode 100644 index 0000000..9db050d --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcrestorefdlite.m @@ -0,0 +1,10 @@ +function retCode = dcrestorefdlite(libName) +%DCRESTOREFDLITE Restore the required hidden file on all Dinkey FD Lite +%dongles attached to this computer. +% RETCODE = DCRESTOREFDLITE(LIBNAME) calls the API via the external +% library LIBNAME. RETCODE is the return code of the API call. + +% Copyright Microcosm Ltd. DO NOT MODIFY THIS FILE. + + retCode = calllib(libName, 'DCRestoreDinkeyFDLite'); +end \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcsample.m b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcsample.m new file mode 100644 index 0000000..9dc00cf --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dcsample.m @@ -0,0 +1,249 @@ +function dcsample +%DCSAMPLE Example use of the DinkeyChange API in MATLAB. + +% Copyright Microcosm Ltd. + + % Load the correct library for this platform + switch computer() + case 'PCWIN64' % 64-bit Windows + loadlibrary('DinkeyChange64.dll', @dinkeychange64proto, 'alias', 'dinkeychange'); + case 'PCWIN' % 32-bit Windows + loadlibrary('DinkeyChange.dll', @dinkeychangewin32proto, 'alias', 'dinkeychange'); + case 'GLNXA64' % 64-bit Linux + loadlibrary('DinkeyChange64.so', @dinkeychange64proto, 'alias', 'dinkeychange'); + case 'GLNX86' % 32-bit Linux + loadlibrary('DinkeyChange.so', @dinkeychange32proto, 'alias', 'dinkeychange'); + case 'MACI64' % 64-bit Mac OS X + loadlibrary('DinkeyChange64.dylib', @dinkeychange64proto, 'alias', 'dinkeychange'); + case 'MAC' % 32-bit Mac OS X + loadlibrary('DinkeyChange32.dylib', @dinkeychange32proto, 'alias', 'dinkeychange'); + otherwise + disp('Error! Platform not supported!'); + return + end + + % Each of the functions below demonstrates different API functionality. + % Uncomment the appropriate functions to execute the examples. + % See the comments in each function for more details about the features + % that they demonstrate. + + getdongleinfo('dinkeychange'); + %writediagnosticfile('dinkeychange'); + %applyshortupdatecode('dinkeychange'); + %applystronglyencryptedupdatecode('dinkeychange'); + %restorefdlite('dinkeychange'); + %getmachineid('dinkeychange'); + %downloadtempsoftwarekey('dinkeychange'); + %downloaddemosoftwarekey('dinkeychange'); + + unloadlibrary('dinkeychange'); +end + +function getdongleinfo(libName) +% Display information about the dongles attached to this computer + + % Possible values for dcgetinfo's typeMask parameter + TYPE_MASK_PRO = 1; + TYPE_MASK_FD = 2; + TYPE_MASK_ALL = bitor(TYPE_MASK_PRO, TYPE_MASK_FD); + + % Possible values for dcgetinfo's modelMask parameter + MODEL_MASK_LITE = 1; + MODEL_MASK_PLUS = 2; + MODEL_MASK_NET = 4; + MODEL_MASK_ALL = bitor(bitor(MODEL_MASK_LITE, MODEL_MASK_PLUS), MODEL_MASK_NET); + MODEL_MASK_DEFAULT = bitor(MODEL_MASK_PLUS, MODEL_MASK_NET); + + % Call the DinkeyChange API + [retCode, dongleArray] = dcgetinfo(libName, TYPE_MASK_ALL, MODEL_MASK_ALL, ''); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, 0); + return + end + + for (i = 1:length(dongleArray)) + disp(sprintf('%3d) Dinkey %s %s', i, dongleArray(i).type_as_string, dongleArray(i).model_as_string)); + disp(sprintf(' Product code : %s', dongleArray(i).product_code)); + disp(sprintf(' Dongle number: %u', dongleArray(i).dongle_number)); + disp(sprintf(' Update number: %u', dongleArray(i).update_number)); + disp(sprintf('\n')); + end +end + +function writediagnosticfile(libName) +% Write diagnostic information about the dongles attached to this computer +% to an encrypted file. + + filename = '!!!! REPLACE THIS WITH THE NAME OF THE FILE TO WRITE TO'; + + % Call the DinkeyChange API + retCode = dcgetdiagnosticinfo(libName, filename); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, 0); + return + end + + disp(['Successfully wrote diagnostic information to ' filename]); +end + +function applyshortupdatecode(libName) +% Update a dongle attached to this computer using a short update code + + % Call the DinkeyChange API + [retCode, confirmationCode, extErr] = dcdoupdatecodestring(libName, '!!!! REPLACE THIS WITH A VALID UPDATE CODE STRING'); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, extErr); + return + end + + disp('Successfully updated dongle'); + disp(['Confirmation code: ' sprintf('%X', confirmationCode)]); +end + +function applystronglyencryptedupdatecode(libName) +% Update a dongle attached to this computer using a strongly encrypted +% update code file + + % Call the DinkeyChange API + [retCode, confirmationCode, extErr] = dcdoupdatecodefromfile(libName, '!!!! REPLACE THIS WITH A VALID UPDATE CODE FILENAME'); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, extErr); + return + end + + disp('Successfully updated dongle'); + disp(['Confirmation code: ' sprintf('%X', confirmationCode)]); +end + +function restorefdlite(libName) +% Restore the required hidden file on a Dinkey FD Lite dongle. + + % Call the DinkeyChange API + retCode = dcrestorefdlite(libName); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, 0); + return + end + + disp('Successfully restored FD Lite dongle'); +end + +function getmachineid(libName) +% Display this computer's machine ID + + % Call the DinkeyChange API + [retCode, machineId, extErr] = dcgetmachineid(libName); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, extErr); + return + end + + disp(['The machine ID for this computer is: ' sprintf('%X', machineId)]); +end + +function downloadtempsoftwarekey(libName) +% Download and install a temporary software key on this computer + + % First call the DinkeyChange API to get the machine ID + [retCode, machineId, extErr] = dcgetmachineid(libName); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, extErr); + return + end + + % Then call the API again to install the software key + [retCode, extErr] = dcdownloadtempsoftwarekey(libName, machineId); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, extErr); + return + end + + disp('The temporary software key has been succesfully installed.'); +end + +function downloaddemosoftwarekey(libName) +% Download and install a demo software key on this computer + + % Possible values for dcdownloaddemosoftwarekey's model parameter + SWKEY_MODEL_DEFAULT = -1; + SWKEY_MODEL_PRO_LITE = 0; + SWKEY_MODEL_PRO_PLUS = 1; + SWKEY_MODEL_PRO_NET = 2; + SWKEY_MODEL_FD_LITE = 3; + SWKEY_MODEL_FD_PLUS = 4; + SWKEY_MODEL_FD_NET = 5; + + % First call the DinkeyChange API to get the machine ID + [retCode, machineId, extErr] = dcgetmachineid(libName); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, extErr); + return + end + + % Then call the API again to install the software key + [retCode, extErr] = dcdownloaddemosoftwarekey(libName, machineId, '!!!! REPLACE THIS WITH THE PRODUCT CODE OF THE KEY', SWKEY_MODEL_DEFAULT); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, extErr); + return + end + + disp('The demo software key has been succesfully installed.'); +end + +% An example of error reporting +% Displays descriptions for some common error codes +function displayerror(retCode, extErr) + switch retCode + case 401 + disp('Error! No dongles detected that meet the search criteria.'); + case 409 + disp('Error! The dongle detected has not been programmed by DinkeyAdd.'); + case 754 + disp('Error! The specified output file could not be written to.'); + case 758 + disp('Error! Cannot open the file specified.'); + case 759 + disp('Error! The file specified is not a valid update code file.'); + case 762 + disp('Error! The update code contains invalid characters.'); + case 763 + disp('Error! Invalid update code.'); + case 764 + disp('Error! The update code was entered incorrectly, or the update code file is corrupt.'); + case 765 + disp('Error! The update code does not match any dongle attached to your computer.'); + case 766 + disp('Error! The update number for this update code is too high. If you have more than one update code, ensure that you apply them in the correct order.'); + case 767 + disp('Error! You have already entered this update code.'); + case 1905 + disp('Error! There is no temporary software key available for download.'); + case 1907 + disp('Error! The temporary software key has expired. Cannot download it.'); + case 1910 + disp('Error! The temporary software key has already been downloaded.'); + otherwise + str = sprintf('An error occurred checking the dongle. Error: %d, Extended Error: %d', retCode, extErr); + disp(str); + end +end diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dinkeychange32proto.p b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dinkeychange32proto.p new file mode 100644 index 0000000..3746269 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dinkeychange32proto.p differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dinkeychange64proto.p b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dinkeychange64proto.p new file mode 100644 index 0000000..b89378f Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dinkeychange64proto.p differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dinkeychangewin32proto.p b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dinkeychangewin32proto.p new file mode 100644 index 0000000..fa7dc34 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/DinkeyChange/dinkeychangewin32proto.p differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/README.html b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/README.html new file mode 100644 index 0000000..05c1104 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/README.html @@ -0,0 +1,343 @@ + + + + + Using Dinkey Pro/FD with MATLAB + + + +

Using Dinkey Pro/FD with MATLAB

+
+

+ The Shell protection method supports Windows executables produced by the MATLAB Compiler. +

+

+ API protection checks in MATLAB are implemented using the M-file ddprotcheck.p to communicate with the dongle via the appropriate shared library + (dpwin32.dll on 32-bit Windows, dplin64.so on 64-bit Linux, etc.). + You should lock these shared libraries with the API method using DinkeyAdd as described in the user manual, and distribute the locked libraries with your software. +

+
+

+ If you are not already familiar with calling shared libraries from MATLAB code, + it is strongly recommended that you read the MATLAB documentation on this topic. + Depending on your version of MATLAB, you may need to install a C compiler and configure MATLAB to use it with the command mex -setup. + Again, refer to the MATLAB documentation for more information. +

+

+ See Modifying Your Code in the user manual for information on using the API. + Below is an overview of how the ddprotcheck function is used in MATLAB. +

+
ddprotcheck Call the Dinkey Pro/FD API.
+    [RETCODE,DRIS] = ddprotcheck(LIBNAME,DRIS) calls the API via the
+    external library LIBNAME. DRIS is a struct used to pass inputs to the
+    API and receive outputs. RETCODE is the return code of the API call.
+
+    [RETCODE,DRIS] = ddprotcheck(LIBNAME,DRIS,@CRYPTFUNCTION) additionally
+    provides an extra layer of security. The function CRYPTFUNCTION
+    is used to encrypt the DRIS before it is passed between MATLAB and the
+    external library.
+ +

+ In MATLAB, the DRIS is a MATLAB structure with some slight differences to the DRIS + documented in Structures > DRIS Structure in the user manual. + These differences are: +

+
    +
  • + The fields header and size are set automatically by ddprotcheck.p. + You do not need to set these fields in your code. +
  • +
  • + The seed1 and seed2 fields must be 1-by-4 vectors of type uint8, not integers. +
  • +
  • + rw_data_ptr is replaced by rw_data. + This field is the actual data read from/to be written to the dongle (rather than a pointer to it). + It should be a 1-by-N vector of type uint8. +
  • +
  • + When using the functions WRITE_DATA_AREA, ENCRYPT_USER_DATA and DECRYPT_USER_DATA, + rw_length is automatically set to be the length of the vector rw_data. +
  • +
  • + The fields var_a to var_h are replaced by alg_vars. + alg_vars must be a 1-by-N vector. The first 8 elements will be used for var_a to var_h. + If alg_vars has fewer than 8 elements, it will be padded with zeros. +
  • +
+

+ DRIS fields are automatically converted to the data types specified in Structures > DRIS Structure. + When casting, MATLAB truncates values that cannot fit into a variable of the new data type. + This can lead to loss of data. +

+

+ Indices for the secure data area of Plus and Net dongles start at zero. + To read the first ten bytes for example, set rw_length = 10 and rw_offset = 0. +

+

+ In the user manual, possible values for the function and flags fields are referred to by the + symbolic names used in other programming languages. Their literal values are provided here for your reference: +

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FunctionValue
PROTECTION_CHECK1
EXECUTE_ALGORITHM2
WRITE_DATA_AREA3
READ_DATA_AREA4
ENCRYPT_USER_DATA5
DECRYPT_USER_DATA6
FAST_PRESENCE_CHECK7
STOP_NET_USER8
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FlagValue
DEC_ONE_EXEC1
DEC_MANY_EXECS2
START_NET_USER4
USE_FUNCTION_ARGUMENT16
CHECK_LOCAL_FIRST32
CHECK_NETWORK_FIRST64
USE_ALT_LICENCE_NAME128
DONT_SET_MAXDAYS_EXPIRY256
MATCH_DONGLE_NUMBER512
DONT_RETURN_FD_DRIVE1024
+
+
+
+

+ Before you distribute your application, you must protect it from modification. + In general, it is best to use the MATLAB Compiler to create a standalone application that can be run outside of MATLAB. + It is also possible to convert your source files to P-code, which protects the code from modification, + but still allows it to be run inside the MATLAB environment. + However, MathWorks do not recommend P-coding files to protect your intellectual property, + as P-code files are obfuscated, not encrypted. + See the MATLAB documentation for more information. +

+
+

MATLAB Example Files

+
    +
  • ddprotcheck.p - a P-file that provides a MATLAB interface to the Dinkey Pro/FD API.
  • +
  • dpsample.m - various examples of using ddprotcheck.p.
  • +
  • dinkeyprowin32proto.p - a prototype P-file that defines the signatures of the API functions for 32-bit MATLAB on Windows.
  • +
  • dinkeypro32proto.p - a prototype P-file that defines the signatures of the API functions for 32-bit MATLAB on all other supported platforms.
  • +
  • dinkeypro64proto.p - a prototype P-file that defines the signatures of the API functions for 64-bit MATLAB on all supported platforms.
  • +
  • dp64_thunk.dll - a compatibility layer required by 64-bit MATLAB to use dpwin64.dll.
  • +
  • dp64_thunk.dylib - a compatibility layer required by 64-bit MATLAB to use dpmac64.dylib.
  • +
  • dp64_thunk.so - a compatibility layer required by 64-bit MATLAB to use dplin64.so.
  • +
+

+ ddprotcheck.p and the appropriate prototype P-file(s) should be used in your own project. + If you are using 64-bit MATLAB, you should also include the appropriate thunk file(s) for the platform(s) that you support. +

+ +

Supported Versions

+

+ The MATLAB sample code provided with the Dinkey Pro/FD SDK was written using MATLAB 7 (R14) for Windows, + and tested using MATLAB 7 on 32-bit Windows and MATLAB R2013a on 64-bit Windows. + All newer versions should be backwards compatible. The sample code may also work with older versions, + but no guarantees can be made, and support for older versions is likely to be very limited. +

+

+ dp64_thunk.dylib and dp64_thunk.so may not be compatible with all versions of MATLAB + on all versions of macOS and/or all Linux distributions. If you have problems calling our API on 64-bit macOS or 64-bit Linux, + please contact us with full details of the platform and MATLAB version that you are using. +

+ +

Try It Yourself

+
+

+ The sample code is designed to teach you how to use the Dinkey Pro/FD API in MATLAB programs. + Do not copy the examples verbatim into your own code. Experiment with the sample code to understand how the API works, + and read the chapter Increasing Your Protection in the user manual for many suggestions on how to + make the best use of the API features. +

+
+

+ dpsample.m gives simple examples of performing a protection check, + as well as using various other features of Dinkey Pro/FD. + To run dpsample.m you will first need to use DinkeyAdd to produce a locked copy of the shared library for your platform, + and program a dongle (if you are using Plus or Net dongles). + Place the locked library in the same folder as the example files and change MATLAB's current directory to this folder. + Browse the examples in dpsample.m to see how different features can be used. + All the examples follow the same basic pattern: +

+
    +
  1. Set up the DRIS structure with the relevant information.
  2. +
  3. Call the API.
  4. +
  5. Use the information returned in the DRIS.
  6. +
+

+ Uncomment the function calls at the top of dpsample.m + to enable the examples of different features, then enter dpsample in the Command Window to run the examples. +

+

+ dpsample.m also demonstrates loading and unloading the appropriate shared library for your platform. +

+

+ Parts of the sample code marked with !!!! must be customised with your own functions or values + for some features to work correctly. Not all features are supported by all dongle models. + See the user manual for more information. +

+ + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/ddprotcheck.p b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/ddprotcheck.p new file mode 100644 index 0000000..787295f Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/ddprotcheck.p differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/dinkeypro32proto.p b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/dinkeypro32proto.p new file mode 100644 index 0000000..eab23ed Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/dinkeypro32proto.p differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/dinkeypro64proto.p b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/dinkeypro64proto.p new file mode 100644 index 0000000..84cd52c Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/dinkeypro64proto.p differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/dinkeyprowin32proto.p b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/dinkeyprowin32proto.p new file mode 100644 index 0000000..0876cac Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/dinkeyprowin32proto.p differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/dp64_thunk.dll b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/dp64_thunk.dll new file mode 100644 index 0000000..58bb549 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/dp64_thunk.dll differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/dp64_thunk.dylib b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/dp64_thunk.dylib new file mode 100644 index 0000000..56abdb1 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/dp64_thunk.dylib differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/dpsample.m b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/dpsample.m new file mode 100644 index 0000000..5de3b88 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/MATLAB/Runtime/dpsample.m @@ -0,0 +1,502 @@ +function dpsample +%DPSAMPLE Example use of the Dinkey Pro/FD API in MATLAB. + +% Copyright 2015 Microcosm Ltd. + + % Load the correct library for this platform + % !!!! If you rename the libraries as recommended in the user manual, + % !!!! you need to modify the lines below to use the new names. + switch computer() + case 'PCWIN64' % 64-bit Windows + loadlibrary('dpwin64.dll', @dinkeypro64proto, 'alias', 'dinkeypro'); + case 'PCWIN' % 32-bit Windows + loadlibrary('dpwin32.dll', @dinkeyprowin32proto, 'alias', 'dinkeypro'); + case 'GLNXA64' % 64-bit Linux + loadlibrary('dplin64.so', @dinkeypro64proto, 'alias', 'dinkeypro'); + case 'GLNX86' % 32-bit Linux + loadlibrary('dplin32.so', @dinkeypro32proto, 'alias', 'dinkeypro'); + case 'MACI64' % 64-bit Mac OS X + loadlibrary('dpmac64.dylib', @dinkeypro64proto, 'alias', 'dinkeypro'); + case 'MAC' % 32-bit Mac OS X + loadlibrary('dpmac32.dylib', @dinkeypro32proto, 'alias', 'dinkeypro'); + otherwise + disp('Error! Platform not supported!'); + return + end + + % Each of the functions below demonstrates different API functionality. + % Uncomment the appropriate functions to execute the examples. + % See the comments in each function for more details about the features + % that they demonstrate. + + protcheck('dinkeypro'); + %protcheckwithalg('dinkeypro'); + %writedataarea('dinkeypro'); + %readdataarea('dinkeypro'); + %encryptuserdata('dinkeypro'); + %protcheckenc('dinkeypro'); + %writedataareaenc('dinkeypro'); + %readdataareaenc('dinkeypro'); + + % Unload the library + unloadlibrary('dinkeypro'); +end + + +function protcheck(libName) +% An example of a basic protection check + + PROTECTION_CHECK = 1; + DEC_ONE_EXEC = 1; + START_NET_USER = 4; + + % Initialise the DRIS + dris.function = PROTECTION_CHECK; + dris.flags = bitor(DEC_ONE_EXEC, START_NET_USER); + + % Call the API + [retCode, dris] = ddprotcheck(libName, dris); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, dris.ext_err); + return + end + + % ... + + % You can check other values from the DRIS in other parts of your + % program to improve security. For example: + + % Check the SDSN + % !!!! "10101" is the SDSN used by the demo SDK and demo dongles + % !!!! If not using a demo, replace "10101" with your own SDSN here + if (dris.sdsn ~= 10101) + disp('Incorrect SDSN! Have you replaced "10101" with your SDSN in the sample code?'); + return + end + + % Check the product code + % !!!! Replace "DEMO" with the product code you specify when adding + % protection with DinkeyAdd + if (~strcmp(dris.prodcode, 'DEMO')) + disp('Incorrect product code! Have you replaced "DEMO" with your product code in the sample code?'); + return + end + + disp('Protection check successful'); +end + + +function protcheckwithalg(libName) +% An example of a protection check that also executes an algorithm stored +% in the dongle. +% The best way to use this feature is to identify lines of code in your +% program that can be represented by algorithms stored in the dongle, and +% replace these lines with calls to the API. Lite dongle users cannot +% change the algorithm stored in the dongles, so should calculate the +% algorithm in their own code and compare the result with the one returned +% by the API, as in this example. + + EXECUTE_ALGORITHM = 2; + + % Initialise the DRIS + dris.function = EXECUTE_ALGORITHM; + dris.alg_vars = [1 2 3 4 5 6 7 8]; % The input variables to use in the algorithm + dris.alg_number = 1; % The algorithm to execute. Lite dongles ignore this field, as they contain only 1 algorithm + + % Call the API + [retCode, dris] = ddprotcheck(libName, dris); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, dris.ext_err); + return + end + + + % Check the algorithm result in another part of your program to improve + % security. !!!! Ensure the myalgorithm() function matches the + % algorithm that was executed by the protection check! + if (dris.alg_answer ~= myalgorithm(dris.alg_vars)) + disp('Error! The algorithm result was not as expected.'); + return + end + + disp('Protection check with algorithm successful'); +end + + +function writedataarea(libName) +% An example of a protection check that also writes data to the dongle's +% secure data area. +% This feature is not supported by Lite dongles. +% Make sure you specify a large enough data area size when adding +% protection with DinkeyAdd! + + WRITE_DATA_AREA = 3; + + % Initialise the DRIS + dris.function = WRITE_DATA_AREA; + dris.rw_data = 'Hello, World!'; % Data to write + dris.rw_offset = 0; % Index to start writing at. Note indices start at zero! + + % Call the API + [retCode, dris] = ddprotcheck(libName, dris); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, dris.ext_err); + return + end + + disp('Writing data successful'); +end + + +function readdataarea(libName) +% An example of a protection check that also reads data from the dongle's +% secure data area. +% This feature is not supported by Lite dongles. +% Make sure you specify a large enough data area size when adding +% protection with DinkeyAdd! + + READ_DATA_AREA = 4; + + % Initialise the DRIS + dris.function = READ_DATA_AREA; + dris.rw_offset = 0; % Index to start reading at. Note indices start at zero! + dris.rw_length = 13; % How many bytes to read + + % Call the API + [retCode, dris] = ddprotcheck(libName, dris); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, dris.ext_err); + return + end + + disp(['Reading data successful: ' char(dris.rw_data)]); +end + + +function encryptuserdata(libName) +% An example of protection checks that encrypt/decrypt your data. +% This feature is not supported by Lite dongles. + + ENCRYPT_USER_DATA = 5; + DECRYPT_USER_DATA = 6; + + originalData = uint8(255 * rand(1, 10)); + + % Initialise the DRIS + dris.function = ENCRYPT_USER_DATA; + dris.rw_data = originalData; + dris.data_crypt_key_num = 1; + + % Call the API + [retCode, dris] = ddprotcheck(libName, dris); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, dris.ext_err); + return + end + + encryptedData = dris.rw_data; + + % Initialise the DRIS + dris.function = DECRYPT_USER_DATA; + + % Call the API + [retCode, dris] = ddprotcheck(libName, dris); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, dris.ext_err); + return + end + + decryptedData = dris.rw_data; + + disp('Data encryption successful'); + disp('Original data:'); + disp(originalData); + disp('Encrypted data:'); + disp(encryptedData); + disp('Decrypted data:'); + disp(decryptedData); +end + + +function protcheckenc(libName) +% An example of a protection check that uses DRIS encryption for extra +% security. + + PROTECTION_CHECK = 1; + + % Initialise the DRIS + dris.function = PROTECTION_CHECK; + dris.seed1 = uint8(255 * rand(1, 4)); % 4 random bytes + dris.seed2 = uint8(255 * rand(1, 4)); % 4 random bytes + + % Call the API + [retCode, dris] = ddprotcheck(libName, dris, @cryptdris); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, dris.ext_err); + return + end + + + % You can check other values from the DRIS in other parts of your + % program to improve security. For example: + + % Check the SDSN + % !!!! "10101" is the SDSN used by the demo SDK and demo dongles + % !!!! If not using a demo, replace "10101" with your own SDSN here + if (dris.sdsn ~= 10101) + disp('Incorrect SDSN! Have you replaced "10101" with your SDSN in the sample code?'); + return + end + + % Check the product code + % !!!! Replace "DEMO" with the product code you specify when adding + % protection with DinkeyAdd + if (~strcmp(dris.prodcode, 'DEMO')) + disp('Incorrect product code! Have you replaced "DEMO" with your product code in the sample code?'); + return + end + + disp('Protection check successful'); +end + + +function writedataareaenc(libName) +% An example of a protection check that also writes data to the dongle's +% secure data area. +% This feature is not supported by Lite dongles. +% Make sure you specify a large enough data area size when adding +% protection with DinkeyAdd! This function also uses DRIS encryption and +% encrypts the rw_data field for extra security. You must select these +% options in DinkeyAdd for this function to work correctly! + + WRITE_DATA_AREA = 3; + + % Initialise the DRIS + dris.function = WRITE_DATA_AREA; + dris.rw_offset = 0; + dris.seed1 = uint8(255 * rand(1, 4)); % 4 random bytes + dris.seed2 = uint8(255 * rand(1, 4)); % 4 random bytes + dris.alg_vars = randint(1 , 8, double([intmin intmax])); % 8 random signed 32-bit integers + + rwAlgAnswer = myrwalgorithm(dris.alg_vars); + + % Encrypt the data to be written to the dongle + dataToWrite = uint8('ABCDEFGHIJKLMNOPQRSTUVWXYZ'); + dris.rw_data = cryptapidata(dataToWrite, dris.seed1, dris.seed2, rwAlgAnswer); + + % Call the API + [retCode, dris] = ddprotcheck(libName, dris, @cryptdris); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, dris.ext_err); + return + end + + disp('Writing data successful'); +end + + +function readdataareaenc(libName) +% An example of a protection check that also reads data from the dongle's +% secure data area. +% This feature is not supported by Lite dongles. +% Make sure you specify a large enough data area size when adding +% protection with DinkeyAdd! This function also uses DRIS encryption and +% encrypts the rw_data field for extra security. You must select these +% options in DinkeyAdd for this function to work correctly! + + READ_DATA_AREA = 4; + + % Initialise the DRIS + dris.function = READ_DATA_AREA; + dris.rw_offset = 0; + dris.rw_length = 10; + dris.seed1 = uint8(255 * rand(1, 4)); % 4 random bytes + dris.seed2 = uint8(255 * rand(1, 4)); % 4 random bytes + dris.alg_vars = randint(1 , 8, double([intmin intmax])); % 8 random signed 32-bit integers + + % Call the API + [retCode, dris] = ddprotcheck(libName, dris, @cryptdris); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, dris.ext_err); + return + end + + % Decrypt the data read from the dongle + rwAlgAnswer = myrwalgorithm(dris.alg_vars); + dataRead = cryptapidata(dris.rw_data, dris.seed1, dris.seed2, rwAlgAnswer); + + disp(['Reading data successful: ' char(dataRead)]); +end + + +function ret = myalgorithm(algVars) +% !!!! This function must match one stored in the dongle for +% protcheckwithalg() to work correctly. +% For Lite dongles, use DinkeyLook to see the algorithm pre-programmed +% into the dongle. For Plus and Net dongles, ensure this algorithm matches +% one you specified in DinkeyAdd when adding protection. + ret = algVars(1) - algVars(2) - algVars(3) - algVars(4) - algVars(5) - algVars(6) - algVars(7); +end + + +function ret = myrwalgorithm(algVars) +% !!!! This function must match the R/W algorithm stored in the dongle for +% writedataareaenc() and readdataareaenc() to work correctly. + ret = algVars(1) - algVars(2) - algVars(3) - algVars(4) - algVars(5) - algVars(6); +end + + +function dris = cryptdris(dris) +% This function can be used to encrypt/decrypt the DRIS. If using DRIS +% encryption in your own program, copy this function exactly. Modify only +% the parts indicated by !!!! + + % !!!! Overwrite the encryption parameters with those chosen in + % DinkeyAdd. This example uses 123, 212, 97. + DRIS_ENCRYPTION_PARAMETERS = [123 212 97]; + + S = 0:255; + bigseed = zeros(256, 1); + + for i = 1:8:256 + for j = 0:3 + bigseed(i+j) = dris(9+j); + bigseed(i+j+4) = dris(13+j); + end + end + + j = 0; + for i = 0:255 + j = bitand((j + S(i+1) + bigseed(i+1) + DRIS_ENCRYPTION_PARAMETERS(1)), 255); + temp = S(i+1); + S(i+1) = S(j+1); + S(j+1) = temp; + end + + i = 0; + j = 0; + for k = 17:length(dris) + i = bitand((i + 1), 255); + j = bitand((j + S(i+1) + DRIS_ENCRYPTION_PARAMETERS(2)), 255); + temp = S(i+1); + S(i+1) = S(j+1); + S(j+1) = temp; + t = bitand((S(i+1) + S(j+1) + DRIS_ENCRYPTION_PARAMETERS(3)), 255); + dris(k) = bitxor(dris(k), S(t+1)); + end +end + + +function data = cryptapidata(data, seed1, seed2, algAnswer) +% This function is used to encrypt/decrypt data passed in the rw_data DRIS +% field (applies to Plus and Net dongles only). If using this feature in +% your own program, copy this function exactly. Modify only the parts +% indicated by !!!! + + % !!!! If you are using constant encryption parameters, define them + % like this: + % DATA_ENCRYPTION_PARAMETERS = [X Y Z]; + + + % !!!! If you are using the R/W algorithm, derive the encryption + % parameters from the algorithm result like this: + + % 1. Convert algAnswer to uint32 without changing underlying data + if (algAnswer < 0) + algAnswer = uint32(double(algAnswer) + hex2dec('FFFFFFFF') + 1); + else + algAnswer = uint32(algAnswer); + end + + % 2. Now algAnswer is a uint32 we can use bitwise operations to derive + % the encryption parameters + DATA_ENCRYPTION_PARAMETERS = [bitand(algAnswer, 255), bitand(bitshift(algAnswer,-8), 255), bitand(bitshift(algAnswer,-16), 255)]; + + + % The rest of the function should not be modified! + + S = 0:255; + bigseed = zeros(256, 1); + + for i = 1:8:256 + for j = 0:3 + bigseed(i+j) = seed1(j+1); + bigseed(i+j+4) = seed2(j+1); + end + end + + j = 0; + for i = 0:255 + j = bitand((j + S(i+1) + bigseed(i+1) + DATA_ENCRYPTION_PARAMETERS(1)), 255); + temp = S(i+1); + S(i+1) = S(j+1); + S(j+1) = temp; + end + + i = 0; + j = 0; + for k = 1:length(data) + i = bitand((i + 1), 255); + j = bitand((j + S(i+1) + DATA_ENCRYPTION_PARAMETERS(2)), 255); + temp = S(i+1); + S(i+1) = S(j+1); + S(j+1) = temp; + t = bitand((S(i+1) + S(j+1) + DATA_ENCRYPTION_PARAMETERS(3)), 255); + data(k) = bitxor(data(k), S(t+1)); + end +end + + +% An example of error reporting +% Displays descriptions for some common error codes +% IMPORTANT - THE MESSAGES DISPLAYED ARE TO HELP DEVELOPERS IMPLEMENT THE +% DINKEY PRO/FD API. THEY ARE NOT SUITABLE FOR DISPLAYING TO USERS! +function displayerror(retCode, extErr) + switch retCode + case 401 + disp('Error! No dongles detected!'); + case 403 + disp('Error! The dongle is a different type to the one specified in DinkeyAdd.'); + case 404 + disp('Error! The dongle is a different model to those specified in DinkeyAdd.'); + case 409 + disp('Error! The dongle has not been programmed by DinkeyAdd.'); + case 410 + disp('Error! The dongle has a different product code to the one specified in DinkeyAdd.'); + case 411 + disp('Error! This program''s licence was not found in the dongle.'); + case 413 + disp('Error! This program has not been locked by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the user manual.'); + case 417 + disp('Error! One or more of the parameters set in the DRIS is incorrect.'); + disp('Check that you have defined the necessary input fields in the DRIS struct.'); + disp('Also check if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.'); + case 423 + disp('Error! The number of network users has been exceeded.'); + case 435 + disp('Error! DinkeyServer has not been detected on the network.'); + case 922 + disp('Error! The Software Key has expired.'); + otherwise + str = sprintf('An error occurred checking the dongle. Error: %d, Extended Error: %d', retCode, extErr); + disp(str); + end +end diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/PHP/README.html b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/PHP/README.html new file mode 100644 index 0000000..accecb1 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/PHP/README.html @@ -0,0 +1,293 @@ + + + + + Using Dinkey Pro/FD with PHP + + + +

Using Dinkey Pro/FD with PHP

+
+

+ Protection checks in PHP are implemented using a PHP extension to communicate with the dongle. + You should use DinkeyAdd to lock this extension with the API protection method as described in the user manual, and distribute the locked file(s) with your software. +

+
+

+ If you are not already familiar with using PHP extensions, it is strongly recommended that you read the PHP documentation on the subject. + The Dinkey Pro/FD SDK includes a large number of different PHP extension files. Which one(s) you need to use depends on several factors, + including operating system, PHP version, architecture (e.g. x86 or x64) and thread safety. + This sample code includes a script, extensionhelper.php, that detects these factors, + indicates which extension is appropriate, and provides basic installation instructions. +

+

+ It is important that you consider which system configuration(s) your protected software will support, + and distribute the corresponding PHP extension(s). + You may wish to distribute extensionhelper.php along with your software + to help your users to install the correct extension for their system. + See Supported Versions below for full information on the platforms supported by Dinkey Pro/FD. +

+

+ Do not specify a calling program when locking the PHP extensions. + The calling program for PHP code is the user's web server (or PHP CLI), which will be different for different users. +

+
+

+ Before you distribute your PHP code, you must protect it from modification using a third-party tool such as + SourceGuardian. +

+
+ +

API Reference

+

+ See Modifying Your Code in the user manual for general information about the Dinkey Pro/FD API. + In PHP, DDProtCheck() and the DRIS structure are not directly accessible. + Instead, the PHP API provides two sets of functions: wrappers to DDProtCheck() that also take parameters that set DRIS input fields; + and functions that access DRIS output fields. +

+ +

Protection Check Functions

+

+ These functions each provide a wrapper to DDProtCheck() using a different function value. + Each function's return value is the return value of DDProtCheck() - zero on success, or a value indicating the cause of the error on failure. +

+ +

DDSimpleCheck ( int $flags ) : int

+

+ Sets the flags DRIS field and calls DDProtCheck() with the PROTECTION_CHECK function. +

+ +

DDSimpleCheckEx ( int $flags , int $execs_decrement, string $alt_licence_name ) : int

+

+ Sets the flags, execs_decrement and alt_licence_name DRIS fields + and calls DDProtCheck() with the PROTECTION_CHECK function. +

+ +

DDSimpleCheckAlg ( int $flags , int $alg_num , int $var_a , int $var_b , int $var_c , int $var_d , int $var_e , int $var_f , int $var_g , int $var_h ) : int

+

+ Sets the flags, alg_num and var_a to var_h DRIS fields + and calls DDProtCheck() with the EXECUTE_ALGORITHM function. +

+ +

DDSimpleCheckAlgEx ( int $flags , int $execs_dec, string $alt_licence_name , int $alg_number , int $var_a , int $var_b , int $var_c , int $var_d , int $var_e , int $var_f , int $var_g , int $var_h ) : int

+

+ Sets the flags, execs_decrement, alt_licence_name, alg_num and var_a to var_h DRIS fields + and calls DDProtCheck() with the EXECUTE_ALGORITHM function. +

+ +

DDWriteString ( int $flags , int $rw_offset , string $rw_data ) : int

+

+ Sets the flags, rw_offset and rw_data DRIS fields + and calls DDProtCheck() with the WRITE_DATA_AREA function. +

+

+ $rw_data must be an ASCII string. To write binary data, first encode it using base64_encode(). + The rw_length DRIS field is automatically set to the length of $rw_data. +

+ +

DDReadString ( int $flags , int $rw_offset , int $rw_length , string &$rw_data) : int

+

+ Sets the flags, rw_offset and rw_length DRIS fields + and calls DDProtCheck() with the READ_DATA_AREA function. + The data read is returned in $rw_data. +

+

+ Only use this function to read data that represents an ASCII string. + If you read bytes that do not represent ASCII characters, the string value returned in $rw_data may be unpredictable. + To read binary data, store it in the dongle data area as a base64-encoded sequence and use base64_decode() on the string returned in $rw_data. +

+ +

DDGet...() Functions

+

+ Each DDGet...() function takes one parameter by reference sets it to the value of the relevant DRIS element. + See Structures > DRIS Structure in the user manual for more information about the DRIS and its fields. + These functions return TRUE on success, or FALSE if the internal DRIS has not been populated by a call to one of the + DDProtCheck() wrapper functions above. +

+
    +
  • DDGetExtendedError ( int &$ext_err ) : bool
  • +
  • DDGetType ( int &$type ) : bool
  • +
  • DDGetModel ( int &$model ) : bool
  • +
  • DDGetSDSN ( int &$sdsn ) : bool
  • +
  • DDGetProdCode ( string &$prodcode ) : bool
  • +
  • DDGetDongleNumber ( int &$dongle_number ) : bool
  • +
  • DDGetUpdateNumber ( int &$update_number ) : bool
  • +
  • DDGetDataAreaSize ( int &$data_area_size ) : bool
  • +
  • DDGetMaxAlgNum ( int &$max_alg_num ) : bool
  • +
  • DDGetExecs ( int &$execs ) : bool
  • +
  • DDGetExpDay ( int &$exp_day ) : bool
  • +
  • DDGetExpMonth ( int &$exp_month ) : bool
  • +
  • DDGetExpYear ( int &$exp_year ) : bool
  • +
  • DDGetFeatures ( int &$features ) : bool
  • +
  • DDGetNetUsers ( int &$net_users ) : bool
  • +
  • DDGetAlgAnswer ( int &$alg_answer ) : bool
  • +
  • DDGetFDCapacity ( int &$fd_capacity ) : bool
  • +
  • DDGetFDDrive ( string &$fd_drive ) : bool
  • +
  • DDGetSWKeyType ( int &$swkey_type ) : bool
  • +
  • DDGetSWKeyExpDay ( int &$swkey_exp_day ) : bool
  • +
  • DDGetSWKeyExpMonth ( int &$swkey_exp_month ) : bool
  • +
  • DDGetSWKeyExpYear ( int &$swkey_exp_year ) : bool
  • +
+ +

PHP Example Files

+
    +
  • + dpsample.php - various examples of using the Dinkey Pro/FD PHP API. + This script outputs HTML and so is best used in a web server, but it can also be run using the PHP CLI. +
  • +
  • + extensionhelper.php - a script that detects system configuration to determine + the appropriate PHP extension to use, and where it should be located. + This script outputs HTML when used in a web server and plain text when executed by the PHP CLI. +
  • +
+ +

Supported Versions

+

+ The Dinkey Pro/FD SDK includes extensions for PHP versions 5.1 and newer on Windows and Linux. + The x86 and x64 architectures are both supported, and extensions are provided for both Thread Safe (TS) and Non-Thread Safe (NTS) builds of PHP. + Due to the large number of combinations of PHP version, OS, architecture and TS/NTS PHP builds, + the exact extension for your system may not be included in the SDK. + In this case, please contact us with full details of your platform. +

+ +

Try It Yourself

+
+

+ The sample code is designed to teach you how to use the Dinkey Pro/FD API in PHP programs. + Do not copy the examples verbatim into your own code. Experiment with the sample code to understand how the API works, + and read the chapter Increasing Your Protection in the user manual for many suggestions on how to + make the best use of the API features. +

+
+

+ To execute the sample code you will first need to use DinkeyAdd to produce a locked copy of the PHP extension for your system, + and program a dongle (if you are using Plus or Net dongles). Place the locked extension in your PHP extensions directory. + Use extensionhelper.php to determine the correct extension and the location of the extensions directory for your system. +

+

+ dpsample.php gives simple examples of performing a protection check, + as well as using various other features of Dinkey Pro/FD. + Browse the examples at the top of dpsample.php to see how different features can be used, + and uncomment the relevant lines to enable them. +

+

+ Not all features are supported by all dongle models. + See the user manual for more information. +

+ + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/PHP/dpsample.php b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/PHP/dpsample.php new file mode 100644 index 0000000..a673a8a --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/PHP/dpsample.php @@ -0,0 +1,181 @@ + + + + + + + Dinkey Pro/FD PHP API Sample Code + + + +

+ Protection check failed +

+

+ Error Code:
+ Extended Error Code:
+

+ +

+ Protection check succeeded +

+

+ + Algorithm result:
+ + + + Data read:
+ + + SDSN:
+ Product Code:
+ Dongle Number:
+ + Dongle Type:
+ + + Flash Drive Path:
+ + + Dongle Model:
+ + DONGLE_MODEL_LITE): ?> + Update Number:
+ Data Area Size:
+ Max Algorithm Number:
+ Executions:
+ Expiry Day:
+ Expiry Month:
+ Expiry Year:
+ Features:
+ + + DONGLE_MODEL_PLUS): ?> + Maximum Simultaneous Network Users:
+ + + + Software Key Type:
+ Software Key Expiry Day:
+ Software Key Expiry Month:
+ Software Key Expiry Year:
+ + + + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/PHP/extensionhelper.php b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/PHP/extensionhelper.php new file mode 100644 index 0000000..e7d5648 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/PHP/extensionhelper.php @@ -0,0 +1,146 @@ + + + + Dinkey Pro/FD PHP Extension Helper + + +

System Configuration

+ + + + ". ( ($os == "win") ? "" : "" ) ." + + + + +
Operating System:$osFriendlyName
PHP Version:{$info['server-config']['php-ver']}
Compiler:{$info['server-config']['compiler']}
Thread Safety:".(($info['server-config']['thread-safety'] == "ts") ? "Enabled" : "Disabled")."
Architecture:{$info['server-config']['arch']}-bit
PHP Extensions Directory:{$info['server-config']['ext-dir']}
PHP Configuration File:{$info['server-config']['php-ini-filename']}
+

Use the following PHP extension on this system: {$info['dp-ext-filename']}.

+

Installation

+
    +
  1. Lock {$info['dp-ext-filename']} with DinkeyAdd and copy the locked file to {$info['server-config']['ext-dir']}.

  2. +
  3. Edit the {$info['server-config']['php-ini-filename']} file to include the following line:
      extension={$info['dp-ext-filename']}

  4. + ". (($info['server-config']['webserver'] != "") ? "
  5. Restart {$info['server-config']['webserver']}.

  6. " : "") ." +
+ + + "; +} + + +$os = ""; +$version = ""; +$threadsafe = ""; +$compiler = ""; +$arch = ""; + +if (stristr(php_uname("s"), "linux") !== false) + $os = "lin"; +else if (stristr(php_uname("s"), "win") !== false) // Windows can be given as "Windows NT", or "WINNT"... just search for "win" + $os = "win"; + +$v = explode(".", PHP_VERSION); +$version = $v[0] . "." . $v[1]; + +$matches = array(); +$match = (bool) preg_match("/php extension build[^,]+,([NTS]{2,3}),?(VC[0-9]+)?/i", PHPINFO, $matches); +if ($match) +{ + $threadsafe = strtolower($matches[1]); + + if ($os == "win") + $compiler = strtolower($matches[2]); +} + +$i = intval("9223372036854775807"); +$s = strval($i); +if ($s == "9223372036854775807") + $arch = "64"; +else + $arch = "32"; + +if ($os == "") + die("Error, could not detect operating system."); +if ($threadsafe == "") + die("Error, could not detect thread-safety setting."); +if (($os == "win") && ($version >= 5.3) && ($compiler == "")) + die("Error, could not detect compiler version."); + +$filename = (($os=="lin") ? "lib" : "") . "dpphp-$os$arch-$version-$threadsafe" . (($os=="win" && $version>=5.3) ? "-$compiler" : "") . "." . (($os=="win") ? "dll" : "so"); + +$phpIniFilename = get_cfg_var('cfg_file_path'); +$extDir = ini_get("extension_dir"); + +$webserver = ""; +if (isset($_SERVER['SERVER_SOFTWARE'])) +{ + if (stripos($_SERVER['SERVER_SOFTWARE'], "iis") !== FALSE) + $webserver = "Microsoft IIS"; + else if (stripos($_SERVER['SERVER_SOFTWARE'], "apache") !== FALSE) + $webserver = "Apache"; + else + $webserver = "your HTTP server software"; +} + +$info = array( + 'server-config' => array( + 'os' => $os, + 'php-ver' => $version, + 'webserver' => $webserver, + 'compiler' => $compiler, + 'thread-safety' => (bool)($threadsafe == "ts"), + 'arch' => $arch, + 'ext-dir' => $extDir, + 'php-ini-filename' => $phpIniFilename + ), + + 'dp-ext-filename' => $filename, +); + +pretty_output($info); + +?> diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/Cython/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/Cython/README.txt new file mode 100644 index 0000000..467a086 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/Cython/README.txt @@ -0,0 +1,50 @@ +Cython Sample Code +~~~~~~~~~~~~~~~~~~ + +NB - tested under Python 2.7 and Python 3.6 with Cython 0.29 with Visual Studio C compiler +but it should work for all versions of Python, Cython and C compiler. (We also tested the +32-bit code using MinGW). + +If you are coding in Cython then you can link the Dinkey Pro/FD Runtime module directly to +your code (rather than having to call an external Python extension). See the notes for +Python sample code as to why this is preferable. Use: + +dpwin32_coff.obj for 32-bit code +dpwin64.obj for 64-bit code + +The source files in the project are: + +File name Description +objtest.pyx main source code file for Cython containing protection functions +objtest.pxd implements the DRIS structure and function definitions +ddpro.h Used by the pxd file so we can call DDProtCheck (a hack because it is + difficult to declare a stdcall function in a pxd file) +setup.py python file to compile the Cython sample code + +The sample code is just a guide. You should implement the protection in a stronger way +using the techniques described in the "Increasing your Protection" chapter of the manual. + +NB - our sample code assumes that you are using 64-bit Python 3. If not then you will have +to make some small modifications to setup.py: + +32-bit Python: modify extra_objects to list "dpwin32_coff.obj" instead of "dpwin64.obj" + +Python 2: modify 'language_level' to be "2" (If you are using an old version of Python/Cython + you may have to modify the objtest.pyx code. e.g. "DEMO" instead of b'DEMO' and use + print instead of print() + +To compile run the following command: + +python setup.py build_ext --inplace --compiler=msvc + +(for mingw32 use --compiler=mingw32) + +So a makefile could look like this: + +all: + python setup.py build_ext -c mingw32 --inplace + rm -rf ./build + rm -f *.c + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/Cython/ddpro.h b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/Cython/ddpro.h new file mode 100644 index 0000000..9e01a29 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/Cython/ddpro.h @@ -0,0 +1,2 @@ +int __stdcall DDProtCheck(void*, unsigned char*); +int __stdcall DDGetNetUserList(char*, int*, void*, int, int*); diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/Cython/objtest.pxd b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/Cython/objtest.pxd new file mode 100644 index 0000000..e15ff5a --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/Cython/objtest.pxd @@ -0,0 +1,62 @@ +#DRIS struture +cdef packed struct DRIS: + # the first 4 fields are never encrypted + char header[4] # should be set to DRIS + # inputs + int size # size of this structure + int seed1 # seed for data/dris encryption + int seed2 # as above + # (maybe encrypted from now on) + int function # specify only one function + int flags # options for the function selected. To use more than one OR them together: OPTION1 | OPTION2... + unsigned int execs_decrement # amount by which to dec execs if we use flag: DEC_MANY_EXECS + int data_crypt_key_num # number of the key (1-3) that the dongle uses to encrypt or decrypt user data + int rw_offset # offset in the dongle data area to read or write data + int rw_length # length of data are to read/write/encrypt/decrypt + char *rw_data_ptr # pointer to data to write / be read + char alt_prog_name[256] # protection check for different program instead of this one, must be null-terminated + int var_a # variable values for user algorithm + int var_b + int var_c + int var_d + int var_e + int var_f + int var_g + int var_h + int alg_number # the number of the user algorithm that you want to execute + # outputs + int ret_code # return code from the protection check + int ext_err # extended error + int type # type of dongle detected. 1 = Pro, 2 = FD + int model # model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + int sdsn # Software Developer's Serial Number + char prodcode[12] # Product Code (null-terminated) + unsigned int dongle_number + int update_number + unsigned int data_area_size # size of the data area used in the dongle detected + int max_alg_num # the maximum algorithm number in the dongle detected + int execs # executions left: -1 indicates 'no limit' + int exp_day # expiry day: -1 indicates 'no limit' + int exp_month # expiry month: -1 indicates 'no limit' + int exp_year # expiry year: -1 indicates 'no limit' + unsigned int features # features value + int net_users # maximum number of network users for the dongle detected: -1 indicates 'no limit' + int alg_answer # answer to the user algorithm executed with the given variable values + unsigned int fd_capacity # capacity of the data area in FD dongle. + char fd_drive[128] # drive letter of FD dongle detected e.g. 'f:\' (or mount name under Linux) + int swkey_type # 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + int swkey_exp_day # software key expiry date (if software key detected) + int swkey_exp_month + int swkey_exp_year + +#NU_INFO struture +cdef packed struct NU_INFO: + char licenceName[256] + char userName[50] + char computerName[256] + char ipAddress[16] + +# declare DDProtCheck (we do it like this because it is stdcall - the default for Cython is cdecl) +cdef extern from "ddpro.h": + int __stdcall DDProtCheck(void*, unsigned char*) + int __stdcall DDGetNetUserList(char*, int*, void*, int, int*) diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/Cython/objtest.pyx b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/Cython/objtest.pyx new file mode 100644 index 0000000..b44a721 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/Cython/objtest.pyx @@ -0,0 +1,647 @@ +from libc.string cimport memcpy +from libc.string cimport strlen +import random + +# The sample code contains 10 functions. You will not need to use all these +# functions in your code. Just use which ever functions are most appropriate +# and customise in your own way. The sample code is just a guide. You should +# implement the protection in a stronger way using the techniques described in +# the "Increasing your Protection" chapter of the manual. +# +# If you are using Dinkey Lite then you can only use 4 functions: +# ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + +# this file contains 10 protection-check functions. +# ProtCheck a standard protection check +# ProtCheckWithAlg a protection check & executing an Algorithm +# WriteBytes a protection check & write data to the dongle +# ReadBytes a protection check & read data from the dongle +# EncryptUserData a protection check & encrypting data and then decrypting the data + +# these functions are the same as the functions listed above but encrypting all parameters passed to our API +# ProtCheckEnc a standard protection check +# ProtCheckWithAlgEnc a protection check & executing an Algorithm +# WriteBytesEnc a protection check & write data to the dongle +# ReadBytesEnc a protection check & read data from the dongle +# EncryptUserDataEnc a protection check & encrypting data and then decrypting the data + +DEF MY_SDSN = 10101 # !!!! modify this value to your SDSN +DEF MY_PRODCODE = b'DEMO' # !!!! change this value to match the Product Code in the dongle + +# for some reason these constants have to be declared here rather than the pxd file +# functions - must specify only one +DEF PROTECTION_CHECK=1 # checks for dongle, check program params... +DEF EXECUTE_ALGORITHM=2 # protection check + calculate answer for specified algorithm with specified inputs +DEF WRITE_DATA_AREA=3 # protection check + writes dongle data area +DEF READ_DATA_AREA=4 # protection check + reads dongle data area +DEF ENCRYPT_USER_DATA=5 # protection check + the dongle will encrypt user data +DEF DECRYPT_USER_DATA=6 # protection check + the dongle will decrypt user data +DEF FAST_PRESENCE_CHECK=7 # checks for the presence of the correct dongle only with minimal security, no flags allowed. +DEF STOP_NET_USER=8 # stops a network user (a protection check is NOT performed) + +# flags - can specify as many as you like +DEF DEC_ONE_EXEC=1 # decrement execs by 1 +DEF DEC_MANY_EXECS=2 # decrement execs by number specified in execs_decrement +DEF START_NET_USER=4 # starts a network user +DEF USE_FUNCTION_ARGUMENT=16 # use the extra argument in the function for pointers +DEF CHECK_LOCAL_FIRST=32 # always look in local ports before looking in network ports +DEF CHECK_NETWORK_FIRST=64 # always look on the network before looking in local ports +DEF USE_ALT_PROG_NAME=128 # use name specified in prog_name instead of this program name +DEF DONT_SET_MAXDAYS_EXPIRY=256 # if the max days expiry date has not been calculated then do not do it this time +DEF MATCH_DONGLE_NUMBER=512 # restrict the search to match the dongle number specified in the DRIS +DEF DONT_RETURN_FD_DRIVE=1024 # if an FD dongle has been detected then don't return the flash drive/mount name + +# ************************* our 10 functions ********************************** + +# ************************** ProtCheck *************************************** +cpdef int ProtCheck(): + cdef DRIS dris + cdef int ret_code + + # set the DRIS to have random values + cdef unsigned char *drisbuf = &dris + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + # then set the values we want to use + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = PROTECTION_CHECK # standard protection check + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + ret_code = DDProtCheck(&dris, NULL) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + # later in your code you can check other values in the DRIS... + + if (dris.sdsn != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return -1 + + if (dris.prodcode != MY_PRODCODE): + print("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.") + return -1 + + # later on in your program you can check the return code again + if (dris.ret_code != 0): + print("Dinkey Dongle protection error") + return -1 + + print("It worked!") + return 0 + + +# ************************** ProtCheckWithAlg ****************************** + +# !!!! You should replace this function with the one generated by the +# "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) +# or from DinkeyLook if you are using a Dinkey Lite dongle. +# (If it does not generate source code for Python you have translate it from C) +cdef int MyAlgorithm(int a, int b, int c, int d, int e, int f, int g, int h): + return a + b + c + d + e + f + g + h + +# NB for this to work you must program at least "user algorithm" into the dongle +# NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +# sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +# code from DinkeyLook +cpdef int ProtCheckWithAlg(): + cdef DRIS dris + cdef int ret_code + + # set the DRIS to have random values + cdef unsigned char *drisbuf = &dris + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + # then set the values we want to use + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = EXECUTE_ALGORITHM # standard protection check and execute algorithm + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number = 1 # execute algorithm 1 (you do not need to specify this field if you are only using Lite models) + + ret_code = DDProtCheck(&dris, NULL) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + if (dris.sdsn != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return -1 + + # later on in your program you can check the return code again + if (dris.ret_code != 0): + print("Dinkey Dongle protection error") + return -1 + + # if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + # !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) != dris.alg_answer): + print("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine") + return -1 + + print("It worked!") + return 0 + + +# ************************** WriteBytes ****************************** +# This writes the string "Hello, World!" to the dongle data area at offset 7 +# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +cpdef int WriteBytes(): + cdef DRIS dris + cdef int ret_code + cdef char *datatowrite = "Hello, World!" + + # set the DRIS to have random values + cdef unsigned char *drisbuf = &dris + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + # then set the values we want to use + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = WRITE_DATA_AREA # standard protection check and write data + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset = 7 + dris.rw_length = strlen(datatowrite)+1 # include the null + dris.rw_data_ptr = datatowrite + + ret_code = DDProtCheck(&dris, NULL) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + if (dris.sdsn != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return -1 + + # later on in your program you can check the return code again + if (dris.ret_code != 0): + print("Dinkey Dongle protection error") + return -1 + + print("It worked!") + return 0 + +# ************************ ReadBytes ************************************ +# This reads 13 bytes of data from offset 7 in the dongle data area +# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +# In order for the data to be displayed properly by this routine it will need to be text data +cpdef ReadBytes(): + cdef DRIS dris + cdef int ret_code + cdef char datatoread[14] + + # set the DRIS to have random values + cdef unsigned char *drisbuf = &dris + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + # then set the values we want to use + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = READ_DATA_AREA # standard protection check and read data + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset = 7 + dris.rw_length = sizeof(datatoread) + dris.rw_data_ptr = datatoread + + ret_code = DDProtCheck(&dris, NULL) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + if (dris.sdsn != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return -1 + + # later on in your program you can check the return code again + if (dris.ret_code != 0): + print("Dinkey Dongle protection error") + return -1 + + print("It worked! Dinkey Dongle Data area, offset 7 is: " + str(datatoread)) + return 0 + +# ************************** EncryptUserData **************************** +# This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +# It will then do another protection check & decrypt the data +cpdef EncryptUserData(): + cdef DRIS dris + cdef int ret_code + cdef char *mydata = "Hello, World!" + cdef int data_length = strlen(mydata)+1 # include the NULL + + # set the DRIS to have random values + cdef unsigned char *drisbuf = &dris + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + # then set the values we want to use + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = ENCRYPT_USER_DATA # standard protection check and encrypt data + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num = 1 + dris.rw_length = data_length + dris.rw_data_ptr = mydata + + ret_code = DDProtCheck(&dris, NULL) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + # ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + # Now decrypt this (encrypted) data to get the original values + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = DECRYPT_USER_DATA # standard protection check and decrypt data + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num = 1 + dris.rw_length = data_length + dris.rw_data_ptr = mydata + + ret_code = DDProtCheck(&dris, NULL) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + print("It worked! Data decrypted is " + str(mydata)) + return 0 + +# !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! +# In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" +# in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm +# but the code can be modified easily to use the 3 encryption parameters. + +# !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm +# NB DinkeyAdd currently does not generate code for Python so you will have to translate it from C +cdef int MyRWAlgorithm(int a, int b, int c, int d, int e, int f, int g, int h): + return a ^ b ^ c ^ d ^ e ^ f + +# !!!! modify parameters 1,2 and 3 to match those specified in DinkeyAdd +cdef void CryptDRIS(DRIS *dris, unsigned int seed1, unsigned int seed2): + cdef int i, j, k, t + cdef unsigned char bigseed[256] + cdef unsigned char S[256] + cdef unsigned char temp + + for i in range(0, 256, 8): + memcpy(bigseed+i, &seed1, 4) + memcpy(bigseed+i+4, &seed2, 4) + for i in range(256): + S[i] = i + j = 0 + for i in range(256): + j = (j + S[i] + bigseed[i] + 123) % 256 # parameter 1 + temp = S[i] + S[i] = S[j] + S[j] = temp + i = 0 + j = 0 + for k in range(16, sizeof(DRIS)): + i = (i + 1) % 256 + j = (j + S[i] + 212) % 256 # parameter 2 + temp = S[i] + S[i] = S[j] + S[j] = temp + t = (S[i] + S[j] + 97) % 256 # parameter 3 + (dris)[k] ^= S[t] + return + +# !!!! modify parameters 1,2 and 3 to match those specified in DinkeyAdd (if you specified r/w algorithm then no need to modify anything) +cdef void CryptApiData(unsigned char *mydata, int length, unsigned int seed1, unsigned int seed2, int alg_answer): + cdef int i, j, k, t + cdef unsigned char bigseed[256] + cdef unsigned char S[256] + cdef unsigned char temp + + for i in range(0, 256, 8): + memcpy(bigseed+i, &seed1, 4) + memcpy(bigseed+i+4, &seed2, 4) + for i in range(256): + S[i] = i + j = 0 + for i in range(256): + j = (j + S[i] + bigseed[i] + (alg_answer & 0xff)) % 256 # parameter1 + temp = S[i] + S[i] = S[j] + S[j] = temp + i = 0 + j = 0 + for k in range(length): + i = (i + 1) % 256 + j = (j + S[i] + ((alg_answer >> 8) & 0xff)) % 256 # parameter 2 + temp = S[i] + S[i] = S[j] + S[j] = temp + t = (S[i] + S[j] + ((alg_answer >> 16) & 0xff)) % 256 # parameter 3 + (mydata)[k] ^= S[t] + return + +# ************************** ProtCheckEnc *************************************** +# We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file with parameters specified in DinkeyAdd +# NB if you are using the debug module then do not call CryptDRIS as DRIS encryption is not supported. See notes in C readme.txt +cpdef int ProtCheckEnc(): + cdef DRIS dris + cdef int ret_code + + # set the DRIS to have random values + cdef unsigned char *drisbuf = &dris + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + # then set the values we want to use + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = PROTECTION_CHECK # standard protection check + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + CryptDRIS(&dris, dris.seed1, dris.seed2) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL) + + CryptDRIS(&dris, dris.seed1, dris.seed2) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + # later in your code you can check other values in the DRIS... + + if (dris.sdsn != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return -1 + + if (dris.prodcode != MY_PRODCODE): + print("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.") + return -1 + + # later on in your program you can check the return code again + if (dris.ret_code != 0): + print("Dinkey Dongle protection error") + return -1 + + print("It worked!") + return 0 + + +# ************************** ProtCheckWithAlgEnc ****************************** + +# NB for this to work you must program at least "user algorithm" into the dongle +# NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +# sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +# code from DinkeyLook +# We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file with parameters specified in DinkeyAdd +cpdef int ProtCheckWithAlgEnc(): + cdef DRIS dris + cdef int ret_code + + # set the DRIS to have random values + cdef unsigned char *drisbuf = &dris + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + # then set the values we want to use + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = EXECUTE_ALGORITHM # standard protection check and execute algorithm + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number = 1 # execute algorithm 1 (you do not need to specify this field if you are only using Lite models) + + CryptDRIS(&dris, dris.seed1, dris.seed2) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL) + + CryptDRIS(&dris, dris.seed1, dris.seed2) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + if (dris.sdsn != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return -1 + + # later on in your program you can check the return code again + if (dris.ret_code != 0): + print("Dinkey Dongle protection error") + return -1 + + # if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + # !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) != dris.alg_answer): + print("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine") + return -1 + + print("It worked!") + return 0 + + +# ************************** WriteBytesEnc ****************************** +# This writes the string "Hello, World!" to the dongle data area at offset 7 +# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +# We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file with parameters specified in DinkeyAdd. +cpdef int WriteBytesEnc(): + cdef DRIS dris + cdef int ret_code, alg_answer + cdef char *datatowrite = "Hello, World!" + cdef string_length = strlen(datatowrite)+1 # include the null + + # set the DRIS to have random values + cdef unsigned char *drisbuf = &dris + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + # then set the values we want to use + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = WRITE_DATA_AREA # standard protection check and write data + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset = 7 + dris.rw_length = string_length + dris.rw_data_ptr = datatowrite + + # calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm specified in DinkeyAdd + alg_answer = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) + + # encrypt data we want to write. + CryptApiData(datatowrite, string_length, dris.seed1, dris.seed2, alg_answer) + + CryptDRIS(&dris, dris.seed1, dris.seed2) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL) + + CryptDRIS(&dris, dris.seed1, dris.seed2) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + if (dris.sdsn != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return -1 + + # later on in your program you can check the return code again + if (dris.ret_code != 0): + print("Dinkey Dongle protection error") + return -1 + + print("It worked!") + return 0 + +# ************************ ReadBytesEnc ************************************ +# This reads 13 bytes of data from offset 7 in the dongle data area +# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +# In order for the data to be displayed properly by this routine it will need to be text data +# We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file with parameters specified in DinkeyAdd. +cpdef ReadBytesEnc(): + cdef DRIS dris + cdef int ret_code, alg_answer + cdef char datatoread[14] + + # set the DRIS to have random values + cdef unsigned char *drisbuf = &dris + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + # then set the values we want to use + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = READ_DATA_AREA # standard protection check and read data + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset = 7 + dris.rw_length = sizeof(datatoread) + dris.rw_data_ptr = datatoread + + # calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm specified in DinkeyAdd + alg_answer = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) + + CryptDRIS(&dris, dris.seed1, dris.seed2) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL) + + CryptDRIS(&dris, dris.seed1, dris.seed2) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + if (dris.sdsn != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return -1 + + # later on in your program you can check the return code again + if (dris.ret_code != 0): + print("Dinkey Dongle protection error") + return -1 + + # decrypt data that was read + CryptApiData(datatoread, sizeof(datatoread), dris.seed1, dris.seed2, alg_answer) + + print("It worked! Dinkey Dongle Data area, offset 7 is: " + str(datatoread)) + return 0 + +# ************************** EncryptUserDataEnc **************************** +# This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +# It will then do another protection check & decrypt the data +# We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +cpdef EncryptUserDataEnc(): + cdef DRIS dris + cdef int ret_code, alg_answer + cdef char *mydata = "Hello, World!" + cdef int data_length = strlen(mydata)+1 # include the NULL + + # set the DRIS to have random values + cdef unsigned char *drisbuf = &dris + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + # then set the values we want to use + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = ENCRYPT_USER_DATA # standard protection check and encrypt data + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num = 1 + dris.rw_length = data_length + dris.rw_data_ptr = mydata + + # calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm specified in DinkeyAdd + alg_answer = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) + + # encrypt data we want to write. + CryptApiData(mydata, data_length, dris.seed1, dris.seed2, alg_answer) + + CryptDRIS(&dris, dris.seed1, dris.seed2) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL) + + CryptDRIS(&dris, dris.seed1, dris.seed2) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + # ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + # Now decrypt this (encrypted) data to get the original values + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = DECRYPT_USER_DATA # standard protection check and decrypt data + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num = 1 + dris.rw_length = data_length + dris.rw_data_ptr = mydata + + # calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm specified in DinkeyAdd + alg_answer = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) + + CryptDRIS(&dris, dris.seed1, dris.seed2) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL) + + CryptDRIS(&dris, dris.seed1, dris.seed2) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + # decrypt data that was pass to us by the API + CryptApiData(mydata, data_length, dris.seed1, dris.seed2, alg_answer) + + print("It worked! Data decrypted is " + str(mydata)) + return 0 + + +#displays messages for the most common errors. You will want to change this for your code +cdef void DisplayError(int ret_code, int extended_error): + cdef char szBuffer[200] + + if (ret_code == 401): + print("Error! No dongles detected!") + elif (ret_code == 403): + print("Error! The dongle detected has a different type to the one specified in DinkeyAdd.") + elif (ret_code == 404): + print("Error! The dongle detected has a different model to those specified in DinkeyAdd.") + elif (ret_code == 409): + print("Error! The dongle detected has not been programmed by DinkeyAdd.") + elif (ret_code == 410): + print("Error! The dongle detected has a different Product Code to the one specified in DinkeyAdd.") + elif (ret_code == 411): + print("Error! The dongle detected does not contain the licence associated with this program.") + elif (ret_code == 413): + print("Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual.") + elif (ret_code == 417): + print("Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.") + elif (ret_code == 423): + print("Error! The number of network users has been exceeded.") + elif (ret_code == 435): + print("Error! DinkeyServer has not been detected on the network.") + elif (ret_code == 922): + print("Error! The Software Key has expired.") + else: + print("An error occurred checking the dongle.\nError: " + str(ret_code) + ", Extended Error: " + str(extended_error)) + return diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/Cython/setup.py b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/Cython/setup.py new file mode 100644 index 0000000..6112e48 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/Cython/setup.py @@ -0,0 +1,16 @@ +from distutils.core import setup +from distutils.extension import Extension +from Cython.Distutils import build_ext + +my_modules = [ + Extension("objtest", ["objtest.pyx"], extra_objects=["dpwin64.obj", "advapi32.lib", "user32.lib"]), +] + +for e in my_modules: + e.cython_directives = {'language_level': "3"} #all are Python-3 + +setup( + name = 'objtest', + cmdclass = {'build_ext': build_ext}, + ext_modules = my_modules +) diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/README.txt new file mode 100644 index 0000000..ef743bd --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/README.txt @@ -0,0 +1,155 @@ +DllTest - sample code for Python +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This sample code will work with versions of Python 2.6 and higher. + +Note - for Cython Sample code please look in the Cython sub-folder. + +The source files in the project are: + +File name Description +dlltest.py main source code file for Python containing protection functions +dris.py contains useful constants and functions that implement the DRIS structure. + +The sample code works by calling a Python extension that communicates with the dongle. +The Python extension is located in the Modules/Python directory of the SDK. You need to +use the extension that matches the version of Python you are using. For each version of +Python we have extensions for each supported Operating System: + +dpwin32py.pyd - Windows 32-bit +dpwin64py.pyd - Windows 64-bit +dplin32py.so - Linux 32-bit +dplin64py.so - Linux 64-bit +dpmac64py.so - MacOS 64-bit + +Please contact Microcosm if you require a Python module for a different version to those we +provide and we will generate it for you. + +The sample code (dris.py) will automatically work out the OS and bitness and load the +appropriate extension for you. + +The sample code contains 10 functions which demonstrate some of the functionality offered by +the Dinkey Pro/FD system. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You should use DinkeyAdd to protect the Python extension(s) (e.g. dpmac64py.pyd etc...) and +not your Python code directly. Because your program is linked to the protected extension +then it is protected. + +How To Protect The Python Sample Code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use DinkeyAdd (using the API Method of protection) to protect the Dinkey Pro/FD Python +extensions we provide for the version of Python you want to support. (If you know which +Operating Systems you will support then you can just protect these extensions. If you are +not sure then just protect them all). + +For example, if you were just distributing on Windows with 64-bit python 3.x then you should +specify the extension: Modules/Python/x86-amd64/3.x/dpwin64py.pyd as the input pathname and +the location of your python code as the output pathname. Do this for each extension you want +to protect. In our example you will have the following in your sample code folder: + +dlltest.py +dris.py +dpwin64py.pyd [output from DinkeyAdd] + +To test everything is working run the sample code with and without the dongle attached. + +Note - the version of the extension you provide must match the version of Python that is +being run. If not you will get an error. In our experience this is different for each OS: +Windows: gives a sensible error message saying that the version of the extension is different. +Linux: We actually found that any 2.x extension could run on any 2.y Python (similar for 3.x). + Otherwise you get an error about PyInit_dpxxxx or init_dpxxx not being found in the + extension. +Mac: you get the very unhelpful error "PyThreadState_Get: no current thread" + + +How To Add Protection to your Python Code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +1) Modify your python code to check the dongle - you can base your protection check function + on those from dlltest.py in the sample code. The sample code in dlltest.py contains 10 + functions. You will not need to use all these functions in your code. Just use which ever + functions are most appropriate and customise in your own way. The sample code is just a + guide. You can implement the protection in a stronger way using the techniques described in + the "Increasing your Protection" chapter of the manual. + +2) You should import dris.py into your python code. + +3) You will probably want to modify some of the error messages in dris.py with your own. + However, you should still display or log any error codes returned by the protection check + otherwise you will not be able to identify the cause of the error. You can look up error + codes in our knowledge base: www.microcosm.com/kb. + +4) Protect the relevant Python extensions just like in the step above for the sample code. + +5) The protected Python extensions (for your version of Python) should be in the same + directory as the dris module. + +6) Compile your Python code (py files) to pyc files for distribution (see instructions below). + +Algorithms in Python +~~~~~~~~~~~~~~~~~~~~ + +Python implements modulo and integer division differently to other programming languages +like C, when it is applied to negative integers. Also, when you perform arithmetic in Python +it can expand the size of the variable to accommodate the size of the result. When the +algorithms are executed in the dongle they assume the output and all the inputs are signed +integers. To ensure that the algorithms are implemented in Python so that they match the +output of the dongle you need to be aware of the following: + +* use the mod function defined in dlltest.py instead of the operator % +* use the div function defined in dlltest.py instead of the integer operator // +* apply the function dris.make_signed32bit to the value of the algorithm to ensure the output + is a 32-bit signed value + +Level of Security +~~~~~~~~~~~~~~~~~ +You should not distribute your py code as this editable and therefore not secure (an end +user could edit the file and remove all the protection checks). You should distribute the +compiled pyc or pyo files and the protected extensions. These files contain byte-code. +You can do this by compiling your python code like this: + +python -m compile_all -b ./ [.\ for windows] + +This will generate the pyc files in the same directory as the py files (rather than the +__pycache__ directory) and ensure that they will work in a pyc-only distribution. + +However, although byte-code is not readable like source code, it is still possible to use +tools to decompile it back to source code. This will not be as easy to read as your source +code but a hacker might be able to work out what your code is doing, remove the protection +checks and re-compile. Also - it is possible to use tools that modify the byte-code directly. + +One way around this is to write your code (or the most sensitive parts of your code) in Cython +(see Cython sample code) or in pure C (see C/C++ sample code). This is recommended if you have +the skills to do it. Another technique is to use a Python obfuscator so that the bytecode is +much more difficult to understand. + +Another tool you could look at is Nuitka (nuitka.net) which converts Python code to C and then +compiles it. + +Another possible hack is to use the Python interpreter to replace the protection check function +with a function that the hacker has written himself. You can combat this hack by using a user +algorithm or (not quite so good) reading data from the dongle data area. This works because it +means that the hacker would have to work out the algorithm (data) to defeat the protection. +Another solution is write some of your code in pure C and call it from Python. + +Note - you may be tempted to not modify your source code and instead use py2exe and the Shell +Method to protect the resulting executable. However, this is not secure as the "compiled" +executable file is just a loader. Your compiled Python code is also included in the library.zip +file, so someone could just extract these files and use them. Therefore you should not use this +method but to use the API method with the source code instead. You can then use py2exe +(without the Shell method) if you prefer to distribute your software this way. + +This is also the case for any other Python-to-executable software unless it specifically says +that your compiled Python code is encrypted. We have not seen this feature in any Python-to-exe +converter. diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/dlltest.py b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/dlltest.py new file mode 100644 index 0000000..68c2f4f --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/dlltest.py @@ -0,0 +1,574 @@ +import dris # code that communicates with the Dinkey Pro/FD runtime extension +import sys # so we can load the correct extension dependent on OS & bitness + +# The sample code contains 10 functions. You will not need to use all these +# functions in your code. Just use which ever functions are most appropriate +# and customise in your own way. The sample code is just a guide. You should +# implement the protection in a stronger way using the techniques described in +# the "Increasing your Protection" chapter of the manual. +# +# If you are using Dinkey Lite then you can only use 4 functions: +# ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + + +# this file contains 10 protection-check functions. +# ProtCheck a standard protection check +# ProtCheckWithAlg a protection check & executing an Algorithm +# WriteBytes a protection check & write data to the dongle +# ReadBytes a protection check & read data from the dongle +# EncryptUserData a protection check & encrypting data and then decrypting the data + +# these functions are the same as the functions listed above but encrypting all parameters passed to our API +# ProtCheckEnc a standard protection check +# ProtCheckWithAlgEnc a protection check & executing an Algorithm +# WriteBytesEnc a protection check & write data to the dongle +# ReadBytesEnc a protection check & read data from the dongle +# EncryptUserDataEnc a protection check & encrypting data and then decrypting the data + +MY_SDSN = 10101 # !!!! change this value to be the value of your SDSN (demo = 10101) +MY_PRODCODE = "DEMO" # !!!! change this value to be the value of the Product Code in the dongle + +# ************************* our 10 functions ********************************** + +# ************************** ProtCheck *************************************** +def ProtCheck(): + # create the DRIS and allocate the values we want to use + mydris = dris.create() + dris.set_function(mydris, dris.PROTECTION_CHECK) # standard protection check + dris.set_flags(mydris, 0) # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + ret_code = DDProtCheck(mydris) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris)) + return + + # later in your code you can check other values in the DRIS... + if (dris.get_sdsn(mydris) != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return + + if (dris.get_prodcode(mydris) != MY_PRODCODE): + print("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.") + return + + # later on in your program you can check the return code again + if (dris.get_ret_code(mydris) != 0): + print("Dinkey Dongle protection error") + return + + print("It worked!") + return ret_code + +# ************************** ProtCheckWithAlg ****************************** + +# this function should be used instead of % for modulo as python calculates this differently to C for negative numbers +def mod(x, y): + return abs(x)%abs(y)*(1,-1)[x<0] + +# this function should be used instead of // for integer division as python calculates this differently to C for negative numbers +def div(x, y): + if (x >= 0) != (y >= 0) and x % y: + return x // y + 1 + else: + return x // y + +# !!!! You should replace this function with the one generated by the +# "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) +# or from DinkeyLook if you are using a Dinkey Lite dongle. +# (If it does not generate source code for Python you have translate it from C but use the mod function instead of % and div instead of //) +def MyAlgorithm(a, b, c, d, e, f, g, h): + value = a + b + c + d + e + f + g + h # place your algorithm here using mod instead of % and div instead of // + return dris.make_signed32bit(value) # this line always needs to be here to convert the value to a signed 32bit integer + +# NB for this to work you must program at least "user algorithm" into the dongle +# NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +# sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +# code from DinkeyLook +def ProtCheckWithAlg(): + # create the DRIS and allocate the values we want to use + mydris = dris.create() + dris.set_function(mydris, dris.EXECUTE_ALGORITHM) # standard protection check & execute algorithm + dris.set_flags(mydris, 0) # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.set_alg_number(mydris, 1) # execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + # you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.set_var_a(mydris, 1) # sample values + dris.set_var_b(mydris, 2) + dris.set_var_c(mydris, 3) + dris.set_var_d(mydris, 4) + dris.set_var_e(mydris, 5) + dris.set_var_f(mydris, 6) + dris.set_var_g(mydris, 7) + dris.set_var_h(mydris, 8) + + ret_code = DDProtCheck(mydris) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris)) + return + + # later in your code you can check other values in the DRIS... + if (dris.get_sdsn(mydris) != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return + + # later on in your program you can check the return code again + if (dris.get_ret_code(mydris) != 0): + print("Dinkey Dongle protection error") + return + + # if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + # !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if MyAlgorithm(dris.get_var_a(mydris), dris.get_var_b(mydris), dris.get_var_c(mydris), dris.get_var_d(mydris), dris.get_var_e(mydris), \ + dris.get_var_f(mydris), dris.get_var_g(mydris), dris.get_var_h(mydris)) != dris.get_alg_answer(mydris): + print("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine") + return + + print("It worked!") + return ret_code + +# ************************** WriteBytes ****************************** +# This writes the string "Hello, World!" to the dongle data area at offset 7 +# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +def WriteBytes(): + datatowrite = bytearray("Hello, World!", "ascii") + # create the DRIS and allocate the values we want to use + mydris = dris.create() + dris.set_function(mydris, dris.WRITE_DATA_AREA) # standard protection check and write data + dris.set_flags(mydris, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python + dris.set_rw_offset(mydris, 7) + dris.set_rw_length(mydris, len(datatowrite)) + + ret_code = DDProtCheck(mydris, datatowrite) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris)) + return + + # later in your code you can check other values in the DRIS... + if (dris.get_sdsn(mydris) != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return + + # later on in your program you can check the return code again + if (dris.get_ret_code(mydris) != 0): + print("Dinkey Dongle protection error") + return + + print("It worked!") + return ret_code + +# ************************ ReadBytes ************************************ +# This reads 13 bytes of data from offset 7 in the dongle data area +# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +# In order for the data to be displayed properly by this routine it will need to be text data +def ReadBytes(): + datatoread = bytearray(13) + # create the DRIS and allocate the values we want to use + mydris = dris.create() + dris.set_function(mydris, dris.READ_DATA_AREA) # standard protection check and read data + dris.set_flags(mydris, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python + dris.set_rw_offset(mydris, 7) + dris.set_rw_length(mydris, len(datatoread)) + + ret_code = DDProtCheck(mydris, datatoread) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris)) + return + + # later in your code you can check other values in the DRIS... + if (dris.get_sdsn(mydris) != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return + + # later on in your program you can check the return code again + if (dris.get_ret_code(mydris) != 0): + print("Dinkey Dongle protection error") + return + + print("It worked! Dinkey Dongle Data area, offset 7 is " + datatoread.decode("ascii")) + return ret_code + +# ************************** EncryptUserData **************************** +# This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +# It will then do another protection check & decrypt the data +def EncryptUserData(): + data = bytearray("Hello, World!", "ascii") + # create the DRIS and allocate the values we want to use + mydris = dris.create() + dris.set_function(mydris, dris.ENCRYPT_USER_DATA) # standard protection check and encrypt data + dris.set_flags(mydris, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python + dris.set_data_crypt_key_num(mydris, 1) + dris.set_rw_length(mydris, len(data)) + + ret_code = DDProtCheck(mydris, data) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris)) + return + + # ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + # Now decrypt this (encrypted) data to get the original values + mydris2 = dris.create() + dris.set_function(mydris2, dris.DECRYPT_USER_DATA) # standard protection check and decrypt data + dris.set_flags(mydris2, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python + dris.set_data_crypt_key_num(mydris2, 1) + dris.set_rw_length(mydris2, len(data)) + + ret_code = DDProtCheck(mydris2, data) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris2)) + return + + # later in your code you can check other values in the DRIS... + if (dris.get_sdsn(mydris2) != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return + + # later on in your program you can check the return code again + if (dris.get_ret_code(mydris2) != 0): + print("Dinkey Dongle protection error") + return + + print("It worked! Data decrypted is " + data.decode("ascii")) + return ret_code + +# !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! +# In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" +# in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm +# but the code can be modified easily to use the 3 encryption parameters. + +# !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm +# NB DinkeyAdd currently does not generate code for Python so you will have to translate it from C +def MyRWAlgorithm(a, b, c, d, e, f, g, h): + value = a ^ b ^ c ^ d ^ e ^ f + return dris.make_signed32bit(value) + +# !!!! please overwrite this function with the one generated by DinkeyAdd +# It is not generated by DinkeyAdd for Python currently so just modify parameters 1,2 and 3 accordingly +def CryptDRIS(mydris): + bigseed = bytearray(256) + S = bytearray(256) + + for i in range(0, 256, 8): + bigseed[i:i+4] = mydris[8:12] # seed1 + bigseed[i+4:i+8] = mydris[12:16] # seed2 + + for i in range(256): + S[i] = i + + j = 0 + for i in range(256): + j = (j + S[i] + bigseed[i] + 123) % 256 # !!!! parameter 1 + temp = S[i] + S[i] = S[j] + S[j] = temp + + i = 0 + j = 0 + for k in range(16,dris.DRIS_SIZE): + i = (i + 1) % 256 + j = (j + S[i] + 212) % 256 # !!!! parameter 2 + temp = S[i] + S[i] = S[j] + S[j] = temp + t = (S[i] + S[j] + 97) % 256 # !!!! parameter 3 + mydris[k] = mydris[k] ^ S[t] + return + +# !!!! please overwrite this function with the one generated by DinkeyAdd +# It is not generated by DinkeyAdd for Python currently. This is set-up for using r/w parameters +def CryptApiData(data, mydris, length, alg_answer): + bigseed = bytearray(256) + S = bytearray(256) + + for i in range(0, 256, 8): + bigseed[i:i+4] = mydris[8:12] # seed1 + bigseed[i+4:i+8] = mydris[12:16] # seed2 + + for i in range(256): + S[i] = i + + j = 0 + for i in range(256): + j = (j + S[i] + bigseed[i] + (alg_answer & 0xff)) % 256 # parameter 1 + temp = S[i] + S[i] = S[j] + S[j] = temp + + i = 0 + j = 0 + for k in range(length): + i = (i + 1) % 256 + j = (j + S[i] + ((alg_answer >> 8) & 0xff)) % 256 # parameter 2 + temp = S[i] + S[i] = S[j] + S[j] = temp + t = (S[i] + S[j] + ((alg_answer >> 16) & 0xff)) % 256 # parameter 3 + data[k] = data[k] ^ S[t] + return + +# ************************* ProtCheckEnc ******************************* +def ProtCheckEnc(): + # We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. + mydris = dris.create() + dris.set_function(mydris, dris.PROTECTION_CHECK) # standard protection check + dris.set_flags(mydris, 0) # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + CryptDRIS(mydris) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris) + + CryptDRIS(mydris) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris)) + return + + # later in your code you can check other values in the DRIS... + if (dris.get_sdsn(mydris) != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return + + if (dris.get_prodcode(mydris) != MY_PRODCODE): + print("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.") + return + + # later on in your program you can check the return code again + if (dris.get_ret_code(mydris) != 0): + print("Dinkey Dongle protection error") + return + + print("It worked!") + return ret_code + +# ************************ ProtCheckWithAlgEnc *********************** +# NB for this to work you must program at least "user algorithm" into the dongle +# NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +# sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +# code from DinkeyLook +# We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +def ProtCheckWithAlgEnc(): + # create the DRIS and allocate the values we want to use + mydris = dris.create() + dris.set_function(mydris, dris.EXECUTE_ALGORITHM) # standard protection check & execute algorithm + dris.set_flags(mydris, 0) # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.set_alg_number(mydris, 1) # execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + # you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.set_var_a(mydris, 1) # sample values + dris.set_var_b(mydris, 2) + dris.set_var_c(mydris, 3) + dris.set_var_d(mydris, 4) + dris.set_var_e(mydris, 5) + dris.set_var_f(mydris, 6) + dris.set_var_g(mydris, 7) + dris.set_var_h(mydris, 8) + + CryptDRIS(mydris) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris) + + CryptDRIS(mydris) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris)) + return + + # later in your code you can check other values in the DRIS... + if (dris.get_sdsn(mydris) != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return + + # later on in your program you can check the return code again + if (dris.get_ret_code(mydris) != 0): + print("Dinkey Dongle protection error") + return + + # if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + # !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if MyAlgorithm(dris.get_var_a(mydris), dris.get_var_b(mydris), dris.get_var_c(mydris), dris.get_var_d(mydris), dris.get_var_e(mydris), \ + dris.get_var_f(mydris), dris.get_var_g(mydris), dris.get_var_h(mydris)) != dris.get_alg_answer(mydris): + print("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine") + return + + print("It worked!") + return ret_code + +# ************************** WriteBytesEnc ****************************** +# This writes the string "Hello, World!" to the dongle data area at offset 7 +# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +# We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +def WriteBytesEnc(): + datatowrite = bytearray("Hello, World!", "ascii") + # create the DRIS and allocate the values we want to use + mydris = dris.create() + dris.set_function(mydris, dris.WRITE_DATA_AREA) # standard protection check and write data + dris.set_flags(mydris, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python + dris.set_rw_offset(mydris, 7) + dris.set_rw_length(mydris, len(datatowrite)) + + # calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.get_var_a(mydris), dris.get_var_b(mydris), dris.get_var_c(mydris), dris.get_var_d(mydris), \ + dris.get_var_e(mydris), dris.get_var_f(mydris), dris.get_var_g(mydris), dris.get_var_h(mydris)) + + # encrypt data we want to write. + CryptApiData(datatowrite, mydris, len(datatowrite), alg_ans) + + CryptDRIS(mydris) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, datatowrite) + + CryptDRIS(mydris) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris)) + return + + # later in your code you can check other values in the DRIS... + if (dris.get_sdsn(mydris) != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return + + # later on in your program you can check the return code again + if (dris.get_ret_code(mydris) != 0): + print("Dinkey Dongle protection error") + return + + print("It worked!") + return ret_code + +# ************************ ReadBytesEnc ************************************ +# This reads 13 bytes of data from offset 7 in the dongle data area +# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +# In order for the data to be displayed properly by this routine it will need to be text data +# We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +def ReadBytesEnc(): + datatoread = bytearray(13) + # create the DRIS and allocate the values we want to use + mydris = dris.create() + dris.set_function(mydris, dris.READ_DATA_AREA) # standard protection check and read data + dris.set_flags(mydris, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python + dris.set_rw_offset(mydris, 7) + dris.set_rw_length(mydris, len(datatoread)) + + # calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.get_var_a(mydris), dris.get_var_b(mydris), dris.get_var_c(mydris), dris.get_var_d(mydris), \ + dris.get_var_e(mydris), dris.get_var_f(mydris), dris.get_var_g(mydris), dris.get_var_h(mydris)) + + CryptDRIS(mydris) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, datatoread) + + CryptDRIS(mydris) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris)) + return + + # later in your code you can check other values in the DRIS... + if (dris.get_sdsn(mydris) != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return + + # later on in your program you can check the return code again + if (dris.get_ret_code(mydris) != 0): + print("Dinkey Dongle protection error") + return + + # decrypt data that was read + CryptApiData(datatoread, mydris, len(datatoread), alg_ans) + print("It worked! Dinkey Dongle Data area, offset 7 is " + datatoread.decode("ascii")) + return ret_code + +# ************************** EncryptUserDataEnc **************************** +# This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +# It will then do another protection check & decrypt the data +# We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +def EncryptUserDataEnc(): + data = bytearray("Hello, World!", "ascii") + # create the DRIS and allocate the values we want to use + mydris = dris.create() + dris.set_function(mydris, dris.ENCRYPT_USER_DATA) # standard protection check and encrypt data + dris.set_flags(mydris, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python + dris.set_data_crypt_key_num(mydris, 1) + dris.set_rw_length(mydris, len(data)) + + # calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.get_var_a(mydris), dris.get_var_b(mydris), dris.get_var_c(mydris), dris.get_var_d(mydris), \ + dris.get_var_e(mydris), dris.get_var_f(mydris), dris.get_var_g(mydris), dris.get_var_h(mydris)) + + # encrypt data we want to pass. + CryptApiData(data, mydris, len(data), alg_ans) + + CryptDRIS(mydris) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, data) + + CryptDRIS(mydris) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris)) + return + + # ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + # Now decrypt this (encrypted) data to get the original values + mydris2 = dris.create() + dris.set_function(mydris2, dris.DECRYPT_USER_DATA) # standard protection check and decrypt data + dris.set_flags(mydris2, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python + dris.set_data_crypt_key_num(mydris2, 1) + dris.set_rw_length(mydris2, len(data)) + + CryptDRIS(mydris2) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris2, data) + + CryptDRIS(mydris2) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris2)) + return + + # later in your code you can check other values in the DRIS... + if (dris.get_sdsn(mydris2) != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return + + # later on in your program you can check the return code again + if (dris.get_ret_code(mydris2) != 0): + print("Dinkey Dongle protection error") + return + + alg_ans = MyRWAlgorithm(dris.get_var_a(mydris2), dris.get_var_b(mydris2), dris.get_var_c(mydris2), dris.get_var_d(mydris2), \ + dris.get_var_e(mydris2), dris.get_var_f(mydris2), dris.get_var_g(mydris2), dris.get_var_h(mydris2)) + + # decrypt data passed to us by the API + CryptApiData(data, mydris2, len(data), alg_ans) + + print("It worked! Data decrypted is " + data.decode("ascii")) + return ret_code + +# entry point +if __name__ == "__main__": + # load the correct extension dependent on the OS and bitness of Python + if sys.platform == 'win32': + if sys.maxsize > 2**32: + from dpwin64py import DDProtCheck + else: + from dpwin32py import DDProtCheck + elif 'linux' in sys.platform: + if sys.maxsize > 2**32: + from dplin64py import DDProtCheck + else: + from dplin32py import DDProtCheck + elif sys.platform == 'darwin': + if sys.maxsize > 2**32: + from dpmac64py import DDProtCheck + else: + from dpmac32py import DDProtCheck + + # choose the protection check function of your choice here. We have chosen the basic protection check. + ProtCheck() diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/dris.py b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/dris.py new file mode 100644 index 0000000..a904565 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Python/dris.py @@ -0,0 +1,254 @@ +import random +import sys + +#define constants + +#these constants depend on the bitness of the OS - the DRIS is 4 bytes bigger for 64-bit code +if sys.maxsize > 2**32: + DRIS_SIZE = 564 # DRIS size is bigger for 64-bit (it has an 8-byte pointer) + python64 = 4 # so we can adjust structure offsets for 64-bit python +else: + DRIS_SIZE = 560 + python64 = 0 + +#function values +PROTECTION_CHECK = 1 # checks for dongle, check program params... +EXECUTE_ALGORITHM = 2 # protection check + calculate answer for specified algorithm with specified inputs +WRITE_DATA_AREA = 3 # protection check + writes dongle data area +READ_DATA_AREA = 4 # protection check + reads dongle data area +ENCRYPT_USER_DATA = 5 # protection check + the dongle will encrypt user data +DECRYPT_USER_DATA = 6 # protection check + the dongle will decrypt user data +FAST_PRESENCE_CHECK = 7 # checks for the presence of the correct dongle only with minimal security, no flags allowed. +STOP_NET_USER = 8 # stops a network user (a protection check is NOT performed) + +# flags - can specify as many as you like +DEC_ONE_EXEC = 1 # decrement execs by 1 +DEC_MANY_EXECS = 2 # decrement execs by number specified in execs_decrement +START_NET_USER = 4 # starts a network user +USE_FUNCTION_ARGUMENT = 16 # use the extra argument in the function for pointers +CHECK_LOCAL_FIRST = 32 # always look in local ports before looking in network ports +CHECK_NETWORK_FIRST = 64 # always look on the network before looking in local ports +USE_ALT_LICENCE_NAME = 128 # use name specified in alt_licence_name instead of the default one +DONT_SET_MAXDAYS_EXPIRY = 256 # if the max days expiry date has not been calculated then do not do it this time +MATCH_DONGLE_NUMBER = 512 # restrict the search to match the dongle number specified in the DRIS +DONT_RETURN_FD_DRIVE = 1024 # if an FD dongle has been detected then don't return the flash drive/mount name + +# set 4 bytes in our DRIS byte array from an integer +def set4bytes(data, offset, value): + data[offset] = value & 0xff + data[offset+1] = (value >> 8) & 0xff + data[offset+2] = (value >> 16) & 0xff + data[offset+3] = (value >> 24) & 0xff + return + +# trunctates a value to 32-bit and converts to a signed integer +def make_signed32bit(value): + value = value & 0xffffffff + if (value > (2**31)): + value = value - (2**32) + return value + +# get 4 bytes in our DRIS byte array and convert to an unsigned integer +# this returns an unsigned value, which is useful for dongle number, features, etc... +def get4bytes(data, offset): + return (data[offset] + data[offset+1]*0x100 + data[offset+2]*0x10000 + data[offset+3]*0x1000000) + +# this returns a signed value, which is useful for alg_answer, expiry day... +def get4bytes_signed(data, offset): + value = data[offset] + data[offset+1]*0x100 + data[offset+2]*0x10000 + data[offset+3]*0x1000000 + if (value > (2**31)): + value = value - (2**32) + return value + +# create the DRIS structure as a byte array, populate it with random values, initialise the header and size fields +def create(): + dris = bytearray(DRIS_SIZE) + random.seed() + for n in range(DRIS_SIZE): + dris[n] = random.randint(0, 255) + dris[0] = ord('D') + dris[1] = ord('R') + dris[2] = ord('I') + dris[3] = ord('S') + set4bytes(dris, 4, DRIS_SIZE) + return dris + +# these functions set various values in the DRIS +def set_function(dris, value): + set4bytes(dris, 16, value) + +def set_flags(dris, value): + set4bytes(dris, 20, value) + +def set_execs_decrement(dris, value): + set4bytes(dris, 24, value) + +def set_data_crypt_key_num(dris, value): + set4bytes(dris, 28, value) + +def set_rw_offset(dris, value): + set4bytes(dris, 32, value) + +def set_rw_length(dris, value): + set4bytes(dris, 36, value) + +def set_alt_licence_name(dris, licence_name): + dris[44+python64:44+python64+len(licence_name)] = licence_name + dris[44+python64+len(licence_name)] = 0 # null-terminate the string + +def set_var_a(dris, value): + set4bytes(dris, 300+python64, value) + +def set_var_b(dris, value): + set4bytes(dris, 304+python64, value) + +def set_var_c(dris, value): + set4bytes(dris, 308+python64, value) + +def set_var_d(dris, value): + set4bytes(dris, 312+python64, value) + +def set_var_e(dris, value): + set4bytes(dris, 316+python64, value) + +def set_var_f(dris, value): + set4bytes(dris, 320+python64, value) + +def set_var_g(dris, value): + set4bytes(dris, 324+python64, value) + +def set_var_h(dris, value): + set4bytes(dris, 328+python64, value) + +def set_alg_number(dris, value): + set4bytes(dris, 332+python64, value) + +# these functions get values from the DRIS +def get_ret_code(dris): + return get4bytes(dris, 336+python64) + +def get_ext_err(dris): + return get4bytes(dris, 340+python64) + +def get_type(dris): + return get4bytes(dris, 344+python64) + +def get_model(dris): + return get4bytes(dris, 348+python64) + +def get_sdsn(dris): + return get4bytes(dris, 352+python64) + +def get_prodcode(dris): + for n in range(356+python64,368+python64): + if dris[n] == 0: + break + return dris[356+python64:n].decode("utf-8") + +def get_dongle_number(dris): + return get4bytes(dris, 368+python64) + +def get_update_number(dris): + return get4bytes(dris, 372+python64) + +def get_data_area_size(dris): + return get4bytes(dris, 376+python64) + +def get_max_alg_num(dris): + return get4bytes(dris, 380+python64) + +def get_execs(dris): + return get4bytes(dris, 384+python64) + +def get_exp_day(dris): + return get4bytes_signed(dris, 388+python64) + +def get_exp_month(dris): + return get4bytes_signed(dris, 392+python64) + +def get_exp_year(dris): + return get4bytes_signed(dris, 396+python64) + +def get_features(dris): + return get4bytes(dris, 400+python64) + +def get_net_users(dris): + return get4bytes(dris, 404+python64) + +def get_alg_answer(dris): + return get4bytes_signed(dris, 408+python64) + +def get_fd_capacity(dris): + return get4bytes(dris, 412+python64) + +def get_fd_drive(dris): + for n in range(416+python64,544+python64): + if dris[n] == 0: + break + return dris[416+python64:n].decode("utf-8") + +def get_swkey_type(dris): + return get4bytes(dris, 544+python64) + +def get_swkey_exp_day(dris): + return get4bytes(dris, 548+python64) + +def get_swkey_exp_month(dris): + return get4bytes(dris, 552+python64) + +def get_swkey_exp_year(dris): + return get4bytes(dris, 556+python64) + +# you may also want to retrieve var_a values that you already entered into the dris! +def get_var_a(dris): + return get4bytes_signed(dris, 300+python64) + +def get_var_b(dris): + return get4bytes_signed(dris, 304+python64) + +def get_var_c(dris): + return get4bytes_signed(dris, 308+python64) + +def get_var_d(dris): + return get4bytes_signed(dris, 312+python64) + +def get_var_e(dris): + return get4bytes_signed(dris, 316+python64) + +def get_var_f(dris): + return get4bytes_signed(dris, 320+python64) + +def get_var_g(dris): + return get4bytes_signed(dris, 324+python64) + +def get_var_h(dris): + return get4bytes_signed(dris, 328+python64) + +# function to display the most common error codes. +# You will want to change this with your own error messages +def DisplayError(ret_code, extended_error): + if (ret_code == 401): + print("Error! No dongles detected!") + elif (ret_code == 403): + print("Error! The dongle detected has a different type to the one specified in DinkeyAdd.") + elif (ret_code == 404): + print("Error! The dongle detected has a different model to those specified in DinkeyAdd.") + elif (ret_code == 409): + print("Error! The dongle detected has not been programmed by DinkeyAdd.") + elif (ret_code == 410): + print("Error! The dongle detected has a different Product Code to the one specified in DinkeyAdd.") + elif (ret_code == 411): + print("Error! The dongle detected does not contain the licence associated with this program.") + elif (ret_code == 413): + print("Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual.") + elif (ret_code == 417): + print("Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.") + elif (ret_code == 423): + print("Error! The number of network users has been exceeded.") + elif (ret_code == 435): + print("Error! DinkeyServer has not been detected on the network.") + elif (ret_code == 922): + print("Error! The Software Key has expired.") + else: + print("An error occurred checking the dongle.\nError: " + str(ret_code) + ", Extended Error: " + str(extended_error)) + return diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/RealBasic/DllTest.rbp b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/RealBasic/DllTest.rbp new file mode 100644 index 0000000..ee09198 Binary files /dev/null and b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/RealBasic/DllTest.rbp differ diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/RealBasic/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/RealBasic/README.txt new file mode 100644 index 0000000..c7fbf58 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/RealBasic/README.txt @@ -0,0 +1,64 @@ +DllTest - Runtime sample code in RealBasic +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in RealBasic 2011 but will also work in later versions +and also in Xojo (tested on Xojo 2013r4.1). It can also work on previous versions +of RealBasic (but if using versions previous to 2005 then see note about use of Nil). +It is a console program so for a Windows application you would need to change "Print" +statements for "MsgBox". + +The Module1 module contains the DRIS structure definition and some useful functions. +The main sample code contains the functions: + +DDProtCheck +DDProtCheckWithAlg +WriteBytes +ReadBytes +EncryptUserData + +There are also encrypted versions of these functions (where the parameters passed +to and from our API are encrypted for greater security): + +DDProtCheckEnc, DDProtCheckWithAlgEnc, WriteBytesEnc, ReadBytesEnc, EncryptUserDataEnc + +These functions also use some smaller functions: +CryptDRIS, CryptAPIData, MyAlgorithm, MyRWAlgorithm + +You will not need to use all these functions in your code. Just use which ever functions +are most appropriate and customise in your own way. The sample code is just a guide. +You should implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN constant to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. + +Note - you should protect dpwin32.dll and not your program. Because your program +is linked to the DLL it is protected. This protected dll should be placed in the +sample folder as the compiled program. + +You can rename the runtime module (e.g. dpwin32.dll) if you want but you must also +change this name for every occurance in the MyDDProtCheck function in Module1. + +You can also use the protected program on MacOS X and Linux by protecting the +appropriate runtime modules (i.e. dpmac32.dylib and dplin32.so). If you do this +you will probably want to protect all the runtime modules to a single licence. + +Due to our anti-debug code it may be impossible to debug your code once it has been +protected (we found that the debugger often crashed anyway even without our anti-debug +code)! + +Note for version of RealBasic previous to 2005 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The "Nil" value is not defined for these earlier versions and so you should define a +MemoryBlock object, initialise it to something and pass that instead (it doesn't get used +so as long as it compiles it is OK). diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/VERY IMPORTANT README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/VERY IMPORTANT README.txt new file mode 100644 index 0000000..ad1899e --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/VERY IMPORTANT README.txt @@ -0,0 +1,13 @@ +Notes on How to use the Sample Code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Always read the "readme" file in the project you use. It contains important +information about the programming language you are using and how to integrate +the sample project with the Dinkey Pro SDK. + +Instead of creating projects for every single version of an IDE, we only create +a new project when an older project can no longer be updated by the IDE. For +example, for Windows C we have a Visual Studio 5 project and a Visual Studio 2008 +project. The VS 5 project will work for VS 5 up to VS 2005 and the Visual Studio +2008 project will work for VS2008 and higher. In these cases VS will update the +project to the latest version. diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyAdd/AssemblyInfo.vb b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyAdd/AssemblyInfo.vb new file mode 100644 index 0000000..41bb2c5 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyAdd/AssemblyInfo.vb @@ -0,0 +1,31 @@ +Imports System.Reflection +Imports System.Runtime.InteropServices + +' General Information about an assembly is controlled through the following +' set of attributes. Change these attribute values to modify the information +' associated with an assembly. + +' Review the values of the assembly attributes + + + + + + + + + +'The following GUID is for the ID of the typelib if this project is exposed to COM + + +' Version information for an assembly consists of the following four values: +' +' Major Version +' Minor Version +' Build Number +' Revision +' +' You can specify all the values or you can default the Build and Revision Numbers +' by using the '*' as shown below: + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyAdd/Form1.resx b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyAdd/Form1.resx new file mode 100644 index 0000000..feb5499 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyAdd/Form1.resx @@ -0,0 +1,283 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Assembly + + + 8, 8 + + + True + + + False + + + True + + + Assembly + + + Assembly + + + False + + + Assembly + + + False + + + Assembly + + + Assembly + + + Assembly + + + False + + + Assembly + + + False + + + Assembly + + + Assembly + + + Assembly + + + False + + + Assembly + + + False + + + Assembly + + + Assembly + + + False + + + Assembly + + + Assembly + + + Assembly + + + False + + + Assembly + + + False + + + Assembly + + + Assembly + + + False + + + Assembly + + + Assembly + + + False + + + Assembly + + + Assembly + + + False + + + Assembly + + + Assembly + + + False + + + Assembly + + + Assembly + + + Assembly + + + Assembly + + + False + + + False + + + Assembly + + + Assembly + + + False + + + (Default) + + + False + + + False + + + 8, 8 + + + True + + + 80 + + + True + + + Assembly + + + Form1 + + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyAdd/Form1.vb b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyAdd/Form1.vb new file mode 100644 index 0000000..c70a0ff --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyAdd/Form1.vb @@ -0,0 +1,485 @@ +' !! We strongly recommend that you read the "readme.txt" file in the sample code folder. +' !! It contains important instructions on how to use the sample code + +Imports System.Runtime.InteropServices ' so we can marshall our structures + +Public Class Form1 + Inherits System.Windows.Forms.Form + + Public Const AppName As String = "dapfTest" +#Region " Windows Form Designer generated code " + + Public Sub New() + MyBase.New() + + 'This call is required by the Windows Form Designer. + InitializeComponent() + + 'Add any initialization after the InitializeComponent() call + + End Sub + + 'Form overrides dispose to clean up the component list. + Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) + If disposing Then + If Not (components Is Nothing) Then + components.Dispose() + End If + End If + MyBase.Dispose(disposing) + End Sub + + 'Required by the Windows Form Designer + Private components As System.ComponentModel.IContainer + + 'NOTE: The following procedure is required by the Windows Form Designer + 'It can be modified using the Windows Form Designer. + 'Do not modify it using the code editor. + Friend WithEvents groupBox2 As System.Windows.Forms.GroupBox + Friend WithEvents label6 As System.Windows.Forms.Label + Friend WithEvents maxDaysText As System.Windows.Forms.TextBox + Friend WithEvents demoSoftwareKey As System.Windows.Forms.Button + Friend WithEvents groupBox1 As System.Windows.Forms.GroupBox + Friend WithEvents expyearText As System.Windows.Forms.TextBox + Friend WithEvents label5 As System.Windows.Forms.Label + Friend WithEvents expmonthText As System.Windows.Forms.TextBox + Friend WithEvents label4 As System.Windows.Forms.Label + Friend WithEvents expdayText As System.Windows.Forms.TextBox + Friend WithEvents label3 As System.Windows.Forms.Label + Friend WithEvents label2 As System.Windows.Forms.Label + Friend WithEvents machineIDText As System.Windows.Forms.TextBox + Friend WithEvents tempSoftwareKey As System.Windows.Forms.Button + Friend WithEvents encryptShellData As System.Windows.Forms.Button + Friend WithEvents lockSoftware As System.Windows.Forms.Button + Friend WithEvents programDongleMod As System.Windows.Forms.Button + Friend WithEvents programDongle As System.Windows.Forms.Button + Friend WithEvents dapfFile As System.Windows.Forms.TextBox + Friend WithEvents label1 As System.Windows.Forms.Label + Private Sub InitializeComponent() + Me.groupBox2 = New System.Windows.Forms.GroupBox + Me.label6 = New System.Windows.Forms.Label + Me.maxDaysText = New System.Windows.Forms.TextBox + Me.demoSoftwareKey = New System.Windows.Forms.Button + Me.groupBox1 = New System.Windows.Forms.GroupBox + Me.expyearText = New System.Windows.Forms.TextBox + Me.label5 = New System.Windows.Forms.Label + Me.expmonthText = New System.Windows.Forms.TextBox + Me.label4 = New System.Windows.Forms.Label + Me.expdayText = New System.Windows.Forms.TextBox + Me.label3 = New System.Windows.Forms.Label + Me.label2 = New System.Windows.Forms.Label + Me.machineIDText = New System.Windows.Forms.TextBox + Me.tempSoftwareKey = New System.Windows.Forms.Button + Me.encryptShellData = New System.Windows.Forms.Button + Me.lockSoftware = New System.Windows.Forms.Button + Me.programDongleMod = New System.Windows.Forms.Button + Me.programDongle = New System.Windows.Forms.Button + Me.dapfFile = New System.Windows.Forms.TextBox + Me.label1 = New System.Windows.Forms.Label + Me.groupBox1.SuspendLayout() + Me.SuspendLayout() + ' + 'groupBox2 + ' + Me.groupBox2.Controls.Add(Me.label6) + Me.groupBox2.Controls.Add(Me.maxDaysText) + Me.groupBox2.Controls.Add(Me.demoSoftwareKey) + Me.groupBox2.Location = New System.Drawing.Point(16, 390) + Me.groupBox2.Name = "groupBox2" + Me.groupBox2.Size = New System.Drawing.Size(336, 96) + Me.groupBox2.TabIndex = 17 + Me.groupBox2.TabStop = False + Me.groupBox2.Text = "Demo Software Key" + ' + 'demoSoftwareKey + ' + Me.demoSoftwareKey.Location = New System.Drawing.Point(64, 56) + Me.demoSoftwareKey.Name = "demoSoftwareKey" + Me.demoSoftwareKey.Size = New System.Drawing.Size(208, 23) + Me.demoSoftwareKey.TabIndex = 15 + Me.demoSoftwareKey.Text = "Create Demo Template" + ' + 'label6 + ' + Me.label6.Location = New System.Drawing.Point(24, 24) + Me.label6.Name = "label6" + Me.label6.Size = New System.Drawing.Size(100, 20) + Me.label6.TabIndex = 18 + Me.label6.Text = "Max Days:" + Me.label6.TextAlign = System.Drawing.ContentAlignment.MiddleLeft + ' + 'maxDaysText + ' + Me.maxDaysText.Location = New System.Drawing.Point(128, 24) + Me.maxDaysText.Name = "maxDaysText" + Me.maxDaysText.Size = New System.Drawing.Size(184, 20) + Me.maxDaysText.TabIndex = 19 + Me.maxDaysText.Text = "" + ' + 'groupBox1 + ' + Me.groupBox1.Controls.Add(Me.expyearText) + Me.groupBox1.Controls.Add(Me.label5) + Me.groupBox1.Controls.Add(Me.expmonthText) + Me.groupBox1.Controls.Add(Me.label4) + Me.groupBox1.Controls.Add(Me.expdayText) + Me.groupBox1.Controls.Add(Me.label3) + Me.groupBox1.Controls.Add(Me.label2) + Me.groupBox1.Controls.Add(Me.machineIDText) + Me.groupBox1.Controls.Add(Me.tempSoftwareKey) + Me.groupBox1.Location = New System.Drawing.Point(16, 251) + Me.groupBox1.Name = "groupBox1" + Me.groupBox1.Size = New System.Drawing.Size(336, 128) + Me.groupBox1.TabIndex = 7 + Me.groupBox1.TabStop = False + Me.groupBox1.Text = "Temporary Software Key" + ' + 'tempSoftwareKey + ' + Me.tempSoftwareKey.Location = New System.Drawing.Point(64, 88) + Me.tempSoftwareKey.Name = "tempSoftwareKey" + Me.tempSoftwareKey.Size = New System.Drawing.Size(208, 23) + Me.tempSoftwareKey.TabIndex = 16 + Me.tempSoftwareKey.Text = "Create Software Key" + ' + 'expyearText + ' + Me.expyearText.Location = New System.Drawing.Point(240, 56) + Me.expyearText.Name = "expyearText" + Me.expyearText.Size = New System.Drawing.Size(32, 20) + Me.expyearText.TabIndex = 15 + Me.expyearText.Text = "yyyy" + ' + 'label5 + ' + Me.label5.Location = New System.Drawing.Point(224, 56) + Me.label5.Name = "label5" + Me.label5.Size = New System.Drawing.Size(8, 20) + Me.label5.TabIndex = 14 + Me.label5.Text = "/" + Me.label5.TextAlign = System.Drawing.ContentAlignment.MiddleLeft + ' + 'expmonthText + ' + Me.expmonthText.Location = New System.Drawing.Point(184, 56) + Me.expmonthText.Name = "expmonthText" + Me.expmonthText.Size = New System.Drawing.Size(32, 20) + Me.expmonthText.TabIndex = 13 + Me.expmonthText.Text = "mm" + ' + 'label4 + ' + Me.label4.Location = New System.Drawing.Point(168, 56) + Me.label4.Name = "label4" + Me.label4.Size = New System.Drawing.Size(8, 20) + Me.label4.TabIndex = 12 + Me.label4.Text = "/" + Me.label4.TextAlign = System.Drawing.ContentAlignment.MiddleLeft + ' + 'expdayText + ' + Me.expdayText.Location = New System.Drawing.Point(128, 56) + Me.expdayText.Name = "expdayText" + Me.expdayText.Size = New System.Drawing.Size(32, 20) + Me.expdayText.TabIndex = 11 + Me.expdayText.Text = "dd" + ' + 'label3 + ' + Me.label3.Location = New System.Drawing.Point(24, 56) + Me.label3.Name = "label3" + Me.label3.Size = New System.Drawing.Size(100, 20) + Me.label3.TabIndex = 10 + Me.label3.Text = "Expiry Date:" + Me.label3.TextAlign = System.Drawing.ContentAlignment.MiddleLeft + ' + 'label2 + ' + Me.label2.Location = New System.Drawing.Point(24, 24) + Me.label2.Name = "label2" + Me.label2.Size = New System.Drawing.Size(100, 20) + Me.label2.TabIndex = 8 + Me.label2.Text = "Machine ID:" + Me.label2.TextAlign = System.Drawing.ContentAlignment.MiddleLeft + ' + 'machineIDText + ' + Me.machineIDText.Location = New System.Drawing.Point(128, 24) + Me.machineIDText.Name = "machineIDText" + Me.machineIDText.Size = New System.Drawing.Size(184, 20) + Me.machineIDText.TabIndex = 9 + Me.machineIDText.Text = "" + ' + 'encryptShellData + ' + Me.encryptShellData.Location = New System.Drawing.Point(80, 203) + Me.encryptShellData.Name = "encryptShellData" + Me.encryptShellData.Size = New System.Drawing.Size(208, 23) + Me.encryptShellData.TabIndex = 6 + Me.encryptShellData.Text = "Encrypt Shell Data Files" + ' + 'lockSoftware + ' + Me.lockSoftware.Location = New System.Drawing.Point(80, 163) + Me.lockSoftware.Name = "lockSoftware" + Me.lockSoftware.Size = New System.Drawing.Size(208, 23) + Me.lockSoftware.TabIndex = 5 + Me.lockSoftware.Text = "Lock Software" + ' + 'programDongleMod + ' + Me.programDongleMod.Location = New System.Drawing.Point(80, 123) + Me.programDongleMod.Name = "programDongleMod" + Me.programDongleMod.Size = New System.Drawing.Size(208, 23) + Me.programDongleMod.TabIndex = 4 + Me.programDongleMod.Text = "Program Dongle with modification" + ' + 'programDongle + ' + Me.programDongle.Location = New System.Drawing.Point(80, 83) + Me.programDongle.Name = "programDongle" + Me.programDongle.Size = New System.Drawing.Size(208, 23) + Me.programDongle.TabIndex = 3 + Me.programDongle.Text = "Program Dongle" + ' + 'dapfFile + ' + Me.dapfFile.Location = New System.Drawing.Point(16, 35) + Me.dapfFile.Name = "dapfFile" + Me.dapfFile.Size = New System.Drawing.Size(344, 20) + Me.dapfFile.TabIndex = 2 + Me.dapfFile.Text = "" + ' + 'label1 + ' + Me.label1.Location = New System.Drawing.Point(16, 19) + Me.label1.Name = "label1" + Me.label1.Size = New System.Drawing.Size(416, 16) + Me.label1.TabIndex = 1 + Me.label1.Text = "Full path of dapf file:" + ' + 'Form1 + ' + Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13) + Me.ClientSize = New System.Drawing.Size(376, 496) + Me.Controls.Add(Me.groupBox2) + Me.Controls.Add(Me.groupBox1) + Me.Controls.Add(Me.encryptShellData) + Me.Controls.Add(Me.lockSoftware) + Me.Controls.Add(Me.programDongleMod) + Me.Controls.Add(Me.programDongle) + Me.Controls.Add(Me.dapfFile) + Me.Controls.Add(Me.label1) + Me.Name = "Form1" + Me.Text = "Form1" + Me.groupBox1.ResumeLayout(False) + Me.ResumeLayout(False) + + End Sub + +#End Region + + ' The sample code contains 5 functions. You will not need to use all these functions in your code. + ' Just use which ever functions are most appropriate and customise in your own way. The sample code + ' is just a guide. + ' + ' There are two methods to loading a DAPF file. These are shown in the first two functions + ' programDongle_Click and programDongleMod_Click: + ' + ' programDongle_Click: we load the DAPF file from disk and get a handle and use it "as is" using the API + ' call LoadDAPFFromFile. You can make some limited changes to overwrite the default + ' behaviour by using API flags. + ' + ' programDongleMod_Click: we load the DAPF file from disk and load into structures. We can then modify the + ' DAPF settings by modifying this structure. This method uses the API calls + ' ReadDAPFEx and LoadDAPF. + ' + ' The other functions use the first method (as it is simpler) but you can use the second method instead if + ' you prefer. + ' + ' Note - an alternative to using the programDongleMod_Click technique is to modify the DAPF file on disk + ' and then use the programDongle_Click technique. To modify a binary DAPF you would use the binary structures + ' that are defined in dapf.h. To modify JSON DAPF you would need to use a JSON parser. + ' + ' lockSoftware_Click : locks software (protect it) to a dongle as specified by the DAPF file. + ' + ' encryptShellData_Click: encrypts the shell data files specified in the DAPF file (this is used with encrypting + ' data file if you use the Shell Method with "Data File Encryption" enabled). + ' + ' tempSoftwareKey_Click: creates a Temporary Software Key based on the DAPF file and settings the user has entered. + ' + ' demoSoftwareKey_Click: creates a Demo Software Key Template based on the DAPF file and settings the user has entered. + + Private Sub programDongle_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles programDongle.Click + Dim dapfHandle As IntPtr + Dim err_code As Integer + Dim dongle_number As UInt32 + + ' load DAPF from File into memory + dapfHandle = LoadDAPFFromFile(dapfFile.Text, err_code) + If IntPtr.Zero.Equals(dapfHandle) Then + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, AppName) + Exit Sub + End If + + ' program dongle as specified by the DAPF file + err_code = AddProtection(dapfHandle, ACTION_PROGRAM_DONGLE, 0, 0, dongle_number) + + ' Unload DAPF from memory + UnloadDAPF(dapfHandle) + + ' display message (error or success) + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Information, AppName) + End Sub +#If VBC_VER >= 14 Then + #Disable Warning BC42108, BC42030 'This line is used in Visual Studio 2015 (and newer) to remove warnings in this function +#End If + Private Sub programDongleMod_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles programDongleMod.Click + Dim dapfHandle As IntPtr + Dim err_code, dummy1, dummy2 As Integer + Dim dongle_number As UInt32 + Dim MyDinkeyInfo As DINKEYINFO + Dim LicenceInfoArray() As LICENCEINFO + Dim FileInfoArray() As FILEINFO + Dim AlgorithmArray() As ALGORITHM + Dim DataFileEncArray() As DATAFILEENC + + ' in this case we need to read the DAPF into our structures, so that the DAPF values can be modified + err_code = ReadDAPFEx(dapfFile.Text, MyDinkeyInfo, LicenceInfoArray, FileInfoArray, AlgorithmArray, DataFileEncArray, dummy1, dummy2) + If err_code <> 0 Then + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, AppName) + Exit Sub + End If + + ' patch new values + LicenceInfoArray(0).Features = Convert.ToUInt32(12345) + LicenceInfoArray(0).Execs = 100 + LicenceInfoArray(0).LicenceName = "fred" + + ' get DAPF handle + dapfHandle = LoadDAPF(MyDinkeyInfo, LicenceInfoArray, FileInfoArray, AlgorithmArray, DataFileEncArray, err_code) + If IntPtr.Zero.Equals(dapfHandle) Then + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, AppName) + Exit Sub + End If + + ' program dongle + err_code = AddProtection(dapfHandle, ACTION_PROGRAM_DONGLE, 0, 0, dongle_number) + + ' Unload DAPF from memory + UnloadDAPF(dapfHandle) + + ' display message (error or success) + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Information, AppName) + End Sub +#If VBC_VER >= 14 Then + #Enable Warning BC42108, BC42030 'This line is used in Visual Studio 2015 (and higher) to remove warnings +#End If + ' load a DAPF file from disk and protect the files specified + ' (in practice it is better to protect the files one at a time and output messages as you go along, similar to DinkeyAdd.exe) + ' In this example we specify the flag to overwrite any existing output file that might exist. + Private Sub lockSoftware_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lockSoftware.Click + Dim dapfHandle As IntPtr + Dim err_code As Integer + Dim dummy As UInt32 + + ' load DAPF from File into memory + dapfHandle = LoadDAPFFromFile(dapfFile.Text, err_code) + If IntPtr.Zero.Equals(dapfHandle) Then + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, AppName) + Exit Sub + End If + + ' protect all the files listed in the DAPF file + err_code = AddProtection(dapfHandle, ACTION_PROTECT_SOFTWARE, -1, FLAGS_OVERWRITE_OUTPUT, dummy) + + ' Unload DAPF from memory + UnloadDAPF(dapfHandle) + + ' display message (error or success) + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Information, AppName) + End Sub + + Private Sub encryptShellData_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles encryptShellData.Click + Dim dapfHandle As IntPtr + Dim err_code As Integer + + ' load DAPF from File into memory + dapfHandle = LoadDAPFFromFile(dapfFile.Text, err_code) + If IntPtr.Zero.Equals(dapfHandle) Then + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, AppName) + Exit Sub + End If + + ' encrypt all the shell data files listed in the DAPF file + err_code = EncryptShellDataFiles(dapfHandle, -1, FLAGS_OVERWRITE_OUTPUT) + + ' Unload DAPF from memory + UnloadDAPF(dapfHandle) + + ' display message (error or success) + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Information, AppName) + End Sub + + Private Sub tempSoftwareKey_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tempSoftwareKey.Click + Dim dapfHandle As IntPtr + Dim err_code As Integer + Dim swkey_info As TEMP_SWKEY_INFO + + ' load DAPF from File into memory + dapfHandle = LoadDAPFFromFile(dapfFile.Text, err_code) + If IntPtr.Zero.Equals(dapfHandle) Then + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, AppName) + Exit Sub + End If + + ' fill out the SWKEY structure from the values the user entered + swkey_info.Size = Marshal.SizeOf(swkey_info.GetType) + swkey_info.MachineID = Convert.ToUInt32(machineIDText.Text, 16) + swkey_info.ExpiryDay = Convert.ToInt32(expdayText.Text, 10) + swkey_info.ExpiryMonth = Convert.ToInt32(expmonthText.Text, 10) + swkey_info.ExpiryYear = Convert.ToInt32(expyearText.Text, 10) + ' !!!! in this case we just choose Pro Plus. You could load the DAPF file into structures and see which model is selected. + ' If there is more than one model selected you can ask the customer to choose which model they want. + swkey_info.DongleModel = SWKEY_MODEL_PRO_PLUS + swkey_info.DongleNumber = Convert.ToUInt32(0) + + ' attempt to create the Temporary Software Key + err_code = CreateTempSoftwareKey(dapfHandle, swkey_info, 0) + + ' Unload DAPF from memory + UnloadDAPF(dapfHandle) + + ' display message (error or success) + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Information, AppName) + End Sub + + Private Sub demoSoftwareKey_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles demoSoftwareKey.Click + Dim dapfHandle As IntPtr + Dim err_code As Integer + Dim swkey_info As DEMO_SWKEY_INFO + + ' load DAPF from File into memory + dapfHandle = LoadDAPFFromFile(dapfFile.Text, err_code) + If IntPtr.Zero.Equals(dapfHandle) Then + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, AppName) + Exit Sub + End If + + ' fill out the SWKEY structure from the values the user entered + swkey_info.Size = Marshal.SizeOf(swkey_info.GetType) + swkey_info.MaxDays = Convert.ToInt32(maxDaysText.Text, 10) + ' !!!! in this case we just choose the default model (assuming you only selected one in the DAPF file). + ' If you want to specify more than one model then OR the flags together. e.g. SWKEY_BITMAP_PRO_LITE Or SWKEY_BITMAP_PRO_PLUS + swkey_info.Models = SWKEY_BITMAP_DEFAULT + + ' attempt to create the Demo Software Key Template + err_code = CreateDemoSoftwareKeyTemplate(dapfHandle, swkey_info, 0) + + ' Unload DAPF from memory + UnloadDAPF(dapfHandle) + + ' display message (error or success) + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Information, AppName) + End Sub +End Class diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyAdd/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyAdd/README.txt new file mode 100644 index 0000000..d77ce0b --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyAdd/README.txt @@ -0,0 +1,50 @@ +dapfTest - sample code to call DinkeyAdd Module in VB.NET +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 2002 but will work in more recent +versions of Visual Studio (they will upgrade the Project to the latest version. +If prompted you should also upgrade the .NET framework the project requires). + +For users of Visual Studio 2005 or higher, the default setting to projects is to +compile for the Target Platform "Any". This means that on 32-bit Windows, your +code will run as 32-bit code (and needs to call DinkeyAdd32.dll) and under 64-bit +Windows your code will run as 64-bit code (and needs to call DinkeyAdd64.dll). +The sample code works this out automatically. If you select the target platform as "x86" +then it will always be 32-bit and so you only need to use DinkeyAdd32.dll. If you +select "x64" then your code will be 64-bit and you only need to use DinkeyAdd64.dll. + +The main source files in the project are: + +dapf.vb - the source file contains declarations of our API. We automatically + work out whether your code is running in 32-bit or 64-bit and load + the appropriate DinkeyAdd module. + +Form1.vb - this is the sample code giving an example on how you can call our API. + It contains 5 functions. Just use which ever functions are most appropriate + and customise in your own way. + +The best approach is to compile the sample code and see how it works and then to take +the appropriate code and apply it to your own project. You should include the dapf.vb +file in your project and use/modify which ever functions from Form1.vb you feel are +appropriate. The dapf.vb file should not be modified. + +The sample code is just a guide. As none of the parameters are security sensitive then +there is no need to implement strong security in calling DinkeyAdd. + +Make sure you remember to do the following when creating your own project: + +1) Insert the following namespaces in your code file: +using System.Runtime.InteropServices; + +2) Insert the dapf.vb file in your project. + +3) You need to put DinkeyAdd32.dll and/or DinkeyAdd64.dll into the folder that +contains dapfTest. Otherwise the message "Unable to open DLL (DinkeyAdd32.dll)" or +the System.DllNotFoundException error will appear when you run dapfTest. + +Notes on Debugging 64-bit Code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +When you use the 64-bit module (DinkeyAdd64.dll) the anti-debug code is so strong +that if you are debugging your code, after calling our API then it will crash with +an SEH exception. There are no debug modules for DinkeyAdd so you will have to find +other ways of debugging your code (for example taking out the call altogether). diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyAdd/dapf.vb b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyAdd/dapf.vb new file mode 100644 index 0000000..350cffc --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyAdd/dapf.vb @@ -0,0 +1,467 @@ +' !! this file should not be modified + +' DAPF file is in the following format: +' DINKEYINFO +' LICENCEINFO (however many are needed) +' FILEINFO (however many are needed) +' ALGORITHM (however many are needed) +' DATAFILEENC (however many are needed) + +Imports System +Imports System.Runtime.InteropServices ' so we can marshal the structures as a block of memory +Imports System.Text ' for StringBuilder + +' *********** define structures that make up the DAPF file ******************* + +Module dapf_code + + _ + Structure DINKEYINFO + Dim Header1 As Byte ' should be set to "DAPF" + Dim Header2 As Byte + Dim Header3 As Byte + Dim Header4 As Byte + Dim Version As Integer ' version of this structure. Currently 9. + Dim SelectedModels As Integer ' BIT0 = Dinkey Pro Lite, BIT1 = Dinkey Pro Plus, BIT2 = Dinkey Pro Net etc... + _ + Dim ProdCode As String + Dim PerLicence As Integer ' 1 = per licence, 0 = per product (default) + Dim MaxNetUsers As Integer ' product net users, unlimited = -1, no entry = -2 + Dim RangeSettings As Integer ' 0 = any number, 1 = dongle in computer, 2 = range + Dim RangeMin As UInt32 + Dim RangeMax As UInt32 + Dim NumLicences As Integer ' number of LICENCEINFO structures in this DAPF file + Dim NumProgs As Integer ' number of FILEINFO structures in this DAPF file + Dim NumAlgs As Integer + Dim DataSizeType As Integer ' 1 = set the zero data size, 0 = use file to initialise data area + Dim ZeroDataSize As Integer ' size of the data area area in bytes + ' NB some of these entries were for an older (deprecated) FD model. Now marked as deprecated. These fields are ignored. + _ + Dim DataFile As String ' path to data file (0 = no data file) + Dim DataAreaSize As Integer ' file size in bytes, -1 = file not found + _ + Dim ShellSuccessMsg As String ' Shell Method messages... + _ + Dim ShellNoDongleMsg As String + _ + Dim ShellExpiryDateMsg As String + _ + Dim ShellExpiryExecsMsg As String + _ + Dim ShellWarnDateMsg As String + _ + Dim ShellWarnExecsMsg As String + _ + Dim ShellNetUserLimitMsg As String + _ + Dim ShellOtherErrorMsg As String + _ + Dim ShellBackgroundMsg As String + _ + Dim NetNoServerMsg As String + _ + Dim rwalg As Byte() ' coded form of rw algorithm (0 = no algorithm) + Dim SecOptions As Integer ' BIT0: DRIS encryption, BIT1: Data encryption, BIT2: Data enc with alg, BIT3: only secure update codes + Dim SecDRISEncKey1 As Byte ' DRIS encryption parameters + Dim SecDRISEncKey2 As Byte + Dim SecDRISEncKey3 As Byte + Dim Ignored1 As Byte ' this byte is ignored + Dim SecDataEncKey1 As Byte ' API Data encryption parameters + Dim SecDataEncKey2 As Byte + Dim SecDataEncKey3 As Byte + Dim Ignored2 As Byte ' this byte is ignored + Dim ProtectionType As Integer ' 0 = software + dongle, 1 = dongle only, 2 = program only + _ + Dim DataEncKeyProdCode As String ' Alternative Product Code used to generate internal encryption keys. Normally set to 0. + _ + Dim Notes As String ' user-defined notes + Dim LockDongle As Integer ' 0 = don't lock (default), 1 = lock dongle to user's computer + Dim Reserved1 As Integer ' must be 0 + Dim Reserved2 As Integer ' must be 0 + Dim AdvancedOptions As Integer ' BIT0 = do not allow usb-over-network for non-Net dongles, BIT1 = do not check for Software Key at Runtime. + Dim NumDataFileEnc As Integer ' Number of data files in our encryption list + End Structure + + _ + Structure LICENCEINFO + _ + Dim LicenceName As String ' licence name + Dim MaxDays As Integer ' -1 = no limit + Dim ExpiryDay As Integer ' -1 = no limit, 0 = no change + Dim ExpiryMonth As Integer + Dim ExpiryYear As Integer + Dim Execs As Integer ' -1 = no limit + Dim ExecsWarn As Integer ' 0 = no warning (just for Shell method) + Dim DaysWarn As Integer ' 0 = no warning (just for Shell method) + Dim Features As Uint32 + Dim LicenceNetUsers As Integer ' unlimited = -1 (-2 = not needed (this is for display only)) + End Structure + + _ + Structure FILEINFO + _ + Dim InputName As String ' input file (full path) + _ + Dim OutputName As String ' output file/folder + _ + Dim CallingProg As String ' calling program name + Dim LicenceIndex As Integer ' index (of licence) in the LicenceInfo structure (1-based index. 0 = no selection) + Dim Method As Integer ' 0-api, 1-shell, 2-shell & api + Dim ShellFlags As Integer ' same bit flag values as in dris. i.e. 1 = DEC_ONE_EXEC, 4 = START_NET_USER + Dim BackGround As Integer ' 0=no background, 1=1min, 2=5min, 3=10min, 4=30min, 5=60min + Dim OtherShellOptions As Integer ' BIT0 = Shell Data Encryption Enabled, BIT1: Extra Anti-Debug is disabled, BIT2: Extra Anti-Piracy is disabled + _ + Dim EncFileList As String ' files (or file types) that the Shell-protected program will treat as encrypted (separated by ':') + _ + Dim ExceptList As String ' files (or file types) that are exceptions to the above list (separated by ':') + Dim ExtraAntiPiracy As Integer ' 0 = off, 1=min, 10=max + End Structure + + _ + Structure ALGORITHM + _ + Dim alg As Byte() ' coded form of algorithm + End Structure + + _ + Structure DATAFILEENC + _ + Dim InputName As String ' file name, wild cards are allowed + _ + Dim OutputName As String ' file name (or folder name if input is a wildcard) + End Structure + + ' this structure is used for creating Temporary Software Keys + _ + Structure TEMP_SWKEY_INFO + Dim Size As Integer + Dim MachineID As UInt32 + Dim ExpiryDay As Integer + Dim ExpiryMonth As Integer + Dim ExpiryYear As Integer + Dim DongleModel As Integer + Dim DongleNumber As UInt32 + End Structure + + ' this structure is used for creating Demo Software Key Templates + _ + Structure DEMO_SWKEY_INFO + Dim Size As Integer + Dim MaxDays As Int32 ' max days demo swkey installation is valid (0-60) + Dim Models As Int32 ' bitmap of valid dongle models. See constant values below. 0 = default (only use if only one model is selected in DINKEYINFO) + End Structure + +' ********************** DinkeyAdd Module Imports ************************ + + ' Loads DAPF from disk and returns handle + Declare Ansi Function LoadDAPFFromFile32 Lib "DinkeyAdd32.dll" Alias "LoadDAPFFromFile" (ByVal dapf_file As String, ByRef err_code As Integer) As IntPtr + Declare Ansi Function LoadDAPFFromFile64 Lib "DinkeyAdd64.dll" Alias "LoadDAPFFromFile" (ByVal dapf_file As String, ByRef err_code As Integer) As IntPtr + + ' Loads DAPF from disk into structures supplied (so we can modify DAPF in memory) + Declare Ansi Function ReadDAPFEx32 Lib "DinkeyAdd32.dll" Alias "ReadDAPFEx" (ByVal dapf_file As String, ByRef MyDinkeyInfo As DINKEYINFO, ByVal licence_bytes() As Byte, _ + ByVal fileinfo_bytes() As Byte, ByVal alg_bytes() As Byte, ByVal datafile_bytes() As Byte, ByRef dapf_version As Integer, ByRef dapf_format As Integer) As Integer + Declare Ansi Function ReadDAPFEx64 Lib "DinkeyAdd64.dll" Alias "ReadDAPFEx" (ByVal dapf_file As String, ByRef MyDinkeyInfo As DINKEYINFO, ByVal licence_bytes() As Byte, _ + ByVal fileinfo_bytes() As Byte, ByVal alg_bytes() As Byte, ByVal datafile_bytes() As Byte, ByRef dapf_version As Integer, ByRef dapf_format As Integer) As Integer + + ' Loads DAPF from structures and returns a handle + Declare Ansi Function LoadDAPF32 Lib "DinkeyAdd32.dll" Alias "LoadDAPF" (ByRef MyDinkeyInfo As DINKEYINFO, ByVal licence_bytes() As Byte, ByVal fileinfo_bytes() As Byte, _ + ByVal alg_bytes() As Byte, ByVal datafile_bytes() As Byte, ByRef ret_code As Integer) As IntPtr + Declare Ansi Function LoadDAPF64 Lib "DinkeyAdd64.dll" Alias "LoadDAPF" (ByRef MyDinkeyInfo As DINKEYINFO, ByVal licence_bytes() As Byte, ByVal fileinfo_bytes() As Byte, _ + ByVal alg_bytes() As Byte, ByVal datafile_bytes() As Byte, ByRef ret_code As Integer) As IntPtr + + ' saves the DAPF file to disk + Declare Ansi Function WriteDAPFEx32 Lib "DinkeyAdd32.dll" Alias "WriteDAPFEx" (ByVal dapf_handle As IntPtr, ByVal dapf_file As String, ByVal dapf_format As Integer, _ + ByVal dapf_version As Integer, ByVal flags As Integer) As Integer + Declare Ansi Function WriteDAPFEx64 Lib "DinkeyAdd64.dll" Alias "WriteDAPFEx" (ByVal dapf_handle As IntPtr, ByVal dapf_file As String, ByVal dapf_format As Integer, _ + ByVal dapf_version As Integer, ByVal flags As Integer) As Integer + + ' unloads the DAPF file + Declare Ansi Sub UnloadDAPF32 Lib "DinkeyAdd32.dll" Alias "UnloadDAPF" (ByRef dapf_handle As IntPtr) + Declare Ansi Sub UnloadDAPF64 Lib "DinkeyAdd64.dll" Alias "UnloadDAPF" (ByRef dapf_handle As IntPtr) + + 'main functions + Declare Ansi Function AddProtection32 Lib "DinkeyAdd32.dll" Alias "AddProtection" (ByVal dapf_handle As IntPtr, ByVal action As Integer, ByVal file_num As Integer, _ + ByVal flags As Integer, ByRef dongle_number As UInt32) As Integer + Declare Ansi Function AddProtection64 Lib "DinkeyAdd64.dll" Alias "AddProtection" (ByVal dapf_handle As IntPtr, ByVal action As Integer, ByVal file_num As Integer, _ + ByVal flags As Integer, ByRef dongle_number As UInt32) As Integer + + Declare Ansi Function CreateTempSoftwareKey32 Lib "DinkeyAdd32.dll" Alias "CreateTempSoftwareKey" (ByVal dapf_handle As IntPtr, ByRef my_swkey_info As TEMP_SWKEY_INFO, _ + ByVal flags As Integer) As Integer + Declare Ansi Function CreateTempSoftwareKey64 Lib "DinkeyAdd64.dll" Alias "CreateTempSoftwareKey" (ByVal dapf_handle As IntPtr, ByRef my_swkey_info As TEMP_SWKEY_INFO, _ + ByVal flags As Integer) As Integer + + Declare Ansi Function CreateDemoSoftwareKeyTemplate32 Lib "DinkeyAdd32.dll" Alias "CreateDemoSoftwareKeyTemplate" (ByVal dapf_handle As IntPtr, ByRef my_swkey_info As DEMO_SWKEY_INFO, _ + ByVal flags As Integer) As Integer + Declare Ansi Function CreateDemoSoftwareKeyTemplate64 Lib "DinkeyAdd64.dll" Alias "CreateDemoSoftwareKeyTemplate" (ByVal dapf_handle As IntPtr, ByRef my_swkey_info As DEMO_SWKEY_INFO, _ + ByVal flags As Integer) As Integer + + Declare Ansi Function EncryptShellDataFiles32 Lib "DinkeyAdd32.dll" Alias "EncryptShellDataFiles" (ByVal dapf_handle As IntPtr, ByVal file_num As Integer, _ + ByVal flags As Integer) As Integer + Declare Ansi Function EncryptShellDataFiles64 Lib "DinkeyAdd64.dll" Alias "EncryptShellDataFiles" (ByVal dapf_handle As IntPtr, ByVal file_num As Integer, _ + ByVal flags As Integer) As Integer + + ' get the message output by DinkeyAdd + Declare Ansi Sub GetLastMessage32 Lib "DinkeyAdd32.dll" Alias "GetLastMessage" (ByVal message As StringBuilder, ByVal buffer_size As Integer, ByRef message_length As Integer) + Declare Ansi Sub GetLastMessage64 Lib "DinkeyAdd64.dll" Alias "GetLastMessage" (ByVal message As StringBuilder, ByVal buffer_size As Integer, ByRef message_length As Integer) + + ' get the extended error (set if an error occurs) + Declare Ansi Function GetLastExtendedError32 Lib "DinkeyAdd32.dll" Alias "GetLastExtendedError" () As Integer + Declare Ansi Function GetLastExtendedError64 Lib "DinkeyAdd64.dll" Alias "GetLastExtendedError" () As Integer + + ' ********************** Constants ************************ + Public Const DAPF_VERSION As Integer = 9 ' current DAPF version + + ' WriteDAPFEx API flags + Public Const FLAGS_LOSE_FEATURES As Integer = 1 ' means that you can save the DAPF file to an earlier version even if it means losing some new features that have been currently set + + ' AddProtection API action values + Public Const ACTION_USE_DAPF_SETTINGS As Integer = 0 ' means you just ignore the action value and use the default dapf settings + Public Const ACTION_PROGRAM_DONGLE As Integer = 1 ' program the dongle only + Public Const ACTION_PROTECT_SOFTWARE As Integer = 2 ' protect a software file (index indicated by separate parameter) + Public Const ACTION_PROGRAM_AND_PROTECT As Integer = 3 ' program the dongle and protect software + + ' AddProtection API flags values + Public Const FLAGS_OVERWRITE_OUTPUT As Integer = 1 ' overwrite the output file if it already exists (default is to give an error) + + ' CreateSoftwareKey API flags + Public Const FLAGS_OVERWRITE_SWKEY As Integer = 1 ' ovewrite an existing swkey with the new one + Public Const FLAGS_EXPIRY_DONTCARE As Integer = 2 ' create the Software Key even though the expiry date (or max days) is less than the expiry date of the key itself. + + ' constants for dapf_format in ReadDAPFEx and WriteDAPFEx functions + Public Const DAPF_FORMAT_BINARY As Integer = 1 + Public Const DAPF_FORMAT_JSON As Integer = 2 + Public Const DAPF_FORMAT_JSON_MIN As Integer = 3 ' this value is only used with WriteDAPEx. ReadDAPFEx cannot return this value. + + ' constants for values for model in the TEMP_SWKEY_INFO structure + Public Const SWKEY_MODEL_PRO_LITE As Integer = 0 + Public Const SWKEY_MODEL_PRO_PLUS As Integer = 1 + Public Const SWKEY_MODEL_PRO_NET As Integer = 2 + Public Const SWKEY_MODEL_FD_LITE As Integer = 3 + Public Const SWKEY_MODEL_FD_PLUS As Integer = 4 + Public Const SWKEY_MODEL_FD_NET As Integer = 5 + + ' constants for models bitmap in the DEMO_SWKEY_INFO structure + Public Const SWKEY_BITMAP_DEFAULT As Integer = 0 ' use default value set in DINKEYINFO.SelectedModels + Public Const SWKEY_BITMAP_PRO_LITE As Integer = 1 ' BIT0 + Public Const SWKEY_BITMAP_PRO_PLUS As Integer = 2 ' BIT1 + Public Const SWKEY_BITMAP_PRO_NET As Integer = 4 ' BIT2 + Public Const SWKEY_BITMAP_FD_LITE As Integer = 8 ' BIT3 + Public Const SWKEY_BITMAP_FD_PLUS As Integer = 16 ' BIT4 + Public Const SWKEY_BITMAP_FD_NET As Integer = 32 ' BIT5 + + ' private constants + Private Const MAX_LICENCES As Integer = 255 ' max number of licences in a DAPF file + Private Const MAX_FILE_INFO As Integer = 1000 ' theoretically unlimited but in practice it is easier if we limit it + Private Const MAX_USER_ALGS As Integer = 20 'max number of user algs in DAPF file + Private Const MAX_DATA_ENCS As Integer = 255 ' max number of Shell data encryption files in DAPF file + +' ********************** API Functions ************************ +' We only want to load the correct DLL for the bit-ness of the computer. The other DLL may not exist. +' if the appropriate DLL does not exist in the same directory as this test program you will receive a DllNotFoundException + + ' call the correct dll depending on whether we are running 32-bit or 64-bit code + Function LoadDAPFFromFile(ByVal dapf_file As String, ByRef err_code As Integer) As IntPtr + If (IntPtr.Size = 4) Then + LoadDAPFFromFile = LoadDAPFFromFile32(dapf_file, err_code) + Else + LoadDAPFFromFile = LoadDAPFFromFile64(dapf_file, err_code) + End If + End Function + + ' we have to do some marshalling of arrays of bytes into arrays of structures + Function ReadDAPFEx(ByVal dapf_file As String, ByRef MyDinkeyInfo As DINKEYINFO, ByRef LicenceInfoArray() As LICENCEINFO, ByRef FileInfoArray() As FILEINFO, _ + ByRef AlgorithmArray() As ALGORITHM, ByRef DataFileEncArray() As DATAFILEENC, ByRef dapf_version As Integer, ByRef dapf_format As Integer) As Integer + Dim i As Integer + Dim MyLicenceInfo As New LICENCEINFO + Dim licence_bytes(MAX_LICENCES * Marshal.SizeOf(MyLicenceInfo)) As Byte + Dim licence_bytes_one_struct(Marshal.SizeOf(MyLicenceInfo)) As Byte + Dim MyFileInfo As New FILEINFO + Dim fileinfo_bytes(MAX_FILE_INFO * Marshal.SizeOf(MyFileInfo)) As Byte + Dim fileinfo_bytes_one_struct(Marshal.SizeOf(MyFileInfo)) As Byte + Dim MyAlgorithm As New ALGORITHM + Dim alg_bytes(MAX_USER_ALGS * Marshal.SizeOf(MyAlgorithm)) As Byte + Dim alg_bytes_one_struct(Marshal.SizeOf(MyAlgorithm)) As Byte + Dim MyDataFileEnc As New DATAFILEENC + Dim datafile_bytes(MAX_DATA_ENCS * Marshal.SizeOf(MyDataFileEnc)) As Byte + Dim datafile_bytes_one_struct(Marshal.SizeOf(MyDataFileEnc)) As Byte + Dim MyGC As GCHandle + MyDinkeyInfo = New DINKEYINFO + + If (IntPtr.Size = 4) Then + ReadDAPFEx = ReadDAPFEx32(dapf_file, MyDinkeyInfo, licence_bytes, fileinfo_bytes, alg_bytes, datafile_bytes, dapf_version, dapf_format) + Else + ReadDAPFEx = ReadDAPFEx64(dapf_file, MyDinkeyInfo, licence_bytes, fileinfo_bytes, alg_bytes, datafile_bytes, dapf_version, dapf_format) + End If + + If ReadDAPFEx <> 0 Then + Exit Function + End If + + ' convert byte array to an array of structs + ReDim LicenceInfoArray(MyDinkeyInfo.NumLicences) + For i = 0 To MyDinkeyInfo.NumLicences - 1 + LicenceInfoArray(i) = New LICENCEINFO + Array.Copy(licence_bytes, i * Marshal.SizeOf(MyLicenceInfo.GetType), licence_bytes_one_struct, 0, Marshal.SizeOf(MyLicenceInfo.GetType)) + MyGC = GCHandle.Alloc(licence_bytes_one_struct, GCHandleType.Pinned) + LicenceInfoArray(i) = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, MyLicenceInfo.GetType) + MyGC.Free() + Next + + ReDim FileInfoArray(MyDinkeyInfo.NumProgs) + For i = 0 To MyDinkeyInfo.NumProgs - 1 + FileInfoArray(i) = New FILEINFO + Array.Copy(fileinfo_bytes, i * Marshal.SizeOf(MyFileInfo.GetType), fileinfo_bytes_one_struct, 0, Marshal.SizeOf(MyFileInfo.GetType)) + MyGC = GCHandle.Alloc(fileinfo_bytes_one_struct, GCHandleType.Pinned) + FileInfoArray(i) = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, MyFileInfo.GetType) + MyGC.Free() + Next + + ReDim AlgorithmArray(MyDinkeyInfo.NumAlgs) + For i = 0 To MyDinkeyInfo.NumAlgs - 1 + AlgorithmArray(i) = New ALGORITHM + Array.Copy(alg_bytes, i * Marshal.SizeOf(MyAlgorithm.GetType), alg_bytes_one_struct, 0, Marshal.SizeOf(MyAlgorithm.GetType)) + MyGC = GCHandle.Alloc(alg_bytes_one_struct, GCHandleType.Pinned) + AlgorithmArray(i) = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, MyAlgorithm.GetType) + MyGC.Free() + Next + + ReDim DataFileEncArray(MyDinkeyInfo.NumDataFileEnc) + For i = 0 To MyDinkeyInfo.NumDataFileEnc - 1 + DataFileEncArray(i) = New DATAFILEENC + Array.Copy(datafile_bytes, i * Marshal.SizeOf(MyDataFileEnc.GetType), datafile_bytes_one_struct, 0, Marshal.SizeOf(MyDataFileEnc.GetType)) + MyGC = GCHandle.Alloc(datafile_bytes_one_struct, GCHandleType.Pinned) + DataFileEncArray(i) = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, MyDataFileEnc.GetType) + MyGC.Free() + Next + + End Function + + Function LoadDAPF(ByRef MyDinkeyInfo As DINKEYINFO, ByRef LicenceInfoArray() As LICENCEINFO, ByRef FileInfoArray() As FILEINFO, _ + ByRef AlgorithmArray() As ALGORITHM, ByRef DataFileEncArray() As DATAFILEENC, ByRef ret_code As Integer) As IntPtr + Dim i As Integer + Dim MyLicenceInfo As New LICENCEINFO + Dim licence_bytes(MAX_LICENCES * Marshal.SizeOf(MyLicenceInfo)) As Byte + Dim licence_bytes_one_struct(Marshal.SizeOf(MyLicenceInfo)) As Byte + Dim MyFileInfo As New FILEINFO + Dim fileinfo_bytes(MAX_FILE_INFO * Marshal.SizeOf(MyFileInfo)) As Byte + Dim fileinfo_bytes_one_struct(Marshal.SizeOf(MyFileInfo)) As Byte + Dim MyAlgorithm As New ALGORITHM + Dim alg_bytes(MAX_USER_ALGS * Marshal.SizeOf(MyAlgorithm)) As Byte + Dim alg_bytes_one_struct(Marshal.SizeOf(MyAlgorithm)) As Byte + Dim MyDataFileEnc As New DATAFILEENC + Dim datafile_bytes(MAX_DATA_ENCS * Marshal.SizeOf(MyDataFileEnc)) As Byte + Dim datafile_bytes_one_struct(Marshal.SizeOf(MyDataFileEnc)) As Byte + Dim MyGC As GCHandle + + ' convert array of structs to byte arrays + For i = 0 To MyDinkeyInfo.NumLicences - 1 + MyGC = GCHandle.Alloc(licence_bytes_one_struct, GCHandleType.Pinned) + Marshal.StructureToPtr(LicenceInfoArray(i), MyGC.AddrOfPinnedObject, False) + MyGC.Free() + Array.Copy(licence_bytes_one_struct, 0, licence_bytes, i * Marshal.SizeOf(MyLicenceInfo.GetType), Marshal.SizeOf(MyLicenceInfo.GetType)) + Next + + For i = 0 To MyDinkeyInfo.NumProgs - 1 + MyGC = GCHandle.Alloc(fileinfo_bytes_one_struct, GCHandleType.Pinned) + Marshal.StructureToPtr(FileInfoArray(i), MyGC.AddrOfPinnedObject, False) + MyGC.Free() + Array.Copy(fileinfo_bytes_one_struct, 0, fileinfo_bytes, i * Marshal.SizeOf(MyFileInfo.GetType), Marshal.SizeOf(MyFileInfo.GetType)) + Next + + For i = 0 To MyDinkeyInfo.NumAlgs - 1 + MyGC = GCHandle.Alloc(alg_bytes_one_struct, GCHandleType.Pinned) + Marshal.StructureToPtr(AlgorithmArray(i), MyGC.AddrOfPinnedObject, False) + MyGC.Free() + Array.Copy(alg_bytes_one_struct, 0, alg_bytes, i * Marshal.SizeOf(MyAlgorithm.GetType), Marshal.SizeOf(MyAlgorithm.GetType)) + Next + + For i = 0 To MyDinkeyInfo.NumDataFileEnc - 1 + MyGC = GCHandle.Alloc(datafile_bytes_one_struct, GCHandleType.Pinned) + Marshal.StructureToPtr(DataFileEncArray(i), MyGC.AddrOfPinnedObject, False) + MyGC.Free() + Array.Copy(datafile_bytes_one_struct, 0, datafile_bytes, i * Marshal.SizeOf(MyDataFileEnc.GetType), Marshal.SizeOf(MyDataFileEnc.GetType)) + Next + + If (IntPtr.Size = 4) Then + LoadDAPF = LoadDAPF32(MyDinkeyInfo, licence_bytes, fileinfo_bytes, alg_bytes, datafile_bytes, ret_code) + Else + LoadDAPF = LoadDAPF64(MyDinkeyInfo, licence_bytes, fileinfo_bytes, alg_bytes, datafile_bytes, ret_code) + End If + + End Function + + Function WriteDAPFEx(ByVal dapf_handle As IntPtr, ByVal dapf_file As String, ByVal dapf_format As Integer, ByVal dapf_version As Integer, ByVal flags As Integer) As Integer + If (IntPtr.Size = 4) Then + WriteDAPFEx = WriteDAPFEx32(dapf_handle, dapf_file, dapf_format, dapf_version, flags) + Else + WriteDAPFEx = WriteDAPFEx64(dapf_handle, dapf_file, dapf_format, dapf_version, flags) + End If + End Function + + Sub UnloadDAPF(ByRef dapf_handle As IntPtr) + If (IntPtr.Size = 4) Then + UnloadDAPF32(dapf_handle) + Else + UnloadDAPF64(dapf_handle) + End If + End Sub + + Function AddProtection(ByVal dapf_handle As IntPtr, ByVal action As Integer, ByVal file_num As Integer, ByVal flags As Integer, ByRef dongle_number As UInt32) As Integer + If (IntPtr.Size = 4) Then + AddProtection = AddProtection32(dapf_handle, action, file_num, flags, dongle_number) + Else + AddProtection = AddProtection64(dapf_handle, action, file_num, flags, dongle_number) + End If + End Function + + Function CreateTempSoftwareKey(ByVal dapf_handle As IntPtr, ByRef swkey_info As TEMP_SWKEY_INFO, ByVal flags As Integer) As Integer + If (IntPtr.Size = 4) Then + CreateTempSoftwareKey = CreateTempSoftwareKey32(dapf_handle, swkey_info, flags) + Else + CreateTempSoftwareKey = CreateTempSoftwareKey64(dapf_handle, swkey_info, flags) + End If + End Function + + Function CreateDemoSoftwareKeyTemplate(ByVal dapf_handle As IntPtr, ByRef swkey_info As DEMO_SWKEY_INFO, ByVal flags As Integer) As Integer + If (IntPtr.Size = 4) Then + CreateDemoSoftwareKeyTemplate = CreateDemoSoftwareKeyTemplate32(dapf_handle, swkey_info, flags) + Else + CreateDemoSoftwareKeyTemplate = CreateDemoSoftwareKeyTemplate64(dapf_handle, swkey_info, flags) + End If + End Function + + Function EncryptShellDataFiles(ByVal dapf_handle As IntPtr, ByVal file_num As Integer, ByVal flags As Integer) As Integer + If (IntPtr.Size = 4) Then + EncryptShellDataFiles = EncryptShellDataFiles32(dapf_handle, file_num, flags) + Else + EncryptShellDataFiles = EncryptShellDataFiles64(dapf_handle, file_num, flags) + End If + End Function + + ' do a bit of work here to make the function easier to use for VB.NET + Function GetLastMessage() As String + Dim length, dummy As Integer + Dim message As StringBuilder + + If (IntPtr.Size = 4) Then + GetLastMessage32(Nothing, 0, length) + message = New StringBuilder(length) + GetLastMessage32(message, length, dummy) + Else + GetLastMessage64(Nothing, 0, length) + message = New StringBuilder(length) + GetLastMessage64(message, length, dummy) + End If + + Return message.ToString() + End Function + + Function GetLastExtendedError() As Integer + If (IntPtr.Size = 4) Then + GetLastExtendedError = GetLastExtendedError32() + Else + GetLastExtendedError = GetLastExtendedError64() + End If + End Function + +End Module diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyAdd/dapfTest.sln b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyAdd/dapfTest.sln new file mode 100644 index 0000000..376658e --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyAdd/dapfTest.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "dapfTest", "dapfTest.vbproj", "{35022C29-459B-4D19-BC69-5133B03CD7FF}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {35022C29-459B-4D19-BC69-5133B03CD7FF}.Debug.ActiveCfg = Debug|.NET + {35022C29-459B-4D19-BC69-5133B03CD7FF}.Debug.Build.0 = Debug|.NET + {35022C29-459B-4D19-BC69-5133B03CD7FF}.Release.ActiveCfg = Release|.NET + {35022C29-459B-4D19-BC69-5133B03CD7FF}.Release.Build.0 = Release|.NET + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyAdd/dapfTest.vbproj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyAdd/dapfTest.vbproj new file mode 100644 index 0000000..d72e0d2 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyAdd/dapfTest.vbproj @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyChange/AssemblyInfo.vb b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyChange/AssemblyInfo.vb new file mode 100644 index 0000000..2635a9c --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyChange/AssemblyInfo.vb @@ -0,0 +1,31 @@ +Imports System.Reflection +Imports System.Runtime.InteropServices + +' General Information about an assembly is controlled through the following +' set of attributes. Change these attribute values to modify the information +' associated with an assembly. + +' Review the values of the assembly attributes + + + + + + + + + +'The following GUID is for the ID of the typelib if this project is exposed to COM + + +' Version information for an assembly consists of the following four values: +' +' Major Version +' Minor Version +' Build Number +' Revision +' +' You can specify all the values or you can default the Build and Revision Numbers +' by using the '*' as shown below: + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyChange/ChangeTest.sln b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyChange/ChangeTest.sln new file mode 100644 index 0000000..03ad53d --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyChange/ChangeTest.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "ChangeTest", "ChangeTest.vbproj", "{5F1FF5B9-0F39-4DF7-B37A-CD1A84027EDB}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {5F1FF5B9-0F39-4DF7-B37A-CD1A84027EDB}.Debug.ActiveCfg = Debug|.NET + {5F1FF5B9-0F39-4DF7-B37A-CD1A84027EDB}.Debug.Build.0 = Debug|.NET + {5F1FF5B9-0F39-4DF7-B37A-CD1A84027EDB}.Release.ActiveCfg = Release|.NET + {5F1FF5B9-0F39-4DF7-B37A-CD1A84027EDB}.Release.Build.0 = Release|.NET + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyChange/ChangeTest.vbproj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyChange/ChangeTest.vbproj new file mode 100644 index 0000000..615886b --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyChange/ChangeTest.vbproj @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyChange/DinkeyChange.vb b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyChange/DinkeyChange.vb new file mode 100644 index 0000000..ca08fcc --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyChange/DinkeyChange.vb @@ -0,0 +1,144 @@ +' !! this file should not be modified + +Imports System.Runtime.InteropServices +Imports System.Text + +Module DinkeyChange_code + + ' declarations for functions exported by DinkeyChange.dll + Declare Ansi Function DCGetInfo32 Lib "DinkeyChange.dll" Alias "DCGetInfo" (ByVal type_mask As Integer, ByVal model_mask As Integer, ByVal prodcode_mask As String, ByVal array_length As Integer, _ + ByRef num_found As Integer, ByVal type_array() As Integer, ByVal model_array() As Integer, ByVal prodcode_array() As Byte, ByVal dongle_number() As UInt32, ByVal update_number() As Integer) As Integer + Declare Ansi Function DCGetDiagnosticInfo32 Lib "DinkeyChange.dll" Alias "DCGetDiagnosticInfo" (ByVal filename As String) As Integer + Declare Ansi Function DCDoUpdateCodeString32 Lib "DinkeyChange.dll" Alias "DCDoUpdateCodeString" (ByVal update_code_string As String, ByRef confirmation_code As Integer, ByRef extended_error As Integer) As Integer + Declare Ansi Function DCDoUpdateCodeFromFile32 Lib "DinkeyChange.dll" Alias "DCDoUpdateCodeFromFile" (ByVal filename As String, ByRef confirmation_code As Integer, ByRef extended_error As Integer) As Integer + Declare Ansi Function DCRestoreDinkeyFDLite32 Lib "DinkeyChange.dll" Alias "DCRestoreDinkeyFDLite" () As Integer + Declare Ansi Function DCGetMachineID32 Lib "DinkeyChange.dll" Alias "DCGetMachineID" (ByRef machineID As UInt32, ByRef extended_error As Integer) As Integer + Declare Ansi Function DCDownloadTempSoftwareKey32 Lib "DinkeyChange.dll" Alias "DCDownloadTempSoftwareKey" (ByVal machineID As UInt32, ByRef extended_error As Integer) As Integer + Declare Ansi Function DCDownloadDemoSoftwareKey32 Lib "DinkeyChange.dll" Alias "DCDownloadDemoSoftwareKey" (ByVal machineID As UInt32, ByVal prodcode As String, ByVal model As Integer, ByRef extended_error As Integer) As Integer + + ' declarations for functions exported by DinkeyChange64.dll + Declare Ansi Function DCGetInfo64 Lib "DinkeyChange64.dll" Alias "DCGetInfo" (ByVal type_mask As Integer, ByVal model_mask As Integer, ByVal prodcode_mask As String, ByVal array_length As Integer, _ + ByRef num_found As Integer, ByVal type_array() As Integer, ByVal model_array() As Integer, ByVal prodcode_array() As Byte, ByVal dongle_number() As UInt32, ByVal update_number() As Integer) As Integer + Declare Ansi Function DCGetDiagnosticInfo64 Lib "DinkeyChange64.dll" Alias "DCGetDiagnosticInfo" (ByVal filename As String) As Integer + Declare Ansi Function DCDoUpdateCodeString64 Lib "DinkeyChange64.dll" Alias "DCDoUpdateCodeString" (ByVal update_code_string As String, ByRef confirmation_code As Integer, ByRef extended_error As Integer) As Integer + Declare Ansi Function DCDoUpdateCodeFromFile64 Lib "DinkeyChange64.dll" Alias "DCDoUpdateCodeFromFile" (ByVal filename As String, ByRef confirmation_code As Integer, ByRef extended_error As Integer) As Integer + Declare Ansi Function DCRestoreDinkeyFDLite64 Lib "DinkeyChange64.dll" Alias "DCRestoreDinkeyFDLite" () As Integer + Declare Ansi Function DCGetMachineID64 Lib "DinkeyChange64.dll" Alias "DCGetMachineID" (ByRef machineID As UInt32, ByRef extended_error As Integer) As Integer + Declare Ansi Function DCDownloadTempSoftwareKey64 Lib "DinkeyChange64.dll" Alias "DCDownloadTempSoftwareKey" (ByVal machineID As UInt32, ByRef extended_error As Integer) As Integer + Declare Ansi Function DCDownloadDemoSoftwareKey64 Lib "DinkeyChange64.dll" Alias "DCDownloadDemoSoftwareKey" (ByVal machineID As UInt32, ByVal prodcode As String, ByVal model As Integer, ByRef extended_error As Integer) As Integer + + 'routines that ensure the relevant dll is called depending on whether we are running on 32-bit or 64-bit Windows + Function DCGetInfo(ByVal type_mask As Integer, ByVal model_mask As Integer, ByVal prodcode_mask As String, ByVal array_length As Integer, _ + ByRef num_found As Integer, ByVal type_array() As Integer, ByVal model_array() As Integer, ByVal prodcode_array() As Byte, ByVal dongle_number() As UInt32, ByVal update_number() As Integer) As Integer + If (IntPtr.Size = 4) Then + DCGetInfo = DCGetInfo32(type_mask, model_mask, prodcode_mask, array_length, num_found, type_array, model_array, prodcode_array, dongle_number, update_number) + Else + DCGetInfo = DCGetInfo64(type_mask, model_mask, prodcode_mask, array_length, num_found, type_array, model_array, prodcode_array, dongle_number, update_number) + End If + End Function + + Function DCGetDiagnosticInfo(ByVal filename As String) As Integer + If (IntPtr.Size = 4) Then + DCGetDiagnosticInfo = DCGetDiagnosticInfo32(filename) + Else + DCGetDiagnosticInfo = DCGetDiagnosticInfo64(filename) + End If + End Function + + Function DCDoUpdateCodeString(ByVal update_code_string As String, ByRef confirmation_code As Integer, ByRef extended_error As Integer) As Integer + If (IntPtr.Size = 4) Then + DCDoUpdateCodeString = DCDoUpdateCodeString32(update_code_string, confirmation_code, extended_error) + Else + DCDoUpdateCodeString = DCDoUpdateCodeString64(update_code_string, confirmation_code, extended_error) + End If + End Function + + Function DCDoUpdateCodeFromFile(ByVal filename As String, ByRef confirmation_code As Integer, ByRef extended_error As Integer) As Integer + If (IntPtr.Size = 4) Then + DCDoUpdateCodeFromFile = DCDoUpdateCodeFromFile32(filename, confirmation_code, extended_error) + Else + DCDoUpdateCodeFromFile = DCDoUpdateCodeFromFile64(filename, confirmation_code, extended_error) + End If + End Function + + Function DCRestoreDinkeyFDLite() As Integer + If (IntPtr.Size = 4) Then + DCRestoreDinkeyFDLite = DCRestoreDinkeyFDLite32() + Else + DCRestoreDinkeyFDLite = DCRestoreDinkeyFDLite64() + End If + End Function + + Function DCGetMachineID(ByRef machineID As UInt32, ByRef extended_error As Integer) As Integer + If (IntPtr.Size = 4) Then + DCGetMachineID = DCGetMachineID32(machineID, extended_error) + Else + DCGetMachineID = DCGetMachineID64(machineID, extended_error) + End If + End Function + + Function DCDownloadTempSoftwareKey(ByVal machineID As UInt32, ByRef extended_error As Integer) As Integer + If (IntPtr.Size = 4) Then + DCDownloadTempSoftwareKey = DCDownloadTempSoftwareKey32(machineID, extended_error) + Else + DCDownloadTempSoftwareKey = DCDownloadTempSoftwareKey64(machineID, extended_error) + End If + End Function + + Function DCDownloadDemoSoftwareKey(ByVal machineID As UInt32, ByVal prodcode As String, ByVal model As Integer, ByRef extended_error As Integer) As Integer + If (IntPtr.Size = 4) Then + DCDownloadDemoSoftwareKey = DCDownloadDemoSoftwareKey32(machineID, prodcode, model, extended_error) + Else + DCDownloadDemoSoftwareKey = DCDownloadDemoSoftwareKey64(machineID, prodcode, model, extended_error) + End If + End Function + + ' routine to extract product code string from array of product codes + Function GetProductCode(ByRef prodcode() As Byte, ByVal index As Integer) As String + Dim i As Integer + Dim ascii As New ASCIIEncoding() + + For i = 0 To 8 + If prodcode((index * 9) + i) = 0 Then + Exit For + End If + Next + Return ascii.GetString(prodcode, index * 9, i) + End Function + + ' maximum number of USB devices that can be attached to a machine at any time + Public Const MAX_USB_DEVICES As Integer = 128 + Public Const MAX_PRODCODE_LEN As Integer = 9 + + ' mask values + Public Const TYPE_MASK_PRO As Integer = 1 + Public Const TYPE_MASK_FD As Integer = 2 + Public Const TYPE_MASK_ALL As Integer = TYPE_MASK_PRO Or TYPE_MASK_FD + + Public Const MODEL_MASK_LITE As Integer = 1 + Public Const MODEL_MASK_PLUS As Integer = 2 + Public Const MODEL_MASK_NET As Integer = 4 + Public Const MODEL_MASK_ALL As Integer = MODEL_MASK_LITE Or MODEL_MASK_PLUS Or MODEL_MASK_NET + Public Const MODEL_MASK_DEFAULT As Integer = MODEL_MASK_PLUS Or MODEL_MASK_NET + + ' type values for DCGetInfo (returned in the array) + Public Const TYPE_PRO As Integer = 1 + Public Const TYPE_FD As Integer = 2 + + ' model values for DCGetInfo (returned in the array) + Public Const MODEL_LITE As Integer = 1 + Public Const MODEL_PLUS As Integer = 2 + Public Const MODEL_NET5 As Integer = 4 + Public Const MODEL_NETU As Integer = 7 + + ' model values for DCDownloadDemoSoftwareKey + Public Const SWKEY_MODEL_DEFAULT As Integer = &HFFFFFFFF ' NB this assumes that the Demo Software Key Template was created with only one valid dongle model + Public Const SWKEY_MODEL_PRO_LITE As Integer = 0 + Public Const SWKEY_MODEL_PRO_PLUS As Integer = 1 + Public Const SWKEY_MODEL_PRO_NET As Integer = 2 + Public Const SWKEY_MODEL_FD_LITE As Integer = 3 + Public Const SWKEY_MODEL_FD_PLUS As Integer = 4 + Public Const SWKEY_MODEL_FD_NET As Integer = 5 + +End Module + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyChange/Form1.resx b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyChange/Form1.resx new file mode 100644 index 0000000..3c1fe23 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyChange/Form1.resx @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + False + + + Assembly + + + Assembly + + + False + + + Assembly + + + Assembly + + + Assembly + + + False + + + Assembly + + + False + + + Assembly + + + Assembly + + + False + + + Assembly + + + Assembly + + + Assembly + + + False + + + Assembly + + + False + + + Assembly + + + Assembly + + + False + + + Assembly + + + Assembly + + + Assembly + + + False + + + Assembly + + + False + + + Assembly + + + Assembly + + + False + + + Assembly + + + Assembly + + + False + + + Assembly + + + Assembly + + + False + + + Assembly + + + Assembly + + + Assembly + + + False + + + Assembly + + + False + + + (Default) + + + False + + + Form1 + + + False + + + 8, 8 + + + True + + + 80 + + + True + + + Assembly + + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyChange/Form1.vb b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyChange/Form1.vb new file mode 100644 index 0000000..11f2263 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyChange/Form1.vb @@ -0,0 +1,458 @@ +' !! We strongly recommend that you read the "readme.txt" file in the sample code folder. +' !! It contains important instructions on how to use the sample code + +Imports System.Text + +Public Class Form1 + Inherits System.Windows.Forms.Form + +#Region " Windows Form Designer generated code " + + Public Sub New() + MyBase.New() + + 'This call is required by the Windows Form Designer. + InitializeComponent() + + 'Add any initialization after the InitializeComponent() call + + End Sub + + 'Form overrides dispose to clean up the component list. + Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) + If disposing Then + If Not (components Is Nothing) Then + components.Dispose() + End If + End If + MyBase.Dispose(disposing) + End Sub + + 'Required by the Windows Form Designer + Private components As System.ComponentModel.IContainer + + 'NOTE: The following procedure is required by the Windows Form Designer + 'It can be modified using the Windows Form Designer. + 'Do not modify it using the code editor. + Friend WithEvents GetDongleInfo As System.Windows.Forms.Button + Friend WithEvents label1 As System.Windows.Forms.Label + Friend WithEvents DiagFilename As System.Windows.Forms.TextBox + Friend WithEvents WriteDiags As System.Windows.Forms.Button + Friend WithEvents DoUpdateCodeString As System.Windows.Forms.Button + Friend WithEvents UpdateCodeString As System.Windows.Forms.TextBox + Friend WithEvents Label2 As System.Windows.Forms.Label + Friend WithEvents DoUpdateCodeFile As System.Windows.Forms.Button + Friend WithEvents Label3 As System.Windows.Forms.Label + Friend WithEvents UpdateCodeFile As System.Windows.Forms.TextBox + Friend WithEvents RestoreFDLite As System.Windows.Forms.Button + Friend WithEvents GetMachineID As System.Windows.Forms.Button + Friend WithEvents DownloadTempSoftwareKey As System.Windows.Forms.Button + Friend WithEvents ShowMachineID As System.Windows.Forms.TextBox + Friend WithEvents label4 As System.Windows.Forms.Label + Friend WithEvents ProdCode As System.Windows.Forms.TextBox + Friend WithEvents DownloadDemoSoftwareKey As System.Windows.Forms.Button + Private Sub InitializeComponent() + Me.GetDongleInfo = New System.Windows.Forms.Button + Me.label1 = New System.Windows.Forms.Label + Me.DiagFilename = New System.Windows.Forms.TextBox + Me.WriteDiags = New System.Windows.Forms.Button + Me.DoUpdateCodeString = New System.Windows.Forms.Button + Me.UpdateCodeString = New System.Windows.Forms.TextBox + Me.Label2 = New System.Windows.Forms.Label + Me.DoUpdateCodeFile = New System.Windows.Forms.Button + Me.UpdateCodeFile = New System.Windows.Forms.TextBox + Me.Label3 = New System.Windows.Forms.Label + Me.RestoreFDLite = New System.Windows.Forms.Button + Me.GetMachineID = New System.Windows.Forms.Button + Me.DownloadTempSoftwareKey = New System.Windows.Forms.Button + Me.ShowMachineID = New System.Windows.Forms.TextBox + Me.label4 = New System.Windows.Forms.Label + Me.ProdCode = New System.Windows.Forms.TextBox + Me.DownloadDemoSoftwareKey = New System.Windows.Forms.Button + Me.SuspendLayout() + ' + 'GetDongleInfo + ' + Me.GetDongleInfo.Location = New System.Drawing.Point(48, 24) + Me.GetDongleInfo.Name = "GetDongleInfo" + Me.GetDongleInfo.Size = New System.Drawing.Size(216, 24) + Me.GetDongleInfo.TabIndex = 0 + Me.GetDongleInfo.Text = "Get Dongle Information" + ' + 'label1 + ' + Me.label1.Location = New System.Drawing.Point(16, 72) + Me.label1.Name = "label1" + Me.label1.Size = New System.Drawing.Size(296, 16) + Me.label1.TabIndex = 1 + Me.label1.Text = "Enter diagnostic filename:" + ' + 'DiagFilename + ' + Me.DiagFilename.Location = New System.Drawing.Point(16, 88) + Me.DiagFilename.Name = "DiagFilename" + Me.DiagFilename.Size = New System.Drawing.Size(288, 20) + Me.DiagFilename.TabIndex = 2 + Me.DiagFilename.Text = "" + ' + 'WriteDiags + ' + Me.WriteDiags.Location = New System.Drawing.Point(56, 120) + Me.WriteDiags.Name = "WriteDiags" + Me.WriteDiags.Size = New System.Drawing.Size(192, 23) + Me.WriteDiags.TabIndex = 3 + Me.WriteDiags.Text = "Write Diagnostics to File" + ' + 'Label2 + ' + Me.Label2.Location = New System.Drawing.Point(16, 171) + Me.Label2.Name = "Label2" + Me.Label2.Size = New System.Drawing.Size(296, 16) + Me.Label2.TabIndex = 4 + Me.Label2.Text = "Enter short Update Code here:" + ' + 'UpdateCodeString + ' + Me.UpdateCodeString.Location = New System.Drawing.Point(16, 187) + Me.UpdateCodeString.Name = "UpdateCodeString" + Me.UpdateCodeString.Size = New System.Drawing.Size(288, 20) + Me.UpdateCodeString.TabIndex = 5 + Me.UpdateCodeString.Text = "" + ' + 'DoUpdateCodeString + ' + Me.DoUpdateCodeString.Location = New System.Drawing.Point(56, 219) + Me.DoUpdateCodeString.Name = "DoUpdateCodeString" + Me.DoUpdateCodeString.Size = New System.Drawing.Size(192, 23) + Me.DoUpdateCodeString.TabIndex = 6 + Me.DoUpdateCodeString.Text = "Make Changes" + ' + 'Label3 + ' + Me.Label3.Location = New System.Drawing.Point(16, 272) + Me.Label3.Name = "Label3" + Me.Label3.Size = New System.Drawing.Size(296, 16) + Me.Label3.TabIndex = 7 + Me.Label3.Text = "Enter path to Update Code file:" + ' + 'UpdateCodeFile + ' + Me.UpdateCodeFile.Location = New System.Drawing.Point(16, 288) + Me.UpdateCodeFile.Name = "UpdateCodeFile" + Me.UpdateCodeFile.Size = New System.Drawing.Size(288, 20) + Me.UpdateCodeFile.TabIndex = 8 + Me.UpdateCodeFile.Text = "" + ' + 'DoUpdateCodeFile + ' + Me.DoUpdateCodeFile.Location = New System.Drawing.Point(56, 320) + Me.DoUpdateCodeFile.Name = "DoUpdateCodeFile" + Me.DoUpdateCodeFile.Size = New System.Drawing.Size(192, 23) + Me.DoUpdateCodeFile.TabIndex = 9 + Me.DoUpdateCodeFile.Text = "Make Changes" + ' + 'RestoreFDLite + ' + Me.RestoreFDLite.Location = New System.Drawing.Point(56, 376) + Me.RestoreFDLite.Name = "RestoreFDLite" + Me.RestoreFDLite.Size = New System.Drawing.Size(192, 23) + Me.RestoreFDLite.TabIndex = 10 + Me.RestoreFDLite.Text = "Restore FD Lite" + ' + 'GetMachineID + ' + Me.GetMachineID.Location = New System.Drawing.Point(24, 432) + Me.GetMachineID.Name = "GetMachineID" + Me.GetMachineID.Size = New System.Drawing.Size(128, 23) + Me.GetMachineID.TabIndex = 11 + Me.GetMachineID.Text = "Get Machine ID" + ' + 'ShowMachineID + ' + Me.ShowMachineID.Location = New System.Drawing.Point(168, 432) + Me.ShowMachineID.Name = "ShowMachineID" + Me.ShowMachineID.Size = New System.Drawing.Size(136, 20) + Me.ShowMachineID.TabIndex = 12 + Me.ShowMachineID.Text = "" + ' + 'DownloadTempSoftwareKey + ' + Me.DownloadTempSoftwareKey.Location = New System.Drawing.Point(56, 488) + Me.DownloadTempSoftwareKey.Name = "DownloadTempSoftwareKey" + Me.DownloadTempSoftwareKey.Size = New System.Drawing.Size(192, 23) + Me.DownloadTempSoftwareKey.TabIndex = 13 + Me.DownloadTempSoftwareKey.Text = "Download Temporary Software Key" + ' + 'label4 + ' + Me.label4.Location = New System.Drawing.Point(16, 541) + Me.label4.Name = "label4" + Me.label4.Size = New System.Drawing.Size(296, 16) + Me.label4.TabIndex = 14 + Me.label4.Text = "Demo Software Key Product Code:" + ' + 'ProdCode + ' + Me.ProdCode.Location = New System.Drawing.Point(16, 557) + Me.ProdCode.Name = "ProdCode" + Me.ProdCode.Size = New System.Drawing.Size(288, 20) + Me.ProdCode.TabIndex = 15 + Me.ProdCode.Text = "" + ' + 'DownloadTempSoftwareKey + ' + Me.DownloadDemoSoftwareKey.Location = New System.Drawing.Point(56, 590) + Me.DownloadDemoSoftwareKey.Name = "DownloadDemoSoftwareKey" + Me.DownloadDemoSoftwareKey.Size = New System.Drawing.Size(192, 23) + Me.DownloadDemoSoftwareKey.TabIndex = 16 + Me.DownloadDemoSoftwareKey.Text = "Download Demo Software Key" + ' + 'Form1 + ' + Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13) + Me.ClientSize = New System.Drawing.Size(320, 636) + Me.Controls.Add(Me.DownloadDemoSoftwareKey) + Me.Controls.Add(Me.ProdCode) + Me.Controls.Add(Me.label4) + Me.Controls.Add(Me.ShowMachineID) + Me.Controls.Add(Me.DownloadTempSoftwareKey) + Me.Controls.Add(Me.GetMachineID) + Me.Controls.Add(Me.RestoreFDLite) + Me.Controls.Add(Me.DoUpdateCodeFile) + Me.Controls.Add(Me.UpdateCodeFile) + Me.Controls.Add(Me.Label3) + Me.Controls.Add(Me.DoUpdateCodeString) + Me.Controls.Add(Me.UpdateCodeString) + Me.Controls.Add(Me.Label2) + Me.Controls.Add(Me.WriteDiags) + Me.Controls.Add(Me.DiagFilename) + Me.Controls.Add(Me.label1) + Me.Controls.Add(Me.GetDongleInfo) + Me.Name = "Form1" + Me.Text = "ChangeTest" + Me.ResumeLayout(False) + + End Sub + +#End Region + + ' Get Dongle Information + Private Sub GetDongleInfo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles GetDongleInfo.Click + Dim sType, sModel, sProdCode, sDisplay As String + Dim ret_code, i, num_found As Integer + ' our arrays + Dim type(MAX_USB_DEVICES), model(MAX_USB_DEVICES), update_number(MAX_USB_DEVICES) As Integer + Dim prodcode(MAX_USB_DEVICES * MAX_PRODCODE_LEN) As Byte + Dim dongle_number(MAX_USB_DEVICES) As UInt32 + + ' find dongle information for all dongle types, Plus & Net models, for all product codes + ' NB In practice you will probably want to set the prodcode_mask to the value of your product code + ret_code = DCGetInfo(TYPE_MASK_ALL, MODEL_MASK_DEFAULT, Nothing, MAX_USB_DEVICES, num_found, type, model, prodcode, dongle_number, update_number) + + ' check error code and display error if an error occurs + If ret_code = 401 Then + MsgBox("No dongles detected matching the search criteria specified", MsgBoxStyle.OkOnly, "Error") + Exit Sub + ElseIf ret_code <> 0 Then + MsgBox("Error " + Str(ret_code) + " getting dongle information", MsgBoxStyle.OkOnly, "Error") + Exit Sub + End If + + ' display info from the dongles detected + sDisplay = "" + For i = 0 To num_found - 1 + ' get type of dongle + If type(i) = TYPE_PRO Then + sType = "Pro" + Else + sType = "FD" + End If + ' get model of dongle + If model(i) = MODEL_LITE Then + sModel = "Lite" + ElseIf model(i) = MODEL_PLUS Then + sModel = "Plus" + Else + sModel = "Net" + End If + ' get product code + sProdCode = GetProductCode(prodcode, i) + sDisplay = sDisplay + Str(i + 1) + ". Dinkey " + sType + " " + sModel + " with dongle number: " + dongle_number(i).ToString + ", product code: " + sProdCode + ", update number: " + Str(update_number(i)) + vbNewLine + Next + MsgBox(sDisplay, MsgBoxStyle.OkOnly, "Dongle Information") + End Sub + + + ' Write Dongle Diagnostics to file + Private Sub WriteDiags_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles WriteDiags.Click + Dim ret_code As Integer + + ret_code = DCGetDiagnosticInfo(DiagFilename.Text) + + ' check error code and display error if an error occurs + If ret_code = 754 Then + MsgBox("Could not create the diagnostic file. Please check that the path exists: " + DiagFilename.Text, MsgBoxStyle.OkOnly, "Error") + Exit Sub + ElseIf ret_code <> 0 Then + MsgBox("Error " + Str(ret_code) + " writing diagnostic information", MsgBoxStyle.OkOnly, "Error") + Exit Sub + End If + + ' display success + MsgBox("Diagnostic file written successfully.", MsgBoxStyle.OkOnly, "Dongle Information") + End Sub + + + ' Apply short update code entered manually + Private Sub DoUpdateCodeString_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DoUpdateCodeString.Click + Dim ret_code, confirmation_code, extended_error As Integer + + ret_code = DCDoUpdateCodeString(UpdateCodeString.Text, confirmation_code, extended_error) + + ' check error code and display error if an error occurs + If ret_code <> 0 Then + DisplayError(ret_code, extended_error) + Exit Sub + End If + + ' display success + MsgBox("Dongle updated successfully!" + vbNewLine + "Confirmation code is : " + Hex(confirmation_code), MsgBoxStyle.OkOnly, "Dongle Information") + End Sub + + Private Sub DoUpdateCodeFile_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DoUpdateCodeFile.Click + Dim ret_code, confirmation_code, extended_error As Integer + + ret_code = DCDoUpdateCodeFromFile(UpdateCodeFile.Text, confirmation_code, extended_error) + + ' check error code and display error if an error occurs + If ret_code <> 0 Then + DisplayError(ret_code, extended_error) + Exit Sub + End If + + ' display success + MsgBox("Dongle updated successfully!" + vbNewLine + "Confirmation code is : " + Hex(confirmation_code), MsgBoxStyle.OkOnly, "Dongle Information") + End Sub + + Private Sub RestoreFDLite_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RestoreFDLite.Click + Dim ret_code As Integer + + ret_code = DCRestoreDinkeyFDLite() + + ' check error code and display error if an error occurs + If ret_code <> 0 Then + DisplayError(ret_code, 0) + Exit Sub + End If + + ' display success + MsgBox("Dinkey FD Lite updated successfully!", MsgBoxStyle.OKOnly, "Dongle Information") + End Sub + + Private Sub GetMachineID_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles GetMachineID.Click + Dim ret_code, extended_error As Integer + Dim machineID As UInt32 + + ret_code = DCGetMachineID(machineID, extended_error) + + ' check error code and display error if an error occurs + If ret_code <> 0 Then + DisplayError(ret_code, extended_error) + Exit Sub + End If + + ' success - display the machineID + ShowMachineID.Text = String.Format("{0:X8}", machineID) + End Sub + + Private Sub DownloadTempSoftwareKey_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DownloadTempSoftwareKey.Click + Dim ret_code, extended_error As Integer + Dim machineID As UInt32 + + ' first get the machine ID + ret_code = DCGetMachineID(machineID, extended_error) + + ' check error code and display error if an error occurs + If ret_code <> 0 Then + DisplayError(ret_code, extended_error) + Exit Sub + End If + + ' ...then try to download the temporary software key + ret_code = DCDownloadTempSoftwareKey(machineID, extended_error) + + ' check error code and display error if an error occurs + If ret_code <> 0 Then + DisplayError(ret_code, extended_error) + Exit Sub + End If + + MsgBox("The Temporary Software Key has been downloaded successfully!", MsgBoxStyle.OKOnly, "Dongle Information") + End Sub + + Private Sub DownloadDemoSoftwareKey_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DownloadDemoSoftwareKey.Click + Dim ret_code, extended_error As Integer + Dim machineID As UInt32 + + ' first get the machine ID + ret_code = DCGetMachineID(machineID, extended_error) + + ' check error code and display error if an error occurs + If ret_code <> 0 Then + DisplayError(ret_code, extended_error) + Exit Sub + End If + + ' ...then try to download the demo software key + ' (NB we are assuming only one dongle model is set in the Demo Software Template. + ' If multiple models are set you will also need to specify the exact model) + ret_code = DCDownloadDemoSoftwareKey(machineID, ProdCode.Text, SWKEY_MODEL_DEFAULT, extended_error) + + ' check error code and display error if an error occurs + If ret_code <> 0 Then + DisplayError(ret_code, extended_error) + Exit Sub + End If + + MsgBox("The Demo Software Key has been downloaded successfully!", MsgBoxStyle.OKOnly, "Dongle Information") + End Sub + + ' look at the error code and try to display an appropriate message + Private Sub DisplayError(ByVal ret_code As Integer, ByVal extended_error As Integer) + Select Case ret_code + Case 401 + MsgBox("Error! No dongles detected that meet the search criteria", MsgBoxStyle.OkOnly, "Error") + Case 409 + MsgBox("Error! The dongle detected has not been programmed by DinkeyAdd.", MsgBoxStyle.OkOnly, "Error") + Case 758 + MsgBox("Error! Cannot open the Update Code file specified.", MsgBoxStyle.OkOnly, "Error") + Case 759 + MsgBox("Error! The file specified is not a valid Update Code file.", MsgBoxStyle.OkOnly, "Error") + Case 762, 763, 764 + MsgBox("Error! Update Code is not in a correct format / update code file is corrupt.", MsgBoxStyle.OkOnly, "Error") + Case 765 + MsgBox("Error! The Update Code does not match any dongle attached to your machine.", MsgBoxStyle.OkOnly, "Error") + Case 766 + MsgBox("Error! The update number for this Update Code is too high. You need to first enter an update code that was previously sent to you.", MsgBoxStyle.OkOnly, "Error") + Case 767 + MsgBox("Error! You have already entered this Update Code.", MsgBoxStyle.OkOnly, "Error") + Case 1905 + MsgBox("Error! There is no Software Key available for download.", MsgBoxStyle.OkOnly, "Error") + Case 1907 + MsgBox("Error! The Temporary Software Key has expired. Cannot download it.", MsgBoxStyle.OkOnly, "Error") + Case 1910 + MsgBox("Error! The Software Key has already been downloaded.", MsgBoxStyle.OkOnly, "Error") + Case 1921 + MsgBox("Error! You specified the 'default model' but there is more than one model available. You need to specify a specific dongle model.", MsgBoxStyle.OkOnly, "Error") + Case 1922: + MsgBox("Error! The model you requested is not available.", MsgBoxStyle.OkOnly, "Error") + Case 1923: + MsgBox("Error! The Demo Software Key Template has been disabled.", MsgBoxStyle.OkOnly, "Error") + Case 1924: + MsgBox("Error! You have run out of Demo Software Key activations. You need to order some more.", MsgBoxStyle.OkOnly, "Error") + Case Else + MsgBox("An error occurred checking the dongle. Error: " + Str(ret_code) + ". Extended Error: " + Str(extended_error) + ".", MsgBoxStyle.OkOnly, "Error") + End Select + End Sub + +End Class diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyChange/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyChange/README.txt new file mode 100644 index 0000000..9ccdf8f --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyChange/README.txt @@ -0,0 +1,61 @@ +ChangeTest - sample code to call DinkeyChange.dll (DinkeyChange64.dll) in VB.NET +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 2003 but will work in more recent versions of +Visual Studio (they will upgrade the Project to the latest version. If prompted you +should also upgrade the .NET framework the project requires). + +For users of Visual Studio 2005 or higher, the default setting to projects is to compile +for the Target Platform "Any". This means that on 32-bit Windows, your code will run as +32-bit code (and needs to call DinkeyChange.dll) and under 64-bit Windows your code will +run as 64-bit code (and needs to call DinkeyChange64.dll). The sample code works this out +automatically. If you select the target platform as "x86" then it will always be 32-bit +and so you only need to use DinkeyChange.dll. If you select "x64" then your code will be +64-bit and you only need to use DinkeyChange64.dll. + +The main source files in the project are: + +DinkeyChange.vb - the source file contains declarations of our API. We automatically + work out whether your code is running in 32-bit or 64-bit and load the + appropriate DinkeyChange module. + +Form1.vb - this is the sample code giving an example on how you can call our API. + It contains 7 functions. Just use which ever functions are most appropriate + and customise in your own way. + +The best approach is to compile the sample code and see how it works and then to take the +appropriate code and apply it to your own project. You should include the DinkeyChange.vb +file in your project and use/modify which ever functions from Form1.vb you feel are +appropriate. The DinkeyChange.vb file should not be modified. + +The sample code is just a guide. As none of the parameters are security sensitive then +there is no need to implement strong security in calling DinkeyChange. + +Make sure you remember to do the following when creating your own project: + +1) Insert the DinkeyChange.vb file in your project. + +2) You need to put DinkeyChange.dll and/or DinkeyChange64.dll into the folder that +contains your EXE file. Otherwise the message "Unable to open DLL (DinkeyChange.dll)" or +the System.DllNotFoundException error will appear when you run ChangeTest. + +You can rename DinkeyChange.dll (DinkeyChange64.dll) to a name of your choice. In this +case you will need to modify the dll name in the DinkeyChange.vb file. + +Notes on Debugging 64-bit Code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +When you use the 64-bit module (DinkeyChange64.dll) the anti-debug code is so strong that +if you are debugging your code, after calling our API then it will crash with an SEH +exception. If you want to be able to debug your code then you can setup your project so +that your code calls the debug module (DinkeyChange64Debug.dll) in your "debug" build and +the standard module (DinkeyChange64.dll) in your release build. In this case you will +need to modify the declarations of our API in DinkeyChange.vb. This is an example for +DCDoUpdateCodeFromFile64: + +#if DEBUG ' debug module + Declare Ansi Function DCDoUpdateCodeFromFile64 Lib "DinkeyChange64Debug.dll" Alias "DCDoUpdateCodeFromFile" _ + (ByVal filename As String, ByRef confirmation_code As Integer, ByRef extended_error As Integer) As Integer +#else ' standard module + Declare Ansi Function DCDoUpdateCodeFromFile64 Lib "DinkeyChange64.dll" Alias "DCDoUpdateCodeFromFile" _ + (ByVal filename As String, ByRef confirmation_code As Integer, ByRef extended_error As Integer) As Integer +#endif diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyRemote/AssemblyInfo.vb b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyRemote/AssemblyInfo.vb new file mode 100644 index 0000000..28d946b --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyRemote/AssemblyInfo.vb @@ -0,0 +1,31 @@ +Imports System.Reflection +Imports System.Runtime.InteropServices + +' General Information about an assembly is controlled through the following +' set of attributes. Change these attribute values to modify the information +' associated with an assembly. + +' Review the values of the assembly attributes + + + + + + + + + +'The following GUID is for the ID of the typelib if this project is exposed to COM + + +' Version information for an assembly consists of the following four values: +' +' Major Version +' Minor Version +' Build Number +' Revision +' +' You can specify all the values or you can default the Build and Revision Numbers +' by using the '*' as shown below: + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyRemote/Form1.resx b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyRemote/Form1.resx new file mode 100644 index 0000000..ed1cd0f --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyRemote/Form1.resx @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Assembly + + + Form1 + + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyRemote/Form1.vb b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyRemote/Form1.vb new file mode 100644 index 0000000..a479e8e --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyRemote/Form1.vb @@ -0,0 +1,179 @@ +' !! We strongly recommend that you read the "readme.txt" file in the sample code folder. +' !! It contains important instructions on how to use the sample code + +Imports System.Runtime.InteropServices ' so we can marshal our structures in drpf.vb + + +Public Class Form1 + Inherits System.Windows.Forms.Form + + Public Const AppName As String = "drpfTest" + +#Region " Windows Form Designer generated code " + + Public Sub New() + MyBase.New() + + 'This call is required by the Windows Form Designer. + InitializeComponent() + + 'Add any initialization after the InitializeComponent() call + + End Sub + + 'Form overrides dispose to clean up the component list. + Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) + If disposing Then + If Not (components Is Nothing) Then + components.Dispose() + End If + End If + MyBase.Dispose(disposing) + End Sub + + 'Required by the Windows Form Designer + Private components As System.ComponentModel.IContainer + + 'NOTE: The following procedure is required by the Windows Form Designer + 'It can be modified using the Windows Form Designer. + 'Do not modify it using the code editor. + Friend WithEvents updatecodeMod As System.Windows.Forms.Button + Friend WithEvents updatecode As System.Windows.Forms.Button + Friend WithEvents drpfFile As System.Windows.Forms.TextBox + Friend WithEvents label1 As System.Windows.Forms.Label + Private Sub InitializeComponent() + Me.updatecodeMod = New System.Windows.Forms.Button + Me.updatecode = New System.Windows.Forms.Button + Me.drpfFile = New System.Windows.Forms.TextBox + Me.label1 = New System.Windows.Forms.Label + Me.SuspendLayout() + ' + 'updatecodeMod + ' + Me.updatecodeMod.Location = New System.Drawing.Point(88, 128) + Me.updatecodeMod.Name = "updatecodeMod" + Me.updatecodeMod.Size = New System.Drawing.Size(264, 23) + Me.updatecodeMod.TabIndex = 7 + Me.updatecodeMod.Text = "Generate Update Code with modifications " + ' + 'updatecode + ' + Me.updatecode.Location = New System.Drawing.Point(88, 88) + Me.updatecode.Name = "updatecode" + Me.updatecode.Size = New System.Drawing.Size(264, 23) + Me.updatecode.TabIndex = 6 + Me.updatecode.Text = "Generate Update Code" + ' + 'drpfFile + ' + Me.drpfFile.Location = New System.Drawing.Point(8, 40) + Me.drpfFile.Name = "drpfFile" + Me.drpfFile.Size = New System.Drawing.Size(424, 20) + Me.drpfFile.TabIndex = 5 + Me.drpfFile.Text = "" + ' + 'label1 + ' + Me.label1.Location = New System.Drawing.Point(8, 24) + Me.label1.Name = "label1" + Me.label1.Size = New System.Drawing.Size(440, 16) + Me.label1.TabIndex = 4 + Me.label1.Text = "Full path of drpf file:" + ' + 'Form1 + ' + Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13) + Me.ClientSize = New System.Drawing.Size(456, 174) + Me.Controls.Add(Me.updatecodeMod) + Me.Controls.Add(Me.updatecode) + Me.Controls.Add(Me.drpfFile) + Me.Controls.Add(Me.label1) + Me.Name = "Form1" + Me.Text = "Form1" + Me.ResumeLayout(False) + + End Sub + +#End Region + + ' The sample code contains 2 functions. Use which ever functions are most appropriate and customise + ' in your own way. The sample code is just a guide. + ' + ' There are two methods to loading a DRPF file. These are shown in the these two functions + ' updatecode_Click and updatecodeMod_Click: + ' + ' updatecode_Click: we load the DRPF file from disk and get a handle and use it "as is" using the API + ' call LoadDRPFFromFile. You can make some limited changes to overwrite the default + ' behaviour by using API flags. + ' + ' updatecodeMod_Click: we load the DRPF file from disk and load into structures. We can then modify the + ' DRPF settings by modifying this structure. This method uses the API calls + ' ReadDRPFEx and LoadDRPF. + + + Private Sub updatecode_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles updatecode.Click + Dim drpfHandle As IntPtr + Dim err_code As Integer + Dim Outputs As New UPDATE_CODE_OUTPUTS + + ' load DRPF from File into memory + drpfHandle = LoadDRPFFromFile(drpfFile.Text, err_code) + If IntPtr.Zero.Equals(drpfHandle) Then + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, AppName) + Exit Sub + End If + + ' generate update code as specified by the DRPF file + err_code = GenerateUpdateCode(drpfHandle, Convert.ToUInt32(0), 0, Nothing, Nothing, Outputs) + + ' Unload DRPF from memory + UnloadDRPF(drpfHandle) + + ' display message (error or success) + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Information, AppName) + End Sub +#If VBC_VER >= 14 Then + #Disable Warning BC42108, BC42030 'This line is used in Visual Studio 2015 (and newer) to remove warnings in this function +#End If + Private Sub updatecodeMod_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles updatecodeMod.Click + Dim drpfHandle As IntPtr + Dim err_code, dummy1, dummy2 As Integer + Dim MyRemoteInfo As REMOTEINFO + Dim LicenceInfoArray() As LICENCEINFO + Dim AlgChangesArray() As ALGCHANGE + Dim DataChangesArray() As DATACHANGE + Dim Outputs As New UPDATE_CODE_OUTPUTS + + ' in this case we need to read the DRPF into our structures, so that the DRPF values can be modified + err_code = ReadDRPFEx(drpfFile.Text, MyRemoteInfo, LicenceInfoArray, AlgChangesArray, DataChangesArray, dummy1, dummy2) + If err_code <> 0 Then + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, AppName) + Exit Sub + End If + + ' patch new values + LicenceInfoArray(0).FeaturesFlag = 1 ' so that the features value below will be recognised + LicenceInfoArray(0).Features = Convert.ToUInt32(12345) + LicenceInfoArray(0).AddSetExecs = 1 ' so the executions will be added to existing + LicenceInfoArray(0).Execs = 100 + + ' get DRPF handle + drpfHandle = LoadDRPF(MyRemoteInfo, LicenceInfoArray, AlgChangesArray, DataChangesArray, err_code) + If IntPtr.Zero.Equals(drpfHandle) Then + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, AppName) + Exit Sub + End If + + ' generate update code as specified by the modified DRPF file + err_code = GenerateUpdateCode(drpfHandle, Convert.ToUInt32(0), 0, Nothing, Nothing, Outputs) + + ' Unload DRPF from memory + UnloadDRPF(drpfHandle) + + ' display message (error or success) + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Information, AppName) + End Sub +#If VBC_VER >= 14 Then + #Enable Warning BC42108, BC42030 'This line is used in Visual Studio 2015 (and higher) to restore warnings +#End If +End Class diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyRemote/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyRemote/README.txt new file mode 100644 index 0000000..3872cf7 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyRemote/README.txt @@ -0,0 +1,50 @@ +drpfTest - sample code to call DinkeyRemote Modules in VB.NET +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 2002 but will work in more recent +versions of Visual Studio (they will upgrade the Project to the latest version. +If prompted you should also upgrade the .NET framework the project requires). + +For users of Visual Studio 2005 or higher, the default setting to projects is to +compile for the Target Platform "Any". This means that on 32-bit Windows, your +code will run as 32-bit code (and needs to call DinkeyRemote32.dll) and under 64-bit +Windows your code will run as 64-bit code (and needs to call DinkeyRemote64.dll). +The sample code works this out automatically. If you select the target platform as "x86" +then it will always be 32-bit and so you only need to use DinkeyRemote32.dll. If you +select "x64" then your code will be 64-bit and you only need to use DinkeyRemote64.dll. + +The main source files in the project are: + +drpf.vb - the source file contains declarations of our API. We automatically + work out whether your code is running in 32-bit or 64-bit and load + the appropriate DinkeyRemote module. + +Form1.vb - this is the sample code giving an example on how you can call our API. + It contains 2 functions. Just use the function most appropriate for you + and customise in your own way. + +The best approach is to compile the sample code and see how it works and then to take +the appropriate code and apply it to your own project. You should include the drpf.vb +file in your project and use/modify which ever functions from Form1.vb you feel are +appropriate. The drpf.vb file should not be modified. + +The sample code is just a guide. As none of the parameters are security sensitive then +there is no need to implement strong security in calling DinkeyRemote. + +Make sure you remember to do the following when creating your own project: + +1) Insert the following namespaces in your code file: +using System.Runtime.InteropServices; + +2) Insert the drpf.cs file in your project. + +3) You need to put DinkeyRemote32.dll and/or DinkeyRemote64.dll into the folder that +contains drpfTest. Otherwise the message "Unable to open DLL (DinkeyRemote32.dll)" or +the System.DllNotFoundException error will appear when you run drpfTest. + +Notes on Debugging 64-bit Code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +When you use the 64-bit module (DinkeyRemote64.dll) the anti-debug code is so strong +that if you are debugging your code, after calling our API then it will crash with +an SEH exception. There are no debug modules for DinkeyRemote so you will have to +find other ways of debugging your code (for example taking out the call altogether). diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyRemote/drpf.vb b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyRemote/drpf.vb new file mode 100644 index 0000000..be6befd --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyRemote/drpf.vb @@ -0,0 +1,321 @@ +' !! this file should not be modified + +' DRPF file is in the following format: +' REMOTEINFO +' LICENCEINFO (however many are needed) +' ALGCHANGE (however many are needed) +' DATACHANGE blocks (however many are needed) - may refer to external files. + +' Remember: you only need to specify a value if you want to change it. Otherwise you +' specify the default "no change" setting. For most entries this is indicated by 0. +' However, for MaxNetUsers and LicenceNetUsers it is "-2" because 0 is a valid value to change to. + +Imports System +Imports System.Runtime.InteropServices ' so we can marshal our structures as a block of memory +Imports System.Text ' for StringBuilder + +' *********** define structures that make up the DRPF file ******************* + +Module drpf_code + + _ + Structure REMOTEINFO + Dim Header1 As Byte ' Should be set to "DRPF" = DinkeyRemote Parameter File + Dim Header2 As Byte + Dim Header3 As Byte + Dim Header4 As Byte + Dim Version As Integer ' version of this structure - currently 2 + _ + Dim ProdCode As String ' Product Code + Dim DongleNumber As UInt32 + Dim UpdateNumber As Integer + _ + Dim Notes As String ' user-defined notes + Dim NumLicences As Integer + Dim NumAlgs As Integer ' number of algs to set (incl r/w alg) + Dim NumDataChanges As Integer ' number of data change blocks specified + Dim DataAreaSize As Integer ' -1 = increase as necessary. specifies the new size of the data area + Dim PerLicence As Integer ' 0 = no change, 1 = per licence net users, 2 = per product net users + Dim MaxNetUsers As Integer ' product net users, unlimited = -1, no change = -2 + Dim LastUsedDay As Integer ' Day = 0 (only) -> no change + Dim LastUsedMonth As Integer + Dim LastUsedYear As Integer + _ + Dim DataEncKeyProdCode As String + Dim ChangeCodeType As Integer ' 0 = no change, bit0 = only accept secure codes, bit1 = accept secure & short codes + Dim CodeType As Integer ' type of code to generate. 0 = secure code, 1 = short code + _ + Dim OutputFileName As String ' name of file to output code to. Null (default) -> UpdateCode.ducf + Dim LockDongle As Integer ' 1 = lock dongle to user's computer + Dim ResetDongleLock As Integer ' 1 = reset the dongle lock so that the dongle can be locked to a new machine + End Structure + + _ + Structure LICENCEINFO + _ + Dim LicenceName As String ' licence name + Dim Action As Integer ' 0 = change, 1 = delete, 2 = add + Dim AddSetExecs As Integer ' 0 = no change to execs, 1 = add, 2 = set + Dim Execs As Integer ' -1 = no limit + Dim ExecsWarn As Integer ' 0 = remove warning, -1 = no change + Dim ExpiryDay As Integer ' -1 = no limit, 0 = no change + Dim ExpiryMonth As Integer + Dim ExpiryYear As Integer + Dim AddSetMaxDays As Integer ' 0 = no change, 1 = add, 2 = set + Dim MaxDays As Integer ' -1 = no limit + Dim DaysWarn As Integer ' 0 = remove warning, -1 = no change + Dim FeaturesFlag As Integer ' 0 = don't change features, 1 = change features + Dim Features As UInt32 ' all values OK + Dim LicenceNetUsers As Integer ' unlimited = -1, no change = -2 + End Structure + + _ + Structure ALGCHANGE + Dim alg_number As Integer ' number of algorithm to set (0 = r/w algorithm) + _ + Dim alg As Byte() ' coded form of algorithm + End Structure + + _ + Structure DATACHANGE + Dim type As Integer ' 1 = file, 2 = hex data, 3 = ascii, 4 = ascii null-term string + Dim offset As Integer ' offset in dongle data memory to write data + Dim length As Integer ' length of data to change + _ + Dim data As Byte() ' data to write OR name of data file depending on which method set + End Structure + + _ + Structure UPDATE_CODE_OUTPUTS + _ + Dim ShortCode As String ' the update code (for short update codes only) + _ + Dim UpdateCodeFile As String ' the output ducf that contains the update code + _ + Dim ConfirmationCode As String ' the confirmation code + End Structure + +' ********************** DinkeyRemote Module Imports ************************ + + ' Loads DRPF from disk and returns handle + Declare Ansi Function LoadDRPFFromFile32 Lib "DinkeyRemote32.dll" Alias "LoadDRPFFromFile" (ByVal drpf_file As String, ByRef err_code As Integer) As IntPtr + Declare Ansi Function LoadDRPFFromFile64 Lib "DinkeyRemote64.dll" Alias "LoadDRPFFromFile" (ByVal drpf_file As String, ByRef err_code As Integer) As IntPtr + + ' Loads DRPF from disk into structures supplied (so we can modify DRPF in memory) + Declare Ansi Function ReadDRPFEx32 Lib "DinkeyRemote32.dll" Alias "ReadDRPFEx" (ByVal drpf_file As String, ByRef MyRemoteInfo As REMOTEINFO, ByVal licence_bytes() As Byte, _ + ByVal algchange_bytes() As Byte, ByVal datachange_bytes() As Byte, ByRef drpf_version As Integer, ByRef drpf_format As Integer) As Integer + Declare Ansi Function ReadDRPFEx64 Lib "DinkeyRemote64.dll" Alias "ReadDRPFEx" (ByVal drpf_file As String, ByRef MyRemoteInfo As REMOTEINFO, ByVal licence_bytes() As Byte, _ + ByVal algchange_bytes() As Byte, ByVal datachange_bytes() As Byte, ByRef drpf_version As Integer, ByRef drpf_format As Integer) As Integer + + ' Loads DRPF from structures and returns a handle + Declare Ansi Function LoadDRPF32 Lib "DinkeyRemote32.dll" Alias "LoadDRPF" (ByRef MyRemoteInfo As REMOTEINFO, ByVal licence_bytes() As Byte, ByVal algchange_bytes() As Byte, _ + ByVal datachange_bytes() As Byte, ByRef ret_code As Integer) As IntPtr + Declare Ansi Function LoadDRPF64 Lib "DinkeyRemote64.dll" Alias "LoadDRPF" (ByRef MyRemoteInfo As REMOTEINFO, ByVal licence_bytes() As Byte, ByVal algchange_bytes() As Byte, _ + ByVal datachange_bytes() As Byte, ByRef ret_code As Integer) As IntPtr + + ' saves the DRPF file to disk + Declare Ansi Function WriteDRPFEx32 Lib "DinkeyRemote32.dll" Alias "WriteDRPFEx" (ByVal drpf_handle As IntPtr, ByVal drpf_file As String, ByVal drpf_format As Integer, _ + ByVal drpf_version As Integer, ByVal flags As Integer) As Integer + Declare Ansi Function WriteDRPFEx64 Lib "DinkeyRemote64.dll" Alias "WriteDRPFEx" (ByVal drpf_handle As IntPtr, ByVal drpf_file As String, ByVal drpf_format As Integer, _ + ByVal drpf_version As Integer, ByVal flags As Integer) As Integer + + ' unloads the DRPF file + Declare Ansi Sub UnloadDRPF32 Lib "DinkeyRemote32.dll" Alias "UnloadDRPF" (ByRef drpf_handle As IntPtr) + Declare Ansi Sub UnloadDRPF64 Lib "DinkeyRemote64.dll" Alias "UnloadDRPF" (ByRef drpf_handle As IntPtr) + + 'main functions + Declare Ansi Function GenerateUpdateCode32 Lib "DinkeyRemote32.dll" Alias "GenerateUpdateCode" (ByVal drpf_handle As IntPtr, ByVal dongle_number As UInt32, _ + ByVal update_number As Integer, ByVal ducf_file As String, ByVal logfile As String, ByRef Outputs As UPDATE_CODE_OUTPUTS) As Integer + Declare Ansi Function GenerateUpdateCode64 Lib "DinkeyRemote64.dll" Alias "GenerateUpdateCode" (ByVal drpf_handle As IntPtr, ByVal dongle_number As UInt32, _ + ByVal update_number As Integer, ByVal ducf_file As String, ByVal logfile As String, ByRef Outputs As UPDATE_CODE_OUTPUTS) As Integer + + ' get the message output by DinkeyRemote + Declare Ansi Sub GetLastMessage32 Lib "DinkeyRemote32.dll" Alias "GetLastMessage" (ByVal message As StringBuilder, ByVal buffer_size As Integer, ByRef message_length As Integer) + Declare Ansi Sub GetLastMessage64 Lib "DinkeyRemote64.dll" Alias "GetLastMessage" (ByVal message As StringBuilder, ByVal buffer_size As Integer, ByRef message_length As Integer) + + ' get the extended error (set if an error occurs) + Declare Ansi Function GetLastExtendedError32 Lib "DinkeyRemote32.dll" Alias "GetLastExtendedError" () As Integer + Declare Ansi Function GetLastExtendedError64 Lib "DinkeyRemote64.dll" Alias "GetLastExtendedError" () As Integer + + ' ********************** Constants ************************ + Public Const DRPF_VERSION As Integer = 2 ' current DRPF version + + ' WriteDRPFEx API flags + Public Const FLAGS_LOSE_FEATURES As Integer = 1 ' means that you can save the DRPF file to an earlier version even if it means losing some new features that have been currently set + + ' constants for drpf_format in ReadDRPFEx and WriteDRPFEx functions + Public Const DRPF_FORMAT_BINARY As Integer = 1 + Public Const DRPF_FORMAT_JSON As Integer = 2 + Public Const DRPF_FORMAT_JSON_MIN As Integer = 3 ' this value is only used with WriteDRPEx. ReadDRPFEx cannot return this value. + + ' private constants + Private const MAX_LICENCES As Integer = 255 ' max number of licence changes in a DRPF file (theoretically unlimited but easier if we limit it) + Private Const MAX_ALG_CHANGES As Integer = 21 ' max number of alg changes in DRPF file + Private Const MAX_DATA_CHANGES As Integer = 127 ' max number of data area changes in DRPF file + + ' ********************** API Functions ************************ + ' We only want to load the correct DLL for the bit-ness of the computer. The other DLL may not exist. + ' if the appropriate DLL does not exist in the same directory as this test program you will receive a DllNotFoundException + + ' call the correct dll depending on whether we are running 32-bit or 64-bit code + Function LoadDRPFFromFile(ByVal drpf_file As String, ByRef err_code As Integer) As IntPtr + If (IntPtr.Size = 4) Then + LoadDRPFFromFile = LoadDRPFFromFile32(drpf_file, err_code) + Else + LoadDRPFFromFile = LoadDRPFFromFile64(drpf_file, err_code) + End If + End Function + + ' we have to do some marshalling of arrays of bytes into arrays of structures + Function ReadDRPFEx(ByVal drpf_file As String, ByRef MyRemoteInfo As REMOTEINFO, ByRef LicenceInfoArray() As LICENCEINFO, ByRef AlgChangesArray() As ALGCHANGE, _ + ByRef DataChangesArray() As DATACHANGE, ByRef drpf_version As Integer, ByRef drpf_format As Integer) As Integer + Dim i As Integer + Dim MyLicenceInfo As New LICENCEINFO + Dim licence_bytes(MAX_LICENCES * Marshal.SizeOf(MyLicenceInfo)) As Byte + Dim licence_bytes_one_struct(Marshal.SizeOf(MyLicenceInfo)) As Byte + Dim MyAlgChanges As New ALGCHANGE + Dim algchange_bytes(MAX_ALG_CHANGES * Marshal.SizeOf(MyAlgChanges)) As Byte + Dim algchange_bytes_one_struct(Marshal.SizeOf(MyAlgChanges)) As Byte + Dim MyDataChanges As New DATACHANGE + Dim datachange_bytes(MAX_DATA_CHANGES * Marshal.SizeOf(MyDataChanges)) As Byte + Dim datachange_bytes_one_struct(Marshal.SizeOf(MyDataChanges)) As Byte + Dim MyGC As GCHandle + MyRemoteInfo = New REMOTEINFO + + If (IntPtr.Size = 4) Then + ReadDRPFEx = ReadDRPFEx32(drpf_file, MyRemoteInfo, licence_bytes, algchange_bytes, datachange_bytes, drpf_version, drpf_format) + Else + ReadDRPFEx = ReadDRPFEx64(drpf_file, MyRemoteInfo, licence_bytes, algchange_bytes, datachange_bytes, drpf_version, drpf_format) + End If + + If ReadDRPFEx <> 0 Then + Exit Function + End If + + ' convert byte array to an array of structs + ReDim LicenceInfoArray(MyRemoteInfo.NumLicences) + For i = 0 To MyRemoteInfo.NumLicences - 1 + LicenceInfoArray(i) = New LICENCEINFO + Array.Copy(licence_bytes, i * Marshal.SizeOf(MyLicenceInfo.GetType), licence_bytes_one_struct, 0, Marshal.SizeOf(MyLicenceInfo.GetType)) + MyGC = GCHandle.Alloc(licence_bytes_one_struct, GCHandleType.Pinned) + LicenceInfoArray(i) = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, MyLicenceInfo.GetType) + MyGC.Free() + Next + + ReDim AlgChangesArray(MyRemoteInfo.NumAlgs) + For i = 0 To MyRemoteInfo.NumAlgs - 1 + AlgChangesArray(i) = New ALGCHANGE + Array.Copy(algchange_bytes, i * Marshal.SizeOf(MyAlgChanges.GetType), algchange_bytes_one_struct, 0, Marshal.SizeOf(MyAlgChanges.GetType)) + MyGC = GCHandle.Alloc(algchange_bytes_one_struct, GCHandleType.Pinned) + AlgChangesArray(i) = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, MyAlgChanges.GetType) + MyGC.Free() + Next + + ReDim DataChangesArray(MyRemoteInfo.NumDataChanges) + For i = 0 To MyRemoteInfo.NumDataChanges - 1 + DataChangesArray(i) = New DATACHANGE + Array.Copy(datachange_bytes, i * Marshal.SizeOf(MyDataChanges.GetType), datachange_bytes_one_struct, 0, Marshal.SizeOf(MyDataChanges.GetType)) + MyGC = GCHandle.Alloc(datachange_bytes_one_struct, GCHandleType.Pinned) + DataChangesArray(i) = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, MyDataChanges.GetType) + MyGC.Free() + Next + + End Function + + Function LoadDRPF(ByRef MyRemoteInfo As REMOTEINFO, ByRef LicenceInfoArray() As LICENCEINFO, ByRef AlgChangesArray() As ALGCHANGE, ByRef DataChangesArray() As DATACHANGE, _ + ByRef ret_code As Integer) As IntPtr + Dim i As Integer + Dim MyLicenceInfo As New LICENCEINFO + Dim licence_bytes(MAX_LICENCES * Marshal.SizeOf(MyLicenceInfo)) As Byte + Dim licence_bytes_one_struct(Marshal.SizeOf(MyLicenceInfo)) As Byte + Dim MyAlgChanges As New ALGCHANGE + Dim algchange_bytes(MAX_ALG_CHANGES * Marshal.SizeOf(MyAlgChanges)) As Byte + Dim algchange_bytes_one_struct(Marshal.SizeOf(MyAlgChanges)) As Byte + Dim MyDataChanges As New DATACHANGE + Dim datachange_bytes(MAX_DATA_CHANGES * Marshal.SizeOf(MyDataChanges)) As Byte + Dim datachange_bytes_one_struct(Marshal.SizeOf(MyDataChanges)) As Byte + Dim MyGC As GCHandle + + ' convert array of structs to byte arrays + For i = 0 To MyRemoteInfo.NumLicences - 1 + MyGC = GCHandle.Alloc(licence_bytes_one_struct, GCHandleType.Pinned) + Marshal.StructureToPtr(LicenceInfoArray(i), MyGC.AddrOfPinnedObject, False) + MyGC.Free() + Array.Copy(licence_bytes_one_struct, 0, licence_bytes, i * Marshal.SizeOf(MyLicenceInfo.GetType), Marshal.SizeOf(MyLicenceInfo.GetType)) + Next + + For i = 0 To MyRemoteInfo.NumAlgs - 1 + MyGC = GCHandle.Alloc(algchange_bytes_one_struct, GCHandleType.Pinned) + Marshal.StructureToPtr(AlgChangesArray(i), MyGC.AddrOfPinnedObject, False) + MyGC.Free() + Array.Copy(algchange_bytes_one_struct, 0, algchange_bytes, i * Marshal.SizeOf(MyAlgChanges.GetType), Marshal.SizeOf(MyAlgChanges.GetType)) + Next + + For i = 0 To MyRemoteInfo.NumDataChanges - 1 + MyGC = GCHandle.Alloc(datachange_bytes_one_struct, GCHandleType.Pinned) + Marshal.StructureToPtr(DataChangesArray(i), MyGC.AddrOfPinnedObject, False) + MyGC.Free() + Array.Copy(datachange_bytes_one_struct, 0, datachange_bytes, i * Marshal.SizeOf(MyDataChanges.GetType), Marshal.SizeOf(MyDataChanges.GetType)) + Next + + If (IntPtr.Size = 4) Then + LoadDRPF = LoadDRPF32(MyRemoteInfo, licence_bytes, algchange_bytes, datachange_bytes, ret_code) + Else + LoadDRPF = LoadDRPF64(MyRemoteInfo, licence_bytes, algchange_bytes, datachange_bytes, ret_code) + End If + + End Function + + Function WriteDRPFEx(ByVal drpf_handle As IntPtr, ByVal drpf_file As String, ByVal drpf_format As Integer, ByVal drpf_version As Integer, ByVal flags As Integer) As Integer + If (IntPtr.Size = 4) Then + WriteDRPFEx = WriteDRPFEx32(drpf_handle, drpf_file, drpf_format, drpf_version, flags) + Else + WriteDRPFEx = WriteDRPFEx64(drpf_handle, drpf_file, drpf_format, drpf_version, flags) + End If + End Function + + Sub UnloadDRPF(ByRef drpf_handle As IntPtr) + If (IntPtr.Size = 4) Then + UnloadDRPF32(drpf_handle) + Else + UnloadDRPF64(drpf_handle) + End If + End Sub + + Function GenerateUpdateCode(ByVal drpf_handle As IntPtr, ByVal dongle_number As UInt32, ByVal update_number As Integer, ByVal ducf_file As String, _ + ByVal logfile As String, ByRef Outputs As UPDATE_CODE_OUTPUTS) As Integer + If (IntPtr.Size = 4) Then + GenerateUpdateCode = GenerateUpdateCode32(drpf_handle, dongle_number, update_number, ducf_file, logfile, Outputs) + Else + GenerateUpdateCode = GenerateUpdateCode64(drpf_handle, dongle_number, update_number, ducf_file, logfile, Outputs) + End If + End Function + + ' do a bit of work here to make the function easier to use for VB.NET + Function GetLastMessage() As String + Dim length, dummy As Integer + Dim message As StringBuilder + + If (IntPtr.Size = 4) Then + GetLastMessage32(Nothing, 0, length) + message = New StringBuilder(length) + GetLastMessage32(message, length, dummy) + Else + GetLastMessage64(Nothing, 0, length) + message = New StringBuilder(length) + GetLastMessage64(message, length, dummy) + End If + + Return message.ToString() + End Function + + Function GetLastExtendedError() As Integer + If (IntPtr.Size = 4) Then + GetLastExtendedError = GetLastExtendedError32() + Else + GetLastExtendedError = GetLastExtendedError64() + End If + End Function + + +End Module diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyRemote/drpfTest.sln b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyRemote/drpfTest.sln new file mode 100644 index 0000000..4c7c9af --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyRemote/drpfTest.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "drpfTest", "drpfTest.vbproj", "{35F04638-E647-4D07-A165-876D21B435B1}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {35F04638-E647-4D07-A165-876D21B435B1}.Debug.ActiveCfg = Debug|.NET + {35F04638-E647-4D07-A165-876D21B435B1}.Debug.Build.0 = Debug|.NET + {35F04638-E647-4D07-A165-876D21B435B1}.Release.ActiveCfg = Release|.NET + {35F04638-E647-4D07-A165-876D21B435B1}.Release.Build.0 = Release|.NET + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyRemote/drpfTest.vbproj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyRemote/drpfTest.vbproj new file mode 100644 index 0000000..31aafaf --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/DinkeyRemote/drpfTest.vbproj @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/AssemblyInfo.vb b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/AssemblyInfo.vb new file mode 100644 index 0000000..9315c48 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/AssemblyInfo.vb @@ -0,0 +1,31 @@ +Imports System.Reflection +Imports System.Runtime.InteropServices + +' General Information about an assembly is controlled through the following +' set of attributes. Change these attribute values to modify the information +' associated with an assembly. + +' Review the values of the assembly attributes + + + + + + + + + +'The following GUID is for the ID of the typelib if this project is exposed to COM + + +' Version information for an assembly consists of the following four values: +' +' Major Version +' Minor Version +' Build Number +' Revision +' +' You can specify all the values or you can default the Build and Revision Numbers +' by using the '*' as shown below: + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/DllTest.sln b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/DllTest.sln new file mode 100644 index 0000000..f0f93c0 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/DllTest.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "DllTest", "DllTest.vbproj", "{7C92E3C8-2E6D-4347-B8B3-579231D8E24D}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {7C92E3C8-2E6D-4347-B8B3-579231D8E24D}.Debug.ActiveCfg = Debug|.NET + {7C92E3C8-2E6D-4347-B8B3-579231D8E24D}.Debug.Build.0 = Debug|.NET + {7C92E3C8-2E6D-4347-B8B3-579231D8E24D}.Release.ActiveCfg = Release|.NET + {7C92E3C8-2E6D-4347-B8B3-579231D8E24D}.Release.Build.0 = Release|.NET + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/DllTest.vbproj b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/DllTest.vbproj new file mode 100644 index 0000000..4da9a7f --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/DllTest.vbproj @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/Form1.resx b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/Form1.resx new file mode 100644 index 0000000..ed1cd0f --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/Form1.resx @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Assembly + + + Form1 + + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/Form1.vb b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/Form1.vb new file mode 100644 index 0000000..49f69d2 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/Form1.vb @@ -0,0 +1,988 @@ +' !! We strongly recommend that you read the "readme.txt" file in the sample code folder. +' !! It contains important instructions on how to use the sample code + +Imports System.Runtime.InteropServices + +Public Class Form1 + Inherits System.Windows.Forms.Form + +#Region " Windows Form Designer generated code " + + Public Sub New() + MyBase.New() + + 'This call is required by the Windows Form Designer. + InitializeComponent() + + 'Add any initialization after the InitializeComponent() call + + End Sub + + 'Form overrides dispose to clean up the component list. + Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) + If disposing Then + If Not (components Is Nothing) Then + components.Dispose() + End If + End If + MyBase.Dispose(disposing) + End Sub + + 'Required by the Windows Form Designer + Private components As System.ComponentModel.IContainer + + 'NOTE: The following procedure is required by the Windows Form Designer + 'It can be modified using the Windows Form Designer. + 'Do not modify it using the code editor. + Friend WithEvents Label1 As System.Windows.Forms.Label + Private Sub InitializeComponent() + Me.Label1 = New System.Windows.Forms.Label() + Me.SuspendLayout() + ' + 'Label1 + ' + Me.Label1.Font = New System.Drawing.Font("Microsoft Sans Serif", 24.0!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte)) + Me.Label1.Location = New System.Drawing.Point(72, 80) + Me.Label1.Name = "Label1" + Me.Label1.Size = New System.Drawing.Size(168, 40) + Me.Label1.TabIndex = 0 + Me.Label1.Text = "It Worked!" + ' + 'Form1 + ' + Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13) + Me.ClientSize = New System.Drawing.Size(304, 213) + Me.Controls.AddRange(New System.Windows.Forms.Control() {Me.Label1}) + Me.Name = "Form1" + Me.Text = "Form1" + Me.ResumeLayout(False) + + End Sub + +#End Region + + ' The sample code contains 11 functions. You will not need to use all these + ' functions in your code. Just use which ever functions are most appropriate + ' and customise in your own way. The sample code is just a guide. You should + ' implement the protection in a stronger way using the techniques described in + ' the "Increasing your Protection" chapter of the manual. + ' + ' The 11 functions are: + ' ProtCheck a standard protection check + ' ProtCheckWithAlg a protection check & executing an Algorithm + ' WriteBytes a protection check & write data to the dongle + ' ReadBytes a protection check & read data from the dongle + ' EncryptUserData a protection check,& encrypting data and then decrypting the data + ' + ' these functions are the same as the functions listed above but encrypting all parameters passed to our API + ' ProtCheckEnc a standard protection check + ' ProtCheckWithAlgEnc a protection check & executing an Algorithm + ' WriteBytesEnc a protection check & write data to the dongle + ' ReadBytesEnc a protection check & read data from the dongle + ' EncryptUserDataEnc a protection check & encrypting data and then decrypting the data + + ' this function displays the current network users + ' DisplayNetUsers + + ' !!!! + Public Const MY_SDSN As Integer = 10101 ' !!!! change this value to be the value of your SDSN (demo = 10101) + Public Const MY_PRODCODE As String = "DEMO" ' !!!! change this value to match the Product Code in the dongle + + ' If you are using Dinkey Lite then you can only use 4 functions: + ' ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + + Private Sub Form1_Load(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles MyBase.Load + + ' call the function(s) of your choice here + ' here I have chosen a standard protection check + If ProtCheck() <> 0 Then + End 'terminate + End If + + End Sub + + ' ************************* our 10 functions ********************************** + + ' ************************** ProtCheck *************************************** + Function ProtCheck() As Integer + Dim dris As DRIS = New DRIS + Dim ret_code As Integer + On Error GoTo Protection_Err + + ' set the DRIS to have random values + Call RandomSet(dris) + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = PROTECTION_CHECK ' standard protection check + dris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + ret_code = DDProtCheck(dris, Nothing) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + ProtCheck = ret_code + Exit Function + End If + + ' later in your code you can check other values in the DRIS... + If (dris.sdsn <> MY_SDSN) Then + MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error") + ProtCheck = -1 + Exit Function + End If + + If (GetProductCode(dris) <> MY_PRODCODE) Then + MsgBox("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", MsgBoxStyle.OkOnly, "Error") + ProtCheck = -1 + Exit Function + End If + + ' later on in your program you can check the return code again + If (dris.ret_code <> 0) Then + MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error") + ProtCheck = -1 + Exit Function + End If + + + ' NB if you are using a network dongle and you want to list the network users then use this function: + ' DisplayNetUsers(dris.net_users, dris.model) + + ProtCheck = 0 + Exit Function + +Protection_Err: ' see readme.txt for explanation of this exception handler + Protection_Exception() + ProtCheck = -1 + End Function + + + ' ************************** ProtCheckWithAlg ****************************** + + ' !!!! You should replace this function with the one generated by the + ' "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) + ' or from DinkeyLook if you are using Dinkey Lite dongles. + ' see readme.txt notes concerning using the algorithm in vb.net + Private Function MyAlgorithm(ByVal a As Integer, ByVal b As Integer, ByVal c As Integer, ByVal d As Integer, ByVal e As Integer, ByVal f As Integer, ByVal g As Integer, ByVal h As Integer) As Integer + MyAlgorithm = a + b + c + d + e + f + g + h + End Function + + ' NB for this to work you must program at least "user algorithm" into the dongle + ' NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + ' sample code generated by DinkeyAdd for the algorithm that you are using. + Function ProtCheckWithAlg() As Integer + Dim dris As DRIS = New DRIS + Dim ret_code As Integer + On Error GoTo Protection_Err + + ' set the DRIS to have random values + Call RandomSet(dris) + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = EXECUTE_ALGORITHM ' standard protection check & execute algorithm + dris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number = 1 ' execute first algorithm (you do not need to specify this field for Dinkey Lite dongles) + ' you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.var_a = 1 ' sample values + dris.var_b = 2 + dris.var_c = 3 + dris.var_d = 4 + dris.var_e = 5 + dris.var_f = 6 + dris.var_g = 7 + dris.var_h = 8 + + ret_code = DDProtCheck(dris, Nothing) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + ProtCheckWithAlg = ret_code + Exit Function + End If + + ' later in your code you can check other values in the DRIS... + If (dris.sdsn <> MY_SDSN) Then + MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error") + ProtCheckWithAlg = -1 + Exit Function + End If + + ' later on in your program you can check the return code again + If (dris.ret_code <> 0) Then + MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error") + ProtCheckWithAlg = -1 + Exit Function + End If + + ' if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + ' NB read the note in the "readme.txt" about possible overflow errors in VB.NET + ' !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + If (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) <> dris.alg_answer) Then + MsgBox("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine", MsgBoxStyle.OkOnly, "Error") + ProtCheckWithAlg = -1 + Exit Function + End If + + ProtCheckWithAlg = 0 + Exit Function +Protection_Err: ' see readme.txt for explanation of this exception handler + Protection_Exception() + ProtCheckWithAlg = -1 + End Function + + ' ************************** WriteBytes ****************************** + ' This writes the data array 0,1,2,3,4,5,6,7,8,9 to the dongle data area at offset 7 + ' In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + ' if you want to write a string then you need to convert it to a byte array first: + ' encoding.GetBytes(your_string, 0, your_string.Length, data, 0) where encoding is declared: Dim encoding As New ASCIIEncoding() You also need to include System.Text + Function WriteBytes() As Integer + Dim dris As DRIS = New DRIS + Dim ret_code As Integer + Dim data() As Byte = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + On Error GoTo Protection_Err + + ' set the DRIS to have random values + Call RandomSet(dris) + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = WRITE_DATA_AREA ' standard protection check & write data + dris.flags = USE_FUNCTION_ARGUMENT ' you have to do it this way in vb.net + dris.rw_offset = 7 + dris.rw_length = data.Length + + ret_code = DDProtCheck(dris, data) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + WriteBytes = ret_code + Exit Function + End If + + ' later in your code you can check other values in the DRIS... + If (dris.sdsn <> MY_SDSN) Then + MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error") + WriteBytes = -1 + Exit Function + End If + + ' later on in your program you can check the return code again + If (dris.ret_code <> 0) Then + MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error") + WriteBytes = -1 + Exit Function + End If + + WriteBytes = 0 + Exit Function +Protection_Err: ' see readme.txt for explanation of this exception handler + Protection_Exception() + WriteBytes = -1 + End Function + + ' ************************ ReadBytes ************************************ + ' This reads 10 bytes of data from offset 7 in the dongle data area + ' In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + ' if you want to read a string then you need to convert it from a byte array (via an array of char). You also need to include System.Text + ' CharArray = encoding.GetChars(data); where CharArray is of type char[] and encoding is of type ASCIIEncoding + ' your_string = new String(CharArray, 0, your_string_length); + Function ReadBytes() As Integer + Dim dris As DRIS = New DRIS + Dim ret_code As Integer + Dim data(10) As Byte + On Error GoTo Protection_Err + + ' set the DRIS to have random values + Call RandomSet(dris) + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = READ_DATA_AREA ' standard protection check & read data + dris.flags = USE_FUNCTION_ARGUMENT ' you have to do it this way in vb.net + dris.rw_offset = 7 + dris.rw_length = data.Length + + ret_code = DDProtCheck(dris, data) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + ReadBytes = ret_code + Exit Function + End If + + ' later in your code you can check other values in the DRIS... + If (dris.sdsn <> MY_SDSN) Then + MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error") + ReadBytes = -1 + Exit Function + End If + + ' later on in your program you can check the return code again + If (dris.ret_code <> 0) Then + MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error") + ReadBytes = -1 + Exit Function + End If + + MsgBox("Dinkey Dongle Data Area, offset 7 is : " + Str(data(0)) + "," + Str(data(1)) + "," + Str(data(2)) + "," + Str(data(3)) + "," + _ + Str(data(4)) + "," + Str(data(5)) + "," + Str(data(6)) + "," + Str(data(7)) + "," + Str(data(8)) + "," + Str(data(9)), MsgBoxStyle.OkOnly) + ReadBytes = 0 + Exit Function +Protection_Err: ' see readme.txt for explanation of this exception handler + Protection_Exception() + ReadBytes = -1 + End Function + + ' ************************** EncryptUserData ************************************ + ' This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 + ' It will then do another protection check & decrypt the data + ' to encrypt or decrypt strings please read notes for WriteBytes and ReadBytes functions + Function EncryptUserData() As Integer + Dim dris As DRIS = New DRIS + Dim ret_code As Integer + Dim data() As Byte = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + On Error GoTo Protection_Err + + ' set the DRIS to have random values + Call RandomSet(dris) + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = ENCRYPT_USER_DATA ' standard protection check & encrypt data + dris.flags = USE_FUNCTION_ARGUMENT ' you have to do it this way in vb.net + dris.rw_length = data.Length + dris.data_crypt_key_num = 1 + + ret_code = DDProtCheck(dris, data) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + EncryptUserData = ret_code + Exit Function + End If + + ' ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + ' Now decrypt the same data to get the original values + Call RandomSet(dris) + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = DECRYPT_USER_DATA ' standard protection check & decrypt data + dris.flags = USE_FUNCTION_ARGUMENT ' you have to do it this way in vb.net + dris.rw_length = data.Length + dris.data_crypt_key_num = 1 + + ret_code = DDProtCheck(dris, data) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + EncryptUserData = ret_code + Exit Function + End If + + ' later in your code you can check other values in the DRIS... + If (dris.sdsn <> MY_SDSN) Then + MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error") + EncryptUserData = -1 + Exit Function + End If + + ' later on in your program you can check the return code again + If (dris.ret_code <> 0) Then + MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error") + EncryptUserData = -1 + Exit Function + End If + + MsgBox("Decrypted data is : " + Str(data(0)) + "," + Str(data(1)) + "," + Str(data(2)) + "," + Str(data(3)) + "," + _ + Str(data(4)) + "," + Str(data(5)) + "," + Str(data(6)) + "," + Str(data(7)) + "," + Str(data(8)) + "," + Str(data(9)), MsgBoxStyle.OkOnly) + EncryptUserData = 0 + Exit Function +Protection_Err: ' see readme.txt for explanation of this exception handler + Protection_Exception() + EncryptUserData = -1 + End Function + + ' !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! + ' In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" + ' in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm + ' but the code can be modified easily to use the 3 encryption parameters. + + ' !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm + Private Function MyRWAlgorithm(ByVal a As Integer, ByVal b As Integer, ByVal c As Integer, ByVal d As Integer, ByVal e As Integer, ByVal f As Integer, ByVal g As Integer, ByVal h As Integer) As Integer + MyRWAlgorithm = a Xor b Xor c Xor d Xor e Xor f + MyRWAlgorithm = MyRWAlgorithm And &HFFFFFF ' we only use bottom 3 bytes. -ve numbers can cause problems for CryptApiData + End Function + + ' !!!! please overwrite this function with the one generated by DinkeyAdd + Private Sub CryptDRIS(ByRef dris As DRIS) + Dim i, j, k, t As Integer + Dim bigseed(255) As Byte + Dim S(255) As Byte + Dim temp As Byte + Dim temp_dris(Marshal.SizeOf(dris) - 1) As Byte + + DrisToByteArray(dris, temp_dris) ' convert DRIS to byte array so we can encrypt it + + For i = 0 To 255 Step 8 + Call Set4Bytes(bigseed, i, dris.seed1) + Call Set4Bytes(bigseed, i + 4, dris.seed2) + Next + For i = 0 To 255 + S(i) = i + Next + j = 0 + For i = 0 To 255 + j = (j + CInt(S(i)) + CInt(bigseed(i)) + 123) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + Next + i = 0 + j = 0 + For k = 16 To Marshal.SizeOf(dris) - 1 + i = (i + 1) Mod 256 + j = (j + CInt(S(i)) + 212) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + t = (CInt(S(i)) + CInt(S(j)) + 97) Mod 256 + temp_dris(k) = temp_dris(k) Xor S(t) + Next + + ByteArrayToDris(temp_dris, dris) ' convert it back again + End Sub + + + ' !!!! please overwrite this function with the one generated by DinkeyAdd + Private Sub CryptApiData(ByVal dris As DRIS, ByVal data() As Byte, ByVal length As Integer, ByVal alg_answer As Integer) + Dim i, j, k, t As Integer + Dim bigseed(255) As Byte + Dim S(255) As Byte + Dim temp As Byte + + For i = 0 To 255 Step 8 + Call Set4Bytes(bigseed, i, dris.seed1) + Call Set4Bytes(bigseed, i + 4, dris.seed2) + Next + For i = 0 To 255 + S(i) = i + Next + j = 0 + For i = 0 To 255 + j = (j + CInt(S(i)) + CInt(bigseed(i)) + (alg_answer And &HFF)) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + Next + i = 0 + j = 0 + For k = 0 To length - 1 + i = (i + 1) Mod 256 + j = (j + CInt(S(i)) + ((alg_answer \ &H100) And &HFF)) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + t = (CInt(S(i)) + CInt(S(j)) + ((alg_answer \ &H10000) And &HFF)) Mod 256 + data(k) = data(k) Xor S(t) + Next + End Sub + + ' ************************** ProtCheckEnc ************************************ + ' We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. + Function ProtCheckEnc() As Integer + Dim dris As DRIS = New DRIS + Dim ret_code As Integer + On Error GoTo Protection_Err + + ' set the DRIS to have random values + Call RandomSet(dris) + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = PROTECTION_CHECK ' standard protection check + dris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + Call CryptDRIS(dris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(dris, Nothing) + + Call CryptDRIS(dris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + ProtCheckEnc = ret_code + Exit Function + End If + + ' later in your code you can check other values in the DRIS... + If (dris.sdsn <> MY_SDSN) Then + MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error") + ProtCheckEnc = -1 + Exit Function + End If + + If (GetProductCode(dris) <> MY_PRODCODE) Then + MsgBox("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", MsgBoxStyle.OkOnly, "Error") + ProtCheckEnc = -1 + Exit Function + End If + + ' later on in your program you can check the return code again + If (dris.ret_code <> 0) Then + MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error") + ProtCheckEnc = -1 + Exit Function + End If + + ProtCheckEnc = 0 + Exit Function + +Protection_Err: ' see readme.txt for explanation of this exception handler + Protection_Exception() + ProtCheckEnc = -1 + End Function + + + ' ************************** ProtCheckWithAlgEnc **************************** + ' NB for this to work you must program at least "user algorithm" into the dongle + ' NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + ' sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite get source from DinkeyLook. + ' We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. + Function ProtCheckWithAlgEnc() As Integer + Dim dris As DRIS = New DRIS + Dim ret_code As Integer + On Error GoTo Protection_Err + + ' set the DRIS to have random values + Call RandomSet(dris) + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = EXECUTE_ALGORITHM ' standard protection check & execute algorithm + dris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number = 1 ' execute first algorithm (you do not need to specify this field for Dinkey Lite dongles) + ' you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.var_a = 1 ' sample values + dris.var_b = 2 + dris.var_c = 3 + dris.var_d = 4 + dris.var_e = 5 + dris.var_f = 6 + dris.var_g = 7 + dris.var_h = 8 + + Call CryptDRIS(dris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(dris, Nothing) + + Call CryptDRIS(dris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + ProtCheckWithAlgEnc = ret_code + Exit Function + End If + + ' later in your code you can check other values in the DRIS... + If (dris.sdsn <> MY_SDSN) Then + MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error") + ProtCheckWithAlgEnc = -1 + Exit Function + End If + + ' later on in your program you can check the return code again + If (dris.ret_code <> 0) Then + MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error") + ProtCheckWithAlgEnc = -1 + Exit Function + End If + + ' if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + ' !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + If (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) <> dris.alg_answer) Then + MsgBox("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine", MsgBoxStyle.OkOnly, "Error") + ProtCheckWithAlgEnc = -1 + Exit Function + End If + + ProtCheckWithAlgEnc = 0 + Exit Function +Protection_Err: ' see readme.txt for explanation of this exception handler + Protection_Exception() + ProtCheckWithAlgEnc = -1 + End Function + + ' ************************** WriteBytesEnc ****************************** + ' This writes the data array 0,1,2,3,4,5,6,7,8,9 to the dongle data area at offset 7 + ' In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + ' We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + ' to write string data please read notes for WriteBytes + Function WriteBytesEnc() As Integer + Dim dris As DRIS = New DRIS + Dim ret_code, alg_ans As Integer + Dim data() As Byte = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + On Error GoTo Protection_Err + + ' set the DRIS to have random values + Call RandomSet(dris) ' sets DRIS to have random values including seed1, seed2 and var_a..var_h + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = WRITE_DATA_AREA ' standard protection check & write data + dris.flags = USE_FUNCTION_ARGUMENT ' you have to do it this way in vb.net + dris.rw_offset = 7 + dris.rw_length = data.Length + dris.var_a = dris.var_a And &HFFFFFF ' restrict to 24-bit to prevent potential overflow in algorithm + dris.var_b = dris.var_b And &HFFFFFF + dris.var_c = dris.var_c And &HFFFFFF + dris.var_d = dris.var_d And &HFFFFFF + dris.var_e = dris.var_e And &HFFFFFF + dris.var_f = dris.var_f And &HFFFFFF + dris.var_g = dris.var_g And &HFFFFFF + dris.var_h = dris.var_h And &HFFFFFF + + ' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) + + ' encrypt data we want to write. + CryptApiData(dris, data, data.Length, alg_ans) + + Call CryptDRIS(dris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(dris, data) + + Call CryptDRIS(dris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + WriteBytesEnc = ret_code + Exit Function + End If + + ' later in your code you can check other values in the DRIS... + If (dris.sdsn <> MY_SDSN) Then + MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error") + WriteBytesEnc = -1 + Exit Function + End If + + ' later on in your program you can check the return code again + If (dris.ret_code <> 0) Then + MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error") + WriteBytesEnc = -1 + Exit Function + End If + + WriteBytesEnc = 0 + Exit Function +Protection_Err: ' see readme.txt for explanation of this exception handler + Protection_Exception() + WriteBytesEnc = -1 + End Function + + ' ************************ ReadBytesEnc ************************************ + ' This reads 10 bytes of data from offset 7 in the dongle data area + ' In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + ' We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + ' to read string data please notes for ReadBytes function + Function ReadBytesEnc() As Integer + Dim dris As DRIS = New DRIS + Dim ret_code, alg_ans As Integer + Dim data(10) As Byte + On Error GoTo Protection_Err + + ' set the DRIS to have random values + Call RandomSet(dris) ' sets DRIS to have random values including seed1, seed2 and var_a..var_h + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = READ_DATA_AREA ' standard protection check & read data + dris.flags = USE_FUNCTION_ARGUMENT ' you have to do it this way in vb.net + dris.rw_offset = 7 + dris.rw_length = data.Length + dris.var_a = dris.var_a And &HFFFFFF ' restrict to 24-bit to prevent potential overflow in algorithm + dris.var_b = dris.var_b And &HFFFFFF + dris.var_c = dris.var_c And &HFFFFFF + dris.var_d = dris.var_d And &HFFFFFF + dris.var_e = dris.var_e And &HFFFFFF + dris.var_f = dris.var_f And &HFFFFFF + dris.var_g = dris.var_g And &HFFFFFF + dris.var_h = dris.var_h And &HFFFFFF + + ' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) + + Call CryptDRIS(dris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(dris, data) + + Call CryptDRIS(dris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + ReadBytesEnc = ret_code + Exit Function + End If + + ' later in your code you can check other values in the DRIS... + If (dris.sdsn <> MY_SDSN) Then + MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error") + ReadBytesEnc = -1 + Exit Function + End If + + ' later on in your program you can check the return code again + If (dris.ret_code <> 0) Then + MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error") + ReadBytesEnc = -1 + Exit Function + End If + + ' decrypt data just read. + CryptApiData(dris, data, data.Length, alg_ans) + MsgBox("Dinkey Dongle Data Area, offset 7 is : " + Str(data(0)) + "," + Str(data(1)) + "," + Str(data(2)) + "," + Str(data(3)) + "," + _ + Str(data(4)) + "," + Str(data(5)) + "," + Str(data(6)) + "," + Str(data(7)) + "," + Str(data(8)) + "," + Str(data(9)), MsgBoxStyle.OkOnly) + ReadBytesEnc = 0 + Exit Function +Protection_Err: ' see readme.txt for explanation of this exception handler + Protection_Exception() + ReadBytesEnc = -1 + End Function + + ' ************************** EncryptUserDataEnc ********************************* + ' This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 + ' It will then do another protection check & decrypt the data + ' We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + ' to encrypt or decrypt strings please read notes for WriteBytes and ReadBytes functions + Function EncryptUserDataEnc() As Integer + Dim dris As DRIS = New DRIS + Dim ret_code, alg_ans As Integer + Dim data() As Byte = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + On Error GoTo Protection_Err + + ' set the DRIS to have random values + Call RandomSet(dris) ' sets DRIS to have random values including seed1, seed2 and var_a..var_h + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = ENCRYPT_USER_DATA ' standard protection check & encrypt data + dris.flags = USE_FUNCTION_ARGUMENT ' you have to do it this way in vb.net + dris.rw_length = data.Length + dris.data_crypt_key_num = 1 + dris.var_a = dris.var_a And &HFFFFFF ' restrict to 24-bit to prevent potential overflow in algorithm + dris.var_b = dris.var_b And &HFFFFFF + dris.var_c = dris.var_c And &HFFFFFF + dris.var_d = dris.var_d And &HFFFFFF + dris.var_e = dris.var_e And &HFFFFFF + dris.var_f = dris.var_f And &HFFFFFF + dris.var_g = dris.var_g And &HFFFFFF + dris.var_h = dris.var_h And &HFFFFFF + + ' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) + + ' encrypt data we pass to our API + CryptApiData(dris, data, data.Length, alg_ans) + + Call CryptDRIS(dris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(dris, data) + + Call CryptDRIS(dris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + EncryptUserDataEnc = ret_code + Exit Function + End If + + ' ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + ' Now decrypt the same data to get the original values + Call RandomSet(dris) ' sets DRIS to have random values including seed1, seed2 and var_a..var_h + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = DECRYPT_USER_DATA ' standard protection check & decrypt data + dris.flags = USE_FUNCTION_ARGUMENT ' you have to do it this way in vb.net + dris.rw_length = data.Length + dris.data_crypt_key_num = 1 + dris.var_a = dris.var_a And &HFFFFFF ' restrict to 24-bit to prevent potential overflow in algorithm + dris.var_b = dris.var_b And &HFFFFFF + dris.var_c = dris.var_c And &HFFFFFF + dris.var_d = dris.var_d And &HFFFFFF + dris.var_e = dris.var_e And &HFFFFFF + dris.var_f = dris.var_f And &HFFFFFF + dris.var_g = dris.var_g And &HFFFFFF + dris.var_h = dris.var_h And &HFFFFFF + + Call CryptDRIS(dris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(dris, data) + + Call CryptDRIS(dris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + EncryptUserDataEnc = ret_code + Exit Function + End If + + ' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) + + ' later in your code you can check other values in the DRIS... + If (dris.sdsn <> MY_SDSN) Then + MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error") + EncryptUserDataEnc = -1 + Exit Function + End If + + ' later on in your program you can check the return code again + If (dris.ret_code <> 0) Then + MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error") + EncryptUserDataEnc = -1 + Exit Function + End If + + ' decrypt data just returned by API. + CryptApiData(dris, data, data.Length, alg_ans) + MsgBox("Decrypted data is : " + Str(data(0)) + "," + Str(data(1)) + "," + Str(data(2)) + "," + Str(data(3)) + "," + _ + Str(data(4)) + "," + Str(data(5)) + "," + Str(data(6)) + "," + Str(data(7)) + "," + Str(data(8)) + "," + Str(data(9)), MsgBoxStyle.OkOnly) + EncryptUserDataEnc = 0 + Exit Function +Protection_Err: ' see readme.txt for explanation of this exception handler + Protection_Exception() + EncryptUserDataEnc = -1 + End Function + + + ' *********************** DisplayNetUsers ******************************* + ' This function displays the current network users (for DinkeyNet only). + ' The DDProtCheck function must be called before this function is called. + ' (Normally you would use DinkeyServer to view the network users but this enables you to do it from the client if you want) + Function DisplayNetUsers(net_users As Integer, model As Integer) As Integer + Dim num_net_users, extended_error, ret_code, i, max_net_users As Integer + Dim DisplayString As String + + If net_users = -1 Then + max_net_users = 100 ' if unlimited network users are allowed then display up to 100 users (for example) + Else + max_net_users = net_users + End If + + If max_net_users = 0 Then ' no network users are allowed, so nothing to do! + DisplayNetUsers = 0 + Exit Function + End If + + If model < 3 Then + MsgBox("A network dongle has not been detected. Therefore you cannot display the network users.", MsgBoxStyle.OKOnly) + DisplayNetUsers = -1 + Exit Function + End If + + Dim nu_info_array(max_net_users) As NU_INFO + + ' now get net users + ret_code = DDGetNetUserList(Nothing, num_net_users, nu_info_array, max_net_users, extended_error) + + If ret_code <> 0 Then + MsgBox("Error " + Str(ret_code) + "/" + Str(extended_error) + " finding network user information.", MsgBoxStyle.OKOnly) + Else + DisplayString = "number of net users: " + Str(num_net_users) + Environment.NewLine + For i = 0 To num_net_users - 1 + DisplayString = DisplayString + Str(i + 1) + ". licence: " + nu_info_array(i).LicenceName + ", user: " + nu_info_array(i).UserName + ", computer: " + nu_info_array(i).ComputerName + ", ip address: " + nu_info_array(i).IPAddress + Environment.NewLine + Next + MsgBox(DisplayString, MsgBoxStyle.OKOnly, "Net Users") + End If + DisplayNetUsers = ret_code + + End Function + + ' look at the error code and try to display an appropriate message + ' you may want to change these messages and specify your own + Public Sub DisplayError(ByVal ret_code As Integer, ByVal extended_error As Integer) + Select Case ret_code + Case 401 + MsgBox("Error! No dongles detected!", MsgBoxStyle.OKOnly, "Error") + Case 403 + MsgBox("Error! A dongle was detected but it was a different type to the one specified in DinkeyAdd.", MsgBoxStyle.OKOnly, "Error") + Case 404 + MsgBox("Error! A dongle was detected but it was a different model to those specified in DinkeyAdd.", MsgBoxStyle.OKOnly, "Error") + Case 409 + MsgBox("Error! The dongle detected has not been programmed by DinkeyAdd.", MsgBoxStyle.OKOnly, "Error") + Case 410 + MsgBox("Error! A dongle was detected but it has a different Product Code to the one specified in DinkeyAdd.", MsgBoxStyle.OKOnly, "Error") + Case 411 + MsgBox("Error! The dongle detected does not contain the licence associated with this program.", MsgBoxStyle.OKOnly, "Error") + Case 413 + MsgBox("Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual.", MsgBoxStyle.OKOnly, "Error") + Case 417 + MsgBox("Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.", MsgBoxStyle.OKOnly, "Error") + Case 423 + MsgBox("Error! The number of network users has been exceeded.", MsgBoxStyle.OKOnly, "Error") + Case 435 + MsgBox("Error! DinkeyServer has not been detected on the network.", MsgBoxStyle.OKOnly, "Error") + Case 922 + MsgBox("Error! The Software Key has expired.", MsgBoxStyle.OKOnly, "Error") + Case Else + MsgBox("An error occurred checking the dongle. Error: " + Str(ret_code) + ". Extended Error: " + Str(extended_error) + ".", MsgBoxStyle.OKOnly, "Error") + End Select + End Sub + + ' if an error exception occurs during a protection check function then display an appropiate message + ' see readme.txt for an explaination + Sub Protection_Exception() + If (TypeOf Err.GetException() Is DllNotFoundException) Then + If (IntPtr.Size = 4) Then + MsgBox("Error! Cannot find dpwin32.dll. This should be in the same folder that DLLTest.exe is in.", MsgBoxStyle.OKOnly, "Error") + Else + MsgBox("Error! Cannot find dpwin64.dll. This should be in the same folder that DLLTest.exe is in.", MsgBoxStyle.OKOnly, "Error") + End If + Else + MsgBox("Error! An exception occurred: " + Err.GetException.Message, MsgBoxStyle.OKOnly, "Error") + End If + End Sub + +End Class diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/README.txt new file mode 100644 index 0000000..7a594ac --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/README.txt @@ -0,0 +1,180 @@ +DllTest - sample code to call the Runtime Module in VB.NET +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 2002 but will work in more recent versions of Visual Studio +(it will upgrade the Project to the latest version. If prompted you should also upgrade the .NET +framework the project requires). + +The main source files in the project are: + +File name Description +Form1.vb main source code file for VB.NET +dris.vb contains the DRIS structure and low-level functions to manipulate it. + +The best approach is to compile the sample code and see how it works and then to take the appropriate code +and apply it to your own project. You should include the dris.vb file in your project and use/modify which +ever functions from form1.vb you feel are appropriate. The dris.vb file should not be modified. + +The sample code contains 11 functions. You will not need to use all these functions in your code. Just use +which ever functions are most appropriate and customise in your own way. The sample code is just a guide. +You should implement the protection in a stronger way using the techniques described in the +"Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. However, you should still +display or log any error codes returned by the protection check otherwise you will not be able to +identify the cause of the error. (You can look up error codes in our knowledge base: microcosm.com/kb). + +For users of Visual Studio 2005 or higher, the default setting for projects is to compile for the Target +Platform "Any". This means that on 32-bit Windows, your code will run as 32-bit code (and needs to call +dpwin32.dll) and under 64-bit Windows your code will run as 64-bit code (and needs to call dpwin64.dll). +The sample code works this out automatically. If you select the target platform as "x86" then it will +always be 32-bit and so you only need to use dpwin32.dll. If you select "x64" then your code will be +64-bit and you only need to use dpwin64.dll. + +Note - as you are using the API method in this sample you should protect dpwin32.dll and/or dpwin64.dll +and not your program. Because your program is linked to the DLL it is protected. You can also protect +your program with the Shell Method should you wish. + +Note - if you are compiling for the Platform target "Any" (and therefore need to protect both dpwin32.dll +and dpwin64.dll) then you will probably want to protect these modules to the same licence so that they share +a common set of protection parameters. + +Make sure you remember to do the following: + +1) Insert the following namespaces in your code file: +Imports System.Runtime.InteropServices + +2) Insert the dris.vb file in your project. + +3) The protected dpwin32.dll (dpwin64.dll) should be output to the folder that contains your EXE file. +Otherwise the message "Unable to open DLL (dpwin32.dll)" or System.DllNotFoundException error will appear +when you run DllTest. Unfortunately, when the system displays these exceptions, it gives the choice of +"Continue" which will return from the program assuming it returned success - and thereby bypassing the +protection check. To combat this we have added the Protection_Err exception handler to handle exceptions. +This behaviour appears to be unique to VB.NET. + +If you wish you can rename dpwin32.dll (dpwin64.dll) to a name of your choice. In this case you will need to +modify the dll name in the dris.vb file. + +Note - VB.NET is an interpreted language and so it is easier to decompile than other languages. You can +improve security if you use an obfuscator to obfuscate your code. Or - even better - you could use the +Shell Method to protect your executable. This encrypts your code (making it impossible to decompile). + +Note for using strings in DRIS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +To set the alt_licence_name field and read the prodcode field in the DRIS you need to use the +SetAltLicenceName and GetProductCode functions. You can use other fields directly, e.g. dris.sdsn + +Notes on Debugging 64-bit Code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +When you use the 64-bit runtime module (dpwin64.dll) to protect your software the anti-debug code is so +strong that if you are debugging your code, after the call DDProtCheck then it will crash with an SEH +exception. If you want to be able to debug your code then you can setup your project so that your code +calls the debug module (dpwin64debug.dll) in your "debug" build and the standard module (dpwin64.dll) +in your release build. You can do this by modifying the declaration of DDProtCheck64 in dris.vb like this: + +#if DEBUG ' debug module + Declare Function DDProtCheck64 Lib "dpwin64debug.dll" Alias "DDProtCheck" (ByRef mydris As DRIS, ByVal data() As Byte) As Integer +#else ' standard module + Declare Function DDProtCheck64 Lib "dpwin64.dll" Alias "DDProtCheck" (ByRef mydris As DRIS, ByVal data() As Byte) As Integer +#endif + +Note - the debug module has the following restrictions: + +1) It will not correctly start a network user (network dongles only). However, other than that the protection + check will function correctly and return success. +2) You will not be able to encrypt the DRIS. (If you do encrypt the DRIS in your release build then you + should make sure that CryptDRIS does not get called in your debug build). +3) The protection check will take slightly longer than normal. +4) The DDGetNetUserList function will return error 428 (not implemented). +5) A temporary subprocess is created which may be (falsely) detected as malicious by anti-virus programs. + +This behaviour does not occur in 32-bit code, so if you are using dpwin32.dll then you can debug your code. + +Special Note for using Algorithms in VB.NET +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The algorithms are calculated using 32-bit integers (Integer in vb.net). It is quite possible for the +MyAlgorithm and MyRWAlgorithm functions to overflow if the values provided are too big. In the dongle the +algorithms can never overflow - if the answer is too big then the high part of the answer is ignored. +In practical terms: + +When you are using the r/w algorithm it is best not to pass random 32-bit integers. It is better to restrict +the variables to 24-bit to avoid the possibility of overflows. You can see this implemented in the MyRWAlgorithm +and WriteBytesEnc function, for example. + +You can also use this technique with the user algorithms. Another option in MyAlgorithm is to convert each input +to 64-bit, apply the algorithm and then convert back to 32-bit to return the answer. + +When using a user algorithm it will behave exactly as the corresponding MyAlgorithm function will in VB +except it will not give overflow errors. + +Important Note for UWP app Developers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Universal Windows Platform (UWP) application (previously called Windows Store Apps or Metro Apps) are not +compatible with Lite or Plus dongles because the restrictions imposed by these applications. However, you +can protect these Apps with network dongles (because the restrictive access is performed by the non-UWP +DinkeyServer process). If you do this you will need to enable the "Private Networks (Client and Server)" +Capability in your package manifest. + +.NET Core / .NET 5+ +~~~~~~~~~~~~~~~~~~~ + +The sample code provided also works with .NET Core. However, .NET Core also supports Linux and macOS as well +as other platforms. If you want to support these OS then please replace dris.vb with dris_dotnetcore.vb. +The files are very similar but dris_dotnetcore.vb will load the relevant native runtime module (dpwin32.dll +under 32-bit Windows; dpwin64.dll under 64-bit Windows; dplin64.so under Linux OS; dpmac64debug.dylib under +macOS - unfortunately the release module is not compatible with the .NET Core framework so you have to use +the debug one. This also means that our solution is not compatible with ARM-based macOS - because the debug +modules do not exist). + +If you are using .NET Core version earlier than 3.0 then Windows.Forms are not supported and you will have to +replace the MessageBox.Show lines with Console.WriteLine. + +The Shell Method is compatible with .NET Core Console, Windows.Forms and WPF applications. It is supported +under Windows and Linux but not macOS. It is only supported for .NET Core version 3.0 or higher. If you are +using the Shell Method then you should protect your compiled dll and not the "appHost" (this is a native +executable which is just a stub program that loads the assemblies in your dll). Also do not use "dotnet run" +to launch your application - it will run the unprotected version. Either launch the executable or run using +"dotnet ". + +If you publish a "single-file executable" file then although this file can be protected we do not recommend +it because it is not secure. (The single-file executable just comprises a stub loader with your compiled +assemblies and configuration files appended to the end of the executable. These files are just considered as +data appended to the executable file in a custom format and therefore are not protected. When you shell +protect your executable you are just protecting the loader but not your assemblies). Instead you need to +build your code and then add protection before publishing. You should protect your assemblies in the obj +directory (and in the platform type you specified) e.g. obj/Release/net5.0/win-x64, because the publish +process takes your assemblies from this location when it builds the single-file executable. You will also +need to distribute all the extra files that DinkeyAdd generates. e.g. .dp64.dll. + +If you publish using the ReadytoRun compilation this will not work because it includes mixtures of .NET +assemblies and native code and the .NET Shell Method does not support that. + +Visual Studio Installer Projects Extension +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can use this extension to create a project in your solution that will create an installation program / msi +file. Please note that after your application has been built you need to protect it with DinkeyAdd before you +can invoke the installer project. You can do this manually by building your application project (not the entire +solution); then adding protection to your application using DinkeyAdd; then building your installer project. +Or you can automate this by executing DinkeyAddCmd as a post-build step. For example: +"c:\program files (x86)\Dinkey Pro 7.6.0\DinkeyAdd\DinkeyAddCmd.exe" c:\adir\mydapf.dapfj /a2 + +Note - if you specify "primary output" in your installer project then it will take the files from +obj\Release\net5.0 (for example), rather than bin\Release\net5.0. So, you need to add protection to your files +in this folder. + +Note - if you use the API Method you will also need to include the protected runtime modules that you use +(e.g. dpwin64.dll). If you use the Shell Method you will also need to include in your installer project all +of the output files mentioned by DinkeyAdd. e.g. .dp64.dll diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/dris.vb b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/dris.vb new file mode 100644 index 0000000..afd2fa5 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/dris.vb @@ -0,0 +1,218 @@ +' !! this file should not be modified + +Imports System.Runtime.InteropServices +Imports System.Text + +Module dris_code + + _ + Structure DRIS + ' the first 4 fields are never encrypted + Dim header1 As Byte ' should be set to 'DRIS' + Dim header2 As Byte + Dim header3 As Byte + Dim header4 As Byte + ' inputs + Dim size As Integer ' size of this structure + Dim seed1 As Integer ' seed for data/dris encryption + Dim seed2 As Integer ' as above + ' (maybe encrypted from now on) + Dim myfunction As Integer ' specify only one function + Dim flags As Integer ' options for the function selected. To use more than one OR them together: OPTION1 Or OPTION2... + Dim execs_decrement As UInt32 ' amount by which to dec execs if we use flag: DEC_MANY_EXECS + Dim data_crypt_key_num As Integer ' number of the key (1-3) that the dongle uses to encrypt or decrypt user data + Dim rw_offset As Integer ' offset in the dongle data area to read or write data + Dim rw_length As Integer ' length of data are to read/write/encrypt/decrypt + Dim DoNotUse As IntPtr ' do not use the rw_data_ptr element use the "Data" argument of the DDProtCheck function + ' to set this field use the function SetAltLicenceName instead + Dim _alt_licence_name As Byte() + Dim var_a As Integer ' variable values for user algorithm + Dim var_b As Integer + Dim var_c As Integer + Dim var_d As Integer + Dim var_e As Integer + Dim var_f As Integer + Dim var_g As Integer + Dim var_h As Integer + Dim alg_number As Integer ' the number of the user algorithm that you want to execute + ' outputs + Dim ret_code As Integer ' return code from the protection check + Dim ext_err As Integer ' extended error + Dim type As Integer ' type of dongle detected. 1 = Pro, 2 = FD + Dim model As Integer ' model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + Dim sdsn As Integer ' Software Developer's Serial Number + 'to read this field use the function GetProductCode instead + Dim _prodcode As Byte() + Dim dongle_number As UInt32 + Dim update_number As Integer + Dim data_area_size As UInt32 ' size of the data area in the dongle detected + Dim max_alg_num As Integer ' the maximum algorithm number in the dongle detected + Dim execs As Integer ' executions left: -1 indicates 'no limit' + Dim exp_day As Integer ' expiry day: -1 indicates 'no limit' + Dim exp_month As Integer ' expiry month: -1 indicates 'no limit' + Dim exp_year As Integer ' expiry year: -1 indicates 'no limit' + Dim features As UInt32 ' features value + Dim net_users As Integer ' maximum number of network users for the dongle detected: -1 indicates 'mo limit' + Dim alg_answer As Integer ' answer to the user algorithm executed with the given variable values + Dim fd_capacity As UInt32 ' capacity of the data area in FD dongle. Currently fixed at ~10MB but may change in the future. + 'to read this field use the function GetFDDrive instead + Dim _fd_drive As Byte() + Dim swkey_type As Integer ' 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + Dim swkey_exp_day As Integer ' software key expiry date (if software key detected) + Dim swkey_exp_month As Integer + Dim swkey_exp_year As Integer + End Structure + + _ + Structure NU_INFO + _ + Dim LicenceName As String + _ + Dim UserName As String + _ + Dim ComputerName As String + _ + Dim IPAddress As String + End Structure + + ' functions exported from dpwin32.dll / dpwin32.dll - do 32-bit and 64-bit separately + + ' DDProtCheck + Declare Function DDProtCheck32 Lib "dpwin32.dll" Alias "DDProtCheck" (ByRef mydris As DRIS, ByVal data() As Byte) As Integer + Declare Function DDProtCheck64 Lib "dpwin64.dll" Alias "DDProtCheck" (ByRef mydris As DRIS, ByVal data() As Byte) As Integer + + ' DDGetNetUserList + Declare Ansi Function DDGetNetUserList32 Lib "dpwin32.dll" Alias "DDGetNetUserList" (ByVal licence_name As String, ByRef num_net_users As Integer, _ + ByVal nu_info_bytes() As Byte, ByVal num_info_structs As Integer, ByRef extended_error As Integer) As Integer + Declare Ansi Function DDGetNetUserList64 Lib "dpwin64.dll" Alias "DDGetNetUserList" (ByVal licence_name As String, ByRef num_net_users As Integer, _ + ByVal nu_info_bytes() As Byte, ByVal num_info_structs As Integer, ByRef extended_error As Integer) As Integer + + ' call the correct dll depending on whether we are running 32-bit or 64-bit code + Function DDProtCheck(ByRef mydris As DRIS, ByVal data() As Byte) As Integer + If (IntPtr.Size = 4) Then + DDProtCheck = DDProtCheck32(mydris, data) + Else + DDProtCheck = DDProtCheck64(mydris, data) + End If + End Function + + Function DDGetNetUserList(ByVal licence_name As String, ByRef num_net_users As Integer, ByRef nu_info_array() As NU_INFO, ByVal num_info_structs As Integer, ByRef extended_error As Integer) As Integer + Dim i As Integer + Dim my_nu_info As New NU_INFO ' NB this only exists so we can get the size of the NU_INFO stucture + Dim nu_info_bytes(num_info_structs * Marshal.SizeOf(my_nu_info)) As Byte + Dim nu_info_one_struct(Marshal.SizeOf(my_nu_info)) As Byte + Dim MyGC As GCHandle + + ' call the function and get info as a byte array + If (IntPtr.Size = 4) Then + DDGetNetUserList = DDGetNetUserList32(licence_name, num_net_users, nu_info_bytes, num_info_structs, extended_error) + Else + DDGetNetUserList = DDGetNetUserList64(licence_name, num_net_users, nu_info_bytes, num_info_structs, extended_error) + End If + + ' convert byte array to an array of structs + For i = 0 To num_net_users - 1 + nu_info_array(i) = New NU_INFO + Array.Copy(nu_info_bytes, i * Marshal.SizeOf(my_nu_info.GetType), nu_info_one_struct, 0, Marshal.SizeOf(my_nu_info.GetType)) + MyGC = GCHandle.Alloc(nu_info_one_struct, GCHandleType.Pinned) + nu_info_array(i) = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, my_nu_info.GetType) + MyGC.Free() + Next + + End Function + + ' Functions + Public Const PROTECTION_CHECK As Integer = 1 ' checks for dongle, check program params... + Public Const EXECUTE_ALGORITHM As Integer = 2 ' protection check + calculate answer for specified algorithm with specified inputs + Public Const WRITE_DATA_AREA As Integer = 3 ' protection check + writes dongle data area + Public Const READ_DATA_AREA As Integer = 4 ' protection check + reads dongle data area + Public Const ENCRYPT_USER_DATA As Integer = 5 ' protection check + the dongle will encrypt user data + Public Const DECRYPT_USER_DATA As Integer = 6 ' protection check + the dongle will decrypt user data + Public Const FAST_PRESENCE_CHECK As Integer = 7 ' checks for the presence of the correct dongle only with minimal security, no flags allowed + Public Const STOP_NET_USER As Integer = 8 ' stops a network user (a protection check is NOT performed) + + ' Flags + Public Const DEC_ONE_EXEC As Integer = 1 ' decrement execs by 1 + Public Const DEC_MANY_EXECS As Integer = 2 ' decrement execs by number specified in execs + Public Const START_NET_USER As Integer = 4 ' starts a network user + Public Const USE_FUNCTION_ARGUMENT As Integer = 16 ' use the extra argument in the function for pointers + Public Const CHECK_LOCAL_FIRST As Integer = 32 ' always look in local ports before looking in network ports + Public Const CHECK_NETWORK_FIRST As Integer = 64 ' always look on the network before looking in local ports + Public Const USE_ALT_LICENCE_NAME As Integer = 128 ' use name specified in alt_licence_name instead of the default one + Public Const DONT_SET_MAXDAYS_EXPIRY As Integer = 256 ' if the max days expiry date has not been calculated then do not do it this time + Public Const MATCH_DONGLE_NUMBER As Integer = 512 ' restrict the search to match the dongle number specified in the DRIS + Public Const DONT_RETURN_FD_DRIVE As Integer = 1024 ' if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + + Public Const NU_INFO_SIZE As Integer = (256 + 50 + 256 + 16) ' size of NU_INFO structure (for listing network users) + + ' ********************** useful functions for use in sample code *************************** + ' use this function to set the alt_licence_name field of the DRIS + Public Sub SetAltLicenceName(ByVal mydris As DRIS, ByVal altlicencename As String) + Dim i, num_bytes As Integer + Dim ascii As New ASCIIEncoding + Dim temp As Byte() + + temp = ascii.GetBytes(altlicencename) + num_bytes = ascii.GetByteCount(altlicencename) + For i = 0 To num_bytes - 1 + mydris._alt_licence_name(i) = temp(i) + Next + mydris._alt_licence_name(num_bytes) = 0 'null-terminate string + End Sub + + ' use this function to read the prodcode field of the DRIS + Public Function GetProductCode(ByVal mydris As DRIS) As String + Dim ascii As New ASCIIEncoding + Dim i As Integer + For i = 0 To 11 + If mydris._prodcode(i) = 0 Then + Exit For + End If + Next + Return ascii.GetString(mydris._prodcode, 0, i) + End Function + + ' use this function to read the fd_drive field of the DRIS + Public Function GetFDDrive(ByVal mydris As DRIS) As String + Dim ascii As New ASCIIEncoding + Dim i As Integer + For i = 0 To 127 + If mydris._fd_drive(i) = 0 Then + Exit For + End If + Next + Return ascii.GetString(mydris._fd_drive, 0, i) + End Function + + ' copies an integer to offset "index" in trhe specified byte array + Public Sub Set4Bytes(ByVal data() As Byte, ByVal index As Integer, ByVal value As Integer) + Dim MyGC As GCHandle = GCHandle.Alloc(value, GCHandleType.Pinned) + Dim AddressOfValue As IntPtr = MyGC.AddrOfPinnedObject() + Marshal.Copy(AddressOfValue, data, index, 4) + MyGC.Free() + End Sub + + ' converts to DRIS structure to a byte array (so we can do encryption) + Public Sub DrisToByteArray(ByVal mydris As DRIS, ByVal data() As Byte) + Dim MyGC As GCHandle = GCHandle.Alloc(data, GCHandleType.Pinned) + Marshal.StructureToPtr(mydris, MyGC.AddrOfPinnedObject, False) + MyGC.Free() + End Sub + + ' converts a byte array to the DRIS structure (so we can do encryption) + Public Sub ByteArrayToDris(ByVal data() As Byte, ByRef mydris As DRIS) + Dim MyGC As GCHandle = GCHandle.Alloc(data, GCHandleType.Pinned) + mydris = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, mydris.GetType) + MyGC.Free() + End Sub + + ' initialise the DRIS with random values + Public Sub RandomSet(ByRef mydris As DRIS) + Dim temp_dris(Marshal.SizeOf(mydris) - 1) As Byte + Dim rnd As New Random + + rnd.NextBytes(temp_dris) + ByteArrayToDris(temp_dris, mydris) + End Sub + +End Module diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/dris_dotnetcore.vb b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/dris_dotnetcore.vb new file mode 100644 index 0000000..7b7fe4f --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic .NET/Runtime/dris_dotnetcore.vb @@ -0,0 +1,236 @@ +' !! this file should not be modified + +Imports System.Runtime.InteropServices +Imports System.Text + +Module dris_code + + _ + Structure DRIS + ' the first 4 fields are never encrypted + Dim header1 As Byte ' should be set to 'DRIS' + Dim header2 As Byte + Dim header3 As Byte + Dim header4 As Byte + ' inputs + Dim size As Integer ' size of this structure + Dim seed1 As Integer ' seed for data/dris encryption + Dim seed2 As Integer ' as above + ' (maybe encrypted from now on) + Dim myfunction As Integer ' specify only one function + Dim flags As Integer ' options for the function selected. To use more than one OR them together: OPTION1 Or OPTION2... + Dim execs_decrement As UInt32 ' amount by which to dec execs if we use flag: DEC_MANY_EXECS + Dim data_crypt_key_num As Integer ' number of the key (1-3) that the dongle uses to encrypt or decrypt user data + Dim rw_offset As Integer ' offset in the dongle data area to read or write data + Dim rw_length As Integer ' length of data are to read/write/encrypt/decrypt + Dim DoNotUse As IntPtr ' do not use the rw_data_ptr element use the "Data" argument of the DDProtCheck function + ' to set this field use the function SetAltLicenceName instead + Dim _alt_licence_name As Byte() + Dim var_a As Integer ' variable values for user algorithm + Dim var_b As Integer + Dim var_c As Integer + Dim var_d As Integer + Dim var_e As Integer + Dim var_f As Integer + Dim var_g As Integer + Dim var_h As Integer + Dim alg_number As Integer ' the number of the user algorithm that you want to execute + ' outputs + Dim ret_code As Integer ' return code from the protection check + Dim ext_err As Integer ' extended error + Dim type As Integer ' type of dongle detected. 1 = Pro, 2 = FD + Dim model As Integer ' model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + Dim sdsn As Integer ' Software Developer's Serial Number + 'to read this field use the function GetProductCode instead + Dim _prodcode As Byte() + Dim dongle_number As UInt32 + Dim update_number As Integer + Dim data_area_size As UInt32 ' size of the data area in the dongle detected + Dim max_alg_num As Integer ' the maximum algorithm number in the dongle detected + Dim execs As Integer ' executions left: -1 indicates 'no limit' + Dim exp_day As Integer ' expiry day: -1 indicates 'no limit' + Dim exp_month As Integer ' expiry month: -1 indicates 'no limit' + Dim exp_year As Integer ' expiry year: -1 indicates 'no limit' + Dim features As UInt32 ' features value + Dim net_users As Integer ' maximum number of network users for the dongle detected: -1 indicates 'mo limit' + Dim alg_answer As Integer ' answer to the user algorithm executed with the given variable values + Dim fd_capacity As UInt32 ' capacity of the data area in FD dongle. Currently fixed at ~10MB but may change in the future. + 'to read this field use the function GetFDDrive instead + Dim _fd_drive As Byte() + Dim swkey_type As Integer ' 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + Dim swkey_exp_day As Integer ' software key expiry date (if software key detected) + Dim swkey_exp_month As Integer + Dim swkey_exp_year As Integer + End Structure + + _ + Structure NU_INFO + _ + Dim LicenceName As String + _ + Dim UserName As String + _ + Dim ComputerName As String + _ + Dim IPAddress As String + End Structure + + ' functions exported from runtime module e.g. dpwin64.dll etc + + ' DDProtCheck + Declare Function DDProtCheckWin32 Lib "dpwin32.dll" Alias "DDProtCheck" (ByRef mydris As DRIS, ByVal data() As Byte) As Integer + Declare Function DDProtCheckWin64 Lib "dpwin64.dll" Alias "DDProtCheck" (ByRef mydris As DRIS, ByVal data() As Byte) As Integer + Declare Function DDProtCheckLin64 Lib "dplin64.so" Alias "DDProtCheck" (ByRef mydris As DRIS, ByVal data() As Byte) As Integer + Declare Function DDProtCheckMac64 Lib "dpmac64debug.dylib" Alias "DDProtCheck" (ByRef mydris As DRIS, ByVal data() As Byte) As Integer + + ' DDGetNetUserList - NB not supported for macOS as this function does not exist in the debug module + Declare Ansi Function DDGetNetUserListWin32 Lib "dpwin32.dll" Alias "DDGetNetUserList" (ByVal licence_name As String, ByRef num_net_users As Integer, + ByVal nu_info_bytes() As Byte, ByVal num_info_structs As Integer, ByRef extended_error As Integer) As Integer + Declare Ansi Function DDGetNetUserListWin64 Lib "dpwin64.dll" Alias "DDGetNetUserList" (ByVal licence_name As String, ByRef num_net_users As Integer, + ByVal nu_info_bytes() As Byte, ByVal num_info_structs As Integer, ByRef extended_error As Integer) As Integer + Declare Ansi Function DDGetNetUserListLin64 Lib "dplin64.so" Alias "DDGetNetUserList" (ByVal licence_name As String, ByRef num_net_users As Integer, + ByVal nu_info_bytes() As Byte, ByVal num_info_structs As Integer, ByRef extended_error As Integer) As Integer + + ' call the correct dll depending on whether we are running 32-bit or 64-bit code + Function DDProtCheck(ByRef mydris As DRIS, ByVal data() As Byte) As Integer + If (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) Then + If (Environment.Is64BitProcess) Then + DDProtCheck = DDProtCheckWin64(mydris, data) + Else + DDProtCheck = DDProtCheckWin32(mydris, data) + End If + ElseIf (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) Then + DDProtCheck = DDProtCheckLin64(mydris, data) + ElseIf (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) Then + DDProtCheck = DDProtCheckMac64(mydris, data) + Else + DDProtCheck = -1 ' OS not supported + End If + End Function + + Function DDGetNetUserList(ByVal licence_name As String, ByRef num_net_users As Integer, ByRef nu_info_array() As NU_INFO, ByVal num_info_structs As Integer, ByRef extended_error As Integer) As Integer + Dim i As Integer + Dim my_nu_info As New NU_INFO ' NB this only exists so we can get the size of the NU_INFO stucture + Dim nu_info_bytes(num_info_structs * Marshal.SizeOf(my_nu_info)) As Byte + Dim nu_info_one_struct(Marshal.SizeOf(my_nu_info)) As Byte + Dim MyGC As GCHandle + + ' call the function and get info as a byte array + If (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) Then + If (Environment.Is64BitProcess) Then + DDGetNetUserList = DDGetNetUserListWin64(licence_name, num_net_users, nu_info_bytes, num_info_structs, extended_error) + Else + DDGetNetUserList = DDGetNetUserListWin32(licence_name, num_net_users, nu_info_bytes, num_info_structs, extended_error) + End If + ElseIf (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) Then + DDGetNetUserList = DDGetNetUserListLin64(licence_name, num_net_users, nu_info_bytes, num_info_structs, extended_error) + Else + DDGetNetUserList = -1 ' OS not supported (this includes macOS) + End If + + ' convert byte array to an array of structs + For i = 0 To num_net_users - 1 + nu_info_array(i) = New NU_INFO + Array.Copy(nu_info_bytes, i * Marshal.SizeOf(my_nu_info.GetType), nu_info_one_struct, 0, Marshal.SizeOf(my_nu_info.GetType)) + MyGC = GCHandle.Alloc(nu_info_one_struct, GCHandleType.Pinned) + nu_info_array(i) = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, my_nu_info.GetType) + MyGC.Free() + Next + + End Function + + ' Functions + Public Const PROTECTION_CHECK As Integer = 1 ' checks for dongle, check program params... + Public Const EXECUTE_ALGORITHM As Integer = 2 ' protection check + calculate answer for specified algorithm with specified inputs + Public Const WRITE_DATA_AREA As Integer = 3 ' protection check + writes dongle data area + Public Const READ_DATA_AREA As Integer = 4 ' protection check + reads dongle data area + Public Const ENCRYPT_USER_DATA As Integer = 5 ' protection check + the dongle will encrypt user data + Public Const DECRYPT_USER_DATA As Integer = 6 ' protection check + the dongle will decrypt user data + Public Const FAST_PRESENCE_CHECK As Integer = 7 ' checks for the presence of the correct dongle only with minimal security, no flags allowed + Public Const STOP_NET_USER As Integer = 8 ' stops a network user (a protection check is NOT performed) + + ' Flags + Public Const DEC_ONE_EXEC As Integer = 1 ' decrement execs by 1 + Public Const DEC_MANY_EXECS As Integer = 2 ' decrement execs by number specified in execs + Public Const START_NET_USER As Integer = 4 ' starts a network user + Public Const USE_FUNCTION_ARGUMENT As Integer = 16 ' use the extra argument in the function for pointers + Public Const CHECK_LOCAL_FIRST As Integer = 32 ' always look in local ports before looking in network ports + Public Const CHECK_NETWORK_FIRST As Integer = 64 ' always look on the network before looking in local ports + Public Const USE_ALT_LICENCE_NAME As Integer = 128 ' use name specified in alt_licence_name instead of the default one + Public Const DONT_SET_MAXDAYS_EXPIRY As Integer = 256 ' if the max days expiry date has not been calculated then do not do it this time + Public Const MATCH_DONGLE_NUMBER As Integer = 512 ' restrict the search to match the dongle number specified in the DRIS + Public Const DONT_RETURN_FD_DRIVE As Integer = 1024 ' if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + + Public Const NU_INFO_SIZE As Integer = (256 + 50 + 256 + 16) ' size of NU_INFO structure (for listing network users) + + ' ********************** useful functions for use in sample code *************************** + ' use this function to set the alt_licence_name field of the DRIS + Public Sub SetAltLicenceName(ByVal mydris As DRIS, ByVal altlicencename As String) + Dim i, num_bytes As Integer + Dim ascii As New ASCIIEncoding + Dim temp As Byte() + + temp = ascii.GetBytes(altlicencename) + num_bytes = ascii.GetByteCount(altlicencename) + For i = 0 To num_bytes - 1 + mydris._alt_licence_name(i) = temp(i) + Next + mydris._alt_licence_name(num_bytes) = 0 'null-terminate string + End Sub + + ' use this function to read the prodcode field of the DRIS + Public Function GetProductCode(ByVal mydris As DRIS) As String + Dim ascii As New ASCIIEncoding + Dim i As Integer + For i = 0 To 11 + If mydris._prodcode(i) = 0 Then + Exit For + End If + Next + Return ascii.GetString(mydris._prodcode, 0, i) + End Function + + ' use this function to read the fd_drive field of the DRIS + Public Function GetFDDrive(ByVal mydris As DRIS) As String + Dim ascii As New ASCIIEncoding + Dim i As Integer + For i = 0 To 127 + If mydris._fd_drive(i) = 0 Then + Exit For + End If + Next + Return ascii.GetString(mydris._fd_drive, 0, i) + End Function + + ' copies an integer to offset "index" in trhe specified byte array + Public Sub Set4Bytes(ByVal data() As Byte, ByVal index As Integer, ByVal value As Integer) + Dim MyGC As GCHandle = GCHandle.Alloc(value, GCHandleType.Pinned) + Dim AddressOfValue As IntPtr = MyGC.AddrOfPinnedObject() + Marshal.Copy(AddressOfValue, data, index, 4) + MyGC.Free() + End Sub + + ' converts to DRIS structure to a byte array (so we can do encryption) + Public Sub DrisToByteArray(ByVal mydris As DRIS, ByVal data() As Byte) + Dim MyGC As GCHandle = GCHandle.Alloc(data, GCHandleType.Pinned) + Marshal.StructureToPtr(mydris, MyGC.AddrOfPinnedObject, False) + MyGC.Free() + End Sub + + ' converts a byte array to the DRIS structure (so we can do encryption) + Public Sub ByteArrayToDris(ByVal data() As Byte, ByRef mydris As DRIS) + Dim MyGC As GCHandle = GCHandle.Alloc(data, GCHandleType.Pinned) + mydris = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, mydris.GetType) + MyGC.Free() + End Sub + + ' initialise the DRIS with random values + Public Sub RandomSet(ByRef mydris As DRIS) + Dim temp_dris(Marshal.SizeOf(mydris) - 1) As Byte + Dim rnd As New Random + + rnd.NextBytes(temp_dris) + ByteArrayToDris(temp_dris, mydris) + End Sub + +End Module diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/DinkeyChange/ChangeTest.bas b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/DinkeyChange/ChangeTest.bas new file mode 100644 index 0000000..a03b903 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/DinkeyChange/ChangeTest.bas @@ -0,0 +1,98 @@ +' !! this file should not be modified + +Attribute VB_Name = "Module1" +' API functions +Declare Function DCGetInfo Lib "DinkeyChange.dll" (ByVal type_mask As Long, ByVal model_mask As Long, ByVal prodcode_mask As Any, ByVal array_length As Long, _ + num_found As Long, type_array As FixedIntegerArray, model_array As FixedIntegerArray, prodcode_array As FixedByteArray, dongle_number_array As FixedIntegerArray, update_number_array As FixedIntegerArray) As Long +Declare Function DCGetDiagnosticInfo Lib "DinkeyChange.dll" (ByVal DiagFileName As Any) As Long +Declare Function DCDoUpdateCodeString Lib "DinkeyChange.dll" (ByVal UpdateCode As Any, confirmation_code As Long, extended_error As Long) As Long +Declare Function DCDoUpdateCodeFromFile Lib "DinkeyChange.dll" (ByVal UpdateCodeFile As Any, confirmation_code As Long, extended_error As Long) As Long +Declare Function DCRestoreDinkeyFDLite Lib "DinkeyChange.dll" () As Long +Declare Function DCGetMachineID Lib "DinkeyChange.dll" (machineID As Long, extended_error As Long) As Long +Declare Function DCDownloadTempSoftwareKey Lib "DinkeyChange.dll" (ByVal machineID As Long, extended_error As Long) As Long +Declare Function DCDownloadDemoSoftwareKey Lib "DinkeyChange.dll" (ByVal machineID As Long, ByVal ProdCode As Any, ByVal model As Long, extended_error As Long) As Long + +' maximum number of USB dongles that can be attached to a machine at any one time +Public Const MAX_USB_DEVICES = 128 + +' mask values +Public Const TYPE_MASK_PRO = 1 +Public Const TYPE_MASK_FD = 2 +Public Const TYPE_MASK_ALL = (TYPE_MASK_PRO Or TYPE_MASK_FD) + +Public Const MODEL_MASK_LITE = 1 +Public Const MODEL_MASK_PLUS = 2 +Public Const MODEL_MASK_NET = 4 +Public Const MODEL_MASK_ALL = (MODEL_MASK_LITE Or MODEL_MASK_PLUS Or MODEL_MASK_NET) +Public Const MODEL_MASK_DEFAULT = (MODEL_MASK_PLUS Or MODEL_MASK_NET) + +' type values for DCGetInfo (returned in the array) +Public Const TYPE_PRO = 1 +Public Const TYPE_FD = 2 + +' model values for DCGetInfo (returned in the array) +Public Const MODEL_LITE = 1 +Public Const MODEL_PLUS = 2 +Public Const MODEL_NET5 = 4 +Public Const MODEL_NETU = 7 + +' model values for DCDownloadDemoSoftwareKey +Public Const SWKEY_MODEL_DEFAULT = &HFFFFFFFF ' NB this assumes that the Demo Software Key Template was created with only one valid dongle model +Public Const SWKEY_MODEL_PRO_LITE = 0 +Public Const SWKEY_MODEL_PRO_PLUS = 1 +Public Const SWKEY_MODEL_PRO_NET = 2 +Public Const SWKEY_MODEL_FD_LITE = 3 +Public Const SWKEY_MODEL_FD_PLUS = 4 +Public Const SWKEY_MODEL_FD_NET = 5 + +'we need a structure for an array of bytes because otherwise the VB runtime can move the data in-between function calls +Type FixedByteArray + data(0 To MAX_USB_DEVICES * 9) As Byte ' 9 is the prodcode length (including terminating null) +End Type + +' and ints +Type FixedIntegerArray + data(1 To MAX_USB_DEVICES) As Long +End Type + +' this function converts an unsigned integer to a double for display purposes (otherwise it may display the dongle number as a negative number!) +Public Function UIntToDouble(ByVal number As Long) As Double + UIntToDouble = CDbl(number) + If UIntToDouble < 0 Then + UIntToDouble = UIntToDouble + 2 ^ 32 + End If +End Function + +' this function gets the index-th prodcode from the array +Public Function GetProdCodeFromArray(prodcode As FixedByteArray, ByVal index As Long) As String + Dim data As Byte ' this will be a byte of data from array + + index = index - 1 ' so it is 0-based + GetProdCodeFromArray = "" + For i = 0 To 8 + data = prodcode.data((index * 9) + i) + If data = 0 Then ' stop when we get to the null + Exit For + Else ' otherwise append character to string + GetProdCodeFromArray = GetProdCodeFromArray & Chr(data) + End If + Next +End Function + +' this function will convert the C string returned in the DCIS to a VB string +' e.g. to access the product code use TrimCString(mydcis.prodcode) +Function TrimCString(Str As String) As String + Dim i As Integer + Dim length As Integer + + length = Len(Str) + + For i = 1 To length + If Mid(Str, i, 1) = Chr$(0) Then + TrimCString = Left$(Str, i - 1) 'take off null and rest of string + Exit For + End If + Next + +End Function + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/DinkeyChange/ChangeTest.frm b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/DinkeyChange/ChangeTest.frm new file mode 100644 index 0000000..2a3f294 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/DinkeyChange/ChangeTest.frm @@ -0,0 +1,361 @@ +VERSION 5.00 +Begin VB.Form ChangeTest + Caption = "ChangeTest" + ClientHeight = 9705 + ClientLeft = 60 + ClientTop = 345 + ClientWidth = 5235 + LinkTopic = "Form1" + ScaleHeight = 9705 + ScaleWidth = 5235 + StartUpPosition = 3 'Windows Default + Begin VB.CommandButton DownloadDemoSoftwareKey + Caption = "Download Demo Software Key" + Height = 315 + Left = 960 + TabIndex = 16 + Top = 9120 + Width = 3015 + End + Begin VB.TextBox SwKeyProdCode + Height = 375 + Left = 240 + TabIndex = 15 + Top = 8640 + Width = 4695 + End + Begin VB.TextBox ShowMachineID + Height = 375 + Left = 2640 + TabIndex = 13 + Top = 6720 + Width = 2295 + End + Begin VB.CommandButton DownloadTempSoftwareKey + Caption = "Download Temporary Software Key" + Height = 375 + Left = 1080 + TabIndex = 12 + Top = 7560 + Width = 2895 + End + Begin VB.CommandButton GetMachineID + Caption = "Get Machine ID" + Height = 375 + Left = 240 + TabIndex = 11 + Top = 6720 + Width = 2175 + End + Begin VB.CommandButton RestoreFDLite + Caption = "Restore FD Lite" + Height = 375 + Left = 1080 + TabIndex = 10 + Top = 5760 + Width = 2895 + End + Begin VB.CommandButton DoUpdateCodeFile + Caption = "Make Changes" + Height = 375 + Left = 1080 + TabIndex = 9 + Top = 4920 + Width = 2895 + End + Begin VB.TextBox UpdateCodeFile + Height = 405 + Left = 240 + TabIndex = 8 + Top = 4440 + Width = 4695 + End + Begin VB.CommandButton DoUpdateCodeString + Caption = "Make Changes" + Height = 375 + Left = 1080 + TabIndex = 6 + Top = 3360 + Width = 2895 + End + Begin VB.TextBox UpdateCodeString + Height = 405 + Left = 240 + TabIndex = 5 + Top = 2880 + Width = 4695 + End + Begin VB.CommandButton WriteDiags + Caption = "Write Diagnostics to File" + Height = 375 + Left = 1080 + TabIndex = 3 + Top = 1800 + Width = 2895 + End + Begin VB.TextBox DiagFileName + Height = 405 + Left = 240 + TabIndex = 2 + Top = 1320 + Width = 4695 + End + Begin VB.CommandButton GetInfo + Caption = "Get Dongle Information" + Height = 375 + Left = 1080 + TabIndex = 0 + Top = 360 + Width = 2895 + End + Begin VB.Label Label4 + Caption = "Demo Software Key Product Code:" + Height = 255 + Left = 240 + TabIndex = 14 + Top = 8400 + Width = 4695 + End + Begin VB.Label Label3 + Caption = "Enter path of Update Code file:" + Height = 255 + Left = 240 + TabIndex = 7 + Top = 4200 + Width = 4695 + End + Begin VB.Label Label2 + Caption = "Enter short Update Code here:" + Height = 255 + Left = 240 + TabIndex = 4 + Top = 2640 + Width = 4695 + End + Begin VB.Label Label1 + Caption = "Enter Diagnostic filename:" + Height = 255 + Left = 240 + TabIndex = 1 + Top = 1080 + Width = 4695 + End +End +Attribute VB_Name = "ChangeTest" +Attribute VB_GlobalNameSpace = False +Attribute VB_Creatable = False +Attribute VB_PredeclaredId = True +Attribute VB_Exposed = False + + +' !! We strongly recommend that you read the "readme.txt" file for this sample. +' !! It contains important instructions on how to use the sample code + +' Display Dongle Information +Private Sub GetInfo_Click() + Dim ret_code As Long + Dim num_found As Long + Dim DisplayString, DongleType, DongleModel, ProdCodeString As String + ' these are the arrays of dongle information filled-in by DCGetInfo + Dim type_array As FixedIntegerArray + Dim model_array As FixedIntegerArray + Dim prodcode_array As FixedByteArray + Dim dongle_number_array As FixedIntegerArray + Dim update_number_array As FixedIntegerArray + + ' find dongle information for all dongle types, Plus & Net models, for all product codes + ' NB In practice you will probably want to set the prodcode_mask to the value of your product code + ret_code = DCGetInfo(TYPE_MASK_ALL, MODEL_MASK_DEFAULT, "", MAX_USB_DEVICES, num_found, type_array, model_array, prodcode_array, dongle_number_array, update_number_array) + + ' check for errors + If ret_code = 401 Then + MsgBox "No dongles detected matching the search criteria specified", vbOKOnly, "Error" + Exit Sub + End If + + If ret_code <> 0 Then + MsgBox "Error " + Str$(ret_code) + " getting dongle information", vbOKOnly, "Error" + Exit Sub + End If + + 'display dongle details + DisplayString = "" ' initialise + For i = 1 To num_found + If type_array.data(i) = 1 Then ' dongle type + DongleType = "Pro" + Else + DongleType = "FD" + End If + If model_array.data(i) = 1 Then ' dongle model + DongleModel = "Lite" + ElseIf model_array.data(i) = 2 Then + DongleModel = "Plus" + Else + DongleModel = "Net" + End If + ProdCodeString = GetProdCodeFromArray(prodcode_array, i) ' product code + ' add details for this dongle to list + DisplayString = DisplayString + Str$(i) + ". Dinkey " + DongleType + " " + DongleModel + ", product code " + ProdCodeString + " with dongle number " + Str$(UIntToDouble(dongle_number_array.data(i))) + ", update number " + Str$(update_number_array.data(i)) + vbNewLine + Next + + MsgBox DisplayString, vbOKOnly + +End Sub + +' Write dongle diagnostics to file +Private Sub WriteDiags_Click() + Dim ret_code As Long + + ret_code = DCGetDiagnosticInfo(DiagFileName.Text) + + If ret_code = 754 Then + MsgBox "Could not create the diagnostic file. Please check that the path exists:" + DiagFileName.Text, vbOKOnly, "Error" + Exit Sub + ElseIf ret_code <> 0 Then + MsgBox "Error " + Str$(ret_code) + " writing diagnostic file.", vbOKOnly, "Error" + Exit Sub + End If + + ' display success + MsgBox "Diagnostic file written successfully.", vbOKOnly +End Sub + +' update dongle with short code entered +Private Sub DoUpdateCodeString_Click() + Dim ret_code, confirmation_code, extended_error As Long + + ret_code = DCDoUpdateCodeString(UpdateCodeString.Text, confirmation_code, extended_error) + + If ret_code <> 0 Then + Call DisplayError(ret_code, extended_eror) + Exit Sub + End If + + MsgBox "Dongle updated successfully!" + vbNewLine + "Confirmation code is: " + Hex(confirmation_code), vbOnly +End Sub + +' update dongle using update code in specified file +Private Sub DoUpdateCodeFile_Click() + Dim ret_code, confirmation_code, extended_error As Long + + ret_code = DCDoUpdateCodeFromFile(UpdateCodeFile.Text, confirmation_code, extended_error) + + If ret_code <> 0 Then + Call DisplayError(ret_code, extended_eror) + Exit Sub + End If + + MsgBox "Dongle updated successfully!" + vbNewLine + "Confirmation code is: " + Hex(confirmation_code), vbOnly +End Sub + +Private Sub RestoreFDLite_Click() + Dim ret_code As Long + + ret_code = DCRestoreDinkeyFDLite() + + If ret_code <> 0 Then + Call DisplayError(ret_code, 0) + Exit Sub + End If + + ' display success + MsgBox "Dinkey FD Lite dongle restored successfully.", vbOKOnly +End Sub + +Private Sub GetMachineID_Click() + Dim ret_code, machineID, extended_error As Long + + ret_code = DCGetMachineID(machineID, extended_error) + + If ret_code <> 0 Then + Call DisplayError(ret_code, 0) + Exit Sub + End If + + ' display machine ID in text box + ShowMachineID.Text = Hex(machineID) +End Sub + +Private Sub DownloadTempSoftwareKey_Click() + Dim ret_code, machineID, extended_error As Long + + ' first get the machine ID... + ret_code = DCGetMachineID(machineID, extended_error) + + If ret_code <> 0 Then + Call DisplayError(ret_code, 0) + Exit Sub + End If + + ' ...then try to download the temporary software key + ret_code = DCDownloadTempSoftwareKey(machineID, extended_error) + + If ret_code <> 0 Then + Call DisplayError(ret_code, 0) + Exit Sub + End If + + MsgBox "The Temporary Software Key has been downloaded successfully!", vbOnly +End Sub + +Private Sub DownloadDemoSoftwareKey_Click() + Dim ret_code, machineID, extended_error As Long + + ' first get the machine ID... + ret_code = DCGetMachineID(machineID, extended_error) + + If ret_code <> 0 Then + Call DisplayError(ret_code, 0) + Exit Sub + End If + + ' ...then try to download the demo software key + '(NB we are assuming only one dongle model is set in the Demo Software Template. + ' If multiple models are set you will also need to specify the exact model) + ret_code = DCDownloadDemoSoftwareKey(machineID, SwKeyProdCode.Text, SWKEY_MODEL_DEFAULT, extended_error) + + If ret_code <> 0 Then + Call DisplayError(ret_code, 0) + Exit Sub + End If + + MsgBox "The Demo Software Key has been downloaded successfully!", vbOnly +End Sub + +' look at the error code and try to display an appropriate message +Public Sub DisplayError(ByVal ret_code As Long, ByVal extended_error As Long) + Select Case ret_code + Case 401 + MsgBox "Error! No dongles detected that meet the search criteria!", vbOKOnly, "Error" + Case 409 + MsgBox "Error! The dongle detected has not been programmed by DinkeyAdd.", vbOKOnly, "Error" + Case 758: + MsgBox "Error! Cannot open the Update Code file specified.", vbOKOnly, "Error" + Case 759: + MsgBox "Error! The file specified is not a valid Update Code file.", vbOKOnly, "Error" + Case 762, 763, 764 + MsgBox "Error! Update Code is not in a correct format / update code file is corrupt.", vbOKOnly, "Error" + Case 765 + MsgBox "Error! The Update Code does not match any dongle attached to your machine.", vbOKOnly, "Error" + Case 766 + MsgBox "Error! The update number for this Update Code is too high. You need to first enter an update code that was previously sent to you.", vbOKOnly, "Error" + Case 767: + MsgBox "Error! You have already entered this Update Code.", vbOKOnly, "Error" + Case 1905: + MsgBox "Error! There is no Software Key available for download.", vbOKOnly, "Error" + Case 1907: + MsgBox "Error! The Temporary Software Key has expired. Cannot download it.", vbOKOnly, "Error" + Case 1910: + MsgBox "Error! The Software Key has already been downloaded.", vbOKOnly, "Error" + Case 1921 + MsgBox "Error! You specified the 'default model' but there is more than one model available. You need to specify a specific dongle model.", vbOKOnly, "Error" + Case 1922: + MsgBox "Error! The model you requested is not available.", vbOKOnly, "Error" + Case 1923: + MsgBox "Error! The Demo Software Key Template has been disabled.", vbOKOnly, "Error" + Case 1924: + MsgBox "Error! You have run out of Demo Software Key activations. You need to order some more.", vbOKOnly, "Error" + Case Else + MsgBox "An error occurred checking the dongle. Error: " + Str$(ret_code) + ". Extended Error: " + Str$(extended_error) + ".", vbOKOnly, "Error" + End Select +End Sub diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/DinkeyChange/ChangeTest.vbp b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/DinkeyChange/ChangeTest.vbp new file mode 100644 index 0000000..5eb7ece --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/DinkeyChange/ChangeTest.vbp @@ -0,0 +1,35 @@ +Type=Exe +Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#..\..\..\..\..\Windows\SysWOW64\stdole2.tlb#OLE Automation +Module=Module1; ChangeTest.bas +Form=ChangeTest.frm +Startup="ChangeTest" +HelpFile="" +ExeName32="ChangeTest.exe" +Command32="" +Name="Project1" +HelpContextID="0" +CompatibleMode="0" +MajorVer=1 +MinorVer=0 +RevisionVer=0 +AutoIncrementVer=0 +ServerSupportFiles=0 +VersionCompanyName="Microcosm Ltd" +CompilationType=0 +OptimizationType=0 +FavorPentiumPro(tm)=0 +CodeViewDebugInfo=0 +NoAliasing=0 +BoundsCheck=0 +OverflowCheck=0 +FlPointCheck=0 +FDIVCheck=0 +UnroundedFP=0 +StartMode=0 +Unattended=0 +Retained=0 +ThreadPerObject=0 +MaxNumberOfThreads=1 + +[MS Transaction Server] +AutoRefresh=1 diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/DinkeyChange/ChangeTest.vbw b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/DinkeyChange/ChangeTest.vbw new file mode 100644 index 0000000..475402b --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/DinkeyChange/ChangeTest.vbw @@ -0,0 +1,2 @@ +Module1 = 525, 283, 1161, 899, +ChangeTest = 244, 99, 880, 715, , 66, 66, 702, 841, C diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/DinkeyChange/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/DinkeyChange/README.txt new file mode 100644 index 0000000..01ac826 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/DinkeyChange/README.txt @@ -0,0 +1,22 @@ +ChangeTest - sample code to call DinkeyChange.dll in Visual Basic +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Note: For VB.net code please look in the vb.net folder. + +The sample code contains 7 functions. Just use which ever functions are most +appropriate and customise in your own way. The sample code is just a guide. +As none of the parameters are sensitive then there is no need to implement +strong security in calling DinkeyChange. + +Note - to run the project from the IDE you will need to place the protected +DinkeyChange.dll in the 32-bit Windows System folder*. For release you can place +DinkeyChange.dll in the folder of the compiled executable or in the Windows System +directory. The former is generally considered better as it is easier to install. + +It is also recommended that you rename DinkeyChange.dll to a name of your choice. In +this case you will need to modify the dll name in the ChangeTest.bas file. + +~~~~~~~~~~~~~~~~~ +* Windows System folder for 32-bit dlls is: +c:\windows\system32 32-bit Windows +c:\windows\sysWOW64 64-bit Windows \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/Runtime/DllTest.vbp b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/Runtime/DllTest.vbp new file mode 100644 index 0000000..683c4be --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/Runtime/DllTest.vbp @@ -0,0 +1,35 @@ +Type=Exe +Form=Form1.frm +Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#C:\WINNT\system32\stdole2.tlb#OLE Automation +Module=Module1; dris.bas +IconForm="Form1" +Startup="Form1" +ExeName32="DllTest.exe" +Command32="" +Name="DllTest" +HelpContextID="0" +CompatibleMode="0" +MajorVer=1 +MinorVer=0 +RevisionVer=0 +AutoIncrementVer=0 +ServerSupportFiles=0 +VersionCompanyName="Microcosm Ltd" +CompilationType=0 +OptimizationType=0 +FavorPentiumPro(tm)=0 +CodeViewDebugInfo=0 +NoAliasing=0 +BoundsCheck=0 +OverflowCheck=0 +FlPointCheck=0 +FDIVCheck=0 +UnroundedFP=0 +StartMode=0 +Unattended=0 +Retained=0 +ThreadPerObject=0 +MaxNumberOfThreads=1 + +[MS Transaction Server] +AutoRefresh=1 diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/Runtime/DllTest.vbw b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/Runtime/DllTest.vbw new file mode 100644 index 0000000..ec4079a --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/Runtime/DllTest.vbw @@ -0,0 +1,2 @@ +Form1 = 243, 27, 938, 801, , 22, 22, 577, 462, C +Module1 = 22, 69, 888, 858, diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/Runtime/Form1.frm b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/Runtime/Form1.frm new file mode 100644 index 0000000..b0124f6 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/Runtime/Form1.frm @@ -0,0 +1,980 @@ +VERSION 5.00 +Begin VB.Form Form1 + Caption = "DllTest" + ClientHeight = 2940 + ClientLeft = 60 + ClientTop = 345 + ClientWidth = 4605 + LinkTopic = "Form1" + ScaleHeight = 2940 + ScaleWidth = 4605 + StartUpPosition = 3 'Windows Default + Begin VB.Label Label1 + Caption = "It Worked!" + BeginProperty Font + Name = "MS Sans Serif" + Size = 24 + Charset = 0 + Weight = 400 + Underline = 0 'False + Italic = 0 'False + Strikethrough = 0 'False + EndProperty + Height = 735 + Left = 1080 + TabIndex = 0 + Top = 840 + Width = 2535 + End +End +Attribute VB_Name = "Form1" +Attribute VB_GlobalNameSpace = False +Attribute VB_Creatable = False +Attribute VB_PredeclaredId = True +Attribute VB_Exposed = False + +' !! We strongly recommend that you read the "readme.txt" file for this sample. +' !! It contains important instructions on how to use the sample code + +' The sample code contains 13 functions. You will not need to use all these +' functions in your code. Just use which ever functions are most appropriate +' and customise in your own way. The sample code is just a guide. You should +' implement the protection in a stronger way using the techniques described in +' the "Increasing your Protection" chapter of the manual. +' +' The 13 functions are: +' ProtCheck a standard protection check +' ProtCheckWithAlg a protection check & executing an Algorithm +' WriteString a protection check & write data to the dongle +' ReadString a protection check & read data from the dongle +' WriteBytes a protection check & write data to the dongle +' ReadBytes a protection check & read data from the dongle +' EncryptUserData a protection check,& encrypting data and then decrypting the data +' +' these functions are the same as some of the functions listed above but encrypting all parameters passed to our API +' ProtCheckEnc a standard protection check +' ProtCheckWithAlgEnc a protection check & executing an Algorithm +' WriteBytesEnc a protection check & write data to the dongle +' ReadBytesEnc a protection check & read data from the dongle +' EncryptUserDataEnc a protection check & encrypting data and then decrypting the data +' +' DisplayNetUsers this function displays the current network users (network dongle only) + +' If you are using Dinkey Lite then you can only use 4 functions: +' ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + +' !!!! +Const MY_SDSN = 10101 ' !!!! change this value to be the value of your SDSN (demo = 10101) +Const MY_PRODCODE = "DEMO" ' !!!! change this value to match the Product Code in the dongle + + +Private Sub Form_Load() + +' call the function(s) of your choice here +' here I have chosen a standard protection check +If ProtCheck() <> 0 Then + End 'terminate +End If + +End Sub + +Function ProtCheck() As Long +Dim mydris As DRIS +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = PROTECTION_CHECK ' standard protection check +mydris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + +ret_code = DDProtCheck(mydris, 0) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ProtCheck = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ProtCheck = -1 + Exit Function +End If + +' NB to access product code you will need to use the TrimCString +If (TrimCString(mydris.prodcode) <> MY_PRODCODE) Then + MsgBox "Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", vbOKOnly, "Error" + ProtCheck = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ProtCheck = -1 + Exit Function +End If + +'to access product code you will need to use the TrimCString function like this: +'TrimCString(mydris.prodcode) + +'to access the dongle number you will need to use the ConvertToUnsigned function like this: +'ConvertToUnsigned(mydris.dongle_number) + +' NB if you are using a network dongle and you want to list the network users then use this function: +' DisplayNetUsers (mydris.net_users, mydris.model) + +ProtCheck = 0 +End Function + +' !!!! You should replace this function with the one generated by the +' "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) +' or from DinkeyLook if you are using Dinkey Lite dongles. +' see readme.txt notes concerning using the algorithm in VB +Private Function MyAlgorithm(ByVal a As Long, ByVal b As Long, ByVal c As Long, ByVal d As Long, ByVal e As Long, ByVal f As Long, ByVal g As Long, ByVal h As Long) As Long + MyAlgorithm = a + b + c + d + e + f + g + h +End Function + +' NB for this to work you must program at least "user algorithm" into the dongle +' NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +' sample code generated by DinkeyAdd for the algorithm that you are using. +Function ProtCheckWithAlg() As Long +Dim mydris As DRIS +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = EXECUTE_ALGORITHM ' standard protection check & execute an algorithm +mydris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... +mydris.alg_number = 1 ' execute first algorithm (you do not need to specify this field for Dinkey Lite dongles) +' you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random +mydris.var_a = 1 ' sample values +mydris.var_b = 2 +mydris.var_c = 3 +mydris.var_d = 4 +mydris.var_e = 5 +mydris.var_f = 6 +mydris.var_g = 7 +mydris.var_h = 8 + +ret_code = DDProtCheck(mydris, 0) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ProtCheckWithAlg = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ProtCheckWithAlg = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ProtCheckWithAlg = -1 + Exit Function +End If + +' if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code +' !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd +If MyAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) <> mydris.alg_answer Then + MsgBox "Dinkey Dongle protection error / You have not patched your algorithm in the MyAlgorithm routine", vbOKOnly, "Error" + ProtCheckWithAlg = -1 + Exit Function +End If + +ProtCheckWithAlg = 0 +End Function + + +' This writes the String "Hello, World" to the dongle data area at offset 7 +' In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +' If you want to write data that isn't a string use the WriteBytes function +Function WriteString() As Long +Dim mydris As DRIS +Dim StringToWrite As String * 13 +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = WRITE_DATA_AREA ' standard protection check and write data provided +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 13 + +StringToWrite = "Hello, World!" + +ret_code = DDProtCheckString(mydris, StringToWrite) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + WriteString = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + WriteString = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + WriteString = -1 + Exit Function +End If + +WriteString = 0 +End Function + + +' This writes the data 0,1,2,...19 to the dongle data area at offset 7 +' In order for this function to work you will need to have a data area in your dongle that is at least 28 bytes long. +' If you want to write strings it is easier to use the WriteString function +Function WriteData() As Long +Dim mydris As DRIS +Dim DataToWrite As FixedByteArray +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = WRITE_DATA_AREA ' standard protection check and write data provided +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 20 + +For i = 0 To 19 + DataToWrite.data(i) = i +Next + +ret_code = DDProtCheckData(mydris, DataToWrite) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + WriteData = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + WriteData = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + WriteData = -1 + Exit Function +End If + +WriteData = 0 +End Function + + +' This reads 13 bytes of data from offset 7 in the dongle data area +' In order for this function to work you will need to have a data area in your dongle that is at least 20 bytes long. +' In order for the data to be displayed properly by this routine it will need to be text data +Function ReadString() As Long +Dim mydris As DRIS +Dim StringToRead As String * 13 +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = READ_DATA_AREA ' standard protection check and read data +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 13 + +ret_code = DDProtCheckString(mydris, StringToRead) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ReadString = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ReadString = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ReadString = -1 + Exit Function +End If + +MsgBox "Dinkey Data Area at offset 7 contains: " + StringToRead, vbOKOnly + +ReadString = 0 +End Function + + +' This reads 20 bytes of data from offset 7 in the dongle data area +' In order for this function to work you will need to have a data area in your dongle that is at least 27 bytes long. +Function ReadData() As Long +Dim mydris As DRIS +Dim DataToRead As FixedByteArray +Dim ret_code As Long +Dim DisplayString As String + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = READ_DATA_AREA ' standard protection check and write data provided +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 20 + +ret_code = DDProtCheckData(mydris, DataToRead) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ReadData = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ReadData = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ReadData = -1 + Exit Function +End If + +DisplayString = "Dinkey Data Area at offset 7 contains: " +For i = 0 To 19 + DisplayString = DisplayString + Str(DataToRead.data(i)) +Next + +MsgBox DisplayString, vbOKOnly +ReadData = 0 +End Function + +' This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +' It will then do another protection check & decrypt the data +' The data used in this example is 0,1,2...19. If you wanted to encrypt and/or decrypt Strings +' then you could use a technique similar to that employed in WriteString & ReadString +Function EncryptUserData() As Long +Dim mydris As DRIS +Dim MyData As FixedByteArray +Dim DisplayString As String +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = ENCRYPT_USER_DATA ' standard protection check & encrypt data +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.data_crypt_key_num = 1 +mydris.rw_length = 20 + +For i = 0 To 19 ' initialise data + MyData.data(i) = i +Next + +ret_code = DDProtCheckData(mydris, MyData) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + EncryptUserData = ret_code + Exit Function +End If + +' ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn as per previous example functions + +' Now decrypt the same data to get the original values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = DECRYPT_USER_DATA ' standard protection check & decrypt data +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.data_crypt_key_num = 1 +mydris.rw_length = 20 + +ret_code = DDProtCheckData(mydris, MyData) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + EncryptUserData = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + EncryptUserData = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + EncryptUserData = -1 + Exit Function +End If + +DisplayString = "Decrypted Data is : " +For i = 0 To 19 + DisplayString = DisplayString + Str(MyData.data(i)) +Next + +MsgBox DisplayString, vbOKOnly +EncryptUserData = 0 +End Function + +' !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! +' In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" +' in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm +' but the code can be modified easily to use the 3 encryption parameters. + +' !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm +Private Function MyRWAlgorithm(ByVal a As Long, ByVal b As Long, ByVal c As Long, ByVal d As Long, ByVal e As Long, ByVal f As Long, ByVal g As Long, ByVal h As Long) As Long + MyRWAlgorithm = a Xor b Xor c Xor d Xor e Xor f + MyRWAlgorithm = MyRWAlgorithm And &HFFFFFF ' we only use bottom 3 bytes and -ve numbers can cause problems with CryptApiData +End Function + +' !!!! please overwrite this function with the one generated by DinkeyAdd +Private Sub CryptDRIS(mydris As DRIS) + Dim i, j, k, t As Integer + Dim bigseed(256) As Byte + Dim S(256) As Byte + Dim temp As Byte + Dim temp_dris(Len(mydris)) As Byte + + Call CopyMemory(temp_dris(0), mydris, Len(mydris)) + For i = 0 To 255 Step 8 + Call CopyMemory(bigseed(i), mydris.seed1, 4) + Call CopyMemory(bigseed(i + 4), mydris.seed2, 4) + Next + For i = 0 To 255 + S(i) = i + Next + j = 0 + For i = 0 To 255 + j = (j + CInt(S(i)) + CInt(bigseed(i)) + 123) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + Next + i = 0 + j = 0 + For k = 16 To Len(mydris) - 1 + i = (i + 1) Mod 256 + j = (j + CInt(S(i)) + 212) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + t = (CInt(S(i)) + CInt(S(j)) + 97) Mod 256 + temp_dris(k) = temp_dris(k) Xor S(t) + Next + + Call CopyMemory(mydris, temp_dris(0), Len(mydris)) +End Sub + +' !!!! please overwrite this function with the one generated by DinkeyAdd +Private Sub CryptApiData(ByRef data() As Byte, ByVal length As Long, ByVal seed1 As Long, ByVal seed2 As Long, ByVal AlgAnswer As Long) + Dim i, j, k, t As Integer + Dim bigseed(256) As Byte + Dim S(256) As Byte + Dim temp As Byte + + For i = 0 To 255 Step 8 + Call CopyMemory(bigseed(i), seed1, 4) + Call CopyMemory(bigseed(i + 4), seed2, 4) + Next + For i = 0 To 255 + S(i) = i + Next + j = 0 + For i = 0 To 255 + j = (j + CInt(S(i)) + CInt(bigseed(i)) + (AlgAnswer And &HFF)) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + Next + i = 0 + j = 0 + For k = 0 To length - 1 + i = (i + 1) Mod 256 + j = (j + CInt(S(i)) + ((AlgAnswer \ &H100) And &HFF)) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + t = (CInt(S(i)) + CInt(S(j)) + ((AlgAnswer \ &H10000) And &HFF)) Mod 256 + data(k) = data(k) Xor S(t) + Next +End Sub + +' We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +Function ProtCheckEnc() As Long +Dim mydris As DRIS +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = PROTECTION_CHECK ' standard protection check +mydris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheck(mydris, 0) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ProtCheckEnc = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ProtCheckEnc = -1 + Exit Function +End If + +' NB to access product code you will need to use the TrimCString +If (TrimCString(mydris.prodcode) <> MY_PRODCODE) Then + MsgBox "Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", vbOKOnly, "Error" + ProtCheckEnc = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ProtCheckEnc = -1 + Exit Function +End If + +ProtCheckEnc = 0 +End Function + + +' NB for this to work you must program at least "user algorithm" into the dongle +' NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +' sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite copy source from DinkeyLook. +' We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +Function ProtCheckWithAlgEnc() As Long +Dim mydris As DRIS +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = EXECUTE_ALGORITHM ' standard protection check & execute an algorithm +mydris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... +mydris.alg_number = 1 ' execute first algorithm - you do not need to specify this field if you are only using Lite models +' you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random +mydris.var_a = 1 ' sample values +mydris.var_b = 2 +mydris.var_c = 3 +mydris.var_d = 4 +mydris.var_e = 5 +mydris.var_f = 6 +mydris.var_g = 7 +mydris.var_h = 8 + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheck(mydris, 0) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ProtCheckWithAlgEnc = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ProtCheckWithAlgEnc = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ProtCheckWithAlgEnc = -1 + Exit Function +End If + +' if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code +' !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd +If MyAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) <> mydris.alg_answer Then + MsgBox "Dinkey Dongle protection error / You have not patched your algorithm in the MyAlgorithm routine", vbOKOnly, "Error" + ProtCheckWithAlgEnc = -1 + Exit Function +End If + +ProtCheckWithAlgEnc = 0 +End Function + + +' This writes the data 0,1,2,...19 to the dongle data area at offset 7 +' In order for this function to work you will need to have a data area in your dongle that is at least 28 bytes long. +' We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +Function WriteDataEnc() As Long +Dim mydris As DRIS +Dim DataToWrite As FixedByteArray +Dim ret_code As Long +Dim alg_ans As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = WRITE_DATA_AREA ' standard protection check and write data provided +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 20 +' NB we restrict the algorithm variables to be 24-bit values to avoid any possible overruns in the algorithm +mydris.var_a = Rand(&HFFFFFF) ' random values +mydris.var_b = Rand(&HFFFFFF) +mydris.var_c = Rand(&HFFFFFF) +mydris.var_d = Rand(&HFFFFFF) +mydris.var_e = Rand(&HFFFFFF) +mydris.var_f = Rand(&HFFFFFF) +mydris.var_g = Rand(&HFFFFFF) +mydris.var_h = Rand(&HFFFFFF) + +For i = 0 To 19 ' initialise data to write + DataToWrite.data(i) = i +Next + +' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm +alg_ans = MyRWAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) + +' encrypt data we want to write. +Call CryptApiData(DataToWrite.data, 20, mydris.seed1, mydris.seed2, alg_ans) + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheckData(mydris, DataToWrite) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + WriteDataEnc = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + WriteDataEnc = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + WriteDataEnc = -1 + Exit Function +End If + +WriteDataEnc = 0 +End Function + + +' This reads 20 bytes of data from offset 7 in the dongle data area +' In order for this function to work you will need to have a data area in your dongle that is at least 27 bytes long. +' We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +Function ReadDataEnc() As Long +Dim mydris As DRIS +Dim DataToRead As FixedByteArray +Dim ret_code As Long +Dim DisplayString As String + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = READ_DATA_AREA ' standard protection check and write data provided +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 20 +' NB we restrict the algorithm variables to be 24-bit values to avoid any possible overruns in the algorithm +mydris.var_a = Rand(&HFFFFFF) ' random values +mydris.var_b = Rand(&HFFFFFF) +mydris.var_c = Rand(&HFFFFFF) +mydris.var_d = Rand(&HFFFFFF) +mydris.var_e = Rand(&HFFFFFF) +mydris.var_f = Rand(&HFFFFFF) +mydris.var_g = Rand(&HFFFFFF) +mydris.var_h = Rand(&HFFFFFF) + +' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm +alg_ans = MyRWAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheckData(mydris, DataToRead) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ReadDataEnc = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ReadDataEnc = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ReadDataEnc = -1 + Exit Function +End If + +' decrypt data we have just read +Call CryptApiData(DataToRead.data, 20, mydris.seed1, mydris.seed2, alg_ans) + +DisplayString = "Dinkey Data Area at offset 7 contains: " +For i = 0 To 19 + DisplayString = DisplayString + Str(DataToRead.data(i)) +Next + +MsgBox DisplayString, vbOKOnly +ReadDataEnc = 0 +End Function + +' This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +' It will then do another protection & decrypt the data +' We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +Function EncryptUserDataEnc() As Long +Dim mydris As DRIS +Dim MyData As FixedByteArray +Dim DisplayString As String +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = ENCRYPT_USER_DATA ' standard protection check & encrypt data +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.data_crypt_key_num = 1 +mydris.rw_length = 20 +' NB we restrict the algorithm variables to be 24-bit values to avoid any possible overruns in the algorithm +mydris.var_a = Rand(&HFFFFFF) ' random values +mydris.var_b = Rand(&HFFFFFF) +mydris.var_c = Rand(&HFFFFFF) +mydris.var_d = Rand(&HFFFFFF) +mydris.var_e = Rand(&HFFFFFF) +mydris.var_f = Rand(&HFFFFFF) +mydris.var_g = Rand(&HFFFFFF) +mydris.var_h = Rand(&HFFFFFF) + +For i = 0 To 19 ' initialise data + MyData.data(i) = i +Next + +' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm +alg_ans = MyRWAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) + +' encrypt data we want to pass. +Call CryptApiData(MyData.data, 20, mydris.seed1, mydris.seed2, alg_ans) + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheckData(mydris, MyData) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + EncryptUserDataEnc = ret_code + Exit Function +End If + +' ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn as per previous example functions + +' Now decrypt the same data to get the original values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = DECRYPT_USER_DATA ' standard protection check & decrypt data +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.data_crypt_key_num = 1 +mydris.rw_length = 20 +' NB we restrict the algorithm variables to be 24-bit values to avoid any possible overruns in the algorithm +mydris.var_a = Rand(&HFFFFFF) ' random values +mydris.var_b = Rand(&HFFFFFF) +mydris.var_c = Rand(&HFFFFFF) +mydris.var_d = Rand(&HFFFFFF) +mydris.var_e = Rand(&HFFFFFF) +mydris.var_f = Rand(&HFFFFFF) +mydris.var_g = Rand(&HFFFFFF) +mydris.var_h = Rand(&HFFFFFF) + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheckData(mydris, MyData) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + EncryptUserDataEnc = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + EncryptUserDataEnc = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + EncryptUserDataEnc = -1 + Exit Function +End If + +' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm +alg_ans = MyRWAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) + +' decrypt data passed to us from the API. +Call CryptApiData(MyData.data, 20, mydris.seed1, mydris.seed2, alg_ans) + +DisplayString = "Decrypted Data is : " +For i = 0 To 19 + DisplayString = DisplayString + Str(MyData.data(i)) +Next + +MsgBox DisplayString, vbOKOnly +EncryptUserDataEnc = 0 +End Function + +' This function displays the current network users (for DinkeyNet only). +' The DDProtCheck function must be called before this function is called. +' (Normally you would use DinkeyServer to view the network users but this enables you to do it from the client if you want) +Function DisplayNetUsers(net_users As Integer, model As Integer) As Integer + Dim num_net_users, extended_error, ret_code, i, max_net_users As Long + Dim DisplayString As String + Dim nu_info_bytes As LargeFixedByteArray ' !!!! only contains space for info for up to 20 net users. If you want more then you must change the type definition + + If net_users = -1 Then + max_net_users = 20 ' if unlimited network users are allowed then display up to 20 users (for example, to change this limit see note above) + Else + max_net_users = net_users + End If + + If max_net_users = 0 Then ' no network users are allowed, so nothing to do! + DisplayNetUsers = 0 + Exit Function + End If + + If model < 3 Then + MsgBox "A network dongle has not been detected. Therefore you cannot display the network users.", vbOKOnly + DisplayNetUsers = -1 + Exit Function + End If + + ' now get net users + ret_code = DDGetNetUserList("", num_net_users, nu_info_bytes, max_net_users, extended_error) + + If ret_code <> 0 Then + MsgBox "Error " + Str$(ret_code) + "/" + Str$(extended_error) + " finding network user information.", vbOKOnly + Else + DisplayString = "number of net users: " + Str(num_net_users) + vbNewLine + For i = 0 To num_net_users - 1 + DisplayString = DisplayString + Str$(i + 1) + ". licence: " + GetLicenceName(nu_info_bytes, i) + ", user: " + GetUserName(nu_info_bytes, i) + ", computer: " + GetComputerName(nu_info_bytes, i) + ", ip address: " + GetIpAddress(nu_info_bytes, i) + vbNewLine + Next + MsgBox DisplayString, vbOKOnly, "Net Users" + End If + DisplayNetUsers = ret_code + +End Function + +' look at the error code and try to display an appropriate message +Public Sub DisplayError(ret_code As Long, extended_error As Long) + Select Case ret_code + Case 401 + MsgBox "Error! No dongles detected!", vbOKOnly, "Error" + Case 403 + MsgBox "Error! A dongle was detected but it was a different type to the one specified in DinkeyAdd.", vbOKOnly, "Error" + Case 404 + MsgBox "Error! A dongle was detected but it was a different model to those specified in DinkeyAdd.", vbOKOnly, "Error" + Case 409 + MsgBox "Error! The dongle detected has not been programmed by DinkeyAdd.", vbOKOnly, "Error" + Case 410 + MsgBox "Error! A dongle was detected but it has a different Product Code to the one specified in DinkeyAdd.", vbOKOnly, "Error" + Case 411 + MsgBox "Error! The dongle detected does not contain the licence associated with this program.", vbOKOnly, "Error" + Case 413 + MsgBox "Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual.", vbOKOnly, "Error" + Case 417 + MsgBox "Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.", vbOKOnly, "Error" + Case 423 + MsgBox "Error! The number of network users has been exceeded.", vbOKOnly, "Error" + Case 435 + MsgBox "Error! DinkeyServer has not been detected on the network.", vbOKOnly, "Error" + Case 922 + MsgBox "Error! The Software Key has expired.", vbOKOnly, "Error" + Case Else + MsgBox "An error occurred checking the dongle. Error: " + Str$(ret_code) + ". Extended Error: " + Str$(extended_error) + ".", vbOKOnly, "Error" + End Select +End Sub diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/Runtime/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/Runtime/README.txt new file mode 100644 index 0000000..3e58f76 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/Runtime/README.txt @@ -0,0 +1,64 @@ +DllTest - sample code to call dpwin32.dll in Visual Basic +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Basic 6.0 but will the code will also +work in version 5.0 (but you will have to create your own project). + +For VB.net code please look in the vb.net folder. + +The source files in the project are: + +File name Folder Description +Form1.frm Samples\vb main source code file for VB +dris.bas Samples\vb contains the DRIS structure & function declarations + +The idea is to include the dris.bas file in your project and use/modify which ever +functions from form1.frm you feel are appropriate. + +The sample code contains 13 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. + +Note - you should protect dpwin32.dll and not your program. Because your program +is linked to the DLL it is protected. + +Note - to run the project from the IDE you will need to place the protected +dpwin32.dll in the 32-bit Windows System folder*. For release you can place +dpwin32.dll in the folder of the compiled executable or in the Windows System folder. +The former is generally considered better as it is easier to install. + +It is also recommended that you rename dpwin32.dll to a name of your choice. In +this case you will need to modify the dll name in the dris.bas file. + +Special Note for using Algorithms in Visual Basic +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The algorithms are calculated on 32-bit integers (Long in VB). It is quite possible for +the MyAlgorithm and MyRWAlgorithm functions to overflow if the values provided are too big. +In the dongle the algorithms can never overflow - if the answer is too big then the high part +of the answer is ignored. In practical terms: + +When you are using the r/w algorithm it is best not to pass random 32-bit integers. It is +better to restrict the variables to 24-bit to avoid the possibility of overflows. + +When using a user algorithm it will behave exactly as the corresponding MyAlgorithm function +will in VB except it will not give overflow errors. + +~~~~~~~~~~~~~~~~~ +* Windows System folder for 32-bit dlls is: +c:\windows\system32 32-bit Windows +c:\windows\sysWOW64 64-bit Windows \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/Runtime/dris.bas b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/Runtime/dris.bas new file mode 100644 index 0000000..10d6a64 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Visual Basic/Runtime/dris.bas @@ -0,0 +1,214 @@ +' !! this file should not be modified + +Attribute VB_Name = "Module1" +' API functions +' DDProtCheck - so we can ignore the second argument +Declare Function DDProtCheck Lib "dpwin32.dll" (mydris As DRIS, data As String) As Long +' DDProtCheckString - so we can pass data as a String +Declare Function DDProtCheckString Lib "dpwin32.dll" Alias "DDProtCheck" (mydris As DRIS, ByVal String1 As Any) As Long +' DDProtCheckData - so we can pass data in any format +Declare Function DDProtCheckData Lib "dpwin32.dll" Alias "DDProtCheck" (mydris As DRIS, data As FixedByteArray) As Long +' DDGetNetUserList +Declare Function DDGetNetUserList Lib "dpwin32.dll" (ByVal licence_name As Any, num_net_users As Long, nu_info_bytes As LargeFixedByteArray, ByVal num_info_structs As Long, extended_error As Long) As Long + +'Dinkey Runtime Information Structure (DRIS) +Type DRIS + ' the first 4 fields are never encrypted + header As String * 4 ' should be set to DRIS + ' inputs + size As Long ' size of this structure + seed1 As Long ' seed for data/dris encryption + seed2 As Long ' as above + ' (maybe encrypted from now on) + function As Long ' specify only one function + flags As Long ' options for the function selected. To use more than one OR them together: OPTION1 Or OPTION2... + execs_decrement As Long ' amount by which to dec execs if we use flag: DEC_MANY_EXECS + data_crypt_key_num As Long ' number of the key (1-3) that the dongle uses to encrypt or decrypt user data + rw_offset As Long ' offset in the dongle data area to read or write data + rw_length As Long ' length of data are to read/write/encrypt/decrypt + not_used As Long ' pass the data as a parameter instead for VB + alt_licence_name As String * 256 ' protection check for different licence instead of the default one, must be null-terminated ascii + var_a As Long ' variable values for user algorithms + var_b As Long + var_c As Long + var_d As Long + var_e As Long + var_f As Long + var_g As Long + var_h As Long + alg_number As Long ' the number of the user algorithm that you want to execute + + ' outputs + ret_code As Long ' the return code from the protection check + ext_err As Long ' extended error + type As Long ' type of dongle detected. 1 = Pro, 2 = FD + model As Long ' model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + sdsn As Long ' Software Developer's Serial Number + prodcode As String * 12 ' product code (null-terminated) + dongle_number As Long ' dongle number. This number should be converted to a positive value using ConvertToUnsigned before being displayed otherwise it my appear as a negative number. + update_number As Long + data_area_size As Long ' size of the data area in the dongle detected + max_alg_num As Long ' the maximum algorithm number in the dongle detected + execs As Long ' executions left: -1 indicates 'no limit' + exp_day As Long ' expiry day: -1 indicates 'no limit' + exp_month As Long ' expiry month: -1 indicates 'no limit' + exp_year As Long ' expiry year: -1 indicates 'no limit' + features As Long ' features value + net_users As Long ' maximum number of network users for the dongle detected: -1 indicates 'mo limit' + alg_answer As Long ' answer to the user algorithm executed with the given variable values + fd_capacity As Long ' capacity of the data area in FD dongle. + fd_drive As String * 128 ' drive letter of FD dongle detected e.g. 'f:\' + swkey_type As Long ' 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + swkey_exp_day As Long ' software key expiry date (if software key detected) + swkey_exp_month As Long + swkey_exp_year As Long +End Type + +'we need a structure for an array of bytes because otherwise the VB runtime can move the data in-between function calls +Type FixedByteArray + data(0 To 1023) As Byte +End Type + +'this is a similar structure that can be used for the DDGetNetUserList call. +'!!!! this structure will acommodate info for upto 20 net users. If you want to alow for more then increase the array size +Public Const NU_INFO_SIZE = (256 + 50 + 256 + 16) +Type LargeFixedByteArray + data(0 To NU_INFO_SIZE * 20) As Byte +End Type + +' Functions +Public Const PROTECTION_CHECK = 1 ' checks for dongle, check program params... +Public Const EXECUTE_ALGORITHM = 2 ' protection check + calculate answer for specified algorithm with specified inputs +Public Const WRITE_DATA_AREA = 3 ' protection check + writes dongle data area +Public Const READ_DATA_AREA = 4 ' protection check + reads dongle data area +Public Const ENCRYPT_USER_DATA = 5 ' protection check + the dongle will encrypt user data +Public Const DECRYPT_USER_DATA = 6 ' protection check + the dongle will decrypt user data +Public Const FAST_PRESENCE_CHECK = 7 ' checks for the presence of the correct dongle only with minimal security, no flags allowed +Public Const STOP_NET_USER = 8 ' stops a network user (a protection check is NOT performed) + +' Flags +Public Const DEC_ONE_EXEC = 1 ' decrement execs by 1 +Public Const DEC_MANY_EXECS = 2 ' decrement execs by number specified in execs +Public Const START_NET_USER = 4 ' starts a network user +Public Const USE_FUNCTION_ARGUMENT = 16 ' use the extra argument in the function for pointers +Public Const CHECK_LOCAL_FIRST = 32 ' always look in local ports before looking in network ports +Public Const CHECK_NETWORK_FIRST = 64 ' always look on the network before looking in local ports +Public Const USE_ALT_LICENCE_NAME = 128 ' use name specified in alt_licence_name instead of the default one +Public Const DONT_SET_MAXDAYS_EXPIRY = 256 ' if the max days expiry date has not been calculated then do not do it this time +Public Const MATCH_DONGLE_NUMBER = 512 ' restrict the search to match the dongle number specified in the DRIS +Public Const DONT_RETURN_FD_DRIVE = 1024 ' if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + +' Useful functions +Declare Sub CopyMemory Lib "KERNEL32" Alias "RtlMoveMemory" (lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long) + +' given the maximum possible value generate a random number between 0 and the maximum +Public Function Rand(ByVal High As Long) As Long + Rand = Int((High + 1) * Rnd) +End Function + +' initialise the DRIS with random values +Public Sub RandomSet(mydris As DRIS) + Dim temp_dris(Len(mydris)) As Byte + + Randomize + + Call CopyMemory(temp_dris(0), mydris, Len(mydris)) + For i = 0 To Len(mydris) - 1 + temp_dris(i) = Rand(255) + Next + Call CopyMemory(mydris, temp_dris(0), Len(mydris)) +End Sub + +' this function will convert the C string returned in the DRIS to a VB string +' e.g. to access the product code use TrimCString(mydris.prodcode) +Public Function TrimCString(Str As String) As String + Dim i As Integer + Dim length As Integer + + length = Len(Str) + + For i = 1 To length + If Mid(Str, i, 1) = Chr$(0) Then + TrimCString = Left$(Str, i - 1) 'take off null and rest of string + Exit For + End If + Next + +End Function + +' this function should be used if you want to display the dongle_number. It will always display as a positive value +Public Function ConvertToUnsigned(number As Long) As Double +If (number >= 0) Then + ConvertToUnsigned = number +Else + ConvertToUnsigned = number + 4294967296# +End If +End Function + +' routine to extract Licence Name from array of NU_INFO structures (implemented as a LargeFixedByteArray) +Public Function GetLicenceName(nu_info_bytes As LargeFixedByteArray, ByVal index As Long) As String + Dim data As Byte ' this will be a byte of data from array + Dim start As Long + + start = (index * NU_INFO_SIZE) + 0 + GetLicenceName = "" + For i = 0 To 255 + data = nu_info_bytes.data(start + i) + If data = 0 Then ' stop when we get to the null + Exit For + Else ' otherwise append character to string + GetLicenceName = GetLicenceName & Chr(data) + End If + Next +End Function + +' routine to extract User Name from array of NU_INFO structures (implemented as a LargeFixedByteArray) +Public Function GetUserName(nu_info_bytes As LargeFixedByteArray, ByVal index As Long) As String + Dim data As Byte ' this will be a byte of data from array + Dim start As Long + + start = (index * NU_INFO_SIZE) + 256 + GetUserName = "" + For i = 0 To 49 + data = nu_info_bytes.data(start + i) + If data = 0 Then ' stop when we get to the null + Exit For + Else ' otherwise append character to string + GetUserName = GetUserName & Chr(data) + End If + Next +End Function + +' routine to extract Computer Name from array of NU_INFO structures (implemented as a LargeFixedByteArray) +Public Function GetComputerName(nu_info_bytes As LargeFixedByteArray, ByVal index As Long) As String + Dim data As Byte ' this will be a byte of data from array + Dim start As Long + + start = (index * NU_INFO_SIZE) + 256 + 50 + GetComputerName = "" + For i = 0 To 255 + data = nu_info_bytes.data(start + i) + If data = 0 Then ' stop when we get to the null + Exit For + Else ' otherwise append character to string + GetComputerName = GetComputerName & Chr(data) + End If + Next +End Function + +' routine to extract ipAddress from array of NU_INFO structures (implemented as a LargeFixedByteArray) +Public Function GetIpAddress(nu_info_bytes As LargeFixedByteArray, ByVal index As Long) As String + Dim data As Byte ' this will be a byte of data from array + Dim start As Long + + start = (index * NU_INFO_SIZE) + 256 + 50 + 256 + GetIpAddress = "" + For i = 0 To 15 + data = nu_info_bytes.data(start + i) + If data = 0 Then ' stop when we get to the null + Exit For + Else ' otherwise append character to string + GetIpAddress = GetIpAddress & Chr(data) + End If + Next +End Function diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/WinDev/DinkeyChange/DinkeyChange functions.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/WinDev/DinkeyChange/DinkeyChange functions.txt new file mode 100644 index 0000000..a866ea8 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/WinDev/DinkeyChange/DinkeyChange functions.txt @@ -0,0 +1,299 @@ +// sample functions for calling DinkeyChange.dll. + + +// Summary: Displays the error code with a helpful error message. You may want to change the messages. +// Syntax: +//DisplayChangeError ( is int, is int) +PROCEDURE DisplayChangeError(ret_code is int, ext_err is int) +SWITCH ret_code + CASE 401: Info("Error! No dongles detected that meet the search criteria!") + CASE 409: Info("Error! The dongle detected has not been programmed by DinkeyAdd.") + CASE 758: Info("Error! Cannot open the Update Code file specified.") + CASE 759: Info("Error! The file specified is not a valid Update Code file.") + CASE 762 TO 764: Info("Error! Update Code is not in a correct format / update code file is corrupt.") + CASE 765: Info("Error! The Update Code does not match any dongle attached to your machine.") + CASE 766: Info("Error! The update number for this Update Code is too high. You need to first enter an update code that was previously sent to you.") + CASE 767: Info("Error! You have already entered this Update Code.") + CASE 1905: Info("Error! There is no Software Key available for download.") + CASE 1907: Info("Error! The Temporary Software Key has expired. Cannot download it.") + CASE 1910: Info("Error! The Software Key has already been downloaded.") + CASE 1921: Info("Error! You specified the 'default model' but there is more than one model available. You need to specify a specific dongle model.") + CASE 1922: Info("Error! The model you requested is not available.") + CASE 1923: Info("Error! The Demo Software Key Template has been disabled.") + CASE 1924: Info("Error! You have run out of Demo Software Key activations. You need to order some more.") + OTHER CASE: Info("An error occurred updating the dongle.","Error: " + ret_code, "Extended Error: " + ext_err) +END + + +// Summary: gets the product code, dongle number and update number for all dongles attached that meet the specify search criteria +// Syntax: +//[ = ] GetDongleInfo () +PROCEDURE GetDongleInfo() +hLib, ret_code are system int +type, model, update_number are fixed array of MAX_USB_DEVICES int +dongle_number is a fixed array of MAX_USB_DEVICES unsigned int +prodcode is a fixed array of MAX_USB_DEVICES fixed strings on MAX_PRODCODE_LEN +num_found is int +sDisplayMsg, sType, sModel are strings + +// Load the DinkeyChange.dll +hLib = LoadDLL(changedllname) +IF hLib = 0 THEN + Info("Cannot load " + changedllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +// get dongle information +ret_code = CallDLL32(changedllname, "DCGetInfo", TYPE_MASK_ALL, MODEL_MASK_DEFAULT, Null, MAX_USB_DEVICES, &num_found, &type, &model, &prodcode, &dongle_number, &update_number) +FreeDLL(hLib) + +IF ret_code <> 0 THEN + DisplayChangeError(ret_code, 0) + RESULT ret_code +END + +// display details on the dongles detected +sDisplayMsg = "Dongle Information:" + CR +FOR i = 1 TO num_found + // get type of dongle + IF type[i] = TYPE_PRO THEN + sType = "Pro" + ELSE + sType = "FD" + END + // get model of dongle + IF model[i] = MODEL_LITE THEN + sModel = "Lite" + ELSE IF model[i] = MODEL_PLUS THEN + sModel = "Plus" + ELSE + sModel = "Net" + END + sDisplayMsg += i + ". Dinkey " + sType + " " + sModel + " with dongle number " + dongle_number[i] + " product code " + ExtractString(prodcode[i], 1, Charact(0)) + " update number " + update_number[i] + CR +END + +Info(sDisplayMsg) + + +// Summary: collect diagnostic information from the system and write to a file +// Syntax: +//[ = ] GetDiagnosticInfo ( is string) +PROCEDURE GetDiagnosticInfo(sDiagPath is string) +hLib, ret_code are system int + +// Load the DinkeyChange.dll +hLib = LoadDLL(changedllname) +IF hLib = 0 THEN + Info("Cannot load " + changedllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +// get diagnostic info +ret_code = CallDLL32(changedllname, "DCGetDiagnosticInfo", sDiagPath) +FreeDLL(hLib) + +IF ret_code = 754 THEN + Info("Could not create the diagnostic file. Please check that the path exists:" + sDiagPath) + RESULT ret_code +END + +IF ret_code <> 0 THEN + Info("Error " + ret_code + " writing diagnostic information") + RESULT ret_code +END + +Info("Diagnostic file written successfully") + + +// Summary: updates the dongle attached using the update code passed +// Syntax: +//[ = ] UpdateCodeString ( is string) +// +// Parameters: +// sUpdateString (string): + +PROCEDURE UpdateCodeString(sUpdateString is string) +hLib, ret_code are system int +extended_error, confirmation_code are int + +// Load the DinkeyChange.dll +hLib = LoadDLL(changedllname) +IF hLib = 0 THEN + Info("Cannot load " + changedllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +// update dongle +ret_code = CallDLL32(changedllname, "DCDoUpdateCodeString", sUpdateString, &confirmation_code, &extended_error) +FreeDLL(hLib) + +IF ret_code <> 0 THEN + DisplayChangeError(ret_code, extended_error) + RESULT ret_code +END + +Info("Dongle updated successfully.", "Confirmation Code is " + NumToString(confirmation_code, "04x")) + + +// Summary: updates the dongle attached using the update code passed +// Syntax: +//[ = ] UpdateCodeFromFile ( is string) +// +// Parameters: +// sUpdateCodeFile (string) + +PROCEDURE UpdateCodeFromFile(sUpdateCodeFile is string) +hLib, ret_code are system int +extended_error, confirmation_code are int + +// Load the DinkeyChange.dll +hLib = LoadDLL(changedllname) +IF hLib = 0 THEN + Info("Cannot load " + changedllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +// update dongle +ret_code = CallDLL32(changedllname, "DCDoUpdateCodeFromFile", sUpdateCodeFile, &confirmation_code, &extended_error) +FreeDLL(hLib) + +IF ret_code <> 0 THEN + DisplayChangeError(ret_code, extended_error) + RESULT ret_code +END + +Info("Dongle updated successfully.", "Confirmation Code is " + NumToString(confirmation_code, "04x")) + + +// Summary: attempts to restore a corrupt Dinkey FD Lite dongle +// Syntax: +//[ = ] RestoreDinkeyFDLite () +// +// Parameters: none + +PROCEDURE RestoreDinkeyFDLite() +hLib, ret_code are system int + +// Load the DinkeyChange.dll +hLib = LoadDLL(changedllname) +IF hLib = 0 THEN + Info("Cannot load " + changedllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +ret_code = CallDLL32(changedllname, "DCRetoreDinkeyFDLite") +FreeDLL(hLib) + +IF ret_code <> 0 THEN + DisplayChangeError(ret_code, extended_error) + RESULT ret_code +END + +Info("Dinkey FD has been restored successfully.") + + +// Summary: displays the machine ID of the current computer +// Syntax: +//[ = ] GetMachineID () +// + +PROCEDURE GetMachineID() +hLib, ret_code are system int +extended_error is int +machineID is unsigned int + +// Load the DinkeyChange.dll +hLib = LoadDLL(changedllname) +IF hLib = 0 THEN + Info("Cannot load " + changedllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +ret_code = CallDLL32(changedllname, "DCGetMachineID", &machineID, &extended_error) +FreeDLL(hLib) + +IF ret_code <> 0 THEN + DisplayChangeError(ret_code, extended_error) + RESULT ret_code +END + +Info("Machine ID is: " + NumToString(machineID, "08x")) + + +// Summary: tries to download an available temporary software key for this machine +// Syntax: +//[ = ] DownloadTempSoftwareKey () +// + +PROCEDURE DownloadTempSoftwareKey() +hLib, ret_code are system int +extended_error is int +machineID is unsigned int + +// Load the DinkeyChange module +hLib = LoadDLL(changedllname) +IF hLib = 0 THEN + Info("Cannot load " + changedllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +// first call GetMachineID to get the machine ID value +ret_code = CallDLL32(changedllname, "DCGetMachineID", &machineID, &extended_error) + +IF ret_code <> 0 THEN + DisplayChangeError(ret_code, extended_error) + RESULT ret_code +END + +// then try to download a temporary software key for that machine ID +ret_code = CallDLL32(changedllname, "DCDownloadTempSoftwareKey", machineID, &extended_error) +FreeDLL(hLib) + +IF ret_code <> 0 THEN + DisplayChangeError(ret_code, extended_error) + RESULT ret_code +END + +Info("The Temporary Software Key has been downloaded successfully.") + + +// Summary: tries to download a demo software key for this machine +// Syntax: +//[ = ] DownloadDemoSoftwareKey ( is string) +// +// Parameters: +// sProdCode (string) +// + +PROCEDURE DownloadDemoSoftwareKey(sProdCode is string) +hLib, ret_code are system int +extended_error is int +machineID is unsigned int + +// Load the DinkeyChange module +hLib = LoadDLL(changedllname) +IF hLib = 0 THEN + Info("Cannot load " + changedllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +// first call GetMachineID to get the machine ID value +ret_code = CallDLL32(changedllname, "DCGetMachineID", &machineID, &extended_error) + +IF ret_code <> 0 THEN + DisplayChangeError(ret_code, extended_error) + RESULT ret_code +END + +// then try to download a demo software key +// (NB we are assuming only one dongle model is set in the Demo Software Template. +// If multiple models are set you will also need to specify the exact model) +ret_code = CallDLL32(changedllname, "DCDownloadDemoSoftwareKey", machineID, sProdCode, SWKEY_MODEL_DEFAULT, &extended_error) +FreeDLL(hLib) + +IF ret_code <> 0 THEN + DisplayChangeError(ret_code, extended_error) + RESULT ret_code +END + +Info("The Demo Software Key has been downloaded successfully.") diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/WinDev/DinkeyChange/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/WinDev/DinkeyChange/README.txt new file mode 100644 index 0000000..97abcb7 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/WinDev/DinkeyChange/README.txt @@ -0,0 +1,15 @@ +Calling DinkeyChange.dll from WinDev +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You should copy all the code in the file "global variables.txt". These data +structures and functions are used by the API sample code. Then copy the +appropraite function(s) from the "protection check functions.txt" file. These +functions implement all the various routines in DinkeyChange.dll + +Note - if you are producing a 64-bit Windows executable you need to use DinkeyChange64.dll +(instead of DinkeyChange.dll) and change the "changedllname" to be "DinkeyChange64.dll" +(this is found in the global variables and functions.txt). +Similarly for Linux you will need to use DinkeyChange.so (32-bit Linux) or +DinkeyChange64.so (64-bit Linux). + +Tested under Windev Express v12 diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/WinDev/DinkeyChange/global variables.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/WinDev/DinkeyChange/global variables.txt new file mode 100644 index 0000000..3ceced4 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/WinDev/DinkeyChange/global variables.txt @@ -0,0 +1,50 @@ +// DinkeyChange constants + +// maximum number of USB devices that can be attached to a machine at any time +CONSTANT + MAX_USB_DEVICES = 128 // max number of USB devices that can be attached to the system + MAX_PRODCODE_LEN = 9 // one extra character for null-terminated strings +END + +// mask values +CONSTANT + TYPE_MASK_PRO = 1 + TYPE_MASK_FD = 2 + TYPE_MASK_ALL = 3 + + MODEL_MASK_LITE = 1 + MODEL_MASK_PLUS = 2 + MODEL_MASK_NET = 4 + MODEL_MASK_ALL = 7 + MODEL_MASK_DEFAULT = 6 // Plus and Net +END + +// type values for DCGetInfo (returned in the array) +CONSTANT + TYPE_PRO = 1 + TYPE_FD = 2 +END + +// model values for DCGetInfo (returned in the array) +CONSTANT + MODEL_LITE = 1 + MODEL_PLUS = 2 + MODEL_NET5 = 4 + MODEL_NETU = 7 +END + +// model values for DCDownloadDemoSoftwareKey + +CONSTANT + SWKEY_MODEL_DEFAULT = -1 // NB this assumes that the Demo Software Key Template was created with only one valid dongle model + SWKEY_MODEL_PRO_LITE = 0 + SWKEY_MODEL_PRO_PLUS = 1 + SWKEY_MODEL_PRO_NET = 2 + SWKEY_MODEL_FD_LITE = 3 + SWKEY_MODEL_FD_PLUS = 4 + SWKEY_MODEL_FD_NET = 5 +END + + +// name for DinkeyChange.dll (you can rename it if you like) +changedllname is a string = "DinkeyChange.dll" diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/WinDev/Runtime/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/WinDev/Runtime/README.txt new file mode 100644 index 0000000..0ce4a34 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/WinDev/Runtime/README.txt @@ -0,0 +1,43 @@ +Protecting Windev applications with Dinkey Dongle +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You should copy all the code in the file "global variables and functions.txt". +These data structures and functions are used by the API sample code. Then copy +the appropriate function(s) from the "protection check functions.txt" file. These +functions implement all the various features of the DInkey Dongle SDK. + +Note that the sample code is just a guide. You should implement the protection in +a stronger way using the techniques described in the "Increasing your Protection" +chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the value of your Product Code +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. However, you should +still display or log any error codes returned by the protection check otherwise you will not +be able to identify the cause of the error. (You can look up error codes in our knowledge +base: microcosm.com/kb). + +Note - you should protect dpwin32.dll and not your program. Because your program +is linked to the DLL it is protected. The protected DLL will need to be in the +same folder as your compiled program for it to run correctly. + +Note - if you are producing a 64-bit Windows executable you need to protect dpwin64.dll +(instead of dpwin32.dll) and change the "protectdllname" to be "dpwin64.dll" +(this is found in the global variables and functions.txt). +Similarly for Linux you will need to use dplin32.so (32-bit Linux) or dplin64.so (64-bit Linux). + +Note - you can also use the Shell Method of protection on WinDev executables. + +Note - we have had reports of a bug in early releases of Windev 19 which causes the "Length" ("Taille") +function to return in incorrect value. This bug has been fixed in the February 2014 release of Windev 19. + +Tested under Windev Express v12 + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/WinDev/Runtime/global variables and functions.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/WinDev/Runtime/global variables and functions.txt new file mode 100644 index 0000000..061886f --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/WinDev/Runtime/global variables and functions.txt @@ -0,0 +1,135 @@ +//******************************************************************* +// Dinkey Runtime Information structure (DRIS) + +GLOBAL + DRIS is composed of + // the first 4 fields are never encrypted + header is a fixed string on 4 // should be set to DRIS + + // inputs + size is an int on 4 // size of this structure + seed1 is an int on 4 // seed for data/dris encryption + seed2 is an int on 4 // seed for data/dris encryption + // (maybe encrypted from now on) + dpfunction is an int on 4 // specify only one function + flags is an int on 4 // options for the function selected. To use more than one OR them together: OPTION1 | OPTION2... + execs_decrement is an unsigned int on 4 // amount by which to dec execs if we use flag: DEC_MANY_EXECS + data_crypt_key_num is an int on 4 // number of the key (1-3) that the dongle uses to encrypt or decrypt user data + rw_offset is an unsigned int on 4 // offset in the dongle data area to read or write data + rw_length is an unsigned int on 4 // length of data are to read/write/encrypt/decrypt + rw_data_ptr is a system int // pointer to data to write / be read + alt_licence_name is a fixed string on 256 // protection check for different licence instead of the default one, must be null-terminated + var_a is an int on 4 // variable values for user algorithm + var_b is an int on 4 + var_c is an int on 4 + var_d is an int on 4 + var_e is an int on 4 + var_f is an int on 4 + var_g is an int on 4 + var_h is an int on 4 + alg_number is an unsigned int on 4 // the number of the user algorithm that you want to execute + + // outputs + ret_code is an int on 4 // return code from the protection check + ext_err is an unsigned int on 4 // extended error + type is an int on 4 // type of dongle detected. 1 = Pro, 2 = FD + model is an int on 4 // model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + sdsn is an int on 4 // Software Developer's Serial Number + prodcode is a fixed string on 12 // Product Code (null-terminated) + dongle_number is an unsigned int on 4 + update_number is an unsigned int on 4 + data_area_size is an unsigned int on 4 // size of the data area used in the dongle detected + num_algs is an int on 4 // the maximum algorithm number in the dongle detected + execs is an int on 4 // executions left: -1 indicates 'no limit' + exp_day is an int on 4 // expiry day: -1 indicates 'no limit' + exp_month is an int on 4 // expiry month: -1 indicates 'no limit' + exp_year is an int on 4 // expiry year: -1 indicates 'no limit' + features is an unsigned int on 4 // features value + net_users is an int on 4 // maximum number of network users for the dongle detected: -1 indicates 'mo limit' + alg_answer is an int on 4 // answer to the user algorithm executed with the given variable values + fd_capacity is an unsigned int on 4 + fd_drive is a fixed string on 128 // drive letter of FD dongle detected e.g. 'f:\' + swkey_type is an int on 4 // 0 = no swkey detected, 1 = temporary software key, 2 = demo software + swkey_exp_day is an int on 4 // software key expiry date (if software key detected) + swkey_exp_month is an int on 4 + swkey_exp_year is an int on 4 + END + + // dpwin32.dll - 32-bit Windows protection module !!!! change this module for 64-bit Windows or Linux or Mac + protectdllname is a string = "dpwin32.dll" + +// functions - must specify only one +CONSTANT + PROTECTION_CHECK = 1 // checks for dongle, check program parameters + EXECUTE_ALGORITHM = 2 // protection check + calculate answer for specified algorithm with specified inputs + WRITE_DATA_AREA =3 // protection check + writes dongle data area + READ_DATA_AREA = 4 // protection check + reads dongle data area + ENCRYPT_USER_DATA = 5 // protection check + the dongle will encrypt user data + DECRYPT_USER_DATA = 6 // protection check + the dongle will decrypt user data + FAST_PRESENCE_CHECK = 7 // checks for the presence of the correct dongle only with minimal security, no flags allowed. + STOP_NET_USER = 8 // stops a network user (and doesn't do a protection check) +END + +// flags - can specify as many as you like +CONSTANT + DEC_ONE_EXEC = 1 // decrement execs by 1 + DEC_MANY_EXECS = 2 // decrement execs by number specified in execs_decrement + START_NET_USER = 4 // starts a network user + USE_FUNCTION_ARGUMENT = 16 // use the extra argument in the function for pointers + CHECK_LOCAL_FIRST = 32 // always look in local ports before looking in network ports + CHECK_NETWORK_FIRST = 64 // always look on the network before looking in local ports + USE_ALT_LICENCE_NAME = 128 // use name specified in alt_licence_name instead of the default one + DONT_SET_MAXDAYS_EXPIRY = 256 // if the max days expiry date has not been calculated then do not do it this time + MATCH_DONGLE_NUMBER = 512 // restrict the search to match the dongle number specified in the DRIS + DONT_RETURN_FD_DRIVE = 1024 // if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS +END + +// SDSN (software developer's serial number) +CONSTANT + MY_SDSN = 10101 // !!!! change this value to be the value of your SDSN (demo = 10101) + MY_PRODCODE = "DEMO" // !!!! change thus value to be the value of your Product Code +END + + +// Summary: Sets each element of the DRIS to be a random value. Improves security +// Syntax: +//RandomSet () +// +PROCEDURE RandomSet() +DRIS_bytes is array of Length(DRIS) 1-byte unsigned int + +Transfer(&DRIS_bytes, &DRIS, Length(DRIS)) // copy DRIS to a byte array so we can look at each byte +InitRandom() +FOR i = 1 _TO_ Length(DRIS) + DRIS_bytes[i] = Random(0,255) // set each element to a random number +END +Transfer(&DRIS, &DRIS_bytes, Length(DRIS)) // copy back to DRIS + + +// Summary: Displays the error code with a helpful error message. You may want to change the messages. +// Syntax: +//DisplayError ( is int, is 4-byte unsigned int) +// +// Parameters: +// ret_code (int): +// ext_err (4-byte unsigned int): +// Return Value: +// None +// +// +PROCEDURE DisplayError(ret_code is int, ext_err is unsigned int) +SWITCH ret_code + CASE 401: Info("Error! No dongles detected!") + CASE 403: Info("Error! The dongle detected has a different type to the one specified in DinkeyAdd.") + CASE 404: Info("Error! The dongle detected has a different model to those specified in DinkeyAdd.") + CASE 409: Info("Error! The dongle detected has not been programmed by DinkeyAdd.") + CASE 410: Info("Error! The dongle detected has a different Product Code to the one specified in DinkeyAdd.") + CASE 411: Info("Error! The dongle detected does not contain the licence associated with this program.") + CASE 413: Info("Error! This program has not been protected by DinkeyAdd.","For guidance please read the DinkeyAdd chapter of the Dinkey manual.") + CASE 417: Info("Error! One or more of the parameters set in the DRIS is incorrect.","This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.") + CASE 423: Info("Error! The number of network users has been exceeded.") + CASE 435: Info("Error! DinkeyServer has not been detected on the network.") + CASE 922: Info("Error! The Software Key has expired.") + OTHER CASE: Info("An error occurred checking the dongle.","Error: " + ret_code, "Extended Error: " + ext_err) +END + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/WinDev/Runtime/protection check functions.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/WinDev/Runtime/protection check functions.txt new file mode 100644 index 0000000..13b748e --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/WinDev/Runtime/protection check functions.txt @@ -0,0 +1,784 @@ +// This code contains the following functions. Please choose the one that matches your needs: +// ProtCheck +// ProtCheckWithAlg (the function also depends on the function MyAlgorithm) +// WriteString +// ReadString +// EncryptUserData +// or the same functions but using DRIS and API data encryption +// (these functions also require the functions CryptDRIS and possibly CryptApiData and MyRWAlgorithm) +// ProtCheckEnc +// ProtCheckWithAlgEnc +// WriteStringEnc +// ReadStringEnc +// EncryptUserDataEnc + + +// Summary: does a standard protection check +// Syntax: +//[ = ] ProtCheck () +// return value is 0 (success) or an error code +PROCEDURE ProtCheck() +hLib, ret_code are system int + +// set the DRIS to have random values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = PROTECTION_CHECK // standard protection check +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... + +// Load the protection DLL. +hLib = LoadDLL(protectdllname) +IF hLib = 0 THEN + Info("Cannot load " + protectdllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +//do a protection check +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) +FreeDLL(hLib) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + RESULT ret_code +END + +// later in your code you can check other values in the DRIS... +IF (DRIS.sdsn <> MY_SDSN) THEN + Info("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + RESULT -1 +END + +IF (ExtractString(DRIS.prodcode, 1, Charact(0)) <> MY_PRODCODE) THEN + Info("Incorrect Product Code. Please modify your source code so that MY_PRODCODE is set to be your Product Code.") + RESULT -1 +END + +// later on in your program you can check the return code again +IF (DRIS.ret_code <> 0) THEN + Info("Dinkey Dongle protection error") + RESULT -1 +END + +Info("It worked!") + +// Summary: does a standard protection check and executes an algorithm +// NB for this to work you must program at least "user algorithm" into the dongle +// NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +// sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +// code from DinkeyLook +// Syntax: +//[ = ] ProtCheckWithAlg () +// return value is 0 (success) or an error code +PROCEDURE ProtCheckWithAlg() +hLib, ret_code are system int + +// set the DRIS to have random values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = EXECUTE_ALGORITHM // protection check and execute specified algorithm +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... +DRIS.alg_number = 1 +// !!!! you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random +DRIS.var_a = 1 // sample values +DRIS.var_b = 2 +DRIS.var_c = 3 +DRIS.var_d = 4 +DRIS.var_e = 5 +DRIS.var_f = 6 +DRIS.var_g = 7 +DRIS.var_h = 8 + +// Load the protection DLL. +hLib = LoadDLL(protectdllname) +IF hLib = 0 THEN + DelayBeforeClosing(1000) + Info("Cannot load " + protectdllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +//do a protection check +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) +FreeDLL(hLib) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + RESULT ret_code +END + +// later in your code you can check other values in the DRIS... +IF (DRIS.sdsn <> MY_SDSN) THEN + Info("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + RESULT -1 +END + +IF (ExtractString(DRIS.prodcode, 1, Charact(0)) <> MY_PRODCODE) THEN + Info("Incorrect Product Code. Please modify your source code so that MY_PRODCODE is set to be your Product Code.") + RESULT -1 +END + +// later on in your program you can check the return code again +IF (DRIS.ret_code <> 0) THEN + Info("Dinkey Dongle protection error") + RESULT -1 +END + +// if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code +// !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd +IF (MyAlgorithm(DRIS.var_a, DRIS.var_b, DRIS.var_c, DRIS.var_d, DRIS.var_e, DRIS.var_f, DRIS.var_g, DRIS.var_h) <> DRIS.alg_answer) THEN + Info("Dinkey protection error!", "You have not patched your algorithm in the MyAlgorithm routine") + RESULT -1 +END + +Info("It worked!") + +// Summary: +// !!!! You should replace this function with the one generated by the +// "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) +// or from DinkeyLook if you are using a Dinkey Lite dongle. You can modify the C code to make it compatiable with Windev. +// Syntax: +//[ = ] MyAlgorithm ( is int, is int, is int, is int, is int, is int, is int, is int) +// +PROCEDURE MyAlgorithm(var_a is int, var_b is int, var_c is int, var_d is int, var_e is int, var_f is int, var_g is int, var_h is int) +RESULT var_a + var_b + var_c + var_d + var_e + var_f + var_g + var_h + + +// Summary: This function does a protection check and writes the string "Hello, World!" to the data area at offset 7 +// In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +// NB you can easily modify the code to write a byte array instead of a string +// Syntax: +//[ = ] WriteString () +// return value is 0 (success) or an error code +// +PROCEDURE WriteString() +hLib, ret_code are system int +OurString is fixed string on 1024 = "Hello, World!" // NB max. data write is 1K + +// set the DRIS to have random values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = WRITE_DATA_AREA // protection check and write specified data +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... +DRIS.rw_offset = 7 +DRIS.rw_length = Length(Left(OurString)) // the length of the string (in this case 13 bytes) +DRIS.rw_data_ptr = &OurString + +// Load the protection DLL. +hLib = LoadDLL(protectdllname) +IF hLib = 0 THEN + Info("Cannot load " + protectdllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +//do a protection check +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) +FreeDLL(hLib) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + RESULT ret_code +END + +// later in your code you can check other values in the DRIS... +IF (DRIS.sdsn <> MY_SDSN) THEN + Info("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + RESULT -1 +END + +IF (ExtractString(DRIS.prodcode, 1, Charact(0)) <> MY_PRODCODE) THEN + Info("Incorrect Product Code. Please modify your source code so that MY_PRODCODE is set to be your Product Code.") + RESULT -1 +END + +// later on in your program you can check the return code again +IF (DRIS.ret_code <> 0) THEN + Info("Dinkey Dongle protection error") + RESULT -1 +END + +Info("It worked!") + + +// Summary: This function does a protection check and reads 13 bytes of data from the data area at offset 7 +// In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +// NB you can amend this code to read a byte array instead of a string if you prefer. +// Syntax: +//[ = ] ReadString () +// return value is 0 (success) or an error code +// +PROCEDURE ReadString() +hLib, ret_code are system int +OurString is fixed string on 1024 // NB max. data read is 1K + +// set the DRIS to have random values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = READ_DATA_AREA // protection check and read data +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... +DRIS.rw_offset = 7 +DRIS.rw_length = 13 +DRIS.rw_data_ptr = &OurString + +// Load the protection DLL. +hLib = LoadDLL(protectdllname) +IF hLib = 0 THEN + Info("Cannot load " + protectdllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +//do a protection check +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) +FreeDLL(hLib) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + RESULT ret_code +END + +// later in your code you can check other values in the DRIS... +IF (DRIS.sdsn <> MY_SDSN) THEN + Info("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + RESULT -1 +END + +IF (ExtractString(DRIS.prodcode, 1, Charact(0)) <> MY_PRODCODE) THEN + Info("Incorrect Product Code. Please modify your source code so that MY_PRODCODE is set to be your Product Code.") + RESULT -1 +END + +// later on in your program you can check the return code again +IF (DRIS.ret_code <> 0) THEN + Info("Dinkey Dongle protection error") + RESULT -1 +END + +Info("It worked! Dinkey Dongle data area at offset 7 is:", OurString) + + +// Summary: this function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +// It will then do another protection check & decrypt the data. NB you can modify the code to encrypt byte arrays instead of strings +// NB you can amend this code to read a byte array instead of a string if you prefer. +// Syntax: +//[ = ] EncryptUserData () +// return value is 0 (success) or an error code +// +PROCEDURE EncryptUserData() +hLib, ret_code are system int +OurString is fixed string on 1024 = "Hello, World!" // NB max. data we can encrypt is 1K + +// set the DRIS to have random values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = ENCRYPT_USER_DATA // protection check and encrypt specified data +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... +DRIS.data_crypt_key_num = 1 +DRIS.rw_length = Length(Left(OurString)) // the length of the string (in this case 13 bytes) +DRIS.rw_data_ptr = &OurString + +// Load the protection DLL. +hLib = LoadDLL(protectdllname) +IF hLib = 0 THEN + Info("Cannot load " + protectdllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +//do a protection check +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + FreeDLL(hLib) + RESULT ret_code +END + +// NB can add code to check other elements of the DRIS e.g. SDSN, ProductCode (see ProtCheck function) + +// Now decrypt the same data to get the original values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = DECRYPT_USER_DATA // protection check and decrypt specified data +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... +DRIS.data_crypt_key_num = 1 +DRIS.rw_length = 13 // the length of the string (in this case 13 bytes) +DRIS.rw_data_ptr = &OurString // NB the data is encrypted at this point + +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) +FreeDLL(hLib) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + RESULT ret_code +END + +// NB can add code to check other elements of the DRIS e.g. SDSN, ProductCode (see ProtCheck function) + +Info("It worked! Dinkey Dongle data area at offset 7 is:", OurString) + + +// !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! +// In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" +// in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm +// but the code can be modified easily to use the 3 encryption parameters. + +// !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm (you will have to adapt the C code generated by DinkeyAdd) +PROCEDURE MyRWAlgorithm(var_a is int, var_b is int, var_c is int, var_d is int, var_e is int, var_f is int, nVar_g is int, nVar_h is int) +RESULT BinaryXOR(BinaryXOR(BinaryXOR(BinaryXOR(BinaryXOR(var_a, var_b), var_c), var_d), var_e), var_f) + +// !!!! please overwrite this function with the one generated by DinkeyAdd +// (just modify the parameters specified in DinkeyAdd in the positiions indicated below): +// Note arrays in Windev are 1-base which makes it a real pain +PROCEDURE CryptDRIS() +i, j, k are int +bigseed, S are array of 256 1-byte unsigned int +DRIS_bytes is an array of Length(DRIS) 1-byte unsigned int +temp, t are 1-byte unsigned int + +FOR i = 1 _TO_ 256 STEP 8 + Transfer(&bigseed[i], &DRIS.seed1, 4) + Transfer(&bigseed[i+4], &DRIS.seed2, 4) +END + +FOR i = 0 _TO_ 255 + S[i+1] = i +END + +j = 0 +FOR i = 0 _TO_ 255 + j = (j + S[i+1] + bigseed[i+1] + 123) modulo 256 // parameter 1, modify 123 + temp = S[i+1] + S[i+1] = S[j+1] + S[j+1] = temp +END + +Transfer(&DRIS_bytes, &DRIS, Length(DRIS)) // convert DRIS to bytes + +i = 0 +j = 0 +FOR k = 17 _TO_ Length(DRIS) + i = (i + 1) modulo 256 + j = (j + S[i+1] + 212) modulo 256 // parameter 2, modify 212 + temp = S[i+1] + S[i+1] = S[j+1] + S[j+1] = temp + t = (S[i+1] + S[j+1] + 97) modulo 256 // parameter 3, modify 97 + DRIS_bytes[k] = BinaryXOR(DRIS_bytes[k], S[t+1]) +END + +Transfer(&DRIS, &DRIS_bytes, Length(DRIS)) // convert back again + + + +// Note arrays in Windev are 1-base which makes it a real pain +// Summary: +// Syntax: +//CryptApiData (, is 4-byte unsigned int, is int) +PROCEDURE CryptApiData(data, enc_length is unsigned int, alg_ans is int) +i, j, k are int +bigseed, S are array of 256 1-byte unsigned int +temp, t are 1-byte unsigned int + +FOR i = 1 _TO_ 256 STEP 8 + Transfer(&bigseed[i], &DRIS.seed1, 4) + Transfer(&bigseed[i+4], &DRIS.seed2, 4) +END + +FOR i = 0 _TO_ 255 + S[i+1] = i +END + +j = 0 +FOR i = 0 _TO_ 255 + j = (j + S[i+1] + bigseed[i+1] + BinaryAND(alg_ans, 0xff)) modulo 256 + temp = S[i+1] + S[i+1] = S[j+1] + S[j+1] = temp +END + +i = 0 +j = 0 +FOR k = 1 _TO_ enc_length + i = (i + 1) modulo 256 + j = (j + S[i+1] + (BinaryAND(alg_ans, 0xff00))/256) modulo 256 + temp = S[i+1] + S[i+1] = S[j+1] + S[j+1] = temp + t = (S[i+1] + S[j+1] + (BinaryAND(alg_ans, 0xff0000))/65536) modulo 256 + data[k] = BinaryXOR(data[k], S[t+1]) +END + + +// Summary: does a standard protection check and encrypt the DRIS we pass and from the API. +// We encrypt the DRIS passed to the API. !!!! Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +// Syntax: +//[ = ] ProtCheckEnc () +// return value is 0 (success) or an error code +PROCEDURE ProtCheckEnc() +hLib, ret_code are system int + +// set the DRIS to have random values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = PROTECTION_CHECK // standard protection check +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... + +// Load the protection DLL. +hLib = LoadDLL(protectdllname) +IF hLib = 0 THEN + Info("Cannot load " + protectdllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +CryptDRIS() // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +//do a protection check +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) +FreeDLL(hLib) + +CryptDRIS() // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + RESULT ret_code +END + +// later in your code you can check other values in the DRIS... +IF (DRIS.sdsn <> MY_SDSN) THEN + Info("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + RESULT -1 +END + +IF (ExtractString(DRIS.prodcode, 1, Charact(0)) <> MY_PRODCODE) THEN + Info("Incorrect Product Code. Please modify your source code so that MY_PRODCODE is set to be your Product Code.") + RESULT -1 +END + +// later on in your program you can check the return code again +IF (DRIS.ret_code <> 0) THEN + Info("Dinkey Dongle protection error") + RESULT -1 +END + +Info("It worked!") + + +// Summary: does a standard protection check and executes an algorithm and encrypts the DRIS +// NB for this to work you must program at least one "user algorithm" into the dongle +// NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +// sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +// code from DinkeyLook. +// We encrypt the DRIS passed to the API. !!!! Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +// Syntax: +//[ = ] ProtCheckWithAlgEnc () +// return value is 0 (success) or an error code +PROCEDURE ProtCheckWithAlgEnc() +hLib, ret_code are system int + +// set the DRIS to have random values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = EXECUTE_ALGORITHM // protection check and execute specified algorithm +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... +DRIS.alg_number = 1 +// !!!! you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random +DRIS.var_a = 1 // sample values +DRIS.var_b = 2 +DRIS.var_c = 3 +DRIS.var_d = 4 +DRIS.var_e = 5 +DRIS.var_f = 6 +DRIS.var_g = 7 +DRIS.var_h = 8 + +// Load the protection DLL. +hLib = LoadDLL(protectdllname) +IF hLib = 0 THEN + DelayBeforeClosing(1000) + Info("Cannot load " + protectdllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +CryptDRIS() // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +//do a protection check +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) +FreeDLL(hLib) + +CryptDRIS() // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + RESULT ret_code +END + +// later in your code you can check other values in the DRIS... +IF (DRIS.sdsn <> MY_SDSN) THEN + Info("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + RESULT -1 +END + +IF (ExtractString(DRIS.prodcode, 1, Charact(0)) <> MY_PRODCODE) THEN + Info("Incorrect Product Code. Please modify your source code so that MY_PRODCODE is set to be your Product Code.") + RESULT -1 +END + +// later on in your program you can check the return code again +IF (DRIS.ret_code <> 0) THEN + Info("Dinkey Dongle protection error") + RESULT -1 +END + +// if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code +// !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd +IF (MyAlgorithm(DRIS.var_a, DRIS.var_b, DRIS.var_c, DRIS.var_d, DRIS.var_e, DRIS.var_f, DRIS.var_g, DRIS.var_h) <> DRIS.alg_answer) THEN + Info("Dinkey protection error!", "You have not patched your algorithm in the MyAlgorithm routine") + RESULT -1 +END + +Info("It worked!") + + +// Summary: This function does a protection check and writes the string "Hello, World!" to the data area at offset 7 +// In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +// NB you can easily modify the code to write a byte array instead of a string +// We encrypt the DRIS and Data passed to the API. !!!! Patch the CryptDRIS, CryptApiData and MyRWAlgorithm functions in this file from source code generated by DinkeyAdd. +// Syntax: +//[ = ] WriteStringEnc () +// return value is 0 (success) or an error code +// +PROCEDURE WriteStringEnc() +hLib, ret_code are system int +alg_ans are int +OurString is fixed string on 1024 = "Hello, World!" // NB max. data write is 1K +OurString_bytes is array of 1024 1-byte unsigned int // byte-array of the encrypted string + +// set the DRIS to have random values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = WRITE_DATA_AREA // protection check and write specified data +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... +DRIS.rw_offset = 7 +DRIS.rw_length = Length(Left(OurString)) // the length of the string (in this case 13 bytes) +DRIS.rw_data_ptr = &OurString_bytes // we convert the string to write to a byte array (so we can encrypt it) and then we pass that value to our API + +// Load the protection DLL. +hLib = LoadDLL(protectdllname) +IF hLib = 0 THEN + Info("Cannot load " + protectdllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +// calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code generated by DinkeyAdd +alg_ans = MyRWAlgorithm(DRIS.var_a, DRIS.var_b, DRIS.var_c, DRIS.var_d, DRIS.var_e, DRIS.var_f, DRIS.var_g, DRIS.var_h) + +// encrypt data we want to write (we must first convert it to a byte array so we can encrypt) +Transfer(&OurString_bytes, &OurString, DRIS.rw_length) +CryptApiData(OurString_bytes, DRIS.rw_length, alg_ans) + +CryptDRIS() // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +//do a protection check +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) +FreeDLL(hLib) + +CryptDRIS() // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + RESULT ret_code +END + +// later in your code you can check other values in the DRIS... +IF (DRIS.sdsn <> MY_SDSN) THEN + Info("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + RESULT -1 +END + +IF (ExtractString(DRIS.prodcode, 1, Charact(0)) <> MY_PRODCODE) THEN + Info("Incorrect Product Code. Please modify your source code so that MY_PRODCODE is set to be your Product Code.") + RESULT -1 +END + +// later on in your program you can check the return code again +IF (DRIS.ret_code <> 0) THEN + Info("Dinkey Dongle protection error") + RESULT -1 +END + +Info("It worked!") + + +// Summary: This function does a protection check and reads 13 bytes of data from the data area at offset 7 +// In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +// NB you can amend this code to read a byte array instead of a string if you prefer. +// We encrypt the DRIS and Data passed to the API. !!!! Patch the CryptDRIS, CryptApiData and MyRWAlgorithm functions in this file from source code generated by DinkeyAdd. +// Syntax: +//[ = ] ReadStringEnc () +// return value is 0 (success) or an error code +// +PROCEDURE ReadStringEnc() +hLib, ret_code are system int +alg_ans are int +OurString is fixed string on 1024 // NB max. data read is 1K +OurString_bytes is array of 1024 1-byte unsigned int // byte-array of the encrypted string + +// set the DRIS to have random values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = READ_DATA_AREA // protection check and read data +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... +DRIS.rw_offset = 7 +DRIS.rw_length = 13 +DRIS.rw_data_ptr = &OurString_bytes // read it to our byte array first and then convert to a string + +// Load the protection DLL. +hLib = LoadDLL(protectdllname) +IF hLib = 0 THEN + Info("Cannot load " + protectdllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +// calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code generated by DinkeyAdd +alg_ans = MyRWAlgorithm(DRIS.var_a, DRIS.var_b, DRIS.var_c, DRIS.var_d, DRIS.var_e, DRIS.var_f, DRIS.var_g, DRIS.var_h) + +CryptDRIS() // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +//do a protection check +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) +FreeDLL(hLib) + +CryptDRIS() // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + RESULT ret_code +END + +// later in your code you can check other values in the DRIS... +IF (DRIS.sdsn <> MY_SDSN) THEN + Info("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + RESULT -1 +END + +IF (ExtractString(DRIS.prodcode, 1, Charact(0)) <> MY_PRODCODE) THEN + Info("Incorrect Product Code. Please modify your source code so that MY_PRODCODE is set to be your Product Code.") + RESULT -1 +END + +// later on in your program you can check the return code again +IF (DRIS.ret_code <> 0) THEN + Info("Dinkey Dongle protection error") + RESULT -1 +END + +// decrypt data we have just read (then convert to string) +CryptApiData(OurString_bytes, DRIS.rw_length, alg_ans) +Transfer(&OurString, &OurString_bytes, DRIS.rw_length) + +Info("It worked! Dinkey Dongle data area at offset 7 is:", OurString) + + +// Summary: this function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +// It will then do another protection check & decrypt the data. NB you can modify the code to encrypt byte arrays instead of strings +// NB you can amend this code to read a byte array instead of a string if you prefer. +// We encrypt the DRIS and Data passed to the API. !!!! Patch the CryptDRIS, CryptApiData and MyRWAlgorithm functions in this file from source code generated by DinkeyAdd. +// Syntax: +//[ = ] EncryptUserDataEnc () +// return value is 0 (success) or an error code +// +PROCEDURE EncryptUserDataEnc() +hLib, ret_code are system int +alg_ans is int +OurString is fixed string on 1024 = "Hello, World!" // NB max. data we can encrypt is 1K +OurString_bytes is array of 1024 1-byte unsigned int // byte-array of the encrypted string + +// set the DRIS to have random values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = ENCRYPT_USER_DATA // protection check and encrypt specified data +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... +DRIS.data_crypt_key_num = 1 +DRIS.rw_length = Length(Left(OurString)) // the length of the string (in this case 13 bytes) +DRIS.rw_data_ptr = &OurString_bytes // we convert the string to encrypt to a byte array (so we can encrypt it) and then we pass that to the API + +// Load the protection DLL. +hLib = LoadDLL(protectdllname) +IF hLib = 0 THEN + Info("Cannot load " + protectdllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +// calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code generated by DinkeyAdd +alg_ans = MyRWAlgorithm(DRIS.var_a, DRIS.var_b, DRIS.var_c, DRIS.var_d, DRIS.var_e, DRIS.var_f, DRIS.var_g, DRIS.var_h) + +// encrypt data we want to write (we must first convert it to a byte array so we can encrypt) +Transfer(&OurString_bytes, &OurString, DRIS.rw_length) +CryptApiData(OurString_bytes, DRIS.rw_length, alg_ans) + +CryptDRIS() // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +//do a protection check +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) + +CryptDRIS() // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + FreeDLL(hLib) + RESULT ret_code +END + +// NB can add code to check other elements of the DRIS e.g. SDSN, ProductCode (see ProtCheck function) + +// Now decrypt the same data to get the original values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = DECRYPT_USER_DATA // protection check and decrypt specified data +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... +DRIS.data_crypt_key_num = 1 +DRIS.rw_length = 13 // the length of the string (in this case 13 bytes) +DRIS.rw_data_ptr = &OurString_bytes // NB this wil still be the encrypted data at this point + +alg_ans = MyRWAlgorithm(DRIS.var_a, DRIS.var_b, DRIS.var_c, DRIS.var_d, DRIS.var_e, DRIS.var_f, DRIS.var_g, DRIS.var_h) + +CryptDRIS() // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) +FreeDLL(hLib) + +CryptDRIS() // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + RESULT ret_code +END + +// NB can add code to check other elements of the DRIS e.g. SDSN, ProductCode (see ProtCheck function) + +// decrypt the returned value and convert to a string +CryptApiData(OurString_bytes, DRIS.rw_length, alg_ans) +Transfer(&OurString, &OurString_bytes, DRIS.rw_length) +Info("It worked! Dinkey Dongle data area at offset 7 is:", OurString) + diff --git a/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Xojo/README.txt b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Xojo/README.txt new file mode 100644 index 0000000..767ad11 --- /dev/null +++ b/Dinkey Pro 7.6.1/$DOCUMENTS/Dinkey Pro 7.6.1 Examples/Samples/Xojo/README.txt @@ -0,0 +1,4 @@ +Xojo Sample Code +~~~~~~~~~~~~~~~~ + +See RealBasic sample code. \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/$PLUGINSDIR/LangDLL.dll b/Dinkey Pro 7.6.1/$PLUGINSDIR/LangDLL.dll new file mode 100644 index 0000000..b3f26e9 Binary files /dev/null and b/Dinkey Pro 7.6.1/$PLUGINSDIR/LangDLL.dll differ diff --git a/Dinkey Pro 7.6.1/$PLUGINSDIR/StartMenu.dll b/Dinkey Pro 7.6.1/$PLUGINSDIR/StartMenu.dll new file mode 100644 index 0000000..d254a5b Binary files /dev/null and b/Dinkey Pro 7.6.1/$PLUGINSDIR/StartMenu.dll differ diff --git a/Dinkey Pro 7.6.1/$PLUGINSDIR/System.dll b/Dinkey Pro 7.6.1/$PLUGINSDIR/System.dll new file mode 100644 index 0000000..c80621b Binary files /dev/null and b/Dinkey Pro 7.6.1/$PLUGINSDIR/System.dll differ diff --git a/Dinkey Pro 7.6.1/$PLUGINSDIR/modern-wizard.bmp b/Dinkey Pro 7.6.1/$PLUGINSDIR/modern-wizard.bmp new file mode 100644 index 0000000..5524eef Binary files /dev/null and b/Dinkey Pro 7.6.1/$PLUGINSDIR/modern-wizard.bmp differ diff --git a/Dinkey Pro 7.6.1/$PLUGINSDIR/nsDialogs.dll b/Dinkey Pro 7.6.1/$PLUGINSDIR/nsDialogs.dll new file mode 100644 index 0000000..aaff800 Binary files /dev/null and b/Dinkey Pro 7.6.1/$PLUGINSDIR/nsDialogs.dll differ diff --git a/Dinkey Pro 7.6.1/DinkeyAdd/DinkeyAdd.NET.dll b/Dinkey Pro 7.6.1/DinkeyAdd/DinkeyAdd.NET.dll new file mode 100644 index 0000000..fd9ab16 Binary files /dev/null and b/Dinkey Pro 7.6.1/DinkeyAdd/DinkeyAdd.NET.dll differ diff --git a/Dinkey Pro 7.6.1/DinkeyAdd/DinkeyAdd.NET64.dll b/Dinkey Pro 7.6.1/DinkeyAdd/DinkeyAdd.NET64.dll new file mode 100644 index 0000000..e62b4a3 Binary files /dev/null and b/Dinkey Pro 7.6.1/DinkeyAdd/DinkeyAdd.NET64.dll differ diff --git a/Dinkey Pro 7.6.1/DinkeyAdd/DinkeyAdd.exe b/Dinkey Pro 7.6.1/DinkeyAdd/DinkeyAdd.exe new file mode 100644 index 0000000..52f41a7 Binary files /dev/null and b/Dinkey Pro 7.6.1/DinkeyAdd/DinkeyAdd.exe differ diff --git a/Dinkey Pro 7.6.1/DinkeyAdd/DinkeyAdd.pdf.dat b/Dinkey Pro 7.6.1/DinkeyAdd/DinkeyAdd.pdf.dat new file mode 100644 index 0000000..6577b7d Binary files /dev/null and b/Dinkey Pro 7.6.1/DinkeyAdd/DinkeyAdd.pdf.dat differ diff --git a/Dinkey Pro 7.6.1/DinkeyAdd/DinkeyAdd32.dll b/Dinkey Pro 7.6.1/DinkeyAdd/DinkeyAdd32.dll new file mode 100644 index 0000000..9448393 Binary files /dev/null and b/Dinkey Pro 7.6.1/DinkeyAdd/DinkeyAdd32.dll differ diff --git a/Dinkey Pro 7.6.1/DinkeyAdd/DinkeyAdd64.dll b/Dinkey Pro 7.6.1/DinkeyAdd/DinkeyAdd64.dll new file mode 100644 index 0000000..8057f5c Binary files /dev/null and b/Dinkey Pro 7.6.1/DinkeyAdd/DinkeyAdd64.dll differ diff --git a/Dinkey Pro 7.6.1/DinkeyAdd/DinkeyAddCmd.exe b/Dinkey Pro 7.6.1/DinkeyAdd/DinkeyAddCmd.exe new file mode 100644 index 0000000..a871d4f Binary files /dev/null and b/Dinkey Pro 7.6.1/DinkeyAdd/DinkeyAddCmd.exe differ diff --git a/Dinkey Pro 7.6.1/DinkeyAdd/import_libs/DinkeyAdd32.lib b/Dinkey Pro 7.6.1/DinkeyAdd/import_libs/DinkeyAdd32.lib new file mode 100644 index 0000000..ed2fde6 Binary files /dev/null and b/Dinkey Pro 7.6.1/DinkeyAdd/import_libs/DinkeyAdd32.lib differ diff --git a/Dinkey Pro 7.6.1/DinkeyAdd/import_libs/DinkeyAdd32_borland.lib b/Dinkey Pro 7.6.1/DinkeyAdd/import_libs/DinkeyAdd32_borland.lib new file mode 100644 index 0000000..b8555c6 Binary files /dev/null and b/Dinkey Pro 7.6.1/DinkeyAdd/import_libs/DinkeyAdd32_borland.lib differ diff --git a/Dinkey Pro 7.6.1/DinkeyAdd/import_libs/DinkeyAdd64.lib b/Dinkey Pro 7.6.1/DinkeyAdd/import_libs/DinkeyAdd64.lib new file mode 100644 index 0000000..b85a461 Binary files /dev/null and b/Dinkey Pro 7.6.1/DinkeyAdd/import_libs/DinkeyAdd64.lib differ diff --git a/Dinkey Pro 7.6.1/DinkeyAdd/import_libs/DinkeyAdd64_borland.lib b/Dinkey Pro 7.6.1/DinkeyAdd/import_libs/DinkeyAdd64_borland.lib new file mode 100644 index 0000000..307c511 Binary files /dev/null and b/Dinkey Pro 7.6.1/DinkeyAdd/import_libs/DinkeyAdd64_borland.lib differ diff --git a/Dinkey Pro 7.6.1/DinkeyChange.exe b/Dinkey Pro 7.6.1/DinkeyChange.exe new file mode 100644 index 0000000..1c1647f Binary files /dev/null and b/Dinkey Pro 7.6.1/DinkeyChange.exe differ diff --git a/Dinkey Pro 7.6.1/DinkeyLook.exe b/Dinkey Pro 7.6.1/DinkeyLook.exe new file mode 100644 index 0000000..33ebffb Binary files /dev/null and b/Dinkey Pro 7.6.1/DinkeyLook.exe differ diff --git a/Dinkey Pro 7.6.1/DinkeyRemote/DinkeyRemote.exe b/Dinkey Pro 7.6.1/DinkeyRemote/DinkeyRemote.exe new file mode 100644 index 0000000..84166ec Binary files /dev/null and b/Dinkey Pro 7.6.1/DinkeyRemote/DinkeyRemote.exe differ diff --git a/Dinkey Pro 7.6.1/DinkeyRemote/DinkeyRemote32.dll b/Dinkey Pro 7.6.1/DinkeyRemote/DinkeyRemote32.dll new file mode 100644 index 0000000..b789fe6 Binary files /dev/null and b/Dinkey Pro 7.6.1/DinkeyRemote/DinkeyRemote32.dll differ diff --git a/Dinkey Pro 7.6.1/DinkeyRemote/DinkeyRemote64.dll b/Dinkey Pro 7.6.1/DinkeyRemote/DinkeyRemote64.dll new file mode 100644 index 0000000..eef65e4 Binary files /dev/null and b/Dinkey Pro 7.6.1/DinkeyRemote/DinkeyRemote64.dll differ diff --git a/Dinkey Pro 7.6.1/DinkeyRemote/DinkeyRemoteCmd.exe b/Dinkey Pro 7.6.1/DinkeyRemote/DinkeyRemoteCmd.exe new file mode 100644 index 0000000..311ae90 Binary files /dev/null and b/Dinkey Pro 7.6.1/DinkeyRemote/DinkeyRemoteCmd.exe differ diff --git a/Dinkey Pro 7.6.1/DinkeyRemote/import_libs/DinkeyRemote32.lib b/Dinkey Pro 7.6.1/DinkeyRemote/import_libs/DinkeyRemote32.lib new file mode 100644 index 0000000..b1af486 Binary files /dev/null and b/Dinkey Pro 7.6.1/DinkeyRemote/import_libs/DinkeyRemote32.lib differ diff --git a/Dinkey Pro 7.6.1/DinkeyRemote/import_libs/DinkeyRemote32_borland.lib b/Dinkey Pro 7.6.1/DinkeyRemote/import_libs/DinkeyRemote32_borland.lib new file mode 100644 index 0000000..579b9cd Binary files /dev/null and b/Dinkey Pro 7.6.1/DinkeyRemote/import_libs/DinkeyRemote32_borland.lib differ diff --git a/Dinkey Pro 7.6.1/DinkeyRemote/import_libs/DinkeyRemote64.lib b/Dinkey Pro 7.6.1/DinkeyRemote/import_libs/DinkeyRemote64.lib new file mode 100644 index 0000000..25e44d7 Binary files /dev/null and b/Dinkey Pro 7.6.1/DinkeyRemote/import_libs/DinkeyRemote64.lib differ diff --git a/Dinkey Pro 7.6.1/DinkeyRemote/import_libs/DinkeyRemote64_borland.lib b/Dinkey Pro 7.6.1/DinkeyRemote/import_libs/DinkeyRemote64_borland.lib new file mode 100644 index 0000000..307c511 Binary files /dev/null and b/Dinkey Pro 7.6.1/DinkeyRemote/import_libs/DinkeyRemote64_borland.lib differ diff --git a/Dinkey Pro 7.6.1/DinkeyServer.exe b/Dinkey Pro 7.6.1/DinkeyServer.exe new file mode 100644 index 0000000..119bdc4 Binary files /dev/null and b/Dinkey Pro 7.6.1/DinkeyServer.exe differ diff --git a/Dinkey Pro 7.6.1/Label Templates/DinkeyFDLabelTemplate.doc b/Dinkey Pro 7.6.1/Label Templates/DinkeyFDLabelTemplate.doc new file mode 100644 index 0000000..c4811b1 Binary files /dev/null and b/Dinkey Pro 7.6.1/Label Templates/DinkeyFDLabelTemplate.doc differ diff --git a/Dinkey Pro 7.6.1/Label Templates/DinkeyProLabelTemplate.doc b/Dinkey Pro 7.6.1/Label Templates/DinkeyProLabelTemplate.doc new file mode 100644 index 0000000..645ac77 Binary files /dev/null and b/Dinkey Pro 7.6.1/Label Templates/DinkeyProLabelTemplate.doc differ diff --git a/Dinkey Pro 7.6.1/Label Templates/NewDinkeyFDLabelTemplate.doc b/Dinkey Pro 7.6.1/Label Templates/NewDinkeyFDLabelTemplate.doc new file mode 100644 index 0000000..0425e38 Binary files /dev/null and b/Dinkey Pro 7.6.1/Label Templates/NewDinkeyFDLabelTemplate.doc differ diff --git a/Dinkey Pro 7.6.1/Label Templates/README.html b/Dinkey Pro 7.6.1/Label Templates/README.html new file mode 100644 index 0000000..be95352 --- /dev/null +++ b/Dinkey Pro 7.6.1/Label Templates/README.html @@ -0,0 +1,60 @@ + + + + + + Important Notes for Printing Labels + + + + +

Important Notes for Printing Labels

+ +

+ Every effort has been made to ensure that the template measurements are as accurate as possible. + However, every printer is different, and you may need to make small adjustments to the template + to ensure that your labels are correctly aligned when using your printer. + We strongly recommend that you make some test prints on plain A4 paper before printing onto the label sheets. +

+

+ Each label consists of two parts - a paper sticker and a protective vinyl over-layer. + You should print only on the matt white paper sticker sheets. Do not attempt to print on the glossy vinyl sheets! + The sticker sheets are suitable for use with both inkjet and laser printers. +

+ +

Which Template Should I Use?

+ + + + + + + + + + + + + + + +
DinkeyProLabelTemplate.docTemplate for elliptical labels suitable for all Dinkey Pro dongles with the standard case size. Not suitable for mini Dinkey Pro dongles.
DinkeyFDLabelTemplate.docTemplate for labels suitable for the larger, white Dinkey FD Plus and Dinkey FD Net dongles.
NewDinkeyFDLabelTemplate.docTemplate for labels suitable for the smaller, red Dinkey FD Plus and Dinkey FD Net dongles.
+ + diff --git a/Dinkey Pro 7.6.1/Manual/DinkeyProManual.chm b/Dinkey Pro 7.6.1/Manual/DinkeyProManual.chm new file mode 100644 index 0000000..62438eb Binary files /dev/null and b/Dinkey Pro 7.6.1/Manual/DinkeyProManual.chm differ diff --git a/Dinkey Pro 7.6.1/Manual/DinkeyProManual.pdf b/Dinkey Pro 7.6.1/Manual/DinkeyProManual.pdf new file mode 100644 index 0000000..128e614 --- /dev/null +++ b/Dinkey Pro 7.6.1/Manual/DinkeyProManual.pdf @@ -0,0 +1,9634 @@ +%PDF-1.3 +%ÿÿÿÿ +1 0 obj +<< +/Fields [] +/DR 876 0 R +>> +endobj +2 0 obj +<< +/Type /Catalog +/Pages 878 0 R +/AcroForm 1 0 R +/PageMode /UseOutlines +/Outlines 3 0 R +>> +endobj +3 0 obj +<< +/Count 141 /First 4 0 R /Last 144 0 R >> +endobj +4 0 obj +<< +/Count -4 /First 5 0 R /Last 8 0 R /Next 9 0 R /Title +/Dest [473 0 R /XYZ 72 734.65 0 ] +>> +endobj +5 0 obj +<< +/Next 6 0 R /Title +/Dest [476 0 R /XYZ 72 769.90 0 ] +>> +endobj +6 0 obj +<< +/Prev 5 0 R /Next 7 0 R /Title +/Dest [476 0 R /XYZ 72 654.40 0 ] +>> +endobj +7 0 obj +<< +/Prev 6 0 R /Next 8 0 R /Title +/Dest [476 0 R /XYZ 72 406.90 0 ] +>> +endobj +8 0 obj +<< +/Prev 7 0 R /Title +/Dest [476 0 R /XYZ 72 233.65 0 ] +>> +endobj +9 0 obj +<< +/Count -4 /First 10 0 R /Last 13 0 R /Prev 4 0 R /Next 14 0 R /Title +/Dest [491 0 R /XYZ 72 769.90 0 ] +>> +endobj +10 0 obj +<< +/Next 11 0 R /Title +/Dest [491 0 R /XYZ 72 592.90 0 ] +>> +endobj +11 0 obj +<< +/Prev 10 0 R /Next 12 0 R /Title +/Dest [491 0 R /XYZ 72 512.65 0 ] +>> +endobj +12 0 obj +<< +/Prev 11 0 R /Next 13 0 R /Title +/Dest [491 0 R /XYZ 72 288.40 0 ] +>> +endobj +13 0 obj +<< +/Prev 12 0 R /Title +/Dest [494 0 R /XYZ 72 722.65 0 ] +>> +endobj +14 0 obj +<< +/Count -2 /First 15 0 R /Last 16 0 R /Prev 9 0 R /Next 17 0 R /Title +/Dest [499 0 R /XYZ 72 769.90 0 ] +>> +endobj +15 0 obj +<< +/Next 16 0 R /Title +/Dest [499 0 R /XYZ 72 627.40 0 ] +>> +endobj +16 0 obj +<< +/Prev 15 0 R /Title +/Dest [502 0 R /XYZ 72 642.40 0 ] +>> +endobj +17 0 obj +<< +/Count -5 /First 18 0 R /Last 22 0 R /Prev 14 0 R /Next 23 0 R /Title +/Dest [511 0 R /XYZ 72 769.90 0 ] +>> +endobj +18 0 obj +<< +/Next 19 0 R /Title +/Dest [511 0 R /XYZ 72 627.40 0 ] +>> +endobj +19 0 obj +<< +/Count -2 /First 20 0 R /Last 21 0 R /Prev 18 0 R /Next 22 0 R /Title +/Dest [511 0 R /XYZ 72 448.15 0 ] +>> +endobj +20 0 obj +<< +/Next 21 0 R /Title +/Dest [516 0 R /XYZ 72 601.40 0 ] +>> +endobj +21 0 obj +<< +/Prev 20 0 R /Title +/Dest [516 0 R /XYZ 72 306.65 0 ] +>> +endobj +22 0 obj +<< +/Prev 19 0 R /Title +/Dest [524 0 R /XYZ 72 769.90 0 ] +>> +endobj +23 0 obj +<< +/Count -6 /First 24 0 R /Last 29 0 R /Prev 17 0 R /Next 30 0 R /Title +/Dest [535 0 R /XYZ 72 769.90 0 ] +>> +endobj +24 0 obj +<< +/Next 25 0 R /Title +/Dest [538 0 R /XYZ 72 769.90 0 ] +>> +endobj +25 0 obj +<< +/Prev 24 0 R /Next 26 0 R /Title +/Dest [541 0 R /XYZ 72 320.65 0 ] +>> +endobj +26 0 obj +<< +/Count -1 /First 27 0 R /Last 27 0 R /Prev 25 0 R /Next 28 0 R /Title +/Dest [544 0 R /XYZ 72 239.65 0 ] +>> +endobj +27 0 obj +<< +/Title +/Dest [549 0 R /XYZ 72 608.90 0 ] +>> +endobj +28 0 obj +<< +/Prev 26 0 R /Next 29 0 R /Title +/Dest [549 0 R /XYZ 72 310.15 0 ] +>> +endobj +29 0 obj +<< +/Prev 28 0 R /Title +/Dest [555 0 R /XYZ 72 637.15 0 ] +>> +endobj +30 0 obj +<< +/Count -24 /First 31 0 R /Last 54 0 R /Prev 23 0 R /Next 55 0 R /Title +/Dest [558 0 R /XYZ 72 769.90 0 ] +>> +endobj +31 0 obj +<< +/Next 32 0 R /Title +/Dest [558 0 R /XYZ 72 169.90 0 ] +>> +endobj +32 0 obj +<< +/Prev 31 0 R /Next 33 0 R /Title +/Dest [561 0 R /XYZ 72 405.40 0 ] +>> +endobj +33 0 obj +<< +/Count -1 /First 34 0 R /Last 34 0 R /Prev 32 0 R /Next 35 0 R /Title +/Dest [566 0 R /XYZ 72 734.65 0 ] +>> +endobj +34 0 obj +<< +/Title +/Dest [566 0 R /XYZ 72 395.90 0 ] +>> +endobj +35 0 obj +<< +/Prev 33 0 R /Next 36 0 R /Title +/Dest [569 0 R /XYZ 72 706.15 0 ] +>> +endobj +36 0 obj +<< +/Count -1 /First 37 0 R /Last 37 0 R /Prev 35 0 R /Next 38 0 R /Title +/Dest [576 0 R /XYZ 72 521.65 0 ] +>> +endobj +37 0 obj +<< +/Title +/Dest [582 0 R /XYZ 72 448.40 0 ] +>> +endobj +38 0 obj +<< +/Prev 36 0 R /Next 39 0 R /Title +/Dest [587 0 R /XYZ 72 769.90 0 ] +>> +endobj +39 0 obj +<< +/Prev 38 0 R /Next 40 0 R /Title +/Dest [587 0 R /XYZ 72 327.40 0 ] +>> +endobj +40 0 obj +<< +/Prev 39 0 R /Next 41 0 R /Title +/Dest [590 0 R /XYZ 72 585.40 0 ] +>> +endobj +41 0 obj +<< +/Count -3 /First 42 0 R /Last 44 0 R /Prev 40 0 R /Next 45 0 R /Title +/Dest [593 0 R /XYZ 72 463.90 0 ] +>> +endobj +42 0 obj +<< +/Next 43 0 R /Title +/Dest [593 0 R /XYZ 72 407.15 0 ] +>> +endobj +43 0 obj +<< +/Prev 42 0 R /Next 44 0 R /Title +/Dest [593 0 R /XYZ 72 281.90 0 ] +>> +endobj +44 0 obj +<< +/Prev 43 0 R /Title +/Dest [598 0 R /XYZ 72 770.15 0 ] +>> +endobj +45 0 obj +<< +/Count -2 /First 46 0 R /Last 47 0 R /Prev 41 0 R /Next 48 0 R /Title +/Dest [598 0 R /XYZ 72 633.40 0 ] +>> +endobj +46 0 obj +<< +/Next 47 0 R /Title +/Dest [598 0 R /XYZ 72 590.90 0 ] +>> +endobj +47 0 obj +<< +/Prev 46 0 R /Title +/Dest [598 0 R /XYZ 72 463.40 0 ] +>> +endobj +48 0 obj +<< +/Prev 45 0 R /Next 49 0 R /Title +/Dest [598 0 R /XYZ 72 325.15 0 ] +>> +endobj +49 0 obj +<< +/Prev 48 0 R /Next 50 0 R /Title +/Dest [603 0 R /XYZ 72 769.90 0 ] +>> +endobj +50 0 obj +<< +/Count -3 /First 51 0 R /Last 53 0 R /Prev 49 0 R /Next 54 0 R /Title +/Dest [609 0 R /XYZ 72 704.65 0 ] +>> +endobj +51 0 obj +<< +/Next 52 0 R /Title +/Dest [609 0 R /XYZ 72 452.90 0 ] +>> +endobj +52 0 obj +<< +/Prev 51 0 R /Next 53 0 R /Title +/Dest [614 0 R /XYZ 72 555.65 0 ] +>> +endobj +53 0 obj +<< +/Prev 52 0 R /Title +/Dest [617 0 R /XYZ 72 475.40 0 ] +>> +endobj +54 0 obj +<< +/Prev 50 0 R /Title +/Dest [617 0 R /XYZ 72 283.15 0 ] +>> +endobj +55 0 obj +<< +/Count -9 /First 56 0 R /Last 64 0 R /Prev 30 0 R /Next 65 0 R /Title +/Dest [622 0 R /XYZ 72 769.90 0 ] +>> +endobj +56 0 obj +<< +/Next 57 0 R /Title +/Dest [622 0 R /XYZ 72 514.40 0 ] +>> +endobj +57 0 obj +<< +/Prev 56 0 R /Next 58 0 R /Title +/Dest [622 0 R /XYZ 72 452.15 0 ] +>> +endobj +58 0 obj +<< +/Prev 57 0 R /Next 59 0 R /Title +/Dest [622 0 R /XYZ 72 378.65 0 ] +>> +endobj +59 0 obj +<< +/Prev 58 0 R /Next 60 0 R /Title +/Dest [622 0 R /XYZ 72 242.15 0 ] +>> +endobj +60 0 obj +<< +/Prev 59 0 R /Next 61 0 R /Title +/Dest [627 0 R /XYZ 72 770.15 0 ] +>> +endobj +61 0 obj +<< +/Prev 60 0 R /Next 62 0 R /Title +/Dest [627 0 R /XYZ 72 674.15 0 ] +>> +endobj +62 0 obj +<< +/Prev 61 0 R /Next 63 0 R /Title +/Dest [627 0 R /XYZ 72 577.40 0 ] +>> +endobj +63 0 obj +<< +/Prev 62 0 R /Next 64 0 R /Title +/Dest [627 0 R /XYZ 72 481.40 0 ] +>> +endobj +64 0 obj +<< +/Prev 63 0 R /Title +/Dest [627 0 R /XYZ 72 419.15 0 ] +>> +endobj +65 0 obj +<< +/Count -16 /First 66 0 R /Last 81 0 R /Prev 55 0 R /Next 82 0 R /Title +/Dest [632 0 R /XYZ 72 769.90 0 ] +>> +endobj +66 0 obj +<< +/Next 67 0 R /Title +/Dest [632 0 R /XYZ 72 420.40 0 ] +>> +endobj +67 0 obj +<< +/Count -6 /First 68 0 R /Last 73 0 R /Prev 66 0 R /Next 74 0 R /Title +/Dest [635 0 R /XYZ 72 671.65 0 ] +>> +endobj +68 0 obj +<< +/Next 69 0 R /Title +/Dest [635 0 R /XYZ 72 300.65 0 ] +>> +endobj +69 0 obj +<< +/Prev 68 0 R /Next 70 0 R /Title +/Dest [640 0 R /XYZ 72 770.15 0 ] +>> +endobj +70 0 obj +<< +/Prev 69 0 R /Next 71 0 R /Title +/Dest [643 0 R /XYZ 72 770.15 0 ] +>> +endobj +71 0 obj +<< +/Prev 70 0 R /Next 72 0 R /Title +/Dest [643 0 R /XYZ 72 460.40 0 ] +>> +endobj +72 0 obj +<< +/Prev 71 0 R /Next 73 0 R /Title +/Dest [643 0 R /XYZ 72 346.40 0 ] +>> +endobj +73 0 obj +<< +/Prev 72 0 R /Title +/Dest [648 0 R /XYZ 72 718.40 0 ] +>> +endobj +74 0 obj +<< +/Prev 67 0 R /Next 75 0 R /Title +/Dest [648 0 R /XYZ 72 482.65 0 ] +>> +endobj +75 0 obj +<< +/Count -3 /First 76 0 R /Last 78 0 R /Prev 74 0 R /Next 79 0 R /Title +/Dest [654 0 R /XYZ 72 560.65 0 ] +>> +endobj +76 0 obj +<< +/Next 77 0 R /Title +/Dest [654 0 R /XYZ 72 337.40 0 ] +>> +endobj +77 0 obj +<< +/Prev 76 0 R /Next 78 0 R /Title +/Dest [659 0 R /XYZ 72 439.40 0 ] +>> +endobj +78 0 obj +<< +/Prev 77 0 R /Title +/Dest [659 0 R /XYZ 72 248.90 0 ] +>> +endobj +79 0 obj +<< +/Prev 75 0 R /Next 80 0 R /Title +/Dest [664 0 R /XYZ 72 769.90 0 ] +>> +endobj +80 0 obj +<< +/Prev 79 0 R /Next 81 0 R /Title +/Dest [664 0 R /XYZ 72 372.40 0 ] +>> +endobj +81 0 obj +<< +/Prev 80 0 R /Title +/Dest [674 0 R /XYZ 72 304.90 0 ] +>> +endobj +82 0 obj +<< +/Count -6 /First 83 0 R /Last 88 0 R /Prev 65 0 R /Next 89 0 R /Title +/Dest [688 0 R /XYZ 72 769.90 0 ] +>> +endobj +83 0 obj +<< +/Count -5 /First 84 0 R /Last 88 0 R /Title +/Dest [688 0 R /XYZ 72 627.40 0 ] +>> +endobj +84 0 obj +<< +/Next 85 0 R /Title +/Dest [688 0 R /XYZ 72 494.15 0 ] +>> +endobj +85 0 obj +<< +/Prev 84 0 R /Next 86 0 R /Title +/Dest [688 0 R /XYZ 72 425.90 0 ] +>> +endobj +86 0 obj +<< +/Prev 85 0 R /Next 87 0 R /Title +/Dest [688 0 R /XYZ 72 358.40 0 ] +>> +endobj +87 0 obj +<< +/Prev 86 0 R /Next 88 0 R /Title +/Dest [688 0 R /XYZ 72 256.40 0 ] +>> +endobj +88 0 obj +<< +/Prev 87 0 R /Title +/Dest [688 0 R /XYZ 72 165.65 0 ] +>> +endobj +89 0 obj +<< +/Count -10 /First 90 0 R /Last 99 0 R /Prev 82 0 R /Next 100 0 R /Title +/Dest [694 0 R /XYZ 72 734.65 0 ] +>> +endobj +90 0 obj +<< +/Next 91 0 R /Title +/Dest [694 0 R /XYZ 72 592.15 0 ] +>> +endobj +91 0 obj +<< +/Prev 90 0 R /Next 92 0 R /Title +/Dest [694 0 R /XYZ 72 373.90 0 ] +>> +endobj +92 0 obj +<< +/Count -3 /First 93 0 R /Last 95 0 R /Prev 91 0 R /Next 96 0 R /Title +/Dest [699 0 R /XYZ 72 665.65 0 ] +>> +endobj +93 0 obj +<< +/Next 94 0 R /Title +/Dest [699 0 R /XYZ 72 623.15 0 ] +>> +endobj +94 0 obj +<< +/Prev 93 0 R /Next 95 0 R /Title +/Dest [699 0 R /XYZ 72 483.65 0 ] +>> +endobj +95 0 obj +<< +/Prev 94 0 R /Title +/Dest [699 0 R /XYZ 72 174.65 0 ] +>> +endobj +96 0 obj +<< +/Prev 92 0 R /Next 97 0 R /Title +/Dest [702 0 R /XYZ 72 670.90 0 ] +>> +endobj +97 0 obj +<< +/Prev 96 0 R /Next 98 0 R /Title +/Dest [702 0 R /XYZ 72 351.40 0 ] +>> +endobj +98 0 obj +<< +/Prev 97 0 R /Next 99 0 R /Title +/Dest [702 0 R /XYZ 72 196.15 0 ] +>> +endobj +99 0 obj +<< +/Prev 98 0 R /Title +/Dest [705 0 R /XYZ 72 452.65 0 ] +>> +endobj +100 0 obj +<< +/Count -13 /First 101 0 R /Last 113 0 R /Prev 89 0 R /Next 114 0 R /Title +/Dest [711 0 R /XYZ 72 769.90 0 ] +>> +endobj +101 0 obj +<< +/Next 102 0 R /Title +/Dest [711 0 R /XYZ 72 627.40 0 ] +>> +endobj +102 0 obj +<< +/Prev 101 0 R /Next 103 0 R /Title +/Dest [711 0 R /XYZ 72 518.65 0 ] +>> +endobj +103 0 obj +<< +/Count -2 /First 104 0 R /Last 105 0 R /Prev 102 0 R /Next 106 0 R /Title +/Dest [711 0 R /XYZ 72 334.15 0 ] +>> +endobj +104 0 obj +<< +/Next 105 0 R /Title +/Dest [711 0 R /XYZ 72 145.40 0 ] +>> +endobj +105 0 obj +<< +/Prev 104 0 R /Title +/Dest [714 0 R /XYZ 72 563.15 0 ] +>> +endobj +106 0 obj +<< +/Count -4 /First 107 0 R /Last 110 0 R /Prev 103 0 R /Next 111 0 R /Title +/Dest [714 0 R /XYZ 72 448.90 0 ] +>> +endobj +107 0 obj +<< +/Next 108 0 R /Title +/Dest [714 0 R /XYZ 72 259.40 0 ] +>> +endobj +108 0 obj +<< +/Prev 107 0 R /Next 109 0 R /Title +/Dest [720 0 R /XYZ 72 770.15 0 ] +>> +endobj +109 0 obj +<< +/Prev 108 0 R /Next 110 0 R /Title +/Dest [720 0 R /XYZ 72 389.90 0 ] +>> +endobj +110 0 obj +<< +/Prev 109 0 R /Title +/Dest [720 0 R /XYZ 72 233.15 0 ] +>> +endobj +111 0 obj +<< +/Prev 106 0 R /Next 112 0 R /Title +/Dest [727 0 R /XYZ 72 769.90 0 ] +>> +endobj +112 0 obj +<< +/Prev 111 0 R /Next 113 0 R /Title +/Dest [727 0 R /XYZ 72 602.65 0 ] +>> +endobj +113 0 obj +<< +/Prev 112 0 R /Title +/Dest [727 0 R /XYZ 72 420.40 0 ] +>> +endobj +114 0 obj +<< +/Count -1 /First 115 0 R /Last 115 0 R /Prev 100 0 R /Next 116 0 R /Title +/Dest [732 0 R /XYZ 72 769.90 0 ] +>> +endobj +115 0 obj +<< +/Title +/Dest [732 0 R /XYZ 72 627.40 0 ] +>> +endobj +116 0 obj +<< +/Count -2 /First 117 0 R /Last 118 0 R /Prev 114 0 R /Next 119 0 R /Title +/Dest [737 0 R /XYZ 72 769.90 0 ] +>> +endobj +117 0 obj +<< +/Next 118 0 R /Title +/Dest [737 0 R /XYZ 72 627.40 0 ] +>> +endobj +118 0 obj +<< +/Prev 117 0 R /Title +/Dest [737 0 R /XYZ 72 332.65 0 ] +>> +endobj +119 0 obj +<< +/Count -10 /First 120 0 R /Last 129 0 R /Prev 116 0 R /Next 130 0 R /Title +/Dest [744 0 R /XYZ 72 769.90 0 ] +>> +endobj +120 0 obj +<< +/Next 121 0 R /Title +/Dest [744 0 R /XYZ 72 627.40 0 ] +>> +endobj +121 0 obj +<< +/Prev 120 0 R /Next 122 0 R /Title +/Dest [744 0 R /XYZ 72 553.15 0 ] +>> +endobj +122 0 obj +<< +/Prev 121 0 R /Next 123 0 R /Title +/Dest [750 0 R /XYZ 72 769.90 0 ] +>> +endobj +123 0 obj +<< +/Prev 122 0 R /Next 124 0 R /Title +/Dest [750 0 R /XYZ 72 634.15 0 ] +>> +endobj +124 0 obj +<< +/Prev 123 0 R /Next 125 0 R /Title +/Dest [756 0 R /XYZ 72 205.15 0 ] +>> +endobj +125 0 obj +<< +/Prev 124 0 R /Next 126 0 R /Title +/Dest [767 0 R /XYZ 72 760.90 0 ] +>> +endobj +126 0 obj +<< +/Prev 125 0 R /Next 127 0 R /Title +/Dest [770 0 R /XYZ 72 234.40 0 ] +>> +endobj +127 0 obj +<< +/Prev 126 0 R /Next 128 0 R /Title +/Dest [778 0 R /XYZ 72 725.65 0 ] +>> +endobj +128 0 obj +<< +/Prev 127 0 R /Next 129 0 R /Title +/Dest [778 0 R /XYZ 72 498.40 0 ] +>> +endobj +129 0 obj +<< +/Prev 128 0 R /Title +/Dest [778 0 R /XYZ 72 302.65 0 ] +>> +endobj +130 0 obj +<< +/Prev 119 0 R /Next 131 0 R /Title +/Dest [781 0 R /XYZ 72 769.90 0 ] +>> +endobj +131 0 obj +<< +/Count -7 /First 132 0 R /Last 138 0 R /Prev 130 0 R /Next 139 0 R /Title +/Dest [787 0 R /XYZ 72 769.90 0 ] +>> +endobj +132 0 obj +<< +/Next 133 0 R /Title +/Dest [787 0 R /XYZ 72 627.40 0 ] +>> +endobj +133 0 obj +<< +/Prev 132 0 R /Next 134 0 R /Title +/Dest [787 0 R /XYZ 72 415.15 0 ] +>> +endobj +134 0 obj +<< +/Prev 133 0 R /Next 135 0 R /Title +/Dest [800 0 R /XYZ 72 769.90 0 ] +>> +endobj +135 0 obj +<< +/Prev 134 0 R /Next 136 0 R /Title +/Dest [803 0 R /XYZ 72 769.90 0 ] +>> +endobj +136 0 obj +<< +/Prev 135 0 R /Next 137 0 R /Title +/Dest [803 0 R /XYZ 72 157.15 0 ] +>> +endobj +137 0 obj +<< +/Prev 136 0 R /Next 138 0 R /Title +/Dest [806 0 R /XYZ 72 601.90 0 ] +>> +endobj +138 0 obj +<< +/Prev 137 0 R /Title +/Dest [806 0 R /XYZ 72 454.90 0 ] +>> +endobj +139 0 obj +<< +/Count -3 /First 140 0 R /Last 142 0 R /Prev 131 0 R /Next 143 0 R /Title +/Dest [809 0 R /XYZ 72 769.90 0 ] +>> +endobj +140 0 obj +<< +/Next 141 0 R /Title +/Dest [809 0 R /XYZ 72 627.40 0 ] +>> +endobj +141 0 obj +<< +/Prev 140 0 R /Next 142 0 R /Title +/Dest [809 0 R /XYZ 72 427.15 0 ] +>> +endobj +142 0 obj +<< +/Prev 141 0 R /Title +/Dest [809 0 R /XYZ 72 284.65 0 ] +>> +endobj +143 0 obj +<< +/Prev 139 0 R /Next 144 0 R /Title +/Dest [815 0 R /XYZ 72 745.90 0 ] +>> +endobj +144 0 obj +<< +/Prev 143 0 R /Title +/Dest [824 0 R /XYZ 72 745.90 0 ] +>> +endobj +145 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R >> +>> +/Contents [146 0 R] +>> +endobj +146 0 obj +<< /Length 147 0 R /Filter /FlateDecode >> +stream +xœ•TÁŠÜ0 ý‚üƒÏ…º’lË6,…Ù̽?Øv…-´ÿ¨ä(‰™…–AL&#?=½'ë÷„äƒÙW’§×÷é×”‚çèbö™]dö\Ügð™ÜŸÓÛ'I¸,Ó—[u=Dç–·&ĨG3 ž]Þ'9È’óêž J$ –Èå«[~N¡x·|×:±”=¿J„–ƒè©I=è³ÄEâªÉ/V`¶ß‹Öèã¿Tír Eo +ÜræEAJ­qBU+¸ŠÆgÅrDä8‘ªorAä*ök—Hëoí¥CŒk§(]"[·óÞéc«"VU4¤¸®[aÌ+–CÚö|]‹a]ÕÙ jöâGEi‡wP!fã‚r‚F&!yŠ.@ðµ rÁgÆêm1«ç.WºŒ<©øDŽ*(Ýs!·)üpf>.ÚÜH«ðr*˜ZÁÌ>li¯ ë¶Ö@«§bq2y(=ΆQNy¬6yOFíäW)wig¤J:™óʃ©Í|ÜÍÙIúÂê11ùÄîj“û|èÑô¿Þé Ç)–n½P¢ÆáfÌlïæ$d/—B´qkëd¹©\Æ$›C¨Fë{ýŸÐÞ§»^Cª:_˜«±Ü4!ódµÆÒåÝÛ2è–ê „jܹÚýo\¥Q +ÝÜxÚ”™U jƒYÕµMÉ®©#>Ömëä¶þOùxwn»Õ9×ÃyÚuÊWž£)ØVàqxÜ„TºÈÿKu¨” êìhŽ+ëüÛôv†k1 +endstream +endobj +147 0 obj +582 +endobj +148 0 obj +<< +/Type /Font +/Subtype /Type0 +/BaseFont /YJDRSH+Arial,Bold +/Encoding /Identity-H +/ToUnicode 149 0 R +/DescendantFonts[ 150 0 R ] +>> +endobj +149 0 obj +<< +/Filter /FlateDecode +/Length 581 +>> +stream +xœ]”ËnÚ@†ŸÀï0Ëtçb)ŠDHX¤­Jª®{H-c³àíkæûC•Zë÷œÛ7çèÌV›§M׎fö}8ÔÛ8š]Û5C<NCÍ[|o»,·¦iëQ*ý×ûªÏf“óö|ã~ÓíÆaÕœzYÎ~L¯ã8œÍͲ9¼Å/¦‰»lömhâÐvïææçj«oÛSßÿ‰ûØfž¾Ä®ádõRõ_«}4³ãvÓLFíx¾œÿY¼žûh,ú×Ë¡‰ +“SJ=}9öU‡ª{Ùý|zÌýzz.©þ;/¸½íêßÕp5O¯¤òOÊ~R.)+å“ò’*¨õŒ*Q¨;T@-’*å·L*(Ã#gµÂozBå¨g”jYSY‘T_)_±BÁW’/_‰‚¯t(ø¼Îà+aÈáóO(ñɾBgðyeUçðyùÁç¹—>m_ »…¯ 2 _ Š…¯€ÝÂWÊ>Gv _ ƒ…/è >§(â»CÁç¨ÓªRð9Õ">e½u08ˆ žéq08ò9<³äÄ‘Ó *& ŽÞ:õH`p²Ô *ƒzÄœ9õˆªdI,–^ tÚÃ`ÉàŰDÁäC ¦W ò0xE!Ða°—ËCIÁà¸ACàÎ< AuÂàT sfeM* sÝ êDAs¶L+G»Å~lšëf²º0eÑ->T`0!N—vÙÇ×UYŸ†aÚ’i§õ˜M»°íâu¯÷‡>mØé—ý(Òcs +endstream +endobj +150 0 obj +<< +/Type /Font +/Subtype /CIDFontType2 +/BaseFont /YJDRSH+Arial,Bold +/CIDSystemInfo << +/Registry (Adobe) +/Ordering (Identity) +/Supplement 0 +>> +/DW 479 +/W [ 15 [611 ] 14 [611 ] 13 [556 ] 12 [611 ] 11 [389 ] 10 [667 ] 9 [556 ] 8 [556 ] 7 [556 ] 6 [611 ] 5 [278 ] 4 [722 ] 3 [278 ] 2 [278 ] 1 [0 ] 31 [722 ] 30 [556 ] 29 [278 ] 28 [722 ] 27 [333 ] 26 [611 ] 25 [889 ] 24 [556 ] 23 [833 ] 22 [611 ] 21 [778 ] 20 [556 ] 19 [238 ] 18 [611 ] 17 [278 ] 16 [556 ] 47 [722 ] 46 [333 ] 45 [333 ] 44 [722 ] 43 [556 ] 42 [667 ] 41 [556 ] 40 [611 ] 39 [556 ] 38 [611 ] 37 [778 ] 36 [556 ] 35 [778 ] 34 [333 ] 33 [667 ] 32 [611 ] 63 [278 ] 62 [333 ] 61 [278 ] 60 [722 ] 59 [611 ] 58 [778 ] 57 [556 ] 56 [556 ] 55 [667 ] 54 [556 ] 53 [611 ] 52 [556 ] 51 [722 ] 50 [556 ] 49 [722 ] 48 [556 ] 79 [278 ] 78 [278 ] 77 [611 ] 76 [333 ] 75 [333 ] 74 [584 ] 73 [584 ] 72 [278 ] 71 [667 ] 70 [722 ] 69 [944 ] 68 [667 ] 67 [556 ] 66 [333 ] 65 [474 ] 64 [584 ] 82 [278 ] 81 [556 ] 80 [556 ] 0 [750 ]] +/FontDescriptor 151 0 R +/CIDToGIDMap /Identity +>> +endobj +151 0 obj +<< +/Type /FontDescriptor +/FontName /YJDRSH+Arial,Bold +/Flags 32 +/FontBBox [ -628 -376 2000 1056 ] +/AvgWidth 479 +/MissingWidth 479 +/StemV 120 +/CapHeight 500 +/ItalicAngle 0 +/Ascent 905 +/Descent 212 +/FontFile2 152 0 R +>> +endobj +152 0 obj +<< +/Filter /FlateDecode +/Length 153 0 R +/Length1 31828 +>> +stream +xœ¤¼ xTE¶8^Uw¿½ÝÞ·tº;Kw’&$$B ’a‰°ˆ ‰ › $‚(•UTpFY%: +ˆ !aIX$îÛ›'îèŒcfE3òQÉíÿ©Û â̼÷}¿ïßáÔ¹·nºU§N¥ª.#„LHÿÍ™yÍõÉ+ôG€Ás #y‹dÝ4ÿº ÷Cên¾fIsòž¬…$tÝ­ C©û] MÍ f¦žË"BÖξé¶YÉû4€É̹yá’äýü ¾Ëg5Ͼ9yßõðï»ùšýâ&¨óÙæù·,LÞ/5Byíä‚¢äýí9LwÍÍ3S÷­|€hß„þôÇ=3,åÿ%QúÄ_Ë´ò ÿO?ïW¸ÊJ8Ù= ®M@#ôÓO?-UP*ÿ—ßä¾é×€§œƒ¶þ!Ö }ðAM[ç $]|(GÈ8>à#„,y›R~ð=Bà«s9B.à“çBÞ³ùw¿x„„Òé_!¼Ø õd@^Öj„²¢O ”s¡†ÐàùÈ;ª‚ç£&ÀØŽ‚vUÇ 4Þ7ºà$Bc¡}5ÐŽñ2Bª®€¶Ô.ø;BuPv"äO„÷Mʸà<•ÓÉ{¨=ˆxD‚ +”jÈKˆC„;„ÒtØ‰ÒØ ÄÉ  ÍMœ¤Ï(&ßÀ’úu gÑÇ8‡P'þ ¹Ñ9ìŃÐXÄ¢ƒö ~ôr )h¶¡,äBW ±˜…21t/~$qkâktú z"qß•Ø Ï7 ×Ð9hÁŸXŒJÑ(š‰¾f¾@ ‰‡‘ˆÖ †&aº}ÿ„6üzõ¾#qÞê@wA}å¨U&^LœGyè^v#wBÚ@‡1Ÿ¸.1¥£ t‰%>J|Ž"¨ý= mŠáv +£Ñ*´{™×àê!ô$Ò°‘42#¹cð¦±Àµyh1ºíFoa®ãNp§·'NWí(Ú4}KðxòkL O|Ц£nôô—þõ°ÓÙÜt­"ñhâ%äD±Œà¹"îþþ;'žGFhÏ àÈxϵènô"zýúž¬H¬@c`^,F¯âápü#â%ËÉræ}4zÛ­]„¶£v‘Cè0: +¼ùêE_`öãqøZüþžÉõäæfó‹Ù§ß™(x´=… ÿB¿Gï`ê/Äuø<oÆâ^ÒN¾%?°"{7û3ÛÏE´^íçÄ„Ä?‘ùÐåh)Z¼ýêDûУÑ÷èè,Vð<?ŽÛq/þ–H$ƒÔ’f²‰²þ‘7ÉGä郖»™L&Æ bÆ2Ó˜éÌ<èÃBf9³8û³›y‡yŸ9Å|ÅôÁ¨¹Ùtv»”ÝÊîd÷±ïr—s7ÃßÜ1®‡{—;Ïç ïãÓøþ~ÿ uÂ:ááb3NÃyÐòÐ¥ê™xa¦“ÝÄÁ®À}À,²@Ïc0“aVüU0Œ‹™>‡¶9‰—µSJ^eA—‘…ø0*Á¯¢ +sã4艫Рè&Ø =ºÞ/B=5ÀçPzŒàݸr®­‡þý6ã!d!¼O…š6Öê6ý} ÜNèíz¡ +O…º~@W¢ëá ƒQÞ #p•f­bþ ø…4gà'® f¨P÷WLÐmBb™Ë“€ü6°^~tnVX ýȉkQ‰6 Úð>fØvüžÞŠ­dfb ³X» ½ž†1QÙ[…*v»Šý¹Òˆ¦0{è)÷™ç™ç`Ì‚Ìs| ØZibžE{À0Ch`Ê<Û)˜ŠÔ.À6‡Ž;\±¢îD\ -Öóó,j=Â<ì*†ìg:® ÙÏtªUE:.–ătÜ!& Ž¢`¥È +²¤®j6l8ÀCƒžAŸ$fóDGujx +*²T:˜§ÀµP!} À@럂¾<…¾Kå°ÐªßuJFúúßéT~æw@eThØð‡æCº ÀÀ¨RÂ<Á<Þ¡•J™y ­ ÌÃÈ‚1 +Bí[:7[;-ö"µRaBuµ3ãQj²â5ùƒtÖtÊæ"ʯ‡F¯‡†¬‡W¶AŠõ{€–_ßiwÑêïî°XuºÛ; +ãÉ‹NÅST\X‚03“™Æ4Jxˆj¹0êk™ë! íT;-JQ+¼¯ŠW€NÊ…Ç•Œ fz©b| e´Ø¢sò=‹:ròŠ Ç#^Ę`’‘:Š‚¡ÃŒª3m§d í[Û¡8‹Ž2«œ  Ó +¥ÜAËQF†‘•õžLé”LE+Ìèæ`KÚˆËóôŠæu@E•Vf“ŽA¹‘ €“dª™tïdsd팤{3¿Õ©~C+…×OŠÖðN“¹¨§Rb†ÃÓvæ~€ûõ—oìŒ •arP!¯€«ºÐßW÷À¨Ý#uŒÔ=Ш{@ú³ž¬ƒ2ÌRÔÌ,F¶Ã5+g0´[¿ÈÊ)êf¼Œ£VbÈõuJfÚ2O‡Í®ótÍEG™[@Îo:Ufa§ÛS4ÿ0“§we@§ÇO š;@\‚‰Õ‡]tHŽ2iÀʘ“Þá ¶Wáž +raò9N™DÞ'Òá¦^†ŽßNáß§ð'q¢‡ON +òŽ•iä ¨lù m‡+B“—Q!|Jºh+È'¤U>÷×î\ øPGø`éêm¤Ãä¢%/wÄ +RÁìÔ…ÛŸº°¹Š*³ÉKäEð´ƒäcÀY€_$=àÉ1ÀÀ= gß¼´Ö0ÀûRør„Š89H€Æ’Î3mB{‡@Ñžž¢ç;Pò®® x„@6@PÏ˃òõjFªÊ#Q€0@ˆ¾¹\à–Û¬¢ÚMLxGç«&$Ñ÷Ds€îpG´PWG´ÐÁŽèµÁJ @Qêáý0rÏÞÓ< ŸK¢g;‚‡íêÆ5vDšÞý}°Ò„¯@A–’NIáÉÐoŠ'u§B±‰Á\@±Žh„–΃eÃÓ\\NÎNQe%ß”Ù(£#XFK‹(Jb£|½yÅL'4è»n\ÏbÕì þ6ø-ÿ  âñI¨‹ôNvžªÊÁ#ùAáÊ`G¥L˃}Ø›ÂíïîÈ^|êÂÙ‚[ƒƒ÷çw‰}´{þŠŽà]¡.òŒj¶ ƒ óOo Ž ^œl̆üŽàUÁ#´™¨דgë Â±Ð‹ìŽàèì.½‰ÕÁÛ‚j0, ¡üEC’õ–æ¡@EÉ·þæewQ¿¢´ [Õ<á´°Q˜.Œ† ™B†.‡hÑ,EYE^dE""ÑÑ•èUctMÔÁëK£7ÂØ»ê¾†äqÝZá©° ·–UWý‡¤)•Æ~ùy.½ ´oª™\ß¾;ÐÐ^D/†šö;'‡®ªï&bUÕMÌ5Ôw³ÍÄ2jÍg›« ØI½H³Š¡(EPLB´è“´ŒQ²\È¡\˜"('›PD/‘Mz9Ór{O„FUí …ô2ÙÐËœÈF—”‰Úª½‘ˆ^*3„ëi)\ŸÒ–«W B‘ü ^ƒ_§WÄúËÚ ~)’*Rr±H‰þ.ÿR&˜,ãȹPÆ‘ebÿ?3GÄpç EË_53sTS標Míëoãio½6Ú»|}jg"M×^7‡âkf¶/ÊœYÕ¾<³*´wÐËÿáñËôñ Ìª½èåQSê÷¾¬Î¬ê¤•yMUCgEy}å¯Þµîâ»êËÿCeå´²zú®ŠÊÿð¸’>® ïª¤ïª¤ïªP+ôwšKå¾®~¯ˆF4Œ¼*‰;‰Anò‡F¸”æáT »‡…=Ëý‡X„w!C¬¡Ý˜9¢Ý@åWæWÒG0Ïè#3d[R<ˇ…ý‡ð®Ô#²­™#ÐÖ"Z¨¦½dbM{xò´z**íê5ÿyÌn¡?ý±š[ÿà~¡ðwiItËü-üO¿E‹ÝB“E±[ªiÏ›\Ó>x"´DàUMU 7ðBÃèy{%iTW¢Æ x!}½ŠápP•!êHß&*,ìôŠæ ¾â8²¸£@ŸÉâÎŒl¿,ì,(IbW)îð…‹à ¥@Jqv«Ö|¸Ø˜½1ci[v[~[)¹v@fp5¥;´0vËFÀåÂ`64‹¾ïñŽ´€þâ6z‹5ÄnÁ:¿þÙøÓ/2ö–T­·èÕ/¼0 Éü[R•ÀH$ß¾èÙ¢‘þp‘N”¬$yw1ùå·p­ŠòS_*¥/üÛ% ûÖx¡‹T¨vıƒdÕ0òŠ<§æŽ ·còÄ”³åýå”3åãûËQ\+ç!T¶†­Ù€E@çCLÏy•C?£ÛïB»®á!,Ñ +µ8‡Ë‘G»g²3\ž»Ì=ÆÕàšãâÊ܃ýkü[¹M.hÍkb·e[ÑÝ#`—dˆCïUí­a +†IØj ¡R¨¥‹¬ï šì‰AÓiÛÆ+-gc-ãûôFVèmD-¸Ñ.r»\6§Càé_f[‹‹J‡“’x$d>H›îìjÊ/5þîkŸìç|vGé˜åå7M¾Ÿ;”yI;õßûïn»®&/Ⱦt¾Äl›úêîÝfÙÌ´§¿ ø,ô”ruq7’@º*¬r…*ÕI¤Uj—z¤ãÒw”š¤Rdp /Ë Â*:Žz²‡çx•‰Á,•P)œg½bE¹ÞÁXŠùô¯¿±¥œá”òrø7¨·4.ˆÙa(0Ào±W;…½ìÌjçÇF~þÌó± ìpäBÛU`wÛ§‰sDlK\Œ+Ub•åk…ãa²¨«`6ñFƒ#™àˆ ©¡¬ø„P‰ÏC[åÊÈŠoô´yH³ç´‡|çÁÙ1šÁÕì0™Œ´„HÚŒø´½îTë[@û•>…ŠQ#ÜœÕ3ôA' O}t¤ 'á°Æ$3ƒçЛ°spqQ:q² Ú©¬‰ecÆ sÜú÷® ’ôgg©[Ù¡Ùȶ}#笼:"ë §3`, è݈I|Öi²V0´U˼ùqQ;•fñ{äcòÒÛò§²<™ibˆIðHÕü•â­,6uùDÑÇÑ|µ\›¾Ët€?à{]~Ãø‘|ÂxNøÁdJ³¤9U îTÍÖ¸ÅyÌùŽ“qÒ™kI¯Ð±Ù ˜Ü§-f[¹ÉL̦ºÖëãb¢e¡¸Ž3r“8–ŸÄž4«³%ÞFÝLš=Ãf£ú5Øj_5ÇQáQÓ-øHÒ¬Tq6TôSElÐ(a£B:†rw\( +#§+[Á[mt‡›¢öNI®ßV†+tÅÞp2fµ•5ê¯7«À%3}©™¾Þ¬³tåßPPÞ‹-ˆÅÊASÑnA1Ìñ|f()QPqbÂ.WqÑ`;-ï&?aÏà¯÷h[5;ÞïÃ6¾_eîºfÄ´(³dêUååO*xøñý|†EÓ^׎.[?ß´tÅÈ‘·ÐycÖ&²“زãø>[‡íÔó÷.`¢@ž&œ ò“ ohÄš fB;ÏÚ Ë0Iñö&+]xj3XLær:›œÌi'ÖE"#§Xµ¥¥Çn·-cT7¾‚ÁLŽªÑï&ôΆ˚68B…0ø^Ç+mÉéßï…þyú'ŒšYõe,Ö²`¼ræ$ŒmcAE9AØVf-CÀn[\f…„”An¬iWÀ +ÞH4‡§AÍÞË(xüôÑä_©fÐ vÅî…Äæ©àº§;á†â¸OÖÕ`Ûí0éÌLfF4J‡¥Ô \>‡3µu#³G^¹¢nâk¯ö²‘~3ùþ<én¼ö² ëM·4P òh­s µ,È«Ù<×íèö0£9<›ûˆ#6k¶ÉlF~%XbA¢ë߬£+( 4š­. XB8É,j Ó~m /ÚGjme¿ØHÐ!0’NO-d¦—@/ƒûøþ6OZ¾ûÚÍnxóÅ'öÜ:òê1%mÜ!Wø³=kºæZý³/iM¯­¬›c’AšÖ€‹Q +šEA»ÔœÍ–Ìx27‹[Ä1¶zós³•%‹1h$Œ #©0Ö‰±‹,Vs,Cx9IŠT(5K¬ä[aÛn#3l+l{lÇm¬MA*(¹ªV܆ öZ+ºqJššK ÍÙFïø“È£[Í>°;eEt.AwÁuO¦Î2¸¢rÑD X07nA7?VÜFmÍÈ«š®}Ù°IldóU%ÿX¹[û`î$ОCMÈ‹6«c¾Â§Äì?8Ù×ÉW0d^Î+‘eª}ª«Á³™lá·ˆ›]Ò‡äÜ¥§¸SüW&e§ø6ù/þeñ5#·H\ǯ+uYeƒ›j6+8Ê_“¿ÙOüæ0òúꓚŒ*²–³tûtÃÙÒ +bd½*ÍUfÙf¹æzXÜ]¿'nƒ!§efdE²T2aH¡“îéßö?8®½ùío´îÁ¡Móæ=ôмy›Hƽ˜¿G{ý»ÿÑ^^™ØõØ®]mÛví¢2:ú;ú›‰Šp‹:Gð‰i\Àåç“66ûÊçVi°·Ú{ed–wvduä7Þßúvøºý¯ûÞðyÞätñ^W”Ïu6x“Õd¿Ÿ7‹¢@VÑ ëS–ÏR3r ñâó³Îg‘¬êÕ… þ/ `Píl 0#r-à\tE˜ªÐ0U¡aÕ㋇{ûYÁh’ÐYϤ·Ž¡ÄÊ_ÕaHs¥SCиÝH‚Fœ¯E5»âF_mÇ›@–ï/Äç†g¸ñçn\ëžážïfÜÞâ”U©ƒÒÒ×HmK,yw’:6} @ì@Suæ؉¤ùî(à–†¾ ¶<+Ñs,蔬ë³Hc¬ì8µ h«”{Gçg”Ê&LOÆár‡aRFÁdDJ⃗.MŽ)¦3×I²—à™‰Ø{ïéªaüÙÚ7E`Æ<ÙøäÑ©üæÕËëæ×LÁWþ&«´¾êòQÅŠüeàÃ6¬;¨uÝ»êò´R¯X]ݱvÚ}5iÙ¡´‰£†iïÙŠ<ÑòaS‹"¥Y3åS@®Ñ5VÚ¨æÛø¹Á6Õ5ÕÓ¶EØ*“¤æôÖt2”‰‡:ãÞqL•qœ³Ê»U’TÄ9ƒÙ ˜Á F²;×lŠ`:©-äÛŽÓ•0˜îúòK¾||_ù—I¸ï¢ÇrošËÏ•ç‚äÏòÌMãÂáÊdUl0Ÿ!>q¸‘|öíçʽÓj?k/uÜ…½ý¶‚ª¥×¬]9ûú5Û¦7à(ØG3ö>H”óÍ»/Ÿ÷Ô“ß Ü z%ôWB Ô +ü;.[‰…â1ñs‘-7ŠDÃR -!Q¨àkyÂOb æ"¾¡Ð@ ¬t©Z–/U˺[R>n~QÌàö'üA… ša63}ýÃÈõýÛ¸Cç´§Îõ?@m·Ú6 l·ûU'—ã+ˆ 4ái"Òà€õ°"vûaóŒAe£L2±1>É'g |Ãë#8+§Uxd2â ä5d£€w‡]j83îRÓ‚ñ  î®b1\—½!›d«ž@<ÛG—ê9¬€ à‚x@z¸\íbÖÃ%‹T¡c(’”BÉR[ÒEyvæ€n©R8õi\ëCÉi­–ðóØ…#ƒÃÕá)¸Á}=žë>‹eì&¬/œArì&#ÉñÍ`1[c¨óa_µ]¨èo„VQ/@c‹¿e$ÞîÌÉSœÄOt¦gÑûÞÎ`VòÞëÓïU?\Ühƒ3ª3¶˜Ìx%ム>œa4±¬öc?DЍ˜ÆŒîü +œ +ªôûŒì8ÅjÀ‘"ˆˆŠë0Û„[ñiÌ ¬À]fõ’v”ÄXX<ƒ=ÍÚ— +U»ŠÝ*ÔëV¡R·ZRwSOÄ­fçBõZÜAÝè³î+|jFVÜâÃu¾„¤:ßBÍ»þ;£·g¨¼M2#ù°!iÉ[àר¨Y‰7UÉ`«°ä@|øö€©Ìè0–ÑËcp蛽†2”ZBl/ÏžíÒ{Iì?Xð Ü\2t‚•cÝÔ‡éYˆ}¶y×Ý\šípŽÕž¾üÓ/>ý GûÁ:£~~a(-‚_l¨?óÝ'ý¸ 6銜´‚Óa­>uë=Gî_?høˆ +3Ý™6k\Íê߼׳èÚÄ)î(÷> +¡jõôšô©Â­â­ÆUâJã*÷J¿Ä»y¿ÍmóçXs<9¾œtqŒa:;Ešf¸½]êYè;`> ¼nzMùX9¥˜™4>„’!d]£‰]iù¼dSͶ¸­¦ÖŽíªÓ·wá5Ï•o¡Ä!ï ÈŽÚ¦’`(Ä€QÍ(Ì Þh›Œ-rP.ÔMȽáåÛSnY2Ú§šW9Ó×b¥±ªè‡Ñaê³Òȧ%F –îF46â’°•gÁM&%q[éàâ›ä+ï¤N¸XLYÞ¨mßÿ¥¶ûÙžîûÞÃV\<@û4øLëK_|u¤ñðHâÿ¡¿kÚºñì÷¿À×ÏûÅ[¥7-;û=ø?‚~Þºh2ØiÚ¦º¯´Î¶nâ‰÷òå¤ÜZCj¬§ˆ`¡zÜÊ\Hv:²ÄÛ§Qnvékq.œÍð¬ÅIâÅE8Ÿ±øëE¸KWà’Fà_Öà“ÎS$RFÊ¡¯1 ¦—Ì„¡GçÞ¸ûrì Nª³ {·_qíÕ»7‘6ÍÓ;sXí¢“¸'i;Á)áÁ¶!#ñ¨#†¥±=˜s)mh\ —¨HaõÉ´ /‰ò_¥oe–•dÙNÒXE +Ê™d’ +äÙd;SºA^L–°OJ»åýÒ!ù¬ô“ìÚÎn”¶Ë¯IoÊ“ìGÒ'ò)òû…ôlZ,-‘ï&÷²wK÷ʉPo˜In`gKsä[Ém¬PEjØ*©F¾R¼Rª—\`Ž“¡l\&W˜†Y^’d'ñ±nIHiÉ aY⌂PÄ›Eé* ëDSÜ@½—fƒ).ªæhÜ@ÈÚ¦*ô 2ôd$R¶SÉ]–T¸ Où fø»ÃÔ|xKˆ%©ˆa Ã,1. TÃYBŒ2øW‚4cs6u +<nÓê®tNoŒsº¹˜<%Î ª°$á(]a9jŒ¤‹ Qm! +" +¡"ˆ~Œ´Ó EžH 0Jùß•rŸWéoéo)÷yf C9Ù‚’žVre’[³ì•5=銮¦Ý>4œ˜èÝk Ò@W(é"å‚äI ]lÀ8œ\­´>€ƒð­OûLû«ö'îÐyóÕOÕì]?/§2uÌ +°ã^ôgub½¥ÁÖàšc™k›ëZæ¹Í»™l6¾¦¼æùXùÈó5ÿµøµýkç9Þ>Ä>Ä9Î6ÎUíi0Î5 +Cm¥®R³˜[lYí¶¬óî²ítuÛ¸$³úãï·9âæbê«vzÓã:¶Xã¦C˜÷n¡j³ +E‘ +åPñFˆ aSxr ˜æ‚1.0Ñ SrIÒ/„¿ +ÝédìL_Œª#ÐF1ª•ÀZÄ’ 1̧î^•r©Pªgi3_W;wÙŠëf9±#væ÷_kî¾—¾ ßMžòÀî£Û¦Ï/xá%³'àìt>.‡ù¸xÅúQ.E#8P­ÑÉ»Œq&.Æ=ñÌ*2Jå©Ê4†˜‚ÜÉRSnkîöÜ'ùÂã~~¿±=÷xno®åäÖÁƒc¹Ÿçò¹Ô:VÀ}«þÂ¬à ¸ô Æàj:+(VkÔŸ–‰Êà­Z”ˆÍªN+i²âùVlí"ÕªÅçÒ o~nJÃi·/;‰R·µ¡hʯ¡X íŽBѨZ PGÕ¡—Å ¢ïD?2–h0ÚeP4-Œ&¢lÔ›ó×ò azjO,µlâ4P!ŽDφòñt¿:¨œñÒå¼>}Šž„!²[àGûŠ™IƒUêÖ 8HÖÌ’â’l+YÚcˆ¦EÇy®½ãò¥eéÎ;±ôjSù?Í+ž8jÐCøÞ÷ŸÔÖ®oçjðv|è#uÂjick;Ú¿.}À|`ø'#eK9ÆS®#×µˆ[$­æDÁ.¸Ýv·;—äÁ 9ÜVn³ô&óª«ÀµÀ„I +½è4/ê{’›28ç]xšêöä³¢™º>æš\kÁêýX¨÷“aË—Ëwæ©è;¤Wå+„9⌶ Ø"…B¡ë¿þå“åõ¤ö8¨·Ór2©_à¢1åꀂO'Du +]òMù9V…ª¶Gh¿ÿVû£¶/ÅqlÚu}‘ößS·þîí7ÚnÝMüÓO7àix~hûÕíÕ V~£ý¤}óí&*Y÷B²OšçëQsgQ\7C™ÙIsTápÇGãèV®7@7s§9¶•£Î ‘0Ÿ€Uj§{¢=”cTÌé)‹æ±ƒ.¸v .§“3›Êù½8G¨1z¬r„ëAšªJ7’ÛÉzÂ4Jç s]äꃢÄad”Ða\ÂI£jâdCl;˲^ùÞ‰ÛÐ…yuö‚Š8ÓØ§;Œap…’ÁY¥ÅLD;õð»ó0)<Éfn•Èzsµ¾~2”œð¢{Ô!‚(H‚â]Òhq´$\)MU6)›­[œ¸v*];¿àÏò“ш²í’Ñ2½C:Y¯f¨þ:“Ÿiö·úIÈ_èoó÷øY?΄¼…Þ/ã¥JÀGö¥ûà Î6&¹Ô§+6QvpèÜ¿xtŠ™¤¦ÉoqŽÁ¾áŽå­>œSxç‰çßûd¹#VøË£C¦Ý<{ÓóL켦ûtSÃ5\±ü,] ž¢Md›ôÕà/×olÉëõù6 ƒ@iu©2*Î +Û¼…W Ï¤Ö ©õ8yaÁ¤ÿLʬ\XËEzãô—wHƸ¾Ý‡©OG­IAÔw¡.¬Ù›æZæ:æfÏΛ[ ¯³¸9—ûÂn (²Ô†ŸŒXÂ>û%+/·áJ13u^i¶Ý´¼ç£e×b|ìÕV, o>¼Aûþ/çïnš}ÿÚ93ﮎq¦‡]ƒ2¯~äÙý>Äì{î¡ó£º¡¼û~3¹ûéGì©¶GYã_²ßƒþ€«—u[»r^À‚’s‚’szb3¹™9 ù%¦…9Ÿ?Ê46ÈW˜¯ÈhÈœcœe›ž›3{ÀâÀêÀ¦°Ñ–©ýÁ8ÅêLò'fLÌ|1ãÅL¶%£%óÎŒ;3ÿœñçL>&癲2²2ËLñÌÄ!cdæ ¦™™·™–f¬3Ý“±CÞiÚ•a—dÉÄgð™^Ùkre™²‰Åî©ÕŠÏ÷àùžíâ9Df"? ¼BK?öç;4F_!ë Å“ëMx#nÃí¸‹øï¬ê+SXÌæçIžïnìVíFˆF|ƒÑ6¥]!J þΚÚ}Ì/¥hk&×ïEê‹FêÒŽ- *W_8™Ä b'é +€®¡ô?øá ~Oá¿vØi¤ß îÞì°Ñ»ãªÅVf +ÙÊd,4ï+°¬g*“=ìe¿:cÔ +NœCå¡&ºU#5̨ÎÜ!?!£Æ† aô„ä¶ý£ûCÝÔ‚¾HíÃ8òm_³áË.wÿ½iÍŠïžÆàÚ û²ewŽ-0·¿³èÞ:¦}£}„?K{`ímãcý¶Ã¦Þö|ó˳¾ËÔr]IFY<»`ÖÍG×/ÿãà)ƒ|y@| òåB]*XœÇ†”µmõp"{ÌCœ.+qØ\V³Ý‚³ž4uH¢Å€gb sWæ±Õ’ …u?“H=MϧÚ!h.®k! cÄ¥À:ÃJ¬Ô 1™íâ˜Ú\=.â¢ç`zº¼î%ÝdnRÏÇZ’~ÆùFPóÞä¶!]… ë:eE)?ƒºƒöbs©ÍB§³\°5Ó³­lë¢%·DF¿¬ä½÷´SÛØHÝê•“³^QÊ&Ö|vþ 3éÿû⇰dÄŸ©ƒˈ'²ÀI~ä"é¬<‡”.[F[Œ‰ñ™†2¦ŒÃŒá·0[x=VQ—‘e9V2ȬÑ|¬‹sH^Ùi4f¢6ÊåK9rÔ8•rÃ¥j4šŒæÆc¥Åh »˜[Añbã´–]í•ÖÊkŒŸ Oع!rþÐø ú†=É„èù¤ñGô#{–;'œ•~”ÏóSëÿ"6›x}ÿ9××8á Ò;Ï ,°˜—èŽuªSnr[`ßK– u%ÆwòÝv%.W‹d cD³F†“ ‚$ò¢ pËÒÍ=ÊEšW˜‰Ùíö‰•6£0ífdPƒÍûBØkz¥û’céóŽï÷yúû}Þ~Or‡àbΤþôéçhЬz+õÓ4-1DWèöTStó\‡© zy̠iÎé#Í¡ˆ§s×@ïz/,Öéó‘.£Ó‡äÁ€0Ãà­[_?ˆ-{߯NííûƒûØHÿÒEáçOÉ3ýW€†‰€ß_ž‹ŒLèsµÌ^2z1ãdãÆ¿ù>æY›Íæ˜Æ˜¦›všš^3I˜ˆÈÈ›`žI@F£ÉÔ…ŸW}É…ºŒabL„•‘ šzLÇáæ0ÎA"0|ßIJ@Žhý>nƒŒå.LT›"lŽoé³T„¯ù¾Ñy{²…°àhPç¢B9Dç¥ÎDŠèz»LyfKJ+ò—ÇoüÌÈ麜PԃȤ[éÜÁVL–÷ï"w|{à€vZÛƒ£g™ß¿úí’Žÿ©€3 ‰›ùtÐN”ò²Õ5á‡ÑÃŽm®mn~‰²Ì½8´Z^m^«¬u¬ó‹|@ÊöùGØ›}£{)"Ü Ì–·ùnK¿-t°ÎºÎ·:´UxذÉú´pÀõšë#—µÔ_o+Ì•—¢ÛžÁ—£«ÐMˆÍreD£Y.1<‰¤å[ð".ß©ÍÈ—Hj}€táɪ…ù@’"‘ 7Jjöäa[ꄆžÐæ©yMyÍy­ymy|(ïtÉûbÄôD¡‘1R7>wùËÝø gOö[Ë +PÅ™¾˜Ò¯%#Ó”3¡;t´±1ÛŠˆî _ðê‘Õ!ðÙƒS.‚“ºö¥‘h©‹tsëÍ#UóÁ{´çµ;q+‹«ñò’íPYYïþýþó³jÙ´ÆÉ¿94a໎Láö +|?žƒgã Z‹¶õ…óÔ‘/Ü®ý|¾_K$œÃÂOQ}6d¶|]-P3 ¤B¶«“š¥Vi£$ð˜#Ù ‚%zÒgõ¿q>(p!„ ýà’ÞZsi&­d#a‰Wì6ee'Öï%* uyƒæòÉÔ&©¾9ÞH…ˆîŒâϵñì}Úö¥sç~Õ^™8ÅæÁLrƒzTvƒa‘¸FÜìÝÉíŸ6ï¶w›XÚ{¬ïØMNn°µJYêÚOÞSŽ;„Ãè g±à±)þŸø©†K·¹âþS0\&aîÂ;*$¬JÇ¥„ÄH]¸¶sÆà9†ÕŒ [À––aw89|-N?Q ~­/ÛsÂæÍzÿ¥_V‚ZRZ¬å Dm-}±– +€ «©í¸d€&€½±éG9R«A—í´ÿõº‡–®ß°jŒäoè9QIêPcÄeÔ…WFàÖ?á±$p..‹Ô[çX9Œ‰ÝaµÙÁúªu€$Yv8eB9"Júrµ„–þ·åj䈸œ—«˜ûß—«/F}ú" hn·~HB¼°kiMýÕjŒ?³öè5ÛjÚ©ÐÄ˪çk§¸Cý_lÓ¼vCÿdÐÎi%UëV÷ ÖOD~É:R2s\­f­±Î4,׉OsO‹;Ì;ìûQ7³ßÜeÝg½eí±[ãö©†Ó ë${“÷r‹][ÝŸ)Ÿ;¸9vœ¡ ¿DHMЧ„C >´ÇŠ.B…®•>—N§D¨-)BûˆC‰¾ÃîOJ‘És¢Ö†m¾ì¤4/‘¢3)9ú_¥(µñtÁ÷+…‚”ÄÑÅ\ÿeµ±+ò”QW.µÞ°ý¹Ÿ±ôûÏqºöÑwÏ~@®^6iÂl¢ùxrú亶ó·cÃGŸc«¶S[¤ÍÓ¶dÒÖnºýÞûWµ"œèGˆ«†ŠèÕnÄ&^P‡JzdÌ2,Çà²0\ò:D° ¼žâzð ³¶ŸÅ a$q²ˆ§ +]d¶jàyŽcB(&n¨›'îý‚ †é"îƒøâ‚Ø¬Néêëè™õÆr¯rÒ£ô'ÑIz>A·ügO&Í•U7úÖÔ +6=^ Ø£_Ðm¨¼¢ Vì™Z+qõŸÂÓaæLÂWôAæ2ûªóÏõo…¹3ôd'}¢­q¾é$·§­O#;˜§¹ŽÌ!î€ãSÏg^ÑåÀ÷¹îs“°l qÛ]á I1‚ÝÍRµ&¬š6˜ˆÉ~-bKÐ^`'v*=ö~dcê%²Q¤ËFÔÔnì1£Ñ¥œXÜÜÜ<䂽‰Ú,œå‹¹N¸ƒØxóþMd tãÒ¨KÎI=¡·-úêgòÜdò_£.BÔí½>@´PêJé!{8WÂÆô¬Ùx¬˜L¼rñ‚Iƒk‚ –Ô3Ë õûo~ù¶w–Í~ùfíË÷^×~«Âsæ­l¾áçÌÜ+ÇÕ_ß4`Õöé+oZûâ-þ#«^ÔN¡^†¸cºu‘qe7'T©´,Îç@"è1~NIœW!»j]8 +Ï ÉEy ÿsäãp‚+Œ7 ÈLf7Gœ-ÅXÆñà4I˜ß’$*>‚!—X6ÄñŽãEYõ†Ëú9_ .g†áYúÍ£jæÞ)F¢ŒÝ5ª!ˆõÿª¨3¸‹d©RPÂ…`‰tˆd!JH!°}^Îä /ÌU°õ©ã«¶áÆ÷é{•ý±Xù¯wV¥¼|Í+¯¤|p)N7÷S»-†É5íéúz)“Ð:DV>”ЀSç÷òìý4+ _Ò1 ‡øÇ”a¸cÚ ­ýnÓ^#ÃpYÞ[¯áñZ'wèü=$ÔßKíúÚD2<.U«æËN†2 I +²‰GqýOÔ EäAU–þa|$ÄR¹$›:­OݨϿ¾þ3}JuS P83BJûàÒbBœ›ÛEf¾¸µíº©+{Ö;¬$S›x +ÿ5L4Ò{T{W»òïOj»™E[2Z¢ê-«z¢$*Ï&³åÍd'Ùe†`AAðϦÐ6!$%Û´Oü÷ˆ‘¶ÆvÃHÚš¾þ“¿nŒ}8S'L±þYaFM®š6kݱÍ;GÔ<«MìxáÜç‹þŽŸÆkéçÞýN;£ýL-Ä&Æ# NFçÔ»Ê,c-W +7n0î–všÛ2˜OH2/ò²[tɃÍÕæj èÉê0;,e°y°e´e‘ù6å}ÙA˜÷Ö„_ÞÕ^r9$£Å<ټȼÒü ùwfÎ2&“ÑbtšÜ®l»âÀMŽ6q8P(L™™Ìf'ÍT£È¤€ÒøÀmãÛùþ8Ïòkš3q(³0“d†—îd ºî—…Býˆ,U„ï—£gzx´f`¬Ñ ú[S–D?qG7ŠôU˜ïn{˜H23­Ö_Î gn"óÿöaëK/6-»¡S{ì£S®žUþ‡o(¯“µìoí[w=õqÚÕÏ€RñLC¸3!«~ĸéÀhOMZÂí@¬¨¹¢9d,µ²õn5=fÞlûÔ,Ù¬vÛ¶U64¨I†xÇfµv‘6Õe69Ìf“Mv„ôà LÞ¨oB\¢6êZÓoᘦš‚rLdª`å}ª;\qº%¡:G~FuX­A¥@!J…R«0 +-ªÐwÙ-3kQ@ÍwcÕݾ ™º6Ób|ä8ý²g;ÚƒäM¿Fû3'é ½ ÎŒÒvCFì¢n¤‡èÔ¿„óÌø¯pÔί<à+€UÏšŽ=Æ[Ç×/½íšÛšNn$§úÿ>àêkcvîíí·fÌß°qÍšÃägíÇ ´ÓŸì¿ÿ%ú}ÐêLzºÿ·j–À{·ÈÚDÐx] Ôi3èßÐÐMe=ÜÏ›<%Î ¢ì/#"€­&D‚–î'³t?™-âßÑ×Ú׫^ÕPgh20͆Vi3ôHòD¤(¥*¥X5Ož—ŠtIí¶%Iþ²¨­oÜ5^X׆;ÝÔ¥%%~ %ù@¦W•ÌѸJîÀ÷”èž¼®4“þH½TëC‰Øj(Ñ;v™o`\œ Ǹ˜"FeØjf•¸Ql;Ä“ ÿ +óŽø©È„˜1Î kÅß0ÛÅ6fØÎ IcT JE-ÖQ¯j*(Š“MG älV¥ðÀ8™‰^º:=wˆD<„q HTFŠ… D®"SÉAüÂx2JxXxFx›|B¾"§„‰!Jr„qήž%<ÝYpq-]Øho@ú>;ÝÄÖ-8Dê±]û¸/èø|æýŸª™#ç«è·€“ÁëusôYÉB…Ø´¿P ã‘®Ä9õ&¸xÝúºýcîc]¤ÜêX©0”gŒ†«ÑåÆyìuâlëçâèšèfÓÏ“¦§=Oûv¤ïŒîðta·ï`º{±}µ}µcM”Ý Ðfµ´[à*&Ñëlf Ok’‡Èý(zÆ.O¼9­5´¥á´4Þ–£óŠæ¨9$§‹Ü¯šl¦ŠŒÚ ’A©3hŽç‚'¤Å±tûÌWä=Á,Î>áòúwŸ‡žšÑ#k1E÷vb}úâT#=êJù;ˆÚLI²Jj;§ƒÕäãƒ/]‚g.¹Æcn¾î‹÷ß=uCÓÒZÿÇo¬zôÖîµuM3&Llò-n¸rÁ†Ù3÷ÀÇ›žüè£'gmÏtäö·µ¹wœXü:ž8åêSjg4õ_¶ð®e·Î^v?Õ†[an¾L¿hè>‘Ç6›,s೿9“DI»ðA5&ð0%y†º02¸0²,Ë"3#‚ÿ,Ðõ4Lô¯ÒD0Ô×wpcD@ªMð…L…`@ˆáRKa¼ÔRxé¶¢'ɾ¤©€Ä Æ"¹‘t¢=úºÏE/<èrñ†¦©ïÖöK!ƒ~Dæ­1J'"]—Y¯z#|TÚÈnáÛØv¶‡Vò»Ø¯Ø³«Ÿ*”ÔYp‘Í_&/dV3[™­ÒÃònæó&#¿ÈgÎËÌeò†,h¡~[“ðð‰¯¨öâéú¹Ýb¨` M.HŒŽ +6d°Q­v¼ÓâMb³;‰¡„Ž¡ŽSå:ÌöŠÔú¾°Æwé÷v[q™Šïï?Aªµ;µ›OC˜¹ˆ¬ïõü¤ýŸÚ(É+!ºö€]3 Õ4.êUY¬qÙà3 e‡Èc¸©†Ý† ¿7|bÃl`4H¡ÂPk` TÔ ‡Hbð³iØ$ˆFõúÎú1iRͤ–ÁŒÏD¿)L‰=–ºvÒŸ<ݧ|ae~4êä q‡m¶Ò+™Ÿ½kÿ#ô½Æ>޹ÿZ¤Óì/áB²äGˆ5‰¯ØSçý¥ßÅSÊJý£ýÄFÏ%'O%ÿ ð%ì0Ó0{‰[cª±ò?(l•d£¬0ºô¬²Ý`° ùÂYe%—0 Ý„3â=©œ<õÿoç”õ 4=§œ<¥ÌÑÝ3}'˜®”¤Ž);í—þ_ƒ½wu¼¤iýÝÓ÷ª¶øØÛï^9{æj«Ój§´µÓÚ§Ó¶‘¼§j›·?sàñG©Ï7ü3èGºèü[µf‰¼VÞ‰w Ôã;(½!‰S­ ®ßÔ hB×ßì XFÊøÁÒ`ÓX2–%U›vJo“7ùW¤WLŸ?ðH˜¬Š'ä!úªH6Œ«g‡h +Z +,ÄBGÙ²qµ,f}Žoø_VŒ¨Ó#üäºG#†ØËªÉcB¥ƒÝ‘ÑÝ|=ØlU"Rôá’ ø‘ö¤Åu®@¼¶8‰¸ž-û´ZÓMx,Þ;°éëÊ)7kð{Q­œrÝ•±d—~¡vZÿ®v£z™Èðeó¶ ‡ ¹=á8)ùéƒ,e(ð5 #ƒÆ2èŠE51¦_ý`üO_?”Ÿ)¿øÝ¶®™SŸàõtʸ®Dk‡OG{õ­¯†ÿôuDØù[qþkÒÛbŠé‡ÐZ~€ÖCë0‚\¡ÎØï9àëö¿Å¾î9î9î=îGúG¦ Lõ>Â>äÙÍîHy_åð¥¾1ìHÏHïHŸ˜åÉòfùW„Ê®õlóoKÛض; Úè7I¡À À­•¢þÁ’Ëገb´ýƒJ}pw`|wl´ÐÿJ&3h,€èŽ»q‡“N¸\¸–~m´œPðSƒŸ4`åt:°—ëÓf3¶Ç’gŠÀ-kmC‡EGªY)cE¥Œ­€­e¿Þ.4H~¯Ÿøí˜þ¨©X__ž¯™Xù½`{¡ÒÞT ²f ¶é[Ó©ÐpVÊ8BÌ!°ÆóQ¥íÛbCg6Ôϵ¯¼X|í“s£ÇkgG»0§ýü –þ°·âÊ+®žyÃíi_½õÍó×u^[y¦.B-F©IÿŽe‹º>Gxƒ%[„nüGü¡pÚĉ‚õð0*hˆ87à;ð"AŽà˜0ªñ8a‹áN²Ùˆ'ÇÙ¡òHv‚ü2+^.OaäëÙ›å%x™ü »I8$ÈþQ>/›Vê‚È O.f+äjVr²^y¨§Íçðyœ>Ážo’¼ùãŠî‘1’9”<ù­† +jêض +œ€mC˜~#X¨G÷v¦ýëKcËÅÏ(1ýоÑ/¥ŸÔ_ØHÁÛEëÑ0²è¹Ùë:q^¥-׎jÝÚr<è˽{ÿúÙÁƒ½äƒÞ-ͱ¡Ú<íaíQm>Þ€çü¨%‰óçô•ƒéÚMìµìpdEô¨Zj+'qSÜQž6ŽT™ªãÒÄæ ˆ _ \ƒ|¥iª½Á F%°CÞ‘vN:kúÁa´"³ŸšPÖàLšPÁ¢ðž°èM·åbŒ"V«nB¥ +V|ÁäÁ•³—|ésæ_>ô‰µ¤>õ™ËÍ•gÙçºçzgøÆlåõc'É]zîäÒ%bflé“3ö/º3=ÿ_sÏE•å9·ÝUÝT¤jš$7$˜)ɃGˆ¼H"=tÞ¸@ð±ã˜qtÀwP|€Ÿˆ³àH‡ Nˆ¸Ëî~ß(Îçî¨|:î,+;2²«ft™Y »öܪî0ã̯ý¾é¤ê¾ëÞº÷Ü{ι÷œSë÷Ö ûâá•«y¨³óñØí,cö’íÏ¡†€ã:n{–XŒŸ¼ðÜȱ½/óùÍ÷N +,ò‚‘«ˆ’*0EÍSÑt@æJTÌát‘œºüoYà< =!Ðãéõ0ŽNö{N{ÄaZ5Á+º¿Qjxð­ k•,œÂ9>Â)ܹ§$ÐÊðߢíêqbì—ÑSD*ü#»åJ#ûnô¾×m^dÓ º¨2Æâ\&Ðllu0ü”eK§àwß~ƒÇ5Õø|¼Ÿo1;°Üðnì1ŸôÙ•tÞS›qÛËI=˜bøùFÃJKÐ\ÊQ¨—ì©/ГZO¾lÖ>BévÜÈf6·qS úlè£ì /«•åñ9a/>qÍÖ‘*Uö‹ïæ&âyi­xa½)–u“¥ÆQâ;˜ƒké1±R–^jaå«d–œw|~E|óe–­€Ïiël]Ð>†Ú ?Ä Ö\NO³Î1ÆKZE¼jŠ(”!#¤ž`+Ê[Ð#ô «,1l0*¶IÛ\—¥Ë.Q¦5u•´ÊµUÚê’¹¾˜ìR A\—œNœº¦–ªµ|À¿5TAgmÑò Ú=ýîƒuñ]J‹<Ö†R2mu²TÊÊ­ûA®Xvi¤vYBÇŒÁêß_Þâ=TbäU(ËU¢ª“óP—ʈD:æ|ë¨}*A“±ær|ÍI¼ùÛl‹àáâ#gÅ6ˆ÷›~zr6QƯ ØŒŠD–òñâíKwÅ6¼òJüëÒ‹_œn<Ÿ"樋ÄU<*rU^tý +Ï:ä‡]OáÂ3Ò“Žg”'\?Â%½Ž‰˜çhÇ¥Ž‡…°V” +œî`>UKÕzq¾z›ú¸S}L|NÝ/žÿSõTײ[Ü«¾Nhò¢CeŠìrNÙ% +N Pž…õëøOëX×᩟ÊFš·Bnâ;ëýÎl0ˆ§¸q§Ëš\|ƒÓ¿róÍs ÑqìV8DÞ˶ïDw}×$èSô™b,ç‚>@¯#¤ºR ¦¸Ôt—KUd‡Cw*éN§"ºÜî¸ÂËŸ +²U_ÀÉåJH|p™¡êòk®×ŒRËŠH™áÖmQŸ'qâÂ…‚‚q© `VâÐå/Im“šGÂÓh'!2Ä•[â»oü¶Ñ’ý!Øá²?@«b°ôº1„ø_XÛûYì?bç¤Ák)Âç×h¾Ò(ι:@óœãÈ.‚ 4Zž‹à—Fíݸ6éž‚ÅË¢¨ø½Š<±ÈŸ›‘:λÀËʼǼÌëMŒÏMMsêéÜ€VN~Ü+3¹ibþ1®ÐcË pñÂ$%FÉÂ’PIOIoÉ®’ý%N½¤¬„•¤×AO+Kci‘ÿI‹ZöÁÌ™—xì4¯H½£˜³§ÏöùT²ekC¯²D£Òüü¤>¾¥ÆÍH¶I®Ä ‚âò{ؼ—në¸sÅ÷wŸß:/ö›˜'þó æ/kšWôöLÝ_8k‰qï›ÒàØåO¯XóRaþ©V¾¶ÑãdâÏb?–”e³ë[)z2vâÞ:ky_YMêçêg“úA ¢7If)oµÐÔ<í|ßcˆHW»Gz÷°§Å§¤ç8^qÉ¥N®ŒrÞdÈ“ Ož ³åe´\‡p{#Î:K$â½Ë $匃¯4È:¹Õp.èéñ±WüPÜž oH3ÑÓÙ¾!ȪÍÙ¢JjN +zW°ˆÎ~{s0¾X3gÖu³‡¬Sì…Æ¹L2ˆ$ SQ¨A*±Ì!J‘½—¤½|õúÑ*!çšoÛ„ƒ64äãkõE-QP] á ¤”{Ç//^Œu;–»Ò}Ž÷@Õ™eÕYoÔJ ¬*ËDê14‡,³qZ—P÷‡W!å…­ÃDJ4¯‰jåt%Ñ)SËSSYV,éâEiðNzîW„–×|_:ÿß3 +d-)­BÒ´ÔŠê¬jŸ!µzWguÈJF¾qq“-7UI`»kϸ933> Ǩc¸E´NEÕ—Ý’èfmãÆË ™/d[{ ý\´‘ëwåçfØ;»ìæë…¿>ùÁ'ˆ™’^ÖÕ½˜0kè•®Þ½_}ª§bÁÆãDOˆ-ÂC–n’vÍŽ<‡žy³ã§Ô›‰±5ÞtæÖ”­2Š^yàß)ɘžÇ4 ¥ìp;@˜é)׸ÌŒÌA¶ül}±ÜVã}ͲlûSqœ`Âl£¥°6Êv#g¼)éö+U&´sEßÔ'·tVMN$V¦Úw]½úóÃßJNþB”r+¾¦ÅÍþ\›f_Òëð¹»Åà1q3:§A9WßÓ°sÃ9QÓk ¦¸Hoè‘·êúv,j#ÿ£õv=2dù›-ÿ.Ëï!¿ßOô†¬µõzCzC¤qëÚpC¨ž×çRëu«Ôâ"èS]äu‘/’èéÃÌ™hyXfCu§‡ÉÔ7D|zÞ‚ˆÛй2²pQ[C}Žßß^\Áºî@W¸)ãB+ ÔYÕD予êF_Çßvè}E§Ã;4è +ºWVv.o‹í¼Ž”Bª·>’yß…¬ëAzxj]Û¶‘©9B¸!k΃áð6=rzQÛÈT?¿··Ó3¨,Ëm …©êÔ‰MÜöu„=ÜÞÁ‡©J¿ +ûýl[й¡õzD Ì +¬ ¯ÑÐd‡#°ø^ÿñìlã¤y²ôpK[À©Í ´wÖéK‡ðâ{û}†îR\Ô§¥ØÛ—”÷¸=#=«†Ó,Ÿ•ûš÷,òæ@DônZÒ wªâ·UUlôkG*YI#².¢Ô…ÂZ5çå#R®ÐÃ_A@`è³Ñ1ñ9Wû¸—ÃÉ0¨QzÂ),ŒpqÔјRgZá©ÅE[ØÍM'‡ºRßv¶W—R÷ûý|€w ÐEHï¢6;¬CWÎq0J Û#,ÄSN'R¼­<¥7‘2\< H¶ˆPðFœyÃÿÉZFZÃÚêfü™äUvzÓ’@ñ'zC8ïÛ¦–Q!;½j8-յ 9,îc9‚•J@¹|83´¹#b.ýËP¯Œ”Vê-4Ǿ·«~ÿ7–p8G0¿à¥,çz±x+#Õ…£ÃÓG…GµÎ¨½bkjé‡ÕQi´…ý1 +wkÔе@ø$;̇{B‰0wäDw¶ÓK¬ÅjV³ú¸}QŸÛ—t´ÔˆœÝÞÒvœ8ŸºÐ¬ö¾ ”ÖvR0¬XÆcy$è<MHp~œ9­ü9' €^+U´"¬p÷‚çLÄ!t0;N³+ʳ*2ˆÞèí#‘[¤8§×kçžÏí¤§ Z6³­DûÇ b¥F‚ƒ5ÇÚ‹íöÍÀÍ "ÛOî‹ÐK(zBü“v:Œ‡|┊ J‰<œ S *`*Ü •PÓ j`Ì„Z¸fAÔC4Âl˜sa4Á|h&®k,„E°–@ ´ÂRXmзAxžNè‚nX «`5¬µ°Ž¨ó p;ü ÜwBl„M°î‚-°î†{à^=MÏÒ}œÕʉÔÊâ¿ÊVñh~ãÌÏ@¢–¦@Èæ]0¿0¯š¿3£æó B…’ÌO‰ÏþÀ*µÏçà\œ‡M8›ñV\€ q.Æ%ØòÿÒ7(œe§ºœÒ3R9ÿú´í +oÃj–ꔘË!2þᆯE·4×é4tóšô.q厙x|T™æ­¢bkÁÆýÌúº¬í¬ïÌÚ~‘ü3ã~‰üKã~™üwÐ\šG3ϯ9PH3qÍ¢NšC‹iV­¡™s;…6}c®oŠ_J¥ùÜ[Góðz—É´V•Ñß7äÿ?›dÈ +endstream +endobj +153 0 obj +22557 +endobj +154 0 obj +<< +/Type /Font +/Subtype /Type0 +/BaseFont /YJDRSH+TimesNewRoman +/Encoding /Identity-H +/ToUnicode 155 0 R +/DescendantFonts[ 156 0 R ] +>> +endobj +155 0 obj +<< +/Filter /FlateDecode +/Length 649 +>> +stream +xœ]•ËnÛ0E¿@ÿÀeºlñ!Å@Àð"mQ§èÚ‘èT@- ²¼ðßWæ¹q‘ +°…+gæp†äd¹YmÚf0“ïý±ÚÆÁì›¶îãéxî«hÞâ{Óf¹5uS Ré¿:ìºl2NÞ^NC)ñ‘uŸ]¡Ä÷Œ‚/u.>YÂçå>'Ÿð9ÁX Ÿ_ à+ÈÚÂçe Ÿ›£à+4>Om-|ñ,| _©ðy,|žÕµð•ò)>Ø-|> Ÿ…ÝÂ穃ƒ¯¤C|%•vðYrqêOzÐÁçapð9rqð9̓Ï)|Z_Éš9ÕO^àóÊ >'%>å_IƒƒÁ«Fäâa¬‹'Ï€OOžŸþš§½6mÆB&/ä鵤XÊ'yEWŸÑ^uPžê3T˜â…Úí#2 –1º ¨ø ÔÁ’g AcâÓ<ÕAJû†0K>â͉C A™Ágéù_©1í#T¡^¢Ò…΂y:6u>ÞNËÛéêÖÅÐdM­}fØ!uJEå³üâéz2_/šÛPû~<þÓ=“Îýl<ä›6Þ.¬îØ¥«cüeæãŽ. +endstream +endobj +156 0 obj +<< +/Type /Font +/Subtype /CIDFontType2 +/BaseFont /YJDRSH+TimesNewRoman +/CIDSystemInfo << +/Registry (Adobe) +/Ordering (Identity) +/Supplement 0 +>> +/DW 401 +/W [ 15 [389 ] 14 [722 ] 13 [500 ] 12 [278 ] 11 [444 ] 10 [278 ] 9 [333 ] 8 [500 ] 7 [278 ] 6 [500 ] 5 [500 ] 4 [556 ] 3 [250 ] 2 [250 ] 1 [0 ] 31 [722 ] 30 [500 ] 29 [500 ] 28 [667 ] 27 [778 ] 26 [611 ] 25 [500 ] 24 [333 ] 23 [500 ] 22 [333 ] 21 [500 ] 20 [944 ] 19 [444 ] 18 [667 ] 17 [250 ] 16 [500 ] 47 [722 ] 46 [408 ] 45 [333 ] 44 [722 ] 43 [500 ] 42 [611 ] 41 [889 ] 40 [722 ] 39 [250 ] 38 [444 ] 37 [921 ] 36 [500 ] 35 [278 ] 34 [611 ] 33 [500 ] 32 [722 ] 63 [500 ] 62 [500 ] 61 [722 ] 60 [500 ] 59 [556 ] 58 [556 ] 57 [444 ] 56 [722 ] 55 [500 ] 54 [500 ] 53 [500 ] 52 [667 ] 51 [278 ] 50 [180 ] 49 [500 ] 48 [500 ] 79 [722 ] 78 [333 ] 77 [278 ] 76 [722 ] 75 [333 ] 74 [278 ] 73 [389 ] 72 [500 ] 71 [500 ] 70 [722 ] 69 [333 ] 68 [333 ] 67 [722 ] 66 [722 ] 65 [500 ] 64 [500 ] 95 [564 ] 94 [564 ] 93 [200 ] 92 [833 ] 91 [278 ] 90 [333 ] 89 [1000 ] 88 [500 ] 87 [564 ] 86 [333 ] 85 [333 ] 84 [500 ] 83 [564 ] 82 [444 ] 81 [778 ] 80 [444 ] 98 [611 ] 97 [541 ] 96 [444 ] 0 [778 ]] +/FontDescriptor 157 0 R +/CIDToGIDMap /Identity +>> +endobj +157 0 obj +<< +/Type /FontDescriptor +/FontName /YJDRSH+TimesNewRoman +/Flags 32 +/FontBBox [ -568 -307 2046 1040 ] +/AvgWidth 401 +/MissingWidth 401 +/StemV 70 +/CapHeight 500 +/ItalicAngle 0 +/Ascent 891 +/Descent 216 +/FontFile2 158 0 R +>> +endobj +158 0 obj +<< +/Filter /FlateDecode +/Length 159 0 R +/Length1 64316 +>> +stream +xœì¼yxÅÕ7ZÕÝ3ݳ÷ìûô¬šÍŒf¤™‘4²ð´lɲ- ¼IB26Ø`Ëò6c±c XvÁäµ,/ [Pˆ!!ÄÁI¾Nâ(8yn–tOÕH¶yß÷»ÏwŸçþsŸ'Óª½ººªúÔ9¿sªZ#„tˆþÖ\¾bU9†~®v d”“Ø^¸oÝÊét=¸û®^qM9Íü<ÿÊÍýSéOoí¸|ªÜ ¡áÞÕ}×^QN‡8„^¹jÍÕ¯)§?‚r„êFjAhÌçÌg’j7w¡ù0‡í›ºÚ¹æeÙr„ºnChyB—Âó/c {wƒû ¡+oG¨žs5ÜÓBð7@ýkúZ¡ënEh+ŠÐ¶o!t»¡;rÝõï†6†D„¾ÑŽÐ½o"ôMhëþ_ ´ ê< yœ@èQè×n5B߆~~‡Ìô…}÷g=ôòÐÄ>ÏSPþÔý˜¯ý0'#0®èÛÁù†ñ©÷w„ž>„Ð30Ægaþž»¡çmýêýî…gþê¿ñCùË„žè[ZÅFè—ðÞ$"ÁÌ(>â>F +Ä(`VíHçaïCn„&î$¸'æOžQ¬E¡‰«&O°fhçS^¼ÙÝ(ŒNájôEóÑc¨ u ûP+zíGzt-~ q(„šÑ(‚%xòdÇ +´ ½.AèO芡6ô6A;-¨ÙPaò#ðÛÐí“Ï@-5šþ=‹ûð"”†ø\&‰ð䓣Ȏb“Ç&ß‚Ô#èO8_ O¿¨n¾®]ø)ü#ü2~ÿF.&WŒ©eŠÌlf³šÙ×}ÌqæMæCÖîd·²ƒp=ÊaßæÇq“Џæ*îT<®|ñsùË„ŸŸ¯ïoM¸&¾2qÿÄ&þ<¹tòZè¥Pôt;ôrÐà^¸žJ<‚^A?G¿¥}ý;f°(ÞC@ IxkEÜŠçÁµ_׸–áåp­À—á5pmŃøf| ¾“^ÂØöâïã#p=Ÿ…ë7ø}üþ þ;D̰@Í&ʤ™Œt6ÓÊ,d.†k5³®~f€Ù oèqæ ó ó&kf#lŠ]Á®gw±ÿÁ¾Ä¾Á~Î1\’KsÜRn5w ÷:÷Kî-î …¤hQ¬Q<ªxIéVæ”K”W)TîW~¨<Ã+ùþ2þþ ~Rˆ·ú Œûð—äTZù:Þ °p×0ïúp°ýŠíx ̘’YÌö±w³¿R\O±~ü¾ƒ½’];ù]vóOv^ʼˆƒ¬¤h`¯@w¡I¼ù=sšù3gÅ‹™pŒû~šYÇÎf”ä!Š_sVîŇ ÷‹˜-x”y™½…½eòÔ x¿¯x”ù%òs'3zVõvæ¸ę́̕“Ë)¾@W¼_q Ì÷Læv\ɾÁ=ŠþĆ˜ÿħðýÀ5Žáù\˜¹”)à}ÀqDZáõ¨Éø9ü..!ŒŸ`ÇíŒÞÖ0£Ãu +ޱü«F]T¤W0VÜÁœb–°Ï+³yŒKü +]‡YœÚ™þM ¯Â +¸‰Oknòk\ƒèà÷§'ž'[ñ–âN ³o³It1Ê næ5ÔkãOpu‚¬©AÏ ÞŽ2̃è†ÉA¼ +øþàŸ *á«Pk€[Ú¡o[A^ؘ ðÂg€ÿÿ ¸~þ+úöÃÊE1Ž”Üŵgêþ{'\«P7¤¾…îQVü-Äv„8ÿÄ£@å¿C—‚Ìù#<ßÒïÀÙ¾Í%¡×~àÌëáŽoMÌYH¤ák˜A[ Ï3awpsóÞ?yŒðJQí _EWN>€fû»xò–É;QÏä·'/A«Ñ¢É'€ÿnžAµh»¢‹YªHp9౯⣠þ¾øö\ôð£v ¿ÀXÍT<‡îà~ ¼³8y×äoæ#3tHÑ“èjôW˜·¹ì(ÊN\ȘœÃöƒ„z]4ùø¤„ÕhÍdpÞçÑ^^¼gù{vïä®`2Ðß8²á4ä^¢ØÍþ–ý×þýû÷ïß¿ÿþýû÷ïß¿ÿÿýlpÙo9ŸA‡â¨Í„àû4`›`:ÐÜ +€_fιPÌ,À=sM´ÎZ×"¸–€ŽÕš÷%€—ºõ€» +PØjм®„k- ¼u€‹6Síïk€‡nD6ºÎÍ€¶Ãuh³wƒÞ? £?íñ»€Öž”s4‹zýt¡Q½ñeÐ4~îgè5Àb?G¿ýóWè× {¼ƒþ`³÷Ðû€®N>û I³Ÿ2?@^$±eÇ`;6¢ôJ%ö“ƒl¥Tl²²'Q/ûÚÍþ ½ŽC"äˆ+‚ë‡ø$8Åä(ûûƒ--5r ÂD GbñšgHÁˆËSóû{æ)Ðì$ÈxÄæ¦%ïÌš5©­/GV¦jÞoR³ï¡OÁ1ì{ìû€Òè]cU5§štÙ‘@³„ö°ï¢ap ’Ùw†+jv¿ÈþÊƾ +“Ln{uDg¬Â> j¯ŠÝá©’ÃõÆÔ´ý:èm£àwÜ)pZÇ>޶‚Û n?8À—À¥Á-$9ì>vôs/Üo? n¸à8˜Ù'!-ñÙ'Ø«iJì]ì}€:%öNö^~B„ß|ÐÇÙoCš„»§ÒCHÊšÊßi„N…@¾Âû©Ib¿9•ÞÌn¢÷mœ +÷°F|’Øäƒr?¸ 8b÷Aì>˜ºû …ÀÇ )õÑ'€°«Ë!L×–‘@ˆ¾£-íΚ=0¥[`ê·ÀÌm™Û‚8(ºaºÎ å:)ö¨sÔ¹êܳ’a7Àó6À Cà‹àüàX˜÷ 0ï$üQpÇiþ­àÛCRì×`ãЫìU#1 ˆlõÁ‚\S|C Í^qÐé­Ùy.¥RB„P?HÝËiéåUZ’{ùA—·B­µMzv%ºƒ,à‡ÁåÀ5ƒãØ•#á´ô,{!ºZ@²^ÚÊle·r[\¦›^dkP‡€€$Ml +5 +èˆÔÓˆë¶íiÚÆ^Flà‹àúÁ ã`´=ïg/×óÒºòøR"¸ã?¡R¨g€zÈ5@®rø¤¤\/¸þ©RåÙ’é{HýS¤\Jõ«‡Qžÿ‰›)¤tÒA­ãÌ衾\8–æïüé²ÌTy/8%-?EëL—Éä^挜ŒŽÆñpï‰ã¡8–‹M5r<“É´mgûþöÛ_oçzÚ×µomgëJ“£G™#$<<âtÕÔšf0û¡g=àï÷>8Ià§ÁÁ­Ç1ûÁ—€»¥ÁÁ-×Nwü€¬Yð¥©2’¿›–‘)g¾TΞiÈ.lZ|¬Ünp,´ý”?Ek—cûiþ0ø'hþ©ú{h¾þô=,½‡ðŽåS¾®®\?8z]|wi| \?¸ýà8v9\ËØeÌàzŠyŠMʺj«„l6^&£ 6‰Œ^ª?Aý©¿ƒúEê‡eý|Ýgóu?œ¯»m¾. +&zºßGý€¬iÒjÒ-lÒÅ›tКĠޱR_I|ü1õ/¤~R¶tŸtÿÐý- {$ [Ð] ÷y`Yè õ5ÄÇ÷S>õ+d¤{EÒ-“tu’®I‡Åðt4‹ú>껉ÿ~ÈÐl@ªçðßQ3´„GãR‰A4À“#MLŒ4¶B0>Òø(ÿi¼WzŽ©´ÀŸ„OJMV|ÏãHú?§Â¿áy ÒKø„«!| 5â„ßi¼‰Ôÿ.Üÿ¤¿ƒ‚©ÿmÔAïÛçÑüG¦îûÖHò2xêÃ#Éká©¡$}ê#É“{ïHr÷Œ$û Ø9!¼j¤±Rj2âÕ(̺+Q„!=iŸzâ\h¹ÂÖòÍ-#IrW3y@ Ï UC%½|‡P}œ4¢ƒô¢mƒB´Ón¡¡hçu(HCa$t´¢<9)ý_Ï‘£`ÃÈ£ÒŸ‡ñ-…äð¼‘}Ò/Ÿ!Ó5"½ž,áÈé¡ç¤—Ã%¼tDM–(x1YbðaéLò0Ôeðirµôƒ-Ý‚RxÕ»SÒáåÒ®¤G¤›’Ï“n «aÄK¡¸+9SjoÜ'͉”0Ëð0Y-5„¤d×—ð¼ƒû¤êp‰t%mì;"UÂ+BЕCR~É’ºg™<âñ&9Éoä/ã—òñ3ø,Ÿâý¼—÷ðÁ$ˆ‚^Ð +jA”'0,¥Ér‚X -J‘¢9âs4.2Ä0r ¬ža3ÛÆ´-š…‡Mm¨mñ¬áºD[‰Ÿ¼x¸>Ñ6,t|¥óÆwwAj˜¹½„ÑâN Q’µÍ=lšÝù Â8½íënÞ°íë]]¸mxt%j»Ì?üÙ"‰ú¢åÊÐ,²m.:Ц™ÆÂœæÿÁëòç~ŽÄù?‡wÖðým‹:GòO>éÕ5\Cã““on]俤óf=³®¥ù¦Ÿ]Ïàë˜õ-“||]s×Ùj(ÈôC5ÔHRí +’j(ˆÒjí´Ðk°¥ù@0X®ôžG*½D+­.·†G@[$€jŒ…i[aÆGªa”3œß˜amÌ E´1©t *É©r .Dêhñ¾sÅ¡H¹;](BŸÁ]ô9Ÿ«+×b˜ªÃP'ñÿåïòYÿ/*ãƒ+~·jeËå¡–ÞPËåàz‡ïܼÆ1¶uvÛ—žµãì³foýÛJ›MžõXÛÿPÜFŠ#Ïj#Ïj#ÏzL~Œ>«íâY¸­£ó€€fu;¤d4jX½î@×,›Ø?“®‘Çîg9òK“èÖ†f ëÀ‘¢TSª‰Á"%EzÈ6L9nœp?‹Ÿ˜*!Ûš…ÈÑreóÙ¿ 6lÜ@¼M›àoÜä ™añµ Ϲhyçpãpc˰ÜÛÜ…Éû€ŠrmO¨'ÒëÙË­ ­‹¬‹­ÛË- -Œ,Œ-ÜËCÅH1VÜË¥CéH:–ÞËI!)"Ť½Ü&úëšÝ)‹/6¾ÞȬkÜÚ¸³qwãþFE9Ûôbðõ Ó\ÜÜÜÜT’‚K:È»ƒŸÙM@‰x#üZšiw7A$¹qÈè]¸WÕ¯T±¢Ê¯Ê¨dU‡J±ŽÝÊîdY‰M³Ev!ÛÃ*Fð Yä9ʆìffX3ª9®Q +G•Ç•'”§” +¿2£”•Ê^e¿rP9¤Ü£T )‡x¦WÓ¯Ô°¢Æ¯ÉhdM‡F!ñÁØ6€#s´i“[ye³¤Q7K,Ó,©„f‰L_WbSbvgS­|Œ˧\\Ü"p +ôcð îàþ‡nÿ^pßwä°)6Õ⸲™ÌAW‚pR[s0“¯©/A¸âŠr¸hy9l¹°66Õ8 )fÕM€ê= þÏÀ½î/àþNÁÖ°5´ñMå5صmH`‚ÄFâmHlÄ ˆ`B;7$ˆ8²\ž jy#¼aÚ°uA•hîrÛ&Nÿ Ñú _<)<Ü#õ oKt`ðsÌYóÌ‹#HÁ•˜b‘š'‘Ã9¥âE(g‹ãH…×âK‘#!~Ö8Þx¡xºqÁx#*B\<^uÆ}q%þ·ûæ!<Ї‘#H'2Õ]cÀ{8tÆÏŽž‘è äçF‰àœü=§P¬EõÌ.Ò'Ùiúfd¶ÑŽåb(®H,Ä •±¡„çÈÇkëk]¬›ëqô8{\=n¥B§Ð£ÊÑn£f£n£~³¡ß×/õ§û3;„Û4ÛuÛõ·¶'žàžÈŠ&]V—Óå½YoΛOã4“âü>¿§²3ñL¦Èeœ_FÊ.È]Ÿ«›[¹X³T·L\_šðüaÜY)ï®]ìXì\ìꪹ${Iî’ü%µËëô¬F7kÜñÆß0#ži0 ˜w„äLïÊ<‘ý¨ò•ÄhéË…B½t÷~ü:fðVŒñ³¨Ä¶ÉºüCÕ·wäöùžõ’œœó!Ke"ѨÕ[´Z}B[©ç*T4P†ð8BÊX5ŠYTÌSXösK¸¢„C²˜6¾hdÞ7b¿q¿ñ}#k,1ÛŸ–žò%DV‘ +Òî*übÕ§U“Ul•Üš—«^‡‹ªüU™ªÑ*®êy<ðì€W o¹»;±~`ÁØÀé±ñîõã…tb ÇŠcâ˜Ñd/`âm×W%ô[Ä£$~rz ‹c§Çh¬‹ë!^™}­\ÎðæX…&©Ê¢¸¡"‹Ãfðø $Õ)mi´ÉDT¬Ìbƒ>^1…²HH+³ˆWlË^y ÜtîFÝÀÝT+5WèV‹+\wW7^?@ëQ707Y«q +\ÆPÈ‚#ôßå–Íù|µÓYÍ0Õ>Ÿ¥ºžõªª•%þo‡úªYK¨Ä:ÒgQ!G1WÑh*¤Ó@ÀتbBA¥Õb·Ù}ŒÕ¢ £ÇŒY“­©Íç*¢ኊ|®6[c·AN»/bê~ê’5·'f~ôÃ;Û>}~FNú±Ëéå#Wçá¾-ߨkˆN|ïÞö?è»¶Þî +¨k'Û÷\ºõ¢™Ù¶-W\}ßE½¯R}iüË{¾Ñ{ëòš+’¾o¼kñ=¿Î;¥4¬hÔ2y’}†Ý ÈˤÊ+𙽏SöX´JQd–hµñu:ðE|Wš<}ˆ’ˆl&™­ÆÙ#‚FŒs ï§aÚŽ/qŒ,n%mXEÊI=¹Ù­Ó)—¸8‹–„­h0(á1$¡…ÆOÉå8ŸV+ù¦¦4!B{ ñX‚>–[LƒVü¸íˆíeüªê¨÷m•Òôg5ž«j±-³nÃw©vÞvó’\“ç¤ÙºîÚÝ~Åúª‹‘%Ä öÿñHŸ )8¡h Q cJÇ@²µö ¨ÛD 9ZÁ ã7®ÝüúÖׯ[½åç‹òkgí¾yÅW¶²ûݾÿú3ƒ{ïüÁŸ­©øè ?xoÏOßÕKÔ Åqö>À·çQ¢-*›LÌ „±Æ#IiòŒ¬!Dç÷‘|HŸ”Í„(ý.ZÑeòz¦Òä?‘jù×!R‘Ó‡IESøYöÈÎþAÖ;"J_ïPz“z /sŽ +*j”~7q ÞŠ©P(ŠcŸà21'h0únâhu&1M×ËxYèúVPqèÃ;´ZnRƒQT.ÁjBÞ˜Ò:ö»8’rq¤Ä¥¦ëÀ$~dû•$Ã﯀Þþý©‘Ï‘"yš”šLÑ +²& /dYVE"A½QBLEñ˜xÌH:ÿn7Y‚rG{aø£½Ñþèp”Ëiê¤ÿ\i®_áÌ }Žh(°Ð‰†„(nâ}B³_ñ + ÝËf5ŠDœN:½Z£Öhþ^-ëÑ0YÛwƒDâp‰yAŽ˜œ®°ÉÔa23ƒà>ŠÌ¢Ù‘Qóq³ÒÜ[ñÒÖ²hX?и@ù’0h€â8r‘žÿcì þG"AW…èöŒƒËƒD£[ôzPK¿é&Ô»\Ý#a‡½Äþá龈C©Öè½%A;Ò§/Sl1›¨¡lØbÎZgW„ò„tÛs|>„ãB*šgW6)ªŸøkjó - Ö'=usqSW1qu[a9{ßøov·zŒ¡õ/ ÎêºkïjªqãÈøÃƒµí a!ºúäߘFîGÈÍÄΣåˆW6™™%^™ÐŸFë ªµš±ÂL£f½JÍÓ$k&|–¬™°B-¹Ç¬’›…+a÷ÂJT<6~üXzìh™2¯¤ ·Mœ¥K§]KÈÇF}ëyqwiòCJY®éˆ"²…Äú5Xcpcë•<Ï‚éãdV³5n¬`H¥S%ft𯴠ÒSJ¥ù¥R³Ù뙢ÒwÁ?Fsüxw÷(çÑîêL™aÇq?ƒtÐ&m¡÷0Lѻ˸Ëù¢õE[Éù¡“ßíÅ;\x¡v¡®GÛ£û‡C¡tXQk³:œ.ÏâÞƒYkfª·l†a°R›'¶½n}ßú©•µ^nqÿiJø9é×bmUÚ;ìe¼cŽS„-fùÂ¥b¾R#-³c`ËGÅórgÎD(2O}xb4’&Q5¥`µ’ªšR°ÚA³4ËA³Žú: Ùš Ù!q’›"¬™@ä ¥õTª¾î¾Ä +²òíö½èc|F€H8Ñ!b1S7•¯ÝØ]Âܙ©óÙ®L”°(ëbql2Å{ Ö“]·ÞÞ Êa±XÃÕ4”mž@nH‘^Ô÷èûõ£úãz¥Þ™|–U²ü”Z:@¹ÆPCOS’n„àƒî“@áÅÆÆÆñÆâ¸±Ðž"nS$j±UD¬[̃¢–0!í2a¬>¿¾›àe{x<´Ïg„whôüñ‘¾¸Q©T”ºJÝ5É$—! ({S„]K8~–Àél^)%„®´Z³Vü˜'2sÑø»ñØ,çÈHçáõWv6ä|öì|Iª¨’=Ÿ°íã “áp¬ù2fùÜÆ?ÜÔœª÷åW›ÍÕ«ßœ54¾FPûx dÖ£ÞgPæÍK²ŽÒª.à äp ˜¬ŠHyÂÀ!r‚²xˆ¼IYÇaóÌÛ†wÄÓ̲fS/Ê3Œn‡êGüO §xüîV†U=;y)ίUÍaZU ¥ÅÌbÕe̳üùËü=Õ÷Ô%á°jXýæÏÌ íiµE8ÎcÄç™õ$$s7“6Ì+ù-œelVÒU³©`ê±nµîÅ€³ZÝ¿æžO± øpÄL‚·ä¹¦™ãK@,Áá.Øbî‚Á†×Ù¶ÚvÚXÛi‹ePÀaH`2ÂNá}…²`X8!(…'õVí tÅ&eSF/ë;ô,J~={J©¨RÁ\êÏZ”댯§x ”bq “H쥄¤ äwÏîYgÅÝ] ‚ËN€F e7ª¯'ZÇìÎCJ„f}×úiSÿÀl²·ÉÃÓ4¡‚VNtàˆc$VàËá#îrÊ].›J©Ë)u9¥¢)Y¯*XEgÁé7tàȾCy›`úGÌG‡y^c´¢ÿ§Ã}V«Æèqx¨ÏÈk¸’ ôi¦ Bˆ„A˜•eçè?L>gìg*ʦÒwðªUÛ—oKIÖŸ=¸÷ã¿yè•ñíø …è\Y»èfÆÏ7n\yeÇï1~ûcÌ¿ödCg¸^¾‰àµ @æ@æYñSçK<;0|*ñ,Z%æ§Gd(Ž Ê`-øDAä/T»ÑN 5-YøÔBZš|ï05’*^ '€ã‘Ä›Æl¡º pžˆ‚DÍYW–G †;Oc‰š©Ü²PÜ ·!ÄOa·2jãÊö£i1¤-+X4RCZ­Ýö%¥£¨,yž²ÚOÙY;…Ksr$” +3rØ>¢[UÛaDz½ÃÞkï·Ù÷@E^÷ñóƒ8îSFC–¨®Éì³4C—x¥á°N;ÕŒ– +’üŒÜwhq¯¶_;¤Ý£=¥UhGlç ’²êPl<':@?¦ŠJŽCV¤à*1ø)‰qÖZsVDLKˆë¹Ö‰b±Ê¥—®˜wÑ´´ÞKÅ+?ÜJa:ƒš'Or +xëJ1çIƒŠ4Åéq¥ƒ¼H¥@AÕw•ÈﵩI®Mã'\ÕHmZB~Ç”ñŸ2…ì~ŠŽüܽ“£GˆÅÐ+%FͲJÏÀ+D‘ˆŠO&Y”#Ú_b, nŠˆýPM—­ãgiàbÜ…ü–%·zú½Xööz¯¤f46J 6j3„RBñSªð3eƒaº*NëÐÁâQ¦«ÊŒ>1 ê0ˆ æ]`ôÀñíJ! ºÓðB[[siòBg%ªr½é¸wpƒéýéÑ4/§Ó JÛ*­‰%Š%ÂâÄý•`ü~@T„ok€o·4úú/õ_¡îó_çßvûŸäŸá_©ÔT樶Éä37[½Q[“Ççm–à6 —´ÒY“’8™”X„4-55𬽶AÛ~+Ù†lŒíãx‡’ +ŸªEŒ­yåìªÙeÃ"ÁõãÝĦ? <Â>‹FûtAå€âzWE‚¢‘ +!îG ¼ñãJEÒPb +á£îzøa€ùë Ø/k°$iT‘ÿÑ¡>Ï&K‚b¤ÕLïÿõF”e¤<ÌžŸ&ÞìyH#Ùâ•Vbòa~2{pþý'þùãküWB‡)CÀæNi&NU)W¦;[¾2Ü÷•Õs.øâå—që‚ï—•Ñ/Þý65E¾Šßjî/,\óÓŸý–ð»BŠGí¨?{ŽîŸn¥*)Šz=L(:’#Ft‰æ¨(G ;g&@ØLM‘8Hi?HÑRØé: ÒŠAW“Hˆ\\\Ò–õXT×H¸à(®º€©ò¨TL§‰ÚsŒs¨W^ £e›:À#²äõý­{Z·žhåÌ­zäÚˆ2&É­ ƒ’Ûæ$wU Ø"¹g‚ŒäVBfÉí„"’;å%÷ÌB(vϼàFÍT¥R[0™ƒŒÄï±?˜ ö÷O•Áã—]bkoëh+ëoÅ­-‘`¾#×›crÎYñ;Gbxz€lW‹ëNÙB}dM‹>ÂÜUZvf#°„#}Þdšu»(‡ ƒD“u}Ð;õLFͤ·€ŠÅò¦a"a¯?Âýƒòʬ„P”ÔrVY$FÀËù¯·à½ÌfÚŸÈd˜æL&á·ëÔR2“>³¨Â9~-ª.³¸ÂQ.aZàHæ·øÖ5§É‰ØÅ¦Ug¾¹ºœ¨ö_‡™Xy.Å®=¯ÐުɓÌoØý¨š»ê<žÍÊ„²2Ù-d0å˜j–Øàv Q-É DU$eÂ}kH¹¡š¢†gJ(ðµ +ܧÀŠHc\É;¿æÃ+}Øñ»p¯«ßŸL€¼ËŽuw§!„ ›08Bc 4{ã˜øFâËÖñš€!*p•6Ÿ©JÁTVóåfœ¦6^«¸^Á("•|³¯òmô1¾ˆIƒIÿ.»o5²5.AO¢BÔD‚h4[3Åm–ã]w'=Ú]š +P";®J:“ŒÉT%k +ɘ¦à°ti—W<,ÞV¨yuLïÍög³JC¶„ýòv@Û¯é^Ó ü6ôføíäÜ¡Â%5¦b²;ùÕÔ–äN¼“ÙÉZ]ƒîAÏŽÔÎ*9¡fUZ¥GüiðÕàam“ÇæuÆÝÉ]ª]ê‡ý÷†î kL ],9?¹0Û“½&~Mò6ý¡ýÙÙ<Ú¸PíC/0>,á4fp 'FÐ U%ì’•Ÿó·Ï%¹°èòÃÌ‘Bç 6R4™@‹Öp†( >üT•®¬Ö“êºÑét”Ø9²Å–&ËüÜ„±éõÀûOl ÄZdM¿÷ú CÖPµ²3êrVI’»£˜ì_ FY4e¢Ï‚WƒýÚ¦7•ÈiŠ Ç Vž ÀZ,¤Lbˆ4}ò4Ùg¢ÚíÉóŽ!Ìî”Õa`:E§ÓLJè*ŸJèøÒ¹ˆ–‰èP•_¥Ë¡D•'žX\ò‹F%/¬Œ ä}ÄÇ\–(7ÝD Ó_🉟¿ˆqÝ]x€=è”»ñnf7»[ónÈ:äryvíNi»»€­¬G€¦ š&J‡ïL>~8©è&ç±dcÌï,¨bΖ՜» Û]Ôê¡.TAV’:UA+úLE½Ÿx€éÓÀY—•ŸP9p÷ás!é0—Û2•Û2˜à&x„©ô›È=§dƒª +¬¨ƒçèH§d“ž£ƒ:àF꾤"ü·ÌM"v4YÇ0U.—­ªšwª+%þƒC}•¼É‘‘>“濲(¯ =^1e8#f3r¸‚È[r¸"=ÿh3¨øÚ%s–ú¥ž{^{aÓâ¾€Õ® <^Ö²lÅÄ{©ÔÃ××.ÈE“–Ý?ñÓ{¯šŸªÅ«ZW~gË.ŸÚ…[ïºû¢BË¥C …eë´ôà|I„Ø}Š5ȇ¿IÏ!ÝÌ;4»ÃsAÎ!ƒç$žÁg³ÅùF~ÿ}^)û¿Â-¾šòZa£q£é[šGô»ŒOižÒ¿ªxÕþSÇÛö·'üŸsŸÛ­Vìåœ +·ÕisÚ½^e×84Þœ³Õ¹Ã¾ÓÏ;œ cw9µN¥Žu2 +¥ƒLoæt%¼FV©d‹¶8HNï°Yß +×N'ÞíÜïdœÏ²YÄâ¯ÄŒÖWÂ_—uHù‡…æó:óV3g.a^6Ë00òËþA?ÛëßãgüÎçðçˆE:,Ë–f³•ÙɼȼμÏ|ÊŒSzßñ”‘uÁÉÆ± ÅîõŸu/ ›fŠ‘ÍÞâøúòâyz§ +¿¨z]Å îõ]‰“dÂ[Åd›„§Ö×ç×PÞ¥oÜ.*¶Õ“Ù[ëÆtãÐ ªèó1¢ª$¸õ‰ +Æ ‘‘>F{V½œ"6G(žº¡û +0KJžá `Ô±ûzΜÀ+°ÿѯ®Ú]q¾þðÞw3óû|&¾¬oÙVL|Á³ðƒß¿é±MëŸyå¡Õ«¿sxâT½X"˜ë«ûðƒè§ÈŽ®¦o?ÚÅtÙÚX•½×yÜɪ0â9Î ˜Ð“¬Õp «d´²Ö®”5’¡ÇÀœŽo}ojÞÆ»)›2•ùRY]r?ÒšLZ²²ic6%*s¾–ž¸ â¾lY£ãR~uõzèß“¥º¡­vÖêû’ÁfÊ¢jÈVÏÙгú9D°âÀŠ1”cО„©`ŽP·=ˆMÛ*^½œbç…O1É^uE†£ŠTDZQ'^Ǭ _¯g6Hü›ƒ×DîÀÛý¦öá}‘§+žOM†­Jÿ­ø®ð­Ñ‡Â{ñ÷˜ÇÂûS/¦ÞÊ|ššLéLȆ]Œ)æÊ¸ªª2W„¯L«+ÆãÁVÉmQ$æF‚äÖB6‚üB2“Œ„ÃA[‡Ÿbü _ßKMevÒ]^ä;ø^ž%&†Gî§<¹þ†l¨‰y½Æ ×i +¦áfyÈ- ó(°?À, ì 0Ãb-–kûkײµ9AI0‹@çA XÚ¬[i¦•Âfë£ùÏ`'šR=‰/v¬˜ 'AÓlê#7 È1Ÿiä8+ÂTèH'ÈβÓ%ŽÈq$@ä``µŽDBÃâh‚R}uÆA¤KªÚ’"©P:‹«}àU“Y +gü5ä¤ÛÔ ·s{Ôî™<1¢-`Âá-… ¬#X\N=uX,dDr —wỺ&Ü#á$š¬êK& ,À$ògFú<5%þ¯¸)¢õ01­A¤ˆÖ P½¦m”Q,°&=oƒc +¡|Zc#TÊc›ÍŽk¦X4аbÍÄýù¬_ç=íùñç²K#VOtAÿõ­c;¿»;zïXwæ³GõÒË»oiXÉ\Ç`<±yPJF"õÒF¶ÄŠßß´¥T1qýmZæ>üÄÍ[w›ÒçMޱ;™Ö  Ø;Ïæþ"UŒŠ¡ZÝ|UD h4Bßxi³ô$±dmÄ–&ߣ 5K@ª•B–ÖÍxò©*BY~ÜR•E>.žÌä´²Šœž“½^âMÔrô†ì#•´Zn«;h®ƒÖpˆߘä¨å€X’ËÚ;àØqÂßHT{lÊ’@6ꎊo”‘­¼Nã¹#˘Õb“_* ŸPQ³¦„i Ú’½ Ý©¹3¯ôšl bq°È©<íŠve‹¿%ØÞ wxµž÷£à<ܦž§™—o«›Ý0ï‚ešÕšmª[Õ·j ‹m·Ø©ØSdz…,Ê5VÅS¹ç°iÉY·#€+Æ–MB yQÛ¡edðzµ¬Ÿ›µœ¶ÑA «qMa¡£Ç±ÎÁ¦[ŒãFIÄdÄ™F¹‘a÷§SL*óF0¢‘ÓT¦pª7‚²:­6—ƒ‰?CM`ÙçÈJ@áðD}E¤È`d(ÂÉ‘Sf0‚#"©yŽ™xd…5/¬Ä”às§ Õ¼¬/ø[ ò¬ÈãS<îà1?{æì¯NÃHrºïôXBOVãx¢|ü£QüŒœü8=~²[[_–0ÊÛ<é²Ìaµ$9ÂTÞñ‡µÛšŸá )ÌuõµõŒR%¨FúƒŒ2¯)ø‘Ñkö “Ù é<8š¡(xP½óã|Ncòˆ¬‚× lô Ê[ÈB§‡Z‰ÊÊJ(®§›ì€y‹&º°”©å÷P5Œ(òĈHƒ#úBÆN@ž–'@++8üVÀyµ»45¼Êº Õª!TA¨úoŽ 6÷a‡ƒóiK|x¸O«ÍøDˆêƒ÷/ ºC} ×HϼpÓØí|£oD9%¹ê@ +—¹€Òj·œ•föòö?µ›ÔÖYËY¶¨©`Ò‘ôðîë.œá1©íQkmì¿¢º?\ؼ´¾ý֫Λ¯š]Ý|ÍÒðŽ+‚ÁdCUM.µt(.ÍJl›xõ–^×X󽸻љì-Ìí!ÒÝ=ù{~ HÉ{ñ9ÎqD…ëã#±ù(f¢ŒG•qs£È¢|ÅñãðÅiº­¢Rêx­ VñjuFYàMzÀÖÚ)|}PPå $!¼…AùCˆÔªòéùª.®Sõ¸JY¡LIML3Ç\qwe,Z]«,¸r™Ve3ߦ™ë^¬ìä;….u§¶ÓÕ™Y\}¥rß§YãZã^›ÝÌmVnæ7«¯Ñ\¯½Þu{‹çÿ¦ô6î.áÏíéÛ3;ªïáwiî5ßëØåzÐ}_ì›éû2OOªžÔ<ézÂý}Ï“ÞÇÓùƒÂÓê’ëPæ'™Ï…Ï5g¼Ÿûç¯I_žYS½CÅÕ»û|뤯¦¸ËùË…5*¶MÕ.͵¥¹.÷²ôE¶ƒï–kXŽGjV£ñØÒ•ž¸TÍ4ªéí0dšÑàΨ<œÆXžY·Ià5X#¢&äfc±ôº—ÉoJg+ÜrRåñ*•Úãq{}>)!™]·9–Ž»c&-´õU¸£…êzw¡4ÙЭQÕ¯“-÷k5š j»]O¥V—˜We«Ûž´W‚™´%“IW+yž”x2Õ¬6›¢±X¡`BŒF­^5ãQåÞjxg#r¾š€‹È©L.S=X=TÍ.¬î©î­î§‰Õ§ª…ê…?«.Ö¸»4Ï2~äÂÿ’5„]ײÚÇf”˜«ÖÞ(à³î±“Nñ¤C?MEbüƒ³bŠ%mWT%¶ë·…Ðq^D˜Š-6‘5–à‰ÿgŸõ\¼ØØE`çÔuSÝPQ5-±˜MWôÏŸOr˜4ŲrÛE _²Eå¡ ¡ÀU¥±¢+LVX&ûÈ‹ôJNød‹ä%`n@P „áîõPóÑæ°9J ZÔ¨u.—ˇòü–ü,Ÿ%1q[lⵉcቫSZKË ü™#_ŸÄšßÇü€ÐÌN§9Έáú\ +s˜Izm(Ú#¹Ð­_<Ç®<ówÅöŠH$’ †nç™í_©©0ëL‚²âÙ­ãóñ {LÐG/O~ANÌ+îF6ÆŸã| +‚D‚ P=è6‚„áÓ;Hg¦7ŽÎÐÓdûFÖ•Ù;ìˆcTfÂHŒgwÜ•&ÐÅ”OÓ“ÝJóéòé·é“žÓ–¬ +h‚…&à>r¹×§PTDÐÔi¶òù6-9ãGwŠJ“¥ç}´ÚŠÈ—7…M=ï˜qÊNu­X¿§<¢<ÌÿEâdÛ×_±‰ÝÌÝÆnçc÷ |+„éM"‡]‹8· ‰|¶'Õ’bHÁô*û¬âc­ !GX«uº~ÝŽoXJ¥¨óë2Õ×ñ:b×oÌëz#/M펞=1LÌ;åïHˆaÿœA?æô³¾ÂÏúüØ¥vxÓ¡ÑzHI\À·y•njÞ§Btê|O—åƒ ­ˆ ”û¡>†W¹KüØHŸjZrzV©$:gÚ7ÚÎáX%ž±í¡¯ÿê;wîëØ»Ôàwx*õØœÊ^]øÊ#¬ÊçcÌgÏüí—§¿9ØÐÀþµåÇÆW“ýé‹Ã/¸-åœÌÓ€VcøóO2TR”ª”ìÆ(Ý©Œ:$l¤;—Fš6ÒK£4}øRš>Ž ‘¿ÊFBn’…`Y‰žÅ”Ξ£—°È:lÎçØ? ª §âF×E·FÙhŒwhY Âcéâ» Ä*9ÿ&=ˆ™¿|ü2Dš«€{ש¶ª4àPBO)1ééã¿(1Jdw•ìb‘¥JIªŒŸ;I íÓShÝgPÊõ3~C ScÙp3ÇË•¸§KqŸ#4Æ}öÛBѨ¿©ÂmFjM¥Ñâ1ç F‚¨ÅÚ.–E¼Ã®îQbY‰•UR%®Dư$I~<èò3È/ú‡ý£þã~…¿7þØW¿|^}àäúòql`¬Û8%‰ÐycÖSCÖˆÍá„E}¨Ï¡ŽiK‚ùàZ6ÆSþW,ŸG·Nië@I„hø³§ Ô9Ó³}õussáÐ2«ÉšÊ˜u³fN$æj….ä’¢jle÷ÿⳓÑÚKüÒ‰yíQw8¶‰!c^¹ç9ƒ‘vb{š½Õ0KΣ)‹J•¨dÑ5Qõš”j›'§wŽi”À›# 2$ZC£5=€”ä¤ËX⸊écÝ”?ãI>Uy-Fæº\ƒLJ¤ ]Gža°X²å²Sæ;TupһݓʯwXl[Üù€®"çä)äškW€ùýßÂ^$‚¿lk"œlsÊÚ„ +`™²ÆhaKI)½Ñ’àéóÊ,D9ymÄ5-¡Ífj“¢2[Ie»ò<8Oì¯u¸,ÖµxŸ5• +¼ÌÈ Á®ŒÄ*çĵû/šÑ^— bj_k¸iâiCÀ)Ú³ì}‘¨7Ú2Qƒÿ™T]$Â9ú♯n»½9Y™µfvífJU!­¨%¸}d:h1µmùÅ wUíVÆô?ú°ˆqîÅCx>Ž•¸„s‡Ñ ·x99º0ÞM¾II“}º©ç>s ¸ô!òejyÀEŒbü ÆþY_±ÿðì,Ë·¾ìyzê>C GÕÔ× [ˆœ®"©7(((lôp¾Ú˜ltÖ6ÍÕmÓ&áꤺ yéÍ^Ú—6áÓ³ùqÊêãå4häm%>- ò/YMîˆ#΢ª–É‘†êÝA$Þ`ù´¾¬ +Â5¼+YF&éty7—â“ÿ"¦âô«$Ó2âÜþÛ¥ia÷úEJ5ÓT—Û7„*0Š^zRY°Ñ£6še£_¡ØlùòÒš^šá¥…^:PzbúÈ Dþþ4©çsÿ§Gõn¹!/Wæ…<9«ŸÉwä{óýù¡¼"Åa™Æ!5œWçç™á<î…ŒÑ<ëlqŸ¡|l?÷…ç…¸O??äûBåcûÕÑʦŒ¯ºÙƒB5Y:âp(d0èÕv[˜ð°€ B¿°[x]àrlßÏzÕR¼#Þïsƒñ¡øpœEq1ÎÄéa2‹-ïÍ•î'þÏî›NVÉEœ¬ÝƒJ‡Â5}pŸìT0ZO€QùÜC oP3®’ •U€Ž‚¢Ž G(_0¨ÃäèÎù‡÷ÿ·G÷A¦ŸyNÎeqÛ·ïiëóÛôšêY3ÌrVÍ5-øÚf¾ºmb†eNµAry¢lI0c/µ-m¼aâÚe’“Ú7,Ä_Û²þæ o·Í ¯u^¼w®‹>X™3â†ÉµÇ>Ê–ãåÌrïrßZ¼–Yë]ëÒb`aàAÅî'¹y{}6É-‚*b‰ñŽ’Ñ J̨lVá’íú¢É€$Ôö#•˜˜ìTÔf¬¢æaµª‚v›”ðQY@î@>Ñ×ãÛãã|Ï21d›üDÖЕ\^çÐúAÿªnúþ§»‰ñØú¤&OÑr䜩‰ù4ÝED²&nºèŠLÈq,¾*¾Jv»0>Ÿ(HŽúpŸÄèD#µÜŠeË-üÁ Û Ø¢Xè¿Xméi>dæ¾m¨Ð˜¥Õ‹_tW,Lÿ(³4lûnO,7Ÿ¯í/-7Ô}qz‹T‰äüœVoî»Ï„7`DH™Þ¸ŒÎç]”7vQ ¬} +È.iÏL3º †dzHŽl s›IÐZ‰êº9ÓµæL×"9r€ÔšÓÔÚDë5Q®ØDùaS;…¾íÓ÷µO3ÀöéÚ 't’ºíjÒL{‚Þž ·'ê¨%˜dÔ‰ä¶:bÁ¥o¯Ž~mZG?”"UëZÎ6꾄̉ÙmêËÕÌÔ‰²—Êmø+§¾l}GÖª~fª:=fs¦kZææìo]¼D&uÒKðÂ%ë–l]Â.Yªl­vD’¾1©(ëŒiòéTwwâ`vò›æÍ„Íý÷èÔ‘Ä2¯NÐðz¾þ»n„æ¡u ¯à/YÊ;ª[”ÓýÑû”C'h^¢®‰¦šhª©ÝO°}ùZgQCIv]ù›3ù;-­«ël'‚Šd¶O³mˆü“–¶·wužÿÍ+õɯÔÁó1€“câþ°ä‹hÎ䇨\\fòÃÃ.‡ÓápÔ—€r<9þx×§6v° »—OèðPö ~P(JÌ™CÁº¸¯"²&Ø÷µÎ§:0ñC¡DÜòRw(Ô÷͈<3´$º i±oI³¯[ â1ñ‘Ö¥ËÈ‹‰$µj ¯ä|ëœê h ] +Ec8ñã~Ð8 çeC]¼*®ÏÔáþºá:¦ŽäÙ,k +··K :0ƒ †0h¸€Y\á0ý½]%fùAKxÕ6Ïi˧‰8Y§À"=W¤ ÆÈG·Ó5tV4L× k ºH¨"¬ x°ÞÔGÎÿ®k‘c tÛ^½”o©I;mŠÖ¹ôCÜjG«:¢h, êƒ}EYñ©)f©õ‡Ê‡ºò×]ÿÃ7^Sêýö…çíçN‚žÍæÏûøëKŸdqÇ*SjMvé ÖÕw·Í[°éÔµL4šgìjÎ]š_ÛÎ0Ö†9Õí"\X›_”rS¬qÑÏ Êæ“U†ŠÊU=×´µ-i¸abóR¿M +‡íT§º£¿JÎÏÕ$&Úèbá°ñbÈ«–½Éº ëòZ?îKð¥$ôÓÀŸA@€ò¡ªg~A¥Pf9ZîÛn÷íÈîr=}ÊõTô#×_¢NkëÑuÑk³ÕìÊî ?™}ËõVô­˜šk(1>hX]Û@¬Åž`Ž„ò­ö\V$Ásúr5r(žÛ›k7Gv¸ÞÆo†ßÉþ)ÂsaÑÕˆ¬UévY|¶°-fÍTÕ´„çç–áNçòèýŒQDbü<ÜÛÐß0ذ§Ape\5ˆyWØs¦9%Ãúì¾…ÙÛÃ…ßÎòþ¹¡£a%³’íUô*{ùÞÌfå×w¿ocxCôºØ­ÊÛÜ·ùvf~–~'ýqø_ag—`ܪ@P”ܶ@(F,—Dù„fƒñúd–­ +Æòy•-³ÛmLULTÂùÇ$Ô¤JƒY$§–®ªÞªz¯êµª»«—é™îffz˜F¦†MaFÙÅDÔ10# ¸\ÆQ#$q×+$îÆDvHsÑkMHbŒ&¹W’ F'!¹¸E¦ùÎ9Õ=€Éýÿo ëœ®î®®®:ç¼Ûó>o ˆ6Ó¥dÑ )Ù™;ƒ¢Á„ ÀÁÁA080J C;@¼Tá>ÞÝ þ\…ûtG¿?[áþŒQèü”ÐXáFvô yBþ X‰Ê •!—ü®¿FñÕ o€Dyuâ«yÆ\5'™ÙôޝO¹dè½÷G†ZæêHzf 5ýÉKxüÆ‘ôÅåo~kÖö/ë]=°û¥y?Ú4~AˆÚpÑí—훫·%éþÓu9¹÷ÚË¿-r\×-3¯}ÖÿåÊÐ×õ|sÃ"ûîüSGégÙ Òp™q-7¤ße7ͬ`Ö±7ñ× ×Ú¯s¬ó\«ÞÍßêAÆû¦,5ŽgÓ²––Y:ª3€c÷ÃK ]i ¬À‰†PÐW¢[£ƒhZv8Yd4Þ³+y?Ru‚PÜ Ü’[uÓî +¼Ìpƒ¬‘ÊÒÒÙ·fd™,Ü  ¡·Ö—­”UÉì‡Qx¬™>J3#GÍ!C²r†¥f0±æk"¦!”ä]ö”¤‡S‰TÌ¡-1¸&yÔSmÑ¥0äB›¸ /­9;Í?œ‹‹ÀvN¯pŸíîç8'€îdÚ;œQ2œìéÔ t{¥¶6÷ØzÎLM¤8KÖï#Æ]¡»ÚË‘_dÿ}ý¦7.¿áµg®ýæ¿öí—¨÷„u3Þ±°{qþßÂ:µ&_¼ì¿öî¸û¹»¾ûå«ën¾’ÚwˬKþpÝÖÇuí¼Fb³Ÿ:FÏCw­®Ç÷l°ƒ€'n§½Ü-L¶N±Íˆ3?`6Ûž5Z—´þ¼õHëgV´Âna}âúüóÉ}ÉýùçßK¼§ÿ.ÿçø‡º}ŸE·ig&#!MýèÎÃEˆÄvënš•üÐ_[vGŒ\¡5‚îïNɑ̀+€Ôÿ1l½êJm&ا +ݲs›Ú+p3ÚƒÔ››¶6QMhÿîÅÜzœ"F½oXV¸µõ`+Õ +*pü^Ãó²‡ò(-gÝeó&÷ œÀ$›;‰+m°k¸ßñL¾MYEÆ×ZRÓ5ÆÂêÎTʪ.…¦i)ŒŠ¨§ÙÒK¡UÈ[ŠKaÌYJjw›¬ÈxèH‘Û)Й,šÆ»ûÑ… ‹Þ³«]‚H…ûŽÓwÝMü9õjÜí^ï+=ÐcÒ~8 aºñ(…ß©Cúú°‚‡MAŒ²Ë}ŠoyLæNltÖ"HÆÌ8Ýö±<W)-cuá1EYD=­'j\){¶ Ú¬š¤7Œ mrDÉ#Ÿn rà ìÙÍ„MØVv÷C™r …äÄŽ~‡IÕRï×0èH«#ο4áZ…¦£Ý„öª&,è_À#-½9ßùÃoü÷Eu2­s’Jä¼M+nÿåÌpz&›Öõ‰±‘ß¾ñ‡o?rËÂO(÷M³t½”ÙÞóÆàôջߡôõ*YA®Å¾ƒFÌDê/dÕ¯Üà|ÉIõ¸¬¡np®-®+]ßö²u¿ƒ¿@739ïZÖÖFÍ¥.£†¨Æfêac§c—sËþ‰¿vü¦Ùá¶AÚIY(¶ùn°¡ùqðÜêüE3o؉ÈÚcBÔÑtX°÷ðZë»àï­¢`SlEX¢ZŒ Fïä§áÔSÆjuÛ„7ÁïÁaøõ6ýø‡ŸXÛÿîý-þÖÖæbëø0¸Ïñ@óý­õÀ¸VãÑÎèäI>à+RÎ" Ó²_ əϦBéqi—F^%,#ˆ(Œt†Œ²ÅÁ…,Q<¸ã…X(£Å;»Ï u² b‘.Ðh¤µÄ¸ÖŽÐ8@Üéð:ŽnðŸSlõ‹­:Z»ÙÉEÐÝÊt8 e·Y$6V9_vRÎÇphP^;ÇËdÒçttd³©Òr `±°iŠå;¿Å8‹Å3ÄÂU,d+T»a7½jÈ,4è¨P_‘̑̑Ì1‹’ %;£ÄE}|ÒäÀN¢Š)uU¬ºÃÙf`JÂâH‚vÕ ;#uìÎé'è +õеÂ"µFAw†§¼æ%¯aðÎz‚ãâƒh2 bïK¡¥©»0¡i"f#Áqk›ìwtYUo¹ƒm¤²!91úîØg`yvp‡„ŸÜ.Õ5$xŽsŒúB†³èDó+má:ΡÓ)lò[ûÑmöq M"J;úe¾F”Ñb:àÍH:†ÓƒÈáÿovˆ«m,Kô2¼ÏIa4ì2xâ†ïϹ¡£ÅSª6’‘üÈKg$ˆLÈc²w ÌŽ54Çàß§®8Ï¿›:^oXhÑõ´,§ZáÏ«3ÎHé_—Í$cYõO?”e¢„®C×ï>dSBÿŽ~ŒÓÀBzÄDP»ý½¦n£A“´ˆZÛ°v6,yËw«LרžE+Ç®I­Z´‰ÙÄÞ¸MÞTºkü­“7͸£çþÀýòÃ=f»+°Kþqëg\txÑ‘EÇ…‚ª¯E*yÛb‹Øgøém]!à§Û´é! Lt»ÊïÀC[ðx¼?¤C·Žín´¢ëXØxí]¸5ln[×ýEýeÖ+ðñÝ rCÔÐ[ ~¯{‹ö¢ö2Îc0?CZô ½×7O‡Ó1"{:&”›Þˆ}>Ó{½Ð‹#Cž•<\Ï£Ž ‘’åá‰pb…cØ•éÖ‚{•!…R~HýX€@Ïè%«…S·ç76Š3_¢‹ ¢h[3é¢CrfeqSqK‘.ÊØ–1ýìÅR9OÍsðos y…:?Ù%yI翉ÃevtY"êé± ÌN@°uSödVefg˜Œ¿3S÷¥ep$Â'kfº¨¸ÈX´]svþhØfo]äÜôÀ8… ò¦ŒQýPô¯òÿÜOûqB ‰Kûí8áÞd§òco·çá.Ø5¦H÷ÒT/ ‘JS˜Ì`§i%-:*]g›À½ø7ÒW\¸h?¼é×Öí1z†ÈÄÁáÁÒÎ •rŸ’'9Ó<Ž¢5ÙjÒp-ÙzäœzÝ%aÅIYÔà÷£7÷M\° §©P} sƒ'†‘°Íá=ú{:Ú3h®+Ã>Šc¯kë×Ϙß19Y +G2dSzó˜–1­chKwª'•×Róô9a ƒ¥™*˜»TpÛ½M3Ãà‚ÜN’§„áÜôü0œ7?ÒBoç™®ÂÓKm5QÅžn¦3 g΃ÙÙóU0901L´ÿ\³¶9›¶d¥`oN¡®"ÀAÃšÇ±Ö’äÆ¸ÁãÛÝ5&Ìí¼™‹†Þ†*°‹yØÃÃ.xà è¦y‹Ñ6½„”‰î½ÝýŠ2ÝÒIzîüF7l1ÕLry‚Ò›‹/®#'JÓt !ÍÓ’HÔ²:ì/@þÕ0ib• äSpÔÁÚ)´œù =/͹ðÍ­·.ùQÎI[XZÌ]Û~è©Iç6Æ´bxÕÏÎé[yåc_¾rû ›«Ä-nÍ•¡oú²I­½ç-ÜRý¼PìXöÃ]ßmi}äpVö[ ïA¸46&–¸˜Ú°öúÇçO¼~Ë…NÞܲ@/&ǯŸÚê÷3t×`v!¥n&+_—QZ¾6ühñ9ù…ââ‘?OYeYÅ­ç× C–!n¿I’±PD‹ë±PNKð$§™×œÎ˜2¹#4¼‡Ó(*f qa)DÁÒ##-à©\=!³…ú•¡56æ(Ÿ÷©HèX8á…xÞòB¶e0yBG£c}`ô’c­Í¿Ð˜‹5ÐGûƒ/¨!#ô^ˆÍî-­*m-Ñ%  .a- .Åõ$‘àI²3I$xòñÖ#ûà`9r5¸<2‡NôùÏ·N’+"}Œd5jªöW˲ÄsJþHŸ íÔl±n‹¹¥B†˜Ïç,–œ ä‚ÁHŠn)¨0’Ä“k Žñ’ç‘(¥ӣѕE¥žMݪaod‹Ë ŒhÄéH"Yc[hS°žvxx„¯¾V§[‘0t:ÝÌ­¾-eÚ?¸fEq|wfÍ—‘<Ì`rN‘ñ‰i_Ksæ2–9–ȯ®f. '2Õî Óµ0þ¦ê X^^JÜÍèÕß\ÕëqÆÆ¶SGáfz°XDb)´‚kDËÛ6+[ÊbӕІ6„Ö;­>Ê÷¨üix$)ÿ„¹ÒaZ'ØÞkw[€Û°¶ËÕâjù*[Ë}¨å»»óèÑX螀[zyŠ#ž fo‚ñaìì½`,ýÅŸ\Œ…lMsÇE¶Ð4}ì Qòãm +3â¸cäLº¶t>kÔs$®¢‘¸Š–'Aî¼ËÓ|=®“¯K§|=ø:UC"»$èŠ1)k ¨gÈa!†áO)PBú–»àð‚”Rjü·ý"Ø„ïˆþãvk ýR#¨É±+Sn‹Ñÿo ÷[7Û6Ûq=ê~$¶¥¼Ój-+åàbi±kq¬_ZéZ{”>ŠǨ!áfçkôkâ‡Ô‡â°ë¯n¾ËÕ%wÅÚÕ®òqкFä Tƒ¤êjªPn‡íç“æÂ ¤9*“æÃùâÒ';Í55ö#áGÖÿce‚_ŠEb±ÉÔÑbs‰GУΘe6=—™Í.”æ¸æx,ЉDc³)¦fÚdðmM—Ð5ºÑí7P°Z”´Ý޾ºÆœGèg´<6›ñó|2_ç‡ÌçËíg ½pàßì«¡½Hòºds%R.·Ç#)±`TÉg£étÜJ Q+fÁK'ÚÒ…îR´m(›G’’jÌ«BJ‰R‚(/„Tó@&M‰VI’­c`&Èódû6›Õ‚&·¢ÈV[Ñ>d§ŽÛáaû;µÊ~ÐNÙ ÀÊÁX–µd$ —òÛòó‡óloå7ç©ü’ör^·SÃp1d• bëͳYÒ৸{‰·32ÇIØEÁ?« hàHÄþ ¾Ö³Sƒ–™fÙnÀ¯â8b `Þ` ® mB2$Lè‰$x,ƒtôˆhàeÄ2EbÉen\eÑl³ÁéÛ]åZ>9dMP¯ J*F×ÍnB¤ßjу~:!È^%m­#{s§  ä`VU‚âw÷y7·E§*ôùF7%ßÚf½`9Ó>fÌÜy¶) ]Áï©¡"’Ât(8¯Ü.NšFM{ÖÓ¹ Œxoœ‰+sçUà»;µÇ.–+p,‰ +öÍéCCòÓ>œÝ‚ßÈû8› ¤ô¾ßÕ5,}Ò7Ò÷>YÉL3–¸?Þ 9;‰;nÒŒ±ç°Ås§N™:y*m×ÑÙAYS‚îK©ºKO¦2º#5éœi«ÁŒ±Ó"ÀR`"€o²­†þ˜§×ìr$ˆÚ½H{U‚’Ž÷àL£wL호No?/Ø"Ö·xµù”6[wBDínhÏŠ«áh2 +ÌÕ‘¼g*µ$1f€Ì‰övÐ7ÚžçH(£í¼ +oÝÑ?i§ÿmˆý¡|?´åCl*0sWÄÒÞÛÑŸ5§h \Àè¸$—´–~Òæ.µRÉDœA:”›iQ§…Zä†ÿ¬ž€²…šîžï¾;v·:”8žà\*üÁ©#@EØ©#;@à4´¢¤Á%چ©Z¯†×fm«¶M;¨ÖŽhÇ5‡vyä=Šÿé×ý¼wvx˸1ÚÑâ;†¶ioÄì°Ç¾ ˉp¾-«Àf° G€€wPàùk‚·©Þ Ü„h¦ Mî8¦+”,fíÖ21>qõ 3’080s¸op`d ïèÄ#=vxx€€•ºkâÚ:;riäšý­ÄyÖH¤b>ÂhÓ £ÀE vIÆyHÇ÷xʬ$ÕTêN* ÅyÈ¢(h-ø 9¼ÀÑ‘ +>Í~s:áºÆâêç´IfYõhŧ§ëïÜúØ1wmøþ˜ÆqQ—-‘¿ìœó¿½q鬱­ð¢Ýÿ-ï½›f¦ +)ßÚXtúÒo?ùåÄü:ìåýÒƒW‚!=ØŒí…a±!…×è( FWi±·/ +”p»ýÊë±ÎK !2Ý,$‰gŸ©Ù‚‚ATÙ™ +mÁÀßã8u”ÝEßM¯T-÷+¥E]Nª B'R2Ïdô˜E´`LtWW¡(Ÿ™ùUçgM!‰<‰$d„ °‘leâáÍ­œ!_×Áê¶5˜±™GollÒ´|Ó(xýõuõô4ÁOc…‰¬~hö4ÔpWÉŸV%Õ¥§Õüâüªü‡ú‡™ÏõÏ3vü†žyßë¡X«–Ïg—µE%JHyÆšŠ¤SåÔÜÀ3gägR¼M››îçÁ™Ü4þÜä”ôÌÌÌìÜ4äúº~gæÎìPþé>üfý€´Oß—y9ÿºþzæ]ýÝÌá| ° º÷L@й´±dK‰ÒDW/{7O¾ »Ñ¶IºSÞ¨lLܩߙÊ6w6¤h‡°^+]ëbGH×­£¢P +¸¢’šÐ¢*È6FhuFŘÆ*§îØÉgÒhàÞd²žTyޏd6ãÍf3hêé"/xy^}²âKZu¯Õª'’É¢¬xeYɦа +Z”Žq¨& 5‰§}wJòÚ»0ýv²z°k=RœÑxqs|G ¬ãÆGžm÷•G_ Õšqt†rº¢  l)&‹ž! „ V2uYÖ` ¸ ×±BË‚ÝkÏa‚Æ9l©´•4סW[å´¿îšõò‡_ñ¦ËP›Ÿ­þ,û~õ½úÛH{'}ŸÎDñƑ¿Áïmè 8i]§RÂëù;ü²MõD)]w\qò#jÚÈ^ššÖâ¨Å·,gÏEŠàÌc¢ €8GFÌŠ L‘sŸÏ),”WÂòÕ…uòƒð‘ÂOåßÊÇàG²Ã!CkÀRœR¤Ûä¶â¹2í/¦åT‘¶Èl1 s ‹ž²\RJÅ®æžæàz°V^§¬.Þ6Ê·ŸO·6ok~#ðcù`óïïʇ›‡–ÿ¬iþü#ðYQŸ +§¦.„ ó +W®S^“_-¾-¿]|_~¿è4‘@j,Ôây™¢b!^K˜Ø D¥²Ð d@E–qHj<ÎȔł\€tî ¢(ç(Ó¾¸J)äãªz†l¶hͰRøITEFõŒÁì^8–ŠÙ½fbît¢•µ +F³+Í1‘$¡‚­[g¸#×rx€¢?@HÐäÆcš©,Ë.dùˀ—ñ(<¼;P½eX³±É›}!Ãå-(~ +ðJØ4²Ê¢gi¾ÙÙŸ!è›–ƺfdiðŸ)pê„£¡Ö³^†ô”‘!½·XÍ`ø®×9c6‚ãp¨0?éë½…‘ƒÅù ÿÈ'Ìš“kë`^zí…™HZÿòw yzò®Ñîúòn4*³0{ѨTÁȨ I@ÂF74âó©åÔµÔ]êÃêsê>Õãx¯Ñâ\Ö6—º(J ±­ÅýcC®sâVŒ¹N¨±:#îŸÂ.‰ +'(š/À~t÷€øDÑ E3+Q?­d¯•8­k—ô¦å0ƒâ'È*†ãGûÊeóÞ ¢%%´Ú-‰ÄE(Qt˜Ä´i†¸麋°ÙÌY‡ú+P'_ªFÐFœƒmÌÚê/?¨“WP—÷ÏW%{ó­—>öo+àµ\u³Þ®®¦¯Z¯6ê:l0Ö|avÌçͯÁ¦_T§Óû‘Žejöž³ì8’û×lmÀ ._€+8x ÒYqˆyTBP¡Ökݨõ\Su4×T¥397ã´ëÅol²"çugÛB —&¼9€ÝZ]Ã…a’âqVòéAéµCÒ¡ÂYÜ•û@ó©“»±>ÓlÅá#B@iµŽë@gGr3<Ä%äQM真Ô_Ð Á~$½+cq¦Ñ$w¢“±á³Á'@2Q%3ަ©®‘çp"à¿YÇaË ,M“I]Ìp\c׸‹¯t]Ùx ¿Îµ®ñ6þ)îCþ ÁQ· eak+cŒƒžÎdÝ5Uîˆ{pæ`¤µžtL¢Ü¹ Íä¥6ˆÏ„âð9)²³yL̺§m Y_´ÒÖTÊC¬ªöbgHƒØ40—V[ÒÓVÍÒ!f•¬ ã Ì£åѦ+h×j¡Ä9x½5eOõ׬‚mZ„6ޱåGI)k0.­Ái;!gi#«Ι¯pÚÝï´“pPqÖ@þfú*­·øF=D+O×´-þ3Ê(°æhƃ¼¸¥`0u».¸sÕóÓÛ2ÍòŒªªŒM{|R"*ë°Up^={Ùøó/2 Iº<øöºKúo{køÑõ>±©úáÅ-QñµYF/]X”ë«Ï¯Lt,˜uù¾_Ì’Ý56¢uh ñ N"«ÈB[ȹCº_úµÄ®•Öz7Hyöý8ôãÈ[/»ÜÞH”æ|pCðÎ(•á-±²¾¹XÈd‡¦Ä2N§ƒR2~?àÃ=nhóŠnÃͺ+§þ{ởF¬Ìñ]%#Õ\•Øš8’ Ú¿Zf¸³Œ\²ÊX_réWÈ(AæÆ§¹¾Á™Ã§¡Ÿå:Ô3ŒŠ>I÷¦¢bx úÐ&âŠÍƒ!2¯~‡1nk BÛZ…§vô;b„Ça'K”ƒÏJ…û5Ülp<Ýì–³W)•qû$΢¥Ñ}. `Š´$È"•ExÎ+/¼R]ó»õóŽÁæêÏŽ_x>V»†îÇ Õ]Õ—~U}ÿ¥·–†á€ +œA«~ Z²®Ã™5àr¿Vj$¥‘ŒÍÈ”íײ6o%ÇBn-®¼Zõ]ZÂí¢(ÈË +É”P¯Âà*qa?ÄáéS˜b»—_ÂÓ‹ùƒüaž®eÉ‘‹Ïã ¶ÂŽý ‚]¢®Bfú.#ÆÓ‘"‚Ýr—n‹±ñ5ð¦ 'fÓ¯K"À&£hrM©Ñ,l0þ/hŠ:;'uÝWè4g§‚¢ÐëPˆQXÄÉûHûÛéõö*àA°_ǽåuå3;3ö1ÿ?i›Š­H²³ÙÔ•S¯ÔQd´ ¶£ÍgvÈÙvʾݹ¼Í*pÎNŽ:Q»ÃKƒ +]BË®•q¢Žá.ëÕÌ®.èº=¾OÃVrîÓ¾‘OMŒ2Ù€®‘Î.\œCük®¶A$)‡‰4‘à›ëE§G™Ç8Z£ÏxBm~ª=Ÿ+{ÊÕ¥cý¥¦ÆŽ`€ÉuŠÒÕÑ1fî¥ÕßÁÌõFǸ1é{«ïâ—„Vmèj„AŒšs†tÃX”ŠF@8‘Œ†)ïK¦zXqQ ž +Gi‘û# ¶ +©5„¼Há**Hûæá7 ,ÊDûËǰ`þI7m8tHB,PB¼S’5*Äz5‹OôHAW0 +Ë á Ó oØÎâ‚VÒæò¤Ý‘5w«)sw0jîÝ;|&ÙØƒ’§Õ!ÚÐÁËâtqŠ4-Ú£-çKs½ ¢WŠË¥ѵÒ³Áy—¸AÚàÞ½3ö¨ø¨ô°ëÑè>qŸôÃà¾èOÅŸH¯G~ýøŽô‘xL:ýBü\ú"òE´Qg„¨Xâ‹"ÑhXpZC‚?ùyŠ ñh€†|×EE R†ã.ÉëZ…î½$:X)vQQ/EEc‘§0/\î6ì¼$Ò>¿#ñÃøCÑg¨§œ†«BwöDa´B}l8UÌmÜI;ŸQ1i ’zJp¤oXÆ–bßðé˜Ç ÊÅ`+¢F÷asp{Ó¡ÿÝÜ Ýt¨“ëDÿ1ï_ߨw- C{£b$"ˆ1ˆ)uíý±˜ Ò\À[W—ý§ÕåÓ¡]­K|P8ð@ÊkµÔpS$&a£èçFþç¢ø¸¥Õ¹s•–ñð¿ðrßì‘Ï/g¾öÁÇðµ·{Ò±§ë¢\üsÑ—Ýy>«ëL^k\ Trä÷ØFs:JÓ÷•úó™ŒAº-dÔºÐCEªžH?üñÇ]÷Yôcd«â!®¡ÏÙ¼$AÖ뱸HÖ•ÛB‘=´¨¤£âã¼™;ýß„ þëM‰°|‚{¶u¼H¡ì›´•âxP^â+yo0!Ä­šKu'eUQƒBÙÚáÆ`Gp:?M˜d,OV¦¯àãþ=øHhKü9ð,ÿ”ðå;ÁgC/ñ»…=Ö=ò^eð@è`ü×ò§ÖOå/ƒM['µM–´’67Æl£Y³=÷\³M§Í6‘0[—‹´†¡„[Åø`R«ØÕ›ÙÛ]›âBßjm•Ë¡×,µw‚ÜÖò…ëž*S§í‡ÔZÚ~åÔF£TTYQЂՋ …P0H’÷ž³° CrýÍ”ý b“+0b¸[¡dMZ·X÷Xß²²Ö›„Öô$ÃRØÊïㆄÐM‚²&ˆÉÏT  óÝ­B œD"iÍ%Üìµ—€pP „ +|y‡Cqój wávèiÕ°F‘r9Ì-vpDþ@A¥æ‡é”‡M² âfÁUæ6Ô¼+£Ü>ÿbò˜ä=õÙBŠ$¢9ƒý&VÕïèBòòØ^Ô +I.sd‡§lÅT`VO™W=åzÔb€°î)‚Àm ÚÔ:R6,5"fø_ LnìûM»à‹átÖ÷ë·¼-Þ +s­ÞD¸z [ÝçÏÄ\Íô}zJM«ÊÑq +¢ Í*WtÊÉ¿Ðl[ABs3q!+íOh^µ3Æ’Áž²Ê­)¦ „c¬5y$ªìASÔe:eÑ:?røðA²qÕ©*Œ îÉV¸É±É¹Éµ!µ¡õmÛÛߦÛ"ˆù”U·%íƒÖ5¶š¹pG^¼°Éw±]R—«=Õ•)·;¦Ùz¤×”è´Ôy™­FÇ_niú{6›néEWü¦,±,§+—,éÞRI·ûÓéb‹ÝÛÒb/µ¦dÁhI늭½’­´½•+…ñÌm„ sÅ0 ÇÐ=)äñ ASÒåÂó,ߤâW™&ØÔF¬ö +œ¼{¥úóz:wª +Tð!ìRÉP¶)G”ã +ƒwàY¦ ÚÖÉÁå;Jùtò;A l9@½Ê ƒš¹S{s£Iš…#š¹¾ÜÀð‰ºêËÕ§® ‘’£}9¼D’Ò50áÏrÖˆ´ ì.ßT?–Žöá«~”\zŒîC{$òTºñcÔãx©Ó‰›ÔyÓ¡C¸9ÄâPã½&b˜Ð ÕCó¶SÇwXqþó½B9€™˜mX³C­ƒ]„°«ËŒã.ïEOpkxÎ.ÃF9L¸Õ†{8p/j³íø±¬«"žÊïìqÉ–#¨!@dzÁAö`²º”Š.´Ï…?‡„™þ;Üfã2ƒ£,¡ àB€á.K’XFúB¹Ñð•=¦OÕo6n¢ä`~èã†ÇWnã}åLÑ[΢‡‹÷cl:˜¿œ5\èá+7ãúæþvôpŸ:øç¿¯R³^ ,%V9ÕÊä)ÉCƒv-í–ÆX˜Îˆ"Í‚ÎrèÖ)£Mtm±â<£˜´ˆ¥ÏRÆâE-_Ìj ›¿{ÆÔx +¶IŽ™{ÓÑ9SËÕÞ&ÅcÜñ­IMMÕ_'C© ~úùç U-›¥øŠ—}]§åøà3Õʺ1t2éu}‡-rÉi*™d½‘kOì‹fÝùHG"Ø.5½iVçPty› «ûv¬îWl¯ÛÞ±³1v¬éïµÐèHA«ù˜ÊC¸šrÌykbÃHŸ%Õ)b:‰» §ÂUø .>ê9Se¼-ÐÚÔ4ލé™rH3/êßÀš9ô©£Ôxö^@×ÎJìOcËÛDÆgÚpP4R!iéðІÎ*fxUºH/¡WÑ[é#´…>¿Gý”©À•Ûß#gfÎÌ.Â_w“ɵ“²Ñ8äN„‘Ø ÆW}½ð#öÞÌcŸGg0ýÔX]—d-£o‚EË$U  ±ć£OˆO¸÷ˆhFðQèÀ›è|×ù¿Nßåÿwúà ôZ°ÓN†ŠL¥Òl—\É:Qv7‚p?ºx3ö¨°™0 +Ô{»]¹mDÆ`÷îMŽ-ÊQ¡ FÁ+P/ ß ›¥^tÁ˜«ËE¹‚F +¦„NU†¢“)™8 äiú²š_»fI}Ÿâhí‰lU œè;ñA×p½Ú=æiÀî_Èbçô`Ê–òë–Ðì>´á¶ Zަ¯¸Ço)ßjX’Âå 'é0Kª,…i¯ƒ$uÖ¤?k¬Ñ<àÄ=ŒZ¨U\b*6âÜI“¢uæ±Øø¾½á·7­~è¶Ÿ¬‹]^=~ úâ¾»öÀ®~kSƒ;ä ÚØ«ª-?ß³±úÖ{•êß7<ëÝýì?öŸü)œs`ªß•զŸ:FïeW «. ~GP—ð*ΜdYnŽ`І©)#E©%©­©#)&廋ÁJ°l[ 'Ѳ‹›Üâ3‡OWN?&Éx’²P†”…ÓáH(¢-ž”¨ÛRH**”Ec\KAÌ\ +½NÔóÛqÒ$T—Â6nÉ·(VßÒÓõÔÈ£¡áæÐvV%Ao–uø*܇;úŽÑŠèÚð»ä#+™\Gm5Oö M¿gõ…K»ñÑ;µôG7_}hry mu4_L–³“JS[©ÇÁž º·¼Z}ñãêžûßå³ê±í÷_2ø,{ôš¢vÎìêcxâJwO±ç8bæÄ1§Žìô„Ƴx¡Í¡ŽÂC–n&ñıÕñøcêøuÄa hƒÀa8h +é¾ø-#HS^š¦ÚÁç–Ø?B j,„˜Ô>¼g« Ú;»Ÿ:hêO†0c0½ÌV†e~@}ìµ["a¢Jr_N`{NÎu2SÖÔa5»Úr{›…} k<ÇjŒXHe0ôÅø¢Öj‚i>´ h-“þõ›jç*xõî✖{^ê/1¯†òKlèšGš¡3¿éA1¼†¼DÞ*‘ÑÑ ™Z Û¯€Ý@€[AФϣ~]Ôϯ~´À¿N(Š”@AVàí öÃÏÐÛ§n§S4\¥¢¸^Ü,nQ ì§’ðhmHbÏßðQÉt*‘ €Q>‚QFÓud¹z*µ}´Ö•Ç, „ÅÌxj”Ìà8œ®y:/ªRKÚýV´.è˜ÿüö—ÛqXŠŒ¹žúý} j4à©÷Oý™}ˆ4üŒüúw¹¡{„”ÑSÚDAw„‚iªÉÓî¹ÎóõuŠâ<ñ¸[ÂÕs⮞§q<.áÅñ¸„Ûí‚wǽnw<^ß1Äô Ð* +y·@“8šÝ=ÛåR¥¢dH´„K·à©Ž¹Åâ`•'äDRWÉÈB5 q4•õx Õª¦ãð 2‹ÌÊBš7ÓOpÍ!%sÉélÇBgQ÷­¢¨ÿf6ª™GÃÃL¿@W¾LBs¦î}8U+#¸wv²»Lw/ºW‚+Ý×»…ÏÁp·û§ðÐýW +b[i!ÈASU£N=‹õ2 šÜ‰ &7®Š¬#ŒÕ–c;jMˆ4{”2äeÜ}kYn¿»LI>B·î1µ, +—$Í绽eÊ8]žÖj’X ‡ + €r i»À¤@É¡09¡Q¤i{au†Öàh0ÊtH&¾$ø›\EŸƒƒ|ðþKž¼%”ê)V38ö7îœq‘qìy'9ÚYî}¹‘™tò‡£±¾'7z3ÚG÷#;Ìß&ã­àæ™ÙÂlqlq>ÇTnK:kcÚzÁ±×G‡˜€Ó#^Ì\ ¾Ç¹Ú‚tÀO‹”“µÏ`á ,ìe—°[´[&‰pµ‹+EJ,RV$3‘ +M6&«výWŸJR·/ŠËº'f–ÝeÚ§(&i­j m£Úþ¦—…lÑa·H‹E(!ePã0Ôx£‘†ù-è§å{°ˆÈUÚ,º=:`ÏÛJH­¡àÛ¦‰1ëÄÀÌG±XGâýDßQé(Î8$•ƒñ¦~޵\ 427ÜtH®å,Ôb€Ápd¨9O64Öè"Ú¦ +êˆ~–ôc¤îï÷øËLÆ‹»ïìñ–™UnÜݼÇ]fdîÛãC]‘t·‹g«Ôxd…öÚlvŸ²³¤½ÝB‰$埲þ‹rhÙÅ +qb,Zƒ5’ò@_d;ùµ¤úÖ%ž“AäÈ#pÖ3’ *Õ?%é%Ñ<½ªŸ|+Ѩ.GÒóžäH| n7eUý®ou” +ù5òêÐêð™UùûÃÜ:yoræw¡ß…›´(i)ŸI•õrz\¦˜¿0}EzU~(o{ À`8žþò»ûlþ$ùnà·ÉwÓïd>JZÂF"’áD‡±§%ÄXȧ%@Dmlˆdº=ÈÂMp¾†Œßï£xŽwƒ ,ઠœ–¯E@ùmyj wÓùFHâ@„|Ì,&‘ŸY¾›„"œ7å+ðÚŽ••Z[±úfb–”É’ªÕ‚¨s‚à´ÿ²ÛŒGãQ2Ëz&• ¤Z`2Œ6i¥¡ê¡DË¢isÖR-à‰qL<ªŽšŠ„‚Ñ!)¼ž m$ÐÞ݉𾆠+÷·ý>/YV|Ôh}êú²Rg~øÈ‚ÓÅpR·ÿ4›Ÿ §f¶’’ Þ.Ùð·=¿Üü»×Ç v—.ˆ¬xpêmsZz©ªkÎ.Ö0cÇõOvžkµ~{hÁƒ3žL¡£ÆX}Y›ÀÖmú¡ÜþÜk¹wé_å>d>´~É|iV±«,ë¹õü;dÙÄmâyÎ*4Pœf·W`Êpð!.‚³ã¢ðž,²8 Ò$ ¥´D®1cåí KQ0îq  $R #a4õ+CO§S”?À§s™ÆR³fàËn¶XbìáàË„d·‘N2\j#ì3FÈp‰2\"çÿ)lH(fqʰ ¡ñ—¾Ñħӫ^®–ù4Ro‘„@·x ‡„F6›bÙÏRÇéO”™þ”ÒÉíNQÞ€Lnwà¬Û}¶àšk‹+‘§L.¸GìÁ¯Ã'>›ÛãÐu˜ž<é3‡Um,ŽÙ_ ¡ÑLÿÍ‘N¾ìJ–ùhÆÊj©gº^wVn0éWß^¼0ƒ£? ½°éq2È@“ß°FXk½Öy‹ð®þ¡n±ÐȬ»ž¹Þ{€éä3–N(ÅB«‹yÈWàÄ=*2ÆR"¬À¯ï”‹M¢̺’À†RŒÊhXÒ°µáHÓ `Þ–~ x$ê)z ÏfÏVçQ²§ Ž“}3GŽÖ,Ž&·Bœ¥N·Z+Xd³„,ÑoÑDn ë‚;ކ)‹Kw¤t!±ƤÐR 9Q/iM-…a·ºÄíê™4- 5ÚŽÐv>…ì¸ÝhjвÉÒ"³"2BþÏŽ~ÑqK ô9iî45u:åBÆ\[ 4&ëÌÔúÛžyâªäæoÜýÆò߸û’—¾ ÅϯyÃ}î”–ió7ÞySj>»Bwô|ç?7^zdÛó÷<ÑNÙ§VŒLÚ0{É&ž|è»ÿPñšŠlñëˆ"~IîÔ˜ÝÏrÏYŸ“˜ká:n¼“c&òŽ  }‹ wÆèMáD^ì0h–ž!ÕBºJjĈPW§$¨% +1¦…kæ3¶žgJ¹OÍhzÝÖk†!lÓSž”ÓîjB7Pn‚^õü,êIVGT(´qó¾&`|MàL5 -}èò4K†wõ#ÓÁGR,¨AU"×ðvlý»ˆAçvIh1†<¼µz}õ£ê±ê­¿ù³=_ÛxïÕ;_þbã×E¼²úVõ§Õð^Ø '¾±}Ú†g«?¨îÚy'l€Ýð¢ïÞ‰«ÓV§3€~D@ŽbÏðdSdÉHùü¤¶rÑZeb'v’Š´5yCHFœõ’‰N¬Q’5‡Ýo"6$.b£î„.[² Ý6Îi"j é:³ñA‚å1á4C 8?+Ô€:!g +ŠÁè<‰†M„O•Ó½M”Ñ4ÔôdfkS µ®†ö\d ­§aj){Á…Ñ^톏•ÒÒàRmeÃÒ@p}t@[Ÿ»=øõÜcâÁÇ¢h5<ž{Öÿtð»áïåöù_BgðÛÜǹ/s jÓ5ú5™Mž=z6q³=0Î;³Q.]«G’ÅhŒN³ÿ¬„‘9Îâ …@,æÄašˆÁÍZ‡à‹†<©žüQjŒäëõQ/û~îû«ö¸µobc½f,®8’ë4—ÚY‡‘¾é +±L†œœÌxÉ@JÚèþ„ +Ó^\:Ö,ìIY²ÁöÕ#ekW„3 ïêçœr‚¨\2çÎVxÿ•ì¾RRZË„!o,íªS-á©L_%·L¯6{Ú#^yÑÓnÿôþGyIª£tkzYת­O\3î"úÅ//_ÐÖuÉV¾ÞÕßó÷Ÿ~uU 'G +ðû3æu¾ôʾƒ-h$¢©LïCë­8 MfqÆï€"˜ì0DÚaƒú8HY -°ÈØmÀØ Îð¨À°áæx/Çñ<Íp;bè8`ƒ[  -o±ð,c·3à4@#{ûrÃ&" ·Ð/â”~ø™!#³ šÃ5·ŠGDZ´H *Î3ªÉ tΤN¤k£î1üÊ…úiÜ.“P «ÚLìZE$±p í¶3<å°Tø€aíç}ÉàÓ¾FL~Ú’k6ƒXЗp%\HùEÒÏé}{žùµækOU“ðĽÕGàåCô-'=B*Ã,EÒ +#–4hVO›ø$Ý £WD׳ë-ë#÷0_p%ª¤Í¥çªóµ«ÂkÙuá Ô]Á»ÂOÐÏ +i$b©$¹ÜR0¼Цñeu©šW¥U †Â4'3,Ú»e§ªjžýð Ó]øG@ýQÓL vîî!Rø¬?1¬F‰%HåõWà{$j«5|CP i«„lÒø~x?ü\Ý£}8U±_IBLe²aþ1BG]å:Ÿ8kæ$Ö¥áÀ‘ÙAõx u‹j©¹uÐ4À0XÛUÌJ÷²(ÒÍ",.HÚN«^ÛÝOÓšC®ð`W¿Ã¡Qh׎~9[šqǘ¬rg¶«Ë1¤@zݬꊅPxôöù·ͺëWæÁtaÆÌ5Û¿ûê@†=ïù=éÇï¬\µg(=vvs8'i­Û×ßðëŽ&ŽÑ8¼ݹ»Ð¸W@ +´À'ÉÝÛ¿B¡%ÖÒ^Ùr}|È6dǵToчRwµ<'?|FßißÜ›:~Õúªí7?¬Ðâ ‚BÚïu‡îœï·:nw>œã@œfÀi™ÅpQú¢–+Á•ð +jyêÊôŠ–àéµ7¶`ö’!nˆ¿Åu‹{“w“ÿ!æþ>×îGýO§¾—þ^K…ÙÃhû³ýCç‡é›³œCHw€2lof'ñÀL3d#ˆGÕÂ6áÆãˆt h HãÁ"êKhÖI d”(ÌY½µt¤Ä”?@/Ðhä4 ÝÇZ ÍÈÒUZ÷ÿԆŠ’%ˆ‡ÄðѦì%¡Ó€ÉiÑœ+Dã.?ÃûtM,1.²6z–‚¼»¸Æu)Œb§jÎß´\M¦ŠS“Á7›éyû±C{ƒvf<¤Ú¼¿«ßÂzš*Üvô{£éwgCÒqþÑBŸhŸ^£$ÊŽ§žœG( 6~»ïçž|½ÿ»ÛÊçývû+ýóÖÁ1×k/¿|¨4¦mvïׯî¿%u.õÝ۶λíåƒç=~Õ³.ØôÓu—\sáö·ûoê¹âÚµ=­+ +Õ?MyjÉÍ^?jùJ4ï±îó<Ò}Zádä̱2Sò”’f(I–Jm3Ú–´]ǯ’W)×5l–7+ÛämŠ­©°Ö¶ÁFËmù`oÛª¶{˜ï1GÚ;}‡í`=•Ç$¸ÀCЃî¬UxÖïµ@ËwÎÅf؇ )j–abÙ =èýµ(®ýª$±> 8¢uプm~ 6zÃã³´àô›ª+õó.ÿ¼ë-ØO}­aÒÇÕ^}ûÅ»žykXytVóÈYM'g•Ì2 üT–F§ãB§åHd[Ñ)™é±´eÈ·àÉ>-|R‚ÖOÊSB“Ü퓇¹M‘œÈSù‡.ÛôXõçŸÝ°e¦¦Ì¸‘]Ö0ãòoV¯ýuõ'Uø5}òGðªW½í®§É9¹Ñêÿ}ìդƒÙk-1Ê´àvùaTràD2gŒòsNŠ#ØSR°VÐî–4èçmåçüÀCe<ÚR2Á£Ò·ª‰Öÿq;®ÑûûäÁmÚûœòBðìË>  g,ÏqÏûžñ³r›ÅÍîGü›5ö +ß²ÀjfuHc/ôÏôj—Y®àØEÜB~‘õbçBkh½`=ŸmaU­•i÷MÓœ¬nÉr>ãËøYdôjEm Nc¨iyaàÔT«?èoðÓ~Îbȉ“4ø˜³võ‘Â|SsÌ{ C@ôI!ÑÉ£7ÇÑP¬rjƒáòs•ç¸8ß~¿µXðJ‚îŽÅDÑég¾ ÀÀŸŠ~ÿÙÜÏø}2ß¶ùŽûXÕ·Ä·Ê7äc|ê£=ªö€Y(ïD_Ÿr¢ïhºÅµõ`4ñÿ )FYýúNÿ™ 91gVÙ†»Ì`»Tæyžõïìñ”­Þûξö…dêû9) +i§ƒøÜÐEâ°l:cÂââpVt©–[X/m—.±ßŸª—²Õ´^eÒ’2m<Õpq{.„F¡c2kG³Ú¡¹ìËc¾q¡7–`u]È'›¯<ù>íZÝ)Ù ¥xê¯Õ)Œ»úÒuK¦ç Ҡ¥àræÜ©hž|Òi’ÏbÔ)¤*Üÿlò6P+iŒûËÿbÕ)sÐñþ_e\”¯ùôñ¬ÙúÁÞŸ%} + +3ÉÁ( ÊÝÞOy0>|užC §þ@»ÐJ@7™×ã&»ábÏb/µ,°*p»ý»âAu˰¨:äÍ‚IðËaɯP*z /EÈóhën%ã"Ẹ ×ÅM˜Ô„À²%„"oð›ø-ü‹<û2ÿЧyª–>ðgÃKÒˆã…êïIP:’Ô+Ô˜Ú‘ï`—þÑ>éÓÑ8¤)x†1M\§iwÖ½R0dµíáqÐf Ù”q€ð¨ÖòuúB»¼^èP*ÜG»û‘ªùbkQﯰ§šÄË5û§æ}ƒ$ÈŸ\}q¿¢5ª-é@2T ¹˜,uŒzýÈ¿ôõ¾Î1J¬aQÛ„9ôãµ|ƒS—V§ÀMì&`Yxü ï“-ã!éžEò.ìm""›±«©&­ß1<ø}‚ƒø¦V¼Û¦w•|u>®Wû}½Ý;†@ÊÏK–dšÙ3$Ó,“õ‡~&Âð›L£ôö›¦_ª^˜âM4i_CÃiÏcAhQ`¯‹]cKŽÜG_›‘ëÍmÎ=ë|6²5gQÑ“¡-¡=‡st§€w§£™I +þI–¹ž Ð „Ô¬óã"[ ;‡¾YÜâ$«³a3®Gç–è|.Úí’²æ`°K ÿR´MÆb›qq.¸DݪWiU%ÈëÊ©O ÉjÛÑû…¶ã‰Z¨Vƒ!G(z1kæ‰Üð 4܇ÅR—¹¸n³¼Úµ ÔòðàBœ*Tóc¸s5ð€9ªÂQ§ÑÃb, £ÎfõƒõZßh©è[Úå÷KYK…³Ç0ËI¡ +wéf®® ‰3}•ØËuf¡]ËÙ¥`&×Ù™kèìz}ë¢c´`Èu‰&çý¤HBÆ ½ì&òrC®³ªž¼ü££‰f7_Ÿÿ êžsfñ^¡/ƒG¶R\BfzDP ¬$xÁ‡á¥Ãèb³b Bög6ì””Pø°hà—ð“äu&¦­-tæ®ó c¹î$åP ™8m§ÖNOìÿËr=h³;mî +3>ÖÐ1ñª…ãèË +ç”R%$v8¡³©9œ˜³ötõ€ˆôóÑêÔE¯8=?v¹NÆåÏwY:Æfp8ÅR. ä™”ÒN¥(…·ð„’ r Úøä¨Ô—ֹдRð:p­Æºc«ãËÉ[–ºœÑMwãѽ)–h] ®s]_•»¾é‘øÃ‰§áÓÒsÚsñçO7=W88 HíoßÓõºôjèUõõòÁî_»­~a;Þv$ÕW“¹L¾P8G*º‹ê8­-]Ì nЭv»w3¯5ÁÕM7nÏm,0s í 5ZH( ÿø®îÁ‰i‹Û›‡ÉüeÚSÚSù:29λ¬+•§\@Ë3!_ŠPÐäñ¥¥ÚS5âW_­5ø"Ôµyµ›4µ Å]RÜÝ`“»Ë"q!KPEGI7eBérWG¨ÌB&Ä¢E*¤¤âø¨…±¡ö¦¸$Åa“Â&¤J¹I¸Zðªj!¯¹C60^noÇQº ¢X,,¿¢ våj(BáEp \·Áƒð<­°BýÃ'©³Õeh7ƒøÖ8¯Pÿ±Çè~ ^t÷DßHßR&ºÎȯù>þ %üÿDepæVD ±®Œ«u£+ƒcèL\°§³ñÂxºo!©ît…¶,·²°¤›ð ÃÁ $Ãâåé+Ú©Ì4œMrÌðØË ÙVΣGbª¿œ*ú Ñ×9žñcåÈÙ‹¡À6’ŒN™uíËM¼»WÝåvlƈČAÛD«f“3›ñg+:_Aè’_Ëö<Ð\L03¶ƒ&AGÃÚ†‡Ì1t0Dð¸hÔü3·Î^ŒËºNZÎÀÞ¶…ð UÉã1ßUgb°pô$˜X·æÂ‘ýa_HàŠT6¹ÛΫÆZôñ«¦B£úÉÕ]J]Ó;®xøo »˜Ÿ +ÿPN¶]xõ×ê¬]‹‘m‚î \狪÷u¤}j­ë¬\°Þ7l¹³3äÃú¹ÕÃ1mŸOò¹ Ú%f]ãa÷V¿ +ôv$U`½‰ÚÕôW\ËÛ^Å)»#äñI‚}lÇ Hg™eÄ¢†l£ 3àÕ’:D-¦ i´özHIℼYYø$‚”ÁéØÒÑÓ´²‡|‡Ý•mBÞˆ+ +_eo¤ÍĦÓKbÍ…ƒ5&Ç‹—gÓÝÞ13Ú&,ßDo7L"GãÿhŒoêõ8¯ÐÑ2fÊ5‹—oG¿ôè©£ð5ù“Ámø— ž +N„1„¶öÿ[Ý·†ÇQ] ÞS¯~?Ô­~·¤j•ºe©õh½e=KnK–mÉ’’mÅ-Y2~È–l6VÆÐ`0É„aÙ|Á„à‰!’mì6&!ùB&ßd—o2;3™gã°;d@Fa!ØÝ{nUK–²¿öÛ•ºêžû¬ºçÞsëœsï=·žÈrW½^=—¥0Toô¿o½£‘Èå õM.ä ÙþKk‘& ë•-(TrvÙ]o”¹÷}t]ðÒîÃëö·Ôjª ½´ºNÓ csš{ÍX¥´róJ›>{"£BOuuw0WY¸ƒ-oðw®[7àÞˆuUÒàÊ.u>33ËÅZ¹H*Ôö+‹Ã¨î+À +VØŠÐn¸îƒSä1ýë¶ßg“I7°[ôì_qiæ ¹Zï^egIá·ôzj¿`ŽÌŽ ëõ6ZÜVä¬v2·æ—ygÿª¥¹ÏUò*f•¿~ÌØ,EÆÒ_úqsŸ×(R(çÐÖI±¨llˆˆá`Äd6šÁ.‘Â#¹Š+¡Àà¯$Þ"yè åVbÍft zŸÕ] ’o9ËÀK+]Ë£¹u#ãŽMëþ녎´îê‹3zb°»Óºß#OÁæLý#w†Øç)áFè)|š¤OçLó ,O™jK`#ì}»¯ÿU*óƒÌß}jÓ=' ^‹g~›¹çâìC|ñå#'Ö®þŽM9cùéóÓ-]ø¾¿”9ùñ™û¹·?ÿtFÉ\:÷À_‡¶?3[­‡½ƒÁVs“Jò¤6ÄÊy=á@Ѫb}ži•\|Ñ“'›.KØjd6lá¢ð¼j¼»\¶ZNcå_³Y‹¬óVÖJà \Ë·QªðUU§áÎó!zè’é<ªVÏñ!ë±–Nf¹¥xRwÚyH±i•)¨ŒImí’MUײAâº4üñÁ]g4X,޲öµM=3Ç™íÓ²Éd6U¸ËÚ×7wï»ß_V5Õ*Y¬¶öŠXüÎÍSÏG"-;:‚V«½5ZÓwxóÞçñ ²¿â?D ÕvÒgUEÈÀÕÆ>‚Õ0‰nk@ôu kÊg³«fëf»ï \- ¨&ÌÝõꆫ£¾L®+ ô”Nê’ÁdY²vº}®öÎö‘WŽ:…ŽÚ®² rÍå(ÓÃ:¹¸#˜ßÑd¹ŠªÊXµê‚åBE´ÃÙe0Ô/4'$”6˜c²É¾æ'Èšjè±ó$¾O‘x—2æ—‚EØ~–4|AvúŠ"ù\²®´.ÌÍ1Ei¨”½m;}³¾c¾G|Oú¾í{Eµ¯ô{ŸÑç[;€ùV6ç"59Œì¸v‚n®5íïÝTÕF¹ù¯EÕ½ý”€ëúVkG,ª8ŒS]µ-*t89R[ìâÜ’ÝÖÏ£\£*‘ÜkÒzã‹3v·AjV×åHKĤ*­£ªÉEON)(ŒÎ[¡¯.¸Z:HWµvÝtk.Dûb®œqF"¥K!œ ¾±uD98öКx2?þÆá³S÷¾~è™W_x§ºø³“ÿé/{4},¥ºË2Ÿ¿÷3cÝ[ÇŠüÅÝíŸ>šº«ó.voX×™y5µgd ?pò¾±}7+÷}÷s{Ž·?·-qòŽ}§wþ·—zªª$À›ZÛÑ÷©£-5Goú.œùLüÌÄþ¯×’lv‰J%»áž&Hs5ó5 ¦œ-ñ}œêÂä$·{ ¿ iµ—úéÎQ/¸j"ò¢Pmš%³&!‰ÂR—ÝHtl)1¢k",B B„è2°/šL$Éÿ ÄŒÞÙÒKÔƒþŠ`¢ÛUü|yEdbŒÌÌ1o0¼È³Ã<ªi5-Ž·ÝlC°úú5ºÙ«-×=o^Ï©9ÏY&­ûùú1ª®Óìä…BHî!W(ñd¬ð‡!X̘O¿ûÛpÆ‚cV8{ý9Rd€Á×ÕšîÐó:‡—÷88‡Õ#äÙtv«§ÐâòÌ:»×Rd y&”茼yzÑÙ}/ãr²ù«Ûce\l¾×âg\c0`dóÇæƒ1 µ5·ˆÁêñP–™ïõZ\n·Ïç÷04ÐÃæ;Á DZ—tyGaaQÏ 4®Rg·ÙÌf“I¯× V‹Åh4%b´çååç»:­'<Ï[N$½s^Æ›f,²Çx"`8xžt2ȱ6Š[QSÍRM+-R¼¾7~íæâ¢Ê]߯jw~ô¼õñãBs»‡Nh'wØ>ò§‰ˆn¿ÚR—fœAÖQ¤–m36“ŽÅƒ—,VcŸèÁ)ÈS`cÖjwz–Sj¨sb»:ëXzÕ¹$¼B¬ä ±Î3tdü¹+ñ,çö‘í°qbdç³—ÙÌ;ã·gžßyFú2ÏáõaØ:¯gVÓk(svXƒlÅnøÍÌ>&‰=BG´þà• @t–ã#,c× }ôäƒsr«‰‡Î¼,55ÐUsì<Ëͳ§Xæ4 ì ^P†˜$àXjHCÍùÐOµO[FO×âé8Èõ7ÕScoIÕ €Húý…p0¼ªG`ì·VF…Ôîb’™>HgÞ„âÌ> ~ îMÈìeXµ&ÏhúzÙpÚÀ$ €ut vž‹0¬£Ó´BØ÷תC¹«Ã‹ü?Ïsóü)ž9T|"F¾tƒ5yjHˆlR ™«£¸Vz²¥ª`_Q™“L×pX‡ 3¬ƒèÔÊ[•q†TŠ `Mú°&oòûßÏ +S”# ÃϹìü†êÈQõ‚©á"?Èíäî»ì:LD‡|l‰Ö–‚L3„·Óä r•ð…Qžaìor22œÆ!ì(•²°Ã CJcɽ6ähýù½qušU%ˆñC´bïшªTuX‹?œŸÑdÌþ;†|ù rúæš>ü[z±G†‡U+™Ì;Ç?L†AP[ã¤kÓqÛöÆËÖWüç—†â-ñ¦ÿú&¾ÕÚlkñ·FšuÃúü{±½-¿+¿;¿§"Po´Ç76ÄwvÆzôí»ß{_ðxÏ}{ ~¥çñ¾g½g‚Ïô<×ÿ£ÈšÄý=«¹Úuõ‰FÎ--)ðع"£…”6ÖrÆ(WÔYuoq[.É’£~ð^![~æª/úYéã?ëì×ÅÖýdÝë¸uÇG4óÔpÄÍ›‹7Q*X\Äqn´¡ºK`nŸ +F&bñ—6&„*YGÔŽ¹5¥+äŽ ¥ º¢`i]s¤ô¶åM4~éÓ«6Qº\Ž~Çy‹kJŠª„¦ŠÞîâPe÷××Õ¨,,ìï(kg\%±@¸ÐUeæ[+úÃþ`q¬¬,ìhmøLAeeahíA.?Þ;Æ'ÕV>Õ+ÕF*‹Â-yî€ÕÝ]ZXQÞ_]ÝswtUS«*v¢®¶46ì¶W}Ms¾Å°ù]¡ê@eù1zÖè[Ùk:¿jÕƒ’¨ºê^ž©È‚YvxåÂB‡C0äÜÓ’;ž¤GšØBƒ¡GàfC¯„²(„þ“MvaMàú¥‹±¹] Àͺ^qe]¬ëŸXÙ0ßÒPdØi` ¿40Лáý’ßü"gù*zS½/9¹Ø×sÇóŽ.yÍ(]84s¬uÈ$Ô&kèÏÀ°9g«•ùçœ\·ÈËÖ[?êRz¸ÌNÃÛª.r¯Š—!‚—bÔáì¼>_¶\$ªFÒf/²ÏÓMPþ"ßâùä-I`ýâum 0ÑØÁÀyK~Žõ_šëÑøû¦[ tUþ ^Þ˜M6£#@•’ÑÕ½ûF[ùýÑŽ†ÒQSJÖ#‡U¥dnÿm»ºÿö.u4> ¬l +N5î= “Û‡k[¹žWw.9òëU×dGª/‘çYÇÿeóÓ͸ª‚õ=l§Û÷ãÒ}+wä:A‚x{(ãÎmÈÅ®/ûCab”%y¤eŒ.ø¢6{Œ;ËœΘÏÚφÏTœ].š/Û/‡/V\Ž™¿¤g•ë@V%%`Š\„íh $ŒŽ„1 c9¹è„„ ìoI”—3ØL,˜J›;þÔØ‹„Ãr¤9Rn Û#¡ˆÇíuûܬ`„ëj HWIG¬Ž"ÔZ†3ÏU@Šù¢ð› +j¨®-€ÎÞš*[ +Hû*¼åÛ +xs[¤P·•ÖË—þÊ—¡Ï©æ‚T›ÖýêÂŒTn pqÆÈ±<çPÃ8¾¼EÊM ¥uå +äšLN7O/Œ:†yr»Ý—mºÁò>Ž\ü­^J£ù¹%cì¿ÞØ|â+ß¼{ð‹ƒC&êÝy%®¢XqmÈž]srý³wö?08øÀš˜TYU«*‰ÅBüþ?óO_}ô…ïnýÖÞ½ [›?ý½û› +õë/|w}Ý̓۾uÇ•m½ï [¯_S×Ôîå:Ú¿ŸÊ$È¢Ú¿§Ô>d&ü¾¼ý§àC·mü\F.GÚ$$·áœÑV’³´3¿ EHžû–9•ÍYÞù®-M ÝÙy«;çIy‹#üÃï§u}ªôq…ãþ’È’P\M,xˆW`rpGô: –zàIuuTSmŸÃ/8}“Àç ,#ðŒæ7P»¥ØƒAx‰íÆQ¹û+2]è%2öõ&,^"á W®’yèägùc”ãáŽð2ÏœÊm†Kb0##?Äd‹þ%fÉà]ÙMl³SxD`f…c#ìЩ|Ä"=fâú u[å´Iõø¡ë~ßÍ›~/:t›$5_Ê-Ù1¥UF¦ý§“¿ê $¸a®þÆ$ûµÿŽy~º5s0³oüãm¸rª-eôÀDÙÕì2º§×ñ]Xæ'G¡èTtq9tñËèb]Q fáÌ<ÇØ`êžn–êü«1h'Æ.áj•€=†ÚXg¨ÉõSÈœqvButCT6¤Šº[\˜†6ˆ½Oˆ< kq8Î! þ¸±ÿŽ}òÆWÏœÌTm/ÁcÛ3åÈ2îÈþ†ÅaÇË*°Rü½hÐÛbØÅ³WåæXC}u¬36Û»×ð áó3þ§†ˆÞl±²v7ˇŠ8°YFçX»Ž¡öÖ*Ž©“˜_4&|,¥a9 Ée&ØCH¤B·ð˰@Á‰ˆý€û­ŠX\ŠÈbE¬‚©¸ÂXH5‰AÓùÐW·iàÞRÅÜC‡–mÀ½×F'ºs—j*e5UQ€ÆoáØé÷õæ@Øäµƒ_Wf±ôA¼åv«ÑD£@—ò¾ªO*3ùŒê._Nû¡Ê]ª&·Q›È©1\+'(U>MЭä~P¦«YßVrbrëT[U¨<þꙿŸèëÚþh—+w<ÈŸ}æË‡Žv{l8ž –ÔŒ¬=ô§G÷÷?±ç,vU«¼ÝôŸ¡‡¹Næ rM_Ñæ),oó³.[[jkalw; ;çâÀl©wQ9€»¥´zíÀÅvòø)äîÊä3K,~<æŸùqKÜ;ú¦jò‚n¿Nª©bioÔ š/Z8‚…§uÿëü g7¤u7fì‡oÿ¾ýû5u¹“TéÑÙ’fÓ£ÚG%÷ÐtÕ¾_<Ñ•HæW÷﨨Ú#ñÝÌÓŸÿrÑ6yËĉG¬…&Õ5ö„£ûÄó Z]¹äiÏA±kÒé¯o¶5Û{ùµ¶û¸,— Ôæœ! H6§¸I]Òy'wX7ç¼û‚nÞy–œ5>cy…¤ácÚ’o³£tdz¬Ç ôhÔbÍÖ–Á®7âg[ÈCi/ÍÊrÞh’òòÝg§£Vå´e[O +œà¯vv:¬3¯V´ƒýa½Ïá<Ú?®q'‹ãtóÕ[㪞@ð¨ +à-Çê%A@û–ÍT¬gµýo5VŒú‡µó ÌôÈÍwÎåSã6ï/hö—Ç—x>Ïn×ç™Òºw/Ìä1zPU:Ú^È•bÕ-°žÜ¶Xl'÷ÄãLÅüÈB¨°»3f&ê\‘ ¿îCaî9!óŸÃÜ?VÝ#T’ìÉ|Ÿ!?ľU“‹Û¿øjÕÙêtõ«ÿ­Z¸Çz—'e=îá¼¾ Š“œ-¤/7{/–Ë%&rÑ!›M5Á–¡J°UUÎW²•ªêút)”¾ÆµØ\E®ydÇé̹Í«Y©´¦³GHÒã‡é’þë×ð·dL7§«¦âñ%/))w8Ì*N 17“þ±³FüŸ ?2Ýi4YŒn·»¼m}S÷þ°këz£Ñlq{òÊÚ×6öÎÏ|¿|õx{ÐjÕëÛ¢±¾Ã[÷¾PR^9Ý*Y-z}G4–¸kóÔó9òÕDѦ]Ü2ãt/†YMòѵ0Ï’A„ÛØ“dºíÖË¿N$¶€L!\ùò[Ð’ôëN’G²b$2bFw„ºÜ¯I‡€Ã¦+FÿF¼F° ^ÔߎñåX¶‚pžîSdËJ`¹b¼E‡|Æ—a¹Ðçb™ul/9ް¦Ç+‡ÈFÌÏbùkÑO¯ux½Ã¿ŽãÿIÌ{Ë8BB6ŠùúhðñšÄë^†—ËÞ„WÂ|ÞïñúÖß-» ÃÿÃmøœ‡¾Fó`Ù=X¯êr_ a,+ŒqßÄk çTOÈ[è¿LßOx–ôÁä)5/Ì·ƒÛ„xþ5ñÓ2ä­Çï¥Â„C!Ì Æ½{zE’b\Iܽ'Oöbq &cÔ3m¬¬ F‚&„4·žPÆoY`ˆÞ‚/¥ø¥Þ¸â“zé(l8>1¥ m÷B¡±Ê +zvI“ +‘º[TMBzÔÇ(B¢S#!Š ßK=”¶“ÉdÔ<%MMìU؉1úŒ¼(>·WñÜsÍ{Ë‹…;zFO¬Œ °©¸w¯H½©Ô Q9½qtelˆÞÇÆ° … '’©>ø!DáÀˆˆÏbŽ*p(ÒzÐ:iµ›–â4$¹OT R·´'µ/‰ ãO)døhèœß/_Î^%þ¸˜Ú4*…”΀46Ñ\È'©á£ç}²è»=¦²bÁž§¡uÁjËfËJ`z9N…Ôä^Æ+Ð7’ú±;(â.ßdTÂ:5ÓÛt3IíjÆdø7˜K™ÂöØ«z’){ †Ûi~…Û%1õG‚í/]ÿŸ·‡LäB„°ý„‚´—,w4Œ_‚•hT)/§D׃-ŠïØ¡ú*+îN3Š4gÑAô‘!ÄíÄXK5"?¢Íû`Z&“èQæ7Žj~‘Lι::¦0Ió½¥×f3¿³œ=)a?¾@õ•Ä¥è#Ë?›ÝíŒïiQÀýˆžÖâF¤ÛFÅx*™ÃíÀ¦Û|Z|ór\-®paÄT¿„]oxÛ( ÀNHñ½É>$5|GÅÙ3ʘ1 b¬ZößË%SϨ™–Å…µÿO¥uzìÀjˆ ÅžìÓîcÆPèfBæR[ÙruRZ¢·û[oóßözæ‹/ÌE˜MÛR)ãmq ¬R©„$&RÉÔD:;?)‰v)u™eGSsñäRó§³/=Pa%ö@Ke…DcR©©†7*2 +*ÐÔóà˜2“”ɨ’F§ñ! -ÄÚ”ìAˆ!Ý Ü¿qA†ûG¶^¶ãWæþM£ç`z’Ýc %7zY$DVCJ©G¤2HK罚>pY&d^åÔÕ¿+ D Ó/…Ù•f´0»ö ˆú zÎÕ®4§ÅÈK©9 ÓkaóZêU¹ÔzŒ±Ó˜—PD&€Fj D;âªIn‘[妓¡Ë˜1膼„i[œï@1°€e«Ái˜_h•—Õ’†s)ç1% ›_Ã7§ÉV„ÏÓ*¾ùV 6o=ßA°|õŽ)ºé/ñ%VR‚:¼P*PÇÒ]øÛ.%ᤄT-­]`6DUT7µVŠOa +zá¢ß*$NÑTí´…ÿl"X‘ˆŽ{já){ë’r>ôà/¥Üq»wϲ7A/ü †«4Áþ¬öͲ/ ÌŒE—“L(ó“b +;q íÉ-jæ5ôJ"a¯QæwMPG¢ß%aÀZ G'¡1,~WRô3¿k³q‘å')£·‰6ᣙ0­Ž2?$&ÇÄ$ lEB]q7~ë¥ J CZ}†p¬Bg"5‚y 6ÄX@Ñስ{bZ¢ä­Ð†Õ°¯Mk22ª@*%¥ÀW '01Q„H?uð7•&¦)²›r!ÓÚ_WÅ--—Bc˜„ «¸DÄaš¤·])ÊäŒ'£ˆ‰¼”#%®NaÏG¢ä"»¶$‘€E»˜Õ¦ž ‘ÐO}cX–Ц 1¿ú‹(¢ ãºð­õ7ÕëÕRÕož2´”D§þ8UO3FÒʵљ"÷#zeìUš[T˜M¹‘RËßO³–Lˆ!*iªŸS{ÂpÿÐJ’ß¡8†·±•DýCùPý☠ÇzÑ}•Ìtk‘D$!RL$&RJÊH9‰’ +RIª¨Ú‚ÔZRGH#i"ÍÔ,i%m¤t™ta=¤—ÄI‚¬!}¤Ÿ¬%dYO6A2D6’a2B6‘Íd ÙJFÉÙF¶“dœì$d’ì"Sdšì&w=d/ÙGö“r€$³dŽ"‡Ér'¹‹ÜMþ‚|š%÷{ÉgE§HígÅ1’Íò±uXõ±u¨ÿuèø¤@˜ì¯ñmÍø¦Møæ&Ä7_•ýMö·ÙpÔæ‰}3û[ 0½!{-ûoÄõõ“¦ù]ö_²ïfÿGöÙ?f?Ìþc³ÙŸaú;qog3Ùïe0üGÙw²ßÉ.fß&úìŸ0͘ç\ö|öµìÙì™ìÓÙ—²§³Oe¯f/£ûBö¹ìcÙ+Ùg¿‘ýjöËÙG1vc¾–}%û«ì¯¯6\í¾Z{µÝ:µgýÿþÇhN6„­ùqS@ ^rÀƒ:ЃŒ`3XÀ +6°C8À ùà7xÀ >ðC‚P…P"„ $(0D VA”CðSUP 1¨Z¨ƒzh€Fh‚fX -Ð +mÐôÓ*CtCôB°ú Ö¬ƒõ°a6Â0ŒÀ&Ø [èBJƒm°vÀ8| +v"Ÿ<“° ¦`úÿ>m€SØoõü¥ï>¤ºMH¿–঑^‡‘† Dhéû.¤ì ¤èOšë“¦Û‚~:NìŃ8’Õ íÇðÿæÿßý|¼à +endstream +endobj +159 0 obj +44058 +endobj +160 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Contents [161 0 R] +>> +endobj +161 0 obj +<< /Length 162 0 R /Filter /FlateDecode >> +stream +xœ½ZKŽä6 =AÝÁëãÑÇ–l `Wwíô &™E€ ¹ÿ"’LR$-UU7:Aà´Ç–)~¿ª¿/v0é?;Ø0®.Ý}ûqùy™ý¦aŠc Öዣþùóòý—´`»|½ÙiXÇ5 ÃÛw"ãì<šiˆÁŒÓ4¼ý¸˜Ñ¸´âÛð«1fJל®®˜®%]+<ÛÒµ§ëš.Ÿ®—t½Âý Ö]áJ÷6ý±éÖý6¼ýuy}K\áæó:ú0ØÉKa<ñ(7gÆçôé2DG€o;#ãn=t‰q†üÍÌÙý`ÔmǺòï „ÜA<·yÝÏoð•ß-Ç {Y|™’à»üMáÖçwn¯÷eÝ^¿Ï´ˆÎ Ïou_ây‘4óšL·ÐGã!­™Ý/°ÞWýïŒÿH¿ü{­ïPgù[*ý²ïÚÚ»BÙÕÍÑ`׉ìz{­Õ&d+ï€gx{åÕ‚Œù»ro%o(ñ¶1{3™ Ø8Ów¸÷KÕ1îeQï€ÃâDWöîZy/xƒý[GØD>€úÞ;tDÄÛËcl n—µbª¬Ã½oì=ǰâçiÙ›6·ÓèN1¨ˆì—û¹º‰‹ 2a 9V¢c7÷B©„t t|Ç SþÎð-šãÌz“ëÝ+šë'Î9¶'™Þþ2þdíï€C +Â+<}£ïNoÊ^÷°¶,̃€vf¸¹±ýyŒ»Kwåß[~× 'bÌÍœb`á âÅäØÁWXæšãÌJ Šndü‡*ÇÙŸÄ6¡7%\±I5\/) a,í3àÍ<< |+”…ŽÜrt&Hþž VhX…bà]¯ãA€PÎúRùh%±\·W0”äA¸Ð[:²ßñF +Ú]@DŸýìd«™Ñçvx©zyºÀ`AW´Q\´êÿÀ߸Ed «¢­(&6…Ÿ`j$œ21Ç R@Áê:àsÙÚ…e œ©ø{9}†€}­°iÎò4 x‹°æCš­YK³7Ö¹o£>¬U$l{²[Gz ¤7ƒå’ïœM:& ™Y”hÚóÐ|½%KœÃë’gÊlcfãGi²MéjÒì yÇ.Õõ»%Ï)Ï»ÙE®ó6§Ãûô­‘ßL±AØK5ÛyÊ Tþü9ø©mœNukΔê;î ¡ï ÍùíxÿÅçh÷½Œl-ÌÛÈÆ +þÔk´ÒÎKÏŒiÍÁ=4¬‘§ÖHà3ì¢ìß=;¸S)ðZ»ÄCgtRZw´ÉBÓNÅß…¢d¬4yi5ûX¦ô5Â’‘€|cη1ÚôMÃèÓ²ÖAx5z‹v¯Dó»ÈŒÇz“Ž'ôÄJ_ ü<»öÊòÆ™EóMCgh§f‡k®F&. IŒxPò ­®F¸^⥗‡=×ÉU8×õžÝcÌ#d°ûB£SåœÐ˜óÃ>ĪØß÷â„8#Œçuät8jÊa(‘ 5„ž8pv¤Kç]NcµœÄÉFN&8M,vÆ/€ÁØ|€)Ž`p¢uÇQ5˜Ú¥¨0è4Á‰<³¨;¨’õnMœõ œ’˜î, dE‡¬Î,ÊA'mêYëV͉]ãq¯ +3ZIÃRŸ_æš–…„Rc.ö°`ïÍ7#à…‡h.d¾*”V]Qò˜‰¦m¶ß8ìÕ…ûr÷ +-,Fʯ.3ìÎxØiÁ$Õƒ4f`‡\<á¬>0kÙDÂW Y²Šj•ƒÓ?:ÄÒSá¶N,îT½~cê`#`£w½ƒ†Ç1#I¢žŸü~‡÷$ƒªò–q™¤~ähàYYÙ>ZÎVò4-&ïS]Âäè7 +¶Uáщ(+ï È(&(Ýö´¢ŽOŒRvb˜†cxÌâÉX‘5óµ”Ñ?|à¥gKxQž£ž½züU,4U§¤{§çq½)®û½™ç}vwÅ‚ÿmÕ°ShMùXn"¢†m€@ÿ!*fÕ´AE^7ί§µj]ù²Æ8b™ó;±Ä¨iÚ²$nóvØD._ËdCêĽ74zå®9Çæû<í.k¡¼Îõ*Åqv|8Evï4rpíU®ó¥t+À"©úõíòûå_vS¨ +endstream +endobj +162 0 obj +2107 +endobj +163 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Annots 166 0 R +/Contents [164 0 R] +>> +endobj +164 0 obj +<< /Length 165 0 R /Filter /FlateDecode >> +stream +xœµYÛÎÛ6 ~‚¼ƒ¯Ô©ƒe`ãý€¼A·^ è€õf¯?I&EÊ‘ãäïŠÂ¨“HäÇÓGJÿ?Lú„qÆôöåÛáïÃé~ø|›‡yî_ë +ïG;åu÷o3‡iÁ—áWcŒKOOHÏ”ž˜žù·áþ×çÑ IÀý!mAW·ØôÓsJÏ™>_HÄ•>o‹ 1é¹fnäÞh/ËHûÀÐÿ°è$yI?¤u@ë!éƒ@z3ŽXô±œ/Ðn€ê8“-i?œH>½ƒkåÌS6 ‘ÓÚ`ËúÏ7ðë@ç ·&ÿÒû÷ƒa ¾ì6ù»N(M!ì+¯ëFÜZîù)[®÷”?ÞŽÁ .Ž..„1Äá“'¾ÿyøú‹$˜5 ³ÍK“žO9°ö çf™%"p*B=Ž"ªÌ‹’ljx]"}ïYïƒO’;ª`ö<\9nf˜sœ4Á4ÖeŸ0œêK{Y¼_r2Ð{©‘"Ó&U‘sž¶`\¡J®Wò³Ð©YÁÐæXÒG—1Ðr3:U_“”új1c\pA£®q¯S©ÔYZk¯TÇGª¯“¸f’yë#HÙŦkQ +HÊ:ÊÏÊ3x&I:Ò7-ØìQÕzþÌx,á ‚µØ¾Ç#Ťø¡‡Wp<ÇkJá^x ï‰~ÿß° +†§X}Œ#%‹™kEzô’ƒóhq‹êáH{Tðf¢Þ™à[Õ +Ôº\Ù4µžÏæ^:¦ äÖ²mŽðÇHFš +nª'q¿p”»º_QŸÊé^Œ£>ƒ¸¬EîoL]«þÇ”öíVN·O;Þù±H"^¤k1aÈ÷¸|sÏÓU,ÓØ­›CÖŽ1>ª?³hñYñ‰ßŸU®?…#zžãA-'5TÎb¾Â“èDæ-Æh©&½ª»5ŸGVr¾ØÅæ\›¥>ó>+û¹Å=Ç-ûsG÷0§Ô¹ŠÂŽ‘ ++ˆï‹-äïbCÔ>èa]¤ÆíUœ‹>A”­F°\†è9 Bm‰«²PYÖ´_.L£g&®NzÌu2PKµTðã>9ÂD›ê°ÃŽˆQ®Ï0„&sˆ |s_¥¡ÙòÉ«·{g›õ/º­÷Á™ +¡ÑÉôÚc_±ê‘}_Ù°\`®»ÙÖUËÒÞ¥]o“ôk}-wº\ó!¾ÉTB +{LµogφÔ+F$†ƒ:†¶Ò^, “B£¼ê.ÜÓo` +rYhª'þa…Ë­TW©Ò*zœ‰¹ß'k¦?'s~jÞ}Þ°Åjr•·Rz²ïL¬¯X j÷/ÁáøxÜ>FoêUrZµ×n”Ò¡0<Î(9ͼ­¸ Lw˜‚D5çÅA¨.Êø^"gX½t·]åZX£¼?\™Tµw|}SÝvt´ ÏA²×´%t&]|~> +endobj +168 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 643.90 535.50 637.65] /H /N /Border [0 0 0] /F 4 /Dest [473 0 R /XYZ 72 592.15 0 ] >> +endobj +169 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 632.65 535.50 625.65] /H /N /Border [0 0 0] /F 4 /Dest [476 0 R /XYZ 72 769.90 0 ] >> +endobj +170 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 620.65 535.50 614.40] /H /N /Border [0 0 0] /F 4 /Dest [476 0 R /XYZ 72 654.40 0 ] >> +endobj +171 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 609.40 535.50 603.15] /H /N /Border [0 0 0] /F 4 /Dest [476 0 R /XYZ 72 406.90 0 ] >> +endobj +172 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 598.15 535.50 591.15] /H /N /Border [0 0 0] /F 4 /Dest [476 0 R /XYZ 72 233.65 0 ] >> +endobj +173 0 obj +<< +/Type /Annot /Subtype /Link /Rect [144 573.90 535.50 547.40] /H /N /Border [0 0 0] /F 4 /Dest [491 0 R /XYZ 72 769.90 0 ] >> +endobj +174 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 554.65 535.50 548.40] /H /N /Border [0 0 0] /F 4 /Dest [491 0 R /XYZ 72 592.90 0 ] >> +endobj +175 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 543.40 535.50 536.40] /H /N /Border [0 0 0] /F 4 /Dest [491 0 R /XYZ 72 512.65 0 ] >> +endobj +176 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 531.40 535.50 525.15] /H /N /Border [0 0 0] /F 4 /Dest [491 0 R /XYZ 72 288.40 0 ] >> +endobj +177 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 520.15 535.50 513.90] /H /N /Border [0 0 0] /F 4 /Dest [494 0 R /XYZ 72 722.65 0 ] >> +endobj +178 0 obj +<< +/Type /Annot /Subtype /Link /Rect [144 496.65 535.50 469.40] /H /N /Border [0 0 0] /F 4 /Dest [499 0 R /XYZ 72 769.90 0 ] >> +endobj +179 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 476.65 535.50 470.40] /H /N /Border [0 0 0] /F 4 /Dest [499 0 R /XYZ 72 627.40 0 ] >> +endobj +180 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 465.40 535.50 458.40] /H /N /Border [0 0 0] /F 4 /Dest [502 0 R /XYZ 72 642.40 0 ] >> +endobj +181 0 obj +<< +/Type /Annot /Subtype /Link /Rect [144 441.15 535.50 414.65] /H /N /Border [0 0 0] /F 4 /Dest [511 0 R /XYZ 72 769.90 0 ] >> +endobj +182 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 421.90 535.50 415.65] /H /N /Border [0 0 0] /F 4 /Dest [511 0 R /XYZ 72 627.40 0 ] >> +endobj +183 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 410.65 535.50 403.65] /H /N /Border [0 0 0] /F 4 /Dest [511 0 R /XYZ 72 448.15 0 ] >> +endobj +184 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 398.65 535.50 392.40] /H /N /Border [0 0 0] /F 4 /Dest [516 0 R /XYZ 72 601.40 0 ] >> +endobj +185 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 387.40 535.50 381.15] /H /N /Border [0 0 0] /F 4 /Dest [516 0 R /XYZ 72 306.65 0 ] >> +endobj +186 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 376.15 535.50 369.15] /H /N /Border [0 0 0] /F 4 /Dest [524 0 R /XYZ 72 769.90 0 ] >> +endobj +187 0 obj +<< +/Type /Annot /Subtype /Link /Rect [144 351.90 535.50 325.40] /H /N /Border [0 0 0] /F 4 /Dest [535 0 R /XYZ 72 769.90 0 ] >> +endobj +188 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 332.65 535.50 326.40] /H /N /Border [0 0 0] /F 4 /Dest [535 0 R /XYZ 72 627.40 0 ] >> +endobj +189 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 321.40 535.50 314.40] /H /N /Border [0 0 0] /F 4 /Dest [538 0 R /XYZ 72 769.90 0 ] >> +endobj +190 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 309.40 535.50 303.15] /H /N /Border [0 0 0] /F 4 /Dest [541 0 R /XYZ 72 320.65 0 ] >> +endobj +191 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 298.15 535.50 291.90] /H /N /Border [0 0 0] /F 4 /Dest [544 0 R /XYZ 72 239.65 0 ] >> +endobj +192 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 286.90 535.50 279.90] /H /N /Border [0 0 0] /F 4 /Dest [549 0 R /XYZ 72 608.90 0 ] >> +endobj +193 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 274.90 535.50 268.65] /H /N /Border [0 0 0] /F 4 /Dest [549 0 R /XYZ 72 310.15 0 ] >> +endobj +194 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 263.65 535.50 257.40] /H /N /Border [0 0 0] /F 4 /Dest [555 0 R /XYZ 72 637.15 0 ] >> +endobj +195 0 obj +<< +/Type /Annot /Subtype /Link /Rect [144 240.15 535.50 212.90] /H /N /Border [0 0 0] /F 4 /Dest [558 0 R /XYZ 72 769.90 0 ] >> +endobj +196 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 220.15 535.50 213.90] /H /N /Border [0 0 0] /F 4 /Dest [558 0 R /XYZ 72 627.40 0 ] >> +endobj +197 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 208.90 535.50 202.65] /H /N /Border [0 0 0] /F 4 /Dest [558 0 R /XYZ 72 169.90 0 ] >> +endobj +198 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 197.65 535.50 190.65] /H /N /Border [0 0 0] /F 4 /Dest [561 0 R /XYZ 72 405.40 0 ] >> +endobj +199 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 185.65 535.50 179.40] /H /N /Border [0 0 0] /F 4 /Dest [566 0 R /XYZ 72 734.65 0 ] >> +endobj +200 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 174.40 535.50 168.15] /H /N /Border [0 0 0] /F 4 /Dest [566 0 R /XYZ 72 395.90 0 ] >> +endobj +201 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 163.15 535.50 156.15] /H /N /Border [0 0 0] /F 4 /Dest [569 0 R /XYZ 72 706.15 0 ] >> +endobj +202 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 151.15 535.50 144.90] /H /N /Border [0 0 0] /F 4 /Dest [576 0 R /XYZ 72 521.65 0 ] >> +endobj +203 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 139.90 535.50 133.65] /H /N /Border [0 0 0] /F 4 /Dest [582 0 R /XYZ 72 448.40 0 ] >> +endobj +204 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 128.65 535.50 121.65] /H /N /Border [0 0 0] /F 4 /Dest [587 0 R /XYZ 72 769.90 0 ] >> +endobj +205 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 116.65 535.50 110.40] /H /N /Border [0 0 0] /F 4 /Dest [587 0 R /XYZ 72 327.40 0 ] >> +endobj +206 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 105.40 535.50 99.15] /H /N /Border [0 0 0] /F 4 /Dest [590 0 R /XYZ 72 585.40 0 ] >> +endobj +207 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 94.15 535.50 87.15] /H /N /Border [0 0 0] /F 4 /Dest [593 0 R /XYZ 72 463.90 0 ] >> +endobj +208 0 obj +<< +/Type /Annot /Subtype /Link /Rect [528.75 651.15 535.50 636.65] /H /N /Border [0 0 0] /F 4 /Dest [473 0 R /XYZ 535.50 769.90 0 ] >> +endobj +209 0 obj +<< +/Type /Annot /Subtype /Link /Rect [530.25 643.90 535.50 637.65] /H /N /Border [0 0 0] /F 4 /Dest [473 0 R /XYZ 72 616.15 0 ] >> +endobj +210 0 obj +<< +/Type /Annot /Subtype /Link /Rect [530.25 632.65 535.50 625.65] /H /N /Border [0 0 0] /F 4 /Dest [476 0 R /XYZ 325.50 752.90 0 ] >> +endobj +211 0 obj +<< +/Type /Annot /Subtype /Link /Rect [530.25 620.65 535.50 614.40] /H /N /Border [0 0 0] /F 4 /Dest [476 0 R /XYZ 367.50 689.90 0 ] >> +endobj +212 0 obj +<< +/Type /Annot /Subtype /Link /Rect [530.25 609.40 535.50 603.15] /H /N /Border [0 0 0] /F 4 /Dest [476 0 R /XYZ 388.50 442.40 0 ] >> +endobj +213 0 obj +<< +/Type /Annot /Subtype /Link /Rect [530.25 598.15 535.50 591.15] /H /N /Border [0 0 0] /F 4 /Dest [476 0 R /XYZ 430.50 269.15 0 ] >> +endobj +214 0 obj +<< +/Type /Annot /Subtype /Link /Rect [528.75 573.90 535.50 547.40] /H /N /Border [0 0 0] /F 4 /Dest [491 0 R /XYZ 295.50 764.15 0 ] >> +endobj +215 0 obj +<< +/Type /Annot /Subtype /Link /Rect [530.25 554.65 535.50 548.40] /H /N /Border [0 0 0] /F 4 /Dest [491 0 R /XYZ 234.75 711.40 0 ] >> +endobj +216 0 obj +<< +/Type /Annot /Subtype /Link /Rect [530.25 543.40 535.50 536.40] /H /N /Border [0 0 0] /F 4 /Dest [491 0 R /XYZ 295.50 542.90 0 ] >> +endobj +217 0 obj +<< +/Type /Annot /Subtype /Link /Rect [530.25 531.40 535.50 525.15] /H /N /Border [0 0 0] /F 4 /Dest [491 0 R /XYZ 107.25 317.90 0 ] >> +endobj +218 0 obj +<< +/Type /Annot /Subtype /Link /Rect [530.25 520.15 535.50 513.90] /H /N /Border [0 0 0] /F 4 /Dest [494 0 R /XYZ 445.50 752.90 0 ] >> +endobj +219 0 obj +<< +/Type /Annot /Subtype /Link /Rect [528.75 496.65 535.50 469.40] /H /N /Border [0 0 0] /F 4 /Dest [499 0 R /XYZ 219.75 769.90 0 ] >> +endobj +220 0 obj +<< +/Type /Annot /Subtype /Link /Rect [530.25 476.65 535.50 470.40] /H /N /Border [0 0 0] /F 4 /Dest [499 0 R /XYZ 244.50 769.90 0 ] >> +endobj +221 0 obj +<< +/Type /Annot /Subtype /Link /Rect [530.25 465.40 535.50 458.40] /H /N /Border [0 0 0] /F 4 /Dest [502 0 R /XYZ 322.50 672.65 0 ] >> +endobj +222 0 obj +<< +/Type /Annot /Subtype /Link /Rect [528.75 441.15 535.50 414.65] /H /N /Border [0 0 0] /F 4 /Dest [511 0 R /XYZ 538.50 764.15 0 ] >> +endobj +223 0 obj +<< +/Type /Annot /Subtype /Link /Rect [530.25 421.90 535.50 415.65] /H /N /Border [0 0 0] /F 4 /Dest [511 0 R /XYZ 348.75 769.90 0 ] >> +endobj +224 0 obj +<< +/Type /Annot /Subtype /Link /Rect [530.25 410.65 535.50 403.65] /H /N /Border [0 0 0] /F 4 /Dest [511 0 R /XYZ 500.25 477.65 0 ] >> +endobj +225 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 398.65 535.50 392.40] /H /N /Border [0 0 0] /F 4 /Dest [516 0 R /XYZ 157.50 623.90 0 ] >> +endobj +226 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 387.40 535.50 381.15] /H /N /Border [0 0 0] /F 4 /Dest [516 0 R /XYZ 234.75 329.90 0 ] >> +endobj +227 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 376.15 535.50 369.15] /H /N /Border [0 0 0] /F 4 /Dest [524 0 R /XYZ 77.25 769.90 0 ] >> +endobj +228 0 obj +<< +/Type /Annot /Subtype /Link /Rect [522 351.90 535.50 325.40] /H /N /Border [0 0 0] /F 4 /Dest [535 0 R /XYZ 219.75 769.90 0 ] >> +endobj +229 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 332.65 535.50 326.40] /H /N /Border [0 0 0] /F 4 /Dest [535 0 R /XYZ 72 651.40 0 ] >> +endobj +230 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 321.40 535.50 314.40] /H /N /Border [0 0 0] /F 4 /Dest [538 0 R /XYZ 76.50 764.15 0 ] >> +endobj +231 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 309.40 535.50 303.15] /H /N /Border [0 0 0] /F 4 /Dest [541 0 R /XYZ 328.50 356.15 0 ] >> +endobj +232 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 298.15 535.50 291.90] /H /N /Border [0 0 0] /F 4 /Dest [544 0 R /XYZ 201 269.90 0 ] >> +endobj +233 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 286.90 535.50 279.90] /H /N /Border [0 0 0] /F 4 /Dest [549 0 R /XYZ 114.75 632.15 0 ] >> +endobj +234 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 274.90 535.50 268.65] /H /N /Border [0 0 0] /F 4 /Dest [549 0 R /XYZ 280.50 340.40 0 ] >> +endobj +235 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 263.65 535.50 257.40] /H /N /Border [0 0 0] /F 4 /Dest [555 0 R /XYZ 76.50 672.40 0 ] >> +endobj +236 0 obj +<< +/Type /Annot /Subtype /Link /Rect [522 240.15 535.50 212.90] /H /N /Border [0 0 0] /F 4 /Dest [558 0 R /XYZ 219.75 769.90 0 ] >> +endobj +237 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 220.15 535.50 213.90] /H /N /Border [0 0 0] /F 4 /Dest [558 0 R /XYZ 72 651.40 0 ] >> +endobj +238 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 208.90 535.50 202.65] /H /N /Border [0 0 0] /F 4 /Dest [558 0 R /XYZ 503.25 199.15 0 ] >> +endobj +239 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 197.65 535.50 190.65] /H /N /Border [0 0 0] /F 4 /Dest [561 0 R /XYZ 449.25 434.90 0 ] >> +endobj +240 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 185.65 535.50 179.40] /H /N /Border [0 0 0] /F 4 /Dest [566 0 R /XYZ 472.50 770.15 0 ] >> +endobj +241 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 174.40 535.50 168.15] /H /N /Border [0 0 0] /F 4 /Dest [566 0 R /XYZ 207.75 419.15 0 ] >> +endobj +242 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 163.15 535.50 156.15] /H /N /Border [0 0 0] /F 4 /Dest [569 0 R /XYZ 297 735.65 0 ] >> +endobj +243 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 151.15 535.50 144.90] /H /N /Border [0 0 0] /F 4 /Dest [576 0 R /XYZ 488.25 551.15 0 ] >> +endobj +244 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 139.90 535.50 133.65] /H /N /Border [0 0 0] /F 4 /Dest [582 0 R /XYZ 230.25 470.90 0 ] >> +endobj +245 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 128.65 535.50 121.65] /H /N /Border [0 0 0] /F 4 /Dest [587 0 R /XYZ 312.75 764.15 0 ] >> +endobj +246 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 116.65 535.50 110.40] /H /N /Border [0 0 0] /F 4 /Dest [587 0 R /XYZ 225 369.40 0 ] >> +endobj +247 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 105.40 535.50 99.15] /H /N /Border [0 0 0] /F 4 /Dest [590 0 R /XYZ 119.25 614.90 0 ] >> +endobj +248 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 94.15 535.50 87.15] /H /N /Border [0 0 0] /F 4 /Dest [593 0 R /XYZ 374.25 493.40 0 ] >> +endobj +249 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Annots 252 0 R +/Contents [250 0 R] +>> +endobj +250 0 obj +<< /Length 251 0 R /Filter /FlateDecode >> +stream +xœÍZÛŽã6 ý‚üƒŸ ¬WwÛ@Q ÉLÞ Ìl»¶@÷¥¿_‘%R¦§3½`0˜x"‘G‡ERþãd“ì`Ó¸¸üéË·Óï§ËÛéóm–axûZGÄ8šyðŒ{ûv2£±0àËð£1&cÍOÃÛouxrct{Ã=üâðÏ7;Eicâ3­þ<åÏßO¦êÃÉþ·E:ÙqJU×áiìÖåh´½æÑð›òçKþ;·Ï6)ÞÅ1!'T9&¬Á\39 Îwˆ,áí—!OqA=çßKÏ/EÄkyޛ欿É5’€[™K2f0_ùkW}Öy°TË]Ç[0u*zÇŒú^ß²ßD?¦0„y óRÓ<|2ãä†ï¿ž¾þ@ŽeͰŒK&³ËÞ5%“Š&Âì2»ä¿iÕmóZÝ¥¬9cr¯~¤Y¢™A¢œªyazã HXF›H8 + dÁ3þõë÷–H¿ƒ¾”ñS!Æåïü¡.€:²€ìˆÙem‚+ndZ½Ì%¹ÜаÐâ 8§LcÐ[Ê\X(ÈBy—Ž®³“OóÑÛöfÄÅ7Ž eÞÔÖ‡›5²yþï…8P‰æÄ ¢ƒ•D'D»4:ß¶/XÀ`Ùºm +¨Jú™QqwËÛ[nŸŸËÿ˜<7 ì°À…QjüHÃÝô>ÊØy}v³Šé;`¤´Ø¶ý] Ë7ºíê/ óú»Û¾ÃmË3þ^5ìÌð³a±ÈsðÚà¤ûP¶@wÞ‚…™p2wã&çDeЗÈ–=‡'ÅÂöé¹4• .X°a_T6òÉÖ›{† ´° ÈÌ*0®¨ËGžÚHqjû”]×Úý¥¨L‹/0ä½_µãùij~yl_ Gb‹lQeÕ´+”' 5X˃]Mˆ.%è|F¦S@ìR`òXçXð±â(.ºI/îÕâ$–мr t6“Úšð¹Ø øí÷wƒ.ÏE“5µÀ;-"“ôm¾Ö·_µÆäí¸Yè& ,.9#¯Y`Zv¬/˜o±$(]ÃNç+˜’ +¹ îºÔˆçY7%ý ´æXtkŽ£wRAˆu·`"D厖ý®Ž3Õ>m6&­¹æK,ã´gfܹEÿZ¢ËnÎ#K[½j›.æmV’KžáR›Ùs`ÏTYQL¾°ñ‘-ŠG§Ìåß÷úúݾ§ÇM*)|‘GH‰ +ÀÞ»– F¹Á€f!¹­N= ~ü¾«¹®¿}üðÌŠ˜ê‡]ùŽ0+ÂëP+ÜEAЪuPZ –·>Èñ8Öö ÊÑè®|¯FRðqX#é„qŽæýX¤–PG`˜JÚc©‘Á³›yŠÃM¥8ž%ޏcÑa¬Õ’OðË1ãçkC‰s“gK¬Üá›ñw„ngÙ¹DÜmÄ—ØZ;ëY"ÒÐ2òÐÖ/ê㳩‡=·Mïcd'âÇðôØ2îh£ŸK®Nu=K¨†óŠŒw9å$Éj ;ôÓ Ù{GÄA,ÊZjˆo ²žŽ‘y¥K -.&§=Š?ˆF®ì‘ßÌÖ•m¯Ìͦ9¼[¶Ü6~:=ÿ¥ŸEíFøA]–.­‹ÿjÄK\ ¸É°}• ¿êo’»û|# JÛ‹ϵ„m¥ûy…ÍǼ Ô k±Ä—76×¢ÏÍ#õ¿°qÖº6ST“Ò…‹)&Yýk­xú6›Dûlj†5JÐþPƶ½ÂÆZôÜmŠE¶Û«EÛ«ÔÆ fònsI7 +&Œ¢¿"—=n“JSï‚Þ:}pAóњ­Rïã\ÆR˜ìæïeĆ>S?q{t•×X,DŠíYT·Ì‡cãúdÕ°ò×·Óϧ¿+Qž +endstream +endobj +251 0 obj +2290 +endobj +252 0 obj +[ +253 0 R 254 0 R 255 0 R 256 0 R 257 0 R 258 0 R 259 0 R 260 0 R 261 0 R 262 0 R 263 0 R 264 0 R 265 0 R 266 0 R 267 0 R 268 0 R 269 0 R 270 0 R 271 0 R 272 0 R 273 0 R 274 0 R 275 0 R 276 0 R 277 0 R 278 0 R 279 0 R 280 0 R 281 0 R 282 0 R 283 0 R 284 0 R 285 0 R 286 0 R 287 0 R 288 0 R 289 0 R 290 0 R 291 0 R 292 0 R 293 0 R 294 0 R 295 0 R 296 0 R 297 0 R 298 0 R 299 0 R 300 0 R 301 0 R 302 0 R 303 0 R 304 0 R 305 0 R 306 0 R 307 0 R 308 0 R 309 0 R 310 0 R 311 0 R 312 0 R 313 0 R 314 0 R 315 0 R 316 0 R 317 0 R 318 0 R 319 0 R 320 0 R 321 0 R 322 0 R 323 0 R 324 0 R 325 0 R 326 0 R 327 0 R 328 0 R 329 0 R 330 0 R 331 0 R 332 0 R 333 0 R 334 0 R 335 0 R 336 0 R 337 0 R 338 0 R 339 0 R 340 0 R 341 0 R 342 0 R 343 0 R 344 0 R 345 0 R 346 0 R 347 0 R 348 0 R 349 0 R 350 0 R 351 0 R 352 0 R 353 0 R 354 0 R 355 0 R 356 0 R 357 0 R 358 0 R +] +endobj +253 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 769.90 535.50 763.65] /H /N /Border [0 0 0] /F 4 /Dest [593 0 R /XYZ 72 407.15 0 ] >> +endobj +254 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 758.65 535.50 751.65] /H /N /Border [0 0 0] /F 4 /Dest [593 0 R /XYZ 72 281.90 0 ] >> +endobj +255 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 746.65 535.50 740.40] /H /N /Border [0 0 0] /F 4 /Dest [598 0 R /XYZ 72 770.15 0 ] >> +endobj +256 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 735.40 535.50 729.15] /H /N /Border [0 0 0] /F 4 /Dest [598 0 R /XYZ 72 633.40 0 ] >> +endobj +257 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 724.15 535.50 717.15] /H /N /Border [0 0 0] /F 4 /Dest [598 0 R /XYZ 72 590.90 0 ] >> +endobj +258 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 712.15 535.50 705.90] /H /N /Border [0 0 0] /F 4 /Dest [598 0 R /XYZ 72 463.40 0 ] >> +endobj +259 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 700.90 535.50 694.65] /H /N /Border [0 0 0] /F 4 /Dest [598 0 R /XYZ 72 325.15 0 ] >> +endobj +260 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 689.65 535.50 682.65] /H /N /Border [0 0 0] /F 4 /Dest [603 0 R /XYZ 72 769.90 0 ] >> +endobj +261 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 677.65 535.50 671.40] /H /N /Border [0 0 0] /F 4 /Dest [609 0 R /XYZ 72 704.65 0 ] >> +endobj +262 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 666.40 535.50 660.15] /H /N /Border [0 0 0] /F 4 /Dest [609 0 R /XYZ 72 452.90 0 ] >> +endobj +263 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 655.15 535.50 648.15] /H /N /Border [0 0 0] /F 4 /Dest [614 0 R /XYZ 72 555.65 0 ] >> +endobj +264 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 643.15 535.50 636.90] /H /N /Border [0 0 0] /F 4 /Dest [617 0 R /XYZ 72 475.40 0 ] >> +endobj +265 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 631.90 535.50 625.65] /H /N /Border [0 0 0] /F 4 /Dest [617 0 R /XYZ 72 283.15 0 ] >> +endobj +266 0 obj +<< +/Type /Annot /Subtype /Link /Rect [144 608.40 535.50 581.15] /H /N /Border [0 0 0] /F 4 /Dest [622 0 R /XYZ 72 769.90 0 ] >> +endobj +267 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 588.40 535.50 582.15] /H /N /Border [0 0 0] /F 4 /Dest [622 0 R /XYZ 72 627.40 0 ] >> +endobj +268 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 577.15 535.50 570.90] /H /N /Border [0 0 0] /F 4 /Dest [622 0 R /XYZ 72 514.40 0 ] >> +endobj +269 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 565.90 535.50 558.90] /H /N /Border [0 0 0] /F 4 /Dest [622 0 R /XYZ 72 452.15 0 ] >> +endobj +270 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 553.90 535.50 547.65] /H /N /Border [0 0 0] /F 4 /Dest [622 0 R /XYZ 72 378.65 0 ] >> +endobj +271 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 542.65 535.50 536.40] /H /N /Border [0 0 0] /F 4 /Dest [622 0 R /XYZ 72 242.15 0 ] >> +endobj +272 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 531.40 535.50 524.40] /H /N /Border [0 0 0] /F 4 /Dest [627 0 R /XYZ 72 770.15 0 ] >> +endobj +273 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 519.40 535.50 513.15] /H /N /Border [0 0 0] /F 4 /Dest [627 0 R /XYZ 72 674.15 0 ] >> +endobj +274 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 508.15 535.50 501.90] /H /N /Border [0 0 0] /F 4 /Dest [627 0 R /XYZ 72 577.40 0 ] >> +endobj +275 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 496.90 535.50 489.90] /H /N /Border [0 0 0] /F 4 /Dest [627 0 R /XYZ 72 481.40 0 ] >> +endobj +276 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 484.90 535.50 478.65] /H /N /Border [0 0 0] /F 4 /Dest [627 0 R /XYZ 72 419.15 0 ] >> +endobj +277 0 obj +<< +/Type /Annot /Subtype /Link /Rect [144 461.40 535.50 434.90] /H /N /Border [0 0 0] /F 4 /Dest [632 0 R /XYZ 72 769.90 0 ] >> +endobj +278 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 442.15 535.50 435.15] /H /N /Border [0 0 0] /F 4 /Dest [632 0 R /XYZ 72 627.40 0 ] >> +endobj +279 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 430.15 535.50 423.90] /H /N /Border [0 0 0] /F 4 /Dest [632 0 R /XYZ 72 420.40 0 ] >> +endobj +280 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 418.90 535.50 412.65] /H /N /Border [0 0 0] /F 4 /Dest [635 0 R /XYZ 72 671.65 0 ] >> +endobj +281 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 407.65 535.50 400.65] /H /N /Border [0 0 0] /F 4 /Dest [635 0 R /XYZ 72 300.65 0 ] >> +endobj +282 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 395.65 535.50 389.40] /H /N /Border [0 0 0] /F 4 /Dest [640 0 R /XYZ 72 770.15 0 ] >> +endobj +283 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 384.40 535.50 378.15] /H /N /Border [0 0 0] /F 4 /Dest [643 0 R /XYZ 72 770.15 0 ] >> +endobj +284 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 373.15 535.50 366.15] /H /N /Border [0 0 0] /F 4 /Dest [643 0 R /XYZ 72 460.40 0 ] >> +endobj +285 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 361.15 535.50 354.90] /H /N /Border [0 0 0] /F 4 /Dest [643 0 R /XYZ 72 346.40 0 ] >> +endobj +286 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 349.90 535.50 343.65] /H /N /Border [0 0 0] /F 4 /Dest [648 0 R /XYZ 72 718.40 0 ] >> +endobj +287 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 338.65 535.50 331.65] /H /N /Border [0 0 0] /F 4 /Dest [648 0 R /XYZ 72 482.65 0 ] >> +endobj +288 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 326.65 535.50 320.40] /H /N /Border [0 0 0] /F 4 /Dest [654 0 R /XYZ 72 560.65 0 ] >> +endobj +289 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 315.40 535.50 309.15] /H /N /Border [0 0 0] /F 4 /Dest [654 0 R /XYZ 72 337.40 0 ] >> +endobj +290 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 304.15 535.50 297.15] /H /N /Border [0 0 0] /F 4 /Dest [659 0 R /XYZ 72 439.40 0 ] >> +endobj +291 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 292.15 535.50 285.90] /H /N /Border [0 0 0] /F 4 /Dest [659 0 R /XYZ 72 248.90 0 ] >> +endobj +292 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 280.90 535.50 274.65] /H /N /Border [0 0 0] /F 4 /Dest [664 0 R /XYZ 72 769.90 0 ] >> +endobj +293 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 269.65 535.50 262.65] /H /N /Border [0 0 0] /F 4 /Dest [664 0 R /XYZ 72 372.40 0 ] >> +endobj +294 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 257.65 535.50 251.40] /H /N /Border [0 0 0] /F 4 /Dest [674 0 R /XYZ 72 304.90 0 ] >> +endobj +295 0 obj +<< +/Type /Annot /Subtype /Link /Rect [144 234.15 535.50 207.65] /H /N /Border [0 0 0] /F 4 /Dest [688 0 R /XYZ 72 769.90 0 ] >> +endobj +296 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 214.90 535.50 207.90] /H /N /Border [0 0 0] /F 4 /Dest [688 0 R /XYZ 72 627.40 0 ] >> +endobj +297 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 202.90 535.50 196.65] /H /N /Border [0 0 0] /F 4 /Dest [688 0 R /XYZ 72 494.15 0 ] >> +endobj +298 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 191.65 535.50 185.40] /H /N /Border [0 0 0] /F 4 /Dest [688 0 R /XYZ 72 425.90 0 ] >> +endobj +299 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 180.40 535.50 173.40] /H /N /Border [0 0 0] /F 4 /Dest [688 0 R /XYZ 72 358.40 0 ] >> +endobj +300 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 168.40 535.50 162.15] /H /N /Border [0 0 0] /F 4 /Dest [688 0 R /XYZ 72 256.40 0 ] >> +endobj +301 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 157.15 535.50 150.90] /H /N /Border [0 0 0] /F 4 /Dest [688 0 R /XYZ 72 165.65 0 ] >> +endobj +302 0 obj +<< +/Type /Annot /Subtype /Link /Rect [144 133.65 535.50 106.40] /H /N /Border [0 0 0] /F 4 /Dest [694 0 R /XYZ 72 734.65 0 ] >> +endobj +303 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 113.65 535.50 107.40] /H /N /Border [0 0 0] /F 4 /Dest [694 0 R /XYZ 72 592.15 0 ] >> +endobj +304 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 102.40 535.50 95.40] /H /N /Border [0 0 0] /F 4 /Dest [694 0 R /XYZ 72 373.90 0 ] >> +endobj +305 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 90.40 535.50 84.15] /H /N /Border [0 0 0] /F 4 /Dest [699 0 R /XYZ 72 665.65 0 ] >> +endobj +306 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 769.90 535.50 763.65] /H /N /Border [0 0 0] /F 4 /Dest [593 0 R /XYZ 152.25 432.65 0 ] >> +endobj +307 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 758.65 535.50 751.65] /H /N /Border [0 0 0] /F 4 /Dest [593 0 R /XYZ 277.50 304.40 0 ] >> +endobj +308 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 746.65 535.50 740.40] /H /N /Border [0 0 0] /F 4 /Dest [598 0 R /XYZ 454.50 764.15 0 ] >> +endobj +309 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 735.40 535.50 729.15] /H /N /Border [0 0 0] /F 4 /Dest [598 0 R /XYZ 371.25 662.90 0 ] >> +endobj +310 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 724.15 535.50 717.15] /H /N /Border [0 0 0] /F 4 /Dest [598 0 R /XYZ 210 633.40 0 ] >> +endobj +311 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 712.15 535.50 705.90] /H /N /Border [0 0 0] /F 4 /Dest [598 0 R /XYZ 204 485.90 0 ] >> +endobj +312 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 700.90 535.50 694.65] /H /N /Border [0 0 0] /F 4 /Dest [598 0 R /XYZ 408 355.40 0 ] >> +endobj +313 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 689.65 535.50 682.65] /H /N /Border [0 0 0] /F 4 /Dest [603 0 R /XYZ 492 764.15 0 ] >> +endobj +314 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 677.65 535.50 671.40] /H /N /Border [0 0 0] /F 4 /Dest [609 0 R /XYZ 190.50 746.65 0 ] >> +endobj +315 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 666.40 535.50 660.15] /H /N /Border [0 0 0] /F 4 /Dest [609 0 R /XYZ 147 476.15 0 ] >> +endobj +316 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 655.15 535.50 648.15] /H /N /Border [0 0 0] /F 4 /Dest [614 0 R /XYZ 522 571.90 0 ] >> +endobj +317 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 643.15 535.50 636.90] /H /N /Border [0 0 0] /F 4 /Dest [617 0 R /XYZ 340.50 503.90 0 ] >> +endobj +318 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 631.90 535.50 625.65] /H /N /Border [0 0 0] /F 4 /Dest [617 0 R /XYZ 146.25 312.65 0 ] >> +endobj +319 0 obj +<< +/Type /Annot /Subtype /Link /Rect [522 608.40 535.50 581.15] /H /N /Border [0 0 0] /F 4 /Dest [622 0 R /XYZ 219.75 769.90 0 ] >> +endobj +320 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 588.40 535.50 582.15] /H /N /Border [0 0 0] /F 4 /Dest [622 0 R /XYZ 72 651.40 0 ] >> +endobj +321 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 577.15 535.50 570.90] /H /N /Border [0 0 0] /F 4 /Dest [622 0 R /XYZ 352.50 536.90 0 ] >> +endobj +322 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 565.90 535.50 558.90] /H /N /Border [0 0 0] /F 4 /Dest [622 0 R /XYZ 475.50 474.65 0 ] >> +endobj +323 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 553.90 535.50 547.65] /H /N /Border [0 0 0] /F 4 /Dest [622 0 R /XYZ 339 401.90 0 ] >> +endobj +324 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 542.65 535.50 536.40] /H /N /Border [0 0 0] /F 4 /Dest [622 0 R /XYZ 417.75 265.40 0 ] >> +endobj +325 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 531.40 535.50 524.40] /H /N /Border [0 0 0] /F 4 /Dest [627 0 R /XYZ 361.50 764.15 0 ] >> +endobj +326 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 519.40 535.50 513.15] /H /N /Border [0 0 0] /F 4 /Dest [627 0 R /XYZ 408.75 696.65 0 ] >> +endobj +327 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 508.15 535.50 501.90] /H /N /Border [0 0 0] /F 4 /Dest [627 0 R /XYZ 141.75 599.90 0 ] >> +endobj +328 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 496.90 535.50 489.90] /H /N /Border [0 0 0] /F 4 /Dest [627 0 R /XYZ 357 503.90 0 ] >> +endobj +329 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 484.90 535.50 478.65] /H /N /Border [0 0 0] /F 4 /Dest [627 0 R /XYZ 381 441.65 0 ] >> +endobj +330 0 obj +<< +/Type /Annot /Subtype /Link /Rect [522 461.40 535.50 434.90] /H /N /Border [0 0 0] /F 4 /Dest [632 0 R /XYZ 219.75 769.90 0 ] >> +endobj +331 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 442.15 535.50 435.15] /H /N /Border [0 0 0] /F 4 /Dest [632 0 R /XYZ 72 651.40 0 ] >> +endobj +332 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 430.15 535.50 423.90] /H /N /Border [0 0 0] /F 4 /Dest [632 0 R /XYZ 484.50 455.90 0 ] >> +endobj +333 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 418.90 535.50 412.65] /H /N /Border [0 0 0] /F 4 /Dest [635 0 R /XYZ 465.75 701.15 0 ] >> +endobj +334 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 407.65 535.50 400.65] /H /N /Border [0 0 0] /F 4 /Dest [635 0 R /XYZ 180.75 336.40 0 ] >> +endobj +335 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 395.65 535.50 389.40] /H /N /Border [0 0 0] /F 4 /Dest [640 0 R /XYZ 76.50 764.15 0 ] >> +endobj +336 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 384.40 535.50 378.15] /H /N /Border [0 0 0] /F 4 /Dest [643 0 R /XYZ 420.75 764.15 0 ] >> +endobj +337 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 373.15 535.50 366.15] /H /N /Border [0 0 0] /F 4 /Dest [643 0 R /XYZ 372 482.90 0 ] >> +endobj +338 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 361.15 535.50 354.90] /H /N /Border [0 0 0] /F 4 /Dest [643 0 R /XYZ 537 368.90 0 ] >> +endobj +339 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 349.90 535.50 343.65] /H /N /Border [0 0 0] /F 4 /Dest [648 0 R /XYZ 201.75 741.65 0 ] >> +endobj +340 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 338.65 535.50 331.65] /H /N /Border [0 0 0] /F 4 /Dest [648 0 R /XYZ 416.25 512.90 0 ] >> +endobj +341 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 326.65 535.50 320.40] /H /N /Border [0 0 0] /F 4 /Dest [654 0 R /XYZ 197.25 601.90 0 ] >> +endobj +342 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 315.40 535.50 309.15] /H /N /Border [0 0 0] /F 4 /Dest [654 0 R /XYZ 459.75 360.65 0 ] >> +endobj +343 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 304.15 535.50 297.15] /H /N /Border [0 0 0] /F 4 /Dest [659 0 R /XYZ 521.25 455.65 0 ] >> +endobj +344 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 292.15 535.50 285.90] /H /N /Border [0 0 0] /F 4 /Dest [659 0 R /XYZ 340.50 277.40 0 ] >> +endobj +345 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 280.90 535.50 274.65] /H /N /Border [0 0 0] /F 4 /Dest [664 0 R /XYZ 146.25 764.15 0 ] >> +endobj +346 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 269.65 535.50 262.65] /H /N /Border [0 0 0] /F 4 /Dest [664 0 R /XYZ 419.25 402.65 0 ] >> +endobj +347 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 257.65 535.50 251.40] /H /N /Border [0 0 0] /F 4 /Dest [674 0 R /XYZ 117 340.90 0 ] >> +endobj +348 0 obj +<< +/Type /Annot /Subtype /Link /Rect [522 234.15 535.50 207.65] /H /N /Border [0 0 0] /F 4 /Dest [688 0 R /XYZ 219.75 769.90 0 ] >> +endobj +349 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 214.90 535.50 207.90] /H /N /Border [0 0 0] /F 4 /Dest [688 0 R /XYZ 355.50 769.90 0 ] >> +endobj +350 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 202.90 535.50 196.65] /H /N /Border [0 0 0] /F 4 /Dest [688 0 R /XYZ 522.75 522.40 0 ] >> +endobj +351 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 191.65 535.50 185.40] /H /N /Border [0 0 0] /F 4 /Dest [688 0 R /XYZ 483.75 454.90 0 ] >> +endobj +352 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 180.40 535.50 173.40] /H /N /Border [0 0 0] /F 4 /Dest [688 0 R /XYZ 223.50 387.40 0 ] >> +endobj +353 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 168.40 535.50 162.15] /H /N /Border [0 0 0] /F 4 /Dest [688 0 R /XYZ 327.75 285.40 0 ] >> +endobj +354 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 157.15 535.50 150.90] /H /N /Border [0 0 0] /F 4 /Dest [688 0 R /XYZ 527.25 194.65 0 ] >> +endobj +355 0 obj +<< +/Type /Annot /Subtype /Link /Rect [522 133.65 535.50 106.40] /H /N /Border [0 0 0] /F 4 /Dest [694 0 R /XYZ 76.50 769.90 0 ] >> +endobj +356 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 113.65 535.50 107.40] /H /N /Border [0 0 0] /F 4 /Dest [694 0 R /XYZ 330.75 734.65 0 ] >> +endobj +357 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 102.40 535.50 95.40] /H /N /Border [0 0 0] /F 4 /Dest [694 0 R /XYZ 386.25 403.40 0 ] >> +endobj +358 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 90.40 535.50 84.15] /H /N /Border [0 0 0] /F 4 /Dest [699 0 R /XYZ 522 695.15 0 ] >> +endobj +359 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Annots 362 0 R +/Contents [360 0 R] +>> +endobj +360 0 obj +<< /Length 361 0 R /Filter /FlateDecode >> +stream +xœ½ZÉŽã6ýÿƒÏZÃâ&´íö=@ÿÁ$s02—ü~HªŠU%S²ºí †íi.¯¶W‹üÏŽ&ÿƒ#Ä!Ùüéë÷Ã߇ÓûáË5Óñøþ­­a0ÓÑeÝû÷ƒŒ·yÁ×ã¯ÆŸ_!¿b~ù5åWúíøþ×Á¦ÁóïóëÛ—_¯ùuʯ3~¿àoø}ýØ8åûù\“Ô¹WÜKgä}`ðæûÀâyù~Èë×C¾"Þ[pLõ>Ò‚fð^©šàŒ²äýpÂóñ3x}NJCˆú-ƒ«ë¿\!, aüà•%2‚ùóƒ¡BÝmÊÿuLi¦!N÷/oëÁ £ëI^S—½½gŸ nˆþè§ÍÇXÎ1e×?ß~!§sLCŠ + dUdϳfó&„šN_ÙNš=Ï~)öh¿í|šmW$ Ïå‹ìk–lµˆ³JˆH\ö'¸¨õÚ§"ÛtÜjxr°„^„xe!H0÷Šë"¾Ÿðo£æÚ-Aì ™mµô^oñ¢Ä n¨@@+`äá›`¢«`l,­wÍ Ý 5Él3›¸"i {ÍMèy˜¼¨«QºÀÀ÷×›Æ[ÕtY P+´^|ê^,Ús±qƒ½u©‹ök Ÿ¾ˆx€ÏLj½ +žÕ¸ì4Á +\¤sM6åx>³ÊE{³¥«PºªgíÐ\L ($)“½bZoÕÕR E¢GÚŽì5(F( úe>©hŽ Só‰¥ürE -¤Dâ¼§ `gæ²TOqJZs#æ•t¬¡/xØŽU‰1 SÝú¢"Ìbâ´vhçál1z/Á“Å'ïŒLà¾X·‘?ù…(apVà)pZ^(§ÙåÈ^ZAŸÈ)É!9Bˆ2­ªT)a]“˜˜Lf3©Ò$‘0{·TE!Ö7‘¦Mo]çvq˜ˆ¿Ló/°äȼp`kĨÞĆRÍë§Q%êšïæMSaÛN@T­‘ç"’Ó‡µº*¸)Мc.oZ!”šùkõ8ÄSñF¨F‹Ôk:(P‡3'•PnÜB „7Õ…̇&–¹××÷fgj¹«a)Ô ;ü×çj–»ö<7ä Õ¨dä8?kÏ]z”TþþY&m'jébO:;ML<<¥*µTIý¥y)BzŸ—Œ[ʆò·’ŒžK4 +ŒvÆ. Ú1 +œTÔøËÿ^‚Ù>ænC邨ƒ,QÀ:ô °þßeÞSÖÕghøù±|¤Àõ„Y/l.ÐGÚjZF—»éá0• 5[ãƒãÚ´Œøý ý¶Ju¡(!¼(£7Jk-?‰„ºæ­ŽÎácCù0ª¯Oy ë³<ˆ +wô IL¸«wTÝ NÛôô̺[×™:t¡³é¾Î`œp ð¢~}°|JW?¿6¥¸¬„iñÔÃ.Û…ª/¾`©/èN wR·‡åsè6åpØØP Ðèéql¶ïV‘òÞ=0ƒx˜cïvNô7­ 8ÝÁOíµc}܈ޟè€÷ÌÌî¯OS/†GøI€ŠÚaDÓÕÍæ}°±´uÄQK}y +p dp ±:×õ€}5zóíŸh R Õ­>À¤ÞÓ¡ +õdËHP=!Ö¹zò¥¤#ZäøŽœï,òKÅ5ÍX€~¸¦ý0 °‹-²¨µ‹|Ùç÷ä–Þ-ýhé÷Ãú“ÅC +endstream +endobj +361 0 obj +1904 +endobj +362 0 obj +[ +363 0 R 364 0 R 365 0 R 366 0 R 367 0 R 368 0 R 369 0 R 370 0 R 371 0 R 372 0 R 373 0 R 374 0 R 375 0 R 376 0 R 377 0 R 378 0 R 379 0 R 380 0 R 381 0 R 382 0 R 383 0 R 384 0 R 385 0 R 386 0 R 387 0 R 388 0 R 389 0 R 390 0 R 391 0 R 392 0 R 393 0 R 394 0 R 395 0 R 396 0 R 397 0 R 398 0 R 399 0 R 400 0 R 401 0 R 402 0 R 403 0 R 404 0 R 405 0 R 406 0 R 407 0 R 408 0 R 409 0 R 410 0 R 411 0 R 412 0 R 413 0 R 414 0 R 415 0 R 416 0 R 417 0 R 418 0 R 419 0 R 420 0 R 421 0 R 422 0 R 423 0 R 424 0 R 425 0 R 426 0 R 427 0 R 428 0 R 429 0 R 430 0 R 431 0 R 432 0 R 433 0 R 434 0 R 435 0 R 436 0 R 437 0 R 438 0 R 439 0 R 440 0 R 441 0 R 442 0 R 443 0 R 444 0 R 445 0 R 446 0 R 447 0 R 448 0 R 449 0 R 450 0 R 451 0 R 452 0 R 453 0 R 454 0 R 455 0 R 456 0 R 457 0 R 458 0 R +] +endobj +363 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 769.90 535.50 763.65] /H /N /Border [0 0 0] /F 4 /Dest [699 0 R /XYZ 72 623.15 0 ] >> +endobj +364 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 758.65 535.50 751.65] /H /N /Border [0 0 0] /F 4 /Dest [699 0 R /XYZ 72 483.65 0 ] >> +endobj +365 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 746.65 535.50 740.40] /H /N /Border [0 0 0] /F 4 /Dest [699 0 R /XYZ 72 174.65 0 ] >> +endobj +366 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 735.40 535.50 729.15] /H /N /Border [0 0 0] /F 4 /Dest [702 0 R /XYZ 72 670.90 0 ] >> +endobj +367 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 724.15 535.50 717.15] /H /N /Border [0 0 0] /F 4 /Dest [702 0 R /XYZ 72 351.40 0 ] >> +endobj +368 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 712.15 535.50 705.90] /H /N /Border [0 0 0] /F 4 /Dest [702 0 R /XYZ 72 196.15 0 ] >> +endobj +369 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 700.90 535.50 694.65] /H /N /Border [0 0 0] /F 4 /Dest [705 0 R /XYZ 72 452.65 0 ] >> +endobj +370 0 obj +<< +/Type /Annot /Subtype /Link /Rect [144 677.40 535.50 650.15] /H /N /Border [0 0 0] /F 4 /Dest [711 0 R /XYZ 72 769.90 0 ] >> +endobj +371 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 657.40 535.50 651.15] /H /N /Border [0 0 0] /F 4 /Dest [711 0 R /XYZ 72 627.40 0 ] >> +endobj +372 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 646.15 535.50 639.90] /H /N /Border [0 0 0] /F 4 /Dest [711 0 R /XYZ 72 518.65 0 ] >> +endobj +373 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 634.90 535.50 627.90] /H /N /Border [0 0 0] /F 4 /Dest [711 0 R /XYZ 72 334.15 0 ] >> +endobj +374 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 622.90 535.50 616.65] /H /N /Border [0 0 0] /F 4 /Dest [711 0 R /XYZ 72 145.40 0 ] >> +endobj +375 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 611.65 535.50 605.40] /H /N /Border [0 0 0] /F 4 /Dest [714 0 R /XYZ 72 563.15 0 ] >> +endobj +376 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 600.40 535.50 593.40] /H /N /Border [0 0 0] /F 4 /Dest [714 0 R /XYZ 72 448.90 0 ] >> +endobj +377 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 588.40 535.50 582.15] /H /N /Border [0 0 0] /F 4 /Dest [714 0 R /XYZ 72 259.40 0 ] >> +endobj +378 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 577.15 535.50 570.90] /H /N /Border [0 0 0] /F 4 /Dest [720 0 R /XYZ 72 770.15 0 ] >> +endobj +379 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 565.90 535.50 558.90] /H /N /Border [0 0 0] /F 4 /Dest [720 0 R /XYZ 72 389.90 0 ] >> +endobj +380 0 obj +<< +/Type /Annot /Subtype /Link /Rect [216 553.90 535.50 547.65] /H /N /Border [0 0 0] /F 4 /Dest [720 0 R /XYZ 72 233.15 0 ] >> +endobj +381 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 542.65 535.50 536.40] /H /N /Border [0 0 0] /F 4 /Dest [727 0 R /XYZ 72 769.90 0 ] >> +endobj +382 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 531.40 535.50 524.40] /H /N /Border [0 0 0] /F 4 /Dest [727 0 R /XYZ 72 602.65 0 ] >> +endobj +383 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 519.40 535.50 513.15] /H /N /Border [0 0 0] /F 4 /Dest [727 0 R /XYZ 72 420.40 0 ] >> +endobj +384 0 obj +<< +/Type /Annot /Subtype /Link /Rect [144 495.90 535.50 469.40] /H /N /Border [0 0 0] /F 4 /Dest [732 0 R /XYZ 72 769.90 0 ] >> +endobj +385 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 476.65 535.50 469.65] /H /N /Border [0 0 0] /F 4 /Dest [732 0 R /XYZ 72 627.40 0 ] >> +endobj +386 0 obj +<< +/Type /Annot /Subtype /Link /Rect [144 452.40 535.50 425.90] /H /N /Border [0 0 0] /F 4 /Dest [737 0 R /XYZ 72 769.90 0 ] >> +endobj +387 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 433.15 535.50 426.15] /H /N /Border [0 0 0] /F 4 /Dest [737 0 R /XYZ 72 627.40 0 ] >> +endobj +388 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 421.15 535.50 414.90] /H /N /Border [0 0 0] /F 4 /Dest [737 0 R /XYZ 72 332.65 0 ] >> +endobj +389 0 obj +<< +/Type /Annot /Subtype /Link /Rect [144 397.65 535.50 371.15] /H /N /Border [0 0 0] /F 4 /Dest [744 0 R /XYZ 72 769.90 0 ] >> +endobj +390 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 378.40 535.50 371.40] /H /N /Border [0 0 0] /F 4 /Dest [744 0 R /XYZ 72 627.40 0 ] >> +endobj +391 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 366.40 535.50 360.15] /H /N /Border [0 0 0] /F 4 /Dest [744 0 R /XYZ 72 553.15 0 ] >> +endobj +392 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 355.15 535.50 348.90] /H /N /Border [0 0 0] /F 4 /Dest [750 0 R /XYZ 72 769.90 0 ] >> +endobj +393 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 343.90 535.50 336.90] /H /N /Border [0 0 0] /F 4 /Dest [750 0 R /XYZ 72 634.15 0 ] >> +endobj +394 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 331.90 535.50 325.65] /H /N /Border [0 0 0] /F 4 /Dest [756 0 R /XYZ 72 205.15 0 ] >> +endobj +395 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 320.65 535.50 314.40] /H /N /Border [0 0 0] /F 4 /Dest [767 0 R /XYZ 72 760.90 0 ] >> +endobj +396 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 309.40 535.50 302.40] /H /N /Border [0 0 0] /F 4 /Dest [770 0 R /XYZ 72 234.40 0 ] >> +endobj +397 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 297.40 535.50 291.15] /H /N /Border [0 0 0] /F 4 /Dest [778 0 R /XYZ 72 725.65 0 ] >> +endobj +398 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 286.15 535.50 279.90] /H /N /Border [0 0 0] /F 4 /Dest [778 0 R /XYZ 72 498.40 0 ] >> +endobj +399 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 274.90 535.50 267.90] /H /N /Border [0 0 0] /F 4 /Dest [778 0 R /XYZ 72 302.65 0 ] >> +endobj +400 0 obj +<< +/Type /Annot /Subtype /Link /Rect [144 250.65 535.50 224.15] /H /N /Border [0 0 0] /F 4 /Dest [781 0 R /XYZ 72 769.90 0 ] >> +endobj +401 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 231.40 535.50 225.15] /H /N /Border [0 0 0] /F 4 /Dest [781 0 R /XYZ 72 627.40 0 ] >> +endobj +402 0 obj +<< +/Type /Annot /Subtype /Link /Rect [144 207.90 535.50 180.65] /H /N /Border [0 0 0] /F 4 /Dest [787 0 R /XYZ 72 769.90 0 ] >> +endobj +403 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 187.90 535.50 181.65] /H /N /Border [0 0 0] /F 4 /Dest [787 0 R /XYZ 72 627.40 0 ] >> +endobj +404 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 176.65 535.50 170.40] /H /N /Border [0 0 0] /F 4 /Dest [787 0 R /XYZ 72 415.15 0 ] >> +endobj +405 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 165.40 535.50 158.40] /H /N /Border [0 0 0] /F 4 /Dest [800 0 R /XYZ 72 769.90 0 ] >> +endobj +406 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 153.40 535.50 147.15] /H /N /Border [0 0 0] /F 4 /Dest [803 0 R /XYZ 72 769.90 0 ] >> +endobj +407 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 142.15 535.50 135.90] /H /N /Border [0 0 0] /F 4 /Dest [803 0 R /XYZ 72 157.15 0 ] >> +endobj +408 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 130.90 535.50 123.90] /H /N /Border [0 0 0] /F 4 /Dest [806 0 R /XYZ 72 601.90 0 ] >> +endobj +409 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 118.90 535.50 112.65] /H /N /Border [0 0 0] /F 4 /Dest [806 0 R /XYZ 72 454.90 0 ] >> +endobj +410 0 obj +<< +/Type /Annot /Subtype /Link /Rect [144 95.40 535.50 68.90] /H /N /Border [0 0 0] /F 4 /Dest [809 0 R /XYZ 72 769.90 0 ] >> +endobj +411 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 769.90 535.50 763.65] /H /N /Border [0 0 0] /F 4 /Dest [699 0 R /XYZ 249 665.65 0 ] >> +endobj +412 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 758.65 535.50 751.65] /H /N /Border [0 0 0] /F 4 /Dest [699 0 R /XYZ 326.25 506.90 0 ] >> +endobj +413 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 746.65 535.50 740.40] /H /N /Border [0 0 0] /F 4 /Dest [699 0 R /XYZ 427.50 197.15 0 ] >> +endobj +414 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 735.40 535.50 729.15] /H /N /Border [0 0 0] /F 4 /Dest [702 0 R /XYZ 413.25 701.15 0 ] >> +endobj +415 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 724.15 535.50 717.15] /H /N /Border [0 0 0] /F 4 /Dest [702 0 R /XYZ 92.25 381.65 0 ] >> +endobj +416 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 712.15 535.50 705.90] /H /N /Border [0 0 0] /F 4 /Dest [702 0 R /XYZ 305.25 225.65 0 ] >> +endobj +417 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 700.90 535.50 694.65] /H /N /Border [0 0 0] /F 4 /Dest [705 0 R /XYZ 154.50 488.65 0 ] >> +endobj +418 0 obj +<< +/Type /Annot /Subtype /Link /Rect [522 677.40 535.50 650.15] /H /N /Border [0 0 0] /F 4 /Dest [711 0 R /XYZ 506.25 763.90 0 ] >> +endobj +419 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 657.40 535.50 651.15] /H /N /Border [0 0 0] /F 4 /Dest [711 0 R /XYZ 294 769.90 0 ] >> +endobj +420 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 646.15 535.50 639.90] /H /N /Border [0 0 0] /F 4 /Dest [711 0 R /XYZ 523.50 554.15 0 ] >> +endobj +421 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 634.90 535.50 627.90] /H /N /Border [0 0 0] /F 4 /Dest [711 0 R /XYZ 453.75 369.65 0 ] >> +endobj +422 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 622.90 535.50 616.65] /H /N /Border [0 0 0] /F 4 /Dest [711 0 R /XYZ 419.25 167.90 0 ] >> +endobj +423 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 611.65 535.50 605.40] /H /N /Border [0 0 0] /F 4 /Dest [714 0 R /XYZ 182.25 586.40 0 ] >> +endobj +424 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 600.40 535.50 593.40] /H /N /Border [0 0 0] /F 4 /Dest [714 0 R /XYZ 240 478.40 0 ] >> +endobj +425 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 588.40 535.50 582.15] /H /N /Border [0 0 0] /F 4 /Dest [714 0 R /XYZ 494.25 282.65 0 ] >> +endobj +426 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 577.15 535.50 570.90] /H /N /Border [0 0 0] /F 4 /Dest [720 0 R /XYZ 442.50 764.15 0 ] >> +endobj +427 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 565.90 535.50 558.90] /H /N /Border [0 0 0] /F 4 /Dest [720 0 R /XYZ 300.75 430.15 0 ] >> +endobj +428 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 553.90 535.50 547.65] /H /N /Border [0 0 0] /F 4 /Dest [720 0 R /XYZ 499.50 262.40 0 ] >> +endobj +429 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 542.65 535.50 536.40] /H /N /Border [0 0 0] /F 4 /Dest [727 0 R /XYZ 76.50 764.15 0 ] >> +endobj +430 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 531.40 535.50 524.40] /H /N /Border [0 0 0] /F 4 /Dest [727 0 R /XYZ 205.50 632.15 0 ] >> +endobj +431 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 519.40 535.50 513.15] /H /N /Border [0 0 0] /F 4 /Dest [727 0 R /XYZ 458.25 456.65 0 ] >> +endobj +432 0 obj +<< +/Type /Annot /Subtype /Link /Rect [522 495.90 535.50 469.40] /H /N /Border [0 0 0] /F 4 /Dest [732 0 R /XYZ 255.75 764.15 0 ] >> +endobj +433 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 476.65 535.50 469.65] /H /N /Border [0 0 0] /F 4 /Dest [732 0 R /XYZ 255.75 769.90 0 ] >> +endobj +434 0 obj +<< +/Type /Annot /Subtype /Link /Rect [522 452.40 535.50 425.90] /H /N /Border [0 0 0] /F 4 /Dest [737 0 R /XYZ 219.75 769.90 0 ] >> +endobj +435 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 433.15 535.50 426.15] /H /N /Border [0 0 0] /F 4 /Dest [737 0 R /XYZ 467.25 769.90 0 ] >> +endobj +436 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 421.15 535.50 414.90] /H /N /Border [0 0 0] /F 4 /Dest [737 0 R /XYZ 168 362.15 0 ] >> +endobj +437 0 obj +<< +/Type /Annot /Subtype /Link /Rect [522 397.65 535.50 371.15] /H /N /Border [0 0 0] /F 4 /Dest [744 0 R /XYZ 219.75 764.15 0 ] >> +endobj +438 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 378.40 535.50 371.40] /H /N /Border [0 0 0] /F 4 /Dest [744 0 R /XYZ 236.25 769.90 0 ] >> +endobj +439 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 366.40 535.50 360.15] /H /N /Border [0 0 0] /F 4 /Dest [744 0 R /XYZ 404.25 582.65 0 ] >> +endobj +440 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 355.15 535.50 348.90] /H /N /Border [0 0 0] /F 4 /Dest [750 0 R /XYZ 76.50 764.15 0 ] >> +endobj +441 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 343.90 535.50 336.90] /H /N /Border [0 0 0] /F 4 /Dest [750 0 R /XYZ 564 674.65 0 ] >> +endobj +442 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 331.90 535.50 325.65] /H /N /Border [0 0 0] /F 4 /Dest [756 0 R /XYZ 76.50 241.15 0 ] >> +endobj +443 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 320.65 535.50 314.40] /H /N /Border [0 0 0] /F 4 /Dest [767 0 R /XYZ 389.25 764.15 0 ] >> +endobj +444 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 309.40 535.50 302.40] /H /N /Border [0 0 0] /F 4 /Dest [770 0 R /XYZ 76.50 269.90 0 ] >> +endobj +445 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 297.40 535.50 291.15] /H /N /Border [0 0 0] /F 4 /Dest [778 0 R /XYZ 472.50 770.15 0 ] >> +endobj +446 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 286.15 535.50 279.90] /H /N /Border [0 0 0] /F 4 /Dest [778 0 R /XYZ 567 538.90 0 ] >> +endobj +447 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 274.90 535.50 267.90] /H /N /Border [0 0 0] /F 4 /Dest [778 0 R /XYZ 76.50 338.15 0 ] >> +endobj +448 0 obj +<< +/Type /Annot /Subtype /Link /Rect [522 250.65 535.50 224.15] /H /N /Border [0 0 0] /F 4 /Dest [781 0 R /XYZ 219.75 769.90 0 ] >> +endobj +449 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 231.40 535.50 225.15] /H /N /Border [0 0 0] /F 4 /Dest [781 0 R /XYZ 72 651.40 0 ] >> +endobj +450 0 obj +<< +/Type /Annot /Subtype /Link /Rect [522 207.90 535.50 180.65] /H /N /Border [0 0 0] /F 4 /Dest [787 0 R /XYZ 219.75 769.90 0 ] >> +endobj +451 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 187.90 535.50 181.65] /H /N /Border [0 0 0] /F 4 /Dest [787 0 R /XYZ 260.25 769.90 0 ] >> +endobj +452 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 176.65 535.50 170.40] /H /N /Border [0 0 0] /F 4 /Dest [787 0 R /XYZ 98.25 444.65 0 ] >> +endobj +453 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 165.40 535.50 158.40] /H /N /Border [0 0 0] /F 4 /Dest [800 0 R /XYZ -1 842.90 0 ] >> +endobj +454 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 153.40 535.50 147.15] /H /N /Border [0 0 0] /F 4 /Dest [803 0 R /XYZ -1 842.90 0 ] >> +endobj +455 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 142.15 535.50 135.90] /H /N /Border [0 0 0] /F 4 /Dest [803 0 R /XYZ 547.50 197.65 0 ] >> +endobj +456 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 130.90 535.50 123.90] /H /N /Border [0 0 0] /F 4 /Dest [806 0 R /XYZ 547.50 654.40 0 ] >> +endobj +457 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 118.90 535.50 112.65] /H /N /Border [0 0 0] /F 4 /Dest [806 0 R /XYZ 547.50 495.40 0 ] >> +endobj +458 0 obj +<< +/Type /Annot /Subtype /Link /Rect [522 95.40 535.50 68.90] /H /N /Border [0 0 0] /F 4 /Dest [809 0 R /XYZ 219.75 769.90 0 ] >> +endobj +459 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Annots 462 0 R +/Contents [460 0 R] +>> +endobj +460 0 obj +<< /Length 461 0 R /Filter /FlateDecode >> +stream +xœ•TËnÛ0üþÏÂì.É% ,'¾ÐäqÍ¥¿ß]ña1vÐÔ† RšîC¿ Z?ZdWHVOïæ—YVsw*¶X»¾DŒ²õIq뻹ÙFA<Ùò‹?íú6ðL.Ò/p,^¯ ~wÂøI‰“‹¼D²Œ¬? t‚ªúìÒjB—øßÒÎ.Ïhç: +Z/–õ"÷|^c˜Xò¦÷°JãDï8Ø]È60;ÎVú$‘ýx1¯7½³lq…§’!{m¯Ä A­ #t¬¹À"ëÐ<¥êǺŸ©²2M„Üù¼àNøn ‡Ü à· ,í½¬éЊ¦ï–«†öß1$ %9m†âÿÒìôÖª{}Öª +éªÁ½à5ƒ:oÛ„ìªGióЍu­¡4b·Žé]Z'Ý7µ[#:ÚOAœºõ8'&—Y ÒÈ +µ2ð®wËŨFˆÎÓL†¤'=î,YÏÇ9º|ùØ¥ˆúrMl;kÑÒèÑü§UÈ +endstream +endobj +461 0 obj +459 +endobj +462 0 obj +[ +463 0 R 464 0 R 465 0 R 466 0 R 467 0 R 468 0 R 469 0 R 470 0 R 471 0 R 472 0 R +] +endobj +463 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 769.90 535.50 763.65] /H /N /Border [0 0 0] /F 4 /Dest [809 0 R /XYZ 72 627.40 0 ] >> +endobj +464 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 758.65 535.50 751.65] /H /N /Border [0 0 0] /F 4 /Dest [809 0 R /XYZ 72 427.15 0 ] >> +endobj +465 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180 746.65 535.50 740.40] /H /N /Border [0 0 0] /F 4 /Dest [809 0 R /XYZ 72 284.65 0 ] >> +endobj +466 0 obj +<< +/Type /Annot /Subtype /Link /Rect [144 723.15 535.50 696.65] /H /N /Border [0 0 0] /F 4 /Dest [815 0 R /XYZ 72 745.90 0 ] >> +endobj +467 0 obj +<< +/Type /Annot /Subtype /Link /Rect [144 691.65 535.50 670.40] /H /N /Border [0 0 0] /F 4 /Dest [824 0 R /XYZ 72 745.90 0 ] >> +endobj +468 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 769.90 535.50 763.65] /H /N /Border [0 0 0] /F 4 /Dest [809 0 R /XYZ 435 769.90 0 ] >> +endobj +469 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 758.65 535.50 751.65] /H /N /Border [0 0 0] /F 4 /Dest [809 0 R /XYZ 127.50 463.15 0 ] >> +endobj +470 0 obj +<< +/Type /Annot /Subtype /Link /Rect [525 746.65 535.50 740.40] /H /N /Border [0 0 0] /F 4 /Dest [809 0 R /XYZ 120 319.90 0 ] >> +endobj +471 0 obj +<< +/Type /Annot /Subtype /Link /Rect [522 723.15 535.50 696.65] /H /N /Border [0 0 0] /F 4 /Dest [815 0 R /XYZ 125.25 769.90 0 ] >> +endobj +472 0 obj +<< +/Type /Annot /Subtype /Link /Rect [522 691.65 535.50 670.40] /H /N /Border [0 0 0] /F 4 /Dest [824 0 R /XYZ 76.50 764.15 0 ] >> +endobj +473 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Contents [474 0 R] +>> +endobj +474 0 obj +<< /Length 475 0 R /Filter /FlateDecode >> +stream +xœÍ\ÝŽ+· ~¿ƒ¯ d¢¿‘f€ €½^ߨ7H›‹ Üôõ+iDŠäPãÙ³[  ûx5E~üø#9^ìÕäÿìÕÆiuùÓ¯¿_þ¸Ü?.??×ëz½~ü†#æy2ËÕ§2îã÷‹™LpyÀ¯×_Œ1!¿æüŠù•òkɯõï×_Ü:…kžàãŸ×üˆ øˆÏ¯[~Ýóë­ýûѦxoÿO—¼~Ÿ×&6ï³= säç¬iïv[Ϻ6_^ßæq¶·sví²üyøíŸÊb ,fc°¼°CˆÓÂõepó¶mÔÞ‰Þ·ùìÒ¾ŸÛ÷‘Ï»f…6¯]Ùæ}ÿóÓÎÒ‚&L>ÒG­»þç’?ÿu10ö}S¾S0`–iޝÇñÖOt8lÿ½ŽzÿÈX›óˆp Ë–kˆqŠË5ë8¹ë_ÿºüö·Fo4&'4‹ñ_PoY¢ÚU.1¯iʨÝÔ5£åý­@jC¸/†(Zß½àÕÆ¥6¨g5o#—J‰vÎÚ+ÅškgÔ„NYŸ` ”Ù=7#¹·Íõìš?‡&c".8·¿5W©*wmsXß]Í6ªc›+»{woÉe·kû¼4׋ۺ®yP2T¡Ä·qp›Ì-MÉ·¶È²ÔÝÉsi/ÝHù¾ +¾9RŸ¿ŽMmýQ@"cï _ Ì{ûÛmShQ,{>5y@V ”D”×ä¶06¶qÂÛ6ÛÇJ<Íøˆ²'ÙvÚT'ÕYþËo[`Ó[[Îçï`¿ÜÛ^+(ø$Áb“,»lÚ¬t×Á°Ð¥®)(ø® ªÐf4 ˆ{kódž|U©'µE ‡ :òžgÁ å "ä>$2!¯™bߣ¶ŸC`!50å·l®fìn'2_54èùÞ,8a"ŽJB÷yçö¨:Ÿ‰-RÇöR‹ƒkµ™ö¸Ì=á¸7»ŒØH¬3²%`Í=ÆÏVùšÃ×ï?É® ´ëƒèu¤Å#ÝÛ™¬›ß½%˜¸ØÖÕ°2`”±,ž‹<Ž*Ýï>ìJæ8wI“ÇÕ@ÙäÁøjo\´‘ðçš 6ýràs`Š•6EØš9€/‚«Á€pøì}û;bðëhÑ»¼^0xr,0Î{tlÓgÇO¢¯WþsbŸ:îrZd£€dv²nëZØ×Bdkã‘wNƬ†p·Œ)Ì—"ÁøCpSšf'„g™ÍNxU¼: NL +ĸTòv¾xÐ<ä B»uÆVF4ZaÕnÝBÈø+ñt`£[_­rëÞº‹°„]³Þ»²ñ9ŒäÚLÍÅ%«Tä,}µwyAÉZ€U0%YÅ."i̪1aX"‰€(³oeêyq0ö;É|RÞC¦må=–a&7OC½;’ÌÂC¤j½%`MOq)õÓ¦'¿èþ€åá®ÖJ>ŸlÇ} +ì¿@E®l«ß*_˜%×yvé¼PU´‰îr1ØóàŽDª=ÊYë.DK"wüZñaÎåÉÄÛ]“Ó~eV{o²ÝHNHÆSý]é1sô„•u‘´„ \ðDe¦%YG4(\4¬Q¦÷P*l‰tØÎ•ÍÛ³ØõP‹ +I!Zp—4zŸ Ú{×Ý% 2¹“ñï±=Á¤ý±†&éF¥Ð`&·|‘pŽŸX÷¯*@ޏ!–›MsŠÒ„Ú1úŸüá`|+ÜWˢ,}Û¼(d-7>å lä̆G-Mþ¦ì/¼Ê!Âú£¨ä–){´åËÞär_-Ò—ºr=ßÍ™PŽt}B¡D~j–óÖÝÕ–$›£öÂzÖ z¶Ñœ³­¤!¥7¤˜Øe¢Y…ia÷Mm +cn¤øŒËð°¤RÅr8xlÒR?Õa´Ô\*o%)"¤]2^ÈFØ›b@:/1Æ!iHÜ»â0öÞÅZ@T@ w>7¡p„`–ͧ`XFN$Þbíöf¸³À|‰4R¥ÎP×5ç‚™I&°&*€ ò‘‘}‡Ä ËJíñªÑ¸Ï“xMš‘ßDÇù8"èv&²A.Q^ü€ÌåDPÎK²eQ±öÿˆ¹cS¢4Ö£Çå{ÎïJN„ÙìâKaÏ6aù-hhoæV0 ±"øš{²É1‹†%¿,E¯_ʈú5#ÂØâ[ŸÔÞ²!;-|†SÉP%C˜+Ó¼“4 5.| rgµlÕrÒ£„ç“I™üX»á œ‡æÏð\ b€8l A ¤'a°†Ô “CC[J¥œÓ’ÓòÊöÆ­¯I›øÈg +4eÛ (CáëÝ!moÕœ±É9sÙ™®h» bB"kÞ‰<´¾:²Á›ìdTåwÎ$³-É +3–ÁbvÆ3¯Zæ)û“%h×.¸áŠe…/íù= r8p¸z]wÖYÐ vxn~t L£I_ƒ%=ÑœE#"Èx)!ÐÑ*nÊ®gо{˜zç¦l¾Nè×3]És¥uó~@ßÖ¬[U|ÖÎõŠ •Ž@Áw_?ìÇŒšùàßÏý<¯òO–çþ`3lwØs´QãÕ!"ø/pQO’C',>Ž`âê›<°¤²`W¡¦"G°pI,3À…wyLB5_ÀäÇ /xÓ¼jžcúz‚ë¦ç˜Ã|Q$ª¾°&ŸÄ³,žfâhxt<>¬|0òDsŽ…r¹ÌÝfÊÉ@íQÆ€¦IÓydÚ·Æ’írXÇȌ嫾ʘÉqa¾¯j ¤/|²LQ}aâêmɪNùÏžûXî ¼uãÏœç>%pkÄ[p½´djGz|c›à]Zwd4D ½áŽgC¹sspç Yý{ ‡)aóOzGçl™ôC· éÜÉô)]_9–Á½Š¬ŠÞaÁr@ÀÝ€Ö„ö&O6îj‹i¬¯Ä|¦s¥¶ŸAdÒjDµÏ†Wx‡'Q(ö¤g3áíÞåeÀ‡+Ne>Òª-|_eï”ÿÎdù4ÄC0$Ïën— nóÒníÖ#/©¶¯MÿÊÕ@rš€e.AÅg’ z)Ø{Ã/“†<$£¦}y÷Êï´,QÆ&GhÒÔTÉ.® )7àX)80#û©‡%õVMè”ùam{M¤³£š?Dr9J˜EÎ^Í<ªg4ö–ëœq­op•]ç\ùÉæ Ô•i½ÿÔI–ë?X[:{ܬA+[ë:Å‘Yýå2Ÿ´J´’¿‰ YLÔãçžùõ dÇ(—éu‰tž€È+±¤{7O&LÎ"øsÎѼœõ54)gòXk BbºÏûð3/¡Fá6‘|zꊼ"cå^†7¨¬-ñì‰Ä¬ö•¹ + +9DÂ6¤ßä68£:ñ’Ù•ëçd=ÿts½+„9¾BOÛ¬t“ú™t[‘CçO¬eË}ûAu-pzͽhÀ{þoÖêžTŽàƒö%ãyägñ¿H{«:Vœ áqÖêܳcâåÀ¯2#±gSšÔ²²cÔÙWc¬ôôÑiÅ¡.ÏxW“xÇ65|íýÓx÷fØÛciª`–].Es¨DÌ2õgf\p”{5\¿rýÙ0]¿ŠÍü´F]®-×}+™^˜Qo¤k©ê ×ÓZGé‹ "ð÷JÚm[N»rSÔBo,ÃgÞnÿ¸üãò_rf +endstream +endobj +475 0 obj +3293 +endobj +476 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Annots 479 0 R +/Contents [477 0 R] +>> +endobj +477 0 obj +<< /Length 478 0 R /Filter /FlateDecode >> +stream +xœí\Ûní¸ ý‚üÃ~.n–m (°/ÙóÜ"0í(0z^úûeR")ù’œLÛ)ŠApvvl‰—Er‘–ç/öbÒöbã°¸ôé§_^þþr{ùá¹\–ËåýçrÅ8f¾ø ®{ÿåå÷Æøù—÷¿• ¢¬«˜ÁXXá§KºÔxøÉ—ÿð´£Z:¦¥¿3­óÏ—ôùÛ‹¡Æ|³ïZÙâ2¸p¼5]>…ÁÍòò‘.·tyLÿÞÒ¿ðsO?oéwønÆïGü>Še½‡ Å®ˆð¾´Ž™ÒOZË,ù~· á’Vxÿó%Ý’á’_™ð;Š"åß·—3Xµ¬k¤Ežx/­ªü×®ûY‡ë¥ýmºÎâõv\Í‘÷9V¼½'èŒ~ˆáæ!Ì—ãçË«&wùö——ŸW±e縦Ñ>›î¶$°–U€lrY…qÏõwcBñkæêO´ SBNܓԚË2,±'¬w $â§8ÍÝW§ÁÞ. ñ¦UV%n¬ñ€± ‰yà"7ØD.àÇ!Êû½÷æ7yÏh¯nrSÑ- Vsèþ ¯ëêþ Çz`uÿȰVÃ)ã—p)£ÐÙ©QÛ +µó.ü,ѽD6 ÙÕàw}Eé¹á+T&!ŸòºÅ £“‚…¹h4®`4W柱˜#Œ’ªEj"xbÔ-°ÔÒ:>†”õ7¦ÅÅBÁ„aV ™âèpXÊ\–«Ÿ±=3h=†1åX¶Æ«ÜõÑŠ9.p©ÓöÑ oœ,è÷ +Ã:iŸ–Óv2ÊQÁM®1¯Y…¯a‹Û0= +lö ß † \>®?öMÞhR‚™úÔ.Ó0ñÍêRf³ÍE`weÎÃÚv(ŽÚ¢5hÅçš ²à”¢¨"ö¬Ì<·˜d˜—óõ¬òîzOÇîØÀ@xÉMòúÉC°ðËKõw¸<ý›~‚•·-rŒtªN¨ï¼Ê›õœÍzƒWRø­"ä–õ;‡ø‡)t"Á¦Š$½{áf²ѱJóìe½±J‚e‡ëG¾rÛºYï‡1ªýê†Iv÷`U…9^ën0¥P5*µ’Id¿U%òºésvH˜ËùKVCK\?Tú‰ÓÅuSwc"…H&,¬ì +3këwð»ö ” ¸¡k‘ì8(§:n㘣a”—WË$ X6)üt"#Û7ä­œ°Å%Sâf½V€èÁ'òú±·ÿj'Y"dIv/é/ý¾ä6Glá¥×{Ì×yðéLŸ 4µ› ä¬ßdÙßKŒ‘ë +§Lß0Ÿ^ëwt/åã&w*’çHfα +Tx(yDøQÓ¥"ÞJ®ëý’m]ŒeÈGÎÈ0#o¶&1Qì¹0ë/hú/›YJżC»¢ÒäUØ´MgÖQí EWÖÔDà^áSMMLœ¼"¾h™‹âÀÏ +Ô(Sv™êßKÆ¢ú¬HýF¥ZÂý-cAQLÚ¥' +{Â@y}R +p¥8 ¬îV×½#°—ª1ÖÂ&::È{B‰ŠÓ0îd†qYjfp#g乌&øÙ¬A ‚SCìr¬qYƯ¶,˜µ-¬Â”­ucëP!ŒŠ£újÍR(UÝÑ;vUŒŠi1/žì³c³„‚žŽÆªéÇQUÒØ“ɹ=Tµs01b$‡ÏªE2ÐâO›Ê…yœpeHч)´Æöâi«jŽó é÷[ø~¶—£·Gù¬­“cªTeIÍž¡.o¬íá¡\Vñ(o`´êiÚé¶\™lRp­ˆkš n\Æg´1>f[¹I~¨›êº"!’]d†&nªtëFÕ•ü"‡¢€·ú”]6.¼S¡œ­í+íÏdwÒ1dä(†•=Û…ñ¸À–Meø€EšN`ÇÒP2sòµªø/ø0¤³4M t[èœxx¼ŸT¢$À§éö¿Òˆ[ëªaÙuW +Z' =+R­$kÒf7%ÖP€&_™×½ôN¾‰]zÕè.­umoªàt ø=¤Ð´Ž° sQ9J2T¦¨‘ôm’ ~Yºù'ƒþ¤Æ6·V®^–¦µI?CãUÔK²}éqoQVÅÃt¾´y9%b«Ógä¦Zñ·ÎdrämÅÇôwmª½¢´‘[÷XÁ&V7Š­n’¨ 7<àÔü¼2Š||„ðZŸŠùEd- DÅÀj#.Õ6kìÒP»œvmדÛ.•4T™ü³ÒQš!‰ÆïtÍávC»ÞL—¹}– v7ÕÁ'Kû³Ð,áô¨{5Uãàž³,•|[òœî7X,Ø[ÇÖ›\£çO3AÝÒ£~OcÓñ½7<‰ð)2·ÕCvmKö{>–ÞÌPt;4Ÿ½Éïø#Mä"3ùT/:´”Öw”ØxàïØÏuMÐ?'²Ól¸YB´lRY Àý߇m+Þ®·¯´Å.£V¸)>ݺ¶¬xT«ac*Ò^Œ 7*¡a³Ýé~¨ä˜¸5"46ÙW ëìý¼ ß[0w_ÝO®Þ³Þ²>O‹€9Slôo8Ù.²7³p €o°ÑÃYŸÈ©<¹D=¢ <ƒl(„j 3Ú̓n %ŠÍë!‚aé·!|â&8:ï±8š>Ñš|E9=3²÷0·êÌ×÷&öåT”zê>ï-øÝû`"ð€Ï ì=¸¹Íÿù½4àl€XIae£¢[¿­½P,/¬ûNn‚ÛL稗aÝËï¥û`žXçç½¼$g „3=­©¶>e¦B¡C³ÀBÏtuªØbú¾3I¿WÑIJ;'ª|yðÀe\Lm•)œI.š…ó öÔ¹”­Âèu)Ôg¼+cÈׯ¹ sØî£C"=í=1-Ù«Ãá­§ŽóC;¨ûÿ~Sƒo->¶†Ô>>PG_C‡X“æÿk†ìú_cà–0ˆ‡êDÉz²¾^ÅÏî} —m$èSY.ÂW1Ùfë>‘å[ÿOòX‰i£ð§GC»Ïo¦ú9ÓfŸ^Kµã[ã$aëÙ¸1ÆGK;#ŽCR±Ê_ðL¶ï7ˆÕ‚Ó3S³¦¦€:ƒMƒÜW<'ñ±÷Üxa×P顲ÂýÁË.–Û]_}:ª·kò±©h}E$ÖMJÔó”xÕÆ¼Àô¬Ã¹ÑG¨³#dMdrr–‡k«€~V>÷ÊaCIÔaWºÉÉ”!%=µ¡Ã›ü:Ðò—†šôwXóMw¢Î¯ é':Q»ÄzX³ w:¦W2ôHøÊD/,±±Ch +‡_éGžžÈÔ—s,+¹¹ú¢¨ÌËŽ±3éÇü¶×6ðvEÉi;ۢýt»ƒÅaz¼U¿næ³ÓR㪾.Sý/ðÁßþŠþôc})ÎÀ‹EêY£ðlƒ¯äÒ"|3®5¯ƒh(¤¯ùèÔ +esí\!]ò¨s€¾*€|¹aMú2óºüˆSˆÌ^<¡Êñìû¥ Òcý¾Ï?ÈšÝlÌð}”a57,>gÍ“xËï­¤tp/†òüáCgÀB§®xOÚÓæâéê{Ø}ÐRæé–#xŠlŸ±æ!ýGWE~ÚEc„?9`êÛy9ï38~Ù«;Ê^›ƒÃÂäF:Ã^WÊÜÄ3Ì,øwv\“?ì×õŽã“Va,vôf©Šˆwj¾X¢mè%) ú©l¯Ÿ)ºm õÀ“¸ÅÔ¶S%(ñ¤—˜ÓQB¢€ †É)2%K_Ì`s„u°¬{SLÓ€F)p}zEÑFY±qöH1‘etVÙÍéîIÉÄ2«>KU‰RÅÈ(F×™”34þøþ¬^µšd²P,ž©/¼Ä¿H¾ xâÉû¼SI‚èZÏðNn Ê'+/Çýò)¯ ¦eG¢Ù±÷¿AÐ#ë£'A»µ‡ò÷™ðÌyí€ûÙy¥RBô‰ƒþt9'µHÔLC˜³i§i2Ù3µ”‡ÜÐE%[}/²¾±º­‹ùHȆc…ÈYêuؽì±bÙ1k9O ò¡–~œ þîž>wëX¬òsòü|czˆBq`¯àœyܲ×—鄸9¤T;•V4ä7Dí„a–'×W·H —;ðHŸ±ÇéŽ[0A”ñ&%—(Ée ¼éôÀ#YþÉ ÒÃäúuÈiÕUÛº¼™U#9AÚÉ;6õrÓÚÀ9SK*«>T +þt¹a‰ß3r¼Ýd°,µÊs{–9NRp\Hê2žæ9ì4àG› }êé3dzE1Ò¾ÀXè6g‚/½×ÏGƲD﮳›0ÓýÊCl•üñå_º›Â +endstream +endobj +478 0 obj +3472 +endobj +479 0 obj +[ +480 0 R 481 0 R 482 0 R 483 0 R 484 0 R +] +endobj +480 0 obj +<< +/Type /Annot /Subtype /Link /Rect [89.25 188.15 135.75 175.90] /H /N /Border [0 0 0] /F 4 /Dest [499 0 R /XYZ 72 627.40 0 ] >> +endobj +481 0 obj +<< +/Type /Annot /Subtype /Link /Rect [205.50 125.15 281.25 112.90] /H /N /Border [0 0 0] /F 4 /Dest [511 0 R /XYZ 348.75 769.90 0 ] >> +endobj +482 0 obj +<< +/Type /Annot /Subtype /Link /Rect [285 125.15 372.75 112.90] /H /N /Border [0 0 0] /F 4 /Dest [535 0 R /XYZ 219.75 769.90 0 ] >> +endobj +483 0 obj +<< +/Type /Annot /Subtype /Link /Rect [450.75 125.15 524.25 112.90] /H /N /Border [0 0 0] /F 4 /Dest [558 0 R /XYZ 219.75 769.90 0 ] >> +endobj +484 0 obj +<< +/Type /Annot /Subtype /Link /Rect [133.50 96.65 265.50 84.40] /H /N /Border [0 0 0] /F 4 /Dest [632 0 R /XYZ 219.75 769.90 0 ] >> +endobj +485 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Annots 488 0 R +/Contents [486 0 R] +>> +endobj +486 0 obj +<< /Length 487 0 R /Filter /FlateDecode >> +stream +xœ•UKnÜ0 =ï u*¢,Ñ2P°3qÖ-æiS @ +t6½~)™”(ÏL?”È +ùø{$`ý€´³§ÛËÛðcXÏÃÃ6›Ù˜ók•ˆÑºdÆ)Ëßg]ð$ðb>8çHéLtù£9ülƒ!€óC*>T•‘ÎBg¥óÈß'†xâïû°˜È~Ã…©ÃÝXW0Hÿ…ÝxÆ#û@rÀò ¾DíÉ +¸†ý>Kb ̧N1´©Ï—«Á +«JÀÓŽ‰ß#¿c;SBC‡ süXä6ˆÇ +º`GÔªàͯî—Á ¾Ëo78à’øwãUF«ÅYÒ¯EêéL\‹$LH6$-&C9ž¼¹|^ß ÁªÞ ä„.ë°3(ÎŒ gË[(±r‰‘ß×ö"ß‘aºÜÕ›à¦G®&2¥ID‡}È׎êÙÞÌþLæb߯Š]“²Ã÷Ò*ãî_–õ‚½ìrÕïeÇ€Yµ˜È¯ü~âXƃlÚ¿}ºöSÚ´mÓù~Þ<û™e|`ùéš<{}Ãl©¬ÜA­ÍOÍW;ԥàm-_ÅϩØ2é:@À‰«IFb9ôF€B¦êÀ="¨¤ þ…TW…ØZ±ÊÛ£"ȬHDßaaå›g¢ùU÷ÙËœ<\ë ¹j°Ù(ñ‰oÊ* +éÙ7Õÿn’ƒF M½vµt·»ÊÔ­Š1vëÈMÝw<¥½ +ƒ1c¡N[?u#N"ózkôiapožZïþi¾üOÊkYÕB¨¶Í‘rGúŠœ¼‹MááŽ_lhª«Ù$~\Ûà“ yùÆ—ÏÏmÇ!·dWÝÖ™þÄáIwè=H¨u´¶ÍS­`ÞixõP]Õê9ðÍ£õâÑzÙÜÖu«Ç`1ÛkÃÎäœ<÷ÌÉNØ;à*ëd8uŒ*Lî'žO%â"ú“8÷iø r› +endstream +endobj +487 0 obj +731 +endobj +488 0 obj +[ +489 0 R 490 0 R +] +endobj +489 0 obj +<< +/Type /Annot /Subtype /Link /Rect [450.75 741.65 517.50 734.65] /H /N /Border [0 0 0] /F 4 /Dest [622 0 R /XYZ 219.75 769.90 0 ] >> +endobj +490 0 obj +<< +/Type /Annot /Subtype /Link /Rect [72 729.65 113.25 723.40] /H /N /Border [0 0 0] /F 4 /Dest [622 0 R /XYZ 219.75 769.90 0 ] >> +endobj +491 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Contents [492 0 R] +>> +endobj +492 0 obj +<< /Length 493 0 R /Filter /FlateDecode >> +stream +xœ½[KŽ3¹ >ïàu€©Ñ[* `w·÷ú“d`d6¹~$)‘”ªÊö?3h.ÛzP|~$Õÿ½è«ÊúªÃ²šüô˯—ÿ\îß—Ÿëu½^¿ÿÕFx¿¨tµ±ŒûþõòW¥ŒûÛõûßm@P‹6}€Z”.+ürÍC•-¯:üç‡öbé—vtf^ç—üüÛEá¾NV廑¶°.Æoã[LbÕÇáú‘‡‡üúʯ”_÷ü˯ü®>Éo~{6jÛÂèüþ‘ßÍ6ÖX‡uÊç|þ€õò÷:Á³ß¾W‘j_?š3íh®Ó¡"ì³Öùf]Ü5¯ðýkž’™C¹AÈPVË.R‘T[Wq.?`.®QަàØ£ a«ÝX[Æë¼Ÿ°oe}Ýïë;«£·KpW——®.„%¤ëOj‰æúÛ?/ÿúK×W«& +.CAÌî3РbQ8 !4ž=¯åx:MŽç×´´Ó¥v:8A] %ýµqxgÂé¬Öêº.k˜‘×Å´ÁvR“éÑ+hJ¸VŸË÷+ù­hDìÜocðݺi¦I EÎiAc=<Ãïå‘ýžúg šhõ&‘Êä]‘øhfÜæ´ŒÐ gý4ZÙЇ¼Fn0Ÿý¹jÕð"Â+™CÏà7Êχ˜÷9?{;ÛmgàÙO*Í­ö!.ɬnºç‰5ÜÄþOÈïU~³õÓö»Ù¼‡vv‰¡»+ˆÊm1KAžµíUfÅS¼*FঀB ‚¯fTáã> ø†¹æÂä¯Ì¹ÓW²î}¢TwB˺ͳ_°ß}ª ƇáàÆ6m°\ZuÐ̲‘qH{ÊɹÙ•ÒR¨ò3ÁíMLgì ¢e½º÷ƒHµqRªðL£ìºè0ð€™'žÝ=j€‡uq/âRgZ´ ~Î7g¯®Ó þQí#2Ùþ£YÒns«#ñÓ3øó¡Z|® –Û±ªèõƆã¨çµ©0ã¨çbitõ-êé¢ +‰cäP€*OÏsƪÑNtFt½L¶N±P¼Mȇ#ްÓFŽâmÑCŠ£"ŒGÕ™zetž‘8®»bàÕ¨~É6Uã>ĦÅÎlí©iDš®ö!à«6ŽÑ∄àü™z/DOü –¤9ü…–;ýÍ7Ú–ªØ¬ )õí»'BËæÓ”Ã©0 pʉârÅ¢±oCìiÎMsXRÝ©–që{6 ¹&sšò4Ïô¦õM85¤0áÑb~UXn¹k-V¦£§Kb\*˜• § ‘–—P¯hÕüI4& +d3¼î•ЕÂÑZ‰]Ø´ ÄÐÍ/1r +‰ÊˆF¾:U #ÀõgtAÚevòñZÿ`®©WS*‹|ÑÀ|ñ¥–êפD„©¡i¶¢4%ô·®ž»ØÆXòbcJ B«ê9#sl­”¶r3Y‹`Ì£TübqQ@»s[@¯çŤ 5ÃBA• ܶmhÕe6ïÐXãüpV“%žèa*ŽW³Ó6dÌ[§›Œy'R¯3†B¶©Svb4HlšÅ§èµÀø »nÌã*_!\b»6€ÊÇy5pDwŽ ¥ƒ¨œ¡î„À€ØfŠ¿%ÕrOD²XèÀ÷Oã +/-”ì*÷.9ý´F©Yp§i3…Œojšy¾èòLÒUªŒ¨!•lü“Dn²—o`Z65ý{Ê&t¾vN:¡“è„Z )p˜Ñ2ˆèOàLñ]S¾—“[ïf˜˜Ú—»OE!Á@šwKa¸/ôgbÎQþžÆufx”U¾­[´¸AcjknR]¢ØU&í{sèü¥Ö<:AM€¨­·9Cγ[µu%ŸÉ¬ý’³ËX§9«­Hy(D0/¡,yþh3'˜gÖ¬ ÙƒAÕÁÐOÂë,M²„PrOì@SÐÌÔòÜ&®e`W;Öäfi9·É®‡¬C¡ ^õª• ÎÔH½*+ ‘vœ¨x2‡…œ?(âi+r7d˜&RØÈð)­“^u7CŸivKC#$îtJκ&¬øö&ÑxbTï[ÆŽ¾Bü!óYT¶»âù²¹)Q*\µÊU°õ=Pô¬ûÔ=eÇÁ¤£û û퓱ּňÐ@6zK$̰êó^ÕÞoÁÁ¯(h¼I!ªs²âømÒÑ9ò™¨înLœç¥&ÞQm\6+2«NÊ  ô´âSÓ¹rgŠŸÁgx±½_[´^e»Æ¾°@)Ìì›iÏ4;†"`U¤´#RlÕK\;ùYŸHh¼°è~ÂȇF£ÌŒèþèYHe•%Â*vÓí;׫&ÛµÝ$¢ŸªUŠZ‚Vž´êÁzñœ¨`ª{ + ð(¿H†ó\µ¸ÓÓ:²Ó"/¯‹fWœSz&Ô~—ZÆn_»ØŠ¿šT*JÅ’ª›þÁ!‚Ýs'=üéIÁìé!ű‘_ï4Ç©Váp‚j ýòÙÁÅÃÃöéŸ„ÒØ>Øü°|vêU +”ÆAÁL!¬'EìþŸ¤ <Ä0Ú·9E•ϧ ×W²ÛZ¢Tõ,}û׸a®U­yY÷‹nóHÝc^!È—\‚1ueˆrS¦mR,áª+234ê)H­»6Ä­¢ŒÌßÒœ4ûN ð¡fMbЗœŒÙIÃõ€FÐØ¿gQA^r’À•6#vä7õÈpó»Fù’Eúµ]:ØJŽõY@*­“9ㄊ=Vœáˆ5k®—”£iÜc7\žI'¹èS׳ŸsLÖA,ïí4æ úÈòLVø˜TyDÕm¦5‡±—ΩAù®¾ÜRÙÄ›Uª\Žýkœ€›݆ÝÿÏ@ÑŠ"ÚPÀÛ)‚±fÖ³jh_P½™Ú¥>Ov5ƒëI°D/TgVêÊRå©c"kë¡¿¾/¿ü\·‰ +endstream +endobj +493 0 obj +2894 +endobj +494 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Annots 497 0 R +/Contents [495 0 R] +>> +endobj +495 0 obj +<< /Length 496 0 R /Filter /FlateDecode >> +stream +xœÅZ[®Û6]÷ ïQøEE+ŽòÝâî m +Hæ§Û/IÍ g(ÒöM/ZBd›"çqæÌC÷¯‹žTú§'íçhÒÝ篗?/ÛËåý§8M/_hŲÌ*LvÍë^¾^Ô¬œI >O?*¥\º–tùt­é +éŠ?M/\LœÝ”6xùuJGØt]Óµ¥ë|¾Ááóx[Òùu_½Š}wx÷HÏiÿëãËš…3 ¼1ÇZƒFÛ`ŸÆ¨¾×î¥r.„y1BFS}šâåúçEꤣ0¼-ëßïziÑ£Üì|´™þ¾¤ûo…;Ò©ü]*Ì><>œÖk;¯\9XjUYöñ%}±³wÉ Y4ç}Þ?98=õí·Ë—0´š|'V¯ò3.,VRæx`ªI`èÉ^Ý*’²‡ó}ävüî|Žàm¼_ ,¤âÚ­Y…*›°mdû²Ášïå&«›S° +Ó:ÜÅdP:®‰Ž6[\¿’iÊQY¿õxHË0ö´îzˆYb.2 +(tAüÙjv†­QÖ€ÍÊoSÿ +ß§ß]öÁ +çì@%öx¶œå™éà7\î]õ çßiéÅ~G9Jô¢€ñLg}ö=ÀÒÅ9™\ï¸í ๠öò×ÅÈ(¨ûß3YÑÅ'±£ËÞè¸ôKûÙÀt°ínoƒ³žÜ§kçè°ÃóÖ¢œ·+=ßììü7GêP5ÿÍ +Œ§Â'I¼hÂÉU’èËÖÍ"ÅFЍ#¹Öå”s¬)ñZɼM7ð¤DÓ’ãjLáÈï`G–Ù9L~ |ë˜øÊàöŒ›¶Jš·šö<+ëÝç²Õf~’ûê–Ë(ãr–3îˆ3GÅ‹".£ø÷ìY\“…Ô²4‰zpÚȤd¢Árå&­!‹¯Â) È*¤½Åý‹’àÚås‚x|Ý‹<D+Œ ÎìO™J‘þ„²¢ÏÂ’IF_ë¾D´ˆD”ß2}öêÔb¯­!ît$•µo7"¦µú#"/§3RkÁöÄD‡>#ÐENôïRõ}äO¡S³ö®œˆÍ¦$aä8cµçgor±zøÙF^‰pLá6Ϻ%W3-Ëû oˆm®Ì_¨`A#ໂá~x|a§²Fy²bIåä#,Ц" K‚H3Rw߀íQµ±aO×´@:Uìò|cÉö¼¯³ KIšG¶39-RaèDßXìî‡]äù¡ÂRÁÞC ˜¶ú{ùŽbì +žHÙ°~Wt(ç]¾ìâÞ–>æÄowb×Aÿ\â8öÏvWU‹ ŒCÀú]¨ú,çw0?,j{üßãQ<;0Gbg±ÝþÀðÖT‹Â^"ŽMèäC=°s[ˆ +‹&§ç{“#¸MíT‹Bû¢"*"œ©RUkЍu–G¾ [èÕçR¨âžèmDckÝWÖ†Ô¾ú5¶¨Ç:¬lJöÕ}ïPŠ^¬m˜·B²e§::¡¦ÜËaL²«iü¥„]yeA™·‡2Í'•icm 5‹ +QQ26 ;óŠW"‘A#†µ¡…,#âý¼ß³UíÛFæãÃÊ«Ûr¢îWÖzr&ºSñòµÉ¼ªºJöÕœÝÎÁáï%Fè9ŸœZY>µ"†œyLs@¬aA×O-4©ffOgz*âšQå ¯níÙØ˜ºc´1ÃUÛ£*žU¹Ý¸ÇLÆG*ÎxªŠd8ÝÁ­¨r{xåã ßüö Ow»ÉYNç¹/óVíW_a½ûŒÐƒÇªòˆ· ŒÚaN;¿îµÕ$&téÀͯÕI$h–xÌhfº,!“Þ‘XÞ€Ïuœ­é¾v# ÝõW`‰—Ïÿá'*}¯ì;î—N+lX×θ¥!!Ñnð¸ûO’mn…qÚ»;ý–xÐÇÜ ÕeB=Q)«òæDnDü±Üx‡†© O 2{TN¢c¯ÂŠ&Nö¹ÚIë¨Ó}üÀ5ÅBú\Çn”âѽ-ö‹«Ø ¿Î¹w%_Óµ5ºêÏÍÀÏ5-‚ƒìÕ N1{Ý~§ç"˜ ‹ÀW…bK£ú¢™@ðZ¹Gè³bKüÕZzÐ[<œ4/:ÌkçµÚƒIs±¸^õ±ðŒ¿ÿõ«­æ/ÊX¬*•ù®Ö0q¢5¹M”VΣÆ/Ëà%ÞòÛïpó˧zÌòËKqLý«|ydXÐòY"gÕ‰„,Žs1(Ç"–—`$ÍšuתüQÇ»RMoÁÔ”uøt¼ «“GŸgÕB*)X ’Žøùòôx +, +endstream +endobj +496 0 obj +1859 +endobj +497 0 obj +[ +498 0 R +] +endobj +498 0 obj +<< +/Type /Annot /Subtype /Link /Rect [294.75 521.90 402.75 515.65] /H /N /Border [0 0 0] /F 4 /Dest [622 0 R /XYZ 72 627.40 0 ] >> +endobj +499 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F14 830 0 R /F15 836 0 R >> +/XObject << /Im47 848 0 R >> +>> +/Contents [500 0 R] +>> +endobj +500 0 obj +<< /Length 501 0 R /Filter /FlateDecode >> +stream +xœµZÉŽ7½Ð?ô9À´¹7 ¤ÑÈÑÀüŒû’ß‹]EV±Ù-ãÀ0¤‘HÖÂW¯–Ö·“žTþ§'ædò»Ïo§¯§Ëëéã-Miš^¿ÔÞÏ*Nvu¯o§_•2ËoÓë_uAP³6mš•†>Oy©²ð¿,ÿxÓ¾;:ä£ß™Ïùç”ß?):À—Í +>ÛêÒlÜ}Ñ´|q³‰rùBËWJ˜_c~]Ö# |öŒß]ÄqÖøÙIñÎTñn=K< ÎLe¿I³›ò ¯LyK6€k|1«Èò÷xÁ¿÷ ¼YÏUÒ7ÜKgä}Zá«F ž—åë¼NãzÍ\SôˆEÞËk†Œ·sp“‹³‹“ aqzRób¦ïž¾üÒ0eÕT‹Ó°tu]Ó÷WGë88:X3/޶Õ̽ú‚æG|n/T׃X½¾×iuQqWÜ^WÙw¡µ½‹‚×ï}i5¥9…‘-ÚŽ®Ï¨Ç¯—®ù‚®Zð;¿ê^l¡õÏ bž€Ÿ_Ѹö…AÍ6¸U(Üå÷´ß\ÚÚ¢Ïõ#]ጴ][Îélý‹,»B³Úz^ïÎPÈŒdëõ}4~ºŸ ½m,?³ï`ÿ +w»D ›_:TPÝ€QðµÕ;œ_”H ÓŠÖH¦Â‹W&3Þ{Å𡯘ْ̙¿·ºùì5i]oèï{~«w,ÔÕ)Î6}+jvÅtEšA•¨¬»­"Ê÷ ¢=´€ÁÌ3 Õ$Íê×k‚ʇ%ýM~šö³3Éüºç*åV]\Œ+Ôà"i¾7¨w@ÀøÅñ­Û3‚ŽOjŽ‘°«ìN®»©û ËåŸt«S¯(3t˜#'-c[ê…_)LFú.™%QÝØ°ãXH£_íì s«ÔÎi- ©ÿs¼ 7`&qaKÀÚºŒh® {žŠ‹/¨Î0¹ö>Ÿt7êZÁóÂ`xnaöÈ o—C¹cEÎÔw‘ËB·êÚe¡GD„Zu½—%¸n<#&vÝú‚—|/91·hY ¼¬_/´¢ÎWPâ¸àû[S‡‚¸2àss—AdSoè’«$U„LÕMf…ê÷í×x¯³ô†ÂçìU[ +»!E’Ò7Õ²A`¶0z-¡àØzÏüÀB‹£ +cÚ°LÕ‡¡á!4¨ïsÐG"–kmWeITܪ±u+íE3Õî¤þÝГTãô(M‘'ÐdáQ%ƒTî °3£¦o¹n1W)¥£Ò¥(´WPz/wáÚl¼gY„÷åfíö0Gô¶2ÑÚAU+°n}K’ucîðó±Ñ6 +ILzmõ;êÏí,ós\W›«þ,-n¶Ï5kËsŒNг¶ƒž$éP~ú2ÇG§CØ«IÅíðQ¯B®M¢ÑJô~=õhÞ`ïW{DzÃÿ=¬ŒUf×l“ðZŠ>‡:“™šŸY³x·Ì—8ßæ"½å}#Û:ÞV}Ge‘Ñú÷À÷ü.õŽª£DM e?Ñï•OßïFñS–x”ÖY9Z§$æ²(.DÚß'ë<\9s¡‰œœÞ§Ž„Iî³;ûi3ãÚMï;w×ãÐ'!@v+Ãp©¬ze%¸¿–a÷Œè +¯Ò²­ÞmR$ªT’?#>í1-u‰°LÓÅÙVdøpìC‹>ÇŠÊÈ*Ñ”nS¨ãEqþ„l{‡íFÀ\–Ñ#†¯ª?ÚQŒÅY‡ÔU:£NHSu¹Å‚G9Y>:hYðGÆyÛ.ßhÐC¨c«:4S§yzyO]:¬Ccq,|àåk?º¥66ïg<¢#ÔBã(Þ¤…bS¬Ã±¬†b€¨,Ο¾­¯0»+Ãøì|Ôñé…‡´ÞŠ*™BgiV…ŸU >0¦…7¯¨RßT0œƒÕmúM¡šßƒ$2]4MÀ.RÉZ6_©¿Aˆ–[€ÃM¸‘ö«Õ¤ÎÑÄhÓK3ïMyœì*ŒwP35ý+ÁuËÒìƒ0“58æ9ê2aN (GÝ&ÙÎ[¬2úy ¾ nî0Ñ.e§ßë^%‹„ÒXT·“³å…/V¨týÞ~’ƈšÍ°+©ÓÑå½×õh®pj“1.É¡—öº4ö9+ÉGØen¾7ñÖÈ,ü =‡£žæì}SÁQ n&ƒ}Üú&³TçæàÚ£…ƈÿF8ñ +útÌþ(TC"giÊàyLÑŸG.U%¬¶­ÕÓ½ŒÒxÿL3š¾Ý"Ÿ¥±d=aHSp/Íô—x'ͯáRȹ«jÊrŸB’¨Þ>¼<´Î( +¥ÜG¢ùØ>)".p8“ç;/×¥ò཭Û> +/XObject << /Im54 850 0 R >> +>> +/Annots 505 0 R +/Contents [503 0 R] +>> +endobj +503 0 obj +<< /Length 504 0 R /Filter /FlateDecode >> +stream +xœÅZK‹$7¾Ô¨óÂäè-%CUW§Ù£—þãõ‚alf.û÷W)B)ee·ËtUŠçå÷‹¼ŠøO^¥[V?}ývùór»|ÙÖëz½¾ý^WX»ˆpÕ>­{ûv‹0*.øzýIaâcããâããâ³þ|}ûã¢ÖÅ\#·ß®q‹2u‹ŽÏ->÷ø¼À÷x…ïs².Äó]éÝ ö"¸O +ø+ËyR½x¾Œë$¬—6ÓG©Uä? +\Åþœ x˜tÀ`b8°ÆJ¶‘1©lÛ+W˜KïœÞº.Öqz+Zçõ_6i{Ë ³f:©®ÿ½ÄÏ?.)±Eúm`{ž^×K½x*<,Õ&/{}‹NfõâÌÕ„Äšq.ÑÊ»~üûòû?Ð ¥¸F¸'z'ÒžÂÍZ¹‘·¢>é G†ºŸf<ƒGIÝ ×bÅ)…KÊgGVZÊïä—R.Ýòfüìi7âÑ„—  ¶ð£Àcñÿ*¿¾|ÎNƒ{czêNœÕ—ß•kŸë>ÜóÝïOüd '^ß öb´¾4šyŸÝg}xžô¨Ïø7íÇ=žÐFšw8ߪîNë’ûlñ*³.Ò¡Íš¿¬$`ï{ž¤# k’ÎÑ1®‘¨b«â±{}åu7Âûÿöè«im€ïHƒëP¹XÅ•¨dUâ6o œ8×ÍIPaU騼;±•'€Ô½¨Î¢¢EáÀ +5¬3A«Ð²5 P K€í°(šŸ\] Ö¬Qœ¬åGg)‘ ±G[Qæ‡B{Ÿò"Ù Û ´`>±åpw$ö²Ö˜¢óÑ,nïÍŽp[ ËÂ*eΰeêÇ”9ðµ‘oiI˜ÍkÑ$„FڗƆ+Ø<XÝ)j…5=(Û}×ÌmÜ>Ù™˜Áv¢·Ä‹ˆ¹¶Ø,eA,L#Å+ƒœj¼d‘êÑ\Âí1ø9n,Ö +¡µà;£”\¿o£ó]êYªDëéûeìÞ›²Fé˃·Q=mÄÆz+Zûñøð¯_êl®JÇ0¢J…Ǝšw¦’­•_õ¿„påtÄíÏù§R‰kbë—R‡U/ß)[Æ3 ƒµ=Xwqn•¤@ª×ÇÒ¤I^¢˜c‡É°·GŠ7â¥Ä›Ž%zR < ž‚^ƒ@ÛLÊ­àŒ¬’z•@\f—çÚ«¡Ó¡¦ûTG°£mX:â¦úŸ„Ê¡ŠökÚÏíÜáIá±K>g0#òñ$ÂÀƒ å^õd};ïE +¹Âø¶õôÒ甃¢&ry¹x÷<Îdì:ƒé¸3¼á8.§1£‹tÙ¯1ykŽ~}Ò® c Ûõ]É4°¶×èï/Eƒª(2m¸?‡úæpжS+ q#Y k\ò¬˜#ìŠYKÁVÝñp–žM)BØõŸ(v©cH;Z5ÏX>¯Dïéz• ihØu°]ÝcküÖ¤ˆæ¹‰Iq ¦™ÒAš4d!ûæÞ)À ŠvÉ€'‘x5+Qóq²TúÚ–²X];ñ(ÚevH .a‚DIºÉ2ãZ ƒÝ€Ã•:L8œ0dÞÒŸ„ýNß]™ŸœÐùH/¨ºbìtï9Hµï…¡ó½±é[Y‰>‹knb7‡ p•åǵ¹ :BêbÛGK†ÙU§ªì]PÄæ¥¤3²$Ê]G›Ûräz*!7í(›HkãëŒIY¯­‹ÑBZ¬ê¼¡ÄË`ö{üª·¬Ä+HW½ãYëð΄yþ`b„º¯ôÑú„‰Òöó‹ACY«öØ=«ÎMZ»¯^aÌÊy ‡n™|Èp‚^%0ÛtXå[ïÌ:c4{OƇg¦FýøUËT7ñƒÛ¼z+Ú®yŒb)ÿqÎUg5« s´žÀ¹ò6… °Sõ?má_šbÅ•/1ÒÚ”~\‚.pð—'Io†° PšÏA‡…Ï’Ž"õx>ïøý +-ð†ÂU»ÆP¸Šbº×Æ +Ô8?šô²Ëü›Ž%É5Œ¡÷(´F¾ªÕ‚­L»dg$½hWox¼å'=ÁÙY!Nç ;½)j2Î&øÅ«Ó鎺•ŸŠ•Ÿ¡øå‚Ë×ãM†qä)—Þd ’Þ°ØÓÝ:Ìï´¥€€¯3,ï‹ÀlG ‹6‘€¬]9šÿ+%S¹¹›©‰IÖ¶¢¶³)¤Xcm&öó¤xÿÈØ¡Ê tµmrÕ™fH£XîAãH(ÀÎ$V:¯Œõý+en¢0iÇnýü®¸K°>u[ÌZ­-,]A×FÄ Ýú†4]÷AíÞ*“âåœ^ÈÃF̘™kÜL¬i– +nö¬›Ñf¤üî¥ Ÿq€ÒmV?Ì£Û¤õ‘«j·vk-huך¯©Lõ³ƒ0 8V¸¾bCÒ8c®aÙ­Ñ­0iÍÙýV[©É½ÞÀ SÝ1S½ŠÍááå°v}V­“i^XÄ:³“Q³´Ø½¹ ÷l˼j‚'Ù˜xˆ­‚ãăJ8NüŒ§ëuÝqE*Qìˆ]zŽ+“lÏ•Ò}òVˆK¯7¨!LbSÆÐ.„'G8mj5ëJFƒ±h¾û–vðbϹ‰H;f$š™kW‡øÑ$ƒTà߇g¢ÕG¤üŸŽ¸fÝ ‘ã¸}™>•I»{‘þ½:>Œ> +endobj +507 0 obj +<< +/Type /Annot /Subtype /Link /Rect [72 683.90 147 677.65] /H /N /Border [0 0 0] /F 4 /Dest [511 0 R /XYZ 72 627.40 0 ] >> +endobj +508 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F14 830 0 R /F15 836 0 R >> +/XObject << /Im61 852 0 R >> +>> +/Contents [509 0 R] +>> +endobj +509 0 obj +<< /Length 510 0 R /Filter /FlateDecode >> +stream +xœ­XËŠ+7ÝøzTRë!àö² ò“{fÂM~?*u•Tê‡=‚1ÝnKõ‹vrg–óÏ!ß4 ËfÏÖ¶ù¤À=VÍ˃Sûå—èµñ¨0_c¾†Yà³ý7uâ,ŒÊõêTõn–¥=ÉB™©ì‡¤Ü%Üþò–쀴øˆjf•å÷™D\è÷¾X1šU®î#q¥½,#ï3š®†\’—õ›¼ÎÐz#BSìˆEßå–!3ZåÝà¢rqpÞ+‡g­ ßßaL9¿ *‚ŠŽB§G¶õa …¾¤$û +ä;XòýL6¡gò+?7©í7— +ŒB÷3*÷5X,ˆŸDR8|nI ÂÈH×CRÉo¹‚(ŒF¤üœZÑÀ$jylz¤¹†‹ ¼ˆä•ld9iƒ”Q +%ÍûŠÍa–[²0‘\Îë™ZQÕ"FYIàKfòH¶ô &4¹À5€§9€l¸tÆ°ð£øŸRÈ—°âûS_I¹úsûVT#&ò:bXÄ%%@í4ÙyJ§’UlU_:<ÌÝ —/÷5÷Òýî,Ä€ µÙ¦uíP–â&Lï;ígËÑ:­F/#ÙÅk`¾bW^ÖäÿR¯.Û¤ :v™ÓDApQÊ¢`'ÂǦAab;âô ¿£l}P‘RaUOûE&÷òÿe?7tnàÜTV9[äv¢XpSñMƵy]²wôhšZ\ƒ\wÅ^.§£X'í?¶:ÞŒÛfK#Ǻ„¡Íœ±›9²)ˆ o)ÛKD1°` àð²œpjûKaM3Ø,Ó+º3w×Ïhm€÷fefVùQo^Ã)×\èkûLy‰Ô^kGÄÆJ^xÝõABU\D jçåô™ Bs +/zâ9ÕóXȼ{ÿÆ­:¬a¶-ôœöâaµbñ,B¼¨S㙪£â‹ƒ¾Î¥}ú³€Xv5÷Yf}c†…\篱OwæW2ÈÔšØþ²ä’Z·1|!×idˆ˜Æ7™Ÿä Ä;"/«p$ÝL”9‚Çn©‰ö6œìÀ09äùë¶GáFlñ F‘ª¬» rÙ ±F€ƒ"I —×f+ܠİ +v[Ù=÷9Éø7†&—+ÎÙ`½èC,Û‹&°Ó×àØ²Û &0‚¹rUïõbç(áòUý÷X¨‰åÔI’ÔNÎôû, +\Ä£ÙDƒY5€­x2ÑyË1pã= æsj%Ÿ<ƒõã +#àñ¿®h¡Ý)ε‚o +¤bq>' ¶dö,Ûä~ßïßuçõ@5àËK¹É6Í7‘zA ’ò‚ôï$“ñº;-ìëJEDÇ寀ðÑúÒòÄ©G’”ø„b¯YO;ìôÀ o „óe5m™-Y‚ØÒ´çOõùÜ +¼²ñ%›½gûƉ°B„õˆã­á¼ï1PŽ`|„.z9^œkÛB=Ųްö»Áõ1&;›$VE< ++“¾nøVOÕ5[¹uVÐþÕÒÔ|©lÆÞ?}/èVŒëš©ÉÞjªüòȰÎ\ÖÁ˜–¾Jlw~Cn4ø*wÛñ¯LKlՃ€À/%âkI¯%ƒ·x¦±xyFâœúø6ü9¼çe»‹òSZôþ„Ïcñ2kÌwó&—G^oO/¿¿y3œÿ~ú〟J“¢( +endstream +endobj +510 0 obj +1454 +endobj +511 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Annots 514 0 R +/Contents [512 0 R] +>> +endobj +512 0 obj +<< /Length 513 0 R /Filter /FlateDecode >> +stream +xœ­\ÛŽô¶ ~‚}‡¹.ð;:ÛŠã™\·Ø7H›R ÿM_¿’LJ$EÏ©‹`’Ýu¢ÈäGzþóaO&ÿcO6M«Ë?ýöÇÇ¿?¶¯_nëi=¾~oOÄ8™åäçòÜ×f2Áå~;ýÙò'æOÊŸ9–üYÿrúúׇ[§pÊ|ýý”‡¸Ð†øü9çÏ–?øý +S|ÂïÇÓ¦%¯ßçµ3›÷cqŽ<Îø¯Ý׳æËëÛüœ…çm¬óã©]Þ>p;ö²Ø‚‹Ù,^ØÀà̸¼Œo›$·llŸ#$Á†ààåÿ¹þß'_k]§˜ØZveñõù_n6Ê[5AlÓºÓ?òÏ?? ΰ‹Ä”¿)za–)-oÏ[?ÍD¢¸ŠÛ/öó++`ôS +§°”­…”ÊüYðyÔÏ|üþ§®¡Þ(*:[™»o–yY¶*€\6y7Í d›ŠøsѽÝü´,Mg­ï[C=„çfx¨([Ší©¸?é¼Tж\Û±¤¬9e5NÚ®óm´{s]±ÏdW çÁRÈïÅ*Ý®øÑC·†o» Ûv5ˆ“£†›Ús1ò`pƒeÊïëþ³ÛˆÝÍû8‡Q„Ÿs–Ü#ˆMp¾y¿_z,GmE +mvå/qByÁDtI¯õBÈ ÉxUÒÍL×q›Íl |–ަåÀUQá,À‘"k{µ³Ÿ¢SN8¼ÙÅõaÛé¶VäÙ@;îË[ßï¨ÜWýýö80á2@ çå \¹’³3k悲tœì‚„ìs€zŸ÷m¶‹d[äëä ¦  ]§á„›A˯ ½ž˜BšÄ^ÁÄÒnZ¡õö>,2 Ûö!¸–½U›PüìèùPô‹xÌO\Úk‹'\B@Ù‡ÌeBřԟ\ð0 NE“®µŸD¿:'HÕèÀ9Œ(5 2{•À[ê-ÜŒÅõnÄ78ëžßø­¸¬wZŒ¯z3ñ®+ë‹ÔšE z°+^ „DSR³ˆ—|[޼“‡Úg³DŠckçë©õX;øë&%/Jz»¦|TÙn{¨è:Öî,šß +‡QÒ¹+³jÒ°G|FWháSu¹TíÀü “YWâs‡Š»²jzÓýž¡QŽ÷ +|É`ý® k7Žê5ÎÝk <—9›Emx7Kß_“73jñ ˜ÅY¹Óz¯ æ¡QÑÜÇïwÎï(§l‹8owG(KE®´4˜¾˜C`Ó\Ëÿ£ÿ xg¤]„ì@ûþµ;ö¶Ø´<³Ãƒ=%kxàU]Lp¦›aÑ,ÓDôÁ“çœÆ¼?_µ ÈDe‚…@Ïþö‚`ç:‹õ´¬ #«è$9“vßu-œï*÷©ÝeáGÂh¯hW"ã[—µ¹Gj)u¤Üm“ó ž»5”y%±º€rDy·ÄþF±¦až—ØMMðfN¤Ô>_b iþÚu¿éy"ò,kb¨vÖím³G B„÷L® ß‹±›3Ð.Ô€r#‚ÙºQ¶Xš8®añ`Zem͉>2ìv¹Ñ0Ð=4ª7¨ŒvùÚŇlf™¢2/À“Œœ·çô¬ î  «]±ÐV’bbce’´°‰i£š-8ëÏ`w»ò™B*ÊÓg"냥v/ÑCäòsX…(žºr3¿ »rî!ûVÈZþÑy•:`1QN‰Šr×!>mн7Æÿ©¶F&ônpRø‚ñÀÞçtv*t nÅ1‹Ü?ˆ›ë"¹öãÔÛ@•'8n0U%˜™=šD‘fsPc@Œýt4"`A‹ B ":‚.¯^…¿†øŽÁ‰Ý‡8ífçCýúaÌòD?ÈcAp…©sAñ@ê€|²›süK7/ÕÀµÍiAfæ¸]bÿCê=¸uÁ°æàZú·8RZŒs1öw8ö¹ÍIrZ<[&™ïÚ#C…-Ì:›°¡H6¸=_ÐdƒI‹D{fœ0®µÌ¢Î9xÀ+lÉr4ÕFâ>ðj’ä]''Ôªd£{åƒc­z±Á=Ôø4XNéð»Ö‹ìÏë €Û龩È6uÖO³Äª"L’–?Ìe‘yÁèZ'&8`ÈlšÜôNˆûgíU‚Û¨vZ‡£’-ˆ£êô­à¥ý¨ ó[~—A7JL x¿®%À‚oçA> ^êîû`F 47ò6[¼£á`¿¶$RlQnCÔ0›oÕªeþ f>8ÿý³ª•ò/ðwOþˆæo4߆0×»¥–Þ™4;Né(™t¡4 yÁÅZ–iá똅ª^G/ˆ³.;ºªÎCÑ`FÇ~'Ða‰¹?RËeî¥íW SÝå ³ú·÷™G¸Y³ËãKÏ3ËVtHÊÏI®)t6Ø"ŽÃ+ÁÏZ»[¡C÷D¼XlÄ&Åú Fç(§w4÷µ_Æk‹›tý5"alÀ1ÅëÉòŒ&°í…ÚäÃÔK;¤Á8»S“Ú8§\D[M,µKr˜_ìMUvè؇³áä"u,8 +«JÎÔ*È"ߺÁÈ{3¸LQ﵌î:„u8|OEaxÞ+èiÚ•c*ÓÀ¶[äNû†}iGq }ƒ„É>;ñQRTŒšœ]’Ûìy´ÄÛ7Œ YèóT GÍÑü•œþNÀØ&K€x­­;½ÚÊÃhÇðƒ +UCÈ ê}¨]~¤G¡í>­k½Ia°Ñ—XnAë!ó Tlí8éÅ=Þ±E©µAË5 ÎyZt£µÜ3iº©;f¬ãqF¨w5‹)ü+U ŒÊY¬u5©jµ™>ºð;Ô›Z²êËÎäç­ûÊ£V‚﬽ üþµï QG «Þÿˆ‚¡âÀC5ŽJ»g»@¬òƒõÈÂÊIæõIxoÇ3…7ÑíÔ‚¤™8]èXPìð%îP;0ù‰xÞ,sVwÎ]³1ÅÐÈ‘\¸ñÃÑIë#Öy@?ZÍEè‡"RÃ0ñÚ[l? „íJaV0ÝzBS娴råP爿¥Æúb!zÈ¡I1H+¢ªè-ë,£0AÉÍ\Ä4è§V—òy‘£>2Rd3¢uÕ5õa4¤¤ÒrbCæ>èÙ;/ÙÜ‹ŽE8jÇ4›°GCÏe?|µ6ñò ecXnä¦4i–€Ô;éΗp|”ý¾S]{u‡`ǵ™F¾°ÿN›hÚ8/$Ä0´t]ÇK–œY´Ò—Ù~þ~øÛ¯4/ºFWpž†ò~Ãp•p©¤õl"ÏZ˪ÈÝ/*Û~ßA§Óã¸ã¹°PŤB¥Çó¿wzÜœÊ1ÝiòîìpÎ^0¤Å‘gò73r´­fîj8O„~õ¬›Õá$¦j¬HZ|!KÙ†Dn5Ö mZ''ÆøÁE¯Ý\iKY¿o‰©9“ÄçÎëÐ pRŠÈ(Íx lCh› QÔVj»ãqžéhÌÈøÌJƈÃ;ßìXmoõ P“*ÁUh7çKÖÌo:Íå¢C/aùÎì±Ô‹S;`}Ö BôÚð™W +V{)Nø:Wôm˜ÖjžŸªo€‰l¿ô¸Ó¥ ™Ÿeé!Cvæ^¿¦_…dî¶k뽦1•|šN’¿ )æ&DÙ;f…W"ÝDzs&•°• ODÖ¶R²û^mN— ó©”¼F-áåBeUôë²pØSr”•Rs|`Þ*i¿¶õnðJÓ½9+ÑAƒ‡—K)ŒGÙéëAX½_¦‘оO*ìKoîGGHX£ ~„|3AJŒFž¹Â;¹å½lp®o¿õóÕV—ÑLe„„3F¬ ¥1o2¦»-á!X”MïY7&keÞÞšá(wGsC*+ —ä›äwÔTÆÕ޵Œ«˜Ý]IùV¢¶4ê—ðÍpP½ñö@8tu¦–•ej_jQã?‡g®/±¨ Ð_W°«…°ñ¹—úóEļ£ý(}:úÚñN&>ÈC¥sùf Ô:Ø«: Ę"?¾@KÜß-97å Û­†VÐWJÓ¥O¡$tsflU§ÖE4XÉ›ºS(o•Hõ¨Í]ÒŸ*ý‡Öu@3v…VšÀ"‡6m}ÿ –‹ÁÍë ^/G ÝÒO`̼Yg]r @vd™½ M̳<ðµí¨¯Ø¹ú–‘X¢[×P +ã, n¡]†PœRê'Çä­¥@ÐsæCô +ÄI¿96r6[—OÅ=ØD‰Áf \?óê¬ÀÈS„àŠO!ÛìOß ã—{8Ÿ!UÂfàßzð„‚‚§…´&êÚš»DbJÈó½÷w—úvLßÀŽü©ï¼¿ª',¢:&vG% h/-¸bAòg(JÇíIÉlåß~ÁÉ +´>G¹=¢˜Ì¤@ìÅè[@N+ ÊìåùëôÄ­T'‡ýíUò"°#F"µ†» ,Ùœî—aRÒöJëm´>v¯¯„¥ôi”/ÊÅ:°‰£/¹¨,§gÀâST­M—ÆwªÜP0|Bƒž|ë´ä÷†Å~ÏÄr}#¹µ,Â\G•C¦>ü>ýµgcí¨±^ÒÓë£Mô¢ix§“¨Äƒ´tsF§HQv‹úÚÏÊG8å§R]£¾„ÕÑÑq#ZV_ú=@Ä™ ´‰À§"íPƒ! 9ÜLz…zޝz4ÔÑ…¯ÙáP‹SžñØà!Õ*hW¢Ø¾ßƒœ9ÄêùÙ¹žË!§eXç*ë«¿c£f»{ÆFÛ Ú™&› Ù´?¾¿OT ò<lþ°›IÆÒõ #Q][ø¡xmŒ¼Ý½´›ƒÐóírWõe=N ºeOñ?qg%-jÔâãÛjó¦¬oh(ì–Î*ÝH×}¾¡”}íØ£Q¾màŠLéºäen¦½ˆÝ8¨èÑäâ~“¼©5nö­äý+“‘úULþŒànºEzЇïàÀ²V雉ìŽòÍ+a.1.ÝÇ˽Å$in[u**ˆ½˜þ²h8€¨.dbÃXe¬e§D5wÜÌLæ8àobíî¢Kž2"•F|º¼:‘ÉÙ5ÊS;ÞN42)%¦4aÜ®®Âúa»¼èK¹#¹5„ùüúøëÇÿ×÷ê +endstream +endobj +513 0 obj +4041 +endobj +514 0 obj +[ +515 0 R +] +endobj +515 0 obj +<< +/Type /Annot /Subtype /Link /Rect [110.25 281.90 215.25 275.65] /H /N /Border [0 0 0] /F 4 /Dest [598 0 R /XYZ 408 355.40 0 ] >> +endobj +516 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Annots 519 0 R +/Contents [517 0 R] +>> +endobj +517 0 obj +<< /Length 518 0 R /Filter /FlateDecode >> +stream +xœµ\ÛŽ#¹ ý‚þ?˜Z]ëìv{ŸÌl²l€ìK~?%I‘eW÷N0L·­Ò…—Còˆ5ÿyó·ÿñ?O[Øúå··¿Ý¾¿ýôØ.ÛåòýW‘óäÖK\ʸ�¹ÉÅ´øåògçü‡sqþËåû¿høœ'?‹á~Ãá.–¿uøOŸÕB‹S ùpùïÛþóïo'ÈõaW>ëwº¤)¬¯—¦áÛƒî" ¿îoûß÷ýåßuÿw…Ÿóñ¹›iýßïß…¾ûKŧ”ÄZ)ÐZ æ,óÁ\n«Ï‡mÚe½÷ï—ý‘ÄiØëïw˜â~O;¯ûúm^'¥ô€gqŽr4ÿzI€ùöõ}Œ÷ûz~†uË>ÖºÞÇ÷ݸrœætIë”ÖKšçi^/ßÜ´„ËïÿxûõOh}Å*¦m–z å“%×/Šô¤5ì¹þ¡­Îݪ‚JÙæi—(›vò+ ¢äv e"Ö¾As!íÿFüæ&p© +±(?{Àçë1¾üHcïÇg8—‹M‘ø9ÌCŸÃ3u? ¨j ø}–óñ³øÍ°gkïx¾y°— ž‡ï Ïç{ªJ1O«Ô• +âË + Õ+Mˆ!Íëà@åþÖ„ð€w84? HÙ›G»Y‡nGž Þ6ø Çg¦¤«8CH±úËàí˜Â"K‘ l5$ˆœÐF™¼žv>à1àΣ‚Å¥ Áh§†{ŸÎ;ȨùÈ_S)òMmU­ïL5«# ¬x>²¦Öj[ó_²ñßyÔ€i~qf1iýfžr9/‹¼Œõ[‰ ŸÄØöÐ.n +¡á½‡¯xë!$„'ö"-ÛÏiÊÁÜ¥)N¿,£Ý‘îmU¸ ìv0®ßMØAi³vãW5n+)‘ÜYy¼"ÁEˆ€¬dn¢Ò>[-p>Än œ:Ë›ÙaÑ:ËZ¸övŒ‰þœ•8ÿ+ií$µ¿ºè{·VÐç:Gæõy…íN¢vb+Ì税¹+l>£0Bö7¶íóCè…ü¬!ùRRT¹‘,ÂbDzÜ4¬ÃKÁ¼¸‚Ó]Ý—C?„‰Ó ÛÛ +Ý¿€[ˆS*w¡ðyeZ¼$-ãþº|ÂÀÒyÝ +dt²æŸ”zSvòÌ üL=äP à7’IY+€áTCCóþßÉ‹e 7ïîȎȃ£<^„*ž•<ž j²²Ðïÿ„þöss§«&Äê´|ñ׺ì½w—x=#ÝVbÐJ¾n,YÀ^cì)ÆQc¸KÙÞÏG­AÛÛ¶R‹Èí­" ɽ²Ia +f«¤´×ŸÌñ<ΧN)3¦z<¹a‚'ŸÚBä-'22iÍTÐÒp<–£ÂÓ;ü\ŸØ\½ç¥™kû[mß%u¸¤²>’A´ xv%"è#[… ÈÀš=È;Üäs˜Ìa¨¤ÊM‘› Öðåâ¤ËmˆZ­'n†í¼7ਟaÔñJÍ +WGÁë ’˜°³+ûÝHh){ãòÄŸõ |™™Êk\ð¾S¥h:.ç+5ê"À1+Èz¶ÖОûÑ@¸½!{cVzf7] ƱÌ>ôïrµÎDå¶ØÆÓHSçþLDH0xâ6…™ùßÜì 5‘+rØRç#ù–1J×.Mq–ÊŽ›`tî#c Že Ð^ÍÓŒ 3£ÉG”§ü{»øTiºŽ‹ÍëZ¸QÀÖVJÔ¢vuÄÔU¶N%EaJúù…lÝ$2»9|šKü‘³¸™'æQããHÔã‚(š~—yî~ÒÄ÷%¸Øâ‚膵ÆÎp´ Ÿ%,>R_|€ÄæmZWùTlý8Ê ø[ûpÙûqœ¦ú[Áßíei”3åó¥{ˆ§…N²òÚ­X°|¦ _AþÓü”‡°Ô*Ì%¢¼îqiîG!‰ÏÍáÙÊ«7eÕôîÛ…bD¼F‘¼×ÛÜÖê,Š® ìùáÆˆÝ$¨à!S¯-•g„ðå¶Ð³C†;zw+ÍlY"åd•rIIÅ2Wi&ñÔcú‚%¶‡¦ÆèYŠ‹©éÁ*\NS†ÞjjІ‹1‡ ÷c¤W­<ùý Å„=Û˜ÑO¸Ø¨ÈôIù¼ñÞô£8 +Eràñk9MÎe?A£í!µ$íò"½ÐðŸ'5ohÕÇ͵2q ³uÀœp½†yu˜’€©ti'˜_Nâv–ý¾0†¥äõ¹xüð{…ÿ{S]XÙ V‘=¢Jߊ@†”êßÚÚÌ”¦Ø›Ì©+âuì÷~ÈRïÓà?JÂÓJ&2é°5så„A‡’´+ò’cp«pN˜~Zg<ÅyÓgñÛ"áµGžùÚHÑŽ¡â¤p(ª!•ßT¢?…]´©3ÝtXiýÙázik–d?†/4Ë­TbÛÚ—[¨È?x¹@¥É"•‡\Ø©»‘GÃŒ¯–YZî…¯%|ã⤂×P A¾ñ¼Ä»DtÀ¹%HÄGÄö=Æ£W\A¸û16áZP3Tcœb މ Õžæõ…e{8Òòoåò}Q$ãí;‹ÉAÄ ¦{ÊcÑ)q 0®K)ø³(.töKåúô ¾`ÑDŸ·C™“Æe⢔w¨XYÎÊ\8‡mµxÁaCêC¶çx™ßQb–Y„ZâtõÐÓ¥ßê{v/ º].¨£Å—ˆ ­¢Øj\¡|pA{ñ"O’d +ϬI5 t¤¾YÑ„f[YZ­°pëz•G-=æÜ~v‚¤¡Þ_‡Ä²´)WþCÁtÕÁýØ0]s¼’9ƒËy‹%¢MY&æ+ÄŠƒàšÈæòj<:õc(Iå¸¥Ü ! +\©¶Œ˜5æÂO¯Ö¸{cX(ðZÆœÀÊN˜ÁZ¿ºæª!¯©–¶‡z®žÎ}87e²‡((:Ì0übœU§Ëb zß¡$€ßEZeèÖ hÂnÝ%‡’a~P{½.ïç +HðZ€ÓÏ«ŠsÍ=ĦNzP¢xSÖÆXRÿ,hi¯mš0,"®›uû> +Nñ Á¨Si^u¨Ý°Zí‰û«òT‡HÈ¥`‘Gn¬ô‹ëm°ÄÐéL¹ã×Tð•°¾+ºAÔu†Ñ»ˆF×BUìŠäªœì@²tॅ-t–º8kHYN¼U†MLl±gºÁy)ý© |ÚGBTœåh?<Òp² o›óa.ô¶X(42µY,’ÎvÖ4%ìž÷%DåR5·Í|“ý㫹r¦Y‰+[9ÚW±Œl×\Úæ §Wg-äpŠÃõÕ<ì ]q<¤¤6j/c;›•ÜòÂbÄ©Rðƒ9–ÂRjPçéÚ0» uŒ;Ü®!…%Ïž)wŒˆ‹ìÐrBr øÖƒÞ¾ÕcV+†=±–B }Çhoµ1ï%é/ÎИcjT8P@¢¯ÄÛ`A¡6eÛÞP Otë˜lžL,­,¹÷¯í¹_ò*À€-T¥ºoÒ×Ü“Ÿà‘ZˆVm”©"®^;.Í<ZU.MŠdî@©% tIèM*_§Ö±,½i”³×PûÙüôÁö0;Q¢ó=|¶ËDÎo™O\X×EâÐ^×A/¿:A­¥Å(q'Vœf±¿†uNdcTÉï'ÌÇQ~ö¤óDP¨*ºó« ¢—GÌšÝùPeº+n“Z²º.¥ëj-%Þ•C)žÊ7¿R^ \ìbOarýqy(_}u\ö8“ÆÌ¬‘í­JG¤‹=]OH.0ØÖÉO´\„-N:~¡Ô<°W½VR·êªpŽÞÍò(,xG«Ò݃󵢤ÓVß„Ùááž½‚fßÀ©–ÌZZ–W¹ÈñŽs˜Ç ¯å¨¨¢Qlú'rsq2 ¡YÂØ5³ûã?ж§™ +îñÜ«áñÚá­–’'ÏIˆd*å4V11>ÍhÑðuÖí‡ï©]™ß°»\½½3àÙ8–Œ!Ûzdá’ë%´ÐèÜÞ~¹7›‡[î½"[š|k§ß^¶Ôtƒ/Û÷0XTU&XΗµÒ¸¿8T‰ƒB~ßÄËË¡2Š·{àY„\ˆ³œÙÕ°£¹cæAeFû›!J£æ¤ÖkûŒzdõ‘öÕˆeÝ¢†å¼»TÒíîNß.\ ë)dxx’Ù³æ8•L”ò¥®Ä íý‡Í'#¶Ê¯kpݺä‹g˜Êþ806* +ÐÅýžÐkD{Áïf'²ù3îÏÙAäï)P´ì$d_@¾qAä'G[)1<,0ý½<ÝvÁ{t‚õäÝàÿŸ9rÿšwx¸‘äÙ~LØÜ·’ÔŽÌ÷4IV­lèIJøÌ™Ü?Û!!º÷ÇRߡЭ:óý‘RÇÌ·üœüS©o%Ç;R ;ÃÄíÿ#öÈ^€´cý߈ôU`Ä„×ÊZn®3*õ‡Ñùt²yuÇ—q¼-¥‰Tn>õ…•“É«Qùë œÑ A”@ø}!¦h"ÑE%ÅC°Ø‚†Uái¶ÇEüß­7dõ»‹´Ì~_e“ý¸³È2P/»Æ UŒö{Zñ¬9YÈ éü'X¹®±`©ÁZè."Mž}‰U_N¿$Q-Ò#Ê­ W¯¤^ÐA4Û;^Rkrس9¨}D²zY# J,c ·<𪭕¢;öCqìsCäeûÿÇÕÿ U.J„L¢UÚœ´ÓìŠã0SzÖ¼$ÿœé~Ú´žš¶e2.´]ýSbh‰¶–YŒûøþö×·ÿS<¶ +endstream +endobj +518 0 obj +4022 +endobj +519 0 obj +[ +520 0 R +] +endobj +520 0 obj +<< +/Type /Annot /Subtype /Link /Rect [139.50 681.65 213.75 669.40] /H /N /Border [0 0 0] /F 4 /Dest [558 0 R /XYZ 219.75 769.90 0 ] >> +endobj +521 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F74 854 0 R /F10 154 0 R /F9 148 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Contents [522 0 R] +>> +endobj +522 0 obj +<< /Length 523 0 R /Filter /FlateDecode >> +stream +xœÅZË®Û6ýÿƒÖ¢Ã7P°üØð¤Í¢@4›þ~Ijø.IK¶Øà‚¸²EžÎÍIþçDbÿè@åhÀ}ý~úqš§Ïw3˜ax|‹3„‰˜róßOd$섯Ãï„n‡°CÚ¡ìÐv˜/Ããàñç`—K˜g;&;.øùŠ7ü\‡•ÚÚO¸T-pï¸6`Øu”à:Û£€xÖ>µó(ΧÂã‡]ƒõßn8nû“3¦ƒ1*ÑAç°^,äTŒœ/âEXt2Û8Ð1Ç"Ñ!ܸ;ÏÝ–¶ ,lQ³óó?ß©Xe•³r“ÂðïÉÿ<‘€0‡„¸ï +¼ l”ü¹ñ4_rI$YAonøù·‡e¢ðØ\\\J·Ðf@Áðó¯Ó·ßU)l–d®J·ÝÑÌ9%߹Ȯ.ñŽ\wK 31<ñÎs^¨=wüNaþϸ6tÊÈ}OÇnm$®‹ó¯qÅ|ìsæä‚û~š‡çÁyµ^¥õÞw6ïÃó,àg>ùùa]îÛ„±Ùç–ý{Åþ%]ÜžÛSfK ß÷4ßï÷âö"NK:Íyæf¤òCž‹{Ïüõ1>g>S¬Ãw‘•XB8wÏÖZŒ.ãyÎ/x]‡¢â}Îö}=𛋏1`#¬ [Hx P–HîÎñl^FÙ¼‘È9ëþE²åÉËÔ^‘¶žØJ…6ÖÎɦ‹‹ä[H¨P4yµ¼p'Ö´ó«1Å®¬ƒC½ÏÕÍGËZƒèŠs/û€.µ5]gÕ:ceš‹×=5ÐP¢*•ÞèAÕÃ\íN@±©˜’=i\qßi¯iŸRp ŠœKP‘‚tpÇ·T-œrpòÁK‡Õ9÷™–ˆ)]ê³#nGTÐ÷Í·ÝatÔUCNV%iFÉQŽ(=‘I”m%;Ú>²>¨!ï%µÚKj+n;m)"·iMä» ÓK¼®XÚLlaÔ®–b•›ÄZ;Qÿ~O@m{¶c¯´½Æ†š¹ Q1z•¿ªÛA‡ÛL:esÔjŽká—…}Æ›”ð½ÁK éôT4IC/Ü%n›Dƒàò˜–]r>¹Z£Ž;À‹3Œ$9…òå‚‘(!/87ÜpÌÎ}u#ΚÛË!p DpÊò˜óLU{qxK‚Õ){/€±,‚Ást©¤…jÆëŒûÄûA8#ZÑSé²rv¿*e±T•îZ)yz¿(9TÁ1ϰvÙBŸ©é£½jÀ½Å¤ ¤“HJÈ;+=À¶Csß­YÚÜw¹N%!7û ×ìhXñNŠ¢ŠÜ[Pr)zm)"7‰Í…|A´¼B욥íÄæêW‹±ŠÈmb³Ý Ð¥m Ì[–ÅVk}ˆË5 V3UEÈQU€z´SnK²êSQkȽ*³¥¼Ï–r³î0Íð¹eïºS³´¹î0ÛÞwµ«ˆÜ¬Ì–rqláC`[’;«!÷n¨Ì–ò>¹ +ÀmZ3ý¾ùM¬.ÚNj0î5H@Eä6©¼à@¡$ ¶=Jñ…Ï»ö*@{ŸÎ„—òî³äùÓšâšCžÞÌT‰6Ô ~­×¬ýÊìo÷ééS%°YÑßt?}ªtßôT Üû›#XZÚóZ +ÜËœ#8\z[>½UAÂ.I'mREî-·À½$êÒ–r³/‡ÿInÕ,mîLÀX'Q’›€÷‘[à~Õeceà_õÄÚ2ê»ý…¬•lEký¼š'GšÏ¬ÈNi­¿¬¡—F4oÙRÖ¨{×ED&äfY£ZàÀ–²V³´¹¬Qe^П›b‘›eJê4NjÈ;‰ +áç©[Û*µÍÏti ¹Í?[êÞw`ÿ*–¶óÏ6¿>—j8üÂí­ŽIm+>B}Gœöbƒ<Ä\¨× üpá¼{ ×Ìîq·o·ÇéÓê•Wœ +endstream +endobj +523 0 obj +1500 +endobj +524 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Annots 527 0 R +/Contents [525 0 R] +>> +endobj +525 0 obj +<< /Length 526 0 R /Filter /FlateDecode >> +stream +xœ­ZÛŽã6 ý‚üƒŸ ¬WwÉ@Q žïs‹ùƒ¶[ Àè¾ô÷+ɤHʲ“)ŠAÄ‘)^)zþ¾éIå?=é0/&úõÛí¯Ûú~û¼-Ó2Mï_Û +ïg•&˺÷o75+ëò‚_§•ÒoJÙôÓôþg[ü¬ƒX®\®lyÕåŸ7í»¢ê6Òfúç–?¿)àëͪ\;jÝlÒã­Ûòe¶F,W¶-¿çך_/ÙÈòžò{‚Ï~¿®Â.VGø=ÿfüö&¶²ÆÏΉ½œi{9Yä,µÔûÍ2g_gs›ò-Æ k˜Šõû+ˆxƒïçbCÊû“\%½´Á½(£˜¦à]ƒK ÈËûëâX¯ó~:À¾Eoï\ÞÎÁM.Í.M.„9¤é“𣙾ÿ~ûú¡O§ü¢×%XÕ&Àå©E7û8/ÜmËòí’Úââ¨ûîW7²_·%úõaH™-1,ÅŠsc´š–y #{¬)~Øí1¡í[î [Y =ÄÚº½ì×Íîïœ)1û|‹ïÆìCläïFCÜ žu¯®•ï 쑯Y½ëWb]õ|÷¸Ë5q¿ÇÙnXYè{ù½~ 7ˆgØKãÚØ‹”ÉK,dC ÒB˜Xi¿¶7ø} >ó©Ä¥‰²"%<¸ J‘-$ë\\Îø‘çO%Ñt“úJÆΕ2RLÁOs$hQÂF¯#ÃÅF£ +J!¹ˆd"8åYr,IùÈÁ"vgA/1ý"# ÄÖ½° {Ü;û a:ü($gv¦é‘–>UKOšÖ@Ϭ”BÕ‚•¬Â”¨”èÁ‹ç*µ"­Ÿx«¾o´góƳtÑËï£M¦'Y#ô¨¥Ô¶ÝWQ ª)T‡J/Bú/>{Ä^ZÕ4›™$„l˜ÁË6yÍ„N tØzÁeÐó]´!¢u"?‘˜9QoL¹6f¹Ê•¯($G#ŠËgDݦZ¾ +’ëŒ7yͺD Éù€°+4Þ¡@b²úD>P:@QXjO fkH®Ð A°Ë¸–+^î>F!#Z:à“ÁÉñ‚f±P“ê…Ü…µ’‡½‘‡§ßFŠx´Ž® úÅнO‘ +’Ú±°™y}Õ¢ÍÇ›flþJŠUG öOñ2a ÚxÞÐö²ówu¬ÐC¶< ÌŽ€ãÙ€q²Hž9³ñ„,?ΞZÎÙ¤Õyw°%‡„ÓY^jYï5 ^«RiC˜Pì±â(l¹%6˜Æ:úÚUæOŸOèþvmíôDXðýG +¢éNƒ¦TüÏ­ð·¶Üƃ¹KíöÅrêÌBÛ`ê¡Ë‡hêÊŽ îüŒ)Ùý}ˆî]­õYzÒ·ð²Øh³Þâi +ÖBÐ`uÒl•Ó«ŽÏð =cš®ªŒb浌ÑX¬Ô"¡Ê«™Yl#ó3÷Ñ1F_TyL¶àÇš¶p]cî·æµƒÿ³¹õfjÄ#Ö™’ÄÒQ’‚‡ %©0Á¦Y)ûåy‹ß`=Ö/¬aã`î*~ÿ>üò…L¡Î„ڪŷøq-ŽºñnÛÔc>JÌ-† “Ó…ó9.÷¡ì˜ß¡Ë,ÔǘÆñˆˆ‚ØÇ5„´Á b%ª¬™ÐEMÅ%_¤NÚ»2qbJÉÈOë9ȯødL~|9q½¹wÄ0À‰†Dâe´}¾ËãeãpL$ÄÜ‚«½e]y¢Äïó™$:ήóÍEQç.©±¯Rsrƒ±š_Mèg èR¬#'£"æˆ>x›—RD𑦹+ì¹mÎñü/‚ݽƒìl•‚~ cU§(úz‡¨y|0ÅšÅy7Hf;raZ‚8ÛPAÏ×S·T\Ý¢x+y'š`)@—;!zU²du(­Sd6(—íTiKZ·¦²ªµìÏLª iFËE,P~¬ÏÕâk«~Fkt”Öå׊·œ?ÄÇåX—&Qèj°DpwŽÄY»Ñêv}Šˆ>¥òÆ)P‚~©Ý9[ÆÑÃæ­TyÉåÌÕ¦£›¢òÛ·S­ 1ŸŒzv¡“Ú*:ùò¬aíD¯‘‘ûv«/µç×äº;§µp>WÞ7C~ߨüµÍb¬¦‡‡õÏ–ÇaüQýóQSç@õïí¤þ‰ålHhh.åÒ´V{G£<‡ª¡ÿeFa޼l\=¡(_»Ñ³AÁÕ`ƒ'NœVœîþ:}tWPدæh—gõ¡cGÁŠõu<ëe k¿æã +ËT`gaËxëGd©ÊøÍ˜:X{˜‰<´UÁêœBB¦Ö½ÌÆ«bH§‡ëÍ9cqR—LÖÚÒ IEDP;ÅD@+¹w¥JÔÙAű™-úèÑãC W’þÌýì$hÖϱќZ†© Hs‰Æ7egè6©•Ѿ<„7wÏý>Ôëž÷°W)>‹é8(–§BYÊ©—½/)/{ќьÔÝþ2]À®áœËçä¡9WÜËá#+ŠÅ°‚®^=¨¼:ïŸ:5 =?›?‰sîɩԱ{W*¿mÇ:NKÖ_StÎjZz£¨ÙÄb‰Cûv8ë&œ&{…<1¤Óòß.Ly.—³ºŽ‰}|,j]3‘nD•ÅÅ,¡¶‘Âbú^ò»X|¤]ª‡Œ'Ú +çYû„šÕøéòŸ%éqá1öÿÁòÏÎ]…P6º.ÖÑ­ÿ$k_#œQ’ê…úRNv|ÐŒ ‹ƒ¨.B¦Ž§ƒæˆQøùö/=æq +endstream +endobj +526 0 obj +2112 +endobj +527 0 obj +[ +528 0 R 529 0 R 530 0 R 531 0 R 532 0 R 533 0 R 534 0 R +] +endobj +528 0 obj +<< +/Type /Annot /Subtype /Link /Rect [480.75 644.15 525 637.15] /H /N /Border [0 0 0] /F 4 /Dest [622 0 R /XYZ 219.75 769.90 0 ] >> +endobj +529 0 obj +<< +/Type /Annot /Subtype /Link /Rect [108 632.15 171.75 625.90] /H /N /Border [0 0 0] /F 4 /Dest [622 0 R /XYZ 219.75 769.90 0 ] >> +endobj +530 0 obj +<< +/Type /Annot /Subtype /Link /Rect [289.50 592.40 368.25 585.40] /H /N /Border [0 0 0] /F 4 /Dest [781 0 R /XYZ 72 769.90 0 ] >> +endobj +531 0 obj +<< +/Type /Annot /Subtype /Link /Rect [148.50 540.65 238.50 528.40] /H /N /Border [0 0 0] /F 4 /Dest [535 0 R /XYZ 72 769.90 0 ] >> +endobj +532 0 obj +<< +/Type /Annot /Subtype /Link /Rect [312.75 540.65 441 528.40] /H /N /Border [0 0 0] /F 4 /Dest [558 0 R /XYZ 219.75 769.90 0 ] >> +endobj +533 0 obj +<< +/Type /Annot /Subtype /Link /Rect [278.25 540.65 288.75 528.40] /H /N /Border [0 0 0] /F 4 /Dest [535 0 R /XYZ 219.75 769.90 0 ] >> +endobj +534 0 obj +<< +/Type /Annot /Subtype /Link /Rect [483 540.65 493.50 528.40] /H /N /Border [0 0 0] /F 4 /Dest [558 0 R /XYZ 219.75 769.90 0 ] >> +endobj +535 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Contents [536 0 R] +>> +endobj +536 0 obj +<< /Length 537 0 R /Filter /FlateDecode >> +stream +xœµ[ÛŽ#¹ ýÿƒŸÄ«»ª€ €ín¿è?Ø$6@ö%¿QEJ¤Š*WÏf00Æ](ò<¤ªÿs±WSþÙ«M·Õ•w¿þvù÷åñuùåµ^×ëõëŸmDŒ7³\}†q_¿]ÌÍWüzý‹1&”W,¯T^¹¼–òZÿzýú×Å­·p- |ýýZ¦¸Ð¦øòº—×£¼žøù—øÄÏóeÓRöïëÚ,Ö}á\Z£Ì³ÿ·Û~Öáze[ÆYoc]ŸNíŠüåÀíØ†ÍÚÌ&^ÄÄ`¼˜XæÅ6-ã™?·éÎuu-·…«kÕ#ALwÇc$T!ˆþdËÒ¬¡˜ cW¡1_‡ÿò²q0{X‹ÅÔ"Ô/åýïÓ„«³ |§§h"ؼ_nI"Í7ØØr6÷¨ã?¿ +Tc];,·°\CJ0±˜(»ëïÿ¸üóOËÞ(`ÎÁÂÐm³›ç‡mÛWÈŒÛ'ïn9¡Rc•¿Z74øÛÒá`}‡!ÇeðLQ€¦Œt~TXŠì8ט5×ü¤Im=3$mAO¯Mx÷úYQ/äº]ÜoïíŠú+¿Ç$1P·Škaq«¦ ºþŠúÎ,Dxtefúýk 5°Ÿ³ø}îJ¬²ž’]Èh— Ê“Bz".-ø`J 1ð;Æ!˜ð/TÔ£Wß“"ï¨1|Fnj)ÔèA©Ãr …tªØÍÿ³ÇCj…ùäc3·Ëšy]f”¦—-÷.ÛÔç^'¾›q-M‡‚ î3‡2XÛõ¯J¦‰Ú”±>ô3À¾P•”íŽ>QDlè`&íȈ²ˆ¡}Ws[[ÙEžë‹a°ú“…:ø?¤J[$w\rPF™« Íž›‡ðÇœ‹@ÖÖ`8€ïBTôsKû2ùÔl¹Sj~(•ÒÍ&¹w³v«&%I¥|˜Çà=ÊÈç¥Ê³µ8Ílë³X ~û8ií¾o?C6ÙcIÐcáªnVV"LH+Àó *ZdÕUV0Ë>8} -ø^C/þxübzö Tµ‡{¶d(žO}®¥î +/ÐúÐ2èÊÖ C)èhïäY¾Shp +ë…ÿ¯³7YÒvÇ÷™Ñüó-¦}gä„>Tv­yû} hݲ‡ŸyäÉÎKMPȶ—Ú]TÊ‚÷BÂwÄ›Qšó#kWÙjsþP˜f†§1Cõ ô×Öf¬¯)JïYÎÍRK¥G~ïXœ³‹îuz*¨†´’kÃUlÜ‹M¢(¹+cl§PΧÖÕÈ“µžá®œz±1Ô^ÑG‡ø¤Ú##Qˆ’—i Éo"€Ê­ƒ[ZÓ—+øoœMÔµÒ06B\`›èõ¬µ 4q¥0j=«¹«aè!Í[²™{!!þ`mÕ©Æå$£*…Ö´ûß+ Ob Ú5›Grq¤%-Tp§ÞnkmŠÔ½S†¨ì;o|,˰–Ž“ÕV’·t:LSŒ&×.™ÂìrÁC?fÊjþùܼŒQ߇£JÁz¨üEê=×uÔ󠿃¨ ÿ8e…ôáár¤ ×4&óxiÉ•>Oœª¬C‡2²Âš­ô3{Må!”ó5;¥üíYõþsZ1ï•W8ûØ ­õ#¬»ŒÛØcqî„.˲‘:zn¹“¼öɼvLc+csŸTa×o½»‘FRZë²óhÊ»~ܨXº0^p¨Ààú]Š_¹eXJÖë ¥•¥Z<`•‡C,“;ñZJ ØÎhˆ›~¹Ö¼«•žš’µ»S5OÈû¨µ²*¦ÐÖPò¹‡^sóË9{'9)"õÛ”ä³0ëÔv|D»Û3O¦³Ìô¡ò‹®í.d—*Xä> +>> +/Contents [539 0 R] +>> +endobj +539 0 obj +<< /Length 540 0 R /Filter /FlateDecode >> +stream +xœí[Ûnã6ýÿƒŸ ¬–CR”;~/?èå¡@ t_úûåP3ä EÙŠowbaÄÑRs¿œ!™¿p4é! Ѧo¿üyøëðüzø|‰Çx<¾þ^VŒã`棛pÝëŸ3çÓ‚_Ž?/ÆXÿÓñõ²<Œµ"/7?yùç Œ £É4ŒÀÿ9¤ï_† ŒùeƒÏÖ’N~°ómÖeyœUËÇ¢×”VŸÒçy&múóÛvæczÿõ×#2°…AZfBZjföi!é™y^žÁI•0ÎŽƒ÷J_iûJß hs'¾Šc½Ò÷‰XŸè÷3‘x¡ß·É†9ñ¯t¶ã…Þeé=0ôHmKô@Õi=Œd’Q™áå5…ßè†à~ü|ô! a>~2Ãd_~;üþCO˜;:€î\Lg¡È{!~é(ß³2;áª^6Ú§'zÙ·‚N!¢ˆ×$C =Y!ÿ Y ·ä.›Äuø3qtÓ1øÎËs—Ìë)’Ü©®q:´!Æ(6±gÊÜNE³–ÔÏSC‚ß~R¬|‡ 9…’G(2zÝÍÌÉoÙ$Dú"Þü"+Ä%µ0Ž Å”Å¬„å;ä ½¢ zÙkŠ5œˆdŽÖ°˜#8G<®‰KPäˆrËÚ’Y#IIÀIÏ™üÝ-RþL‚þ$x:r} LžH>ú½ðNïZ¢eymÙ®ÕåËtOõwËzOKøåõéc'®š”Í,+É”i‘ܸŒí–ùrU¡ÿ·Â® õ—:]Vš"cÉ{ä6+;¿ÎîØPµ5é–«ìt;DSÂÛ"‰“UDÉg +Ëx%g;´ÄæU4v"!‹ýLÞ$ú¥šØcÒû'R™#Œ<_Ì'ÌTŸ‘.Ýk–T<Ó¬Ìr®æØmšhr¾5 °§ÛÊz/bƒü\B5Ötä8zK¼”4i ñðLçy©Ö–øÛgÁ¯WFN }? ù0µ¹‰áŒÍÎ`B Ôlh np©-Æçz q˜¸ñÅ—ð´D†£…í(¿´¦^ëQ‚èÖãæ}­G“(ÁrOyCo1L>²·HëlÎuu£‡ X_Ýy±3–çéûyyŽ&ÃÀÀ爚x ƒM(N&ÉE6dé¼^ö7 +ôü#ÉÛI ´EŸ§º]à#Û³:=dœç¡SSÎU½VÄÒÎØÜ¢Xf`¼/Úô^XÕˆU]vaÎ{š!J­»æÂ{]$› ÕD¦|_'ÀÙçcúª&¶Fyï꫺Ò%éçmé7z’ågO¶®cKÚydÕ'âB‡ ÕÒ'´Ö¯ÖXL—àÕ‚¶Ñ^ fÆžš õ£Ÿ¼zÆ1Ó0ZmDk%Ðég¹&âr;ÓDºžg~ éÚ…qõ"ƒº-LääšnŒx‹c-Qc)Pl(°ÝdƒÆ ‰pæM½·ãàJ€O§˜êWBc\?Ï +÷•„E66Û,ú²ï6šõ‡>êÎêhæÁ~ºVÔÆï\sm@|Ôº¢šoɰè¬7ã\ÄÍe« +v4Ó\×N¦ÎÿOUg”ž휽« wòÌǼ9Ey6o6’k¶ëÄÀíAćõ6föžœhú@ÎHžýxq±öïPÖ€Ã~Ëkjƒ Xô/PçËÂÖžzCKZO,9¹vL,õý»¶À¼÷Ãì9¦(v•þߘbi_|š¤ S§.±Ûì‡míaœrÎ1Ø;‡ÀÎÚµ¢/r¸ìÏ]ÁMWë¯ïæµsuúëŠ>óæ½:± ñ[ìhS‚€'ïñšØWÛÓØ¼©7…`E¦Ž{\œq4XN±‚“¡Ëñmd.ôì–•Û¸3µŒä©Çâàž¡îMñ/rˆ• žñTíçÍäº@ÒÍÀƒý.C;egR§¨—ÕïÚ¹²éao–´Ko_hMÙ3›Éœ¤KQUÉkǺ)åULÒ°ˆàºãƒüÎSÓsóþy-fn¬¦ARw¹‹8Ÿ°7o3Cºžgƒ%®Í>í°P€ ÷¶-(%l ÐN3 ?|Æ{»rTÞšìi;mrÌÐø]ö…&³Š¤ŸÜ“ù0•û.ñÊ€‰i B[I÷lV£²‚¥mŒFS`l^Ï"ÊÉŽ6áüÔmwŽ3šÜýãŒÎyg±òŽaR3nlÖe ÃXW\³àªFâÆH‹íóBÙp¾U0¿ÊÝNu‘]²^¹,ôHÐ.ù\³çƒP{‹Ì“PÁ7BÕýÿÆ_›Û€³cè à܂֖ý›רâÔ-ùwbsEÎÞÍ)”VGO­ôu»p=¿;8ÁÖKR®ä,f9 +“¯"Q:×DáòµÑËÂt4Ns¹rðQƒñ­@Ïpÿͳ-O¬ügZ?þeOy +endstream +endobj +540 0 obj +2328 +endobj +541 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Contents [542 0 R] +>> +endobj +542 0 obj +<< /Length 543 0 R /Filter /FlateDecode >> +stream +xœí[ÛŽä¸ ý‚ú‡zÝ-A€º´ßôl²vÝ—ü~D™IY®òôL'Ø ….»$êÂCòÒür²gSþÙ³M—Ù•o?ütúùt{?}Yæó|>¿ÿØZÄx1ùì'h÷þÓÉ\Lp¥Áç¿cBùÄòIå3•O.Ÿùïç÷ŸÜ| ç"àýŸçÒÅ…Öŗϵ|nåsÇçŠxÃç}±)—ñY®”Üû’ŒÒÏük×ñ¬Cye|[ÚYloc•O«veþeÁmÙ…Á2 fN&œUÇ`¼êXúÅÖmÂ5¿­ÝãíÊ—,–Å;ŒÛ-ašîŠËH¸…0õ»ÛÍfE r2vV;ækó/‹ÚÃ\¨º–IýçT¾ÿz2mrµ·wà”Hçöù’4Ò|ƒ}ƒ.µýÛ{j¬²C¾„|)AÇ¢¢Éý×éÇ¿–­95¦ž§d Ï: ïöc€þ†ò×¥u·Ayî¶þVß>ÛyÕ”½©UÙä7ãY¶†‰ÑXUÙ„"q€„ÛÏ3~ïúÕvóx²ÕÚ"ÊözâMVÄï ­å†ÒÖOjAÞ{¹ÒOî¥K±yµêh¥2à_KFÍ_ ‹ŦsíÜiª¹•‰æ]ŸiAnG›Qß_õ†Ò†Ã_—Wí‘,Ô¾w +r÷í|-aYé¤H3™ÒA|üUx ÒÎ àÈ>ð”ûàõ×qiÞ{ÀšÑßxl¿W‹ëG5s »ææøÔª—ö³É.òw;“ÄÏF‹3Í-;±±Õ!Þµ)šé’û¹¤6—ÙèÀôàÕ‚|h7üì05S¿¡<&…%9å·«FÛ¸„ŠY£ cDXò"˜PÝ45ï)*Íö¹ß,½ŸÖPã C×ur[ÖÁ¡ ü0;Ô€1àÔ)¾ù¹ízÅk§¦yú™Øæ;@Fy{‘§ˆÔ| ØìšÏ/q›¦Ðœ‘™ån€«j5+‡uV[öÞÎ=™£5 Z`7@vä½:¯^ Œî«w2ž ~¬ï=z¯ê!Þ¸ ± +I–4œÅpH ÜB Í­÷ïl)Ìàü{}À‹¤8 ½R©Ã$»K/,õ[¿qàèp-™bÒ[E[ÓTµãJ½ÃHëü &?_2¢I;Zì¬ÆÖ$Å$B`i)#V"Ç‘¤³WçP »»]V2 +Ò’m<ƒ¹Ý;ºX¨5Åòv¾x§ã§ë®n +Á>âHÎýOé¡ï7OÅjžÒCµêƒô0™ø'=ü½ÑØó÷¤‡ZÜ´OÅ"þðÌ/–”šÈ’L‹— AKùât{ã9~Zf…•!.èn‘€EÂ÷ÊáûÙ¥÷#2¨Ód°ò™dP‹h\ÎΈ!Áû 湺½Åc2ÊáF&I{€jó‹bN‹èŸtý<Ì—)IÅ mˆ¾Ó.L\Y›M³Ëúžf(ÌÆ6vݱ"i›d,lÞŠ±hÈm옫“m$‚ðwpWTk úÛLw^QT2MDW£Û$—Мõo =¨m—´œ×.Y[碾G½¤érúDdŠŒåy9ò5 -lCt¿ ãõòÒÄÔ囉¼’¶Yž'ÄKAh™8=—VÕslj׬$‰6ˆ¨F0ðýˆ¿[é‡0¨¤ÃnýNݽyíø?]B0*ûo„‚bDèžä7=ÁèÉÕˆp¼Î%‚wpוO(5ðX<’á©h<,$R%»KܱT@ˆ ’ðkÖld[ûÚ¯FpqhÍÓ;#+~Û+ȶpÛº®5—tȉ#ç$]‘•!_8Ò–v'¿wpíò,‚Ž Ç–q÷ÌSºÑ¸$=/l®Žƒ„ÿ ÆÓà=‰ò镤/d†mŽ’öUyƒ€ŠvMÀ[âAÝ›Ú~©Â4P[£É|A 3{ <Œ‚ÏÑ-±xy¢PÀcHŽ!>ÖgŠ“Ø¦òÑžkŸßÅAª3 çïr=˜  j¶fYnŽPèU 媵äûJ·pöU¶%ÈKË»i²d3ˆ}{r®[¢µ›WúÙ‰by”ÏâÔ\×~Ê©|Û&öäS­ã¥8è(Ü!{ p©±Z~ºÎ3X…tÁúä•]ÇïŸ&›2Þæb_–¶®×Á ™n¯›+´¤ÆÇçíM=wÐÚâ‹+ª"±Þõ±b¸ê½„ÙfiøWe…à ¯»“”!3Q3‡ Š(ëŽ%áu¢Ü‚r“bÞì3çNª°jTÞÚ×Õ-lJà"ôFÇ$ÚòGV•í¨Ö¬Z_MèHv’ã­7x<´5¯ž¸C½ æ[ˆö/Jd S/)O^džß˜»°0@• CºÓ\Tw‘£ò75™+º-ËY;MPºi7I… ÚÍ× oìRyµOŽ|HÃÜïƒÙ‘÷]Ò#Y/m\éIªôL=*‘Úì°±âu–¨F’‘ôþ&aI€Sì_%ÜÍu\–ùû7qc&`ù’ú<Ññ)´éîžFçZ°Jt áx™è„Nć.À¸ôÙYaPÃèÌ4™Ý¬§!W”‹výyäx$Ö‰±‘-ËOæ@bì¼m·‰ÝTÈEå¸Ä5·ûº,wAÉôÅk‚Ó:ô6iαÔú HV8k¾ýHƒLGÉJ2àÁ›ìüÛÅ[?ö^ŸdÄ/׵𭇗{µ^ÛŠf04—ÀL­–‘VX8N' ·É ]T\ï.ÿ×@ƒßW– Ð”xfÛ«‰GN£ƒq¼e“ûLOÌâí¶øD‡¦´…´ +˜­¸¬Ÿ¿&©Ü=_Ú+ug8`å*kÆ{ m¥Ö.ÞÑ}…ŠñÇqhƒ÷"f$SEá‚6»¬vK÷\¢JNÌlãýtYṘ\uaJ ïÏAšapAGúŠ;+¾ùLè°4oY%¨U%6©²è'}V«\j]EWu%àt½nt,NyØàš]ES%©Û6(<;{j›³ãÀåÅÑdáöÎyû?¨ßcqú§d…ÏÎUb^zm8£«u`äháêÿ8ý³éá +endstream +endobj +543 0 obj +2561 +endobj +544 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Annots 547 0 R +/Contents [545 0 R] +>> +endobj +545 0 obj +<< /Length 546 0 R /Filter /FlateDecode >> +stream +xœí\YŠ$É=AÝ!¿ã[l ¹TÍ·DÝ`¤F ùÑõîafþ̗Ȩšj$ÁÐ4•åánnë³%ú_/öb¶?öb§auÛ§Ÿ~yùçËíý凷õ²^.ï?ËŠqÌrñs\÷þË‹ŒÛ‚Ÿ.4ƾãæ?]Þÿ!˧q°“ZnW^n|ü›–ÿðfÇâ ÙYwù÷Ëöù×ÃŒéa¿«)Ãà–çGËòuðN-å^ó¶ú¾ý}gnwtÛ¿kzÚ-ÃrÙžÿë%àä€m™™¶¥f?Ì]÷-ìö¹íßÙ;l»(b¼‡5!ïòþ&’¶drÖ!dr\P÷½ÒÑwúùA[¼ÒÏým§e;?ïk4ßèYÞc{Îú×Òµí·oãÕi½‰%£bÃëû¦~£¦p Ë–K˜¦aZ.ßÌ0»Ë¯{ùù ŸÃ:5TtžÌ0N̼Id¹Qããß™>oT„HÉÆÝ¿s÷ýÖ›FLÀM+{\÷gâÍíÆE·ýë¶›ºI ÑmBÜD 1²‰‹nìð[Ü+[©¯–9êlC;ø…Ÿ +]&¿)½¢E[µë® Qv#Åû=âg›ôü€,k¶5àäçI¼¨rwRŸÕ,‰žU(~·îªçR°–¤’#íë÷ýY•¤l¶\OÖËßi“x;ÖÙëÎ 9dCi½›ò¡‰Òãø}ZÏ{ðsëþ_Ðz°¹‘8O¶!î`¤Ïøì­C÷öð™±¥7¸sq'¡“ÍgíüPLJäí°,ìC=ó6ºÑœî8­3ø¤c<ÃJ÷šèÚ#ÑȾxâ +9Y¯Ÿc>&E‹ŸÚ:½‰ñA_nBÅ9Xˆ„ÓA4ZãŸï´‡Ïû$bùr|ÿF {Àe™©oµÐE°ÈdÞßú+}ÏÆ´¢‚'AÜ2½¸v§¥¥ÎDÛ#þÍâb>jѤ r'4šŽ+úC凌¿Ïæç¸y1<Æñy=¹;|Gü|!#í÷Èt˦eXGsPï…2o÷ï"¿¢žÆ°Ïãߟ [xfµæý.g¢VÞå|К6¸1}ר¥NøŸ [Yó΄­Ï»ütø:G@•Ïî*ý—F2¥hÁ¸¤h(ŒºÏ„Ùlñ–/kk\µ«[Ø¢µ©ûI,0å[ë ºÏpT³âH÷0O“µgJÔ…òÏ4Ö”ykWP†âîœF$Þ+rò}¨pÖXׄ+ + Hˆ*/Ë”GömÉ~ ¹Ž€±"ß L^×,÷gE@‡yÄЮJ»@¿ÉhÊà™~_1DnEqâH*؈w^«QWð-ÇÁ²OÜFA~tƒâ½ ¶èe“‰>AŸ%G;9vWuôOè·ŸØ^åT6Ì>B0Š\^aƒBísÜü"©Ÿ¹Ø8KAÒ¦1£Yé2µæR°JòKW#ÅÍôÝÛ¾o˜¿¼µC&¨Œ‘ÊâÄ€—ÃŽÃy䜸ú뀋ؠСV©ÐãÏÕK]}®ƒ”oä Íñ•Ò% –À„ï,Þ8*ô7ò tmxçC¬¨9H6M›5k¬"Lõ¨ÜË_A&$C‘Iü}€ßAÈ”!=ês"c³ß¼eG–”çLS©SŸ´[NÄߘ!4³ö‹ŠºÆ+¬Šc¶QNz.aK“MO¥Ó:¦hôÉ +ah:Û Ì*Ø74ÄïUƒ²ý&–Ã…„€ZQñ„ƒ,Yžhò³ýI^žU,j÷Ô%à úÈŠüìÐCAåyÅYŸcªpgÄ»Œ,S«kÓ,ÿ¨¦C_~Ìk‰ŠèSy´d º=••UÉËWè:’ÆFÚ**LãG½g‰ÕùXQrR¥º/fǧ~ý;}øËy§°D©EœóûNbpYµRÿTðwž–Æè$Ãë72Û§„Í%žýã>-\ΰ'`UiKb5] ð¬wÒjŽ{öÀÝÂd$ûnZVqÂz„W1¥áŠ«;œø*W@ç(~v˜£PovÙÊ]6¼‰°Z.fò±ùB°Ú)U†œðyÂàÝßt¨Ú7­B囑BešvxÛϳyT Öatú€ü¢gކúbM½=—7ø¦úb2—0Qqr´Oï—{Æ9ÐüÞð¼U×8?è- é~—Câî¡ß(jœKu-»äÄ/yžÉ›a®1¿£wì}ôióã!\ŸcéX´7SÄÒlªJÖÝú%‡‰¯¨-IvÖÒè9…ãŽÅlLµXœ Jë)SS–ÏjÑšGûl+â K­ÚPÏøüá¸*³ù£PË޴ãH?ãª9›ž9µä=<*ãèzYʇò²#cš~£-Ù6AÚllœ«ujªú ðàóäÈJ霥>AdF6bOyÛ Ë/›Ê€Ñ/ [®Q¬²!”`'Oë{~ÃÂ,y3¿ªÁ³£ãØ»g°€å;°ÎÇ×zûïÀ¶`-Ý;¾bQáf.~¨‚_ñêˆ*¦Xu“ij‘ûÝÇÂùaÀDD²@SvY 5‰*0²[­ƒ¬Ü/¢?SÖ,•)Þh_r %øévûX;Ǽ7v£Ë‚d¯#©\ÌâÒÖ釺¯qj‘ŒÍ£KHnYû‘ÙÅð'Ϩü˜a;qhT=I¶U®ÝN´J\sæ:¾ÌaksÆ–ä‚Æa°šŒ +hªX6i5ˆ…A­Ó¯ê M¨*=ˆå€+j„ð6Z#e Ï> ªI;´–SÑ :Órʦ–’lËðGëNgê[Ò âº–7hUr-áKä¢b¦è¾¤Q-/P´¬Ï:[ +Ñ;ö6+€4elz&€*0@_{@/ÎéO…Rø +Ùáç±làÆåÞˆtoJ枥Öݪ·]BޘǑéïK(jô ]¥R+0#¥ÐåN¯¡ù­ Úµ¢íÂ^,LNfÝ(ß +yȬ(.<Ì`¹hQg½ÃSù<0ý¶·[\„„Š!øBŒ¡q~’w\Hò?þ5ªVÞMCÐ{V¯]Jh Kƒa¶{È~L8w…rÍk%í8ðä4%.»bgê7§þ2™õà«ÿçd +Få­¨…Ú×QƒúûJÛR3=ý?=Ô×’Ê÷ƒŽÏ’z}ùóË(; +endstream +endobj +546 0 obj +3828 +endobj +547 0 obj +[ +548 0 R +] +endobj +548 0 obj +<< +/Type /Annot /Subtype /Link /Rect [465 390.65 510.75 383.65] /H /N /Border [0 0 0] /F 4 /Dest [664 0 R /XYZ 419.25 402.65 0 ] >> +endobj +549 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Annots 552 0 R +/Contents [550 0 R] +>> +endobj +550 0 obj +<< /Length 551 0 R /Filter /FlateDecode >> +stream +xœµ\ÙŽ+¹ ý‚þ?¶Ú€ €—ö<'¸0É0r_òû‘T¤t¨¢ªÊ·'hí¶µ’‡ä!¥êÿ|Ø‹‰?öbÇëââ»_ÿø÷ÇýÛÇϯå²\.ß~+-†áj拟R»o¿˜« .6øõògcLˆ¯!¾Æøšâkޝå/—oÿúpË5\âßþ~‰]\(]||Ýâë_úûIC|ÒßýaÇ9Î_ǵ“÷E}yŒØÏúm×ù¬£ñâü6¶³ÔÞy|Þµ‹ë.Ûþ)M6ódv¤¦Ï¢c0^tŒý†Òm¢=®Ý«âš¯3l«J˜ÄZ¦eºmc$¦¥?`Øf5KˆjÀÅØEHÌçæ?¿ìШ=,Q¢k\Ô?âûï¦,.÷6é38Qã‰Ékûù:J¤ù÷æCnÿù-BuÈc‡ùæKÇÔ1ªhr—ïÿøøíOŒe.Q£‚çi4i{´¬±LóJHX_n"ñÆßÎ’øão7¯ËÉß-ë÷6~æêÿYÕ’Çb„=iÜ{ýÌÑ÷¹Ý˜Þ ‘Øeº:¹Xažwmï¯Þ|¢¬¯J‹½¯¬4¢‹ÃŒ'O˜êgy±-î’¾¿Ñßaý.·»u5­›Å —÷÷*äÒ¾ÓÒXÞÑØª”,è; _â0×(ŒŽ¶§EÞWKïóâ -&Ë‹¸Ó¦—-pWD…処9nFɲ¾/c²`_´ P“7=Aû¼&¶X³Å¶ !Ù,…w:i+öö:Ï©xr1ì!³W½W¼g—4ÕÏØC[~Ÿ•6/ò¶÷R<~–6;Ó'´¿Ñ¼žÆ%HåˆpkÚ¾¨g-Ùër4¡ù,ïůŸç÷4f6…×Ú¿´{RÛ™<÷LA. ºŽ&XØm»ùôwþ½€àh¡lesÔÆÑæØÿ'å`Ó3l¤J¾Î$_Ú‚!ÜHp/è@{¸p$hP(ûnÇöú‡€c2[  Ô&¯U†ó°ú±Éb£¨¨°¯®Ú[w¦Ãñ5$:v£¶sÄ{pÅùu£ñÙœºf³ÚqKOËX_0{ë(i8EÞß{¥Ùù¸÷Á¯/5,i®ä„KɃý¢yc4×£ácë¬û=Bœ?'ì¸P÷Ò×õSº¢ëIP/r¢^øK¥u¬—L6£§‰AHkîM»˜{C³”2´i«KiˆÜjÉ[ÙL„JI]9Íd_êg¡ìyÛÐÖÞAMd暴¡“'~©ì¨1DU-¯(&ùÉn|#ºñþ!_1\: ÝmôéŠÂÎzóteõ,äéwmäéDMmv4od8Û-ä’ f,E1öÞæriïÜ\‹ µ¸wÖ¯T+³!Wc6…©aÓTr4µ`FõLOÃqAkŠyK¢;ušjšiª„ëÂê=Ú»»¡q›*lÎË3»F†®°N‘áHlØcŠ‹*%,ÙnйY»ô-T)YCj¢¦À˜ûlmJÔ>vÂ6SìmNY»`×ì?¸^Ñ£4@såˆýÒa¨PÀ>¤Új‘shå\ü…A×+kÐß¹ýMÊRmTý9–,Rž^vÞÃB'CaŠTBü¬È¿¡%‡€Vw˜ÿÁNam·±»$_«‡n¦á('DZŒýWVšžã/[Êô]Vò‡ˆTšsð×Óg¯Wp–÷ÔfžÇU ›òh•}I¥¹²s3±ÀÁbþ¸Š_v +¹¾+:¹Â8ìül ’/;GÃ÷͌ƗOúÿœ6ϲˮÞBØê¡Ö¥ãœ^ê-Ćªž›˜†y# (ÑhH²c 6­Ü+8› Ò%ƒ™ü–óï•u´rà™`qºô§”tŽ +å{äuC.O–ÃDNm8ÒÖ½É=Ÿ “†Ð³cuKíW‚Ù«Àª7ÓtéÆtÖ¶Ñ¥{#À1É £¹–ÑÕ/ëýFKX~àD$\Çht%HSë/ +råsx”^gž ¬†ˆÔâéœ,DÓ¡HÛ¹>[=Ó—Áþê8ްLZaȽ&Ò¦C d-+C–‹åˆM½ªq81Å4Œ¦–ŠÝúòΉë862ž¯‚ÝÌ›NM‚o’w—BÐÛ‹ôZIFˆàÉÉj&÷uר\ñò%ˆ2YfPõ–; ÎaOÔË¢š²žtÚz°S_ Ÿ‡k3vu”þ‚£h¿àT<`qÑoÿ.ìž+HÃÖ¦LEfxëh‘‹ §™¬b{=YlljæZWÎHëwRu“ϸˆ¹x!,•€M‰ãˆæ‘goš;ÁoŠ)¯ý†dõˆÐ£wGõ·‰V‰3c7Ä#qp?ÖþBÅäÝ\ÇdÎn0>iâl¢©x’Rtñ`sp( žBcÀ#nrM> åP;È-2²JÒ5É(pT LWòšBoÛ>]&kwýÙÛ5´®wÐ$yâô +®êÅÏõ}¾ƒú¸™Âvßb¢SuÅìî€#H¸ý‹”HBÊÉK«„3÷8î«B•|€i'-¿yõ$‰Í!miEùGPnE”lN¹ °®1;ª8nLñQçT‹MÁVF\TúeQ”çu6\}6×Á¡@uDøÈ~\+ø°ü›‹|×¾O–Ü $Ӹ昙È65<ÌÆO ’ðY7­7¨i€Þ®7ëÕî±ä² ïÕbÅö‡u»ö LXåc÷ ú,Δ\”/\œ;‰ÞóÝÛ×JFÒç)Âæûº©°Ã§¤è…3‘!'v͘CùzÌ­¶' ÆáªÎà¶”‚ W€Ëyq©åf £J<ðNÇAŠtÇ£¨‹Q®Ýëh/ðx½ûxøÞÆñ‰†#&KHhvJ$LJkæýª¦œ}á&M¦¤À¯þšÕ’€÷ãU¹n¦Ü‡.êäøßS¿¢¶ÍáüXD›Ê@=€Ÿ•#qmoržè9‹à%'#v°å¤MCS’O¶ùäàÂÏd€'Ï…ÏÂ¥G +¶6ϽxkÖ¼»ûàK÷ÐßM.ýËd‚ÉÞBÔÊ‹œL¶Q¯µ;Æ#·#Ú—WÄ/ð17¥<>®ˆ×»—ø2x°Tz"„ô m !*6ÈYe 0ô Ì”gc +ý›Ëgg,e•´”À`–zÎ(F¦(³TÞ+sðkZ:º¹Ó| 7\“æûªìã!æˆû“|.Â"éùàNЍcMB(ÿ÷?\>.U»Þ©ãÑÉx{äá¥]‹§èNCFQ¹]fíü¡@—áËsõr½Ûûë)߀¯T Që_ϤãÍú}[‡~êíX§¢„¸@¾²Cë­“UÊ)?:)I?ÈÓÛM óX³ãz’ÜR}Æ/Û†Jõ×ïÓ¯6uئ'ÚRÆžè/|êGžÉx—qíÓ@ÍFÛ”Và\¾v3àÝë€" ‡ó™¤Ð3ëùŒ¤:èZv¥Æ4­ž…|³+$Û.”ãb§¾¦ãqÀÿ-2 +@öÖõNÝ u\Dê¥Ùs LO³uBíé:š^ ‚Ž~0Gä{ñ© -Ä5Êÿ!İâħñ¢ü»-aÅ_¹.y^é˜ÎÖìúØù!•Æ¥ãAØ|H7"wq j¬¨Êýíx[»’Ãx}‡T -©ÚüS‹;Ør[¿; `ÿwž‰6¯-Ú;ŒÃ6†ør†ýCñ @¢3Û"È¥ª­sïÝ'!;*iW/¥ ¬Û›õñmò®šK‡—3™lµ¼S¤íC•ŠHí”Ë_½}¿¯ ëéR›)쥙{@<:ž;:zˆ6ub™5å(Ñn¤ý³—ÄȺ-7YöÊÉPÏ“¸R/üëÇÿìÿ û +endstream +endobj +551 0 obj +3850 +endobj +552 0 obj +[ +553 0 R 554 0 R +] +endobj +553 0 obj +<< +/Type /Annot /Subtype /Link /Rect [231 242.15 288 229.90] /H /N /Border [0 0 0] /F 4 /Dest [593 0 R /XYZ 374.25 493.40 0 ] >> +endobj +554 0 obj +<< +/Type /Annot /Subtype /Link /Rect [309.75 161.15 418.50 154.90] /H /N /Border [0 0 0] /F 4 /Dest [593 0 R /XYZ 277.50 304.40 0 ] >> +endobj +555 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Contents [556 0 R] +>> +endobj +556 0 obj +<< /Length 557 0 R /Filter /FlateDecode >> +stream +xœÅZÛŽ#¹ ýÿƒŸL­î*A_Úïú6Ù‡»@ö%¿Ÿ¢Š”HJe»g&q»u¡ÈCòÒ¿Oöl¶ölÓRÜöé×ßOœ®Ÿ§_å\ÎçÏßÚˆ³ž}†qŸ¿ŸÌb|Øüzþ«1öÃïþvþüWžâb“n 7~êð_6ª²QYwþÏiûüçÉбN6ðÝ(i‹[_o݆—Å;1<¶såmômûù€=qnû¿ÔÙn]Öó6ÿógØÀµ ¶a&mC;™»ìKØí;sÝ¿³7¶ì*„ñ..!iB_;ôõ ˆ¶vqʺ8.ˆó^pëþ~Ç%>ð÷ãeÓºíß×5RœKkló¬Áÿ-ÛázÛþŽŽãmD•D¡†Ï ~Ñ/)œÃº„õRZÒzþf–ìÎþóôÛ_ŸÖœËRÒ£9˜ƒ¦oÆôh ¥Še*‰(ZÁÏ-hqýŽb×qÕFkÝûñhŽÃã×} îGs.ð@€Û\1¡Êâ™™”ü°¾³ýœm,žd€3€úàŽ Ö±8§þïÑl¥Ÿíé&ÃÑz$Îoº»¡>Ùùh®žWíÀíøÐg:E\„1IëTÈë>v¬¸MvG{ã2—ç{t+ló`ëß'"gsóÌ>£NÂ…á-ëZÔ£ 3l-ø»!wåx» ½Êþ¹úEB;Ò>…Í•6 Ö‚ûJ£Øy=S4 ŒŠƒHX›ä¢±,±( Z\›ˆÔúÝu—Ðá …Õ„§ÍPµÅê-\ázà=²ö T׃3M(×ÆÏ„Vvy&§3PQNOr¯ö/¦E« ++º=ZŠ#âÿŠÎô…\6§%:%˜tKR>©R”PUˆ²=fÜ©ðJ™ 4ü€[µì”÷}´«‘VöÝ­Ë5*O¹D€4'Ò²ÿTËü|AëX{¨´BÌ +9äœçQLÐŒ]Á?œÞ4$òXt(Ó½î«2íF– Í”j$¡¬Ôâ ¢$d# W ¦³ ÿ",T´ÄýÇ‘;±ñFº|¾º²ÓHN¨t +{Œ8ܤÀ)hRÉ@XuüvlG†‹û–Hó5­qËF^å¢~¿‰5\å./J(uðˆÂ©CŸû¼¯ Z1³iT(Ÿy.Å}›º %…>$2m£Ë3ô„Ä(AZ*ÎoiL›Ó5 ph£4†q?² Ætúª1<Ýα„×%&.É¢ å‚’ÛOÝ‘ÜèaŽ9bZ#+Û2/=Y¡x‹ãI­•Š•»¨Ñ‰bà·/Pù‘¨ yžF者ÒÝÞ^dš° qÆÉÞMЦ®'òØV+eìB”³]'¥d²+´6~ƒHb…3¡OÔ³=×ΕëY(WÝ0âà˜fŸÀôz×su9œ|úÞz8– ÍPí¥ël Sü÷klje¼ž¨8Ù«Õr)l-h=ÕW¶ÖÄî†xŽf¦Ñ´šQDN† ±6³}KqSb7‰ q¥†TL\‰’½’îð  °‹ Ö¢WÛ€Š,OGU÷Üf1òbUþ¨Fê÷+ŽUžª+GÞ‰^r}—K;Lv¾ÜZS?ÓAGª¡5ÑK~{^2=yB«¾:$ÙBäV²2é¢4Ö©œ{a9{¢«]ß3”eÎþ{Ä•´éuu˜ðoÍ^:Ua@ì/ÓX*J ªסŽÛÒ<êtÇù‡ KK%<ĨôñêÐÂHOÆ6ðÜ¥ñMyÞˆôQ}GÎNÃÛ: g_5Ò(6´çQ¼X5ITg·î«­*Ò MsÔíoÞ²80‹ŽuÝý;šË÷ @W'õQI™’à0‰-ÚÇxüÛ3’¤¯1iH¯ÚòlbR¹D{0Ë O ëÃ’¾j×6‡UpÑðÿª8Z§é ôªéöèàLÖ±çÃÊž²`Oóˆß*Ö-ù ¥8Jd¾Qw'yñr®ïy4»ô­ÐþØóJœÈ¢ŒúM6oF&”±éË +Ù€ŠÆ:Ÿ ©ÞlsÞ ä¯íÌÎ<í’ ¨xÕéyÕÁÖyðÙ­ÄQ÷‡wv8š¼¸àòs,Í0rd*?xcfÖQ¢èÐú»¹½]VvÈKᆚËÔËÔM_ÝÎŒ#p…67•/ Ñ›s Flák$KÌ;@/Ad¯þJ #âù¨¤kˆ0„J‹šP.]WðP gËBs7°ô·Po±¥bd œŒ@>”äÙ]ÒЋ|ÑsüŠ2æÑhbäPÃ"öFö¶Ø“¤…{‘év^€Eܼ|Ÿ½³úsò×Ý )2ª ÷â)œßféƒ{e``¿–YHÉÕ››PˆR Ò&K5B°{ç°ÄÁŸi•L[¢„çúóSÿ¬;`2ž®É·;Œ„v–ŽÄmîD)ÖÊq?ã<ˆÍPCç½SÓZºbEøžÏeèÚAÐ×™WiÅ˽lŠ"JyŒ|’³´zôîYt`® ÅØããt 5HgïHï[Ô wMÅâpN–Ÿ¯]ÚCë2( ½n`ª—\£ ìÚbðiÕ“JàWRù Œ7üýkA›\‚7ßxßY'æu<Œ¡dNM¹ ƒDs(a8±hÈõ } Qöμ6÷ãóô÷ÓDÒŒ, +endstream +endobj +557 0 obj +2715 +endobj +558 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Contents [559 0 R] +>> +endobj +559 0 obj +<< /Length 560 0 R /Filter /FlateDecode >> +stream +xœ½\KŽ$¹ =AÝ!×:Gÿˆ ™Y]{uƒ±ga` x6¾¾%†(~¤øU÷ƒDeu…$Š|$)ÅüçÍÞLþÏÞlº/.ûõ÷·¿=?ß~ùXnËíöù[{"Æ»™o~*Ï}þþfî&¸üÀ¯·¿cBþÄüIù3åÏœ?ËßnŸÿzsË=ÜòŸÿ¸å!.´!>ùóÌŸWýý½Nñ½þ¾=mšóú4¯Ä¼u,ΑÇYSÚu=ëê|y}›Ÿ³õya~ܵËòç ·m+‹Í¸˜MUÀ"ð,údîKú2mœ{Õ1ßiƒE­û¬BÏõ{¬ÊJë³î]¬B¸Ë%IÔ}¹™t†bºïr©%Ü£“k-žÿåÃF¤°dH>ÔºÛßò÷?Þ Î°ZÁ”@Ñø{ +Ç‹Óóó=IìúD[6·*âûg„¹Ã|Ïz)•Ùè“»ýñÏ·ßþBÞáÍÀ=¦`Ë£e¦C!Ê”î⩌ +ò¢Ÿ‚ˆ-SÍY6ÑIÞݧTEtŽÞv9Ù2¨!i²ÝÖ²ˆþQ¼ž¶ØŸ·žÖAÏ\Ÿs= Ò‘¼.ÜçaÔ¼×FMëzÛVµæ¶¯èÃz¶ØÀó Y!z,ëwo«~0Mk”q–ž³~ÔïSÝŽ¯æÌß]F¥‰ôn›7®ú/ãÝ\#Ybkðy')+Àá±Ê ë<ë:‰cý[˜m‘žƒµÒúìýÁÆì¬á>êùã&鬠︤b±ê"^D¤ÝùÄ\Ö„»Mj2 +o©*l©Â>ë„©*5®ßÁÏdD±YJ§¤ „v¥iœ ´ˆÖ]ÌqûM¡I™“¬½gW‹Sb˜¡{>ÈŒæCNâ—2šM"Ýf ÜÚ&Wþ%NsD¡¢´~|£Ç‹ïX¾C kêž« WsHu{È6b"Gv|ÔØØ€/çL\ÅSø‡ˆö¢€ ü xR@5 b‚3NM‰Ê—$À™IêK¢½ÓtŽú$džŸ§ðâUYwñ|±pó¢²(‚ ò¨E‹H/òÞÞ•þ{0:ïí»ðÊ“j=1ÃÙ EhuÊ8c3å’xSÁ n ®Ó¹ÕX#ê³%¬1®ì<®:‰+›ÙWq^±iéX ‘#¼̬0“c‘ã“æ€Ä¨îÔ̰ŠÝ¨·À3&'‡¸Œ«:vyòbx·žÉÍ¿³$ƒQ­ù€—û-IÐo:rrV½a²º|qÍ&ó®{æp஺'ÉI.5P¡vçUd·Í: ¸ûäd.ñt[_ju÷¢­ÁÏA^Éþô„ñœ¯RúªïZJm¤‹L?½(N§‹¸€ûsqXe‹&cpuÕ5ct9aph\ó %8黄9üÛƒÍsÂ58§ÕôªðÆö<ÊÌÖµÒ6a^î>)äžÂH#?³ ÕX) ?+öu¯"Ý“âCóC$ÇÕo¼Uã1e3¦XJ&Xcl +”®%6À*Ž:¹Ã‚Qðd–Ç@yÄäqc5 ´€ñq.O]잆•¾,OCœÅ´Ð~ÍEyx¹©[îq´-•}ŸJ)¶b¨ÿP `/Ã2‚ŽÖrâ’þƒœØIèÆ~Ð2ŸˆANøÉ“EÃæ ñ¬¨ž ¶& &Äz=ÃRsŽdZNS“ø¨<±˜¨½QI^µ¸ •ÓÛH…Ò]§JÊ;æÅx° ÔÞ™C!KÁR{mBþáÝÒ4‘&ì…¢®Nøc˜\â¼?²1œŽø©J†y æÔFßóSTZ¥t§*¨<14Ø:‘•íœ +ºé¹¯ÒQ6B7ELC‚‹eIìÜðÀ¯]z‹ÀòN ÆiŒÕ0Vg@ÞYé:>ÒQKÿ5m™šÙX˜Õ̸g¥ÁG©àÒÉ J±ÆÜÖ¥)/¡®sE`¼b'mÃüÄ‚•pɑ˥Ò:©-yÖ!Ú)<†¦|é-èŒä°gƒÌJ„³Éx KŒ‰Š—(¶<^ó7ÊÎãlkç ˆÏVLô\í79›0ŒsÛý#)Éj*§„Á_tÓzá›"xû’)üË­Äàc÷ÒGPN¤¨ª’ÚçÐIÍ©¶l5†õË–10)Íç7¯KáýÒ{ç<òÇK|Y¶¯èÌÙ Ø$ÂkúŠ8Ôl«½µ½DÚ!¥ h5q§ wÚnœ«æs„G“㼪ImM @ô%nz$B´çr’n~N¯¢÷Èüa¯ù§Ç£ÓB¨f“¦Àßû/50•%O5žÙü¨‡ÀºÖ’¬Ï¾Ó8ëéï ¨œ®ömùŠ%ãGYcÒ#žyGéÈ£-ŽJ9´ßA¬Qlî˜{~¤ñPu¹™ëßyt‡Û¦ö½9Fºõö»>~ Ë Ò_ÇÖÀö~±+%îy:vlél\>J@Ã$é§@,h!þW£1a-Û·vËÏÜí:-4Ônâ V³y’« ¸úŸ”vlí  Áɸ8ÐÌ@Tb38qGØ nxŒ>µoP®U3ʼnµ%M˵xKåÔ‚ò­Jàd­;¤}YUÆ.•7§rv%&gD Nd0X"Fð÷§òvÎ;{ìŪ9®S^ÕÖ‰pˆo(QëK€TyÆ”|/FÛU:²Câ­‡Ë.4h\–ùõÊ׆𝍧åFX±d¾ÎTíK‡„,Å^#hcU]d+wy¢PÖH2&"¦› 'Ã;atú¶‘I0¼eARh7´S“´=ª¤N&á6I×ÎõÕñg %–³ç² $xÓ¥G ÿí…æWçÝÌÅ'e[nœBµXã}Vóˆãkq&¦„ˆ3x ì›_!¯æ¡£–oEA9ACǫٕVŽX@ur˜>~ M¸ßÁ1=eQçd"¡Ž(Ùµ—X|®¸Rlw¿ Ö˜”ƒ=±gçFú²(&qíë%Ä(ï^0L‰< Â×\VLÙ% ):Î_®.~¯ûR6)÷€7ËÒ »Éëêg(gºB gyoomiv–Œp¨Æ®8ÛÒ;2ÐUBìZAä§è^5ÌRâÄ0ÑßÛ&6Hüf‘sÑyÑtÛž„ ßN´…­c7—‚¯¯ú«¯0ù¹7êéy^…bù^:Šx¤"cT“ãËœ%ï‚m¢‰á=GýÞ¡M`¯¼wX®¼û>žr(ë[fú÷òF6NFÜYäüÜ•¿žÌ6×\J…«Gó¦çå #+–”$ï‚uÎ\}¯ÁõÁ$RA7Áík¡þ$˜ñ"ŸŸá‡4×µ÷ Þ'hà‰WõlfJ^$Õã;¡l ¯1œ"™j„Eú‹hÅÙÞ÷8]ß l'.;(t«ºWn•Q­E¨+FÜ*¾;{jÐÚ¾úZÄ0“?§Ü\Æ´ÐÖ±ÝüùÂ9Eú„9:E^ÿR0ŠŸ=}uÆBjèT'ºÂ‹ÁŠ!ã"§ss*Õ¼\Œº$ðÿ‡iQÆWò›àêÁ¨pü+$ ñœñë»›[þsòÍø~©,ïÜ¡b²É3ÌœZÿþö?¹w©Ê +endstream +endobj +560 0 obj +3299 +endobj +561 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F14 830 0 R /F15 836 0 R >> +/XObject << /Im102 860 0 R >> +>> +/Annots 564 0 R +/Contents [562 0 R] +>> +endobj +562 0 obj +<< /Length 563 0 R /Filter /FlateDecode >> +stream +xœ½[ÛŽ7}70ÿÐÏ ¸¬[©T@ kf:ØÇ] °à$ ,à,â—ýýU"ERªêöÄ Œ{zTÅËá!¥úýÉ^Lþg/6N«ËŸ>yúíi{{út[/ëåòö+˜çɤ‹_`ÜÛ—'3ò€Ï—Œñ)ÿÄ/oÿ¡áqžlÃíŠÃ‡Ÿ2üÓÍÎj¡Å¨…¬»üï)þúdp‚¹šiq—¯¿<ýú7ôdð°iÒG|³Ìå =éYÅ©ô3k™š=“C žk,X&ô딘z‚¥ç^›zíRUÿºo¹¨T0VL/•MiZF[±Iø‹]Ã4+ñ9:‰¼1­ƒã‚Çj•µz„gNŽò\Ÿ½U+×ù,~Fošëó¾>ó,Çãú® +?[prÒ›]Hàê œ« ØÀ&ØšÛÀüŵ_Ø}ÝŒÍBûkR¿Û çï„»±9N• ´_}\5 Ê´¹5ÅŒWü}«EÈÏj·¶/•W¬ Ì&¡ãMŒwv†8±à‚’òf°¦–”¶5ãùM)=ÿîmÝè¶\c ˜²Q0d T KLa SÐÌþ«“,ÒI´3ÁÜ66¹FÓëaä >² 5sg cêˆÚÔºgéœãŽìC›ÕH…9œíeAt `ÀÀ™Ûº¨»ò{Ü׃çÌf„o˜•­y­¿¯lÜ&íæ¤û´ÑÊtQx0NˆŽ›ʤW6îö47gçùظڡG¡”Ã'E÷•ËÌÕA¾3 Jõx¾kϼ?ßͳÎwö¹jüõ,·Å|/¶Îm‹Ÿ‚”Ô†.µ]Y0±Ï訤÷ꈎûsr´“­ÈJÁö"‘2ÅÌéîŠîVS•Æ}„ÔÐÒ8ÈU=1Ñ‘»%æg׿=!0؈ a BL@< Œˆ€!ÛCZ0iŠJ¦Æ¢#{î™ÁE4"Ÿ"ü"¼wyø4% ¢0Ói +â!eQˆ…™”›\)¿wøÌ•aä–br¯F¹¨`›´l05LjòB[”gÀlÆt$…Eõ_¥ „Ù+Ú–u +¨éö0. 4ÛÉw5’¿=3í \vªUÖ®ë‡ÌúíQ/˜ð•õMn‹{!àTtÆ@1'„lÕ”ô'©z ˆ6°+© ìF>ä,ÀˆùY…kd² ¤© +ˆ” ”ùKÍ,dX÷ÉÀ÷r.ÀàFg>,êKé©Äv›]©"ÁhÇš·nÀµÂ‘ö¹Õ”Èóºfózƒ«:ª*¤FÞ™Fïœ,ïCÅǶT4‚ +ÞwÆS³Yí`_.cÎùûmWCœÃ9U6ó–¿#Æ3Vá òu†[›£ìWú Ï.í¹Œä#mÏ%wi¸ÿ^X TR«òÅüQº5•8ļµ>£çyëÄç,—c1±ê͈´K2Wwò¯†°˜\ìÅôûÀ}c ~€íg©»P€[Kó"ûW)ÕÆ>±”5º*ªè^êßyi»aˆvbä·Ø»·ò÷Ô‡TZ&%cl´£³ Ù‡-…#»éòûN5ÙÑ^Šr4…{2cštkð3š“¯E…ÍG]AræóplŽüÂ-˜_IÐC¹ ¾–úHDˆ«bu€…¦e[ÒÊ2éìi)"`›ƒÄ†Ø ¢ïØõm™ëý)‰ãÖ)ž(c‹Ëó4¥LÀ9&ɶbÈD jéG4]àçÈWì ÜAfÊ% +7ÕLw‡q¨Rá#ºæ»yM”¹]¥;­~þûNþË´9o†g¥þ½N6Dí‚Ú¢ª@?ÉÝØô-FqÕ± +÷aõdkEì˾T*º™Öê©uáÂÚ …I%0 âÖÝ!¹øt¾V¸~ÛzG Я9rŽRïcF5‡0‘œ#(hé£fÅ¢¶uæ ,n–·1³{±ü2f¦¬p¯;"dMÑ,WŒì/c`¼]£šæ$ËI&îö„Í–ƒ7Múþ,É@‡#çZf8Óܽ+“²MQêþ€›8«YS;Ò7GÖòž1Káa¼]¦õ‰8vÀ^©B„®ó”Ï@gÅÐm¤-˜eãx:éS«:;·ÓH#Ê™5ÀQÅÂí3Æ—¶>®‡ ÷ŒEèÑVw ÔËSý*z8<ì‡÷åÿ¤Z^°ÑoÁ†Q‚bºÀø·ÌO,±é Æ@±+”ÐNåÜ‹œ”E‚œ” XÞ™ücÁ+¤5Ú©Ú Êü1í!!àí®!pŽÂÃùiŽHc½`±DäE¯T ‹ž“rw½dÓ5ŒN{Ü•…G¬TW…E:µx³Ã=q÷39³VLõ¡Fléî©ú/;ÿu‡ÂwÀVÉ;j®+vï4=ÿ2ŠM´eä]yË£†ñ#´\{¶îo?Hˆ2nuuH vyÃZBvvÄ ôº¡RULbÔ¸½6{¶„WÖLVœ¬¨†äˆþ2½PAxv³à-¸¯Q}”ˆ±°ë¡£Û™ö +EúÆ{yYyPÀÖQ»òb¹gAÊ3²jÖ*›é¢zT%²S˜#pŶ‘‡éfÄþ—b]¨ÁíÿE—œøÜk¬…äYcÌõO‰m‰¼!upZ€pGzoý0: :8ûsY)HaäÉço×èLˆšÕ(ºÅ£È²é>PF”××w‘@ʯÿ®þù»£PÞa¢ÛΑÕ!§Ôs{å…f3åퟒÚ3äbçÅ\@„Ÿöw_ÚEµr-îH„g¶ü¥|Enе²bdi†ó,± #/âÐVµdK…(¤L"Ö—T÷ «ËõÌCg ].È×½—é\ T +Œ5æ½·ÃDó{jÏ]…îµ§\뜼ô4¸Q%Ž ò5ÊnÃ}Œ8o潟Úón½ø³2BŽŠºv{OU 6x–ªïYVÓ¼çÆµ‚¨V-˜>\ª\0]Š=»µýN+s7\•ý•à<Ä<·¥—¢¢ÒŽŸn!ßç\"Ý`õ(}Å&ØÑÖ×öÊ«{~¯ûK¼¶¸³èǯMKõ£ì»¿ƒ÷–€oišµ ˜‹+Äý×_.ÿºüÃ>À_r¾aë÷S€¯?ùðéï_lƆ—ÿ~øÇüû?ˆ™°§ +endstream +endobj +563 0 obj +3045 +endobj +564 0 obj +[ +565 0 R +] +endobj +565 0 obj +<< +/Type /Annot /Subtype /Link /Rect [198 434.90 234.75 428.65] /H /N /Border [0 0 0] /F 4 /Dest [756 0 R /XYZ 76.50 241.15 0 ] >> +endobj +566 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Contents [567 0 R] +>> +endobj +567 0 obj +<< /Length 568 0 R /Filter /FlateDecode >> +stream +xœµ\ËŽë8ý‚üCÖ´[/K60 IUö Ôôc1@0½™ßI%’¢l'u…zÄ’(ê<$åûß‹¾ªøO_µŸVúõÏË.÷¯ËÏÏõº^¯_Ô'æyRËÕ†ôÜן5)gâ¿^ÿ©”rñkŽ_>~…øµÄ¯õ_ׯ_Ì:¹kœàë·kb\bã×-~Ýã×£üþQ¦ø,¿§õK\¿Í«™÷YÆÂqœVå»ÞÖÓ¦Ì××ñ9]ž×sžvm¢üqÃuÛ?¥ÅXLû"`x!­WÓꉾ4 32ä³í/‰Ãu¢ïEæ¥ü<]ùíYó±«#­MZ¼*É-’æ“ÈíV7͆ʽåÚüüÏO=3„¸5žµÃCµ¹þïþë¢`†M½*ýMÀ˜²“wÇ‹·ç—ÉSPÚŠ0›´¶mîó+¢zÎs»eŠzpÞ§ñ4ƒ¹þõûå쵺®éàzè‡x¢qL«Nß’ˆIÊ (_çYíŽp¶q¯<¯Wôl™+¿—uÊ8æ…Ã×ð³ÝæÍãVw“33w´~Z{Eü(c`/0î£üü,óç±û:$ …™Šþ*ÄGC<X'e#7äðs€t´™=EÖ5ÛßM1VkF‹…€q„ðõš-½Ãž§EðsÉ#Ñ>’Ãá ÖMÚï`pAЯ~Z ºßGó#ÙÇ-eç¡|ö þÌwtVô¹ÚœE%è|L: Îë£Ñm^ ŸâgÎmk¸y ö¼›\8û¤%×ð”×gãµG¸š‹a„„aÞ2Î9œ¥rp#<Òì¿[caó¾uJ}ævÆ1€@±^š7Ë‹oÌäQ„­@Çç{N‘¨³Í›jNÏ÷˜‘ô½ë±Ï8q.dx¨êCòߊncÏܶé¹âÖ²ÌÑ­“Aº¤zú&æ«c?ᨑÏõ¬¦¥ +Y1¡`Ÿ%ÒÝH‚=rÇ®ÃÚäͶUÔÜÅH ‰ÃØFT­cL‰3“ZLÙ t¾èÙj¶Sݰ©* Æ ²v†¶ù&Ø >–.³Œ€ïòyÅh‹MFyBqmV9tW¥Ó)ÊMéÊŠ2g-xÌ#ªò#½gÕDZ÷†,rèÁŒ™Lot;F† rÏYƒ«T“Œ©ì¡K‚  ¤À—‚hUiIwªJÓçNQG€áNS“ÅO³Gzc[ØcëDµUy>ߤ,lŠÕ9KCçuÖÃA”°8²WŇÿ )Él‰üJÕÓ~ÙJ@ÒJ¢;b;ÃÇx7-#´qãÌŸßJØBJÍ a +ÉZsÌåç÷(Ù«†œçY¸³ðè3n%\×;–’)Sù\3ÝÊÀÎ~Ž)k ÝŽŸý.½,A^î,±Iº_UKà}Ó«à݋܋9NDßp5@œ_VÄ7@õbRÜB¶ B‚úNúš¥)ÒUßÃÙ²wv œ¢u•Er‰ vGåJù$~·Œ-nfF}WdˆÁcmè3¡J@dÍ Äƒ_@Tªmp0c\Tƒ-F¿k4.:΂áO°9èT‘“lΈƫHôÌh/æÑ aš#Wó jU¤ó†Ü<š¸Ï÷¬vŽy»Zº‚”-ivZÔ¤îHIÚÚ!å»Cþ<ÛLúþ>þLhü¹Úú94ßþœ6/¶6!ìB·<Äô“±ðMOµë`{¼A̓0MÞÒK¥a,,£‡TX—Ïí%QÀy§†Ä]ÈȸwÍ‚“k³Ýá=ѺÀKrKw´·'’¡è¢(.äÉ[©Þp „3 œA’*&óRŸé³j³©@×6žjnÀVNð¬Pe¦¯'k¨útÝÞÞ7×,½ŠyY`"±йKO¤æN÷ïHÉT?†Ó|;o'¦,Uó+N9þ2>°°ßtL¦åƒ +‹ rmሠAø½÷y-AÜÔ ©?Œâ:‡Wk“„sµ_°ã:·¾‘(8j‹çí-MõŠÍÍaNÈ… ÛeYJGaïwö7L•¸ÜRfä·çôÐç)ˆÀLj 7%ûrÕÖʘ‡g1ÝÄd–ím×^˜ßzy-®£Q +ŒÖ°¡_£/L*Á.÷÷2$’nq­´bqýÿ¬ë‘ yÒYkç·>]“a©¦™ ¼qƒmŒKVë=†G…„¼ç™9Å©®ýš½mÏuTkÀœ¼;NVâ›stôVT´Á&BLÛñ È“ÊÊw AÍ9ì×àïÕc7$EÀauäOÂi0SïHíñO)Ó$½÷?·åÉIå‹bv6©Œ@äéXgÙUš2gˆ±gI3‹•G.Y¦|ÇçÆ?§Âüeg”'tê)‡m/œÄßû½À^¿á:œµ)¦Ë°×!êP‡êcÆÓuû–¡„H¯[[ ›$êEïÔN“|S›$ÍÑxêm¤„n­ýäè<†·tÙìqîë"o}#Or_|Eå8·uÆ£†ÄnnÛ·DÐg¼.ŠÍòÙ~'-©HTæ­L—8pôf¶wf®Q=¯2(Á ’ >NÑûâÖé@Ö£VÓ[ÿ}È–³Õ³ÀvKÊ‚;;•ä ÷ÉM»Åár#­¿Ë¶˜v«K‡Z×ÙnGm»\&œÒ A©Ê¯S¿4‹_®­e¢dTweë„XïÐÕ§v•‰§¦¼«¤Tk¯vJ¬q74¶DY‰=v-ú½Imõ®<lã Ù)éÏì]©˜gmw“èQV+–ÕAAõÜôyÆçYP¡ ÁyçšøÅ…ì ;8>o«RÒ|Æ'înë>ó¨oñ#»Õ@q™˜g1o”ÅIËBØ#¦ç£«ÆŸXæ ˜šq~è7mt0«ï¢+ØnÿÖljÈÌ¡º9Q%ð ~0Ö2+~£rŸ7ÏTÞ8[àm¼ìM‘ —د´B<-øÆq®VxðÙíèh˜-[¥Ñ5Grý”ØØ972ßšï±¶ùúÊ"Ô"ñµEÒa$oS®}n./ ×è÷ôsœÏúþó³ÉAu^°„a¾)’H¹{“uØ`ÝÛÿÀ)í%kÇ1Ĥ´NÑ´»š‰\”;˜kºËÙêítÞoÂ×K +!ß¡Ï +‚-0N¿Ê\$?kË\ë)nb|H¨ëº`Œ›Ôk¢È/óŠ*ÏAw¯¿A® >Žqæ|„¡øöb·8å­ÂW†ö‘ÖÓ"•‡0ªÄp}þzGÿ”ÌÉqoPæD9çµØ¿¿;—––óßBíàk]…ÝÑôÕºÔ4,È»ï»åÕå“{«Å÷à’öYRÜ]Áõ%Llg$×}^«ÚýÎ]7·_„:áÖ§*¾éÞÆíÝ—6üN€xèUiyud{w¬£0ªxïu.¾sÍ«£»¶>1]~õÎUšÃšÝÑžCŒñµÎ¥V’;cjçÖj=P°mt0Hj›¦ ¬¦«£òT¢• ñÇF:Ö÷ޤÁ±ÅÛ›P q¹­!´7Ïe»ôR÷¯sÅñkRç¯s‡^¡®žêó€—}Ü­>_ ãr…‚àîôº ŽãŽ +YR7õˆnŠõÞ²Àyשܒæ8˜#÷k¸ÝÄë­'óZƒÆÐ=Î1}ÙO1Kh¥_‹®½[ü{÷Z«’0°xñâ¼Ô™Ÿ{ŒãÛ™ó¹o߈]¢Û!¯àì•ó=Ž5Ú¯©5Ñ]Ì€À’\&Ê Kªl‘qÞá@¹©yð$سõÚU¤œ_–Ö„ú¹mÞaƒÞ!0QßÒmr´FͼØcs'‹¥×xøÝW—®ä÷[úVq<¯nâÖ詽{]P±¢Ö˜©«·\ÊêµXLÑtÓø k¾øØ&(-ù$íMóËV6Aˆ*-+B5Sùþä!KH W u³… qn-)† + v5m`‚φ zs ˜L×ОUK¨wî0ÞîÑQ¸Y¾V 6£áµ5œc¶ ÔÚp y6Aª?DïóÖ÷vÁOc?~¬°î÷È{’_Âüš¶Éíöú*9<Êj¸F»â":1˜¤«LÈ!땽än8‘ ò»3nͯØPÛ…˜Êí¤(\c^§ÞO‚ѽ[4(G!HDÛ:ŒrÆaê `öÜ’ÃúÜ+§RO¬@@Bœr“®'Ä»Ý"×Kõ ÊKoÚÊ(»üàT†=7ŸqlX@²bÜÆ÷C×À *\6ÝtÔ™+¢Qç#²&±‚™]lÈØð:敚ÍKÿ· ÊqWÊ™kOùÖþfJ[,;ÞK†€ ¶ u¡£§ÇŒÄš–EúŸx+•Né~O +%:ÊåbjæéüÝëĤ—}^ñ‚¬û颢l«ê­QLnM¦ôŒÕUŸ_—_.ÿŸõ´ +endstream +endobj +568 0 obj +3575 +endobj +569 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +/XObject << /Im112 862 0 R >> +>> +/Annots 572 0 R +/Contents [570 0 R] +>> +endobj +570 0 obj +<< /Length 571 0 R /Filter /FlateDecode >> +stream +xœµ[ÛŠ$¹}èÈgÃäè–R&CUW×âG›Àx×`˜5;/þ}+”R„2òÒ;k†bꢔâr"ℤþíÅ&ÿ³ƒãâò»¯ß^~}¹¿¿|y.Ã2 ï¿ÔÓ4šyð Æ½{1£ñ!ø:üÙ?Ãë/Ãû¿ëð86Šáv¡áÆÃ« ÿò´S·P2ÝBÖ ÿ}Éï¿¿š`*øn+i +£›Ï—®Ã—Ñ;1ÜL4ܽæáoøšò+æï Ns˯{~å1þÏF°3¾ŸÖïa<Œuühs˜´Ž7Ë*ŠuãSAZü‰ÏÒ`&ƒÿ[4¡Ãùòú6³8ÞæõlÄuAŽgo﨓cÂ<†y1Žq>›1¹áûÏ/¿ü‰!y\¢æÍ8EÂÈ,Œ‡ð$Ý¥ÉïÝÜœ]¬vø Žsø|Ï:²&¥ÌíÉ‚M[Ck¹'j¨ìR-CÇìj|ö2¢¹¡é±.VIÌ•ä¢{S ÄYS’ŸÛ5Än8—_çwwüíÆðlü½}Çe²9wæþÄeCyLþ õKà¤Uö—¶†vÁXd#á_›÷‹`´03=[AoK‚[Ïž‰8wÂg)=”µ1—‰¿ÿ ßüý§èó4J«Ï©*kï«¶óèxpûêù{Ž„·¤Tè-§Çà:©Éå }Zã OçèËÖ^£Ï  ÌOk’2a^Æ9m&[1TÍwb¹·ã<ã,É‹œÉlRÒ{µ‰÷|µÑŸ„09uÏÞŸjoý9JÎòέ…'"@dŒ]PnÁð¢ÜCÏòÜ š>Gü-ÏãRu$Ï"`Ÿ`âœÀßY…Ï ƒÀã„©qÆi)]†>q'3gîýs½qÕ„uý)¯í)ˆ#SÛ7õJê%Ó¢jͦý*³Xyöu™)Ьˆòdcº­•Ï>[Æ>-þ“,†Í`#Oª5_Ð ôþ‰aMH@ôÔ°îTTºáXLºô¾ªŠÏXz¿—'†L– y5ÅÜѬ\‡ÜèGt”c@±sa$IÓѹ±’æÆ‚IÔ#ñ$µ4èV—ãðUÍ®¨*ÔÃzߙƱRL&¯QMóà¼!˜ZŠyÙ¶¾g€ð3Þº*ù`aqGÚÊž©rîÉJ:Åf’‘ÏU*P\áN¯01ø;t7§‡~nK€Ì[ý ÙÛYQž{ø·Ò4‚ËgmáªübZ?ñhñef¯€ªÄ)s."xž.®/åLj¿wq¾øº’7»8ò6 cÕ&«º¢ï‰‹X¦À}ëé«lø()‰¤žŒŒ„¡iÆ´,¬OÛ‡ÏÅÖ·³=&מ¥"ȨI'Ãì6È,Ež8“ªXEa×¹™}~5¢½ØG“l“Ä Ä©-ã.Çf:l—¾õÍ'qÑ÷gpÑ` Õ{Í"5®”ºrIÅ]~±°mÁ4¶¼=݆UJŠpΩ´¥ÒO¦‘8%s¨V«ÀÔ@• «øóUϨëòŠßƒ:ž­8ñêëAÍ.™¾“û–VpŒ:ï®ïjM÷UYý$ŽÐ +ðeLÒÒ +og9 (ÙÖ3fHÎuþ\›wWë•ñkïQ·-§ìMü#]3ôiIz´ïÊëÞTs^¡òè2ýùš›75 +€û(Ô=GØ!k6X¸ë:”\“i{7\æ³=žÐTî½ Ð—‰Öo÷Lågu>êîî*òà!7è@Føadàï¢_EEe¢B#gü8¹¦’He¿—±§R#ÛÞC„tÈtc¢šjÚJ€•*!úUÙžûõ8Ï›Gûj²f;g >4Ðw|Se +š+ÐWFRó™DoµJWzÎKœš H2Sæ§þ0^˜‡õ¢¢záœ0å‘ë}Z)5?gãK'J¨6J”fàá€l'üÙS·ØYóÂKñ¦œöu™©ÚÄÁ¥8Ö@`ç1Å ®8§t½¼§&yN¨F£­ÌVw¤[·nNZ›ovìlò8Ð3dW”ßY}.‹‡KЇ´ú6†`/²|¾­IÃã˜rXÉÆÃçò̲~WsÖ+j++Ï” +N©ÀƒÃd-Ê’IðÊQ5g›{ø´±‡¾Àæ%Lò3ʇqÉÌ©¬›ñKÜ4©%8^¥c)Ê)@jvCq(Šû`¹Rk¡C;9ÚÖ¸Xø³!çÜŒ†Q–æÌqþg—Ù.dÖpJgvLA˜žvà›Ç ýæ¯fMù\òp/>kåDÛskѧ(Í›ÍotjXZ9¤ïúíJ2(ØñYá†Î/N +ÒмA$Eã^ªêÓùEŠ#⻄ܨýº§k0?gïüä i +Å­miʧ¢/§-ÜL±1Wnc,¥ 0ƒ4¨žæË9g嵓ĉfíÕøD¦‰c'Ô¤ +%#²ÌGoü¸ÓöÍIr:•|o7ÒÜ1ÁµìlUlÝ&ZpâÌÕO¢`ÄûbçD_Ü„VÓ";tÙã§À«àî¶žJ“Ý4ÏEá9-Gv„à(®ÛÖšUÃÒjçÕ V +Õ „m¤“K'Xý.ÂÂÆ[žØ‘\Õã5*± DDDOjÜR¿OˆeÝù½›ÜÝ‘® +­T~ Ô\[J ®ä!$3Ë%NÂäqr·c)×KÄœŒ +œî1™?¸]ØõA{õW‚<§Ïíï†ñ©½sÔKûr|+UÛ—#û?ŒŽ_¶StØ Ìh°Ó¸uׇw1hÉ´õªI*M¥ $\mÊçÔß»çû¾„.Áóu96uw*†¥íDT­}¤]™ccëF?Õ¥p¸Øó£òýüoü¸½LÁÕ®maߺágaž³Ã2B:#á–» ï8®b™í1ž³å®ÐIÒñ­?.bt¢d„.Ó«4Ëg†7¹Í¾Q¹£uõbg°ce¶xN§ÕaÇx2ªF26OO·nìýEj×N3ŒÜ‚Ù° Ô ‘L +¥:Ú(ÕBE½gFáG•ųyuîNwñ§MÛÍïñÕØÅ áùRŒõŽq²¸˜ÿ×K§Ñ}©9;R»Ðu_ª3”ó۽ț‰Ö  }€ín¿˜öW‘¡£oHê÷3á€K£lzrüà k#l| 1”kÚ,¸‰²RàT[ña¤BÕΚ¿YíªÔ’õsnÿ ‘*xç­–*ä5}üÀ$¿ŒU#C¹¥°—­®Ee®*ʆM7íuÌNtÌœ°yÖ5ÕÁhZïu³ÅŒ À€ ª¡+Á6Þ0Ø~~¥ß»+2ÛÉÙÁóžwFôg«ÅÛX`LõH0»ô´bò„¿Àrxñ Je6wééo6È›‹žíOºSÓboè*ˆZ,ûÓ¨föG¥r0œ®óÒ:ÆSÞTÏTÌ>ÕÕh<ÑÔò'5’{å^ÏI•ZÒ xÄÇ?3;"‚ÿñ¯s|`êD¾L{¾ =×9€e«s„ZUßÞ_~ƒKî%ûXzQ;ç|<|v¶4¨ßþ1ü +£>Áq.Êàës6DÈ÷_¿}úò×o°õøøÏ§¿½À¿ÿ/ð 0 +endstream +endobj +571 0 obj +2889 +endobj +572 0 obj +[ +573 0 R 574 0 R 575 0 R +] +endobj +573 0 obj +<< +/Type /Annot /Subtype /Link /Rect [401.25 752.90 504 740.65] /H /N /Border [0 0 0] /F 4 /Dest [711 0 R /XYZ 453.75 369.65 0 ] >> +endobj +574 0 obj +<< +/Type /Annot /Subtype /Link /Rect [517.50 752.90 517.50 746.65] /H /N /Border [0 0 0] /F 4 /Dest [714 0 R /XYZ 240 478.40 0 ] >> +endobj +575 0 obj +<< +/Type /Annot /Subtype /Link /Rect [72 735.65 153 729.40] /H /N /Border [0 0 0] /F 4 /Dest [714 0 R /XYZ 240 478.40 0 ] >> +endobj +576 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F14 830 0 R /F15 836 0 R >> +/XObject << /Im119 864 0 R >> +>> +/Annots 579 0 R +/Contents [577 0 R] +>> +endobj +577 0 obj +<< /Length 578 0 R /Filter /FlateDecode >> +stream +xœÕ[ÍŽ#¹ ¾àwð9@jô_* `w·9nÐo°É0ì\òú%R"URÙíé=cì¶J¢øóñ#%ÿ~Òg•þé³ËfÒ»_¾~;]ßO_oÛy;Ÿß­#¼_T<Ûƽ;©E9“ürþ‹RÊ¥—O¯^kzÅôÚþz~ÿ÷Él‹;§ ÞÿqNW±éuI¯kz½àçWœâ ?ϧ 1­ßæÕ«˜÷†ÏÒé9­ð]ÖÓçKëë4Nãxíóü´k“äO®Ûþ3,i1P@8ŠmPË„¾4=f^ð‘·¶?§×‰¾¢Ìß{ÔU(cÍ롎´6°xU’‹#Ì›ÛmnñFʽ åÚ<þëMûÎCÜ–líø£Úœÿ{J￟ÍPÔ«àoSv îþâm|\‚tJ[=Ì&M˜kÿöž¼Úç¹]\’\ð`²æjÎßÿyúõOÌíÁn{Ï_“A} ©|]%éÜnÌNal+çÑ¿¯ø·jwR§Ú¯¬“´»¥--í\sïFJY„+s ZÞ–÷zC[Q4©Xcx[˜ÖŒÝ¸¸˜N¾P½,²Ûpí•Ékñï¨2íqlhr*z.ýÝêò¿ ÌÝ/l?7#0~ûÍõãA¶²U/60 ÂÛHØK›þ xQm{Ýo¬nm\6$=·ø”Û½7l^‹6¿EfŒbë’‹6ÏÂ[Œ{)¢öá“Ç_Ð*k³¬&/ ؤ§èUuPæ"Òz×$ß•yç­E>÷&räµÑ;²í"޵%%8SbL_Ú™¬¨ˆÅÒƒšÀõ\'#t3 +ÀmÔ˜ßHwžžEÀúýÚæ#{ö¶Õ¡Ù‚¯[#´Ã-Ò…Ðå¥{SS=e¹^›ÁV™u’Cñ3·£ÐÉL–‡m5±“ß^(­Òwä“äŸC»'VÚ½±^MñHìçÆôEúfØE¯Tø6éwá‹›†QÛ&Žû 6 ©ˆ/¼Š…Câ•lT® wvÛaaw„…@ƒ‡+÷[΄›K[nK?Kµ^Y pûtþ6·Çâ¶l"hÈê£nÔ] rŒ”J)ÀÖñ¼ÎÍç®ü±'3 ÐéÚ{Ux~ +”!BuFt¢J£õ(`Žœ ^Ë«ø°jå ½ï_•ŸôwÇ!êøµÌkÄW¾2T°…Ä%%¤r3ë--b_Êkǯ >CHGJ ì·–1´iÍ + ºÙ'=ó§ù1Ô9CˆPzaÖ4"(:S R‹¡—nî׿ÔUÞ%˜w¯«GRÛ¯,•²oÜ‘-aDVs¸RAÐgÈtàØî¥ŒÏï4ó÷¦|g/ÅÑlÂ÷»øÀG™U6#š^Ï?ÏYÛ–9Æ6ö+*iµ\Iv!›ÐñÖ‚ >¨¸?JCŸ Â`DÍrZ¾‡ Ž‹³àéä¤gY¾¢Yg žjõéÍ4¤>bvƒöòœøH9ô\Ȫ¥[­ÅÖÙÒø;[xÒ2Ò—Ðÿ!] 5‘™Jí’Q¿ù^¥ÿ‚ÎŽýlç?CЗEz;Y[ïD ¼ŠÓNùC™ÃäÒiDàôÁv˜³@$g]õO톩§k¼Oïr™h#µCßåX̬²wh¸¶>£ F‚­Kò­ üw· f£ÏEßN‹FÑã|q¤è">¤üê$#GM¾w}ŠVƒÞÇpÿ `g7GSÝÎêfMŸ) ‰¶“èl\îÌQÙ8«±Y"þ;ŒJfŒ§úƒ€è&Â"3FÂÆ„…|¸R¢=D[¼uVËi–m²Y­ìÅ‚5Z‰Å+°ØØ^”Ô F‡eqa´ 3¨dnõÑêNp›WT¨Ôö#¥ƒ+{†¹`¥-¬2¦¢¬vUŽøq2š—åߪO–ë÷z ‰qO8îÛ0GiŸ}¯î#¥5·Cb³59I¶Q샃‚AÀ&ú•}†÷Pù=@J­ü¢44‘* MRnq½ëñë±¶™_ÕvlÕb¿:;œeº&}Ý”¬èÛd&Ÿƒˆ•çÅ6v³_UãÀäîÌõîñá”ùÆÆ@cTœKõ!5è|ŒŠ¿^ʸ-Rý­%HæÎf ©Cs¿‡yøM>ŸE]YX¢ƒ’é¶ë(-€–q^ªš»<;àHø”!ö§ÓýцI ÞÅ¥þIC¡^à fÀñ£€Œ—ÔA¼w¼0¦¸)LÜ>LŒÏåׂjZE¿aÐuŽV˜Š?× ”$Uåy ÉåýAÀšm•ưœ–Å®“8ân¼Èëx¡hÓâ-£Ú¦¬KF°D‹ +Yã@È1i&Œ}Ò­Ðâï.|ŒÇçáÑÜ\ð¼Jc_FóHδ®p–Òd…³ Õ‚W$B.Èùžû8á5Ýν`ÿ}‹ÉwÛcÌ´×4¯2ÅyCÚnËÝIZµèˆl4J–û +z4ro»“NûÜ”½’*ÝöÛeÛ|÷l—ksb¢³§fv•,_/#FØÎŸØÅ(o4\'˜ßŒEtYߥ:uÛ';M¦ê´C²J¼zÓ<ÜŠf¦aÁzÄÒ9[™ÕÅGg>´¢w”ܾ/ƈÑú<ññ‚ñš3cGd)DjÁ<.·švØÈª¶çŽ ´Ê¹ILÚ®WÌ}¤ÕÊ=9wÁAÊìJ&QÆ\™‚ú3…׿¬d¬ÃA~YͲòÇT¶3¨ FÁs¯ÒqŽÉA{!Ùï‚÷ÇÊÌVBÏ'èvÈÉl|ä8“«ñžo>Âà…ÎK=S³"‹c P,ŸoˆÞJ/Θ¦{ê¢Ôu/M;¦w‰ë]\¹w«rÿ—m~ÜC·z]L¯¤JÒnªž{å5•~¤¯oÖ‘=œe7¨ZÝDtawÚ9vñ¨òÅÂP’îÎw²9èëø•%BànlŸj©•Îþáë5„Àt ëÒæ&Ä%^ßï®eí2VÇó{š+}RoŸUŒÁæÆr«ïÑ› dútŸTª Ï6î•ÔRŠ£¾T w×ç©é­òû‘B´ctÆ<ûô©v‚N¼²9*”œñqèv?EÕæÁ|Bh£Eš›y>Ya’Þ §Öƒ&ùÜC:h‹p UjµV~5oj6Y@7"“&f­ s†CÏæ•ììÝy¹ Sj¬,cí· !eOÜÀu(6¾Þ Ã|þÃxZƒVÌ?vAåo;b„ßIÜ]bÓPˆ%l뮢—æ%r›äð"ô¢äL?çÐÅEÄx%’?@Åï»süû™‡1ðÖ®Ôõ%&wšöÝ­ß{HàõpöU„zÞ5®¿-A‚/NžŽîÀ<‹Fœ?ÎPé êœÐ3Bõ¾Þ»þm3Œ"5>?Õ‹ ×MЀÉy]œU‡•夑@›oÐ%ˆw%üݳù‚«D­a +"ÅâÚ»ëÍ=˜µ&Y=«<ñ³¥ÃêÉépm³m¬I`8@Bít»˜Û.{æÞ¸jF0üÉ^†éÛ +ñ¦#|xëJKÌ»“Í+¹ªû¢Ú­‹5Áªj=¢>ÈFª:á.›.ãáC1AϽuÍ0·Ä^¸¦²¡Bíèf÷Ã+ªÚ˜epÉ#;Lžß¬¹)Ïç`${§PñÔ@¢xp›$;àáÏ>RžŒRWË?e©«eÏO—ëYZ‹ í¦Z)D¾DÑK°ÅN.ï0cc¡£ÆuÐŒïÝT«Ê×7¸>Å9Ǭ¡{÷óÓèZ h=É»ÊÛ3Ù¢;©)ßÖZzJ´RmÌ8ièÒ‘8¡·óqµ à7/e +¡¬IVxäöÿÁH5ʧס"­ïbŠÜ>K‘r‡MTÉÃÖ†;qÏ\÷$*bÇ)Tâà ê(ÀÑ`÷$Šîu¬„"pÅOºŽ~ÜÄÄ“åWî¶TAÜGUôè`±Ä?TvÉ<;= yÿ@åUoà_ÔSÕSö˜[ÓI=N;Ž»R–ÚÙ}s„³Ç;æoï§ßO¿}1‰Vh“u +?~N~âTZÚçºì—o_¾þí›NûúŸ/?Ÿ~>ý>\ñ+ +endstream +endobj +578 0 obj +3290 +endobj +579 0 obj +[ +580 0 R 581 0 R +] +endobj +580 0 obj +<< +/Type /Annot /Subtype /Link /Rect [177 752.90 276 746.65] /H /N /Border [0 0 0] /F 4 /Dest [587 0 R /XYZ 72 327.40 0 ] >> +endobj +581 0 obj +<< +/Type /Annot /Subtype /Link /Rect [300 632.15 402 625.15] /H /N /Border [0 0 0] /F 4 /Dest [587 0 R /XYZ 72 327.40 0 ] >> +endobj +582 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Annots 585 0 R +/Contents [583 0 R] +>> +endobj +583 0 obj +<< /Length 584 0 R /Filter /FlateDecode >> +stream +xœÕ]َ츑ý‚ú‡|6Ðin¢$ a ³?ÏàþÇ`p¿ø÷GA1ÈARRUÝŒa”oVÅ%ˉàúŸ/öf¶ÿÙ›÷ÕmŸþò÷—¼<¼üñc½­·Û¿•Ót7ËÍÏÔîÇß_ÌÝø°5øËíWcübŒ ºýøŸÒ…¢·ê&y „{y>ضŒÖɽBA×Ìní0ô`¸RëÜ]˜ØúോBœYv|"ОÛ¢¸¬hÎóÊãU#YÁH^œ¼ +”£v© C?"ô±» JKÙXû*—q×£þ­ì@ž_ÒŒVânÒˆŸ‘x UbÆ +t:rŠ›²miEK6ŠŠß…òE3¤ÄÕ€^ä*ZBýrfÕÓL­ù•ß?Zµ,’N{ÿf&ÕSH³y’ÐlǹDÌE$)Æ´~%<+…ä.ø,­½(<ÿðlö e’¼t—F›ÁøØÁJ 7 Û|ýN«Ywà«ì½¼åÓ¦ŽPÀÆ þvŒ~um‰ëLæÕœ;ÄÉ6Áá Œ<ǽ¢ÑÓÅçÛ¬]áQpà·É£ tiŒÜ_'ÊêA1&hùN’æ@]Å”J0J8åf¹ÜþLÝ7§§ËTS|W‘r àâ99µoŠV÷ÆØÒ÷Èkq=}¾ +PÒž?a©èE”°ìŽ!³ y¯ÊM”‰°G(2ÄD6'SÞÊXh ¹°Ð@¸VÅüȰ†vÏ® +@yuÆP6PVWÍ»¤Œ«œ ûÒÓØ=Wó-ßMy!Ú1]]Æck7qš~Çi¦”)»ÄÂþøœ:4i6ûä¬*6#4¥ÖÆ-§}WT'Ó‡jÚ†ã»@ÅUÊß`z b+ê!º¯Z½vÇì²>òžª”ÒG’„e±¨vkrQ(8'áðÈF¶¯ròôÈ•…NxŽÌœ²¸-—žÐVfá)j=©jOÃtÿL.íd.=â +ÂS)í¼ÚHæaG>«¬ƒ ªRí´”~“ë«1ò˜“”.2D38`ù£}ÖŽBðRÍ®ˆ°'¦ àGííJAUÌ©n¡9ç7.¯)ã~0ÄŽˆ}©ÎèPMÍ!æ9w®>Ü‹¯ŸC¢»5”ÀîŒEí¿Î*KÝDâe¿*ù>H/ºéH×;©ïˆ€k)šÂ,3ï¶E7+´W%Ð3%‘¥ÏäAä§ö;aÔña¢mŽ +Å à\UÊQ¯K~e ØáÒð(6‹ˆ =ûÁUú.kENä×¶ú9ˆýc7k ùãÄd’®½&R /Ò³˜ôùµzW‘Ç#íõf”§k-²dBWB¶š[‡pò!™âúš /’—´ÿŠèðD3Š.jÒÇ€›9Fj!…Í FÓØVß_"àðû›É±z—,ÇÔÇX¬8 éù+3Ý[ÒÃ=`¨¸‡-äß`¸,A”B;ôÖ6IX*ædSÁ9¬è¤گIDûbaåhæ(µÿÔÑUbiCÅìبtµ„ùÞñ!6ó|Ý÷,íÛ(ñ‰õ™t|d_8þi˜›ÖdGP¤'3ybòf^À¹È¾³±Ïiž±~húFïkѽSó =Òú5ot¸,d™ÑÎ0>`®ül–¡€¹WsÃi´•ɽŠ0ʼn쉚iöFûú´ÝÌ2$:¥FïZ©0¡O%áh9?;ÍLL7€Ð€nµ$)!0à¹Ã‹Êyj_LbÑ1„+‘±µpŽ=e™M1ÿéN´ç,;,{sØÖ3pEÖnœ8Ù­B¬jŒ®ûɆ’,¢zÄ:FþO̽·ßSª¿Ê>"”v W¹A bÜRÖV%Ï`õ,”}oÙý09ùónÞr«¨z¬©+A1ϪAt +ûx^V3 öÛÊ¿„VÄÎD¢`R<ŸE%S”ñ æþ0/Ô e7fb2Ø• +x›VÐAdi=Œm¾GèË'üã¡ïéÙ€O¹”ÎbE†ó!¸¢#¶‰bkH¿O”+ZÓ© ñ(g ©†$6wr†¦Õ3¤d$cç¥YbÝ{Ø÷P¹Š8ö ¯˜©³ºÉ¨F«”Â/Â¥Ž#àÞTÝÔD›ßéÝ©Â)GTšXûd6è°$¤vË…©¯ó=*¹VÕ °1ɨg·Ë,.»Jd°&é‘\¤‘¿kéׄ†„µo ÅcÕóÍÎÈ^t§l JzNâ¼v_ç0‚ôq¦ddQjvBˆlb=ÂC9* + +Ymú°¶?Oh$ÿ;ùýGÛ¨ã>_sDfÀ騤´oËÝÕ&ŠB‘Ѱ)2uë(aXMŒ•ž=»|²vÊ‚ ¹;µ÷ /óDwZ®2ÊÄ|ᡆo}§³g,é9ÖKm&`œ¥=ñó*޳ƒo\U©ÊPÕÕÿÊ]¬°^9žmW#æ¥rÐK_èf€Ïº …â`¤å[¤ßùü€7‰º[¢Nõ-XÌÕu‘^yê ?rfßÈF¶òUÑl¨a•ò¨*„ Ô$»,úGÒ±8bÎÄÛÓ¨˜‚4­ÿY³úÔn( ¼=9ZgvV¸Ûæò%gØò¼ä–uÒ|ÈÔë/²ÊÈšR"UN™†Âþ·TÜèÚ̆³Ô%ØåÂ3NÂrˆ}‚sÒla2¬¥˜DÓYFٻúÓè§Ëv vÐÓUÚ;C$ãã“…dgD'Ck¯°t‹½ŒET»œ¿AÜq~x*ZÂ!Ëð9SŠ¥1}r]ͽ[Ûè™·™€_µbã®ÍFHõ¸¾)øPJUã:J>`¬ANìR¡œ“L>@—G\×(|wÉ›Éô‹²Tîèwƒ„‚É’ ˜&ÄÕg°Qç„\®ýn((¾4ÈÒÈ•¡…œCÀ wЯõ¹r3¤¸¤#O@—HNgà {׳na/À`îGÀ‘×Èõ ¯ÜÉ\%ïa†aÂJ¾p2n¿$]e#r”hz¢óš:Ì3Eiï^Á§ƒSƇNù¨¿÷[]áé¡^éC¤Ì¼¬é5iç;ÊA²gGn<´Ì|ˆûB’§`ÀÛöjJRÎ’ +› +ìLíÉçT7ÎcŽ˜ç4¡3±^ˆÕ:”ºâ£dí§H[»r~šZg=kGlÀŠáUuz†¾.ÚÇ6«jrN³+ïͽ½É‰kt3ûˆL»˜4–hSvõžVÆ%ß.'໑aä¾yÁR 7wD¨¢ŒÅü«fTaŠ3r éí90u³ÎwެhÝ㬞›¶£5¥¤898(¸hI̹‰be Œ ~ŽÑ ª‚ÔCRU Ÿ.œ-ÍKÙŸXZÔXÎbñ  (ã(ÿžÅ'hÙ“s–'ªŒ8[FØ ˆRèoÕ gû0¶BšK’½:32é…Ø'Ty¯Ô=Uºt +i",1sYŽJ³ +ç•×ÈëgTx ½€tî]µùÎUìÓ5;>b}˜ZJÖ2Qûö»ÕT& +®à |³¡ +CVpT„ õÏuý_Ë^M—ŠªÝìj½áïíôa°#¯/æToÀñBy> ñ¢¿ïú a£v†ï›K3ü7ðý3Sœ®ªJ–ÑÚ\6ÓåýºšÔD€ôF$©Jß.Zê–“-Èû'ž"Xíhëg®ÁDœ +îϺqS³¨ˆÉÛïâ,ÁQ‹;Š08k'Ö6=aÁÙɪ*Øh¼}åôMçÀl ¨èDGTÆ—jþî´É…@ÿè9Ÿ'G Nø ˜ƒ)ïjÁwBÕŽû(L 9êæ°áÈÙ-kÒÁ:ųG×»ÕJª;¾B}\ñ~FÁ|âDÉOéM@bAõœ'äk Ž;Q2;½&6‚„ÂBót/<¯6%Ì®» ª|ÊXBÔzŠ»ûx{Lñ¥Qô<–wùýn×nr˯yå-(jà”וøhöMŸLïú À†ÖS£î­†/xpºÈc+}fÞ¦"Æ€ãPÞRžl¬[g'Ø2ýJ³I ®„î‚PÇéVˆho‹7B½Ž6ëMSKùýW´ÿPb ·!¿BQÜ îÜŽ,6”Ÿ-—|rfµ¿ @†ý%½ƒq ôÓRHçM»üÒT`²‘vª‰³Q9 /Ú«ïhP)Û‘SØUZ¡ß•°¥è»Þº¸Y‚™–úðvGfdÄFì4²ß†ÛÙºöâèÀɪc¸¾~î­ñ¸èþd/ôZ>åˆ{ú±ídl_Žsíp%õ·÷öÛçÿùgq„Záì^ÛYûgk^ÎHCgûPqwö8‰I“ßKϤ7”ò„òÕ”á…ôŠÒíÿ÷W”š­òÏû«J+ôHW"`”~Ùê.o»:€åprܦ¢[þ°uX•óÀw|õ-§?Ž—Cu…ßaxîLã}í£®ƒ•¼Q…©åDαاŒ FX‡?i*?FIQ|í8UpžÍÑïÉS¥×*G1¬ö8xcÓ™ƒNVµì}—rší殺\ß’êÜúÀZ½z†ÀYBh³o<}%E7#ò!/B3 ¨eéÕ ¬ÂïYýh¨÷]R}>ºwïç-+n©…@{‚10æzš±Â`~‰‘¯ry0Lg‹`„q¤pq…7c-ÂÁ̦òVJñ‹sùPëÊsµ¬p¬,J!ô=èC²ñÍÈè)ν÷5Åt ³’ò…M_ð’[UÃv÷pdQ=­×–ÑÃÅ’,c¿Æ ¶^ZðÜÃp2Œw0Šç®ž{è=0‚0'°/º÷Ò$æS’h_#2Õ·ãůrj:]XhÖåiîÞ‰;ðœ3Ú Ó‹m¼ÁöµãŸ“ÛU§"ù7¡~y écràÁ4>¡—“™ôj±Xg`¥.5Å„Œ„”C³2¨¯ø®=ó@#HІ~uo‡ŽÚä\wwΔڑ\N] +¼žuLQ+Òõ´!–rŽ+oªYn=~ã¤ì±¹ +Œ ³CW²2«F: ïL+‡o]]®±ÁÀåW>«&ñŽSšÎ·€ËÚòš'™¹“â6ï„<88²ˆË‰–òx–R +¯Þ½ ¤½Ÿ$¸^¡wõjÛ<¡Ïö©Ò%Ü£áðXˆËBK€ŽF’aÚÛ))Å2 F®ÝRͰHÚ–ÚÍÉT©OY²¯ëQ/Qöé R`V ¤©C\ èÚNàg¤\šPÚ˜h=û—tq5eÌ—ä.öôÒÎpalF„…/Ï9;S±ëŠLò”@Cç…ãlH§¨&á£ÕRˆŠ„M'r¢Uœ©h®0·T¡ãéJŠÆbÅF°^䓨¢ì°ßéªNw/ŽŒWêMLJ+&.öKú2g€ÖÛ ®šs8¦’Õý!ÛNÈé|©ûú +¬Wüã™c›2+t÷p¦§Ì&Öwщ£äÙσgLS‘š²FZWírxª@i* ×fT×Õ A|ýú&µ†Ú¸bByô%ú+’ÿÎÁõQÅýè´}s"S<Ý@†!w@f˜ÁñÜw¥ÜÑÀý$F·PÒôãòÑ)%’hCo?~Gq> +endobj +587 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F15 836 0 R >> +/XObject << /Im129 866 0 R >> +>> +/Contents [588 0 R] +>> +endobj +588 0 obj +<< /Length 589 0 R /Filter /FlateDecode >> +stream +xœÕ[ÍŠ$7¾Ô;ÔÙà…¤Tf‚1TuvÁöfíÃÂØx.~}+”¡Rʪérƒ—!éêjý„"¾øâG9œàlâ?8C?}ùzúít};}¾-çå|~ûUFŒã`æ³›pÜÛדŒ·qÀ—óOÆŸ1>!>S|æø,?Ÿßþw²ËàÏq·ÿžãëeŠ‹Ï%>×ø¼Ðï+-ñJ¿÷— sÜ?¯ S±îæòqú Û~`i½¸?Äq@ãaLëó©m”?XŽý#n6ófH@x.&º`†%úžf_hÊk>ŠSë®$óLŸGÒUØÆÚõPG7%ù¹%€}-äö‹F[ʽÊuiüçŒBümíõT°ç?Oñó·“á6õü®1ã†àïožÇÏC(AéanÆ)iüë[Dõ˜ÖöóõàCÀ‰Ñš“=ûåôëöɼ5î§'p®@þJæYE@ï¤ù8ÁN¥ê¯Û)–aÎcÌ(k¢ ×Zð),(r_r0ç!×ÞY<4)T`8Fظ‹‚Ô\Ÿ…ϳ)2Ar¢¿3Wå¾4¿Os¾qüJƒmòÀ8ˆ}³3]²GÊ6×¼:,.Šj!ÏIb-ôy*×ãŠÃ2Û¸–XAÖ¹¨#­Û¾8X®øw¶ßÓ¼%Ûºý?¦uXMk^;©hR²ÄÏv#;ÙÁÎÙkƒÀbÜáß9È/ô)0²ÌlÌ ñ<Ö•ºþL?“>=éõ¶µ6vTç¬ô«÷e¿4îJr°N—lÓýZ-È 3„CqF¶)ícCþÌ:×ãÐÖ…ŒØ7uÄgPké$aGéVö F"¥¹‰bÄÅöâ³Ì„+¯)`ÜÎ%r`UŸôèï<—Ï1“î6ŒºÙ"Óçð[tRj gõ]Ï™ÅÙ†Kr2¼„y§‚ËÊ2FíÈÐ!„C8è÷¶u¦iÜ{ëšeFK¿_3Z%Oº(D*¦‚Ey‚Æ…Š«Z»f&ÍHŒò²oÛÞn1°o™SM€¾¬´9îµî$em°hœ2?Á8¥Í¥Oй*ŸÐ¾®O¤4nÉ/Øov|s¥8ÀïB"8 +Ñ1²«˜˜Î™Æo±]<.g ŒÐ%Såkö„.>>Q‹ÇŸ5% +˜\ž§éA²B+îŽi¾WúJ+h!É>=k$\ó:L׺JèѰ>'ÿÑ€{bUf›TÞBÀ015ÚÜOQ´ÑË8ºl1ä"Û#®hë°ÙA!¸0T2-#·iV‰>;Q{Ƈv/òØ&n..Óñ¸@Fs•m°)à¤b® ú¨@-¶Ôf+M·LØ9Qs¹?cJmšÔ3Éã°'b²MV +Sì+ÎIp ¾abRß©ª? ¤Kf üI½8Ò_§ä¶N)·¡°7*Áo®Ÿzz黺™ã܈T÷žfŽú”ôÀ,º™Ã½NiÊßYÆ㉛7ÌÎ÷6Ñá‡=1'·í¸¿†e‘ñÕYh ñ÷A•CL¼£íõ‡[•s'=äQG–ÃŽÃEéS¥—<ÆzÒò§ðãQ×Bñ¹tV8fÜ2GäîOÙæ f°¥]¥qê©¥,b4Äm— -è„Euq—®è/´7«_'UM.&Aó]¶Ç—¼> »Bxñ‰}ë@Ö ©ç&œ»ŸmÞˆd×hŒ4±Eгv£'q÷fªŽg™žÎ7.µítY@Xÿµ7*ðÖž)Þ|3¹Üò¼^Ðú; ú’ƒQw¿Ù@('•8ä ÒUnl#%©ý~oqf„Ì{=3K9tÂ|9Ö™N€Ãµ±$v%HF?Ì•2|£ÿ^uk v&ò¤ttv¾Ã" Õ6¢îjÜ<̾Ǻ¤jÚE·ku„aÕ÷k¡ï(—Wu(ÔͦÂe1/Es^JÎ4vˆoœk®ÆC(eDËž]M·\F³sÇn)q‡Rº:·'’Ãì’ˆÉ!ïë52MHŒ¡;Ç"Ÿaˆ5s¾ld-º˜×•[–¥Ð#”¨ã@Çó58œïZ£.•n™*Yvìs/_éôûæ‹E®™Ÿ4Ÿ^£¼„§ž&Z%eµ„hÇ·ÞÚY^ŒTz¦¼†. õ>V±¦êޏ|Üòu1ìwaÄš sU)Û)lßëù÷X…çr9¼æq ”fiì4ÛéuTTZK jÝÙ+RÝÉT祤yªÖ¦'Â!@«‘¥/ŽäLµÜ›Ô~×Ó_+j–y¼ÙGÁª´¿—Bµö÷"þ.˨ì–̹š=ïà:¶Ã+KÏÑJÉ^ÚŸ3¹wòD±Fn—¸ik9å4Û@¿Ï@äa©»›¾ŸU=Àåö{ÂBTV-!¸ˆ +l¤@Ëuûh;×Å|µÍä}»,Ót/¿:0›LÎÈ6“×($7mù¬m`^´á£Ì’nÇÈäö¹Wha笃¼îƒ5¹îR÷Í7.Ø‘yÎùôïw>¯_´Qzà÷ÅÞç|0ãK^…ˆç}õÍ`×£nù×ïå¶ C£«Z·’G½«îÅo¯º?ÓËaå»·míSG“_ßÃ8ò²Au×­º©Pb¦ªåueG¹ñ-+¥(f¹T +½Zi'0]÷Ê¡U€,Ú«ž‰öM¹‹åkÌKmç"®F²¢ £ucE¾<ëøzÜUë1ø‡88à[3¾'Ê?ŽÇµ<Ô´Uruø29†¾£*’ÐN:pOÞ¤ò.¹´à òêÎôÆìÞ8yžˆÌÿ)Á˜¿CÁ]/¨Ü¡‡µ)ÃXd¥ç(C¯¡jè¹¼Ö>›zÕGòвØoñ:­ØÀ–os¶øtF#_±Ïs]žæ­Ã;"ïMF^ÙÕ_Þe­Á™ƒšå­«~ 4~çæZ:ÓÝËîÅääL½ÞyBþßÀ*8}};ý7Žé +$˜ô‚™ #âáGëàüí—óοá˜Oøµ÷i{üË6ÅM© ôåë§Ïÿú +v9¯¿ú÷ ÿýî¤ø· +endstream +endobj +589 0 obj +2497 +endobj +590 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Contents [591 0 R] +>> +endobj +591 0 obj +<< /Length 592 0 R /Filter /FlateDecode >> +stream +xœÍ\ÉŽ#¹ý‚ú ´†k.€a@ª*Ý ôŒ=3€çâßw’A¾ ƒ©,u0f +­’(.±¾xŒ¬¿Ù‹Ùþ³;]W·½úõ÷·?Þîßß~y¬—õrùþ[ãÕ,?§qß3WãÃ6à×Ë_ñ‹1nþÛåû¿Êð)^í$†Û•‡Ÿ~òð_66 ͦYȺËÞ¶×¾ž æ/›ô^¿Ó9\Ýò|é2|½z'†›ÈÃÝû6ü“~âö3mïšæ¶ýÜ·ŸmŒMÿnB° ½Žûûi|ë>¶CÃÌûx³î[±îº\¶Ý|ÿÇ%­¿hë»O±mïâ5±ïàÊ1Çk¹õêR.ÉÀ‘òï4Å'ý>žvZ¶õáRâú.Ï‘Ädè_K"t4ß¶¾ÝÆYo·õìDë¦},y½ÏFÂ%,×°\Â4]§åòÍ\gwùóŸo¿ý…-ÙšËz]'ÅšçÉ\ãÄæ\¤nou+ÅN×~’Ù_œÃNÇØ´há˜×ÙþgQÜAlït|Pƒ¥ù’ˆ²˜>È*ö)åÄn³”MÛr»Åгæ uúݱó²wú<õGY黳åœëšÌ¶ÎùM($o˜'â‹v Öó„»áï,rœ3Í–«º?@ (>O1çF" ¤Þ™,šDŸ6ǯó/qlù}Z+› 9tš»I$foÓùöØ'é•2ÉLÙ¤a<†úSÞ+¾ëKB»í¦‡&žÍ‡MŒƒ$Ÿñ´[¢ +K³…ð#)¾jÈjR<‰­4¿OãØ³Xµ­uçïóë• õ~uLž=p3á½Ä}5rµ°/ÎSxޏΦéhöAãîÚ:šù9sõŠ>»¼“YðZœ'ã;™Éåמk(çu—s™Ü«è飮—“ÇÉõrb!9–yÐn¾¸'–m`òø;½~aG¶ z+û>² Ðcú¨ØÞŸ«:5Ëu }’ަó“ìò7¹Ú¼½7û¾Ê‰3UþŒmðFŸCè@1bïθ~óÒ>r¶\aI¾î¡èÖ™•dmy/lKË>û”õ÷AøžV›€é*1GÕW˜v{J0;§Þ—’Þkøæñ?=„;¿$ø-·ûC  +ÕÑeÒH*çìiM2DŒÍu3"›ç÷—:Æ1ŒçÐ3%ô“9l¢ +#Ä=íÅGÍíf?]>ÑçÀç˜ÊA1K•·óº# Ãô”ÏÆáã£Ê'…Ww“c1 ³ë¥/Ë&F®Ï®Êï•ôÄn—ç´Ú„•ü ¯ ñ:ý°ÓÁ$±ÏÒC‰ÿE!È).‡köSŠ{Ù‡Xêmår“6¨Vß÷*¥¾¬)²‹³— +#Ç^w"˜E–`V(±á•ïÖóÓ|•ú²N³ò²ý‡éŒK%Š‹2d©K9 Ú:CDíÒíW—±ìS¯@Éú6Ë5‹Zà”"á^5™GÉ|mÆÛÆ%€¨õ(¤'ú¸”o"òÉì~‰ÔËÙ"ñˆyõ Œ +Jæ^_—bi†½¢Œʪϙ!‚yÉR$“s@/UOábî½­ß“áw€äu>ÊZ¿<ÂÔ‡§Å¦2ZÌRéGÛ2¯H%~ÒÉ?MÉ›ö“¤Ëðï㨂kJ{òÐ%iò€Ã W7 YÈMµ‹ppD¬d˜Ba68¨t-Ua™Èà#7 +ŒRÞÙæëaèñÞŒó)I­•²Ä­õÀš «‹coz7{ÙI.´.tÃ\Ì£©{õ$' Ë¥*å½`IÏñ?~’pc 1 Г÷}M`S=ÀÚÄ„“ºÑvµÜ$Ï·N‰‡€ùÚ„¿^ì¢dû¸¹U¡Ý,.,¡ž-ËÀ…äŽG¢È$ÀÐ2ïq ×è^¢Þc˜ÓµK˥ƸÛlå-SE~Ñò¸åÒ…a<²Qœ~ß÷à'EmÑ(Õà9ûبdŒXEº +Ñ/'ž› UI}Þìô½Nÿ¹5 RÚdÑ$Ô™§äÿR•*apAY):]1-Å—6”qg§áfä¼Å ó9bôA^¶“ª·!9qn³t1©½MÕï÷õÊfé:@\/ÍIšÞOü]ËÅ=Ê\>ûքΰí½Í°óà¤É©©®QƒÊjÂ^ȶ9ÈÜ›°„kPøêÁ¢,̆¢¤˜†Ùú¡PØð¾°ï®Ðˆ8(u*‹®¦Dvæù0º©ªYÁÁÜžïÕŒQöv—&ƒ„Sy_#”|ýlHH5^x–„ÒL7ÜLß×Ö_‰&šÉŸÑW#Ï™3ë?y tæ9 +YÈL0ú“RƒF#3“JLrÞ ‚¿×ù$ºmúì–îÆ Ñ +jã›À§‚äR_JežN8ÄÝëÄâ´giPÒ|a°ZK©¶y8³C÷ú¹f¹¥C“1ÌÃwC-®ÃîÃGiÖ-°t³¬-À­lŠ÷àçha N+{ƒ(Á:(‰ð}¿±½k³~Ñ<Þ&’V^ˆÃ=ZªÄIOñ¢ÿš÷´2à ãáxÚs2“>`šjc>^ýJêÚÅD IæZ‡ÎÃ-Um2…ÛÑ|Æ|‹ê8)Œ×n¸xÌp<(VëA\ê:°¦‰ó†àœz‹Í¦”DÊHyh<­ˆõÇ6‚Lúe‘÷!?~†ë¡µ §ivZú½Ç–´{Î×~™ ¾Öb¡Ùµ@ÊÕéè®MôèF˜¤šð1¯jw(Ùƒ=Vh¤RS¼Äfš+ôgué©!‡‡eß_ÌÿR(³ 7jš3µS‰/'cu¢>«§y [!Ù¤égKMwrvìÁ’cßJhïäDþö^ÒSœÚþ–fØî)b?×ÍU(«y€1•h ²×]Òñ6·V2x~…÷ê"5^¤³È;r—,lrðl\˜S_Š8 ¤.ñ8TÀ%lgÑMöÕ¬ú¨9¡³ö¶þ»›ÚlˆiMm;ä0Ba°mkäÐ#ÐÔž½Åg¿:ƦY??Ÿ!»JBÌ9JAW«yÔMkÀóâÃ-Ëõ æ¸×ór1¢œaMw¦¶ºÃ÷8Ò1ó2èmï$4¦ Ðô¨õU…Gn¶×ò˜þkààòö)qá¥á6›uûÆÛ'ýüÄBúãM<ÃûÐ"ê.€ ayˆL»Œä²»²j¹?‡çBuÞ p µp–U]ùL¯†`’ÄÅÇAƒw)$¡T5E ]¢™ÓæÄK%»Ú”úMßµ‡Á1NnY{¾¼»Ñä{äèÛºŠ×Àµòý½î0ù‘êzGcÅ ç¶‘nП€Á&óGÙŠÇ¿ÅÞ›}³ÌZRôÔ–ÐH¶Ü®k¹¨a‚Ýè>§™Lú« êsçg¬ºSsëepUT/ÑûÀŸèêtþcL˜~™€ôÒœ˜áï«~¯;[ïŽæÿ¦ƒ +[bJH×V£©ØODò~­Î²¿Fû¢]¯ƒÚý‰»·ÔVÑK£ç³5c7ÿÃÔ†[ƒµ'=ìnôY>ºf…’jZƒÖ”u‹htÜêKe÷@‚@á—&%&?¢Þ2é}Ÿ¬`ª?Yéóþè¶µ9Y0 ͳ“KÐOìµÔG: jÉ€v¶Š<ç°aqÁ43€d%aQRÒžâi›Æº&²/FÃæ“¢IGáÄÔ½ÂÔ«|2,ÃÒS^vÿPoŸ…?-A¿æÙ5g5Ëv»’Á±Ž.ÇÂÑ,Þ¨µX‡Øi4C³ëTŸ=™ú{,TôY1Ú•$¥°Ãôuò ?åÛ ‰ ZÐiÏÐ#§tÔ)ër®óŸêØÑê7 (ímØm¡ÙÄáŸumF:ÕkÑæ÷dÇ ÁSîÚ¹;”Ë/öøYQ •ò3)  Q²ˆjÁi§.|gQq²±Pï½átwl'Œ·<½ÏCá86–´•ŒKÄ„åi$D準.“h”¦_z õÕ³›BÂînÌH ‚àâ÷Ř¢ÝN©†M“b!團8Ï&÷Q{÷tÄÑ3Ás‚)MÝ~U»§Fɹ©æ ;qÖQ×ys˜G±£¯å³h51¼ý[4!ß÷ÈC +ö·»ú|Q‘£–ضg虿rÝyÊAˆÃv\ëfx$¸¶TIh‡Ð¯«eRØ›´`â³mr{½Ü@U(ÃV L{5”ÇS‹|Ô 9z‚ S`4Bqú8ÊúõðO9 ,ƵŠ2áž¾ æ:N¦ç?ñd¦מ+o+ +µUã¤ý=ú‚¹QP>RòkÙøæÏÒb«åï&ŽŒs9Óʱ§•Ó}ò‚R,¶ÀE{ï¥ÜWQU«9¿ìãóûÛßßþ sIÈ +endstream +endobj +592 0 obj +4188 +endobj +593 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F15 836 0 R >> +/XObject << /Im139 868 0 R >> +>> +/Annots 596 0 R +/Contents [594 0 R] +>> +endobj +594 0 obj +<< /Length 595 0 R /Filter /FlateDecode >> +stream +xœÍ[ÛÎܸ ¾0ïàëqt¶ ,˜ã¢—-~ î(››¾~E‰”¨ƒÇž?ÙE™Ø²D‘É”óûIN"ü‘“tóªÂ¯Ï_N_O—·Ó§Ç:­Óôö[aí,ü¤÷öå$faTðyúIaÂeÃ嵄ˇkýyzû÷I­³™ÂoÿœÂ+ÊäWt¸ÎẄëŠÿ¾áwü÷ö´Î‡õ˼r©æ}à»4GxO +ü[¦õ¤ÂùÂú2Œ“8^Ú8?íZùÆó¶?Âbž“}õ¢vb^]¥/I¯©+¾r/ûqZÈ Êìñ·E]¹4VÝžêHJ‹“’šå+i¯EUÅ´AFÕ ^ÍlU½µµÒ¿Žã?=¤m@dÖÃ_•júï)üþv4C²€€{ +=;³¿xïgWãVgê ,mâøû[¾s??çàÅ`ðEMß~=ýöò ㆮáä:w¦–6™4"åšL%4©@X֯ˬ›dÕ()Ì,]À:›ØtEÄß%:- h‘wDÌQ‡hRš<E—]òN–Ó +øîÕ`ƒ‰½'=d‰4âW"vãZ¢ï…ߊâÀWÔ(I~ªï—ZF°uI÷¾fgëùJ_Ó󬋕ékwzÁ±?`/|ñß²ŸO®lÎ^šÍר°•%ÚûÌ÷S»n“_ Ú´xŠsâú +ÃpÆ‘Å9I\–ŒxÃ=KÚâ.¾ƒ÷äÂæF9áwÔó9í=êǺÖ#äjçòØ2Úžø‘ +®­]³q›#ŠFÅ“²áîÞ)ýQœ.ß[kçä %Wk2*TTtpT ,&±w5ÊäÊFس~ö†læ2(ˆwÔù¡¤àIIÓ§õágå'$/S_ï'ÊJvÃù%Ù´ß»F#«r,nø~xȼY‰Â3uÆulºO¤Fž ¢ÈCÊï2Œ´¾­2³Ni/äÖ”4eY?Ë6ÎÈç¡¡!î¹’b6z–Ü7õðU²VÔ%cx!Éò3½Ü4É]@â«”£=ïKÁÂú ÕDý¢öP •?ÖM?â>”1,¯Ö)¼¶GaLü ã_‰Ka7zí=!júpäqHe±×ÆÛGNÇMnö¶{'F9¨›’µE/ŠDb!KP¸¡LÁê˺¢ Û¦}[wÕ…q)ǃ0A&m6cqÈ¡cß©4D‹&‰-o Áݾ‘^,#}…EŸ¨iÓÌ%zôŽ2"oe®.qS$£ß,êQþQ®¹÷è׊ ¾&cåöð‚ÉÕÈ÷¢h|îí¼ÜaeEÿè‘ F¾&â)ìsSŸ˜¢™AP¦ˆkúJ9š;'7Ëåüý€,g­QR;5Ú¼4¨G›¦%*gÃçÜèŠeVíÚÁØvˆÑöÑ-gžmw):ˆ¼¢%ªÅ“ âÕÈ­”Ú—Z©œ®–ÚŒJ#b,da>h5BLDÍE^Œ·ù™Lt–ç8_¼7"˳9ži~P`6‡.&p&U먳œW±¼P[ "Ê3Ùs®èÁ;eLÿG” ¹ää‘f¡3¾0Z§.D—»3¯Zñ"{К„‡kA»Â³ÉäKÍ1Œ<¹YA÷®¢ãÑÓNúè?²¡¶¬ò0¼És,Zí臟L0\V<Œ:Ô)Ú†U•¡X+¢~†ga°³oÿÂÿ¥„­á4£Þ®?´Ý :XF!6y'(.fðøGb#&í—Dp2g‘SÔ¢eoª"ËF# Óii‡Õ/ލoç2sm"OÖ–•E¥6漩.ø$h´z_É*·ç.£ÆÉ†7En$Šc;t•U74˪Àk(O"‘nñ#œÆ4ÌZäµ´$2® uè^TEçH& +†ŠžÛro‹æ½Úö8]ê:S!™éäfÒ‘jÔù߉ì.gØ&©½ ²˜³;øAt©ÍXŒÏ°þŒ[Ïñ¿&4‹ØØtE6Îe³D§ Æ™~SBw¢aĉä6õÓxx97sR‰GÏ·ŠöQH!™*»ßqa#Û\®2=(G^ñ?Ò¯Üð÷´^Í¥—5²ÒJÀ ^²w–H¼’ߨ]•‹_x¼£v…ÒU K×{²¦äí#…÷Lº}bA +oפ!µBgEr!!°ïÛnA¬¬˜{£ÿ?ÕÃQøœ@ºÚ•©ð{ê䮞: Kvn‚E:.Óø¯Êö”‰*½B¹ÙEö5üÓîã`¿U~f‡‹¨) fO¹´¶¶Ç¡š‚(%ôWõÌ?Qˆ=¸ºI¸Ê^áKåuìŒuJÞ"î˜E!M‹€ú2Çò=™YzÃfØ$ü$©ºïø;õ5)¾027Êf=‡O÷â‡E˜¨©ÃÀÖIa.Õ/b–ŽõŒÊ®Cü0S©¤øfî¥ïðÐAn}K÷ ¶¢a?PVÃXè|Âûð<:±G,CaÆŠñ’±jÕÖÁ(S3°wÆýÔ±~xCíx£LrÛ’<íÑÁ…4¿,A”'ˆªÌ}¼hÝ]½íáfïD]®+# ÕqËÞ±Õ6¿ub|¬ÝS3¦U@ ] ̪¼WúBjCØÇ'å’‚3G²Ïu`g f%x”Ó°cÏuAeWº¿RC}7*à º¾¾8|˜9*¹9"ÔSVÙ‰ïi³²PE…m!{ì}9ÕÚ¢£fÔ¸Û’á=_Dq +÷¹u¾O;Fv]”m¶äû7˜}¡yÚÞϽƒQv%½a‡™FZ_2z.24;¤ÌìŒàö´eЋñr—‹W;ñÀ-гËñ`‘}<¨‹y­Á"զ˩Wéà +…bŸa6ƒ÷oOá»ïÇ9Åié^“ö†Ý[ÖÑÎ즫=èh- ­” Õ×Õ¡Î,å¹üw€ïë~ÔùKú¹Y‡ñÕ?¥CÒv>$ú˜_+תŸö¬5BáøŒnŽ‹ç +ëp›DüÈöÇýíô;|_àÀ+§fÊÄäöQ× ûuúÇô5 ÛdfCc¾~PéĨ1ÿGNzË)Zûüåç¿~ O¦Û>üíþþ» +endstream +endobj +595 0 obj +2748 +endobj +596 0 obj +[ +597 0 R +] +endobj +597 0 obj +<< +/Type /Annot /Subtype /Link /Rect [250.50 338.90 320.25 332.65] /H /N /Border [0 0 0] /F 4 /Dest [549 0 R /XYZ 280.50 340.40 0 ] >> +endobj +598 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F15 836 0 R >> +>> +/Annots 601 0 R +/Contents [599 0 R] +>> +endobj +599 0 obj +<< /Length 600 0 R /Filter /FlateDecode >> +stream +xœµ\[®#¹ ]Á݃¿´G¯R©€ €×ó w0É0Ò?Ù~J*R")ªªÜFð¯-KŸçPrÿçÃ^ÌúÏ^l¼.n}õÛÿþ¸ýøåµ\–ËåëïuÄ4]Mºø9ûúLJ¹Ö¿]þlŒOëÃýåòõ_uxœ®6²ávÁáÆçGþËËNb¡Ùˆ…¬»ü÷c}ýíÃàSù²Éïõ’ÎáêÒñÒuørõŽ 7wuø'<¦õ×÷ Ls[÷õ±Ž±ùyU‚MðzÚÞÏãóX÷\ŸC›ÃÌÛx³l¢XwM—Uš¯¿äõ“¶¾ûdb{7]C`rW·9^Ë-×Жri†l©üý„)>áïñ´1­ë“-p¿à»8GV“g *t0ߺ¾]ÇYo×õl„u³©¬÷ùuuÔÉ_c¸„t éb¼Ætùb®³»|ûÇÇïjžlC®óæyŠ×²ö¾pµ¿@¶æ“VózåÑ\¢ì#ÌT‡0¦|æžìuŠ ¬¼²åVxÂJ ¤pmU&[½Ì¼,×…LRÝ’YšãÛmuâ d-v@wId°lF A?µesb°8ãâ„­a¿:2‘ÊvÖXx°‰8““}LêkD”-a4Óbþ1—Mi½w8w#¦Àbò¶‰ã8ì |'ñ?W%Ö,kS?q7‚ã/3,Ì·ÀsùœÏmvl>_3Ð ~â·×.`ðwÚ¡/½àý ]|ëþèù|#ò¹½ç<‰ô¹ElQFø c`SeÑÈó?ß]Ÿ)%{e:Au¼Ä°9è®âIöú³è¼Šò8ŸÙ[Ëhº¯æH ¸v-:ÿOjòÙ<ÌúÌSV'Ã5^`ÛYŒ·4ˆ1ËQY}¯Ãòz"ßyÁ7Ø/Îû ~»Cf­óBÀ”ñT7ÏmNÛ¼eÍ—¯¼75Y«¾b³AYûÞtƒ1BõUçÚ³u\Só\ñÈ\ƒsÙÔý'ƒ†òÊ{¯>IÖd6Ã8 ÔÿDô*SZ=‘ÊX³¦ráâ{ñ4Ù[DhÃ'ÙÏ ÞǽÄmÔ>¨WfO¦[ºGˆÌšù…l­Ĭu¯6f/&BPâm‡:yÐXà i­\)!„!1ßh¬Éƒ8R ‚_mó'¿Æ +¶9‰æ¸)]•e¨ïaNÀܳ>‡ ’+:=rk-~¼ Âb±KüºÎû€udMù˜ÇÂ,ýQaM•ÆéÅ“ìùFüQ§ÔÕÀÿØÞð}ZKHN¬öšÈ<˜[DÍÑæ¯{%qZ] +Ö®õHË»2žv½“qy#¯aÏl<úÝ¿œã0çOËuÒC”ê†ùÁ_E%'ò$l +Ñá“7ºu ìNAH±09*ÎÜÈ­ôJÊÓ( ¦[Û$“ïFÆðå✙YDOŽn.…ŒÊâÆŠ\WLf1‘¯M"· ±BIï·æI“-1d‰BQ“Â@âªÙJfÜ,ÚÛš¾ñ³ÌaÛšŸdƒ‡m +É©£÷ßŨ§dòw€~5œão¦ñXÒ9AæèÈ”¦2:‡›IØ’”&,º¸ÌzÛdäF*ä’.$*ñRZú¢¶.¡Z‚àŽµêŠÈr÷–³ƒ`¥¶t,M;é:ÞŽQ¨ÀrO÷EÊNÍÃè!Mû¬Ì£<Ï~/˜¦kù‘if—®,)©ušlî/JZäÄ +”·ƒ”NLD¾Ô>W³Ó‹Ï¡¦ðJÿ4™}‰Uè1Ö`öw.S^ÃÛfw‡6¸7]Ó ºãóÖÇœ‘ØÂ­©8ìNœC”Úœ@nN”–ªDgœ1Ôwbµ¬ô»67ÊZ±…€È¸V~ªüòÖ{# ¾ŠT9Žêká½}XA'v„ß:>º7¡/´!ö}\œŸ8u¥gm&ÄäFý¨ ;ûóÁðD¤$¯£„‰ü²öL)¶–z¹7;9(×@¢Ià6âš­Éå­+<a¢…$Pቆ£÷üp2]¡*qqã{øîØìâ_Àµ’qئ[C—´ +EÉ1mT r@€j© Ù(òDI˜-I'µ‰ R™áS1fX9;Z§ý$;=匒õz%]R1å!,Ðã^´…FØt¥R3½G#¶±\ÂùCp¼mÐd©«zH·@¬ì‰;-;ðZáóËÖ%:'v¨ÝR¬ü¾õ_wA†¯oD3àŒ„¾Dæ\2Oazilºã" ìǤûÒÚ$ë1ã(Aù#¼%–žÁ¥àò9dV\ëF`‹¬Ã6xjˆ½§Z³-ز®õà,»œggU8š¹m³úžtÐ@É/;âŒÍý^¶|ë÷°ÆÖL´:Ôžñù©;ˆ @¨j†4#Æ9‚žA¨ÕZA"ËMÄ›èšø9²cd?¤”¨utÄØŽ"B²Ðaˆ’H‰<Sâð;¯X÷VrJÔXEnï€ÂM¥\2èi´²KìR{ïv^dŽ3x³ o”;³”{CLøŠC;î,6b7¡«#àH€t×:RÆj²±´ýu¢û¥Þ¢¤ìg°ÀKÁZÒ𢌉†ôºÁø.¡þ€þFmŒòyø«]‘Ç6.ÏåôKº +1 û\HüP{Læ´>;""|Yo¡i¾2YRà&Öél1Ð1eä ñãhvą́P±/ÜÃ%YüËßÛó–üƳ+Úfûm÷”Dë]X{Øì"ùpÜá1„7±õ§Œa— Ÿ°[Áºèm8@ .F= ¨e ïsXy*á]ÈA7>˜ —f8JáÞõ4ì¬õ<ÊþŽÎ3÷¬L+í'ieø'øÎãϰ¤ÁÁH¥ƒÊ]ˆîMûßþ /þö+ÉIKö|frÝÕÚŠ½›.Qe =$Ýʱêö¿J±dÚËåhM:GsÃ*yÌðÄZ›­\´?4—¼ß_78nj㻬tmÕ㤳8óÕ(S „ã'Ãy.α××yâ³7_Wgè©kàfL•gД ©¯Ý‚*E‚»_&lì oˆq)£ÁÄbÂâùñP¾G»~ëx‘2‚e‹8^U€ö•_=wÛƒì¤!‡ÃªîÅxÈ;Ø­<*8Ã{’± ÔÄëçÜÙïõ5 Ìž3U®—©Ó$:‘‚}ï"õQào‰H ¦•¿(¹k¨`º¬»£Äønë‘tqЍ„?„ÐDV‹ìF‰+v¶œ±½$–ÇGyí„Ô\'dÖPò;{>{/^ï¹N¦Îz53‹5w”û ò€B‹“=b£‘!Ы<4³!ÿº¤žšñ™Î Þ¦Z² FùŽD!‹~w„žKh n2•ÄâÅ<–£A…żì=Ú²Oƒ ¢@ÛÌÝ­¹;@K4€cû®ýù='Z[÷Ì/ 3Ág·«zgn(íVÀ½>휷ÿõ¦ìʵ{‰šå‰ Ï=ω‘TÙYóœJóNw +›åÅiéé‡I=訩 ’vðó/&›¸ß{tU-¢‡ó]c–­©eFµ¹C?ø…tâ®$’ïÊ(Í‚êaá^É{ì4˜P¼Ó#¤qtHÑõBÐ&äd«ÑGíÞ0Û»¬hpèD/@a†y„½}"P ³øMþÁ˜b¶¤>ÍÐoö“Ÿ¾ž®G¯Nvw„j‹ÄŸ´=B\wÜ–ö{£J2½«ú7ï|†it“ägÈ¥•´ý´ŸýÄž_:y0á½ðvr”ÚÕLu`wýÖQ¦h±¦\o˜™(òø?ˆ/ÅT +uû2ÞÛõýøG°¦» +endstream +endobj +600 0 obj +3307 +endobj +601 0 obj +[ +602 0 R +] +endobj +602 0 obj +<< +/Type /Annot /Subtype /Link /Rect [415.50 293.90 528.75 284.65] /H /N /Border [0 0 0] /F 4 /Dest [582 0 R /XYZ 230.25 470.90 0 ] >> +endobj +603 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Annots 606 0 R +/Contents [604 0 R] +>> +endobj +604 0 obj +<< /Length 605 0 R /Filter /FlateDecode >> +stream +xœÅÛŽ+·í ü~.pÝGìõ:Ï-öÒ&@èyÉïWԈɑfÆÞM‚ÖÙݳIñNŠÚÿôY¥ÿé³—Ù¤ï~þíôßÓíãôÃc>ÏçóÇ/u…÷Ïv‚u¿ÔE9“ü|þ»RÊ¥OŸ>SúÄô™<üçdæ‹;'ÿ:§-ÆÕ-6}®ésKŸ·òó½€x/?Á†˜ð7¸zbpe/ÂHû´*_õ‚O›/á×i.ëµÏðñÔ&ÑŸ\ý ED¦C!Žl£ ê2Æ/ÛÌ[ÙòÞÎäHžè[¡9–ï}áUXÖšû&´6€¼2ÉÅæÑífwñ†Ó=3æÚ¼þ‡‡öBCÜœdíèVmοŸÒ÷ßO +!,ìUðoSöÜ>ò¶>^WJ[5Ì&N˜…ïI«}†íâ%ñÁ…“4'sþþïÓ/kjŸÅ+õ~òúb‡ÙQ|`pÆ;é˪tðu_f>;‹v3¨4GTÕZƒ:Ìh|c’˜t#2€#0Ê_ ‡¯…¯ +ŽŒG˜¢¾’ƒFÉÔ)ÌÀÎ1Wµ:Ï`ÆZ)¶UCï #3î‰àµÅdçÂt[¾ú²>,kuÙŸµýºül\1ù´Þ<Ê9ïÆÜ,:›Â-n"Ã"¿×7BÇóÚ{z2dr‹â%9Ķœ‹jž,“Íw{‰’gUá3…Nç +í·åLù<…@su¹W§+ù9í±ºðÓ€uðÂù5Ÿô@nÙ-Gòoo ¦”ç;7úEoLö¯…•iæÖdht9»mò<¢ Ö•õ÷.ŠÎez®E"q×ÕÂ×­ü|-øQ&¨c…Fø· çZô¼À­²y+ü+z™uù85Zw†–5CÅ£à™V<´ÉnÁg0&VïdoámQd¤Á˜}ë •  Žnf’T(Êຶ§*GéH2CCÛ‹F‹ÆÌ«¡|"™ˆ² 1³"ö”N[Å¥Qá‘^uÂ×ÈÛ+7†7å{ ÐÓÿï{.ÃqN’Œ­')â*3·gTežd芘ÄBÕ>¥ªÛBSª°·Ž¹ö޶„9'R[ð UCÐô;š’鼪fö",ë‚?ATp8´™ s‚Vw4ÓL=¾DT—ô æ99ü–=ƒ›’¤CnM;T‘q'ºÏGã@K’>£K@Vsàë `‡GÎm×›)þÉ,LÁØÐ$P¢²í 5YäF°ƒ¦Úó({ +~‚³•C…ƒi©/‘Nê¸Rðl3ãk+0û‰A¸/å•1B‹&´h<ÉÑaʆCT +Ýmqi€Ã7æ[]Égð÷Ælÿè„ßú, U¡Ð?/?/{¹‹T‹ÁRúZìDC%RÐ%¬ˆ1I$|RŠfÞ—¢”Ïr>ip…ÿ¦THVç ¼lÊ… =C«+¿KÞçæv& ¡æ¦–ÐFò%)¡+)ÊeÛFÜ"ƒ^WŒfòP°PbÅÙ–€å0pú^£U€ëOâ—œ+ùÕ×_Dsy¿Íw{ã{Œ‡¼o°g¥®|¯øê¶žF_>©ÒÓH¥Ë"g#;ÞAQÅúªµ+ +ð9Þx½Íá°—C·Ä v÷JðVÅ­ªŽ¯VH$UÙ`~©he× #}’¦½ÅÐ8<*¶j®Ü‹ù3ÉßI6[st«jö ™¦½® -Ñ qÂK:0™šzé|ì§ÀÜû¤’Ϧ–{çÒwÙà`]³Å&›;!«5ÌpåfrÓCf8+È!7Jf,QªØ9–Ï´Úªƺ$нõž¶Xª­ÕüÀ½¶Lo„³¶c¨–½‹åþ`09õÚY¥ÒDXM¹Dätàþ9c¸õÆ’2cÙœ•æJ<-ÉÃ"Lè%‰¢Äz(NÛºïW5*:ìd!G#Ëÿ.ÖEð( TÓ56Wx +lçÏÁƒÍär£P'Õúð¤ÀéÜDnßUm +T5à¶îâÜ'²pyË/[ßâwKÖ©÷†oŽòH©”å¤ÕÐ…+fø“=»Z´£‡}kÆnHûŠ:Úî¡Íÿ¾|ï‘>ߌ+ëú’ ›TÄ{rÕÒ C£Çêô’VaƒÝX†^™4tWÖÎâ•j^“„¢Ž÷.a,4÷eÇÄâÅ@é;eü^±Ðhjc“ö©?ñȒᚨ¼éRáÂú+–»诰eÏ´‹W=­{“ŠÑü”ý®…R0G^ùjÕ#•¬c.v«KÙ£õ¡ZÖ2‘äö‘„ôsœz¶þî™& i)=Ó{÷Lm­Ðžã¿(;ã +°æIÊ@P«ûŒ?™±ûÞ×y’¨+K½// ·¼¯Î Òü¼û €†%ÆôE~š+ݾŒ¬U5q1˜ÌLÅ]dXZp™uáâø•¯ÕÎç<±Cҳ̠68oƒj‹³>næþN[®f•Ó€6Y>¨`cšÓ¿t´s¾ÿeĹvÍìU»­(b:¨²vjU¡á=•ý¶ ¦j/Kk¸>•MÐ:õ‰k©¹GX4N^¾ÈR¤§Å+wGÞn¨¹Šó ʉ&/„3¼$Ê-¯H>ÚI ¯×åÒVéѵƒn’³ºV1аü$ 0:Ip„LTj9TøToc!÷ÖÂ&;„jÏ;²BÞnd—zl‡(>òÔ°W»S¤ÁÛ7ÄÈ^ÖzÆ +;}ÿý×òÍ?ba'9b†Ö°°ƒ Ñxrv+ îg"D¶]Ç]r&ÛÆ]*%SJ&µò@Oâ_úï2î¢Î@þOËØK­œ­[‘ßfÁzp'˜Ñ!‘YKެT…#ÃËÖµóƒ7Þ‘á>Væv\Œ'R‘¶VÚºh‰`î/)&ñ"ãˆk?êÖÅìá4_lç…å‘ìõH¶ŠL£‚¦×»„I'`ƒ˜î .Iº/ü\% Ò ç—YƹWôþÝ‹g3Üà ƒ#Îb•ËJJÅ‘\ö=‡"É8-Í>ßQyÊ­¶µñ¼4V“–w“ÛBgrøt0À±ü„¶r}XÉÔœÉ÷CÔ~x·^õîU¾þŠsˆ y+I ‡÷ÆX^‘áÔ[Õ¥£º¼3ôÑݳeԞȰÇV³¯ÊúúiY[Ëod-oû :$uÕº& 6Ç™ +&U„µSðD§—x±6û"_Y§tgžOýâút4ÉÙ­s<13š‰—½¦'t(Ü®'YǦ½};s½è´{@¿BF¯ºëkæ†vûždÅ“5Ð-¾ËÆ‘Òê¶9×3îy*£F7µÙÉ$ë^ ’mÞ¦QÕü™o篸æç¶ª˜Ì¡¢Ê¸Üje¾ZUqÕ¹© 5ÓÄtc²ÎÓ¢åLfNÖ*~Y žcÉæZ­îžc„ïwK5kóxÇ{rR˜ÛãÏ´¥RܸÆôø­˜zoâÒ×¼æzàR‚-[»K(ú­¨(—±™äfânÆVW2¶†%Ö/Í´måñIÿV+>ç á÷ŽSÄnù¾4Í?âÐöRü øÏô¶4î}ªLT»Ž®*Û†¢»™1:B¨îvzËÔÚ¨Ó›ütÛÍm뉬~‹ÕUd¥%Èà“™¢ûFñéPVUïÜ2‘”Y¤š}—²î´?éÈ_-è(±Ê bÂÛ ü}}г+&¥áÖ°+¦2‰;lÈó½ú@Gž'Ày–©a0V3‰Øã9,½µ„¤[iG6°‰¬é„ˆŠoTÛ ¤U=ù]1§±ûôÖÖ¬îýh†Bï}òz1‰»WŒé­h)43pÊï¹3þ¾Ìôn¸£Ûy¯jËJFN[Ü{b»~¡Cdÿâl7™ÖË äÕƒF|uŠýqûΡ>—b¬öÖ)Vi‹ÈL^xÃb‘ûõèÐ_z~ ~û|Ýž„íÒÌMñ{kvoËœÈÝá³(ÌðD.m´2ÁÔyˆ0n#™.Ãûò±ÊM ½6Qn=ÞÖ7ÑÔ0p“IQ´Ê`™Gyž–ëÅÝ1/çµ PPsŸšªñhäƒdp@Õ™ V¥ªÖ;~¨zgÁ3Ó×Ùè'çò¹5y²‡Î[~ènm& Ó­i4fs½Jò¦©úK“òÝÙãÎ&ÍXÅÜ›uAŠ˜ž÷è_T°ù/MÃô盌 кá‡ö´6ªVÒs@ƒ¡œî¥’'£Jvk0PáXYù ™N}7M¤—Á¯¾"û:‡DMPOS<¡µ¥vßÑ}†wGwŸ†Ö½ßØÝöpK €j«hÑ ‰óLÐ_£d‘Q¾û¹þKQ®WÚÁftΩºÊ…<»y7 ²]t>\ æٛ9Ävì™k—kò;ö=JàòGsRÚ 3þ<Žïsù×.xo˜öãjôÔŽ^ßÿ™/íúÓ Ï=Àm0FŠõ¿.˵Úêe®ç+¤ E“ÿ  Y!±Ä°:¦µaÅ@¥þÔ8ÆŠ&æ‡+{Œ01÷ž(‰do»‘ÄÝo¡wÔ“Ÿ?bÙ}ü»Vù90ÁTþœWa^p%Îz%{è\R{ËOzÈ€a’xÞ?ó¹Þ­Ë†üþqúÇéÿ¨¨8 +endstream +endobj +605 0 obj +3618 +endobj +606 0 obj +[ +607 0 R 608 0 R +] +endobj +607 0 obj +<< +/Type /Annot /Subtype /Link /Rect [142.50 417.65 247.50 405.40] /H /N /Border [0 0 0] /F 4 /Dest [598 0 R /XYZ 408 355.40 0 ] >> +endobj +608 0 obj +<< +/Type /Annot /Subtype /Link /Rect [261 290.90 351 278.65] /H /N /Border [0 0 0] /F 4 /Dest [756 0 R /XYZ 76.50 241.15 0 ] >> +endobj +609 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Annots 612 0 R +/Contents [610 0 R] +>> +endobj +610 0 obj +<< /Length 611 0 R /Filter /FlateDecode >> +stream +xœ½Ûnì¶ñ üû\À +ï’€¢À®íÍs‹óiS @ +4/ýýrH93$µZÛ)Ãë="9÷;•ÿ¼è‹Šÿé‹Ënâ§_~{ù÷ËíÇËO÷ý²_.?~­Ox¿¨íbWxîÇo/jQÖÅ~¹üY)sSʆ¿\~ü«>ü¢{\ïø¸²ð“ÿ鮽8hUâ m.ÿ}‰ŸQ¸O‹|×CººÅl®ï‹5ìqå+boññòããOˆß©²Í5þDÄU|FÃï-þÞÊgŸ¿‡çáY󻶇ZóójÏ h³l—Í¿_àümt¾ù``[ãçÜÎT4çg™}qí(ãeJéï÷²ÅGù{¾mØâùNñ{Y‹{™Tù­ MÙ/ž¯ãsº<¯ãy:”sŽ-÷ñ# +ª·Kp·-n»¸–°]^Õ²šËïÿxùõOD’—= „y jñ¥9˜‘N¶û²Q +6L £4`³7ª9üüž±4ñÇ];9Ôa]Ö@*ûZÎx½jP |•X@€?à ¶Ø( |êq7ñ\Xèc=Fí\ªgpµ‚ò–¹Ê4ÀÏI9L¦w’„-ÓÆ ”`íáâÊŽFMÔímz€ÕäçñzçôÊÑwp[QDÎ%úMä¼>9..Ö,urð˜ãÚú%pøœ­ûèÅа›l^«áÚšv¿3¹‹Éß/z¨cØ70Ü…[lY¥MÔ†(6VÒ&‘µµ"zzdHÖèÁžL-‰V3S¢qH†fü’Ýß ˆ‡Í$J†n/xÙòÛ÷<ÔŽœ¢f(¡“y¼–Õ’«+°‡-ÖÕ½dÒ‚ŒRQ7ꇲ¿Í¥ó +F€šæŒ?{g«j„%QÀwFBÂþ[Ùü½(,X{!­%$|o> þ6XÈñ ~ÖHæ[[ŸD}Þ*}]6œnNsk©bqëákáJ¡N=¨pJ#Ï}“óFpùøœ¹ßp.*Ÿ°UOPuåÖ8ÖÉ`@ò}÷r¡®Æ +5ª ]ÈA­œh€˜½"7Ù>Û‡·}^YdF©Æ7šcû4+ ¯É]Ȇ!ÆCoå0ÃÂF}-@\ó÷u`W<ª9Ä4UlByþÖD(yKMÄÊ%„X[¶ÝŠlxêšëgÍÎÈ =±ùeÕæf¾H½Y!dË ¨è„9'Èãc™ŠNÃñMµ}^¤š9@Žwô† ÀšˆëãLÓ\ðÉ œɉn&ó+!]‚OðLð^Í@ oÊwÀ;9m±ý‘•2îž} Ë&ÒÝŸ »‰„ßfÇ~šî´µÆtˆšð m-€âž ­Ý=x<Žd+¨É 1$Θþ/Ù’^=\pÉx)šÔr v„j-.Lµ²±ž5ªT3¦VýŠŽ••H C”.}Ö² +סVDÓâLâ¦h¢«k +g莊gT Fq'㋨|Tç3QEí’êIRŒi†J"»* +‚ !0Ô_ O{Ì®¡¨ÆÎ›‡«by †C5œ(’ZÜ[“Ô‘ ¡¡š _Ž¾È –'¡] «íSR^$V9pþ’ÖÒì!nÚöx09qa 'Pesâ(^O,u1 ¨Av–ì$¢ß„»Û>0©¹*o-Ã\–Ir[ÿªÉsmä©ÿ7–‰D~œDè˜x±Dá­Á]ƒk[>ß: ÈRà·•$&•5¶àÛ$ÞRH–Œ¬Å’÷s[ä‹8!P»3Ká:ëO|_—ÑdûdºkОŒ"Rj‡ µòa ·!  Ñ,•¸Â}çf¥’¡¶ ©Ú“V„vµ=û¶ÎU#åD®xT2Iߣ›¥ +{†ÉÐðò<ÃGÝ…$ÿÌtt$£kèLôVCa‹½ïœNÝŸb&µ~÷^ÖP“_¨£q è:¾ ¦3÷>Vd¿Âxƒ0`aîNp?pÒ˜!Ç1³¯ÆÆ+®>ôür5Ê¢h†·5L¨÷{‘äšìâ¹XµzS4l[ K÷ZÖ= +b«áG§bÉw½+¶»•àÌk6òD¼€Ö–¨šV{3±qùù‘@¹5‡F¯¼8úÖ„ÃöLÙ,džu- £rqdÌ2Åä§šà@*$Tª¡‰t$b¥|¡ËI>\/_:ɪZE7×ÒXp¤µÝj¯2I4{ãÐX¤B¡Œë[$ÖjHá(e7ÇÎBû]$Û5Š*×¢X§­»<­É=Vꦴ¦ †Á7El$Oº¼‘2ÓrÓä: Ñ¥ŽšÂÓè…oÕzÞZ=’të—>|VŽxêì‘|: Ù·Šæ~µv¥náôŽ•µ¯‰ÔyÕ%ëm‰*Ý"Aïƒþd­šˆìB3˜Ölä;ÏŸ£Ù}Ͱ¯¤Zƒ¹Ò ÛŸ†DŒÊ#GQ³>œæ6µP"µ«)qXÌ:·{pt³…všY¬!!oD°ø³›(µ¯åÃgâT½éÅðMÏÅ©*ÍÕ’…“@Uyâà|"X†›cÞ&§¡êQxîöEÐ’$³Á9Ÿ¿KPy¸xzÇ*=dÕ¤¬•qâIL­àTM£žÂ݉yK¡KÞ™ðBòù4öN§‰Oή±¤¢ÿ$ZnK£f³fE>¨¤=M1N&%K²VrÆÇÝ'3E÷óaÌÇ#µ46|ËæêÒ.¡¥U‰«º„$G µžìûʯû%t¹UZ¡–AA­ â1AÆ×î¶VO»n¨}(»plŽ @̾´ØŽÄ/®>]‚')=hÔ‘ÍÚl19â+z0r‰cUOs £Çæ=§ÞÖ«––ïë¤+<÷ˆò'Õ¢yÁ@ÁYc;â7¯Ó°åGºîÇsÙdΚ\æ›ØŸ®:p!òGôÈö¡Ð#ëól4 É`˜#S¢%ÚGõ +³o­He)Œ´Oëè]“U MüµÄÏ3ЙðÙ>ÖÃäÐl+m¹ë1=³Km!‹›GR÷Üœ \(wŽïO1œ=oˆåå¿ÿ³|øÛÏDM Kàw—ÑN·QÝiiIwÊñp˜ ‡×ÈŠ¢ÁË7ÊÕàý9ß,oY¤MÒÊHÀ5›M2‘¿%ÍgÃAO[û#â¿ +\xD\#Vì›dINv¦‡yn”°­Ågnao2.έ62†mÒâ(ˆðÕ)7DÝ0‹¹"ðGQ IïgáÇ4ãu#¢G´„vÑW˱ÝHÅd’–0†—£¦®Ü†oé- ‰u;a1¬Ú’<×…¯¬¯Äl_h\’3F6>·`ܘs;­v,øÒ;f„Ìz­ ÖlF3ß²¾ó6àÏz†'n½(“ “Ö‹ÖIÑ(ÀDžNt^lJçØd†ïYI€7y Ï7w^tj•ó#Âg¤âËófOñ¾<éÒk${!¶€“¾ŸÖÿÜd!¢UuJ|êן,î ËþgÓOÔÅó;&8aªrȹ'vÏS$Ú[ØŸ¤cÔ™.¡H*ÕR2ë$¯Ã$&7³Î sŽ$ÈxòBBæ”fÑ eìAP•1axLÒvf»ˆKsU’ã>?ù9Øç':O•¹ìk?)(.æ¸ÓKÇŠ'Àr]“Óå{&?­I}"¶µeÃe_ý´ùç‚HÏÌ~Z°§@rÙ””Êä%\Y y\³àEÍ5]reÈŸË‘Š2E7åû¶|7ÕiÕ3w¥Ë e¶ùámim=Z¼p„èz];kª×TÆä›1éa¯áýBaÝGv=R¥(h=Å«ÚÖ!0H= Š0ëÆØðl%äa÷°­íœÜ½ˆ)IVñúêô™›%sÔÓyˆZ.O¯o«k&¹Ü0÷\“Õ¡KÉe,,"6œÜ»<Õ¸•F|%IÕŽ¾ã˜£Šp +ÍʪHÆ0ýC´þnj–·Ç'ùlz§1Ý´½ŒíT^¡£q§/»–-GS’ެ%QºªC”ùÕ÷Cćðî6Ot5ý½QcÒ§™8N¦Ù€êQðì-“ðn†’äü,é–rÆÓdÈù8}œŒЬçôTVþ¿–0YqGœ³·Ö9ÉÇ §a%½‚?¿3Ë¥´ä‹=Ô—£m“CÎV;íS.ÀM€SÚߊ4ÍHð`ê}<öº‡ø|õ=“"ÇøGãiPO؆ÎãpÈ__þø7•Œ +endstream +endobj +611 0 obj +4936 +endobj +612 0 obj +[ +613 0 R +] +endobj +613 0 obj +<< +/Type /Annot /Subtype /Link /Rect [180.75 284.65 277.50 278.40] /H /N /Border [0 0 0] /F 4 /Dest [750 0 R /XYZ 564 674.65 0 ] >> +endobj +614 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Contents [615 0 R] +>> +endobj +615 0 obj +<< /Length 616 0 R /Filter /FlateDecode >> +stream +xœíÛŠ+7ò æü¼0>ºw7„{|ü¾0Ý<,$¼ä÷W%UIUêêvÛs˲3>m©Tªû­óû›=™üŸ=Ùt^\þöó¯o¿½]?߾ݗÓr:}þÒVÄx6óÉO°îó×7s6Áå?Ÿ~2Æ„ü‰ù“ògÊŸ9–¿Ÿ>ÿýæ–s8eŸÿ<å-.´->.ùsÍŸü÷ A|ÇoƒMs>¿Ãµ“€{ǽ#ï³ÿÚzžu/Ÿoó:‹ëm,ðéÖ.ãŸ/Ü®ý‡Ít˜Mˆ <‹>™ó’½,ms¸å{¿ 3ÒÄ^ç¿G¤UªkÝm—FÖ:8¼)Ìî»À;,áÄ{Äõeý·»ƒ„„%ó:ð­Öþ|Ëßÿx3¡’×À3EÆŒ?§ðøð¾~>')”¾I˜ÎÖË}ÿÌR ì0Ÿ3BJ°1ssr§?þõöËßHì­9-À¸µèO™£y¢Õޱ$úÐ\*Clþëˆ1—Ê(xVÍ#3?ês7÷ývbLõ¸?vᆽðÕ\9ì<úºQ¢@ÚŠÙ[Ø9LÊ\µfÎL .Í„ø(Lß7]+í`£ŸVRáã ú)(æ< +a}‹0Õ¿þV™å–ú;Hüf?ªñó3>ÏkB>Pú|‡_4ƒÙk†Æ/ήñ« Xr§i­U²: ~8–îÃíUÂht$ü„K¸ü;þNt¦;Z´#8푎t—]ë0h4.eÏe¸ÓäòŒÖÞðLóÎÕói ÒVqúCE¿²5ôŒ”¾so¨Ìì~‹ +Hacßû(η¹z­xÆôw7š×¼)ÑÝ:R£ÍóAdT"UndÅÁÐÉ(–—P‚ò º…–¾‡Zð<âïà Â:C K‰øY¦×ޏðë. +Uˆ=$m¼ qÙ—{’¹uR–`ªÞÚJ +e3L`çf£ç|?¹p‹>¼ÞÖÞ&ÚsAÔ„„#ͽå¡Ó B°Q)6C=ˆ¢Ö‘Æ(€íl† ð¦¡ÝQ²#o%#˜ë¨LxÎbkT{´Qàz'ùü 8Σ;¥ +Ýã2ƒ?VeÄs)Â!_º(‘ötž`½öh1*Ä€#—ü¸ 3HybðîÁK Ýu½3T ÄÙ}wÇ»GE~ÀµÙ:%(§„ 0§8!¦%Påz‹:U_Ü|³¬¼æ_À(­QñvXW¢qÉ«n +bÕ7KÁ,a‡jΧó”4*DMJ¦Ðë­=„|\°/9j7é™2U/ZK÷XñàÉÆn,2”ÿ#±¢¬×À³š›i ù¨ôÒwÍ.’^⾖ΓP.cÉÙ ²,%·R·ýì t—`…<~0œp©»tš–ï~­ŒKýÆDMkíìª*bfO³¬8†çØ{VÚœ@<¢(¢JI'ö¢±­XíCíª]ƒ]šF‡;èë¥Áæ&zàº^<ÄjofiVZxN‚`%£ç¬ü†á…ÚæpùîGl7#^v]ŽÅíÞesUˆÁÎ3ò`ñ%‘ :äŽÅ‡\«_qnï:SÒ™c–søè2§mZ¦¢ÉâÎéù;û @"™o6Ý¢ WÖ![vç»ç à=¼»®¸ï£ïã6å9ZùÉK¾¾(~žÏ#®‹ Õ½ŠIuM;ä f^飗’>øœ˜ñõKHoxôe½±¶™äÕ}§pzâú¬íhD’°µ=½ 2ÑŒ¬Ý »BæÅÔìçX¼T¹Á„¢%,czè¬*›Ù½9X&,Z<w섎«˜Æ…R^ë}wƒOW›¤ö˜R`–ïQFx`[¤G¡fDkIÄeÄj%“È2p^êâåZ{[Ão×-âóPw,©!sCàçiÂ6M¬Âa9'[ H.ˆ/—ˆ˜€ÒÀ¯"Ä^f;`»JÕ3+9©C5;Þåò$^š”]*f\Ò) +ƒF‚~¤oä²—º•§êb«ÚL‹Ì"Qž4‹°µÐb~cÖÅ–aÕDEšÙœ­:Ž/¡ªJS\z=§KSQÉP%§82Öæ¶8ÃEÅm­uN¿C|éΰÊóâÀ! +DbC„ +(ƒÝu©Øç¾é]0Y6“†ÇCT+Žcìy²ÅüuSkXGêËæyš“£ù)–xèGÀ3`‘Å^L4‹=caÉ-ÊFvöÀÅi“‹lO7æ ·Êª=Þ&4’¹ØóIÖ;H³ò»ëkIÊú+ªA0m"fƒv I<¸Ïñæ¢vðCÜvC e­]Ì ·®ì1ÕÍÌLôÓTW%õ^ׂÄîsIå@GHÏ]!JñŸÌªXÊè¢X²Á:qýe_ð‡„«„à@(ÄXZÚbÐJ6šCÆùäŰáa–ŠðàéCv8Éù¿ #¼d(šAEOá +]l¯ 7È)„-™Ââ nRŸÛ{Da­­HÏ4%{à9ªã”Á³-ßì2$1ÀtNð`²š_šUW¢‘åÐë_Sôr—¢ó×»A%ØÅuj5+Ã(üCº@6˜aèyïº5HsùË9*³9_R’=)¬®d^ýÀY»ÑŠL<ïùÜ‹Ò+F¦5笸µÏåsðîæµÐ î³Îì­ŒeU¾›ÒØ‹›}ˆ+s°5R|U€ØÕH ø-æ“h•N<Õ(U?E§ï:)\TdSóPýwÝ=õ+†È-ž’ݹ ’»ijÈÜ÷´ÄŽ•3Š¡XOHùèË« #6›µ|hzsE]³(MƒôŽ™ ÃüÌ[nÚd•éå¸H´ +Û4 +®xìOú›ªÃhÜ?W)åûÙ?!Hj¢\Ñ,þ-‡Gi%ø|FåÒYxn¶®Áí4{´=x¦Ç ªð‚¬ÂÓFëÊ,÷³!„µ©0Žƒg¹ «–Xšè£–¹ªçV“MÌ$ìõyåd‡YÏ$;–JŒ×_Œ—“ ôa5 ":l $mÌ3P¹sSÞKîÚàÕmG î~b]r%Z¼2‡ò¿> +>> +/Annots 620 0 R +/Contents [618 0 R] +>> +endobj +618 0 obj +<< /Length 619 0 R /Filter /FlateDecode >> +stream +xœí[ëŠ+¹~‚yÿŒW÷nAØãñþÎ2o°› 6ó'¯U©JªR«ÛžÙ³@8 ¶ûèR÷ª¯¤þ׋=™òÏžl:gW¾ýüÛË?_®/?Üó)ŸN¿¶1žÍzò ŒûøíÅœeÀϧ?ã®Æøõ/§´á)žmRÃmæáÆÃÿánã°Ñb†¬;ýû¥|ÿöbxˆ“ <ÛRº„³[o݆ç³wj¸‰±·2üþbùK噡e.å¯0nÊ Ÿkù\é{¬Ïa<Œu·òúf©ãM®¤Xw^O…š_N°ÿ:Ûß½+²½‹çÝÁ56÷÷rùúV.(É–ð÷–x§ßû˦µì/XпÓ\^ÄdèÓ’­Wö·eœ¥ñ¶ìgí tT;{ÿ(†ý9…SXÏa=…”Îi=½šóâNßþöòëŸØ’­9åsNk^’9d$ “ìmI¤ «WbÃÓ3OÚ¹ +Kå:Ï­Ä­‡ó Í[h½K_DZEÉ}=‰ü^UdËÚÎÒsVãÿ¿ +5Ý»ð9ì“HÝY¨ý¦×˜­<»Â€+ÿïËø°TžA]Àü_ðõ9X½/sýµŽm¦°<ѱ(Ë‹u)åßì)ia¢p³ ^¬&¥‡ ¡‰ÖU®æ +qþR ƵX8¤h·ì­éíym†ÔÜ+•“»rQ¤ø/T8‡ vü‘/ SlÓ¯4¸€w©¼W•ÊA奪0ð=P |‚Ò€nTäT¹joç„Oµy´¼y(}Y$D=)-0ZM +bpÏ.VwἊc›æ,›²p)5xæ-!óÛ¸ÑÜÆ´}WaÞ + —®mˉàÚã'¹#ÓnÉÍw--åÂ>iù‘’QaoÕ¨Q±Ò;ߪ€‡‚ÂÑ(B] ÁÍ­ö׊Qέ&Ù^6WÞÄ»1®}AA¨x~ÆÆÀ1ï8TkÏ> ÂK^±kË)®3(Õ,_!¢ô4¶u#R[(Ö[E qNʨÛveǯ2o÷#Æ UbÚ õÀ>ÕÒg5Ð4Œò2eÍÛ|ŽI/ìzepgAåœNÓv!Ñ@  T>¿¯Z¿&(Uúb 5çµjA{ZK&ŽôûHÃ.A…¢'k £wË,b”Ò,5çKÍ:oz¿i…*™þ¾©Øñô Þù÷Ziµ\°¼õyœ»XSè˜ÓêIØ?Ä=B<»Æƒß˯M.K_“-b/ÇvÓÈŸäÂõg‹â\ÞÄØ¬Ç´µäú±`œ8áÜÜåɲ,÷»iSóé{ýÛ—›«eïµ>ÇžeFUrbྼ¬ÑSË˜å•©Ž¸Ö¬Š¶Dõ=Öød#– Í;ñli\`@8)×í’ÓIJüiÒÙÕb®jÃ[–†Œ¼’¿æ\¼j°¶´žGÚtˆž œ¾Õœ€^LÉÿâ`A6>HÀŤú@.YHKO³Öæ4\ìä3v3•IÆÊNnß¡%ÀÜø¶)àÙz _J=+@3½ÏP1~Z>"²V2ð~+ƒþ‹s@¨W”jþïÕj„:â9x´5å8q÷˜‹€66ˆv–{¹…¶ÇQr/òÝÅoÎÍ¢–AÇU‡BIÚÊ–Ü#ér‹Ìÿ²jiµ9F½NY ”cŠ?»ÑÈ\‹•'`°c톴×<ˆK½°F#`(GxG9!7Ü6×tù©–´[·»™VÞÍú²ji—Ó5§.Y(MRºã,öõ]ÆÊ”›Å³ d~ÔO¨©n¨ø a°ã¬Ã8´Ðzä$®_n5ON-î{6Gžê!lk—y}¢Ü@ïî¡\b$)h¹$•¶gÀ2&û¾õ_`z +'ÌbÖhz÷ª(†É‘… #`¦òé¼=z¶‰ÚžØM¡‹‰áhèXÆ"!AÛ«›…Ž®ÿR¦1¬tÚÔŠ6íbõ½¡ÐKrsÓÕ•ä=€/\uu!žã¶´Æò”2÷ß7•Õ½y1¾¹6›øÁ핽k­Ï”ÓœmTw•͇yâ»x×ÏЩKç †TìW6×qfµýmâëC±€zO©ÃîM…×,¼`âÚé‘iwìSÚmÙBFâöVÞÑ„d¬iNú÷rµ-hÏÀÙ,ðÉï;§@-÷?AkSBÒ4ïõïùw2úYÒ!¾ý;Yû¥?cËlÖúå‹Ú3e:lÛ<«OéY è°~co?âì0Éz1ýÂUx1÷†9ú½‰zRFz'AFŸYs~s/<ï¡–HÌm‰º°u>8¶ÇôŒå0žƒq*Ëdm»'#šïŽî°;káCbèaX†`%†)6bý£Ø1ƒ¬ãÑy+Ÿ5 +x_±("öîªÞõBK‚2T/”6˜’/^Èš‘ú'‚Àæ4gà|~¹V§ ƒgàWy§·æ œP“u+¶ºpDjú쥄Ç>\NuЕQÂíýv-=Ñ#’PLÊ{RM|³ÛÎj»~%ø°ÌhüNÂf¼i¼i– úÄËÂm ¹ŽM^w»Ð5l·ÎÞBPÕR2¯JåJ‹ÍñKÉÛôÅy“E'óÉC³Õ€æÙ—Œ ×…ñ”®8ê}ñkŽšÖžÆàK@b<Æß{I\ŒïÆìž C‡¥Ãé®"D;:˜59[M2œ–]xÚ×Õ¦Tb–&V#èh”Bå«!œx¸‘Q3ܯ<ÔN_}xT¡1ļšÖ…Q°> +endobj +622 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Annots 625 0 R +/Contents [623 0 R] +>> +endobj +623 0 obj +<< /Length 624 0 R /Filter /FlateDecode >> +stream +xœÅ[ÙŽ+¹ ýÿƒŸ¤F[m@ÀK{žôL2L€ÌK~?’J¤U”]í¾Apa\/*‰ârxH©ÿ}²gÿÙ³†ÕÅw¿üvú×éúyú鱞×óùóW1ŽƒYÎ~Nã>;™Áürþ“1&Ä×_S|ÍñµÄ×úçóç?OnÂ9Nðù·s|Ä~ÄÇ×%¾®ñu+ŸïeŠò¹?í´Äõë¼vó>ʳ4G|Κò¿ÝÖ³®Ì×·qœ-ãí˜ç§]»(Ü0oûi±…³S0 ¼ˆý7„¾ÌÄÏ•Ú"@ä^„(Nò%Ü¥<•±âly>Í•ßE¡“'¬aÇ®Bi>ÿéaÇÆòam·bÝù?§øþ÷“¡6µ™ôâ;ÆSx½x¿ “t6Ïžã®é•Ç|FoóÜaÂrÓ”ŒVšÝù÷¿Ÿ~ýCugožƒMC‹üÿÁ@I´ìQ­h“wÃ<‘h¬.g·¥ÒòŽœ:Ôe(xÜT—uK ¢¸´¿Qós­§Ñ&ëöõhÍ9FĤÉk=˜—Ò^Š\—˜(›ßÌ™ƒ›ä¢ß£¬vÝ~³E¥ùs™ƒžá¹ÖmŒÿ({½6cÇ›ÙuIû“‚³˜µø¢™ºn H_³À3ÆËqBø¹(‡6 ÏZz¯Íw«Jq¡ÈFcåý”[žËs‚¿Ú‚¼üìXö¾Â~ã<®üîî •öžÆosɘޜĸ˜6±5dUnÃMÂØ] 2GíµQÏX¶ØlM¨ï æDAêzÕù{2#¹Ê¥ÈGêÂñšj5²ÜêB†bR 1âY-éc2ªËf"·¸6±¦¹$Éî•yðû¼íÙ‚ܬ¸Â¸Œ jvxA ]56oÛû¬WÚ«§´P~'øÝÅ¿FqŒ¿·NŸ‹mxÜ>ÔØF„ĺ×;É&RC §-t%g0f˜½Ä}Õ|&ýøjWug¹“OsŒ½w¯cCó‰9f!ÚúÈ.16¡p—Û©´¯ªÖÔ=éî:NƒWÌò7»eÚ¶yTU°ú/f‡ô,ã‹Ô˜D´òüÝ„°xWôA쥦Å/DzÔè:ò§v…S»+¬Óf™ïfJ„ÎÖÛ ©º\5ûO}Ž|Ãj¿&àÔ4Õô…šCi+}ìà'He•ñ~>FÈ®o°çð\Ö¸È9»°«ÅS1 in– • ý„³Yt"¤Õsý=Óð0üÝ(ÇAIy÷Áy3»³EÖN‘zJªÙú$5ïòžøNäuKÀ&yØh²n[ÖÁNbšŠ=˜Ö(Ʋ}Q% + zMøÁ©RùU0ô Ž]åç5øJ,suD}€[u‰‚ɹZ +¹öß £±lœZj?*¥ 5²—Ïɇés¢|LûˆÓø$ õ%¨LÏ«Ïcò-Ø“Õ?Ú™ñé4·<[Ê‚KEŽê89òîÏ%ô*以ZXü>o`$Œ'Cà éò€KuîÜ™ø{úù¾-†«Îat{‡ wE¦Ìóhìn­’­¤c<“xæd·j¥êÎÈÊ,Á3í~4õ®Mhê¤dõE­0ÛÊÂ\:G+!Ã"ôÞ7ÂQÖ…Ê·´@¤ +b ¸ÁÄ’×™ëºÞ.¬²‘Ž:)­Aãi ØÅ„L¬ÍÇ™6›Æ¯ó02 [¼FÃà×ÁíüÇÏF6¶¶ +Ä/©ÕTÑ `Á™Ú9hÐ*…W²nB$è&z¸Ûwwê £ cóhóVçϯ¦›– Š1{Ù´zõ"!«M\vëníV:ši‚ßÿQÞüõçš™S𜉎H%†l„Ð Nム/^—ô•Å„v]Y=÷b§¼á¸«°”f9'ÞšvÜîƒPƒle·üò^¡Š£¡aÔNÁ(xìÈE/¥Ê,;¦àµÑÀI’‰, é&½ÚšÅì3µjt+êe/-" š`kæGÐËyÊltÏcì2˜5…oÓK1ØmA5,Öy/PšÞºÛF"w[ÏÚ5µÄÞ‡ú¾ñ,ýr6‚òy-ø‘ÈMmõ´ûª¥{ªÃ{2?¡ÞƒìõØÉ øƒ)ÞNû…À°GÙ³ob­ÍØ*`¬P–„:Ÿu‡ºPbXÓ+ûÐÍìtø•˜?%ý4–C–LÚƒ Úˆ©¤1çL…‚“ÒÑ3¶&T>#»ÉÓ‡¸t@ DN±¶E\ÎÅy’à Î×\’íµ-´¤Ò»&uÙ¯ Nqyw—ç?jL§=çJfé+†c¢œšÈÍ>RÞeÙ%³o —’ÍèÜñØ*2䪋 @/âx- ÅŠ«T¾thg=<ÓdÜnµÝd¨^ç0σ·ú[Ú»'¾N(¥Èài>䶈r7#8-6Ó~\¯±ëý”ša»šÂ.빑áîÚt×XGÙJ¶-R"J)>±kzÓ3ˆ>½"—iãéÎ@@žh@Ñ õÉéDϨ|òð Štõ¶Ò*“•P­QµžáR¯æ>.$,kÏŠ^žù¡–$ŸWÚNad ê3q¸V2Ãdõi­ßÑ‘5„º[#O»FgïÜr ‰v—WZ·|Ãñ]˦ÚN1vîKíï°Ù$ºš#X_Oaà6ÑØ~¢¤É§{UGcOG¯ÎÀ™Õ>ŒÞGBNtÓÞ$oty4‡õœOÐÙëÝ쬜¶‘ ÈØj.PìçÖ)±ȵÊyÔ9Õ¼7ôóò 6·? ÆcWÚY¹—¼…·µ§RKÂí¡Xåw¯¦í’|§ü镽C4Þ! ßuôpg§ß{Îß%mšE<›öG!¶ |{\Ú+ïµl!Ê–ö² v° ðÈ–ØhƒM´&Z§G™)P[½C £¼Z Ú)c-4-ø +–ô»F/êõÚd1 +Ú‹œsÇWµQ4˜}½-a8¹=i·LkŠOùœÙ·[À^·Q¬'ç„ã^$‹×:ï[Çt’½"¡Ä´h¿´gR~7¹TOÊ ˆv&õuÅ¢m¹¥@Kg¼²Ù†q´§˜õ¸"\ÈFܱZ°±#kŽ6Á¡ˆèZ~¯ûgM¾}ˆÓé: á¯¸ä˜¯ +±UâÌüȨÖÝkeÑ ­Fç:¤‡öŒ£“"ð¦‘ߜ֘DÙŽ„Ô¦Ï:BéÆ7·a<ý¢dH§µ®ú¤-åEö+<~Ò$ +65€àÔ¥òÙæ>±Åhê¼´'-÷òNRØŽxÂþN—‡w¤E†õ|ªâ#·ÛL·c]5ë+u%^÷†ì:j°z¨7qGõÑ/NMGû9;8n.g)¥°ã.¯P Á´yß(Æ^åfâ> +endobj +627 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Annots 630 0 R +/Contents [628 0 R] +>> +endobj +628 0 obj +<< /Length 629 0 R /Filter /FlateDecode >> +stream +xœµZÛŠ$7 ý‚þ‡zL­ïå‚èËô>'Ìl²À²/ùýØ.I–\vuϰaúæ²e]ŽŽdÿsÒ“JzÒa^Mz÷åÛéïÓåíôé¾Në4½}¥ÞÏ*NvÉãÞ¾Ô¬¬K¾L?+e.éßý2½ýEßuÃõŠÃ•Íÿeø§»öÍB‹jÒfú÷”Þ?)œÀ—‡Uþn/éâf/MÃ×Ù1\i®oixH¯1½¦Mªüš¾Ó. ±ýfÔ6­9§×kú-ÀؼÔÞçïáùÌÑeí½dë“út’ÇÄj†¼×,O–C¯°Æ„åûë&c§a?Ì~C3Âo›Þt²iÍK­yapã=8^ÉýŒ'`Î0ã¤e_–fE™Ñ¶—*£F—Õ _ã¶e<ØOŸ·Ôwãò<>'wà‚Ê.+µnRæ?K0ËìM#h §]Ù¤œ—ê°&V!Q+ãLÁ“óh|ßQ,WP™/€£á3¸¦­ãQ¶üÞ8;€ ­q/\i+|æÎ‡rIã‚Ã$ÕYƒ>gɺЦqiñÞ°ç„®IÞЬßèªÈˆïñ·; Ïôêa.f3ÂÿÌ…û¾T€Ä9ì^gEFk.,–í9ÏÚÈäÙ‰U¶DIUèÂE9N«œ‘¤âv΃†ÅèbŠÊo÷Æ}Þáx<ëxÚ6™ÂnÒ±T”ž… +ѱç€Úϱ .dßVlîï:\ \•êw;˦^|hë# ,àsÙH£ª¹|ï\³¹âƒ¸ï¥š£3Üïdq^Òǵú÷>âù1}¶çܵg~UÈf‹#( º]}ˆm´U!B¨Ç³ƒ[ÂhÂ&½Z óKxÓKÌ|If8Q'le‰ +}fè·~/gÏŸë(”üÆù0î1‹ö)ñÆnÙ›öñ""LjD>éõ`û„$ dtt¿»œ(®™_JG>ùâ¹êŒ°šëI'Ë!Çþ* Öê3º`‚•6ZE 1p +Öõß°š9ÒÞ*áêų%ù0ä!§~?þÝ<¡—sÑ÷Àw³îÝ¥þîÎlMž7oªÂ>` ÆæòðœËÓ 'rZ~~f³í×+!h²ÂBVе|ÒÅKI°•n}`¥™E²ˆ«:¦ÿ¬44O7Æ.åMТ.”å&Êi±l‰Ì)m•J«YºŠ¾,…qI˜Ä:…0•=æû ]˜]3_ìG@žJÆAÒs,UÚµm9*hÙª$Ò²uˆšvèj~»+X+Ê<,p @ÍÖÏû¤6K½T†¦× €&zï–^£HxÈ"å© Ù3¢¬å#ÚEwM faã£Æ„_C+p…žÇu‹ô™Ç=Ad}&1ÔŽ«Ç(- ýÊä•_«oe‚Çûì…Lâ1ÊÊô‡ç@JSFœjÎJ3“.“Þ€Yf'q0¸Q¾ƒÏš¡EÊÓ¬oC””i¯â°cF°4ÛZË¿Ÿà±>Á‹¦s«ð %~Êú+» (® ùi¢¡Y°–*Üg°P£(âÍ\üþÇ"Ê<„å7Á/¡œ!Ž Í”á61dL–T½êþö›®Eb“’\†qSp +øL““[ˆ`‚_R$z¬¯þ¦[nw‘@^áÚM1Þº)j=©¢%±J¿b@M­oóÈw4Úsil|@ÝvÇhë!¥l›ú&>—•ËØ´žtW²áÙú:Ïø î#ÊçèŒ÷p®²¼ÎúÙ8a;Æ^·5Ñ>tÚieãPÖr=1v6»ÚZlå¨ÏÓn•Ó_4‡…ï0a_ÆjÜ•š«¢^šU3lÜp³9 Ó¹6§}åökÄ ›ÀRê¡¢ÊÉ\Ɖw¦ÞN©ÿžqN5e\œÈB~ÿÞüö™õNí¼4’דÈ3 ¦X©œÀ¦üêÀap,;ᢱm0Þëñ? a2Š®¥ïsDÎ,Y¤ÞKYò ©˜ œ¹ÕM×¼ äáΨÝÀš³V3)}“Šõ ¯Tõ†6÷zÙ”@T$úá·ãÌ.FÓô!Cˆ'ü8?lðÍ‹µ^D;¹[½`¸#…áŽ-«³”«Lr'«(©[bæ›ÑZBí³þÜ03›„MŒs>.k\X2 ¡f,¯kÚûDƒÚ$šÜàcÕ€h˜_Ýõië¢rŸ +k'^„Þië)0qÛ¢ì‰b¹¶) [0÷ªt:XI³ÓuÀñ?ìð˜RÀLÿö,ƒÄº½ÄoþÇK4Ý$0àtù§a—ÉDoqT©Ã¶9[š[»Ë +Lnl¶4ÀN´ÙW,‘`®ð–(纇ݽ{µñ߆kêî\ý§G Ð†˜8ù9H—'@ByhÞËËyCx°[ð7gûš-#¯c ¢EKÓ˜`ÇÄ ¥˜Èá=QŽ7xßÓ°H¼)ºæú¨å"ZxgrÉ÷>©l4$ť̎kç£úŠÐŒ²¶Wh²#T´‹fGäOµXzMgвzŽ:pŒr ÍïþH·¿¤!jqÄÂg/õyq €øô¢®É4} Uz­Fw…ë¢:é.Áð¦»8=ß +ªÂ¦z|@©Mžð¹T—ˆ©Xi<èK·Y®×ýj›> +endobj +632 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Contents [633 0 R] +>> +endobj +633 0 obj +<< /Length 634 0 R /Filter /FlateDecode >> +stream +xœÅ[ÛŽó¸ ~‚¼C® Ô«³m (d&÷æ ¶Ý‹[ {Óׯ$“)Q¶“™¢øü3ëÄÃÇýªøO_u˜Vúõ÷Ë¿.÷¯Ë/Ïõº^¯_¿•'¼ŸÔrµszîë÷‹š”3ñ_¯QJ¹øññâgŽŸ%~Ö¿^¿þy1ëä®q‚¯¿_ããÊ?·ø¹ÇÏ~ÿ€)>á÷ñ´a‰ë×yõÌæ}ÂXœ#ŽÓ +þ×ÛzÚÀ|q}ŸÓð¼öy~<µ‰û.ÇþsZlÁÅt€ ¦ /l ÕÄÅ¥43OØË +{¹Ã^P& —xf!ÏÜaŸqœYªÌÒqPVF±­¸ÕEÐ­è•‰ËæÇyjßèÜ­ëd ªÍõ?—øó…3lSé;Áj”¼9^¼>¿L>°çm±sOCòóŸ_ÑN½‚»ºerËÕ…0…åõ3›ëÿ¸üö§jÈV –<;ý?é&m+ÛQ»­`Í4¶/–foÉ„7²Ó²Ó×¶z!š3<7ãC\SÅåµ&«EÁ'Š3Û +:xô?–´V×è-A:•¶¨PXÂóÍø¨DG›ªJÒÙ3Dpm .»‚ˆãÏÅ?Ãßï rTWÿäçwv2 _s®"ðÄæmàœdÅeê?F>­_C’ô¸Žnõùÿ¸?ƒw#KÛíoVo¦Ÿ·f˜ÿŽs,Ûfªg›v›»È ~Ïf ß]M·À,üžÖ-(7ïïÕ ”âzw¢œ÷|«ãò™ÒøGýÞ8úÌzôd¿²Ç…Èõ1>ËÞNf2߃ìsî!kÓùâQá5<àÁ1^P +G²è „LÀG6Þ*> •ðAÆá¸'"0al1ehàö½e$i2­?~Iå°ÐƒY–)±™eŸMŒ c—€=6(¶„ +T3>Æ›´óœÂ×+»Áo—ÎÍe B³daaž–‚*ïà5ÔÀ›1d²#dñÜÎó¤tÍê%„çU ˜2bî\MªÅiê“ãòÏ'$,áÖÀüÑ”çè+W\;+˜UçÀ ¨óis;>îÈFG@d†àâCâa übÅ#ÀÜSˆ¡@‰¼1ä g@åuU£0ØÆe—‡ófYÜào¸F€¿ ¥²£ÁšÈ·‚î‰À¦·uÓIgt¼&sb³¯sŽŒ³œu‰œä½ÎµÍ!éÙ¹˜4@ša‹™z¹gF».c<4ODf?Ù@žbê^EÚ8gß”àÝ kÀF†k1Y˜I‡$j<û}pãã9šõ11b¢q,vïØ(‹Ï”ûƒÿØO×­~‡[?2ÑG%Ñz\W²%k'ÄkÕk¼uµ¬½U:¤$¡å¾&̓Û`åe(~ëÜŒWaù´Æ5(ÌàzX¶hcå” ža Šš9FðwÒÏÆ5.HBhKï Ãl#w²‡6GBê Ã2é?`g406§UÊm™ ”?CÚDêé–yêé’l“­¥ß»pÜæ—VËŠrgþHrËw(ûï VéT )J[­4G0˜Ø=÷2«Ácr..UÎȰW‰õ„V5DlgBùJ"ðrš:¦ÚðÑ‘à_<³L)ò‘åG˜l>r¶ö\¿†2žÜÌ©B]·…ÆÝ¤@K.”±Ý{<$pŒøgú9íÊRcí‚/þmU…7îË¥½k<ÔQqÎLäoBVi}a­Ï–à$Éh‚KpeJ]*žsØèTr«I^%r/° +ü.)H‹(¤þÁ #ètQwÈ-ãV¥ÚÂù t®·ž–šá¼΋îõ;j=Hœ“… Übi1}ïüµK…Š£ÍŒð+ä/ù™6"Ï)Ï_1dsZpêW2)ž¿Í©<¶¸+Æ®QÝC‚¡×qJäøwÂ!l¯œ2•–+÷R[ED?E; ÿÔ}(ïVvd"D€î–µ4¾¥°‹%N\‹…TRîÞV?ÏpºÃLµy~À™ =•lwß(4tК|Äe Kòj…‚:’ƒr@8¼ÑÚR‰a@„ +ÒÙZ苲bi¼Ð·dMÕÑ}4Ö²g|lC/N[“šMúÆ’â·p"›\³µ’1,½ù†¯“Š·lb^^JTýc/óJwÂqt‹ +k³ÿ¥MϘeП[WX«‹`5:{Þ»Á˜zà–Oܥ̖¥”AJR”î Ïd\Çæ˜TÁ.|FÒŽ;ŸJ¡¸–윰›OhhzøJ}f÷>q‡Þ¢"‘{±îıH)~SLI.¤Bð¨öìÄl­ËÍL,ž‚HIÃ-)46ùVU8Zé€éëfGv–òLFƒÑ³JAC´ güµµÎ÷ƒ·*Ÿ®ÛØÖS+=j|¾Õ¦š:¿Û…]ã`Ð9Ä-ÿ4âÒ‰Yýë]YÖæs;lTH‰™QF`3¡µ=’ï@}ðÀ˜YE1ÌÞ$XÍ•\S3“¯H`ý’ž’¬Œ‚fš‚µá`Òƒ¹Ås㞺䇮_ø¶ä*ÚÀ}gJ9—b›@¶f"T‚º‘¬^,XHµÊ=y– —'7 +ë³Q”C¥3±VîzÆëÂ!ðtj bá˜Ø›2ª¢Îí½ÑÕN¢:¼ÙŠhÀ¥ +úŰEÕÚ>§Ò±K,$ûQ:u4uþר£Äɱn*úÚ]½@h¸NUºâû +T_#ˆf5]Љ9g9¿¯cùÚ«î…¢‡B±õ ã䄇n·¦™ùsË^AÔBky§2±FR^Ù‹`&n8ÉéÄŒ¡lh§¶„«˜¤ÛÀ'¨í½§âJ4›€P§ þÜM1\¨þàmŠÚ¥ÜÙ,£ä”¤ó°JvG˃íU²rÍùåÍ[5§B}._TØÌܑЭ=°F&ÒZP +†HáÐG׊'îD÷–xdBH)C—+4×߯‘ß&) ýBµÐØdz­NÓW´•Ac&G›üðb¢çš&:@¤þlqS¥ŒÀäêéÐÇ3ƒáéUtñ”,³É¬¥yDK±‚ÙôkôŸ Yl² [dËW§¾”B6òWËjï€v¤6Úq²÷uèljêãR,[s®Å¦'¯1Aï°­¶»6â-/ªyœZì«V©}6 :Yg*k‚´þþ’e²Ø„íöðm [s#a"`˜v€eƒd”Ùqõÿ’E–KCŠ‘h X´w@žuŽ­´k¹ÑAR¥:v–’˜ïŽ+GŒX·V"É|¥t˜ªÞÈûø‘ ^O ½wûÅBÜá]C-ÿèNÏŸâZG1)ý¾ä:ÇÿV†Ã‹L”O$n‡dþ‚ØÓ&¬1á=Û··ò²ª´W¤’ô¨]Cy\)c8á¦%¿èA1ú“ÀÑlÎ({Þ²6î]N¹´[d”«A_ûžLºPLòsÕ>5ˆ„¯¯!E%ö"Ø•Ø£ØØVZ#Ù‹¥‘ªyÑ‚6Ë•}ÞUI8†7Êz QX$|o÷Õ6üáñj’_¤ÞÝ®|jæú£V Ú×Gz‹ŽÄc@”9à.Nóf‡u¯íû,º&ßf—ÙÉŽ@»Y7Jðl—ýµÜíµõFí¯ýš’Ú£[ +\f({îÓzkwÙ›Cª¹uaÛ¯Õé½jP5>ÞµA$†öý[ 3±­áWk$à\Às·wšÇ6EŲgÈùËÕ°^yÏHj)—bdÙC)’J†3;h68[”]¯é¥m²hðm/Ynû±Ú"­¦,ð…’„=ª<2Ç‚ygÛãìØ5Ô8 €½Öäô¬ +“㺆öä:ë±Ò5*ëfE$†Ã`º4ªêŸ¸Ëƒ ¦¾äK²`‚âßË~Õ©€Þö +)ÂЉ;ßÓ¦›¦à´$(à‚mùÀ|ðI¥&¸å)SéØt^|Y&úî ¡rOÓZSíäè%Åcyñ +Ä’Þé`Ç­—c¹J¶“î@ºòÁˆÿ°¦zÑs«G-ea`' +êB å>{.Øå­Ä Å|[[úþu-2í¼¼ÑU< fŸ­g%®„6ÃZ§†¸Tê¹e›ZØ{¨¥.5›…b?Oju­[Çh;5ËTu¿‘îµoWþ¼ÕèBʬ)”ÌÛÞ·/£üè´Ç3 WK-%îJ–ª+K–VÐæfÈ܈õ ~ƒH~("J)Àç~lÞ­DÐZßÀë;Ï;ê ÿvQóúG.ZR}Ô—~âõý¼%3ЊôÏ8JÒYgk‚m•ñd€,Œèk¬Œ }~]þvù/» +endstream +endobj +634 0 obj +3326 +endobj +635 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F15 836 0 R >> +/XObject << /Im170 870 0 R >> +>> +/Annots 638 0 R +/Contents [636 0 R] +>> +endobj +636 0 obj +<< /Length 637 0 R /Filter /FlateDecode >> +stream +xœÍZÛŽÜ6 }0ÿàçqt³lEñÌNÐÇ ôÒ¤@¤H^úûe’"eÙ³»ÝÅbvn2EñrxHÏדíLú³ýìÒ«ŸO_NËãéÝmîæ®{üÄ+†¡7SçGX÷øùdzãCZð¡ûÑ·¤ÇøS÷ø'/Co£ZngZn<<òòw7;T¦ÚȺîïSzýídHÀ/6ðÙVÓ1ônº¿5/Ÿ{ïÔr3ðÁniùd’€ô|IÏËú>‹9§Ç5=–õÙÎJ¬ ®¡È} ‚=ë1 aË*Ц Ü„Bczmà¤ôZ ÷nP“ìàXv(×™÷X•ssŸœ–ìö{—.qA™åŒª\ð=ªaðý¾Ø8¥ý‹\£Í}ÃkIÝà³E»ºb + ¦Àõ6íg#î zLy¿‡Ç¥ƒïcèÂÔ‡© 1öqê’G×}ûxúô…±5ÝÜϱÊc4p ¹¦øüŠþöâœË&l&ÓN„ˆ$#ÜÐNɦÜGç9æsypy–;DeC²‹°cÄdC?Ùåú²&ÛO¬¡ëÚÙ'<ÉœÑïb¼§ó‡yõ™O6ñ“¸ýbÑ_`'G:½.ø0G¢ãäÃPÙÐJP½Â¯×ö÷q69•ìïE¬zL«³Ð‰ì¹ˆs£¯é<[ÿ£´û m/m>ìÇ`˜#¢¢<7Çü¸^ï(ç0~È?Žò%¿çýðº,ç¶õëæ\—ò½ ›£ +„×s:h•²?© PË)‰éÊ +é¬ a¬\=²ÄFXŠ(òQŽ!ð£p´{yj& XDæzÏ—…¶&ƒÞ3QYf:þQù‡U˜Cà#ò]fMä£YCmêìÐOÕél¡|d5LÅ‚©¼åuPä[¦tò+)¥KuBŸXéÁhH2ZÖ¶®¢ ¡–ã˜Q+Z#dYe rnƒÔž?»”óg°# ¡÷’"É…UAÑ‚b„)q#ã<>ו¢BwAŒt#ýD’så@Z•ý9 žÃ›^àY \]<°'ƒS}û_üú¾äÀ<õ‰!«£Ú㣎µù ûgiž|þÿ6CÇJÿM*¼_ÛΈTSÓ£T0£ª÷´ýxˆ.Èg%ÈO{ÀGá´¡®±b³Æ)¡'ñÜŠwúMr͵YÃÔÖ‚+ÔD¾•-òßÈÊ`sÐFšiYuX롃·S£C‹ƒëÆåpÜßî5ëuÃGÕù%côV×HjÃ}´É6Žß™€W{7=U<{èfÕ ÉîÒIÒ)Ì…v)›rA®!³ÊuG³ ÛC'7M§NùTÆ…3îA,DØ‘bç¹î­‹²™{)ÜpÎèe)¾SÜh% +pÁ&¹ ŸËa-‘©‡‚ÅØúæ`¹ÕßœÓÍÆ»Þ"<&0ÄCÞn[ÁçðÅ…fj»!ìÆ±ôËÈó\B²þYˆà°ò\ÆÊ»W£Šà EKÍBëTL—N‹N~·6Tw.¨ë) +8“™¥{v^ÕÇnäRïztô rïÁ푾²psËHp‚º4f$èóueΰ;#a¢§;°9¬k¥EFJNìTÎH¸C¢@ÐsÙ²[Ý×+ûò¹±Å0zLîäËa×&·”Çݤ¸–f'ÜÍ5KxË÷@™ µŠïE·°EƒÛIU°zñцÒÃÁjZr%"Í娭Ý3¥‹Âm¢wäjËTwôÛô4U5Þ«¾žÆÕ^„^4Å™ÄçuÕ¥¾ˆ¦4TëñmÍ@_š·½pn§Ô^ AJ+L›E|1ºöÕËs‘ùxݦ¨f*.|ÕAJÐþŸêDsõZµ£1!âÆm9ªÞö ã®Uþ­0ŸÌC2§kšðJdP­ÙÜQ\ìÜN½hs(èònÓ|i*ÜkÇFŸzZ%CÀ#è„ê]µ3ÇRzý@{/˜$⨷*M'šŠ¹²¼³@¦¨¼ÛŒ¾†i%Wg8 LŽ;ìÎ>ÍH£æx)ë^¡<ÐkLóå0háÇ*Ùà²Ú·Y}mt…H¨!<…#»ä7;·GÌ‚–yxëGÝÖi@ñS¸ÝÞ= +]I€më÷*' ÃÉÜÝ#Tú­K“à>‘·¾O}m…À`áiscIú@ø¿9;ö'=UœÈ°¬ý$ÙDÃÏMv˜{ß7²=wO/Û®‰z÷¤öÐ;mÓ¤5æp#½áؼ„ªžJ¸ `»c½gð{µ¾ÕcÒUéøg/-—:×—ar3ú7Œد—·ò¿§•Õ¥Ž1\­…îÖ ¹Ñ(#(•–JÑØANåýÿçþžà^v¶Æ?²Z¨bßB}YìëÛµ±oàl~x<}…[?y„ñW“n†woÝ”o}ûØýÖ}eoà›Áeïã—ë…ÞO >¿y÷óçä’îú×›_Nð÷Ž'“% +endstream +endobj +637 0 obj +2271 +endobj +638 0 obj +[ +639 0 R +] +endobj +639 0 obj +<< +/Type /Annot /Subtype /Link /Rect [214.50 701.15 252 694.90] /H /N /Border [0 0 0] /F 4 /Dest [756 0 R /XYZ 76.50 241.15 0 ] >> +endobj +640 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F15 836 0 R >> +/XObject << /Im177 872 0 R >> +>> +/Contents [641 0 R] +>> +endobj +641 0 obj +<< /Length 642 0 R /Filter /FlateDecode >> +stream +xœå[ËÊä¶Þô;x} ©$K„}…³ üo0IIH6yý#ÉUR•,»Ý=!ÂÐL_d©TõÕWéÿý¤ÿéA»1@|÷åëé×Óåãôù†0 ?—Ó4ªy0>ûøzR£²|¾WJÙøšâËÅ—¯9¾Â‡_NF;Ä >~â#`Ë#&¾Îñu‰¯+~¾áwü¼=­›ãúu^íż|–æˆÏi…ÿëe= 8_\_ÇqÇë)ÏO»†(ÜpÙöwi±™ÓLÏâAãÕ(Õ¥4=”% ,”…trC½ÜpÌÌÆ\PÎøÌUgi;¤+PBl´E¡.“‡~話¹ a4ÀÕ0üyŠïÿ8)šaQ˜JßuP£Ì8ÁóÅëøyœœo +f îÝØ<þþq:™ÑÙÁΣëÜèæ!ÚÇÃðÇO§ŸÿS¬mË +Ì~rãl‹Y œõyÑ¥žQ箾ז”¥† ×›ÖÌ8mšµZ¬išÑšp^,ê{õÒ:kH.bŠJ=ÂybpÂEµgîdpk]Èe&·jÝz«:˜±Ù*”­jt¸ìtäØß»eE¾»í("l«MW–0¸©°h f¶Ô¿.›M¾½|6ø9?sÆqÈA鹄³ô*Ü”ã™2:F·.顤*”&ÇUq’©  7´t­ÂÈæ&Ÿ3ª„ËŽP†E Tݼ`"¾$…¾ÓJÕfJy)>]æ÷vq16A\"ÒLª÷å@•ÝÑÖñpÆñHêúþÔ¡¬Íë# +XZ ñœÝÓ,oɱZGË:¿à÷äæ¡þF¾’}çËΨQòPá ù„Lžû‚Ú|àÜiØ0x^{rÊä£uwgî»æJ}Þ‘˸1†g±Nõh²fÙÿ•é]K“‡?ªû!,àïE‡2DÁ4êv“bÉ.9f2…í3f|ä³7(xbè>Yʵ€Ò@Bkë]È®LIôÝÚZç˜)¨Ä·kò]sïYQ +Ã>_?RËy|á‡Å]KVs;`Èè =úÀw9H=|#(Ö° ^âN¾Ù¨3f맬­•¢àAXQlé<<ùäÐR½%Õ™U– å[5y.xµ‡·fvè€7Ü€¯¿¥¬76óÑBPŒÀ0îU?2)Á’ê)Îq´ëT”·Ç¯¦NɉÅ/왋Äû’; +”waP  )k—„+Z§Œ¿HïXælÓXÇ*‰U3Î&„Á+’’ß“çÊNuÑ0ÊŽ° +5Ù×HtÒ“8ñ­=‹ž+;¾MK¤–êй@òC›0>ãO")Ê…4ò¦f&„vœW x&Üwe½ä¼r§œÆå"GšÉ‹H}a2ø¾,³_éŠaç‚Y2áU„îÕd €Ûm*\Îa"®“Ëqéb%Ö†h¬¾DÐA¼ ü µ0¿”]‘݇[I=V§êF/$&{ö&|J‰«½Y„ÚñÐ[ùõAOHdr$_·ŠŸ—>þÁ¤ÇÄ.Bà~®s¼XEl×Xڌ¥n ¨PÊ$Ô4ul¨´–àÛ­ ²ÅbBãG°š_•ÈØ+W³M û~‹Y)ì#:€Â¼¨z®1ëT¬RfW× ÞÁ´®ÜrPmLn¹ñ…k9»Ò&¬/Ö;d/9îzlGk`B¢¦ºh‚¶ë³üò OÉ~'‹î™››2—\ÔÕ`•E/ËŒ &™v!Â]ÛmÙö›ÎZÊS|`VR±ý¬áèBŠ}hL8‚ŠËkÇà,ã%lÞ“C" j/ö¥äq%X5â•=Œi{îÿ<¤X«ÖÍkÄ9Åú¥@ZUS‘BN(Õ ˆ> µß4D<&ˆÒ¶a\—[¹kÁdin&Í¥¾ÎÔünGãänÞj&`ipÁ†!ú†~ˌƪu¢K´‹™†±ãòº½&”x°etè`gFÚ$A®H={ )F“äiàhãnÏÜ=î)ÝažF£´dºÖ?-Í×Ë7ޤÐGæ!¨c`AŽË$`Ú$^YÅR¡/W0ÓœC?Ÿ¤†Ú®õN¡‡xÓÀ!-ÒM–÷×p-æ˜U–©ÎA$|–òÌr©Ú#–dås†ëy¥H­[™©YßÔ= rÝÃd= ½S«­T¦ ç¼Póøù¬62_‰ÂBJlòÏB^·#dÁ²Ó«‚­ê¡î_¿Qr5³›IR÷©­Lþìrdß‘8à€«‰Œ +©¯!'šzI?7rÑ@'7n5²KhôlÈÔ€|7"Btj»çô‘¯bøbÃÞtú9¤ru½\ãóaJ•ŽXΈ²W-\+%Þkñ¥¬~ÞgàÅË~f#L›•÷ ¶­làé뢊o<Õ! ºxЉ<×,}“›†ˆI]¡z_ƒîÞ¬Zżµ‹çx d—tÏ&.aô).¢jwË·¸È‰¹>iÔ.Z\.ÙìÙ?Æ+×.±ÛŸiœxóÚÒ, ‡eÔ’ãwŽqÚóäÜìˆ}µÌmÀûäµb’Zx¼Liû9‹±¹Äëó—±> .Ô[fbôñ½3s>?–ª|;k©J‰í¦{ =â7>UÌ-?ýC2"êÑá‘ò‰«Þ™roHóÌ}s³d?Mrlý^Ñ„ÆÍû;PQÇ­t6üÎܽހC¢a¾¯vH§xK¯’Ønö²ÜĘÒkÔ—«íéà×> +/XObject << /Im184 874 0 R >> +>> +/Annots 646 0 R +/Contents [644 0 R] +>> +endobj +644 0 obj +<< /Length 645 0 R /Filter /FlateDecode >> +stream +xœ½\ÛŽä¶}_ ÿ¡Ÿ¬–¤(J‚}™6ò˜`€|ÀÚ`x_òû!©*òEJêžµ±ôL7EëzêíßOú¬ü?}Ö®›ÿíë·Óo§ëûéËc>Ïçóû¯iÄ0tj:÷c÷þí¤:Õ[?àëù¯J™«R½ùÛùý?i¸:íÄp=ópÕ‡Ÿ8üËCÅB£*Òæü¿“ÿýûIñC|X…÷֒޶3ÓþÒiøÜõF W:mìá‡OþÙ¿Þüëuù;Nsñ?wÿs]^㘠Æ\—qÚ?g&ëüï*l€¢ôf謲X“D·ù95Òs|ÞÌ·…WÇÏgÿˆ±b·åF“êþnOë&¿~žWI->èYž#l]Ñ«&u™¬ +TAãµ_O;Z7È1ÅõÞÞ½ó }çìÙNÎÖ¹ÎMçϪÍùû/§_ÿ’½SÛ(ÜÊCÇÁu“%í-´w'ëÜ1Ì-.kmpÕ¬¾>=Ö¼³¯ªóÜÍ®¶j?ÁªÏ /4Ã…Ö/JÖ¤„¨ŒžŒs[be cpü$•ÎF¥yô†£yÍi¢_üÒèìÉÈü÷d ¹’qi¾h(ÐZØKôõƒsE\v‚8.ȹ1G\—å¾-Ÿ™qº¤{£»Áq¨'=Y^Çe°>„Þ/êí±è¢Ÿá½}ѵ ã Ís‘~mÏ2\iLá“Wæ%S¶ÐsÎK,ç æu [ÅoÌ-ÿm,í¤|{‡gЧ¯9i»h¶gÕ>5?Ñ!Ÿ²üC’ÿ€]ìÀþçÿƒ½j´ûÖ@²rñ))³q,âÍ‘OþÉ>ˆÏ醜†óç.öÏAêäGç—vn€|Ûò7O¡¼”¹"Õñ™dt47Ú ò7ûdxI~ì +=¢þ$»¥uÙ¯à?凟 ö Ø’ìÉ9°iãö´J>×¹7ä~zŸÂf¶B”FK‰ç#c ‘RRò<–üÈq¦X$fin–¹£÷x,;uÃ\Rb)œ–ƒÃ0H­ŒÁ¹é¸GÌËÆOˆoˉ(˜±f7g•ý`¯ÐG\A‡äÉîi×®CžÓp¡€2PÔãs$ó"#ÁKëÖðÒ KàÖûº#ðæüÈnÃ5ö®¶¬™ç€a î~P° +èè |ÝAj …Y¤C†a¿º³?[kååÈs³0½l•´ïX}NÈðm‹Vñ«i† oÙó¢ªFxßÉÏbïr§×ž^éùôž¢j•ú&ýFÊš[= }§Éø)i+À c–Í}ÔuÃ\“ë#'Ó©áX*Œ]Îw³ZÇê©qÑ^²ÁTÛQFˆ&%»©½x­*E§»JA¼#ÍØB¹ä¡œF™(ëlÙP™ð²ðCš0†ûLÛ~™M¥"5Ä“ ÕÞè\©3Ý0|py+$ÀBļç¤# +CË)F +ÎkÅQZƯ Á”pkÈFÆâ¤ yŠN l_ÙtèO=ÍI᜺‚¢;áægCÒœ9A>ÍŽ}ƒ°ç½ð.°W,hœÜ£\•BfgxÒ†Íù °Ûb‰Ýb¥˜o&F`sŸØ§Fêˆôºš‹mÉá&ç‹©øš÷–üvȶÕEGjL`í¤"sD'ÄÒÀ–®DQna+sFåúµV6¹¶šóŒ±\/e7ïy Ê8~Éë $:7ÞîMeô΀Å*™ŸwØ‘Ô_‹íÜr¡@&%ùÉòûë“ùGK[Ý2à¥) õ·˜Ek]7²â=hJÉ?¦ˆÅR}®8i³S~2Ä,k»Ë/Z3ÑÚˆv‘o±ùj¢(èH4xJŒ¬L4î°¼psѵNTÿFÑ…€ŒÙ„b® a2l"gƒE›qÌPÌÍü£"ôºÍ[´üýßôË?Ê9ÆÆR.Uoq;=Ó!‘2ÇfCöl炷؉8nuÒü´pÝIßO…#èqUþ+Y'†-f3.¤P‹Êú(ÁbõØ™ +É6çP7\..y­DnrO»Û£/­Hp®#NÂæ$ÇøRZ%ÿfé”GÈДž´m¥ˆ~ŽP‹˜ÃN-±)Ó·D3ŽÁ'aN2“0ó4tF®¥{Ñ}T(3Ãɘ‹˜oj”qþœ•j.Ïš ” +Ï«i%:’#‚¯Âš*c’¿æ}Z.¤L·!–(-ï÷ÍŒôÞO%ŠûiÊT?œû}€še¿Ï@É>ÐñH*ÎÂJz±N0‡’ +(=Í¥Æ\ôªe¾Ÿ‹(§V‰èxåüåùS¢)[sø„¦¯ /¤M©?!¬KNU«”ÞèØY‡«9‹ÏªÂ©·À/ľßÐ!rìmE¶-=PIÁhGé ño.IˆJÑî¥þa<ÛÁÒÌG|.ÑbÊͳ4ís{]N½=ø¨j2©¸´‹¡M>„–$ŸÄÙ5¯pC‚+Ò¼Ó(¿Ÿv×€®«S´Va®õÐÎ…!t`ô(ÒÄþ›C x®ÌåA$¬‹Ýù¨ÒEÌ*òäz¢Zïæ>—µE‰ë=²LÑ3Xp C|GÞSÊ@=:Ý=tàmGPI…!_1"źBÖ‡ZŸ”Í +ïeyà÷bÞ/ÏÝÊZk{ø<……A€R¿x²Š`åza°Æ íÆ;r·ásq,ïÁ<­8’òÈ’cUŒ^Α¶Ú×MÍ¿®ÐÕûg·(ë«\)èÉÀõæú–Êo¬Y[<6aMP£LDQ¥ \CQö½Kzˆ_ƒ%[,–±…d®ì\·*ýæ#X³/µ·§›ÿg~.d÷Æ^vPQ›ˆ«„²5œ¹7`öðz3÷íÜEþŠë™iä{<߯+b‚Ù ‚P?¬ëýˆZ×{G#³Ò) þŽ'/Î[áñ¶Jù/vx{“ñù¤R'¸Ùú>Óƒo¹Ñz ¢>;Òm ÒKŽx‹óÝ+ÃÏ„Dõ»$[¤ßU†üY­Ñ@¼x,ÊñdC9–."”G@÷°‘樶&˜f•‰·âÑww§ýòJ¤’ßgÙd¢ÔS¸ç@Œ™!—nù%å2´8,X›Ã‰C’C è;©üÍa +-ÍaÉÜÝü¢ƒ±t€äPë£=󸃡æöB­¬€tx‰‹Ó|«Éå,¼‰{ŠþY‘#}­åcí5ø#Ò} %”ÇîÏÈѰ+ãC¶³¤ŸâÓ½ÔNÑÅÚ qùœ;Ú-¡(¯UsùžL‹Úg–FÑÏ š FºðtÉû Âù…ÃÖœD™*´)X(»ZK.Ùð%äÙ$hjdù´*‰x4.ßõ!C¦oN¸æ*ÏÉú—Úa®£Ååq7h ¯ÞÞO¿‡ÿCüš•s±y5ΆÃùÏÚ÷²¾x~ÿåü¯óoaØ'ÿÉb·å“å©ÁÎáðë·O_þþMû·ïÿýôSø÷‘ +endstream +endobj +645 0 obj +3274 +endobj +646 0 obj +[ +647 0 R +] +endobj +647 0 obj +<< +/Type /Annot /Subtype /Link /Rect [357.75 437.90 412.50 425.65] /H /N /Border [0 0 0] /F 4 /Dest [590 0 R /XYZ 119.25 614.90 0 ] >> +endobj +648 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Annots 651 0 R +/Contents [649 0 R] +>> +endobj +649 0 obj +<< /Length 650 0 R /Filter /FlateDecode >> +stream +xœÍ\Ynô¸>ïÐÏþn¢$ Ћ{žø“L€ ó’뇤X«JjµíÁÀóÛn‘,ÖúÕ"ÿëÍŸ\ùÏŸ|>Ï¡|÷Ëooÿ|»~¼ýô˜Oóéôñ+>1 g7âXŸûøíÍ] +å_NtÎ¥ò5”¯\¾Æò5•¯ùO§¼…ùœNeƒ¿žÊ’pI,_—òu-_·þó½oñÞÞÞ6Oå|Ú×bßG_ {”uÞõýrž}¿r¾/Ïùþ¼ÚþpëPè/Ækÿ¨‡Mp˜ÏÀJð$ÆÑ%»œ‡eáÑi™;-×N ðäÞùrïÏLì™k§³¬ ñ¬^xœ %ͩȀ“âgÁ®Øÿéá%ó4ÏçøRNÿ~+ßÿþæ`‡…a®þÎÐÏCx~8=?‡,ž¨3¡Ü=,òÿ(z:ÄsN§4ÓtJ9Ÿót*òÃé÷¿½ýú¦Èç9º,¤…~]üìÒ7.FÙ®ÉHKÇþìmÙ'Tq$2¶OÛ>ïwn¼¸ö=V¼TŽjh‚—BGµËô1 ð‘z¡ï›ž]úzÐE-¾.pS +¡ÎCZæemcÀƒû£íjÿÏ´>°½²”¥x¤âk:_#òx7/{„‰)ˆ¡ÔíßÜyÅ…üè{dâ-(ºïÊÊr»Ï'ŸZ4\{87œC‚¸2Æ-p9™±çîD ò$ßÏ@ü÷lw²‘§±ŽÎ< ÕáÖ…=“×K·S¯ýD&(ËRš2ƒeuᢀº`¸ÒÕsš""dì_¹?s_ï + ¡:ð8jDœ0NU$'0äÔðáb€¢./ò×r0‘wä6q¹Õswd—âtŽY’ìH…@÷ý‹§¢A«@à@ˆ\Ú_š¢Z-à—}UÂó8œÁ1:ÚâŽLñ<Ɉ–Öz‘¼xî1”unÊ™r +¯´V:*¹Ç©[¢1ŒŒŽ+…2z^†‘1T¼&˜µ's\7œŸÄºàÑä!±„Ë5tÙ|:ySAZtèWQ@‡[—‰"JpO­„v‡ƒ¥‹9QQƒ†wÆ% ñ«í 1ãÒùmu’/™K±~T”Ê*©þ8Éï}95Lkªš‹Ò0ø®#!ÈñMA˜ÅápæP¾ÈmG£ˆ»#˜6Ú@ÂAéô9ê s×9Ù>ࢉLD[ûÝšµÅÇ¥ %wR©=Tض‡XÈÑLWF ³» +¡æKŠÉŸa‹R<KºÉöGW«+VŸ%ÌìñØü$’>‚ð&NÎËWpÀhñ:gÄŽYˆ^xÅ#6nh4Ç‘i.RðŠ{yîÙúzßÿÞ¿ùËÏ$¹¹¥âV“¶S`£D¼Û¾9>¾"¨ƒZ/”jµÃc-(Ä\þ¿TÜ©²á祢@ž5DŒ:Ž„2q]•®"ø³Ò™k€Êêˆvgú \DCðÚÇÜCH¦ F¶_˜¨Uhܵ¹‹“nül®î±‚_<”_¤ú`5áAëÍdÔ‚LÊ jrH ×¿r‡Øœ-6”ø¸¡[çu³k!Ú;ràCí¶Ÿ*@,¯üÔÁvÝîA7ë_FO„0>•.õŠ–£3QÚ6ñºø,”õ îg!D!M²î`gQÌq¡cØÊÔe–^ö,ßûžE†ð4sŠgĺwF'Ÿ¨À¢E±úÍ¥ÿƒCZ;* Í›C…x‡h«s_}ukaq;7˜Í+‘+¥åëË÷i ?ƒsèÀ%–ôÏl9(Cá²ÂÚ–Ò ì‘)½è|ÄÏ@Lƒ1.|‘©Ö4Ôz-+Ã\$ÑEðªA ´¹Ü.Ž×öK}FN©ª0—´svf©¯h¸ª¡äâFáYÀbVKD8i„®Ã¶ uN]ßdÛÁ Õ|äž´Ö¶{HÕÈ¡‹Ðû@¶‡by%c—ÇêjFŠNšŒ‚ׇ2iË,!€4ÂáMÕÕvæ3×Ï5ìêè™ì=„]z¹ éãXÝ}äöò +Œ9\Á00ÝÓ|ߨR ùÉŒ<ε°L—3äÑC@`â@è`Š£hµò#»ŽR™U¨fâí8Ò'€-Ž ÌË‚(zÄÁr¼Îªº´™¥&ÙQ! ¹ÅnäXÜâî©»Ú…‡ s3–;»Ñgàº"@#Á™Ž×@$T¦@ ¶‘ʼÄDd˜ª<µºJT$‘"gQÐ5ǡ֋ÉýÙ᪞SŒ1¥‰Ðkê~lÆ/;”„pà~† +h“u¨M¹…Úuª‡æïƒét^ožcmì¼À¬Xlx Ï™U³ZÉTÑg½>€+h¤£2nÏ¡A †ÍÓ@Y Nc+=%4B“fÇу[¦˜fÖט8˜¸t!ÅÚqlJJkmâ¦F”8‚”o°hàš'»-ÊÌ1ì³à½‰¿ÑÃrÇ€.·X= Þ7j ]±XÀ0ÅlíY9¸K0nÔ'D]cWq·T«6‹×Hn&_ã7Ø,ì)o¤éCpÕchµŠw¹ŸRà,xV¢,x—íI7µé<Úø‡ì´÷i°eL`5:$V‚•Äw• äjM‚tïù8r˜Í%\ØÕ¦õ_ÉFw†ø¶KT)QAA5Wvê>h'Ùó†J–ñ÷ÕÂãg¯[Úd»’í¹Y,ÝÓöaµs;(/fWÀ0˜ˆdœìÏ ©3ßÞH¾°ŸËšè-·Sž›ÉU%Ã|·êÈÜ,1o¸Ûbyšl¥Yk‘Tãê60ÿçÄax§ºŒ'y’H¹¹tZ@>Æ„ÅÐF-7.µWÛòÝ+Ÿhd·€õ<øEÀmW™ñ®2ˆ6I ¥bõMz-Åvf¿±þšð»ÛhVYxGf=¯:£Š¸ñ3-lôò¹o5šQ|ã$ˆ³gr y5#’— LRCC ”ÏÜ’ï(¹&Cá¾&X›1ôÐêR%½‡9 +F]ºu”y®‰¯Ü×ñr[ÝÃ3訙Rcß ÌÜŒšdÙXEäõ^Ë\¾%¦Ñ½Û[³¯ëTø ïilØ©÷—2&_söUññ `bá’Ø8 6–(çH[òËÈŸ¤J]ãé(\X<ÇÄO­f@—.†iÄú¨8*àQéÚ³¢÷J£Ûà'Wï…ùªŽ4¶ÙxIžä¥uµ¡V©4…šÀzpêˆakvÓ&Ë.|£ S·Ï~¶Öõïú$f؈;ý7ÃækmjJúª¯ö1Ö:¦U¢“<õg2ý¯31–Üíˆ7#â²g³º®ÇٵŊ”YB¿‹õÌtÚ¼!°·¨üÄç { 8àcÜPSäÖl“4Ž5i»Ä#èeoâÁì ³N©ñî‡}Mv!äC3¬–Ò¢k›§jÇâäj·z\Oú8V*òü¹J™YîpOoC|š ã!`t(‹ð²8.37_Æ s²J¥TX ´ÒñrëLÌm¸²|r/ìñ´d޼ï%dÏJá ,§ôIW1=Ò*?8Jºm Ç6µÁ¥ìwõ\sþB@,î,70 ÎCÍìTÁßÕ¹ +©ÖËXÂÐYÞº%£øÞõ“ñké>óualéº5`C Y÷ŸVëYáŽ@Žvvü¨/i` ÂìˆñÚ!W~JRF ”7ë³;s¢±y(¹q9š é׬lïÃ|§ïÆËÖžR-c{£A00 )·P'9?mE +U,ÜÒÈ¡£ÅøuìøDÓ2?y[Ñ’¦0V´zëÿ¢}–Æ£Š6­xPÑòZ7¾ªh‰¨ÿ¿ŸTì(Ñ’®³]7”¨ÀSyt<¦Aê–šj‰}dÇþ± %ìrªo"ˆu¬²fA»ÿ™ö©T2ÔÌŠêÃ(o(Ìc ‰Íï¨1¨;fA1"é€?©}WÂ:¦õ.lÓh*½{†…Rj™ÒZMJ©ýu©©™c!œÓžW¦jî¯g’”Weʰ †Úâä°&y€P²€wtUù­AJ¡•O¼|°\ïÍ(˜À^½]/f^L°ÉÁ’Õ[ýƒä×jæ…oŒö žðä>ªjªÓcs&øØÚ+çöÛ¨8 TlÙcvT;Ⱦº»2^ì @~5)6_€þÛL:&zÁZ¿à|­[ÂY9JŽw†^W{³â²è½Œ6jÚköUüœeË0Êq’<äcb${ ËiôU±· ]¾û/æ­,JGœJ€ãIêȦBº˜˜5<]Ѳá~˜ÂìÁO…ï&…ô焤ÐàâB¥X¼O#ó›W’Tûž¹Éˆ³L·_ò ©Í>JŠ6âóê:µ]•bų¤{ÖuŽ[œAéöše»âjÃHµ«½Çi¬þèù‹|6úÍ«ê¶ÎçòDÂÞ2BË8{„Ë:6G×}1½/´ä!ú‚DŸMå1dÖJ÷«ÞîȾòM¶¥”`Žìš¤ªÝ;B3-ÌÆ®½´Öî*‘U5«Õ­õ:¼«á'qÀØÇèdu½ˆ¡ªìê(¨3µi+Ç—õÛþy¨JM|çཅ\é”RlVÌi"’¬>ýY]÷öÑû}७rŽ1]Ú{×@Œ³³–ìÞd[dˆ²FŸ#7ïõÇ·LäFm!7¶‘Èh?Õ +Û«Õ·¦7ÎúdgçËžíI³~7W8ˆç0ö‚†°<‚׎0ÏÐXtÇã¡6íhÒ±ŠÎ<Õf<Q:Œ{ ®ŽâÑbi:/÷=F£Àú̽Û€¤®ØÁUG;–[†¿©eÌ ô +*fO6=$[¬ŠÁÛˆ4aì¨{Ãlpô7às|1ý™&oKh÷ÏåÌÖ±žÙ¦t$¬måéei²ºgɆ‚ŽIl-í©·4‚^,vOÿ¤Çfš¶!!s¼xfÏ]íýÄà€>xK„ƒ“ ѤÏb¦ZpêŸßþŠF÷ø +endstream +endobj +650 0 obj +4042 +endobj +651 0 obj +[ +652 0 R 653 0 R +] +endobj +652 0 obj +<< +/Type /Annot /Subtype /Link /Rect [211.50 644.90 390.75 632.65] /H /N /Border [0 0 0] /F 4 /Dest [598 0 R /XYZ 454.50 764.15 0 ] >> +endobj +653 0 obj +<< +/Type /Annot /Subtype /Link /Rect [261 170.90 351 158.65] /H /N /Border [0 0 0] /F 4 /Dest [770 0 R /XYZ 76.50 269.90 0 ] >> +endobj +654 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Annots 657 0 R +/Contents [655 0 R] +>> +endobj +655 0 obj +<< /Length 656 0 R /Filter /FlateDecode >> +stream +xœ½Ùj$Éñ ôz6LoÞUÆÐÝRï³ÍüÁÚk0¬ÁóâßwFVDfDdfUKÌ ÔêÉ#î»ê?/öÕäöÕ¦Ëæò§ßþxù÷ËíûË/íu{}ýþ{]ãŬ¯~ußÿx1ãC^ðÛëŸqÁŸþòúý_uyŠ›Är»Ñrãá§,ÿåa£ºh1ê"ë^ÿû’?ÿx1t@,› |×Cº„‹[ϯ®Ë·‹wb¹±±G^¾æ/¶üûžßö¿Ë1×üó–nûï²feknû:›÷¹צüÙôY€â]¼„ ` ®‚Ú>³à[Ùï¶KæE&Çß_ó¶WåŽ#æÿž›Ö|;×H*>p/¨üm‘\®‘Â)p½Í÷Ù„÷k¹ïý{¾è/)¼†õÖ×Ò%­¯ßÌeq¯?þñòûŸ˜t^¶4Ð%™KL@¼oòB ûŒvx#™3ýö|UàÛAlREø ™‘vĤЂ„ðŒxÈw³!QïŒø}O‘•e?Ã[ü¿ˆ{ògwßïƒu \…€ ô†2ñÎüÙü.Ãé!SH–ೈ Z±Š÷[»² Brà‘~ÿXQ¢5¢EP6üöõR•‘+‚ved£;’ó­ßëH>HňÌÛþ=aI¶6ÄdüŠk|Þ…Ý‘ðlÄ­ÀJëcÚ¸Ôî$<ÊZN'. +\£ï‹BÈž\3A¨G>ããor_VPÏö‰o2»5¢W[ÄÝäÄÛ˺’ T ªÜKòýAm©×Ú"*_4]žäSYQ¬B Õ¬ÈAðŽÖ¼ËÜÙYÅŒ_œ¼owé»=É +“o{“2\ád& Ò+"ì Â4)ìAZ2%Z?–S9ûë†bà HÖ.SÖVäŠQØ7X°ÓÕ94YŒcƒ;™‚Dš¬{J(Ð6¹b¼+Ôzì6R)ÝlQ<¾¯!Û)ITdMÒqeÒ9“ +²œ?‘ócco<üBKRññ«NÃyóeg#´‚9:’2·{vë7p«MZÖ*-Ú‹Æær€ëEâÈ”,’ Si0nH¨´ÆQøyBIér%Ž—´ÐìkÍÑJ‰=㔞ä–&&Ø‘vELtÚÃåj¤Ûä®YkðÍH3Iw€"àšðŽ´Ÿ§ïÌjTWÏ].…I®ÂÙ¾ iIô¥3n3ÉN.õ¡“¿©{¯LiS‹ê´r;¼ßѾ/*…iÓ(´ =Ì¡é£<Ÿî@x‹¡[qÍýã¡×a$Ìd‰öÌÀ +Ÿ´çàò¼rw7âg\ £D~6/A†8)z- R¤v§e!)tÒ]¢ _u‹ó‡ÕSç pq¾¤I ÒÿU­Kœ ¤[Þ>ò4 XNyðº^\PÔŒ<^¤ä³jq*,“4ê$B»Ô³lIJîTM˜æ…),Ô(u9Nªg‰¿2ï’uqphvøŽ›1͛ܜ¡rªy¼#zÙ8'7.á²ò[!è5ê×Nìíê!ºaWÑZå®ÖâSÚ:°rï*^2G´|ßÉm4¯`É,™ Œ™ +£7tE}•t©‹djX†{‡©ËáÜö¦n‹’s=¦n[/SDxB´ âá7#+DCD9øhÁz|Á,%{,[»KFV¥ã»“½D÷ÄÝ)›Â/o5'pŒ³ 2WÃúÄYbWÅÔ’M +5pù>2÷6µX˜Õ?¤÷#uÖZz¨{ ˆ1Ƥ{Øê›€w•Ÿ‰.êÅڹ󛜋 +"N¸IHÏy5×>GáÐS¡jH–·î)2x;2<%YÞ[(âž_àÛºoý0‘¢˜ÍA+ ÆŸ#ERÔpÅ=¡ +€ï%&&p¼bËyWS ±ÖUßXÒ.ícÌÚÖ» ¢VËdwfslu𬴭ymwTEP3û¶Ê†Ö~8(cÖxpR•˜å—üœZ®Œ¸žç¯•ó•·\À–3 '1š1 HäZg ¨á‘$5lb‰‘cÉJW£”­ë*I¨Á-¬þ_(_k8쌙ªîJ·Dy¤»Îƒ·ïèª(]]9>ÝÚOàW¿£þ‹(Nàš+Þƒ­†ºO'\”¤íxý™µ,…ΪfNI=%:ÔÒ(°ÓJâ~¦RQ!ešcŒáí•qÄgkY1gå…–² WW­») âÕ-¯¬0"û£h@y:*JO‹ßƒ‹ª(׎þŸe—¢2ò` Sy˜¬ìH- ¬Ö ¤×UÉU9At–Fœ ª“DRZ¾µý»)ÆB´µÅVðìmš‘eKÜ[Šj»›• ®u})ÉÆl*‰1­¬•{p«²aœ•uï–ÖƒÇ.ÆZ!» ’©XVÞëºÿPч_u~o\.N]f÷yॖAijh•µµYÙ‘U L9Þ¤Le¸™l»æ5ÍBêR^Wê”ÉÒ»·&ÏGp8”kJ6‚ãSÖ]x´‘¬.³gýîƒlùXJ«PÊò›¹&jÉé ÖÕ¨×úhÒ†,°Ç¯<ô-ts;¿ +Òo¨‹ï³høÐE´›âÔTâe"׈>Dùn ³ƒqçWÈx$EE€Ç„ºÕk´[ʧ|t ËêÚõëŒ<`–÷ ÄoÂ3kÊ‘¼ó²ÎÎ…†]é>˰—%eu„ÇÊ⣒2E“‰ÔÑ”­C§M¼âÏUŸ›ÐÞ•2Aa•h\ÂäŽê¿ 1Ã]ؓĎùô„ÎêYù|ÞŽ”%¦z5uGóYàæAâI’¡D•½Ú•/Fdˆ¿U—N'—©¤o€v;wü;b˜âùú‘ød+˜új“Àó!ñ9’+mtj×Ç÷xi`¡S(Ö’ƒèe}KO@QG¬zìW•»£a/g6^%‚59£ãÈŠ)7oËÀôŽ4LiP—z²ÿ1«JñguŠ£ôŠÒÉ]¥=Œ¡xEN'ŠÊ„\c<”æÀ†ÍÓàm ¨7îìªÄ®ƒ2ÂYŠNIïçI›O­ÐONå5ïêÔ”ãPu$“ð Tþnxðç¶ ‚öQ†EÄ¢Èñ¦@&a”üœLªÌâP·Xp¥xí ­­URH…±ì…O€´R¼¢â8D5bÞ¶v¤9µŸ°‘$¬]g›4ÞÌTó÷õ]‡,ÕŽý³£{.íc®u+*¬1x0QQñN WÇÛm(UÕk`›¨hòú;¢_é w•çJl÷~–gBZº`³á³`ÖaS”§n7Ư«i@wÆÿ#<¹%[‹¤j¶l)©sªx•ïæ\K”ÚRÆÚ« ̘ I¥ú3»ãã4𭛬’¿¥Ä6‚hq– œ1 ˜2›$UhO'_ŸT¬Z9£–)wã5ÿÖ…ª‘`ù-µ +{+`œMCÅA +Å©èöÂ{EýÖ¼j-’µ¯5 +`‚(¼9ªéõbw)mså°òŠ9lYƒº„ñ˜rƒhÚü‰5mÒŠ2=¢Û>¼±®-û&Êæ@ó·ÆR{»öçáÄÑÑ<‚Û(¹OŠ©2•¥¶¶ ÖgVmñu¤t0Þ̤kdzq’8îX¦ÆNä!m·œVbZ•†W¨4Ù¦;fE–Rucg<…éLQr†Fà´+6„vi·µm<,.Æ2 €÷|ëè¥æÌ O›¬.ÕG9,äe%B‚JÉ*`_°jL8P³5H»ɶV ¥ô¬n9çʨFly‚RF‡Å-ë‚kÀŸ¸ÿ.Ý-ƒ_Oà÷k€é%E¨Î%›©K5þ]ˆÈÝØi8£Z¢¶€ÀŽo©¦£YØÍmíBÎy¦`Óv‘Û<ÒC…LµØ»ð½Ïdð³j-~tð{”еÆf7ÑÖiŽ'‡Å7/¨Ÿë(u1 +ÐèÿgÏ<™RUŸãÕ ±)ݽqG³ƒê5JnÜØŒ¥H)ÖøoĶAR¢ŽÊc TÒÄéÌ´Nð« +nÑ9íÆnž¬# P‘!ØIñ•9"FÕù¡¢Wj`»Ô M»tOÅJg#+úãQ˜Ü¥tƒ°;)ÕuÜ`•³4A°s6GsÖÃwa>Ì> >¿‚ØÙ„åDº|_›‹Ô"érUì²%–âˆ9Q!¤DªÚV5T?À6 *µÃ´Q¡C(s£’5‰ñÕtO)ZumÄ-K¯}ø&§ùgN{ .åíí$1»B£»Gá ÙJt$@ ʸ¨§`ög²Ãg ýQkÖúp â£0$ j}»­EŠÝ´’O¸$®&#Ú럊IÒÅÛŒmþþU³·=Û/8ÍOìbÙ¤ÏÈÍZFýž“±­ôl ïiYõàÅ¥-p8†}û⇿ýÊ»òÊ$‰ÿ}Ú)ûÛ“võ˜QÞ_ãö­<{»?hg^¨_÷îZ:tJ\5¡•سÎÌ ¹hã‘B¢ª‡=·R@€~ısMIe¶º¾Ÿ +—]éƒâÏÒâ'ä­æ]K´¾“Ùo‡¹¤cšFÎWÂó(r¥†ÛŽ/ÏÑ7M»1¡eÒ:•#«-`íÓT„­ënOŠuÎYžíac™{eA¦/ПˆÅè½!]¹â> ÿò$É™Ñ<7âÁÕLJ͑›Ëfh•Ë'õ¹´ä§Uk=NA²QEÃÖ¢q>õ´pÖcÊN<²9X‡²_þ­€Kô–þ±÷Þx6 E¶›Ê]ºL‹áe}bà+å_œ8'yÊùɬ¶è-PwWLùdÚ[ÈötáôHoøƒ]„ËÍFý…#Zуa†Î‹ížé´3<Ïðy8¤emøª/´ƒ.¥Aæ²M C @,þCï$„­Šõ¬XÖkMCœÎc©’syC £ˆ(âðìá”Ú<½´Î#T! &ó–ýwÉc¡h´áäÒuÿ¿òêbì¼—ïÝ>:|9›™)“q,Ê­ógà‘E'õôlÓG!•.œy´;5iJ’ìÓ§‚žm‰ÍkÒÿ¾×NÅä#½/‰Þ;‰Åôn¾H‚L#“&…xˆ¡Îœqüõå!ªU; +endstream +endobj +656 0 obj +4495 +endobj +657 0 obj +[ +658 0 R +] +endobj +658 0 obj +<< +/Type /Annot /Subtype /Link /Rect [208.50 169.15 276 162.15] /H /N /Border [0 0 0] /F 4 /Dest [767 0 R /XYZ 389.25 764.15 0 ] >> +endobj +659 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Annots 662 0 R +/Contents [660 0 R] +>> +endobj +660 0 obj +<< /Length 661 0 R /Filter /FlateDecode >> +stream +xœÝ\Én$¹ýýC t ÷L†ÒRs¶Ñ0ö00<ÿ¾dÁ$YYjÍÅhRK™d0Ö ë?/ú¢Ò?}ÑáMúé—ß^þýòúýå§{¼ÄËåû¯õ ï¯j¿Ø žûþÛ‹º*gÒ¿\þ¬”ré˧¯¾¶ôµ§¯ø—Ë÷½˜xu—´À÷¿_Ò+ÆÕWlúº¥¯×ôõ†ÿÇ%>ðÿóeÞöoëêM¬{ÇwiôžVø]—ý´ÁõÒþ:=§ñyíóútj“èO®Çþ›í´™H ¼‹í¦®’]JÓk掴D¤åi!ž¼#_Þñ™=óŠt¦÷ÌÞxÇ!^%HqÑ%pRtì²ùñŸîÚw2w1^­á¯jsùïKúù÷E+†)øÝ@k”½zóxóöü~õAÁ5üJnYJœpA?Ÿ>”u¾[ßýØ‘DZ1ûs¹]u³`]úŽKoÅïé ªDÇÇpÉ?$&7œ?‰t¥IMG§iáàY)¢rñª«ö5Òžtvdl¼œxEÀg9¤“âȵ>#gûŽBºÑÁ‹ÛÉ®p;cä±;cìG ÐùË—ïV£Nû²çòˆÆÆ«œ&%Ã= +Äxp¦½Uå“íäLñD¹wnÅÊòÉá)<­íuï7iGµ%Îå¨A›öyíØq£PÌ]Û ±Aý:^ÓdL$=#pËHBMuk6mbi±z¢dÀ²Ê]»µ›q®,ƒ‹‡ ø3é“G&œ¦á q àÈMENÊ­PÙr7ª†^IJ7$@3¢ XF#*ÿýÞžïÑPQGí@‡¸²Â\ú÷ÆÃAûffÓ™8ݶ¹jOhë×õèï3m]ÑÉMéÎøCëxäÿ^œ‹¹•¯#Ñø]S°g£5<ÈgPõ[¦ïÖ4Rrâ°Œ“›Ë¾…/ÏÌä„8ˆ'u¤Êá ÎÀÏrñêêMèÄØ&\•¹ø¦s™PþеtU™ë/¢è±˜€‘Óz: ­"`z¾¦±CÿÓ©fåíÙe¿g…hë2¬rA i Ö·³:¾: )+Ra¸ÒšÜuqõÒíú’ Têh[™`šP„7dx¶wÊ1<|< +mìàÉßu¶K¬ÈQå¿SDÚÚ»‡èsGå -jeÛÉ*º6 ß( ×ÜĆ(chm¸µ•Dž6©^¥’ã‰YÉÅ»ÍG9™†¬#{˜“Õ7’µoy[5H›Îgã +È¥ÔE¼»Ìà\GÝ,…s)ù•Ë~&ƒóqƹ Þ€{¾$%ØqüzC`¹xZƒ«Ÿ¾Dä>ëëÏ7Ñ”cu…  ¼üiök ígn/p°‚êkô > ꔬh)¿dN¾×S"Ã5– 39&¸äñ‘ 14ZícõYXò0g´êºwšéVJU2^Ì"Št(^]|Õë’w­‚þžcæi}³{Î<þ>8£ ^<¡ otÓ˜^-€eÖ³ä+¢šäÂ*ãNé©\¾ò¥K¦;¿Ž'0RˆleÆ‘7Ôõ@øâ0é, ç¶Ò*q 6—1¾*qÌ‘ñ ¿<Â(ÊàèàÍf*háÅ °”fÉïÒŒBHY_S›CÈ"ùW-'¢gCË,¾­¾óMFØLz—¡*¹Ë7qÖ÷ÆrÀYf‰,YOMüì~Y#sœ\$å5r‘æD€¯²Ø¸›Ãž­%ˆ8ËðTªw]Êû*öwXZÖ b4³ÊaûÜmVaè“ïa5á1†|6#27*¿ÍxH‡Ûð°è=,¥ZîHîá{®`A¥4– èü-·ZÐåß›’²\¬É¾:¨3ê—Š,y¯úõ:\,0Ó"-Î7AÔJÉÇçÏyXÃgØ~”²Jû(B­Ê¼¯s{”ŒdxMýÆ”‹Z+Åc®Œµ¶µ}«{}C%£ÖÚ1.òòqäBT‘ËKßdË¡êgÉ*\%/âºDzWBÜ=8¼1­¢Ž²)‰/ïrñˆ´ô_èóAÓ]U¿RÏÎSß Dâ_º®ªuy-ú*ÏT‰üÁMFE5Ï;/¹,n­^Ux: öeïf,8 +~Ï0êÇB‡Xäqèëqè 3n£sd¨³ À´X^ýpø dQ˃}azB:` ÷’¬Ò}›ëj$¹Ô>aÚW¤)†Â¿ƒ¶\¹^ÙzĵYÕî,I¬lFÊök˼]c©„t}^ \y=¨ØqW܃‰ñ놢äô£ú~‹P£zÝ ‘¹þ¬Š7,IŸ1m¨\F#·ô;(t­1»Z;kf¤Ã2Õ›•Ú€âe6|ÁËë BÈevè•€"[A¹ÐešÈ½eDÑ‘¡÷|Ï7™ks’ÀVêÓÙS-:Sõ0åQ »v s.DKBÃ1û`lçýh¬£Ë‘æ:Å0dàâ_ú…WöÌ f]qòÊ7aêIë‹BÕ]50Ã*ñ³¤@# 2”ÕǶç¨S7YûQˆšJ·ü¬Ìz§¸u +¸š¼f +F3C¹+x&п÷øwˆÕ2¸RW=é€Ù[¤ú.]VX©ó¬…—…¸jÈþ1½Jè29¯ÖøŽ«¶-{mIŠÓÂ#Ü ÉÌ·Î 9 ä¬QÍ¿±Ì¤jðÊi=„U¶L[¸väŒ[Ä©é^CNÈÖàÿ«vÓ^¼O6r«¾! Þši>¡ÒêU›¹ÄåßÝžËöCÏæU†´Õ*Æ] ô@.Öª±HM~®¦èLŽ˜m¡g§èì(Z²îÁØŽpÙƒ™ôRÜIIå²à[*‚‚¬q½wÜwÁ¿ùâf5}B/nÁ€îI®ƒŽê§ÎïôûyÙyýTfHe”¯Áæj–:㬷vN_›:ÖD`’Ý®+a]KÉACQÜ´e25AA&ÃVé¶“Z¸‘×>xQ²N\²&í}c—SS|¤5 ß~ðe4¼±È+œ3 +‚-§²½„Há ©ÇeÐ/_Ñ®©û>‚3Ì´Ÿ@Èç}W2_|+¢Èz­>¹qYè÷ÙµÞåFß„ S4ü\Þ×)Ö,M÷# 8ýhó¼­$+¯%˜dßU\§Ü »^þ{ÒÌ6C?q®›¹îr÷¥o… àøó“þvrM¦;T«û^Õ1u^ödaøÍÉMrù±F¸ ð+ɦ&$1¡Ú)(&ÙÕ9Y³å$yXv­C¨Óª‘@fG¦%4MsÊ¡ C¦8d°O„ › À Öu#mP™L¡Í~ù±’u\K¯B\,Î\ÓY¦Ù˜»j“e€+†¦a· ?Å5ìñm.©îõma–n3§Í­5Š·ÞòÇ#Ê5%yØÆþýðg6*%Ç^O˜LGt+¯Fâ–ïÖðÇÙlFßýþìÀŒùøn#°±¦ð}öœº\µKºÃ Èq\ºÝhE’¥9Yà!ØSm©Öœ°C•ÿF¿c{ÙÛWº]k4ԛڦ߄×yò.€õ¡“÷ +Ú‚{ÙL¯½Ÿ› è ƒ†ýÅúÌ¢´j5‘>«ë .Ÿ"5½ù³“Ì’Æ%KͳÐû7>ú©n]yëØÓì1")Ä–sÄþü¤»Z–í†å¢ûƒ5nszûAÝZ®•z¬‹×jWâ2¯øQ+ÜAjHsØç]4ܽ6I'ÍÝw‰ú¬…ÒÊó>ìñÀªÞÊÕ>vº’,o–RUZ©cE…ɨšÁëzž‘‚Íý|2°×&M‚…þ¯Þ¥4±VÈXŽ$ÒÅÚ€ .!4ø/Ú!ªYþ¸åà>E[AúS¥DÍ­N˜Ü³«ùv­tÆ.|i%K‚g¦ð!Å »\†A 4˜ŒKNS–°nO™¼IÃûÁSí…»{l™öÆŒ‡Æ{=JqÉÚ†=‰ƒawÖ;+ì>(]Û›±SͳæÄúó¿u@ÍÚì 8“Z£ Çîrï2÷A3ݤGˆ¦ÓÞD:æÛhopña0@Aãvú¸÷øÊÆÑÁ/Ý* ò\ÈTæó2Ô›ªý–¾óôfèô a„¡à‰‹jð´ÂÝWü¹ W~ÐÄÐê-ìB +•çZà,oýþOüáo?·Z…‘Ë´[½_ .óMô¼[J/:AÌ| =©s¹…®.@ÝÏå6zC¿ EPØ)×>ÄvëO›0P÷bÏOj¹!×Ý%? ‡Ñ_RS1*_æhÛÈ’z–â‚-Œù/ágáWc–Œ.0¹(þ¢›I•*ÕÊ»óÛzmï†ä:Y,‘=Æê¨ÖlciöY›P¡¤¤]N\W—¬ßå)>Y¥¶›@)Ö1lk¯G-£L—ÁDúA žd—3q¤ù£"“†!Ñ£#8V™Ä»¾‡î]9$ù`DáÑÍöà Ï>p"K€Ðáµ ŠÁÃèã1¡>r»Ósu%Ã|ñE2G4•Ť1˜Å;#Á¥z°ò”–nÁɼ²ÃÞUjÏ Ç´o4¢æS~:£³ÞMðó@;VT®-W’{åúáJ7ns^&7ô‚é=âíæÁÅÕŸWUDZt/¦Mæ…6ïb–ÕìñÈ¡ÚóÍw1&‰ÿáC¬4­GÞpø‰Q®È×£bÑ ;׎?Øþ¡#ãÀ/²«&.ªl>œ1A@Ý–Ä–-Ô/‡ ™“«n¨™>›au°á“~¨¾ YVxf#^4d!s£suH¹f«<ðj÷ÔK3{Ýé­í¨¶}Sµt;ðÒðù_rg¿­t›– óª}vpàþ(¯…·jÕ³ñƒŒZK̺z³OpGx>Žè)ðÇãç;|úFé“‘š‚“è °O'œe{uÎ`otRÙiVm=u¼çžÂ2k›dšËϧá:þ‚xÈßOiòÝèÃx椥 ´WIá¤_÷-×w³xþY8¸dMýëÔm½{Z»Â.<H ÅyEC8ýn’ÃÇ>+C ðÿ¨¦.´ªy?8ø¤I G¦#•Úmƒ‡ÞUi+jÖÈœW‡«wtFâ~Çpðñýå¯/ÿŽÉ,; +endstream +endobj +661 0 obj +4229 +endobj +662 0 obj +[ +663 0 R +] +endobj +663 0 obj +<< +/Type /Annot /Subtype /Link /Rect [88.50 305.90 207 293.65] /H /N /Border [0 0 0] /F 4 /Dest [778 0 R /XYZ 76.50 338.15 0 ] >> +endobj +664 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Annots 667 0 R +/Contents [665 0 R] +>> +endobj +665 0 obj +<< /Length 666 0 R /Filter /FlateDecode >> +stream +xœÕ\ÛŽä¸ ý‚þ‡z0Ý,Û@ ª«kŸÌl²l€ÌK~?¢LФL».Ól0tu·,ñÎCRîÿ¼ù“+ÿüÉça åÓ¯¿¿ýûíòííëm9-§Ó·ßÚŠqÜ|Ьûöû›\LeÁ¯§?;’sqþËéÛ¿Úò<>«å~¡å.ÂÿºüëÍÝA“ëòáôß·òùû›£ Æú°ƒŸm)ÒæûG·å˃Zî|cìV–ÏåKùú^¾^Öïë6çòÿZþ_Ö¯uÍ,Ö\Öu¾<f\›Ëg ÐgEJ ã’¢%…FzâçÜ„g,õù° EE?•GBRÜž‘”wüÉpøýþ¶y.çó¾NKñ†ÏÒÀºÃ¯ÅXDë}9Ïg<èXmçã[1¾19Ò<¤ù”rò|úâ†)œ¾ÿãí·?±uúÙ0Ïiô LTãx,ºÕlh™òTìãÝi–lÑðVØèñgm"á}Õ˜øR•W¡3’\#þ΋g.,Cø9|®ëè÷3êþ]è~Ás2êob]†Ìç´µ¤§ò}¤½èÙ(Ö_q ñDû^q¢ý/ž¯k§õ3ÐÐä‚{Ößâ³”ò<ƒ<š~/LwOcýzFžÑ/êšÉ:C¹'ê48P6ê4“NãYØ4ÙSVÏϱ¸©~œ]IlqAW"±DIbÏ«ÀµŽØ÷ÄöUˆÿ}zsPbºñG*“%NÁ­îºH¦7±Ú%½ {¤9PľàÏ:éͪªnGFAªÌõ&é%SÚ¸ÔÕ0å3»…¢µþNÐÖt:òþ"ÎÀóÈå¥IÃçpá3‚ÿqÞëúÑ¢ËÐs^¤åÞmê9H7ÐTéêh´\¸…¾ËOâ C%Ù=…R¥Þq†zø(}޼È Ê#u4Z©à&Î7²O.o…¥ð-gC¿)DÂîŒk,˜Kæ¬ï‹JÎGœ™#çÈI5„½ˆALj…"F#š´^f=kÊCXŠáá‡w~¤aȪ{C#Íh ÊðkÁ‡a š·¦'þ¸!9Ä‹~.ù¡ ÑÞˆ)°DÏtTûá:aˆ’Ÿ—ðɼuO{Rà=‹ó'¼úõ-X£Lò@çg騖ÙlhämåÐ Ó夺@BvÞhº +:G’·¢Á§i˜“$‚Î×u“/ zbƒW¾ÒGнò¤/ìdýmTá5ð"„`e'ö?f`’½§¾A¢ˆºªÄü^´¶ Ìy$Z=ê-«Š á D5¯*Ç@¹YÃÀiOi%*NpþˆÒ{IoŒ½êÓ=À"%ŸD©7ß ±ñÑÓˆkšu`3@@ |/cº«ècÕŒŸ ¢®2f˜^O£Z¾øÍr77=^Ù úð„˜TÞ'ŒGéÃý×[ÊÛbÑC·$hG(Gfj™õ¦Ÿæ¡ÛA€¬¾nj†é¸f¤´Hº» &pcŒm@ìÜÙÂ@=IÐr`Ÿ€Ú(À²Ç›Vr+O#­íy´«fHçx +\¶ÂG rã0Ï r"ÆÖÆph†T¢@`IéH½£BÒGx6Rʵç.’=òçÊó…m@F>ÒeÕÏ;úôA*hçL|öaÓÅÏT»pv¨kuŽsØÈ]Et•=å*áÑÊ@D3¤ èúYÌg\ƒ6§• T ¿ý™åpüÚô#<›DJæŽCèÕUòÏ Y‘RUÖdx/IYØ‚öîžÝKZA8.ü¼KÕkB§iØäØØÌrµ¿›d â^›BÑ“ŒV_ð÷'ÏÛÁB”Íe×-ÀMì–Æ$^¢’˜”#ÊTæ,ö”ûÆÕî(º…ð¹F]ä9„•'øêñ+ÒæX¦3•ʈê°:ÀÉuý{ÜL2ôþS3’+9“ì.R·»×‡ÐCWØÕv€S ãû?ñÃß~áÚ/ú¡£LŒ (¶ޤ>.Ô‘7]CæÚç5çà^8V€+ (\í„—ðµvÂÝ èûe툷}'_\ÈÖLJ®•ÏÁdiµe©×§p+ÚX©©=Oe':Bƒ—ÂÀ•³Ð37±ÏÏšñÙăþÝ,0&˜² x‚Ù÷Úã=_ +²=Y¨ã¿ +›Â`Z£$FYAÕÐE8‰¨#WÛê´ž4uë\îc%çGh…09G À{Š}¢caZ’xg?0xµJV³—+ŠåÌ´H§ð‚™½Zø¤ŸS¤Ï[ÞšÞvš#@Ý>Oìåi¹œÕ•¢{)9÷hªÁi²oŸ^¶ûPŠŠò Z<8r®óS2{ÊÄD:lÍ”De¶F‰”‘Šû-öÛ.ǹz¤¤ŒÇü{m±GÝ€L:­ô¤™¶Ü@ÓöªŸèT,îéaû0ЧBÓÈ»–Šë3 ÂA£O\w ªl%wÕƒjOÖ½ÆÚûf^ dŒîÁžl­Ìi=´Ñ.¡wj`!_V~»×NÝ-# Vh$]ôùf§Ôî牭䤰†üôôªöùû[‹å¥ìÔÖýE>²¦ü¾Å¸À xŸÖt¦6cd¤Ð"‹ìe\²$ä¬Öq²Yr4š'¨LµhK×cº`Ý4ŒY3'ÕÔ¸8­êJÌÌã2ļ'Ï–Ó¬Ñ ¹1@m;{ˆ]ãIü.D-çÁ]ENX6±˜ O–¾–‹À`ÌxVSJ‹³®=ÓNèTåScW‹ÇMDM™éÎÚkãNánTG5{%}QfÈ}IÚ6ýÞº¸B‘G˜âÓC¦(öB¿}.Â÷6j)}‚+Z‡"ödÃC)o;Ø·$Äkÿ¯`“-ÆEb ü4ÀD9!:]mË¢¥gÍöé½u’÷^Uän…',«)Ð$oúê==ö=Y^{Y¬ÎúãÐeeoör‚¯{5ªuÐWC›€Ò]Î Õ\›¼ì.Üá,QX‰uVZ=@7ŽT»Á£÷žÆ²é] +¦Ì|G±xBºv©¥EGÃæ6%°ldÞ˜›@¶×gZlÙaIßnÞøAë ‰@¥Æ¢³¿JÚ™ûÀÄçzX“ñ)À¤íC³íoy°ÈëWëJ¸©ñ…7Þ¹ ãŽF”#›°åVñÝõ³u_âHüî¹#\7Ñ|û½s !7tÚ݇\]«‹~#بŠBéN¢°kè´Ó™‡P7ìñ.BY|2®ß¿å´0l·¼[jt묋©=± Ï‚_Õ3Q¸Þå¼ÃÐâZ›¡¾Ð· ––Ä£'ñúW_\Væ(¹“…W­ï\¤²¬>8Mºc}1o‰‹/™_Ôæ³ _­ø£®\2:ƒ “¢&(ðQE‚Wƒ*ÛWÇåÒ„=B8ù£ƒdõ(µ1#èˆwŽj{Ô4 K.ii©.“Lµ–Œã4Ì÷•“‡îÁα/ëè@q©ýÉÏWDgˆÆzãæ ÐÅ­¯º<ª4‡ \÷š77ìf=ú(¼¨¹½RÐ×á\d/ ú¾á³æK³khñ~Ö!:ïVZG®—ë‹'JBå8â4Œ¨PûrÔcwºª-ÝÔG¾Ö,êÕ8niöêþ5Íz Amên.ªn@QZÔj=î¶&ôZæ6y1·ã”€3†j"â*¡9ù¿¹‡Mp“+»‚~×\Ì7ŠËA(T,ðß ø@qA&s8²¡é]‡¿EÚ¸l·?~½M6³àTÆÂÉÓ–3vÎ7Ò 7Dµ¹È+››òõˆ;ƒŽ¾i&YÆÕ0´œì†æQYŽ‚ê¸-NfÏ0@oɸïLì½ vâmÓÉéD%©¬ÒHžÿHwè•owâ£_ÐÕ’v/šÌK¨´õ*Û›J–,ýBûÛ8M/«ïò²/ +‡¨n×pæ u‹e“ òó;Ò<£YQg¦Þ,;zá$Ô÷QÕÎŒpÊríÁoYOÉèØ7ódC¿lgÁù¹—ÆAæŠ!VÈ­¹ZýëÚ^WI–0h×ÌVAøL½]€‰69y-cG y®YPžÆÛ›B]…å—ÌãOV[ # +À\°€Œê}hõjê¿‘ÄT¤Š«1|3Wü‘ž^ýܹ…Ð{B‰õ/©cÄàqÅ õfôyM^ôyµ”ºuªVöB ¡ÎQºþ¡ð‚ I<(¼Iö|>ÕåÔÖ|M²ZCÂÿÓ{ª¥ h¤Ú þÙ‡£‹Ù~ªñRÓ¶Í3Y †õE“›k/›<Ïk)¥‹bÕî|#4`6§Þ€Toj®ÜcDX9ùóç³'Q‡>¨n1ý•Õ)Œ…°1?$zÇ@t¬íbèÆÙÎÀ¯ÜýA®åÄü§°½ècŽÂ¦—‡ÅÛ¼}Ü|J0Kí¢)6”Œš‘ûCɼ?S‚æ¢:*äÇãç“ÂE“>îAaølMQLaäWM%ÕF²:ªËž£èÜXLÊ÷ ZKzE@Ééó”ŽKÎbìÇp2¿ ¥œWk,yH0]»ÚéêˆÈmüG¸Âù¥UFiG[þõíDŽÖ +endstream +endobj +666 0 obj +3886 +endobj +667 0 obj +[ +668 0 R 669 0 R 670 0 R +] +endobj +668 0 obj +<< +/Type /Annot /Subtype /Link /Rect [247.50 569.15 285.75 562.90] /H /N /Border [0 0 0] /F 4 /Dest [787 0 R /XYZ 98.25 444.65 0 ] >> +endobj +669 0 obj +<< +/Type /Annot /Subtype /Link /Rect [355.50 506.15 414.75 499.15] /H /N /Border [0 0 0] /F 4 /Dest [711 0 R /XYZ 506.25 763.90 0 ] >> +endobj +670 0 obj +<< +/Type /Annot /Subtype /Link /Rect [186 442.40 244.50 436.15] /H /N /Border [0 0 0] /F 4 /Dest [711 0 R /XYZ 506.25 763.90 0 ] >> +endobj +671 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Contents [672 0 R] +>> +endobj +672 0 obj +<< /Length 673 0 R /Filter /FlateDecode >> +stream +xœå\ÝŽë6~‚¼C® W–e`±€Lî˜7èÏE.°½éëW’IŠ”eÇÉLÚsÎbÌ$‘%ŠüH~¤åùßIŸUüÑgí»ÑÄ¿~úýôßÓü~úñ6žÇóùýWÑ÷ +g;¤q￟T§œ‰~:ÿK)åâ«/_C|…øÿ}~ÿídÆÎãï?Ÿã%ÆÑ%6¾¦øšãëï¯0żߞև¸~™WbÞ\‹sÄë´‚ßzYO˜/®¯ã8 ãuŸçÇ]›(Ü0mûKZ,àbÚƒ€Ià .´ƒê¤º”ÆËÌ dA–dA\A/WؘäŒ×™Pt–¶ƒº2JˆâFmÀEÑ£P—Íü龲¹ÇÎ~©6ç?Oñï?N +gX¦Òg Ô(Ûõæþâe|èz/Æ[ÂŒ‰62sÿöqÚÛλ³ gç}çÃ9Úg0ç?~9ýúY«s´¡o€yð*]bõdÕ T=”’˜ã¢Údƒpœ•g!ìNÆ¡É`žô]†;B~P¬ùó~¹–ƦëÒÞ›ÖFYPN.O=·g2Æ¿— ä&™'˜g.rç÷W檠.œÇpYpŽ±ÈŠë4õÇÿ®åïUsoB‹mÝØi¿²m–Ö1 +¸}PV´uoÐÁ“¸0x ·;~f²,Ìé™>Õ%GöÚÙ7ɈzE[öE §æ²ü¶¡èÆÙ2VÙ‚_”‡öv[ÖÈï'¦³4‡c{º-îîú£öŽ!#°·%{où$ΉóßÃÞñŇò^¤<º:SÉSBÞ¤„&gÿµrzj®Q]»%/ør–ÓÈEîm™çD]ƒ ì’÷Šé|Þ <8·—ö3^®kÌ+n3k×™EK|µP¦×)B³aò§“o¦ýÄìk£ô’MˆêGf -eݤê¬.«‘´wÝàó‚Ž2­hF‰NÒji¢®qÝKìY¿…*òRžU¦2_úˆ>çžjË]Óâí6yodnXôb C%"’>Kß'’e¯ˆjé% he’ nÑ{ž‚\`i0½»Ìªéëè&Ò{3Áë>œ}è;'à¬& g—Ø YlÙt¿–ðœò=ôUyATÂð¨Ó²þÛõVH{Ø’ÇÒ'–B9†@&ÑßB°\!¥¾IZMÐOLKÚDYB×u1~KIà9ÖîöàõÖžöÜÕ{S²šÑOm–¹TË5š ÆdW¿-^“ÆgEÖ¬1lbMƒ*Yv .X”5Ý¢©¤^—l¥µ žó‚}tü¢ýÙõ±ŠÒÙ‰ ʃ5S¦EAQ÷¨£¤‰z‰yÖ¦’‹§p[§pÃGÅŠŽèPªº1ì%£òÈŸË\ê£á/Š0ú¿=ü=ÊšŽ†LÂ÷­ÈÖ”{^ÌnXmÔLœÂnÅ„´ðY>ƒIáO(WºË³©À¦SrdáÏuýü°vo22S𔬹y]Æê ¥Vb¤Ko«8øR<‘L„êG3±Ð²~˜“‡4BS™&I­‘@OaU<ëJ°i2­X—Ç]<Ç=,uyÙu[/N¥*Î9—ÏÈXs@c©“ßÏŠZºj³pYÓXü^£RªŒñT×Ö +,óØz (Œ»ýh;I5GvMgø¨vµ»ÂçBím »™øeû€ôݰšV(…Æ[3³ +â¿Q`×! #Yƒ5™ k]²æÅáóv˜ïñÉ í5G¡ß& å¹²•d»7Ø.® DÿP ÉG„Òõ“ïuQd^À™Ä_7&Æ‚!ÍbLžTÓɳö&U¸Å°åô}Œÿ Ùù+8M·²GÂZdïò¶x|]ÀÜ-a¿}pª¡4žt“ìY(âèvâ½ñ¬+”ÈÔ#ãsÑxè.Œ˜»vúlTÔËñþÁ˜w£êÖUÌgCþ™Âõï†x¶$Ê‚­Ž¹Ì¹[ð¸Gy<²ÐÛ–K¸!”ä(nþÔã“⶯ +Ç‚M–)J¹H¥q„©0V®AÙ°®È–ùÔ]X‡%øf×Bn8B8w€v\’Åð²h¾½·(æ?ïÜí ê–Jä †© k´PÕ]¶Ö¬*‡œÉk›ä»é½B;Нa2ÅÍ9A_{È̱ÚUPŸÄ¿5˜µè¨N üeïé ÚP¦¿ ýqùR|ù—Áßk¾ªRé|UðoŸpj,IOŸ7š8{'Tš¼Gw.¾Ä´Ë¤GÈP|h.*çªiö,ëS/&«êKQCí?hò4©y„m’ž÷Ì!Qã l<±¶]}drLL}›É÷CöEôDrÅ“zãäƒZÎÑb,¿àɱ 9ÒfÀ{â.¦·:3OzxÚy6îh2¬M!©f»”eªùÁrKʱOFÒ¿7b‹AÉ0}åÕx—ƽ¨e‹;leuÔìÎþk”[°÷*ýÏL(ÓŸüÞõ–µE3Ô2Ò±Íh`4cœöõ´Šáñ[¦Lf4é×=ÊT†}„2±Å"ÿjÎT•ñc>î ®±…å\€T$®ôštéÞ–÷9M£ó@ƒ76øU©Š‘â:N—Rö´Ø§Ù¥NL/MúdûÔIK•d–ÃhÔly)jÀíѨ¸“Mb‹1d»³à†¦ ã¶6a­K·Zå2¥èTª´]&“ÃK+Ïv”G~†b:¼>«êàæv»izóé»G +ü —²Ê´nÁrÔ²}[~[øœ*ì´1·‡Íèär{ÄØD÷ýdb¼â4ÆÏ»#Ï çg¬Ú-ÜëÐIp–êãôy½ö†K®ÛŽ<«Ö*†VH©˜6^>@5ö –]ßzcï9#Q eãzÙIm9EaŠÁïé±ýl”$½*Ÿ¡’(|­UQ°çõܰ-ä‘\Nßߘ²ÙÙ1j^^å&2wáγ2U€“Ú­ó]¦o8ÄKVr·€ÃtáÅûÁ€9n}¾NTJ{§}ÀAwoY†‚ 2°Š—ô{ÙÖßÖ‘åloL·>4úi4R¦ºµØ¤‘eØGh$[L<çL4R=DÉw.ªÔ=$ž½cyFéô‘G¿ˆ&º|ø`­f}‘µ7•’ Í^úpÕð¡Wð»õëBŸ§‰™^Â4õ +_ÓÔ©­.ù*¦©ƒ.­Ö×3M¶ÜÓÔ}þ?›ø'0MÑ à‰¥ö¬ŠyQCb.kR{‘5¡è¹˜àLso$üf›q‡µÖO¨n°$ëu¥àö1dë]*%…! +·{Çr’1äˆ &!G9ÒÆk5˜¡Çè•p@ö¯$5…ä‘-Ä9ß<Åø5 +×Üú›áýÿŸ¯ŽS§'(¥ÒÙ©ç»Ä_½˜Ï·b{ÆwÈwËû¿w>ß²³±ÄmKæùÿ£ýŸÈçG{„ÎÓ¨/’íQD¼ÇäGö([9jˆDžþyÞ'ÇhÔÆ?,‚9°0æêÝgk–^/—DËúHÁJp+ +ØÏÛûé?§¿4ߨ‘ +endstream +endobj +673 0 obj +3108 +endobj +674 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Annots 677 0 R +/Contents [675 0 R] +>> +endobj +675 0 obj +<< /Length 676 0 R /Filter /FlateDecode >> +stream +xœí[ëŽë¸ ~‚¼C~X¯î¶¢@<3Ùß-æ ¶Ý¶@ÏŸ¾~E™¤HYv.“Ó.ŠÅÁœÉ$²Dñòñ#¥üëdÏ&ÿ³g›†ÙåW?ÿzúçiù<ýxÏóùüù ˆq0ÓÙ0îóדŒyÀÏç?ãüüéüùžâ`“ngn<ü”á?^mlM³uçŸòëo'CÄò°÷¶’ŽapÓí¥yøÈAßq”‘_K^šçPNøÜ¡ŒöÒÑxMãyM¹öõÜY»xåõ‘¶ó–ý.u¬Cx_Ç9ºG˜˜²Ý—æè*“£¡y"Ø#ÜÀ4ßþŽ/þòO=MCLbjÇ,(:9ߎs%ê8ÞÔø!Y&DQá“ci sñZèN‡1é)ÝØSž‡èHyg.Bqìó6B3´ƒl<‹ž$¬X à@8ZB°uÂ0# ‚ÏÁ}e‘ØMÅr¸RÐ©ÊÆq˜´Ti$©<¬~Ý€ˆ2L5úðž·’vt’f#¦3RœšËÅÄŽ [Ecx0ã±eç˜u¨2—ÿ°¨ª#õ¸hÞ·ê±Vm5Ë¢mqsK?n²Å¥öÄÊ9RÌ<¾q—ºgØ# "DzyíV‚×ðÛãûsʄޑ>|òÍrä.± +iN`5TÇÄRõpð©Òý «©E-Û&¥„âÇJú%@%0}Ø‹Pï5ñwº¤ƒH>ŽP\s1•f@·” 0!p¢Qq©*Š“ŸoBì™ä%ö爢 .û…¬ûÉ®ç S(8+Ÿý¢UãŒâ‘:i›øÚÊ|GãEB!àV6•}eìE .[¥ÇTÚ„÷od<›gÏ,JlÒ†QèlYõ2A\UzÊ(Pü! +§Jz˜–¢} ¼IßðȤ†Ç’þX0Qlƒµof@7O|ëvHB½ñ{¥i+ud¯ Ï;ðbØ S@±£C÷ØáaL«z®AsÉù#Z`©ØBSϳG?09§æÁƒQ:nZ%t’_T)žäŠùäµÌ|7ŒAŒš);L9°íÚ=\[Ö4Â@…ä5Œûkßcaþüj*~]«×t9X +H”pR£S/°™ †éÌ{?M å Z–Vâò â?•|E?Ú¦Þi‰ò|ÑËäE%¶u 1›‡FÇ™–*’÷„Œ“çóÞÈZv‡9Óè4û[’> >ç©â§\§¨Ðe—ÅÀ&&m»èÿ½ó&¬RÚ«ì ¾Ò7±ÅG¶ç£ƒf…^Æ~7’2;3¡}’æ »¾Ž¤U\¯9Q•”'¹ 'è,LóÝʾචt¹½é ý:Ùš¿gú%Éò¢Ùr~í(ô½qúæ"XfU{”“ŠA_?÷FÈgl·InQîrñݺK-L©O±—T¢š=75ô¼pÝÊ)}’KaˆÒO“f*×s‡.D60 1}ôüq>z/é4•^ËPz‰vèûÿœ¨u|!梷–x‘}áe„î+Tíw +¶Ú(hÈ­¬*s—cÕ™^ñÔ|zÂzŒ¡LAÆûI–îúØrZ#'«Ê¹ÍÅ,´•$¯æby³cÒöûïp1è0ê…–ŠmvG0+vIPyƒ’¥­"k‡Ê ªuÁìbpê±¾o?i˜ÛlhÃ-7zÄT!¢whªH¦rd)‘í +­¼ía ðV?íöü L¦‰¯[MЬIÈÅ;Aî7+DSކ—žþ©ÖÞíwïÚ»z¹#Z3XuÊ­ÿZ®¶7ÖB÷DYURŽa*Û¿p¡À‡œv{*üQÞ‚¯Mìr›§gÍk è˜ëFš°{1×$͸úwÚa¸€±’P%á ÍbO¡·XÒãF;L­wzeÑbÛ4­—f 5ί••9„rêôªSÐ(¢»ÛÌîE’³¢ba¶xOÓ£†Öxº¢1wT*¦Ï¼wtvO3žµb¡T•„¯ƒ~’Ö™Š;yøqxàžÎˆ«>ešî2Pð‡ž-Ã\zÕß³ pÀà’£óÁ¯¬×ÍkÞqHÏàf@yÿ.·®k^‚ÏÚ:_­bÑþá¨ó%'Õq%ù6C&€%?«Õ›$àr<ŽÍxQm‹Ã¤®îÉWfÔ-v1²ï݆Øñ·£ –|ý›ý°©`dg¢•·Â¾éb;*c2ÀßÛ6Ý£%n·|îœÒ<ò”ŽæTcßiü*t µ—”$7QHBÑôV)5ñ¨X’ˆÚq¥§›0Ü5gW©dÕ•:YÑ+Ê_ŸpCêÞ•R>Ñ‹Ïè*n4׈O±èÖÏʸˊ¥…‹»nŒÊ…ãæÄe'ºäCâ¦ÀÑ=#:{ÄìÓ»k´ ž¦rvÉâ«4$+7Ϻš’ 7šÚÇ!ùPÍhÊûÝû4eÇa{´ñeEMDé»JkjAxíèHv$'–_¸Öw—†üä(=M¤†n‡™Z´ ³ëž†ÔCµ¨½WCO‡˜OQ„÷ó1&5t_jA­°`ZJÿ°vž‰.œÈÀ Ó¿ö¸ù½íý²¶wÏþÞVÌ…ÇÛãÐá.¡ÕöŸÜ” ônûeý;ç¦U¥ÅZ«Ü˜ëºÇn/bÎÍ}roÂðÜ}rPîuÔ^ÕUÅêVÂTZòQÑæ +5¦eëIê¼m,Pîß _º×G ÍíÔ"›×‡Þ©ha—‹´D†­hBY}ƒõM!‘¢ê—ÏãÚÊm1º.•»Ñ ÛÍ3ÀŸX8äNÉZ°¬Rò| 8=„xQRPQ´Ô`*QÙ}ð¦D²Ê{h½N@:nŸÞY½ˆ µ XµgÃFL®†Í‡ðÀeÝ# 6ˆ úíÁ»›ë5W¹DÇ÷ØyÓÙ E‡8hfgÛAwÙ®ÍÚÚ¹,ÇâJ ¯hÍz_ŠY­Ü°Á¹GÊwY–‹>+WnTƒ=ózkÍžç…P¿ #pú!Ch2¥™ª&®÷‚œÀ4—ÍU•#›Ka €ºNÜ|£ñOò7[ûÂ~¬æÝ"#^}Íà…˜Î:éèÍ\¹ƒªö. i¯×ž»*œÇá!Ý­EçYM/ÚÿzË×ñÊNAcÊ,XÉNŒË5ÛH^2®€†:N¼èÎÞ×oâˆjì"æLȰžR†À™‰µƒͶ•(­,YÜReà0»‘”:÷gqÿp©sô»ÑÊs‹‘´˜ß´Ý¿ê\nº[öõµï3 ÖÏpãM(áà¼kGY­ÞÍZ§ç9xzv7eàÕ윭ôœ"S`ß9׺®s®•[t”ø‘ÑmàY–_T–4U¾Æ%Zȼ÷^—·Í6ÉýÖ©«- ´·=Éos¸÷cs°ßmZø¦IíÚ¯\¹X jRÌç³´+_f¶aî9ŸM¾x´\¹’œ=´ÈLS—x-vê‘ö›9꫟±~FWúø`…œEÔ(Ù Kë<Á­²::«xÍ¿:3{µ³k2àÑ™Ëýrôl:F‘™“â]&¿IÆöxR¯ð¾Åç}~Öï‚•9¡×TÕqcË[Wv_É6 ¦É(úAÔ¯"2ÉzîÙ2…ÊfR%¢°|]žuA|ÛŠÌ~p×F|ÉòÉFMs#Ñ4S#´á󹂚‚W@[ ¶Ü&—2ú$©m“Ù-4}:K»öû%IÏ Ò]zpþ¥ªqÅ +4+”·7:=8¨TŸ=ÉLWð^)\øX>)€8ýÀn÷¼¶ÊKÚU®ŠsšÓ¦ly¦QØùêlž¹Î¸‹/”Žÿ|ú¸½s +endstream +endobj +676 0 obj +3176 +endobj +677 0 obj +[ +678 0 R 679 0 R 680 0 R 681 0 R 682 0 R +] +endobj +678 0 obj +<< +/Type /Annot /Subtype /Link /Rect [105 758.65 142.50 751.65] /H /N /Border [0 0 0] /F 4 /Dest [787 0 R /XYZ 98.25 444.65 0 ] >> +endobj +679 0 obj +<< +/Type /Annot /Subtype /Link /Rect [213 682.15 315 675.15] /H /N /Border [0 0 0] /F 4 /Dest [711 0 R /XYZ 453.75 369.65 0 ] >> +endobj +680 0 obj +<< +/Type /Annot /Subtype /Link /Rect [237.75 629.65 339.75 622.65] /H /N /Border [0 0 0] /F 4 /Dest [711 0 R /XYZ 453.75 369.65 0 ] >> +endobj +681 0 obj +<< +/Type /Annot /Subtype /Link /Rect [237.75 541.90 319.50 535.65] /H /N /Border [0 0 0] /F 4 /Dest [714 0 R /XYZ 240 478.40 0 ] >> +endobj +682 0 obj +<< +/Type /Annot /Subtype /Link /Rect [231 207.65 379.50 201.40] /H /N /Border [0 0 0] /F 4 /Dest [720 0 R /XYZ 442.50 764.15 0 ] >> +endobj +683 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Annots 686 0 R +/Contents [684 0 R] +>> +endobj +684 0 obj +<< /Length 685 0 R /Filter /FlateDecode >> +stream +xœÍZÛnä6 ý‚ù?ˆWwKÀ¢ÀÌ$³Ï-òÛ P` t_úû%J"e[v²Ý¢ŒLbŠ"©ÃCJš¿.rñGNÒÍAÅOŸ¿\þ¼Ü^/a +Óôú[•°v~Ò È½~¹ˆY>O…&>6>.>K|||ÂÓëf3E¯¿Lqˆ2uˆŽÏ5>·øÜñïgTñ‚ï«u>ÎßôÊ…é}àØ¢#Ž“Ë<ŸT¨/Î/£œDyi“þⵊöG‡«ÛO0™/“I‡‚Áž Ô‹˜y¸„,ÃÔm hË m)1yƸ<£Œ'27´3ŽS¾Å Ü)±R‚™b‚‰k@M‘…K'ñi»57!ÌZÑ¡RM_âç¯Q4ä€ øßj„ž­:ž¼ÉûÙ:&¯+f”!Iþå5âÔêÙ™ÉøÙøÉ87;?ÅõYÔôõ×Ëo? ÏÁm`yqæB«À¼q¿é…TiJ2êÖ/\Nkˆ/3D銮°O6Üh@ÿw4¼M06¼Ê¹·-S•…õGS—÷™Ú™ÑlˆbHI± 0Uœj¦Œªrד`c"½³ÌÞì9´¾›€Tè/2ˆôí3Ä\W®(ßop^EQe6œ7·NÎÏnè˜Ò² ck£BI Ü‘ô.:cî[‰/k ÌûÁÜ­¥è”£^+:9 nSDMÀ4Ú/Õ†í.ˆù{ÕoªYúeº‰ý¨¼¨4[J_*uÅ6XWx_ìQ¤sË\ãbû¸$….ÿV¥ˆìÒ­3Э+Ê0 ý.g€R9"é·Å‚²a`mi­æJ‹ÍÚ{®ª€J¨ Éê¸,ºtßÉV]“‡W v' —–sAàõ ÿ.ïl“Uåý=ÏWeHWndžÇ:‘}ªsÛ>‚|šë†:¯rµÃzµ»ÈeemK…¥Ã±šè¸£îåp•¥™—Qͳ蛈ͭ1Y¯|JcØe‹HʘÎqºH™bÉŒPÔŠ´Ï˜£Ñ`f3RáÙÒoyoÃõ Ï© òð?Yà´tP¹"Ì%BÊ"l—ü.ÁˆBeRžßH:]ñÿ–v¢K³ýcØZŸêÅl›XWxí.8]¨ýØ\\d\&N6M¥Á´ñb{üH®‡n„ÔXsõ-ýîY}q8ŸS¤«_¯.Ì·^# N¹ñ@I:­à¥v×,|σ¼/<^@TÀ~<&öX'ÀSÅžXÀ`¢ð,ic@ôgA&OZ*ÜBV+ð+rŒdxè””©Þ1.A´ 4ÄïX±Z gŠI7#q9›åCƾV•‚)jÌkï]˶V¦CnTmfß)­uC9\‡™zã`J¬ºÃÎðNßð=È]w˜w Ìñ1¨§$²¼¸ñùY£bÛøzša³Œ±§À/KÏ9ľ$)Ûáî!úr:jˆ{¯bè$žN’NR<¹ž~_© 8rG*—²£ˆ­ë¢~J4¥oçÖ­î‘B¿ŠÆøc›ŒÕ©í¬ä½• Z`L6k w0ª»–òÛœ Gá ;GäX%Øè­Çï{NÚ¦ªN'8•r°žÓΊYêॼCn± €œÛw¹‹ç­ÝµŠÄ'ÕñdJº´zl²F¤},OÇüSµKÄ2aøÐ#‘bgÁ£ƒ¢[—ÜÂ#ÁzFZ¶l†¼£U£NûÞ˜Ÿ³èÛÈ1¥£”uÌE1…ÔF{*ÊyÄãȪC—Î:–%e6§³^$öG{éÜ$èqñ©;§ ørµãV)-Ø€ó lûÁ{ÝIÊ)6‰R«òN=z?Ê¥DþÚ¦#œQ.QJ'ïɤŠö’)§Š§‘ÃŒbÕ¨”¾ÿs +º´)\G¿ÏÁ¼³åÎzžƒ­É1®•ZÑeõÁØ[‰ÞÙÕYêeníR‹­û*DX,|µm =ÃÅÁ/”€–¯¿ã‡Ÿ?‘Ü p0ÈT“æúž)Ya'¬Èmhg¼ZÿÕÚgw„Ž[ëÚüš¶y'¡j˜h_N©VJ81”ZAõ”‚’¿ž"&ðíSþšJ;W1ûÍ·§uÜÿ•T³¥»/\`KÄ£Tƒ´Ô8x9nÛÎõ7NÎøð}Xßá.¾VM—õ̭‡ˆÇ‘§ +.ÎO‚ä)ÿÆ‹öìµZô¡ ½%.útk!­þî ÷0ªþ§Ë?C·â +endstream +endobj +685 0 obj +2024 +endobj +686 0 obj +[ +687 0 R +] +endobj +687 0 obj +<< +/Type /Annot /Subtype /Link /Rect [135.75 346.40 269.25 340.15] /H /N /Border [0 0 0] /F 4 /Dest [664 0 R /XYZ 419.25 402.65 0 ] >> +endobj +688 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Contents [689 0 R] +>> +endobj +689 0 obj +<< /Length 690 0 R /Filter /FlateDecode >> +stream +xœ½\ÛŽãÈ ý‚þ?mÝt‚¬vû=@ÿÁ&û`d_òû«*‘,’bɲ»'VÛu%ÉCVyþûæ/nýç/~èæ°>ýöÇÛÞ–Ï·_îóe¾\>§}ß¹éÇÜîó7×¹˜Ö¿]þî\Hëküõòùoj>ôDs?csó«4ÿåî{5ÑèÔD>\þ÷¶>ÿùæp€¾tvù³ýJÇÔ…éñÔÔ|îbÍ6÷×<Ùú>­ïù5¬Ïiû,?· üúù²>ç× ž'ø~ÓÅÐw)‰ùÍçØØn„9·þaîVy¯[þçeí’ØÑ¦~‡¿o0ÄüÝv˜Öùë¸NJê}qŒµŸwðî·ù|€ñÖù}ñä÷,¶æÍë˜Ê|Ÿ+ÀúØ é’¦.M—4 Ý0]~¸n —?ÿõöûß*£3 8&Ÿ›n¢s?CUyj?S1tãS½ÐZMé¾6š¦*R>-¶^ c•Þn’º?¾‡¢ßø­{fzzŸm®­ï.s7–€|é³­}ޏö8mk +|±¸Še9€§Çç¼Í‘Á7Â6gÃ0»oí ç*"‚û¢Àö×­]€ç€æ³ÀXæœã¼³1¬Ö¯ú1ÿ½@{0©ÒÖ[ú-ö>Ë>˜Úh=¬agÜ„^7’@ÁCbB &ôC] m|Ì“€Pܼ-èÝwî“æ'a÷u³çG좀A æ)Ÿß™=[߸K Yã°¯²ö¾îÉÚ§XøK\[€q­ʪ¬÷.¼ï‚iè87‚Ö¶·[co=³UÜßÕølRTcyðÁZçÈ¥ ‚~lè·Ÿ‹gØÂq Ûº¶ö.G5ƒÜ°<ßÿÈô§±pB;ã¸ËýÄ:”]Ï ß'?= y„!¬:çòXWDò˜·~ÑF‹1rfã#Î游NÐ×_aì™ÙÈråzíëxèD K×7œZ±‚²^Ð,\L!‡ŠM“f1© U\‹o?øöüHÔ¦g&4°¶°Uj ð/qÝ Œé¹Èùwc[eîZa·…±×ÜVÓïë˜e@V¸èƒ1ð !;”í‘Úq×R÷ÊÍÉËWúÓØzÑÂþ@l\¥Åƒ{·³n…žy¿TµÕb{üÄNð0D[¶Þ;ͪ¨Ñª¼ö =k‡ƒ{Ô¹FÏÆDˆ¡HÑ*O©¼a™^&)®ÈõRÍЊ´$?·oªßµ< @¡Ÿó`˜š¡Çþï,½»s^(mt)³S•UÂÜi¬,Ó'Í2É”û +“ÛycM½™ËËÌ æ¾ÖuQÉp|Üì5ê±)Ú‹<ÂRDÔöƒ®™¢v]Ü6™=˜2Ýå÷¬ô%SÖÒk*‹tIàxª: 6ËýÊ0ç$n¼›º8𠯓l·2ºA®ƒ…+Yô šYrV©XV“•4lå¨÷‹>–˜ÂÍw«íÉÅèìåT†Ù©ékÙ<"ÔœZ—…몃pHLþ^c‰`c<¤>¢Ü~Á†é‡ÅÞp,~ }kyZs‹=)æhú]Ž[ÄËYÿöPΖÎ|¬ Qkxa¹&!ÕŒüR¿'ó;H©†®A¹I +Œ®Èrõƒ{˜\©w…Õ7ò©\6 _¿Ë¾ Ö=c~Zëî™lšè4·þˆ …ó–n¹r/ï;—ŠY*•Ä]M(Mêu?„èÒ° ‰+ÏÝLƒ…ªü-#O?д»JTœ¶òM»¦¬”œÒ‡w+e 2­]Û%(Ÿf iÈ„5¿~wsµ «Å~e(Mõó’ÂŽÂÖÁ›Eµ4LÝ>i¢¤C‘}nRN±iŠ^óóш{Í&¾À–žeù³”êÍ|^¢ý+ì)õδ&ôþ{wí ãdd:ÞÃ~m$cUÃÁ,gAG58“•³š†Y÷8À/Ê ³„VF‰é~äÆ|ºT½†(úi¡ïÂó®¢k õ]?ìiÎÉ~Éà0^ð;IÇTŽlÄGžûQ@åù÷ +ˆ" ºVD†â”gUOá•”h–}°pUTU ïÛ ÆkÅs2RцQÔ¾R²JóT(9L3¢ɉ šLi¦±›ï‡>åC4›C×Ö,Çê ƒM_ñŒ‘#K9ŠŠf…›)æá"üsš&W+k¤£FY’u}ÜœÏåÔàµrq*2=¦L ç¨Å«Ì⻄sìt;ñcèÖÕR(Aƒm™QV;%ƒ¹)ËN† LF¡oóØ b, æ5Z§Ö |;:cœ÷™GdݤHFÙÿÙ3>¶9µØ˜°kTâ”/ ì wD‘2õìý«ª‘dG&Ç&GÑb&ú„Co«Uƒ(&Ï@›]~Ü#âñ|dû2&~îÒPÕ{‹ i«¤ã Æ š³qdýœ9Y0÷ÅRq¼†Š__ѰíŸm{'ɸÒrÜÞóㇲ:¸Ø@|F•öÖ(±æƒ4H+e×-§"ïA¡å>†Š:ݹHá'*~B8ˆ±„Y}Žó•p ÈÈÈé{í\Lp?´5ñ³³nù ±µþÎ]žSð ¹Bù^¿§#µÁíLfóòÜÆÅ«"VœUÕo›,fYwªgn/†mʹ.šCIh%#1øÌ¡~G¦p^]_Rúz¦¢œyN™+ZÇŪ–Ö…î…÷zì2Ïê`š°‡ëƾGçbÆQsP˜æõ=‡xæ4 +nPo‡ «“Š¡}rs{*„øú‚Ý‹ÍZçì—άÐÍзæÙ”ÖÝA}•Ö¢ÏÝôº…­:ÃÇØë«Ø5tæ©CvàÆjÙ¥%^_¨S«ë²íò1Ùe´/˜Å®\ [nªŸ»8 Mj¾°T•˜—±èÈÝvYÍ£ô«­Ž³áJ\>;º¨ó¢,s4¶2†0•ÕS´)wyG'ª%Xû´nkLÞëÖë^X[üÎ8!9´º35Îg¬1iòžL-t¢§“`ô ƒ1¯ª?{¬µêú£‚ÖîÔüÔþØŒ}®èDAÜEke,6ó(ùä!ùe€É_-ÍC•xØÓÅŸs^Z@È÷»Â‰ô é—)Å“½VÁeç(4µj% õPG±^§.CÄ(†û¾Ê Ó>~©Š® CbÆ`dÓŒ')ßä|Fì¾>ý‚kÇ,'ä÷°ÎºGõ¡ÊE‰Bøú +­‡îCÕ¯ôGu:5ÇdI×·4ž‰ƒØŸßË•·T:õ™4Á&ëáäÎÅÉßwŽù°Nôe4G»B]æ>)ëÖ­ï8çè0ä³çºÌO!Í3:QO²\É3ØYÏ‘áÙö}ºŸý=»(0’æ|_´’ìÊD14Ó=J:ý…¿Q·È÷†úLÄ»ÍNס¬ßñ|î¨:}úÖè× w÷qZäH£:—}F«üßZjc,R äï¼mIÏ^ö¦nªg`º»æ{䦙Ëàí‚¯ŠØ=×tãß1¾V„ý#GÉ→u +™ÕD×c\Ä"W­€ÒP~ì3ÔóÇòRʦâU¯»8ŽyÈâÁÅö¨Ñ¿l”œ”…¾`qò.Ñ3ÖcÒæÌ Jª)úk<ŽÄFÍ[™Køûò'̬v?îÄìlSœf?÷Š©ÒÖ(}Ÿµ_´3JõkyÙÎ §÷ìŠÍ=·2Š»“þªýÌ‘UJÒÿÓ‚Dr¡\‰IèD€óÕ[²˜wÉöúCþç8¹*\2“ùø|ûÇÛ_5+®* +endstream +endobj +690 0 obj +3090 +endobj +691 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Contents [692 0 R] +>> +endobj +692 0 obj +<< /Length 693 0 R /Filter /FlateDecode >> +stream +xœ•VKnÜ0 =ïàu:ú€¢Àؓ٘¤Í¢@ +4›^¿¤LJ”Ç®SBl‹©ù=èQÁŸu˜²§—·á×0߇§[ó8Þ_«…÷“J£hwÔ¤œƒ—ñ‹RÊÁò°¬+ÁÊ_ÇûÏÁäÉpÀýû.ÆU ëk†µÐû•Žx¦÷ãcC‚øí\»soäËg€ŸVô_¯ñ´¡ó ¾;MöÚ—ó9kø!ášög –8˜§ÎÑi;¥ž/]ùÒ—ÕO'%‹ØŒ°z&’®ôœh?÷ñ²›Ì&^îH±Åþé¦ý¦².Cœt¤x~Ÿ°Ò¢ðÛŽ6”‚;ÞìÓz°¶*ÃÖûç;¨Ñ—³]š\]èUˆf|ÿ1¼~b¹bVS¬hQ²Ñ— Ó'NêÑ)ë“T—Å"d*hn"(Å +¤&Ú/ʽ­JG?´Q´_ìà›Žd»¬v&*s{.g€n <[´»ÆÃâ©“,‰,“âaß!N+º …˜iq.[E‘£¥½Ø°”8™ò‰M¼ÅŽ»m`ß$qñS¹œf⪼ÏküŠéºÅ×éŠj‡Zq\;_u%jU|gâ7ÌÕ&çZϹùi®+Õ¤äèEî`cuó5<åfš@ÿÁݳô-¹—†}¯§:¥Úà#×æÃø(×Êç§Aàbÿiò°–6ì PË:oly06Éc¨}—ÅVäZ½™§.ÎúT]ú[Ä'X]2F×Û€ 'Ó‹±ˆ†‘×!_¡;…/ɺ–¤¡ÛIE¦÷f仌=Ù‚ýÊâ ûU©)Ǹ#?yó0ºŽ1\D%Nr9šÐ2Ÿ’ ý¦0p÷º¸NasY¯òòNÙ’ *Ô +{|/>yýV;{Y9á¸8M°ÈõV ‰§ˆó‚wÙWø^·?L:1iϦ‚a.Õ~£1_óQ­ôãèÝ’y*0¾>¨0\îÁ+Nœ»€ ‘äm⚥]Ÿ–±d‘ä,Ç/þ)òmø Ë8R +endstream +endobj +693 0 obj +774 +endobj +694 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Annots 697 0 R +/Contents [695 0 R] +>> +endobj +695 0 obj +<< /Length 696 0 R /Filter /FlateDecode >> +stream +xœÍ[ëŽë¶~¿ƒ8 +o¢$ (`¯×ùÝbß m +H€œ?}ý’ÔÌpfDJ¶wO[Áñzy™Ë7wî'{6é?{¶qX\úôËo§ßO×ÓO÷弜ϿҊqÌ|öS^÷ñÛÉ Æ‡´à—óŸqÁïþrþø-ã`£Xn\n|þ¿,ÿénGuÑdÔEÖÿ}JŸ¿Ÿ 0–Í&·¥t +ƒ›¯¦åËàXn,.÷6-ŸÓ×ÄdÞú–þOŸÍGø.¦ß§,®â +ïÆ!qGpDR>c\Ï(ç¦ýf)ûÝ2$'6ÿ~N[\\\€”7øùG¼3ÒÚÇÆ9Ý_Ï5R:wØ‹gdv ük×û¬ƒóÒýÖgv×õ6Ýg#Ü›é˜Ë}ï T£b8‡yó9Ä8ÄùüÍ “;ÿÇé×?UÔyÓ€Ýdâ@Ú1_¤|›·Ë4$a§ë…nš æé,¿BÏùaž™'áÛ*‚LS¦¡Ò¸ŠÞu›_êÑ…üõè‚•uÍ· ^:úq֘쇏#qkÎ˰˦¤,´ ˆTØÀt¿5psY¿s¾ŸêÚü³»n§ú]ÁÏøÍ»TÎÊ™ˆí‘ýÆö_o7f°ÏNÕ +.3 W†Q ÃEFÓÙA^³¬¿s3Ð?3ðóÆìè,@@m!mú¾=Þî꼆<ËÚq=ÏúJƒ»,÷ÌU/åîr¯pO î‘„éUß‹'Խë-Ûâ- øùìL‚ùZËdô ^ +È㑌þW:¾›êû"“s óÈÿ¨è^*~_ÎBß»Ôï„l Óõ…ñ²‘‘Ðq˜“[‘:v\u¨.I"éÑ%TŸ‡ðºW[ÏHCs¶Q ÚeŒlÍêݵÂíö*ÆW³!X‚úÆŸ¦G¨¸È3…ƒaŒ,¦“ ™úÀÞ_¬¬(¾ŒªGüÑZÐSùù¢Ü‘€o !…> + ÀÊ@WN¸¸þÉì·"¿‰Ñye< ?2\‹wÞ·÷~­›€@mr>WuIÁ}ˆ›ZBt%ƒÉ×Ú ßq†ñgfªw¼äoU¼&_t¯çò;ò÷h—é³MÀU#.‰ŠÝÒ%UÂŒ[@®{¦œ Õ¸5Òºÿ °¶0bK µf¡ÌЊlËú5ok„bí8–¹j)rRŠÚ˜Ù¸Ãþ[õMÁ›}_ӀŃ´†¬!8_êçf8_€o”îƒôª¤?¨¾/NÇú¡¾ SRz[i5?ïé”Z™¸ˆ=È{K6½”åA÷òla:TL•é{ã^þkqªè/$#®ù²l_Pj6­nŒ+×SÕ×öò€eÉP`.ë9Ít%L¡æ|Žhv7vÒzSW|i{|8õ¸oùÀ’ÔÛÜðkB{]¬ßQ~†ˆÕë:‘> ¤ª" -Do¦‹îŒz†ø¸‚‰±¤U ZB°v‚¢í6¢Ï. Lhæyo¹cR¯!7*rn{|J·à§!È»ç7ì‰Ú¥ò¼|HŸh¥9•I”•ÐG ýTM½¨ ƒ7šžhL4¢•­¨hjÖyÔxá-T­×kO”‹d¨%8nT9,Jh,M¢3&ÓÔ®•쥃,Ëç¼·]¬ÍÔîfš%,¥i<;i«ã©Ë|,§#Ÿ«ñÚìfWXu½ºòÀ.›|fÌ6'•0‹ê—×#­¢)bS᪆žð¢‹Ð†åÝ€šf o×€ßT÷u‚["LCäô†MÌ~H†µÝUÊkMÇŒ{ÓzV“6yëîv¥pïN]y8Nx óóÌÄO8 <ë‰e»¼6ÐM©eK÷s¦í³ÜOéé‘\ödÚHl°ë4†\ƒI":^Xu±MÞÁ6bäSäwVA]PûZQظå½+LhqMëG"Kâ­$ØM¥¢’„8Qî)Ï´;\œXNÐ4gjåä{ÑÏfh²æíkf-¥K+¿CP¯Ò+?G†'¦¥‡ÆgXVàè‹¿ 6ÁW‹¼?_Tžêëﱜ#!²êϱ×öGÂç墰«£ Ç¡iŸSon}ÁXÓ{Š~Ú@&OYäêª Ïa)ê5{¥°W‚/¸ór÷ª >áê +IÏH¹smer41“ÏB™{¹PÕQ478ójê< iˆ ¤¼­p©rÉkr–Ô¼ÒÛŠù½uˆ¶ß =ïXo—ÔçîG,3{Ñ.¶Ú´*c +A61à¯d„OxÀ“£“óïÀË\uõ* ©¶0'}I=ls5m·VòAüƒ©PnéÜÙú€¸ÏšŠ`Î¥nä¥u.£.Õ®‹©ã\wmÊP›K]EÎ$ ÔSô¯p¡—‘0a<“×¢›Šíß‹^ùE³Å/úh‘³_¯nùÜuÕÝÞÎkî`šMޝ‘ÿmC€ÏŠJ~xÛ¡S+¯ùDÄþÊä‰zåIã½ÀžÎÊ_ØñµìO,º9,Ï3y'áºbŽxƒ'ŽW? ÃÑåÜ@w(D&2"ݲÈv&Ù§Üe¢d<0gG½±«¡×áÄ“ÎÔ^­_t°9?—µ)}îÐA/§³†Ë–=ìû¨–®ƒýÌÓs‘y\«MÇNžý+#Xâ ž§‹4NKÄ–žË×ûBS_¦ñ?â­€¥Ó$³Î·²œ1Óy—¸Ù+ß_ úÍáÅ^;A÷º}¥Ê‚¬b˜æ›å„`ÚoE¦<¥l<¾ÛÍÞßû˜m¼®sYIMs~¦ÒQb«)ØPñ@t4%e‰ƒn ò¬QL<·µкaëï‹­â5ÖkÔÉâñ3ã÷Ó_Oÿì!Æñ +endstream +endobj +696 0 obj +2994 +endobj +697 0 obj +[ +698 0 R +] +endobj +698 0 obj +<< +/Type /Annot /Subtype /Link /Rect [213.75 495.65 260.25 489.40] /H /N /Border [0 0 0] /F 4 /Dest [566 0 R /XYZ 472.50 770.15 0 ] >> +endobj +699 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Contents [700 0 R] +>> +endobj +700 0 obj +<< /Length 701 0 R /Filter /FlateDecode >> +stream +xœÍ\ë®Ü¶~‚óû»€ÞDI€Q`uœý_Ào6¤@ó§¯_’âÜ(Wgm§Epâcó6œùæJRÿ~³7“þ³7§Í¥ß~ùýí_oû×·ŸÛm»Ý¾þŠ=æy2ëÍ/¹ß×ßßÌd‚K~¹}6Æ„ô3§Ÿ˜~–ô³¦Ÿí¯·¯¿½¹m +·4Á׿ßÒpˆO?÷ô³§Ÿ÷ú÷/uŠŸëßõiãšÖ§yí"æ}Ô±0GgMýÓëYWçKëÛÔÏÖþv.óî]¢?m·ý)/¶Âb6V3Á«œ™¶(øe6çm%&-î|eÀ^7 D¿ÏtZèä[˜f'Ö°›`„/ýzع‘fØ’\jÝí?oé÷?Þ Ìp°ÂäëàÁø)†ç‹SÿuŠ@ÑàÒ†Ý!ÙŸ¿&Îeî°Na½…óÀÄùÅÝþøÇÛ¯ˆZsÛ2“Ï0]¢ÉcZ²üZåµT~K—%ƒŠ­Ã‚í¦Ø¬ zv«PÞ+B^wÖ–¨pk…*¨ÂVû. öéï.V¨ÎõçÔ×Ìu\<ÆØ:{§53ƒ =KEW¥-O!èôDSQ‹~wûñcê¼™. 4Ü:xÜk{°ÐÇÍõÈ7远÷Uï‰Väô}¿[àÁÂöi.»Kz‘þ÷j–3h4…mJ"ne]ä&dct¯ŒÎHò—õ²ü­”ž£hz3Up‘÷ƒó/„•²ßëÎøüªx~¹ÈxÕðÿ!ÖÙ^ž_ÂN¼˜ïB~+¶^ +AºžVøñj!lu3ïæ¤˜=°fB +Ð÷ʘªœ:@’UKöªÒ† nÁÀ•\þ~? ÌEÜÓ)h°ó29Nè”4[i•lò%­ä7™qýøjp;ÑhAˆ­!ªã,/ƒè;*¶[zrKN:¼ê&hìÈMˆÈß½Àbnî´+4%wiZÔù; Tj„å7}`m»Œ~B˜ÖÎNÍCv›mVM¹WBÖÆL7hšÐ­ùÊqUYøS#6aÆBγ3 æî£á×*&”!º”í¸“í-£€õ%QG#¼¬ ý­ä¥{pv•UwÂA÷8úÚ]Ò[²¼{µ!+ã[;çž_á¥#EÊÙRÉÛ¼$†8ôÍ"’–ëf¢õü—í&Sb”%•]WЬ#¥b+‚š¥V1ÎÙdë¹UÚ@()öy6- fzYH¬R_Y)Wžj¹3‰µòZ¡Àæpž,”Ç>vÍ”Ö>Àrb5{œS^½žC$ÌÉ̽£’2e+sÂ\öd@ìê&×xÕ³¡îq݆bòÁ’«®½ÿB›€yËšJò +“ÄÝ»´¸`IŠë]`&" è­û@ºFt?z´w,ø¼úFWþϨfÜrÔçœ Zèò¢—~<ª3"ÑÄ(‹ó®cÙˆßÚz°ÚK•Wõhº´‰p]OËW(¼“ì0jÛh-ܯæ)ê^1Üyh2],«b­ß¥£G`qI×Ëñ؆åYO=î³BR`x†¨ÆVÌæ™Çjø1Ê æÚÒ{Ëœ(LK”ã¬ð m\Wøð`²š/´bJ‹Ñò»4’‹É~´ïM¿0¹Ð,•ˆœI ÌÆÙVx…Aâ/¨“aÛ¯ÓŠƒÀ‹¼º`cUŸSÕmgŒ…‡9¾¢ª{åô¨^Í0ƒØ_ð¹} +‘/&BÚÝõ,Ä,yÓ)1 GÔ56Õ¹Ŷu¦ZË ? +R  %õœÝÜuøz4r20ÌSBâ«òꊣî9ÃŽŒ 3鎊Ld•qShx-‹ŒZ +ÅàîcûéÉ<ßd82ÀŽ x™g%ZШæyR? +}_˜Nÿo†J(l/!ÔµµFþ 3Ù¨rÞ5cU? 7ÏS‰\ÍôŽ8¸‡@ïÕFž,ŠøÑ‘&æ·`4®‡êUˆÆQTáì«Q…«+‡†°OP"ØO)NŠqÐè­H¾œ–¨@=/=;_´†6Ú/=§ì,»Y…!ßRz®s”¯¦¼1o¸æ«tæh¡: ò§Ï2ZpKVG9Å7Xäõ¥»¡ØT¯ù¢ÙOSÑòúÙž^,*žªk‘”ß{™sºË ÌUx$¾¥°mBÇmvú⹄œu-G´ÚÄm"¥ °ík³Õj;1éê•ãxìÀËT Ý$l/ÄO,¦ký®8̂ذ&®g†‚/±9Ôk¾LÚœ$¹rîŽ#DT )eáD5€Åøñâ'pó•HäbAÎ7Æøã‘‰ôüÑNNî9âž³',ê[£c[Ëᨫ,,UÖyƒÄç›\ +ŸÑj•zœ½ýó-”ËÉÃÞÊ Ê§ò(Ç=kL57nK¶lµaѦ¦BVjõKœæØ´Ï®˜Seô¸µRœþHzw´Û%—]z3Ì®õ0‰e¥LÙ=)wåÖwQ~tÞŸ ñ«§ ©à)ÀònòqŸ£]E:@ttâhDB!Ñæ¼eíZÔf\@é¡€%«¥ }¼øŸ{x¡¢H‡ñ2ØöškC6ßC0ÀŠ[— +“à†yŽÿPEnóé³.ñÒ¬ +\ ò.íCq–¯ÔY§K[ofów{hÒ^í¤¹ÀØ6 èßîu É/š‹‹Ìw û4chÆè,íD“¸|ò÷ åæ}Üú-æ\nm׫¯Ð­FØ’PIDSvï ™-Ðí¡7z~à&Ñ»tÑ‹#d -rßYÌ=eþ?‡á²eÎë0<ÚUªÃ†G‡! G$×i€Bµ§ïwÐ0bþ£½áæAòõÄ'sV$LCua*&=]Žº~L§-jèh©,‰<ƒ]Rj¯“ñþ¡B,{s¬f·—°XEÖ‚wÿÒÙ“ÔñmUžWÚÜÑkÈ3šäõ¶Æ)µñnã£]…±:`|tÂxDB!ѵíàXoÆ”’Ýš kDà×5]èâ,º¡ŠIÜÇûŸž–wa|–—‹£]……:`qtÂbDB%ÑèùÀ ™-Ðí¡ÁšLP{äéA¿áNœ¾u‘Á'¢âIÎ<_òÅ*Á*"ò¹Ç¥YŃ6àPÚ‡h,_©ózº0hfów{(`p›ÃkZ”éù­Ÿ—ã¤$_Ë( ûûñ“/ 9WÅzxk-í‰Óé‡F]ŠšŸþbTé|ñ½H·ˆÌ¯wh×6¸oe'O–ÏõNkû–/ Â"caåÞld¯¹\ïàœö¨á”Úlò‰ÇyEוmÊÈ\'ÀéœÞð1qwÑ!¾!^þLȺxÒÄ(i£ÛsçšGÁ3æê%ð¡R`_x[Ñ Nðˆêô½ãs(·^‘_Ÿ¸›î#)ãÎÀ²˜ñ´¡<¨?^gpãÆªá§ûâØr– r!"AÅ(›òðE·ÊG»j–Õá`—CÃ<"¡¸fr Z+Nßï ™e:ƺ  ³1Îl/¥¶|Œ}ïÊu>ßøºdv›Õ~¤yUS‹æ0ètlûƒÌ­+Ç”NæµÖÖ‡lXˆ½tÒ;J˜»SK³š¯+gCN‡°fþ˜Qí!!/žRÛ¡ñí@2´b„f#3À~»¸ Ëòµ]Óo}xÕïÚa¤ßC +‰‘ªê)åi)ÐZqú~M¿S ]ÑtE‡#Ä=™+<%Õ~¯}=aI^²,l1#”Ož¡o$, n¦þ½{süžØµãu׆ ýãu¿8É)öDñÛï^´¨öë°tVÛUT«ÃÕG‡!ªG$¥8VÛÖ,†íy‹G»¾EmùÒªN 8:Œ ­ÔEžtÐ4×̽J^û²<Íh.o^®è:ñ"´³•¯ÈA†îÆtKfÒzØÄs¢r`"Çùr÷Ÿ „1M) XIái¬áÙŸ©hÞéÎÙÄH–žYÂ#0=»C8 +õ†Æìx0}môpQñɵ6ÇP±¸p±kºC¢ÎáE¢«Ùyÿe­Oðn1Gë4›ê½v¿¾ÙÓ7=ÖWp|¹%úöÁz²Ø!Ç)WZû[l"$[ÔWðfÖž?«Ý»“:m7Ï +Yä[/{‡3²Ïæ‘M,ßdQ¿5G%Ôï3Ü{ÓbÝÄØ\`j¶Ä ÙÞºèhþñõ1ÁP‚v>¯èèÜĘQ½–ž|­rUá5_ý&ª;._§;?|m7Ê”k,}Ë 1ÕQ>Çãèï<;þˆLR,_êÙ~¼´ÌÞf*WEm´õŸÄ¶K<¿ºàY‹p‚ãá£B»áßé]ì´ù•2xmÿtÞ*‡\¸qÿ].ˆ²WÃ[ïÄ.\þvæy»O˜Ž2Óbº×ÈÙã&õ*Žã˜gv®Åkú+®|uîwú;ãÊNÿ>ŸD•¬·tßÒ2ÃYªtÇGIDs•˜…Sâ/£WWv{Ö 2.|‡[¨°»ßÉsîvJ‰uÇÙÈœ¿…T^tÊuÆSÑJpœNî½yÕLdmƒDŒ>þð¬DøìÌË—þž}ËçIyTT òÀßò• ñÌ¿Fùÿw§¨‹½øÑ^VáõxÈ"ý~|4 ³þ:³ï'ÌW Öû^~:éTïWBŸÈë½hEs lãí´Ëa\¼s—«ÙXõj•hÐ6·ýàÜ1ZÐãÚ„¬6GaB>"k_ 8@BPÿí>ÑÕ;hQö¢Æ¸@ÕL\yàÚzSùDÁŸFMçì¨ë«7[`í ÌßàÛ¼z•—ªù!I¾ZP|jPÆà®¦a^2PHnJ19ºœIsñR¤³GÎqDÑç¥Ô¯þöö_õ„Q +endstream +endobj +701 0 obj +3811 +endobj +702 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Contents [703 0 R] +>> +endobj +703 0 obj +<< /Length 704 0 R /Filter /FlateDecode >> +stream +xœ½\ÝŽë6~‚y‡\/0®þ,ÛÀ¢@29¹_à¼Aw{±@ØÞìë×’Eê#%;NN·(3Mdýɤ|þûa/fýÏ^l·þõËoÿù¸}ÿøé±\–Ëåû¯$¶ö¾Á×ÁµÈ´$F\þò§'½,…Å=[ϯ?Á6›-˜_·<·E9¨n~ë$@·Ö‘éÄï9¤u0@°Ùb”¼U®Ê>ÿÔ€‡Uâü0·9ä=u…qû¶I[@Vw‡£ŒJLªLåé^ÜòõrºtàˆÝ4¼ÌHø™¡6?cH¢ pÞRÌpí¦B¤vÊ9.WSºä‰©Þ{VqÙÒÝYŸ’>!ZØ©îÖa#ì“€ +×ïuŒH2ˆ7ÈxB® á>©²æ Ö<Þ÷,aÍ&jÍÛ‹þÕžg€&RÞG=7l»SŠÊs^«7P¤0VÊ&ÝZ}Xæ!6œÚÙðC]Ê؈ …æx TÁ>)ÁFë=¦ U¤?›mW¸éFQ*‹U9ŽÊZ¢M¥7´,÷¬›·¬ˆFì¬ç$êMöwB½µ3‰ñ’,–+ˆšjo'=´ÍSú¥ã{ëÈëÚ»ÅÀ£ÒÁG øE©Úw!ÈÖ:îÏý.Ûm˜ê5×òЭz릥¶Wz»›ʨ8Sƈƒ¨Ô¤•«ƒ·K6Y™|„™„úFǽ’IÔÊ~ÉZJxGä*ûq‘Bõ@™NÇ­=Î\ö]º)q¯67½æÒ¤øDQs[(ã¹`5Þêç#Ñü'Õ©=a~‡¿UÖ¹]Vê‰Ò©9Öt–Ov0r\ìjr;iA;Õ_,.‘"vâ²ó‰ŽÖa +wŒž®d¨½ö!*¤ÜLÊø‡®Ÿè”·©ŽSîžTßÔœ‡®E×%^|ûÁ€üJ‹çØÅº‰@TjÝ™ÒkîðK²4¥{“ð,ñYÕC¢B¸‚iÈ-ß Úý¿vúù{µBHÙx» U\¶anŽZ g†ÓµB˜ÕD7ñR­ÌÂæšJF'Ot¥4¹¹pè" +ãŸÒ®;~º)zµy ¼äCö,vìÎêâÆÏK§t +6õÑÔàü®R,¬ +=-ÄåYÇEÜõs}˜7˲saíà¤8"&e¥SÔœ*þ¹Ï†íòŒE25UÑZ$=šÁžñ/G[™Ä¹˜| Ÿ{åRÎ;™–VÞܶ²ÈYdÒmø]álXTD3a²ÙC芶™sÁŠ! UÏîÜxï Ú¢Ðtós°íÆ»¾4“®c¬qîK3Þ"ó(DÈHÙ“úÿ‡:ÐŽ¬KR +åmDuT^Œþî¨.ƒÊ—yˆáÂ]ª4œ]Ya÷è§)h躒D¯H.ªJi }%FŒ%šF{œ%…zþÃÛ¸Þ{‡Ìë…,A4Sèù¼.ýÜ‘®)ìêl‡¾ôhÐ,qê zÕí$hÂ{TÇÈÏévxÖŸttÉ +*¨O2‚R +-)‚ ^'!3P®¨hU.‹®Ÿo[TQ¿=°Ž(žöS–Ԏܤ[SÇæ^W¨ÀR¦¢>z?òªÕ×[­@ 11N®:Då¬êvTýæ=Ó¾ +éáj§_Ät`‡x!Îr¤'ëÉÕe¶rìþöXåËréYôÏŽ“µ÷" SÚWgþÄ>5îjr§*31…Uhß*}\†¨äÑ ÎÌö‰f‰Zé|Éïèò$E’Q9ö¾¢~ÖÃJtõª6!Î`©Ó‰¾â;úQ­ÛaÆ.—ÔÅA§ +ùæÒAuJf=¦©N±Ó)‚ êâÑâÓ»bñêÜv 4Œª +ë%íM/á¨õDµVnoÿdëÃx³^žŒkH2ç²kpQëBÛù7 o\pM|'ëàÐAgk‚¥il¨kõëIRSóØ‘»ê¨º”g)ZýfC¤‹Ú”؇z 5‡ê΢²­ê}h +ê\õǬOÝùZ–:QÉZÌïèIé1~ÆoÛby#aKâǽÚWzù¦Ço(„"1DÜW÷EÖär? +¿àBY¸ô®ïQC¬( ]s¶™[ÝK€½¢"ˆ&p={6Ý·Tê‹°ª³WB!Ö×p¨QöIg˜7$qŸôÆ›±£ïÖ$V‘qëSÜØN2狼²—êm4ìŸdñM›å¸Oño"˜‚¬¼BúMS>u5È.ù5”wªA«Æ’EëW%ðPDrýÆR°§ÆÝÎ[k\Ý@'‰•%^oг;9óîÚ réöÄ|êÕF³ž¸}ß½V,^ÏQuÑ0 ²2b8Ôž»®b·vµß´¾ð~R;NÙ†©{A‹‰ µýcý¯–î6H0%Ô}.ÐÂEü˜ªàåö}*Õðxšw \~³Ž< {ë÷Íìè¨Ó/Q/M™¥/wîúÙbkuXo'ܓ✶^ÎǪ(VéÕ$ø†µº BQ~¬ÿ®€i^1`è¸~³V%C~¸ÎN×ÏÆìrq?êÞÚÕˆNÜû/Ít|ì¹ò.t*¹5U?«èSéíœn˜ŠÃU¶rêPOw)ÞµN†j“XVÃ~6…¼Þ%DêüvBD"PB-÷Z""Õôî(±EÙ%v~nÎV£J‡Å>ËMÎì§[†ÄR˜Ü£!«÷(V4”ΉîÛ Œ±Ïûþ»a=x˜ú¾ŽéæÁ: ì¤AÛtóÒ i: :wIÕˆºÆõ=„åj µ8¸§*=È2Â&Ùq¨1sêƒâYj´ïsœÉŽIß +zÛiwîtœWsq™P%¶‘¸oH„¦oðÒø×zÙ¼»WåÈ?à[¹ZC½õ;w7Ù^i~ªü—¬ûws: ð!h&Š… tOtÿ§#Ê +endstream +endobj +704 0 obj +3798 +endobj +705 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Contents [706 0 R] +>> +endobj +706 0 obj +<< /Length 707 0 R /Filter /FlateDecode >> +stream +xœÅ\ÝŽë¸ ~‚y‡\جþmE$“ܘ7Øv/ +ìÝ›¾~E™¤HZv’ÙSFœŒ,ñŸ)ùüûß\ýçO¾œ—Pï~ùíã÷ë×ÇÏå´œN_¿òˆœÏn>Å Æ}ýöáÎ.…:à—Ó_s©^¹^¥^S½æz-;}ýë#,çtª|ýãT ‰‰õºÔëZ¯~ÿÄ)îø}Ú2×õû¼~Ró>ðYš£>ç~úu=p¾º¾¯ã<Ž÷¹ÍO\‡Je˜Ùþ ›i1_@ xV¦àÎKQòr ==SpE&‰èÛÊ8Ðéi|Òk,霃ZÃ/J±ÿùá³ÑfZª^’|Ô‡Ó>êýŽfXEáà·=¸x.éùâ}ü|.Ú€"[ ÷÷6þþU-0·¹Ó|Nó)•VÉOáôÇ??~ý ™¨w§„,Éš"˜éT<³.Sx•*Þ¤õ»øÍðØÕ{é6b¸ñn9ýœçuÜ‚fqC›¾¢©˜9b>—RÛ㋞Ju%½dø$I­VsíÖüzßÌÿžÐµV²ðÆ,8×ÇâøvŸ…‹¢Å¦ŒŸ„«šõÛ|`é¥ß·y`zÍ27ErœðÌØE0ܸJhH(Ûú÷ðÀIë&%84‰«øŒ˜Á¯Æ!Fû06ˆÊÜ ¾aPy`ð!îë}¼I,ÈJ/ß´†çü¹¯Ëæ«VI šÄ‰Ä|G>×OS~ GîØeÀ°¯Ú(àïªÈpµ“ÞBRÄñ AêºióƒñÍHO\ý/f­øÊò$Ÿ÷ï£ëIâ*,2öÅšQxO£˜§/:/]xͤœŽŒû“òÁÐÿÑJ¢?Ï[gCfüÜTÖÇï¨Ö9jÞÜ£äeÏ©7q%=Ib“j²œàS?˜$…çTæiý +² dùir…“OÑ7¹Ña¸£*˜;p§³Î±ËFahÇð[(Ff‚+Ïy^ð§m¯¹$½rMK×îe$tŽ^äA Ÿ›q“ךÐnƒ9Ž´ÖMŒAî!:4+ ++S` 1õûÖh!áÝèá-m¤JêcŸ‡—ÓI<+OÃ9®Z~O¬FTQ+=Kô¯›?Í€vä£?Z{¡©8ÆI*o¨e©]!m6['¯ý;Iu¨aŠÓ´Æ<°œÑú±Ö£k-Èù)Eaâoš4]ºØ5Eþ`âÝšsËœ;Ú{ÃÔpŸö²ns2"úíI/Nc $ד‘E·ëX/c–W°Õ"D¥Ejú±¼vÜ÷¹Ò +*à9/H©ü²š!¯[\/¥ˆ7‘õÚo³{’ÞvTÿCe>Òù”:Ð*ß…³Íºg!*aÍ»qÑz“eyGÔ mk·ñÊ0Ì>yó(Îášì½QÇ]ø¹yÅ|º'ÕJ•=ð9¡"á³yë!—šÖýÆ[w!²Þ1røÜ·¢”„¸¬KTI4Ñ—ù†ÅZrq +£'é5óV„¯¬9glÅ©ç}Oœrx~G⌈ÑfëHä~St«Uë`UiÅçš8Æj‰a5Ò-¹™?ÉóS0B•£i¸L²^ÃÁbL¸•œ³™=2ª³L`>šÝ‹°¡Qò3ÐkˆkK¢BŸvkÇû:Y¨DPŒíùb@kõÀ¢tQu!,Nœý¶ÊYOV–sV“Ñ<=n*P2i.Ã^à~ʈ|é…Öu°–m«ÅíšÁ`̰¹õ}½Z¯k×t¨,ϳe]e©3CýÃ'ëG"‚ƒð/\¯­5¯ÏÕ*³)¬Ï´ñTCÃ\F¥s65A]ºqï2N "5G²ˆ ý¹ž1MàØÏ¨IòJ¹Û¸ù-æQ“;ÏiS¶9Ñ:ÚwÇ=Ôö‰÷@'šl ½Î¯]ˆAÁ¸8T<¦†4ãªRuÐjDr¡W9oKYˆ±C(vgßTÍÏ·Þr{’QËø KêSOãzË +[#Í(Üݸò!ít± E´Ü6Õ°×Âè}Ùº ꥇ`±¦¾-MÓ>®f÷^¦ÔÖžò«ØÛ÷tÀ"øÇTÌtq7„]°%(ûÙ‘©ÕÑ^U×;Ž‹¬»Å(±Æ´~Õ6J7­ýÖ¨£û"eéÌ1ñ‡åìzRög£Žwòe¤ÕÃ?é$ö–GѤŠÏš¸‡AU`m®§VÕ‰íP*gh1‰žëK¶¿e~âjE(ùÈÂ, Žª ÑHpÙõªÀ@æw ‰ª¡ ´½â+â' †•½ Y©m`}“¥Þ +«˜{¶ +ëáÞ +}h)ÑAº°ÑEr)pÆVÀ;•6•“$P'„5Ú*–¢Ircjý6'«!‰¶)C·ß4jH-ïŠEÉÜg3.mÅ¥,*Ygì4Ó7í‘Ô ›=¶ +g`ZœòåH/¦òÑnìon;¨J(=J¿–>F6ékâc!ç½ôŠãÃÔN Ô1m…uãÌé¶ÆÖW|™Z*V„…öaj·NÔnTSí27.¾Ä=lˆm›ií[›b,,Ó¹h:÷æßÙé +CÅ8ßëÓ¾É-MžË`ŽŠˆa»¥¹;^‘aCeZiÀïªß¿·OMD(,7¢cšG‡t¨Ø÷ìF×F\¶µ  šSL€Myï)þ'U!¿84KS±† Á¾Ï¥‘/n»Éå+¾Õ…ÎôMx&VŽªSeSè™ +Gi}Æ£=™t©Ñ‹{þö‘U†‡S‚(d9©^%«ÈGá1õ›£9Ôñ½£¨:Ÿû¶I/·7Ù DnòˆÎíŽ`‚ìÐ aÎ7ÒA=ò 2¸ÖiÖ ]ŽåÅúd&ê¸f“ríQ¢5¶·d'ž7hÊœÛã½s2mM‹+e‡™7 ¶FŒ†õži—{kÔŠf¦'ꃆ·(Æ/q»Û2hH¢:(Ö)—^,Ü6˜ðPÉ9qF¬Ëîª ÄÛ€Á®ÁfOàRÕÑGdv£LàwŒúYu¨õhZ¦ ŒDÊD ’;¤B¹i½çXºJ„ ECë4ÿp—ÆØ_ÿœ¶w³«£61¦©àœ"/ûÓ°#Ð}h`’q ½)ú÷/A»kDëͲ„ MA»1IöF \{زŽS>Þxxqk‰aš(Ø6 +CxÈÐpÿ^Ú~P6Fp´ 69Ê ‘¢KA‡Y.CŽ"à8|§Žµ S~5|? #5âÔÒv^ÃH °0)•i ŸGU"Ý´(áfs…éï©=X[“ðh›—ªamÍÄR0þèT€Ç±Ì“möȃ”4Šc:ïÔ4— ¯ß¶Ê7,OÐ#gQé4N hªy90‹ßÙ…÷cÄœŽ¼aT¬{ãôj;]vQD‚dÚŒÎ8¡åíÁîȸ1Lg€\˜bò0xפwNUüv»^×ÕmGçÑê,6žœœxì5P{B˜ ‹KŠ”LùÈÕŒûŒÔ>êuªþ#™hÁÉ¿oè6Ø¢tn¤òwÂ… =¦DzÝ;pÍaòºíà`r ‘1‰nÒQº´MäLF5SOf 8’í¼{¡êHÍ^µ³çÛUmŽ=+†Æ.*‚[Œ‹š#’ñq¸S¨ +$ë/WaüfÁ9èÕD+táØ<¨¹ˆ•ð$¹Xêà¤ÈˆÃr2³)ììÕÀÞ°€%i½èç­(y€)ÇRßÛÑi…—Z"Z£âZªt9½ížC»ö6ð6'nGÆFityKÈ€W§˜¬ÃNÓpã2V¤_^•9 ÛaI"mß9y“¦ã*R$¦°½='>®Cr‹ßk®Øvô&u¾íøb^:æs•¾ÌãÁ ^Pð(wSŸ¼% +Æmâ’§n<íWŽ:¥>`ŠÆÈ¨ó4î&ôvÁþbaôÄ Ò¦½A+G'£ŽË{÷RsòíÆï(F¸h†SeF÷ª²½½³?ó1á¬I¸¸üˆ¶'¯á‘Ò‚ë/ïrTQêwOÝæe ™êÉÓ•æTT¡©ß~VhªÛ›Ñtø2ÎAáøÿ°—ØÊ¦‹0Ögû9l{#¿"7¡/µ¬öìhlG´ØÄÔ ZMý¿rø1¢wrÔRH}½ÿ!µõç¢x|£Û2T2íÛnµÿ°àE2<2F2^‘ò‚ש~´í…ÆÂQZœm‡ëÂþ³1HD8 ~ÿ\©¶ª¤.ÂÈ ŸœàÜ·ƒè¾ÕÉ¡ÛëùƦ§@"÷¯¿üXÊçð +endstream +endobj +707 0 obj +3816 +endobj +708 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Contents [709 0 R] +>> +endobj +709 0 obj +<< /Length 710 0 R /Filter /FlateDecode >> +stream +xœ­VÛjÛ@ýýÃ>ºÙ½C)Xqü^ð¤íC!…楿ߙÕÌ^d¥I cIžë™3gõg±ÊàÇ*u¼z|Z~/ëu¹»U”ºþl!h“•Kdw}ZŒ6ΣÁ£úbŒ3øÍ_ÕõW3AÛ8™Û"æ›}5¿»Ø°K”Ì.‘õwÁëçÅH€P =»­4y ùõÔͼh“¹±­1‹æ¬Æ¹Þã¯MâPžŸEü¬Øû)…ƒ ½Ÿrxh%QŒ°Å¨qÑß”êE#ÆØæw….à§.N\Ê=ߟ9ÄÃPÚqؘ1kft.ì+1¨ÿvËgãa~ë¨ÝÍÞb>9/Õ±qâኤ +NG¯|Ö>+£ŽY}6:zþ±üü$¬³^]âóRðäCèqµ3㌎£Ž=Jc‹»Í¨è²=£ÂéY/6e©¹ Ì4·µ`·4CJÓÙ$ \¶Ð ·aQ¿t-”!lØÆ¦èãñ?8o÷Kqça‰1%ŠÉ,9nÿe³ƽæO[NâH½ç_‚ÀŒÏ ûÄ ‚ꓘ[¡÷2] —Ö!o콚µ×Pq(}e ÷| ‹ÜÃÊþx éfK}¢]˜p÷qZ¡Ujšüd`Þ¡û@ž`vfAã~u3\77…u s¼t>È:SÖfÐ)NY‘é’uξ©’hƒ›.’Í©‘}m +iw¢ HÓµVõ“á# Iöïe-@=ͯkA·Ò]Òëúg^{Þ ’zN²VïË$"L½©¹=͈T¤Ñ0Ð|'ïYõ61‘•0ؽ =oAÕdÒãUû0¡Š0š ÷]bEZùü?Žÿ¹ wîØX70n¤&ÌXB<–##ì¶ž:–Ât‘ç*‘§Í¼mÈÊo©cº—.ÃsnÇñ;·Êòñ9ÙvÔÿ\nÅÒ{cÛôÌ»!Kø„±ô´šCüëˆ;W©oäôÞ‚S]=ésïÉͱ5â-3m»0õø¸úy±õòrCr®Ö„]žðæÛòÀ;» +endstream +endobj +710 0 obj +780 +endobj +711 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Contents [712 0 R] +>> +endobj +712 0 obj +<< /Length 713 0 R /Filter /FlateDecode >> +stream +xœµ[IŽ+¹=î µŸÍ)™™€a@ªúÚ¨´Ý mÀ½ñõM2/H¦&W£ ”JÅ$ƒ1¾ôŸ“=›ôcÏ6N›Kï~ýýôïÓõëôËm;oçó×o¼bž'³žý’×}ý~2“ .-øõüWcLH¯9½bz-鵦×ö·ó׿Nn›Â9mðõszÄ~ħ×%½®éõQÿþ¬[ü¬o×t¾ìkµï­>K{¤ç¬©¿í~žuu¿t¾Mël]oç²?ÝÚ%úÓ…ùÚ?òa+fc%0¼ªƒw“Š_6Òs®á6àèò×JTúÛ{uá9NëJ¦ãƒ>r “Ó"²›â‹/ë¹Ù¹nØ’˜>jÝù¿§ôþfvΘüÙ@=ŒŸbx|¸¬_§¨‰õ¬y¹»–õ?¿’BÎeï°Na=‡óƒI‹;ÿñÏÓoõf ²K°yé~†±ÿ‡ X)Â<%aÂÆZ ™”¢$-)1)ʼnäd5ÚD'I‰¼ü¾'w'É­Yæ»^dåôb”÷/Œ³Íò>æ¬5çdqt#ëAà|¶»5¼íìÖjm±Ò–ofª.àêóÖ×5×Ý ðs°þvï -8S. +D“àÖf]ÈÆ«.'®ËΕ°[%æ³Óîì6bË™¹s×±ì›8òq—ýs»ÉíÊMo²Ö^»½ñÍiâ«ç,$WžåÓ +6òz"âmÕÕvªh­#þ×}ø9’È­<_oCÌë·ú¿Ø<óQÏ»Vn,‡l®:h\Š1#&bte*_H%¦ÛºÞ‘Z½ªº¤òu7²Ž®VX÷³ˆåt}Å>:£ +î0T2 ”¯ˆ¸ÒÄAEÆ¥ÞþŸ÷ >;âó´zù<ïQÞ×ûóÝ*î¼Ë` êy39 V‹”8|1ÌA>­¼v9îñÔLcü0ƒæÒu6½µÝ„Íå +‹°ÕUì/ø’Õjç³6ŒÀâÀ‡òÎŶ´7±èM¼ò ™| 2Þ,Ñ ¯ä/âör0ò׺¾²(¿ÏlpËHò‹Ïч`¶4v»0CvÄòt‘*î®;±%ö’w¢ÈIfð:TÇL»Î¶*jD8øxû[µ&[ÅŽNyu}äÀ9^¡£…pRÔ·:cRM’)ÌÈñ“×T&Afól hî]ί +ZÖâ)ØóÞ#]‰.ÿj!y¥3ÐÞ +MÌE¡›#y̖߸_k8ã^øÝ•ÝÆ~ׄÕ¸.ñ‚­·‹šnòð^•ë²ÎToÏÑï®7Å8ßµi~:Çqà”ðmrãï3àh3òWGKZg ½|ìŒÊ~žŽŒ•Â=/+‡ÇÊUJSód…¾0Œ#:&ÈA!V;×t놑V¹£*n¾Y˜ôn‹™RŽñµO°• °ñ>ÉÙê³F!ÙÍën¢Àqç0{ËI2ãk3+m­Y™MáÛ +$~TRB›{Ͷ$pïä^aµàæ˜û®e™ý)(ev[H@8¿³ŒÆ]¾ +zv)I¥2O¢Ÿˆ%¬PI-MÐuͶ«Eÿ1†Š»£„ˆbh„u7«?EdËŒGó⃠å–ã‘™ïi×aഢ̟û«Áa•Á!fµm8œE8æ0.³Cï£ð܉‚Øùâøå ò'ˆ…aB´|ÖMûÊÍ1f$XÂÈ6&öYüë +þ$lÔ§UØ~Î啽~f‡ ØÅä¼B°‹Tû=­Ùë}°)x]vÚÖpÜcŽsüÓ†EïÅ‚(,*:B¸tà:Õ°œü¶ãÉd„Ϧq"½ÀmÁuïAX+¢lR1¥ïtþÍhôA{/¢ +ÞŽP ÐæƒT.ØeZY•YüªU²‘Þ²äÔ ž%íÒÐb 9‚ʲQÔDKÜ©˜Åª«i>‹ÊTì=GêräJ®¦·2_IYáÿX¿‰²:^C™7°xAM–‘ë¬"•[Ñbv&"êÝX[OëxRÕi¤Šœõ…æYæÃHLÌ ³:ˆUå]rãq̤÷³^y(»«ó–‹ÃÒÓ²¨:ä‡8Šå#©ÔGQ­eŠ9ýö¶ŠàÒ°ªaÿкüºåå-ë‚g­+6'Ãê¹ Ê– û/ÀEE½ZS%„;¾R•œLlGi»ß·3Uba©RhÒܹvi˜îŰOìÊ6X@”Ïr%Ê}é`ú! +SS:…d®Ҡdž>Òª¤ ?DæY´™nWµÄú#`´Šª#Û¬º¼^GL Á‘Œ­"šl´•~nåd>3]DÏ'ìÝvcGƲ» ïï‰Xúùùš‘ +‹tbiX3£r7Ñ,ªwiÐiN_ƒb/hÇ,ÀÏåeÒ¦kßzJö¦°™ô†{öꇓ¼q»/qO â8°œ+«êB‹Ë8’U3Ú<¬$x;K1*ëï¤w„EsY æ¸ÚeE ï}†Oï%܆yŠÔ^o¢¨*¡kËb£‚dcPªãu„p ¡;¬[¢ãy27zt+dsäˆ$¼lv€ŽÚÆ7#­y5Iw…`§'Â2OsÔÂs÷œüCTæVL´Têáz·ÑÙ¯ÉWñ“‚¨ëæ=€®»—¢å(y­¨Ó•<ãknJmfŒ@|±‹vin¡Å²¥0på¾Ì§(8”€š^…ìZžã’q K/­†ßé&4ô…ìe4y½¶¡t;B#Í[¼Ìû8=s %|_(™ªžýµ®Axu!–ù/v6d÷9hÑtoDŽ0çS­ª#!‘ëÂàU.¤»Ä[”šYØáUVÔT”†ÞìmÏYyæ³Î2Ïâ2δ"¹§Ô%Œ˜%Q¼£fw=N:{XOù»˜Nߺc¯´ØÐ[å6O‡“¶fŠÊŽ´©lÑн.-¨+ÌÊ G8zÕôP^Â],p2]Q  }Þtáo˜¸”vÊŒ”Œ4ÀIáÃEøpÜ×Åg`÷jNCõý±8a,‘ŒäeV~¿8@Àfùq ø()0utöë³Gò qàZº8Ú¡{+ø¾¦¶Öp_&ÕEtU± Ï4Xº Ìä°ÈGüÀ\jçK-?mqX¹> +>> +/Annots 717 0 R +/Contents [715 0 R] +>> +endobj +715 0 obj +<< /Length 716 0 R /Filter /FlateDecode >> +stream +xœÕ\ÛŽã¸ý‚þ? o¢$ `·Ûûœ ÿ`“ `d^òû!©ªbU‘ºØ3™ X ÖÝM‘źžºÈÿz³“þ³‡Å¥O¿þþöÏ·ÛçÛ×ÇrY.—ÏßhÅ8f¾ø)¯ûüýÍ Æ‡´à×ËñÆþtùü-ã`£Xn\^Öû²üëÃŽê É¨ƒ¬»üû-}þöfpƒ±>“Ž~ˆáæ!Ì—ãçË3Lîòíoo¿ý•КË2,QŠ×gý˜¢ÉϬÜ#ye‚Â(˜½Øf9“ïu¥8sÅ.éçXåêÞW®–߸]âœ{wïÀ•q]Sn2ðv…gt|bƆ]'À2:&tb à:ø{Æc[˜‡®HÆ4ÐD€wT \³í~\v?ìa-{'nëI`Ž¡7 +9Ú¼_÷Bk(i)tjÕ’‹B„ÓÉ#ïÐ ^Wø8W ÈaDÀ¯ÀÂȸKtÖÝ M`ëªUtÙ¥Â=Æž3åP”j0x·ž„àg¹«ÁuW©«ÝŠÖïÌQˆ¯@ƒÈxu‚W]<ÓçJ‹râkE3¦ðTAHØ™?+G³Kµ–×øÑXfP—tB_¸°*vn.b¶OعÅd ,™:ißýRIŒ;°©îCë:±¯[ŽÃ3˜¡;v>žwTòª»§T> `‹ “ÛËÈÅ|—ëÙè…X® ;@sî^¨“ˆÁuÖö€.¦k© ëSq¹õYTY ›‹ÿ'& +ÊãZ×^–ZvÕɺ®VÀW€T®)ÚÇZZëF¥À¢ÛÐMÌ´o‡ù…Á¦9'_¬<}m^‹@€p«…{:e,yÉ’õã‹ÉNf­Ü›K&í—µ‚OÅ€±”ñiµÏ€UlÇনÈC R>îë#Ķ=kF +ôì ÌÊØÈVãsètóý8û©ªZ>ÔZ™py›ë'üÖe‚3<:æ ›]~†KÿEìÔÍz±^÷KŠ{žùXI×ÈÀoë쑎îæ*GúІ\5YÜ0ºúÌ0E©EãËêZ£ÄžÊŽ 1¤æ’€0`–r·å½øµé{Ê–Ô61 žÅòV!ÖrmîÚ¶GE H¯…¨`1q¶dº3éç îICrÉMün¶[eØTƦn0ônÊzÃجI¾¢É<-¤:¯ð +±‡g¯¦Ö·6ÒŒ`:¡}œ]¾SS‹¼­iÍ="ðR?„ùäöÝ´Pà®Ca.I¥J ºµ‰± $ê¾òdº¹ÓL™IÖ™9„w0˰£3pŒwpŒìßUŽaòÚ1òÜ…‚nº‹˜÷©æ–…¢ä¶C1M^ú´3Ç}°¤k¤<;’¢‰ûI 1_ÉÏj† “ ïé(Äö +/,@vê8wŠ~ç‚bÏHœÆØ¤O¯-’oËiÛ—2$µ.äÂJ]—µR¡ìRŠMi@¨RäZ4êÄòÿEÒ+“Fë3–”D9‘5=ÙÁÄìê¨ÃXݘrô HzÜÌ™ÚïŒªŠ“ÏBn"LAWT»øŽT]6×Ì” @ls*eu”#¤äݶuj³¡byí 6ʱÓZãáá{g&’/aZFÏ Ïv˜o][¹—c‘`KH¡7(Ü ºPºsÝØJÐv%DÊÜÂÈ—1c£Tù +MžJDÕäz{åÈ0å(ªCmQª©ÊµM9äÏʼ_€lFƒÊ‡ý¨W…%VG`UÁCæ8nZÖÍikÚåżàzç”|XTâ/¢Í°=MHÈ…ÏË%èmž˜ƒk¤C5cÇ!•zùDÓKTd4vœèÅ!t Ÿoú¶22˜XŒ‘Ó^ñ„(åqEmkQ.^ÉšÎ;AGN1++5Œ£`ø®Ïq‡Ö°}xqÝ&yìTâø"ªßQ¯IW¸A4#*üw@_–Ü*ë59˜<ȆEøžVsì6µTÑSð øH•àyPåÑ蜻§–ŸÒ.Ìò3¶=˜U¦‘µ®^RŒn§Åk¦Ü9íÎòåµ/ @ÚBGÊv§ÄOxá×Õt‚3N•ž³£ç—Ñ<7OÍ+j[ŸÖfI‘Þ#Ð7j`7³ÏC[¦mæ–@œqNç&LJ/ÅLIÀ"Ò€‘,;~ø~ï¨fÚÜ hœëËjTÝ^Ÿ)Ã1·Åß„\iW‡%¦Ø!ý‚¾÷%ï’ «3>;Õ¼­ÁA²#Ž6baíXíÃv4€ìû€+£I ðž&NsÖêÞXA_¸˜}…¸·ç6™Ó(é{eàTudœ 5È ô_·Ù 0g{*‡”-ƒ½/ÕF`Ï›k±#;Œs…·\{ZÀ£/HL¼l}p¡³.à›f9q¨Êƒ0¡ — -VН€…°+¦L¨ó* ª@Áºâí±ÐòD3` +õ•ƒLA¬mn3 <\ÆXôP˜gQR€­‹è.⻜zCËÙ¢œY†õ´áe(Çò{Q873x\aàÿÍ+öªa°äÛÔKÈF+7@F€ˆ #€S}ÈÙ%Wk½ãÄËÿ?ç¥xUX ¹1%ˆž<'šÇÊòÅR[Õë·a¶¹ª$ö{bþ¢al¬“éŒ4ƒÚ·>ó±Š4Õ(-=±Ý@Í9yÄ«ƒª4Z²RÚß@¤[啨}4A„GìÊÛã÷ñÑ_„-a—%‚P+軂ÀŠHX¶|+³,¬ÑÈBºÅKø^xõb뮢á²ßþMð;¹ÎíONcÖoFz?ˆæVH’¸¸bä>v­‰B<_¿òü×ü°bÀ™AÇŸÌ`«£k¢RðNó‹µÈYÇÉrç, iÃë›Æ:~!7¥êhºÚ¸Û†Svô~* ý’® ¨`•Y7±Pu]¿®¿+[öô4EyÇOÚPÓäWÓACݺ~½÷z!ÆŒ= #NÂò1b¦¾¡÷ +ù@Ôãÿ–}°t”2¡N?$Ì9® ¦Ÿ<¬{J;.½Š¤Ha°ù²1%fV7^Šç_šò”ÀÔ +è÷E©ˆ§’ìë4襃ì{3îNEíNyKìƒrÃ5O+yOÎaªÁ¿ãœvŒL9Ú%QnÅϲ:¸&L†%">1v¶¯­>©ZÊf·ìŸ®É*?#ž® «‘æ—^ L[xÖúHoF™¦#Û*ÔpA¼ì^¿À¿YÞ?ÆÎ½7·ú_`\ßüÖ …osuMì.cÌ" +¤”ÎÔõnõÔÓÕ8;M’¢ú$6Æ…rǺc±u´ûF9Õ¤À\Àä+Wg³ß¡áÍhî~*â£Ï [̾…sD·XÑ| #—1lúø|ûóÛí]cM +endstream +endobj +716 0 obj +3912 +endobj +717 0 obj +[ +718 0 R 719 0 R +] +endobj +718 0 obj +<< +/Type /Annot /Subtype /Link /Rect [394.50 626.15 474.75 613.90] /H /N /Border [0 0 0] /F 4 /Dest [609 0 R /XYZ 190.50 746.65 0 ] >> +endobj +719 0 obj +<< +/Type /Annot /Subtype /Link /Rect [362.25 608.90 455.25 602.65] /H /N /Border [0 0 0] /F 4 /Dest [664 0 R /XYZ 419.25 402.65 0 ] >> +endobj +720 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F15 836 0 R >> +>> +/Annots 723 0 R +/Contents [721 0 R] +>> +endobj +721 0 obj +<< /Length 722 0 R /Filter /FlateDecode >> +stream +xœÅ[ëŠ+7~¿ƒ¶£{«!ìñ8¿w™7Èea! {þäõWRW©ªÔR·í™$ÌñØ-ÕýöIþßIŸUú§Ï:L‹Iï~þýôßÓõãôý}9/çóÇoõ ï'ÏvÎÏ}ü~R“r&=ðóù¥”K/Ÿ^!½æôŠéµüxþøÏÉ,“;§ >~9§%ÆÕ%6½.éuM¯7øû[¼ÃßãmCLôi_=‹}ï°÷Hë´‚ÿõJOØ/Ñ×é9 Ïk_öG©Mâ? \ÅþG&‘˜À`f8Š…ÎšÉ¡/p&LbB' +¦ÒßÖ +}˜bD‘¼“$7i"½½Øòü÷wíãº%™Éñ¥Úœÿ8¥÷ßNHM­šQù³Ž{(;wLœžSÌÚêåqUžÿHéËÞ.N.ž]ya2ÄlÎß~=ýöy¬vÅ+6^;gí9°Ÿ&g±o`‹¾Щ²¡@3OÕà©ÙkÊç·Õ³Šw¡1¹÷-´vküU1¾¨‚¨S¨t=£,rfZBãà0ÉÊê¼”¯·ú°ô‘Íd«[Þר1;sWà<@,Þá;Ò_!,}^´Ïéóú¬‹pl¶¦d¨ÆI^X˜ÉÒÆÕiá;MÌágUõ ŧ¾öªÌ/  +AÂâóöù|—>÷7&àöõM[VúùL±Šd43£õ”òe|­†6ódk¨Kßwñò7fHÈXîJô «#¶Én›*ÒqË’,ñЖ9žÍp_ƒ4<Ñ4Œ>ÒãÏåÐÑH‹U¹š­! ëç½lâœ{9°=Å D ÊËìX³ Ø¥VÉQÊèTZ±m]C¹Ç{X¨+Xj›Rºíâ7ëš%—8(ޝ++(KmÎ0{7þh0  *^×^¤ Ÿ@›`«r8«¶”ù(Ú[ðÄcÑoý»ÆÞ…ù‰ôµÕZßþ oþõMª N„F‹´ƒÛ>ÚàñÊéøJCB¥§9œ“SVJvidX§uÎlþ´N £ùÈÚ$j¼;-d/¸_1j1îí«Ñ< dãdÐΖgB>L.l'“ç+'Ub¨#Ç:yL£Š€L‚|ïa²¡>¡jn°NS,[ÌëóÎðb—ÒÍ +ÖhxÙf§Ê .­;(™¯ùd¶"¦gÙðõÒ™ µÛP• ¬Jµ!²@âBÙKÝåФ”Ø/µ$VqÐòü†C^ôU[ì Ý·z$¢BoUí­ G›®G§- +;Ih\ÒTNÍÇ,fUl·1Á/2ÞªúÞXOÙ5˜6±ö‚g˜™ô9OŸì©Ÿ³JQpºžå–DÎBvûxjAgÄB‹¡iø'fú\ÏtdŒnãG_© ; CÊ ®Ýp3o& V.ÅûÞ0údyLâ­QI!(4”›| AS¬1µHÛY3n8P‡‚.½;Öa÷çáfÐJ³C›Ïv;~ôZ¹ ü§Ù7úŒXJ¦ãˣɽâpÚìÃf~qÙoÚTÔ‡©ÓÆo  ×LP¢ÄÚ¸,…ؘ0r s¬]¶ ] 4ZX,NÀæm»"جÜ©\“ƒnYÿ¯£ù;¤ÖÈZ HßeöœŒ.ãM†f%¡:xäÌZZˆ-r³òyr'÷¶ñÑØZÀ·›Úk^É ¹ºÙ$êgÿƒêLóq¤à®Ðñ£ø‚jæÍª~eF›sWLýPÍÕç1¾§ÈVPCjÆh²R­‡¯f& oVù0(à2^»šš¿ެÅWÁ§‡Æ±arýÑf×ÙõäêZ…Få¼qµœØ^9B(w}ªòK2³Ï#§#§‘ØÿPõk¤œÏj–4‡Þ3‡Íëh¹LNQ·Â=eåMÈ¡éúú"™‰^á3¢÷Æú~·'3«‹©ìvÀºãGZëhâè³y¨Ó"z5çÒ³9F~Ë+PÎåÉ.ž}]å« Ï=?ô„`)ßµ`J‹q£Ç1`°‚<|6áÏv¼nÄSëUYÙD+À¿NÛÞÇV ¹%LU¨ÙóoEtL-dœQ:†RȤuŒ12ãJSÃ)k‰Ì1DV úîKš‚Ž2ëtž8“=Ìe'Å»9NƒÕ^÷ n Å¢å~¦ëá­¹€ý¹—ßU3!Ñž3•{6‚9D–dÝQu Ž:`ôc6AÔÑ D&xælà}ŽÔhDy$<ŒÅµ”x?ªÃn¿5¥µ/·¦µ¼uâê¹j˜i8£ãR5rUþ8Ýè9šÍ:ç!»?õàk¾ Q‘"ÍGRù;ªNN‰!+T,’8.4KŒµ]xcß=PgZ™Ýä†L?0}≠å‡ÅŒ¸tª÷Ó?Oÿj©`- +endstream +endobj +722 0 obj +3019 +endobj +723 0 obj +[ +724 0 R 725 0 R 726 0 R +] +endobj +724 0 obj +<< +/Type /Annot /Subtype /Link /Rect [426 679.40 519.75 667.15] /H /N /Border [0 0 0] /F 4 /Dest [664 0 R /XYZ 419.25 402.65 0 ] >> +endobj +725 0 obj +<< +/Type /Annot /Subtype /Link /Rect [265.50 500.15 358.50 493.15] /H /N /Border [0 0 0] /F 4 /Dest [664 0 R /XYZ 419.25 402.65 0 ] >> +endobj +726 0 obj +<< +/Type /Annot /Subtype /Link /Rect [228 362.90 384.75 355.90] /H /N /Border [0 0 0] /F 4 /A <> >> +endobj +727 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Annots 730 0 R +/Contents [728 0 R] +>> +endobj +728 0 obj +<< /Length 729 0 R /Filter /FlateDecode >> +stream +xœÅZÛŽÜ6 ý‚ù?ˆ£›e ( +Œg2yn±6 +¤@óÒ߯$“")˳žÙ,Š`±;Yòððò?'=¨ôOÚѤ¿¾|;ý}Z^NoqˆÃðòµŽ˜¦Q…ÁÎyÜË·“•uiÀ—ág¥¬RÊÌ¿ /Õá~µÃuÄáe¼-Ã?ÞôÔ,4«f!m†Oéïï'…Låa•ÿo»ÓÙ&¼¾tGkäpÃNÃ/é·QJ/éw~üš~Òß*¬ÓY Ç2íädž4óËïîW;±¢5ÓèœXÒ™ºC—Ï—~|ú™ÅÔ&Žg•qâPgØÕ>_aŠOðyZÒú4¯’ƺÁ³8Gz.¥üëhó¥õµÍÇ]Çë´žö°nÞG(ë}zI›ìèÝàÂèÂà¼}>¨q6Ã÷?N_"êÐAá<éì3ðVµƒñ°/·z Ï›·—÷#½¹ºDÙ1ÐÙËjë\w=]]ÊÎ2û˜O±­†8Fß;5Ù…zžbÇliÁ·—õ\fµ¥ ãdêþS,1×é5"çŒ5:á\‡ , b"›e]¹Xô 'žáûìÕH;3àá CØÞÇùœb¦ç +Z"¡ç,sÜàóµ³G˜¿Œ™åÕbu_€Æ²¦§óÔ=À:æBÏÕõ0z⺎ 4Oµƒ‚çfØ—]ÇûáÞ0¢À^볂Fe¨Â­ðYÜ9/îl¢Áwýqf¾»Égð¬V‘Í ØÇÙ+è— ÃHëƒ3³Á|¦À9Ð÷çu¯%j7ç…-öýOøã·ÏŒbµ´¡ÙìQ_æÈ¿‚Ý.´¯:6†4²ÌBþÕ‘ìcÑ`ƒ5ª‰IʶuÌD'1™F1¬4¢†|ÐÏ+àA]ˆ™hÄYUÍ_Û=œ©˜éžSÕF|ß a‰ü!æŠjLÙHÌŨH`B<§ÕœU‚x0FAçQuÛ£ê¨s¦‡¯ôH³·~€!1Ô A*Þqö#ëÖï:ë*L3ružq‘à5–’ŽÛK:>𬓠<(é¤tJÖ:íÀLšn …òéØÃw—uUcÙv†¹®¸›N +Ô~Îúƒmvâ‚KÒuŽo;Å Dê* ×*Nˆž‰'žò‰'+Ç•sX‘;KTeŒ_¿Ç¤V!#ð£ êÙäSÆO´v9Û_“E(|H‚¦&¤*"2¡U‰’“'ëØwˆçIícýú`ŒH.Îm×ÑÌ6ýޱØó/JlLœ Õn:gÞ’¸›-OCkœ­ÖŽ\‡Ri¥Qˆp“ì[2€XÆy®cŸ Kg3ß²iwÂrR›åI°hm{˜.doôÚ™ Á*éïÈokÅ·g+ ‰– ®_Q19]c¾#_5öwÎXüÒ`ØM´¿Ê ÍÊ<Ä=òÏûFα{q›J¥* }$r}Ö0ÎŒBp>ÃA<Î[áþŽñŽþ·ùb+²M´™Í˜qúඪš4îC–IÃÀ†j»Ì"gvqœ¼t™ýHØÔÚ§ýpM5iS;™›êU’Z• U LVÔ’Ù¹‹8›Mî_lm¨C3Î"'¥*ôN`n“XàNx<¨×57¢~:¢Õ(ÏÅÌZhH¬Z—[`tNÑ¡zŸŠÐ…%U¯}´VáÄ ™‘Ý=Ÿkég—í¤%Hκ؄ÂlJù€LÌӷͤ71GC§ìqIÂÊuV=“»Wõ¬ìI}§w6—gl+¾Œ I®VŒ‹¢nôÍ8°ógÃzåwž# mzd^™Ü¯ºÓ#›¶Jd¶eßÞ‚f ºûê%jù §œ¶¡±iDYfÙ‰±8« Þ¬/ÚZÀî!öq$b4×;aÖp®ÿn5I«Ÿq½O2"•Ï1±ñu“RÀ»S¸·Æ-¦E<c÷Z™1’3ÈÄvnM<ݦp#`“JåwåsËŒ¾#ì´.…0MðAvÁ»jÈgù÷ÀÒbqkø}…¾²\²+`;äÔå¼3ŒÔÅ\Žûù¡ÝÝîu©Æfm…·Yhƪëï÷·ºšŸÕ@‚S®Šj µöx¤n–è'-òAøyîñEŠ BefrþúPÈmE²ˆ¹ï‡1“Ôå955ÜUåwG›æ¡kȰiÎlµV#¢çl ÚW)Dé=ÐÒTjCJ@k!@Pâ²H"ãUBt±jŒã„ÈzŽÅ¬=ü#¢¾§rxµ’iïÍDfcTæ¶ÖÚ9Ö0—OÖ6ÌV¥j¢,|°>`FFGF”MRtJ¤—eºp†š÷¼ùÜ¥]Ì.˜,07—ÿƒ£ù%g»¨Ä6œëã¿îp}çßÛãAŸE›{4èé!‘òΪ{õòÖ®wÐL†r9¾wÇ'Ô„½_Q繫KgwÄ„I—=nBzˆ#Ÿ››¤§Âw»¬½Dµs+öfzå/§<Í O‚٤¼ê€c¹Ûvêi§t¾®Ý¤d MT{mMן!ËAš¡–;M¿Àh¹’ÐûßÊÁ·tX¥Þyã%&R«×Ææ—õE#7Zäþ|*KšËüÌ=Pý×aœ)—Âϼcƒ¥Îˆ©ˆÎõl¯G.xîŽp©ú˜4wðù.±órLWsßöׯ—:î¡îÁlºW iï%™zŸ‡Ü¥’ˆ¨¥‰àÞz8¾¯UðyºÛó¸Ò™hü¦×g©Ÿ/jÿ¥;ëÜ%jíµ{Ú§£}ÇÎÈsø†ñàl£p<î·‡_Ö‰¨ –«k½wkì% W|è\%‘‰qÏ… ø¾&U<ÇЭ²iâ‰_OÿÑ™oõ +endstream +endobj +729 0 obj +2145 +endobj +730 0 obj +[ +731 0 R +] +endobj +731 0 obj +<< +/Type /Annot /Subtype /Link /Rect [337.50 724.40 505.50 718.15] /H /N /Border [0 0 0] /F 4 /Dest [720 0 R /XYZ 300.75 430.15 0 ] >> +endobj +732 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Annots 735 0 R +/Contents [733 0 R] +>> +endobj +733 0 obj +<< /Length 734 0 R /Filter /FlateDecode >> +stream +xœµZ[®ã6 ]Aöàïõèm( +ÄÉx¾[ÜL;˜Ÿn¿’LR¤";Îm‹ ã:±DQ‡G|9]ô ÒŸtg“î>»üyYÞ.Öy˜‡áí ð~Tq°S÷öí¢FåLðyøI)åÒåÓÒ5¥+¦kþyxûãbæÑ IÀÛoCšbM±éº¦kI× >ßAÄGø¼/6Ä´~•«'!w…¹(#ÍÓ +þëm=m@^Z_§qÆk_äã®MÒ?m˜¶ýc^,âb:€‚Yá(&:gÓÆÿ-\4E_¦|Mr¥Ù5+éY aËð«öIÝœVSµþ¾¤ûï…6ŽA²È%ÊpWÆ|K4ôE¶‹£‹ƒ !OLðOføþûåË•§Vuˆ:9‡nk({ }ÆWè©'=F'…TECd +'Z‚5ã^ÐáA4Ã!xͳ„VCâjèé¡-³OœŠp ×Í^&À1É÷ è·Óñ¹ßlEßÃÜrŒf°{zfõ6?ѾÇ=ã^¯0&]Æø>Ë2ÖÉϯ€›ß¾7¬ÛÛÇRO§ÑU½ÀóÈt@÷³2w*¸71íò4¸}«ëçµ5îw­.0jdÙ~[—Ö5³ ÉXÏ×foe’GsWÏ83•`ÎÏì•97nÚ;<_`>zmrÀ»ÕZZÜÙx0•ï_ÆL DL_„€¨ã+ŒEÏÌŒŸïloº÷U=PºÈCºãýZifîðÝ}PÆíå]{•î=†ìЏM§#ÜŤC ?«1Fä„ÛãÄ3["†´n‰˜ªFqßÁ9„÷­ç€Gé¿ëžîSr€¨:mÝ.Rõâ®Õ„§¶sUÇ&}f¾æ›‚[}–·§ÊY1·î9H„L¨úYÇž¡×iV¡“€Ðº)ñ¦BˆÄ‘ÙŠõ*Ç4Åq± +ÑAÄ:ˆ£ß*»Gëà˜¸íTkA‹òYL9oÁq‚ÉÿZæü–ÞÕ -r`ébÙe“AéìÜ–qË1k vÈuÒáJÞD—S tØó.Ï‚(&A†Yå 0ãVY@€c¬XUǬ[†±„«TÕž h&Ÿ«©Zó{~ìóø#g‰Y¢¤+Û˜‡a¸V \ÛI,"ã¿§N¤Ç3åp œš¹ËAQ‘@ +9³½‘r^HnŽÇ +3»N ÛWgêUÈÙà@™"“‹ç§™ +º…­ùÄ&\W,$ϸ³3 Ën%ÓÊß+z×j3Ê~YáÛ瀹ÞTÛq€3 GµîdÐn޹†hã³YëÞÎÝ­¹-é ¢ØÞ)¬1'†ãßSõñðÞ­,^Hýyã€äòJ“§;ã ㄨt<Û{[]a(ù&vÎØ]bIM…ñ¶ËÇžÝã”0ؽ•Ö?µzò}?qÒ% éØãž–zéàsþ&3A(Æ ä- hC4HÑ2òpä]Gú8Ôõi»YG%mÏñM $FAD[†ó˜'âA%!ìÈía})Âr\®ß#MгµÙÍz è½j°Mûþn~ýD¢&5rIY&·³ãj,¶ê-Cc©}Pé¶vHn¦ôkkª!ëðik…׬S–'´`ÝÏgŽXRÇ 6 Fš9FʳÓ÷ä9Ãd-•‹¼Ú#$,´¯f¶8=Ó¸n·³“ÿ› dm«t–˜<]®Ñð“Ÿ^RPä!Ž˜9î:­àj÷² {ë4—)gOÊ£ÅW¥sËŒ«#JòÈGEæÿînÖBÅ].!§é™¾ÚŠ—E)¼Ñò£gi;{òR¦ÇoXSÓs¹/¥¼™lÎvx:©™èÙóˆÁ ñÐÏy!r¿Hc¯¬&uE7סW21ç¯ç÷¥Å[z²žmxôÞ{§¦KM¨†^ÉN_íôá=Ómêî‡ ƒ½Š¦l§ÔôòutÊ›R ,Au0ÖuØŠâ/ñˆ€¼%ôN/Óm9Õ{ø¹õpè‘°y€N`fáƒrÓAÌÌj +2eììëD]Ù¯¥´éµEÍjks›+öåÙKÌý°ªkíÀ:W¹"%ä6g©r:S½<5­¾ò~I‚CÆ(?¶` +œA.2Ûò +œ/â(œèÌâæµÆ<ç×ärB}ù…Û½Á1TëV^ýì¤õå;À—^”>¥•®­@Ö0mZ& Äl=ì&m;~aŸß[†³{Ã(…sD¾Æ¬N¬Ô ýâ—Ë?®ÒG[ +endstream +endobj +734 0 obj +1889 +endobj +735 0 obj +[ +736 0 R +] +endobj +736 0 obj +<< +/Type /Annot /Subtype /Link /Rect [87 479.15 147.75 472.90] /H /N /Border [0 0 0] /F 4 /Dest [664 0 R /XYZ 146.25 764.15 0 ] >> +endobj +737 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Annots 740 0 R +/Contents [738 0 R] +>> +endobj +738 0 obj +<< /Length 739 0 R /Filter /FlateDecode >> +stream +xœÝZé®ì4 ~‚y‡ùDÉžVBH³œòtÞ€MB‰û‡×'NìÄNÓÎÌåº:ºm'‰/Ÿ—ä“>«ôOŸu˜“ž~øíôûéú~új]ÎËùüþsáý¤æ³0îý·“š”uiÀ篕²*ý™oÎï¿ÖáÁO:ˆáz¡áe|þÕª}G(ªŽ6ç?OéùÓIÑ>OVðmËit“™“®Ã—Éš6üË4^é:Þµô!ý¯¯éùZÞ-| ø-=«ôlTYß\Òÿ·ò{ßtùfL™c€;þ> ~¬ñ“s‚gz~€žŠ07ý-y¾Y¦¤$“ÏiŠqbË$uÃ÷;.ñ†ïûˆ9Ñoë*)ÊçÒiì4ÿ[Ö×Kôµ-¢„ñE˜é¾U1¼½' ôv +îìæÉÍgÂæsÒK4çO?~þ¢™¨UNÃÐ"ºÿD•Àšž¬k¦¶fæ]3—u4ÒÑL_™æ,u&~ð©ñ½îÞÒE/ëà58Ú¾°µ:/ÓF›Ò–¹š§=iÇô¾ O‘Ùð}e6€6iøØxýhN,¿ÛD×û6| ó±–±`‹Y~7|Žè'¾ñkÐfa}ãðYÂmÍ;IT¬”p异E_˜Ç=³ãX¨×_Q +Ý8 ‘µO–"¹uve6†“Ƴņ3yBÑyö~0ÙP½)l×ôüU¬™¼«.Jþ·3câ3 hPqyË7$}* R™…¨…º + MK-(Ð[S)„”dxê?øâg‡´dlÊa©Ÿ²d·jS{ñÙ‹4Th"˜9¥fðåd”IZ€-xiªº ý ºËCã*ÚÉïäêžÉ:à:ÌXµmkçg‚ÑKs3M:Z›{rgrÒ!Ó)9wñ +™Ÿ+A…4I=CÞÑÕÂøåN}ÃuÓšáÈÜ4qyVÞVäi('ÁšO2¼yÞè¬ÊÃ2ÈB(ÝU¾ßì1 +ùîò²>®M÷=e{Å5ª]ܘO9œ1-¸20>z=Ú ó|&¿ÌÒ¶äÛ´Ï¿«²ÏÈiu€·à1…ÿH_sÉ#{Å5$í£ÃÖPñA¹>¥}䘽 H0\ÁÕÑ"{§é.×Ñ$0O1žœŽ;A6£Õ+·F@îÔ9:–´Ö„inù'sB\ŒŠj¯rmÍ߯^ÞãƒbÓ6ŠL©yŠSBÆpEÐf+ºQznÊ-K~ú¾ÿ¶W·ËÐÞcÏž?YJ¿-Ù¼Ä{2Þ·EIŒ,$Â3Øi2î9g‚i«%Tg`öÛ’Ö…½šøºÀb|6­n㟙u8Èb~3kº|måîs'fú‰#³5ƒƒdY²ãy¢¢v2ݬn…w9»`ؤí°TäUˆ«Þô y:÷§ø¼vô^H­âAå\S¹¦B㩆¢õq¯g“=¾12†x={h:†2Œ!þÿÝPSÖ“ø{Ð=25JÏ× ^>ïá«¢çP¦p¹}ò(Æg¹-õúǬ5X¯«ÆivP#%}ˆëV-Ð`¬ÑÝ%í”IÝGÀ[ÔØÆƒ[@½«]6`òhÁÅUÉZnjÔì°)Zq²lŠw–žMO»LhDMrÀruº©Ý”kŒe8ï;Þ›Ilzb›FðÈÞJ˵Gèhc˜—Ug—i…,‹Óµ…Dl3»ÕD} ì©Géöa8Çú"óÒCCßõ7Z ¹´ò”Á¼%ÕR‰$Mukû¨jjÔ-·ÁB'hVHÌ~{P‡ªN'”ÂLnJŽ^†O·†òB32);Ûfí&®Ex[¾V-Ùfú<ôfžåÙr ãSu;Aá†Ò‡ä¼‰’Gb“kdOfÅ10_Ýo¾Jëö +8±–;:P ÿcê°:uÛ‚3%à éÛmÚwÀ8–‰é”›·Ù!oL,Ëæ@ð™FFÍòŠ +l,PWð5t^cÕa1ë@`÷š#*ƒ ]•vaÁŸíõ¡ñìÉîÀ°ëyÌ}'”Ø2]Êo¤çOœû¢dµË3;—ñ¦ÑÖdüdœÔ>òLŽÄ®AWöÀ&{t„ò%úGqµ1J®.’îVNÏïŸÊÁ¼—¢Öä.h;O«y0KŠsV}šíæa{¤ðT-Æ-:×Ëu¡9àÐè_H)ú’}蜡»ðæ!5L²É£jÌ2bëfóÆxÀB¶ðøî€±´'¥$¯o zü¢Ü£|b/ìg7yb£}FI‰ZÓn«sG[RüÿîôNØža +endstream +endobj +739 0 obj +2415 +endobj +740 0 obj +[ +741 0 R 742 0 R 743 0 R +] +endobj +741 0 obj +<< +/Type /Annot /Subtype /Link /Rect [484.50 564.65 484.50 558.40] /H /N /Border [0 0 0] /F 4 /Dest [664 0 R /XYZ 146.25 764.15 0 ] >> +endobj +742 0 obj +<< +/Type /Annot /Subtype /Link /Rect [108 553.40 168.75 547.15] /H /N /Border [0 0 0] /F 4 /Dest [664 0 R /XYZ 146.25 764.15 0 ] >> +endobj +743 0 obj +<< +/Type /Annot /Subtype /Link /Rect [270 512.15 324.75 505.90] /H /N /Border [0 0 0] /F 4 /Dest [699 0 R /XYZ 72 665.65 0 ] >> +endobj +744 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Contents [745 0 R] +>> +endobj +745 0 obj +<< /Length 746 0 R /Filter /FlateDecode >> +stream +xœÍ[ëŠ+Ç~½ƒ~,÷}fÀV«•'ì8±Áà@Ο¼~ºzºn=5ÒhÀá0¬´[]]]_Ý{οOþìê?ö岄úé—?Nÿ:]?O?Þ—ór>þJ9_Ü|ŽÐ}þqr—B%øåü“s.Õ'×§ÔgªÏ\Ÿå¯çÏßOa¹¤seðùs]-‰õy«Ïµ>ïýû­³øèß÷Ù–¹îÏ|ý¤øÞûZäQ×y×úu?:¿º¿¯t¾ÓûÜøã©C•¿˜Žýl6ãf¾tAàY-L .ÕåhY¨2økß»²ðóú½±»v9“f·¤KŠŸ_Ô™c£ÿñîó\Zª$JÎÿ9ÕÏßN9¬§vð;z/%=ßœéçKѶ x +ˆŸÕØrãæKšÏ©XX•<…ó·ž~ý [ct†9NÉiÆ¥/hx7DGÞ%†ËTˆ78¢i>â0%{Ðñþi¼;W³*Ö¦> +%óyªgø¥[hìƒ^3±%“õOý¬õ è=EœÿÞiß»ö5ío7ôáõs˜ìWyÄEüÖvyÑÚÈc¼ÿ&"Â?Ó™+?? +M˜úßÞ´<°5­­49°ÜÀ#\…œb¿¦WøùÑB{Ÿ —º8§wÌxĦз~¡¸f¬¨¼Ûpø~` AcFaÛßoâÐÅ:¸öÌÕÈêqŠWÈ‘éböMÄÂÖÄœš"äFyW¥ËüE}<24º¦¯òº1Dä= ÒÜûoý‰Û=Éø§­Ì£Üä ËêDôÝr|éè]?M/â ¼~ÈNþ2 [„£tÞ]p3½0OLžÁŸŠƒÐ'ñ„¿ÔC ¢]vÝ„ ÛÍ‹»Ì3ÚI¼žŠkï²dÜ™&}&ïÃ%—AöžëšBWx3,Y‚™Æw£ðC´{,F`RØl!FØ7¡nümݕ׆¤µŠNÚöZ”Rb¬‰ÛÐÝ`±Ú[‘t ^?´l©Ô›ÉfÈ_zIè¯ku/aeà"áÀ‡±²©ý±Ç:Þmåë0®f§ãtYUÙÔ™ºcñ˲ãi¹Ä2Úñð¢ +Kú3!hå§M¼Ä‹mÇ&ú“ +ïB=땻ۆ߮n ÏÆºoŽêŠÆ·ïÕj”7±ÇèYFíâ»§\…3ï¦ÇõbŽ-ça4²9 +°Ï­ãÔ§cM™s€ˆý•š2û :N$ט.ûˆ6=P”Â̧N'R'Õ§"ÒadAúö{Ä!¹¡FÕ]W- j‘¡_Tþ(Ú RZ‚‚0°Aʃa‰¼~¨HÞ µªHEGÚ ›T§5LÛgΉy o¨Oæçô"è² +tWQ)OŽzfÊ7¸Yî–WØêíàäèÌqcÑ9zO|ãý€&&¦ ˜gD`õYÐ#¨¬ë~7¾çÈV®Ã€Q »ˆ´Ôg§=KséM© +íÝ%à'„ƒ7Ssi0­Õ%™ëÒù½²ÖÚæÎd¾ž¼YÖx5ìȆ‡+˜ ¤–ýtÊS è­÷Úa!ž€Ø©ÇÙÌñÏ·MP£»,•¢^×(«TÌo(#”!£M0À.þn)‘Èš.(¥étjjQJ˜¢îÛM¥©#=VÞØËp€*+KôvhwÞŒÈykÐh +ø¡"Î3t°LUµ¡ŵÙ7U=r¶5Eçã¶þ1•,Ä9¤c)~–vùp^Q"‰®SC‚ªGòl‘"ŽGÌqÂdUmaLàq2QÙð·a!²—p‘RF.ðÜw†!ÇdÌQÂòåP`è«T2V•_Ÿn‚ß~ëþþ3c:ÅËp 1{³²Lϸ¡ãJ£Uëp ‡¤Kͦ¥ÍE«‚«êÖÎA¨Ÿ×RŽ{ô–„•TÁïåbª„ïÂ;.kác‚Q›(#s;âž9»c‚§æÌd{æÅfSSÓ"‡Š16ËFJšmÇÕtô¸q˜ÖF©uLVÁ Üÿ‚bRç+šQ—á¸j5ç>[Ilë•’·^f~Ðzåže@‰°=ÎÖ€(˜v"÷MNAšâ`Ÿ+ßÛÐZ𥌳=_«¾›wy;$iIì]X±Ç(mbCÛ<„©^B†Op Aϸ„7ë(ì|41|âÜ–2(—œþ!p‹£{"o‚éx(B{Z‡™fjÇÖ{&CÆû‡êé³Þ°†2üûªŒáUˆ<¯¡œ:-p%¬x1bsãh]³n7ʳiTr£CV¥N­:±[×¢,ÍÅû ÿËòN53|/¥-Ë²Ž +>e~§T¾k@ŽŽ©R¤­gµð0ðä –t; œ'ˆ—j1߯º>Ž~·Œ‡—ÐÖÆx{¢ûAbôø²KÉsÈä‚Àó~ùèû`òþz˜•I PwÛhM44Õå4¯ýŽ„—{ÜáµJþO:Í}3ØJ„ù¨¶yuôõ*ÝÒº__üîê b|ì°‘/Îzã/úZqJ^;íºO0rR{Š·òÅ+_ùs/¿Ë7T` ^>äØNl7ú¦ã©j·TœÂ“Òì¦[qÖ,ÿ«À$­‚êãWZ©Z×b[†ÉFߤ'i.:ÎŽÓ¶<ê…‹ÁÛª\˜ì•ÒE u ¸¨ür@*|”¶#v²â¯M A(­ášæ{ÙéTÒ_á²ÑÈql"·h0ÍÙDcËÛDƒÈ^BC u ¹à{E#–Kx‘ì`aϨ¶œM(ê%$¤DG€ôß+~þ?…Óì 1Œˆ‰-o +"{ %Ô0ä‚ï çŸg ¦ÙCâ¼M4ˆì%4”PGÐ ¸H9ŽÆæ… ZI+¦\mý_!›ÓÓ¬Â${€™÷ï[Î^súBJQ@KÒ7®óñyúÛé¿Ö¿Éè +endstream +endobj +746 0 obj +2833 +endobj +747 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Contents [748 0 R] +>> +endobj +748 0 obj +<< /Length 749 0 R /Filter /FlateDecode >> +stream +xœÍ[Mn,¹ >Aß¡×^þUtÛî}ß`’Y˜™M®?’Š”H‰U­Êd<¶Û”D~E‘”Þ¿oú®Ò?}×aÙLúé—ßnÿº=¿o?½¶ûv¿ÿZ%¼_Ôz·1Ë}ÿvS‹². ürÿ«R&*eÃÏ÷ïVñà˜¸ÞP\ÙüUÄziß-U·6÷ÿÜÒÏ¿ßNàË`•?5n1ëû¥«ø¶XÃÄÓòh˜VJ?Óô¥CúZ÷ßóÏù3•wl:küâ›Ï™º¼Ëʧ¯<>îãÕVÆ›mIx&“þ~OCŒc?`¹øý¦ø‚ß§ kZ¿Í«8/‹sds|×ûzÚÀ|Ùl›ÍÝåµ<è±–õ¾¾“y»wwëâÖ» a ëý‡Z¢¹ÿþÛ¯AÓê¾-[¼,z‡è¶VqïRT¦X¸Ë “V.fòØLVA˜ûÅåV·P~dW·¶D…Þ2Ìl±.Ë•ªƒÌgÄÄmg´Æ.4SÊŠxq€'üô³r +¡¯ñï…0»Ï>­|›&ûµáVÉ—çl4™6À?z6ƹE6ªØ%6˜R3lÐÿ¯l•m#ˆiÏü¶xCÅÒ®W0X23R€ Ð<9‘¥aM™¥*v‰%ªéKleip5¬ ¹‘èùª±ßn‹!QQ×mVˆv˜cÊŒÇà?Iá@}úÌj¢#FìCº•]X´êòk>mšTÂÝW@žûä%b¨ÎGÇS$¹_Iæ¥.QL™€ƒ,cQ¤™ØäªMÆÀIè|$˜¹=ôØã8€Vßdû#b4\~öš8ˆûj\Gļ‰]šEÛ´QØÑ®bÓÖ ,ß-µ•R3 yJTøAÐéçcQ¯Še£ªM:âÖaæ–afsOÃÌFMÃÜTJ07;-ÙÂÐÑlƒÏ<„5Lý®žÑüDr)Ú¸ÿìá»}z4„1ÕÉdŠÒ<ÎK4yÝb¯^cUòþòäØe’œ?ŠOÆd›h|zõqŠ›DŒ …ÿ×Рïs˾_Å.ù>5íûÌ–bU¿Ž{ºT3cpS.›Ý¾îßbX)j:sbZõhiUåúÃÆ +¸ž‡5ó Mšš…„12WWBø°½‰ÜëÌ}lèΖ.sH"E3»Öè7rƒNô—~QÙ]PêÒf§ƒ¦…˜wZ,¡É5­W6ÛS;Š +2=º´ûÞµsšOµX¿î%R1, sÁ˜&ƒšf£©D‹©ÚÇéû¶kbŽ[“}[¥»CGƶ‰%´:Üõ:ŠëÈW±K³QÓS›H Ù4»$Î:òȆ¿ç¨säÊ‡ÑÆ%K»ÃJ‚œˆÑ:ƒ qe¯œj&k[Šqx}3ª"²ÒÄ®°ÂGͲÂÌÖ~†ìà4[ÿ ;!.ïcM“b­J–c‡à÷+ÉØ£Ô%èé iä‰M-K?žÙøg@÷ªð¼Ó²D,™ÅîIjN€ ìçQ°×’q¯bWó4>r}j[»ð³Ï#û$­‘"šÆœ/5úË0§6Ù)NUì’ƒ²QÓQûL‹ØÛ›¤ä¤¡9.ÅÉ@¼T1ww[pu,¸æŒß_œƒ +iß‚›âMQ™ÜhÖŒdÂS’ªØ%’بi’¨-€™dݤªu~¢@ +).ßÜ"'R¨ÅLþèôfT¯77Ôx“V  år§ªooS%Ð ü6~Þäð®k¸-ZÓ îøðú8O‚O ALNØpÆ3·™«’ ›uªfßñeÛ¹=3r‰8SöΔ¶t«¥s½A/#¥®9¼4±Ñ“ (Š*Þ™ èPxR½v#»Éªz‘xªó ujÏlê=ÚôPôíFkü›e];½y¶|ó;b †Ü:ÈcÀoêܦ–n½êK.g8¼}ï•Ïï&ßu¬é{=™‘`¥k,,¡Ñv€ðèÝh# +”Ä˺Ð×R‚EÄèÞÄ(R¼vÕÞ¤áAÁÇ<šMÒ]d¤¥@2¨gºãn-åp“ûA»ç)Ý ÙˆC­p,#{DÓ¶ìHR>ÉE:¹Ç|u„>Ègôg®Wr§ŽMígŠqŸó[•¤÷ÒQ¥‡‡GôÚä]d4x+»ANô$§$‡NdÂzîõ§ºÐ™&“Ÿíû&veßóQ³ûžÙKüõòFæXÌt³kI‹eö@TMÉêU.ô]j?Qìˆ/.ŒÛÆügÒÆF±è°Â©7ì2—\¡ ™öƒj+ÉÍþÇNðÝêŒÌw÷ß«¦qÛ ' œÂ^Å.!ÏFMƒOm¾ø„î +þÇØöj]ÆÝùµ%{Kldt½þRÃ5]þ·[[C~\¥uyÊTi}¯Z÷ Zòš !§¯©k?/Hy|¡æºF»ôwª­SV€?¹yP)þcÜ')icÄb!æ?¤Â7OEÚ <¥V–íéEyº÷M¾Ý§Ë+I³×ùú&ÿ-¦_Ð+ÿØ?/ÿ5°KØk‹” +¤Ç"žÏ:bÏ;šë¾VÑùS ç +kD‰ £R–+ +=ÚAp¢øV®±Â÷$ô\B;#qB‘?îi~K>FìÇT¦sÈàrû‚áÄ:#ë×÷ío·?¥”çù +endstream +endobj +749 0 obj +2760 +endobj +750 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Contents [751 0 R] +>> +endobj +751 0 obj +<< /Length 752 0 R /Filter /FlateDecode >> +stream +xœÅ[KŽ4· >Aß¡×\Ö»$ÀÐÕ3½07pâEˆ7¾~ô¢DJ¬êªíÀh¸gF"©oJÿoò.âò.ÝTüöó¯·ÿܶ¯Û¯p÷û×/m…µ‹ðw½¦u_¿ÞÄ"ŒŠ ~¾ÿ$„0ñcãÇÅÏ?>~Âßï_ÿ¾©°˜{$ðõÏ{Ü¢LÛ¢ãç?[ü<ëÏ•ÄgýyŸ¬ó‘§+WB÷U÷¸OŠúYøIUéEþ2®“u½´™>œZEùãÛ±HÌ<0“® +˜öd£1éà.á`›Š2È­òŽ$¤/?KGIx±·C#ã–öº'˜Å*²G‚Îë|I;(Ø„(1Yªûï·øý·› +‘~ǘˆÐ‹3ï™÷õ~qÔ¦t3.?óúϯh”6Ó6~1þnœK£2Vuÿí_·_þÖ­6kg4ÛÕÊE7 + LtÒD´“4ÿQ~NÖ£Eà}MFW’hûJsI­ŒÑÖ¢ƒTànŸ•ågU>†Òº„Hß›Ø=Ó•Ý üŠfÛéÍ20¢Y¶,€(;íSÚ0mãw(U!L¶#¥°º„ep0ɇ q£(ž™ŽD}ÈÌ,Yì"*ÕÒ\§ym7Q:U•˜ÕïÚ×p•> ½&•bšÍ%œ'1ìÈ@µH•Y;ÇBŒ7ªÆLC˜\YT‘|²{ÓcÿÌÙ8Ö.LþŽ~kÒžü=þ^ù¢éä +B­«¡Bükøû£ò—ÉËiDÈjs1ˆq!o ¤+'"„N#“¥µŒžúò«Š¢;ÏjŠˆ'[L’ +;k‚¯½®K‰(ü1ªãÕ²®Ëê&yUM‚ÙG7”­O¨©¸!|Χú–˺";O늜Ýìéêÿ?ÝE‡ˆ‡sË£ÆçW‰ÕéÓR[úÝ‹ó*LªÃ·îiª-¿¬)²ó´¦ÈI["T(«ïwÖÆ7Ñß­Dœ´Kµ#…©©‚ž²´^ج«" 9ÖPéÔl]n]¦4]†¬À@ë*,2ÆÄñÙsF†l‹§3õƒ¢g7EÛภÒ‹?õjíöö‚:8ߣª Î„Ïø@*õ˜Û…d +« í1 +w‹ì%Òèá¶ RÜ¡2K¶ú,öšlWƒ@UpPŒ‚µH0”xǨ”mþ¾U@F»×Èð ŽZ¯Z™UÀšÑ8Dg­?;¤G}ÎB"+È©;>åg&ÒYo{U©äæYÞ1 +Ÿ”q¯`¢²ÑØ«Ú&ê’îçžø9Ë¥%ZÓšëëÁ@rí-‘@1OØÙیˡ +qô  +€1È{9Õ³ÿ=Ë­5¾y]¨†Q½ޱ{@sJ_õâA馗Øm_©´°G~™‰'ûø@ß÷…ÃÙÈÅÏì ™6ø7*±!‰þÓéŒYüÉyê‚96ž÷Yú +àDyäu¦TËÚ£½´õÕ±HO¥ƺÅ/éPRG!c®Îè÷VîºÜ0›WÉ.0 Ý2$uºÏNÀ*KÂ8R8„O’ÍPxÇ¡£†E»æV§ÝyÈs¥L3™ù°Önˆü\Ñ!7R0a¢­¾šQ1›(FqIðÖ£øÄ)ýà“‘SÁº­×ˆ£`„û˜£» Ϥü4;:¿êÁ›zA«¶ý8Œâlñò>\H×ÃdÀþF"Ä Ûþ³ÁBV$â¡hÕÕä/û‚F¬ýýÑÅ£‹«ÌÇ U-6Mz@+-ÏÍjMˆè‘5õeW¬‰H¬Ôì$Lâå‚”Ÿ€¡5 d•ßCö +Y¯PGÖ'TJ´ifnÓ ¦Ë2µé<Âø!ÂmÙ%„‰änöWÑff9²aWƒÙ™eC0ˆHû©µÝ F° ‰a>‰gÆûOXþ6 ØBÞo:FUšª¯·S˜Þ9s0 +5@þÈT»æeUß ª¾-›GoÔO$58$´7¨ûºxÓ˜U9#Î!© û¨wH–0Æ"Ù "Ù–]FKÚßpâà:#I ùܪBèRí/ƒ\¬Ë<ÇÓhX~ø\aæ!ø°êRÃâNÜ <Ô8xmY®„Òû‰ùŠ ³Ä i?°#:G°ôeWp!B¢:æ$0¸ÖÊÃC0|ω.‹Hm¶¢xÉXÎ?ælbõeÏxÆ!xmÙ%ðˆ€×­j¬ÆÐm`>Q­1ðÈý °“"ÿžž‘ìÄ ÞªãÿzëÕgïgäðÎI§ªïBf}‚¡Ãh‚JÛ3s:PP’GáhcÀZE§yhDæÓVAÚm Úülå´2…|g(aÝ›¦€LÈN›µ©y"›%N]mH°¢ —ïC±7]ür—Æø¢U +­¤EÁ•К䢷©6wìäLª×Óp½µM¶XmXûe6a’Àžƒ û– +fÕèZ¬ºdTHdôJˆÄDÆÓGuS´æh‘"˜„.dNÝQ%Qù,ø¨P†bÝD†k²Ê»7ÔL%¿y5D˜IÒ4J ÝhÅœ•¬/Àœ®1¦*ìóÚ½|Â0™rD?¿:Á"¼7èN÷Т۲K&=n±·N×5ôpvŒ§I}z¦R Ê– SNy püZ¢>źVíïñÛXCܲp™˜KExF%'óÇÄÎYÛqÕø1+Aå†pO¡ˆ@gÈÆÔºßarµ"âpi6 R£Bc"'ØÑ·;ØÁó4k¿šÓƒiÀ¤¬¡ÙDäîæÙ‡Ø0à1U§™öð¨Òfñ”MŸ÷x¢» ô j3>¿nÿ¸ý¯½& +endstream +endobj +752 0 obj +2860 +endobj +753 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Contents [754 0 R] +>> +endobj +754 0 obj +<< /Length 755 0 R /Filter /FlateDecode >> +stream +xœµ[Ýnì¸ ~‚y‡¹.ýÛŠ™$s_ o°í^غ7}ýв(’²¬±“ ‚3™Hüùô‰")û¿}U韾ê0E“>ýöÇåÏËíóòë¯ñzýü½Žð~RËÕÎ0îó‹š”uiÀo׿+ef¥ìòëçêðà'Äpq¸²ð“‡ÿºkß(šU£H›ëÿ.éó_…|ž¬à»­¥³›ÌòXu'kÄð¤ÓJé[š’~tH?Ëú;|†ïüî„8küäœçLUïÀøôóçu¾Šy¾‰SÂ3¹ô¯kšbœ°øµ¨{+¿¿å÷}±aIúI®’HÜË\”î¨ò¿^õiSäÛÜ]Çk_`ðÅŽuý?>¼‚»ºerËÕ…0…åú¢¦Ù\ÿú÷å÷¿!ôºÆ)†Ëfï=£ëj¼­êt\W&Ãqê3€†7‚ÆT&®®-VJ‡FS@EayŒ2“aS^йZ +pNf#•)'H±°.«ŒÄË«t_g·o›8séE°“[Ò*7ù ­ÐÜÌ©¸Ù’Hg®Äd©hö“mÙºœcDrâ§eéx¢O¢…¨ =©›Öébå­xƒ,}_wz輚ìÖn•›YŒ+MKšF·(š´[l’mnE 4¯ßçÏaLG.õ ë”ÓtäÊžOG’>¦£².bÞ× 1üöÌ ¤h …®ç¿5Ô\rtÞmÄ͘¸é:n5ÜtÊnùñmnúÄÍŽî>5‚À[¢gËLМµÞ³’ <ÈÊ:å4+¹²ç³’¤YÉ­`éí¹òJÁ3/ï[YÎÂ^ œYꔆS{ÄK^ù½q³e©^¦ve¿ÏÒtÔ›Žî>KÓ>©±;<ŠŸuè`Ö>`+|¬8ã4W™ªçSµ +3•ãøåði‰/­r>g¡ðЩlöfëÏ&pºiÞóçËqÓ@-°U­;Œ él tÂç : +©ÇøHSÎR({:#™ô!%w€<<÷¹øœàjÃÔ uŒÆ^5ïð8U?±á»Döi¹¥£¼ªú(ù¨ÎYjYr¬l3{,沸N9Íb®ìù,&éc —«™‘DS&æÕîÕàR",±CƒùȬÝ.Ð#.›T›wh©l5 túvLž#´†¶ÊûTöše(Õ7û®¨ÓQàäÙl…~@i.ù ¥ë”Ó”nèG”6H²#”^„e»¤öpºJ;ÎÔκ´ ¤ù{¿:a¼ŽéU\ ìŽ=è†yƒi ÛK|¸}×¾œ9Øp7Êû,µ®&-¦îýFûb@î&¢úcý).ø GqÆiŠ2U?ÁÐ*~LPn…­ûcHª&Z}cI{_5·ÞÇ<ß?ZšÂǵ¶K)R(4Ëš–à‹Éa˜‰'2|5¡°Ð˜ÞªîÓ{½h»ã<Ÿ¨=XGh‚Uëç-¯¹ÄƒÄ®SN3›+û j“ü1·…•ÜCbÎVK+ +ŠYˆAbµc1­ˆeÜJý÷xyœ³ù|æÆLçI.탂B9Oç®ú)Y¡k¸Æ€ªÍÜWó‚âNǼ+ßîH®Î +jW!´ÒÕB­:T¥ág©*Ñ!fCÓ#’úFg³Â>”]=·ìâæ$Õ‚¨+·ˆ-Th)™)Ñ@”t÷Q ‡ Dï=$ë0@ÒÒž)TPsEn­6=k1kAϱ9²ïEú~{yˆ +MR +Ò.$º-I-;ÓÏ´CaiàïõŽ‘¾ÞlŒéà#ôýÚ’[07$ìk1 *aDÛoäøýkè”oÄ UûœØXVYü›-rotΆ©‚=w}û¾U»Þˆj5¡)‰sõofg–°[¹ÚÇaÁƒD(ß÷ú~<¼Þ6›µlþTà·IoùvjÙœk±b›Ásfî> uØ‹¸QÏ™áŒNu‹[¯é™…çì?«8-…’@½C¼4åÿÕBãò½wm¤lùjW#Ó²R¬õ -c,ß©}üNnK“mÞØ©FpU5fI4{s#Ÿ ™ +è>øŠžU¸Ó眪³cªS"–)ÍbhØe‹'XF‡,«ÃN³LXO'þ³cÚ†P?D—W$@òsž2ÚCMBò#œq‹ƒ”³Qa_Yu8}Z@s F°Û¼/Ó†Éц†ÉR„ñ‘&}¬î4©Þ¤üº\íÔ:øv ÓÍhÜœ«€¶Vi³UÉ…ö]Q:Ë~>®¸×[#±¨¯¼F‡6O¥t šeΑçè"Éø’BÕ9Ä»FxŤ¨kŸÚÀ€²¬¡-gÄQ÷0l6ûæ½­:zu‘Ð÷¸.¢ágë"¡ˆ]—Z†‡?É[à9–¹9ä5ª D ½©³š®}·,/­,É‘Qm€ÓqÇN ÏgŽ^Ò×pßÎhVPÿ|¡èªoÌž_¢Óþ‚õ]¥Vç‹)­úšqBkâf@kä,›w×Vzûx˜µ“ò‹8¾p +«[c¬smëù¾Óy€ l +™±…ºÎoêáÐÌ<Ö £)§·WF¥üæBÐÒ¼cº¾¤”w¨Qdâ ﱉ;ë˜ROÛ(x^£žeh;æUæþ§½L¥Ò„2&óªùs.Êß_ vÓf¿Ý;íºÍè„c[¼MÛÛK‡-RÞšÄ2¯æ0¾¶éÃ;éÛ:ÖS8Õ, €²RyqHP'àÒ–E!$Ö©†(Y0†”zÒóîéGî=î–v-ÑõÉTºÝ´IG‚'-¬bZR!Ào<èòÆÖÄÙx¬2yÞóïöù#^™2³tûŒ…Mv ¿;W!&ÀCÅŠî^® Ãö½ ³Raˆª£~ðéѪx.óçAÃ+Žn»Ñ,–í™G•tµ­hò[ìúŒ*œÞVc +F[†ÙjÂzÝ3ƒ˜¢^Ø`!1÷;h«nœ˜œwµí-E L›¯'@bcsìÉŠdí^8´¿¨Û)Vð§5p÷ÜÅMÖ å'þ¦)Î+· &æ “·q"xÙ¤:2Ë.l‰pk»jõ[‹®-{«‹—æò¯{Úx›æ˜^"'Ìgº.o—Á `1~Îv›uk?h¾g 2gò©š9Š_»«o”ˆ‰ËÂâ©ÀO3 ,»fzðîWÞ$k°Ö2SÖÁ©^§¾ˆdwX>²>äĸ€\'u4á]7 G™ßÌ3ÖååâóèDqÅÐXÊ•ÄæRÙíÆ lCCMT‹GYì@l1¸vÚ—ë)B裺² DsN–#¡m¶<ô±»¦Ÿ)ß­hÃáÈýn§µÙV¦ðùyørptòhÐ?£uÐÁcaGÊmò€rv0ë)hŽéz4³ Hö †¥îÝ7Õ*B=tHÖ :îFé;0 žˆ”óìèv‘ªyŸâw" b$sŒXw +±ôÄ„gODÌ,¬—ôð-‡Î6†´HÞ­:îZé;hq¯ž‰VŠI*ÛBUogºA©Lc²:ˆ”»ƒFµú‰PDËvð‰Wm:à¨!> +>> +/Annots 759 0 R +/Contents [757 0 R] +>> +endobj +757 0 obj +<< /Length 758 0 R /Filter /FlateDecode >> +stream +xœÝ\éŠ$¹~‚~‡úm˜ZÝÊc¨£{Ûô¬½Ã<üúV(Š#•Y™3;–¡˜:¤P(ŽO¡ÈþÏ›½˜òÏ^lºÎ®¼ûå··¿Ý?ß~ú˜/óåòùkãÕLŸaÜçooæj‚+~¹üÙÊ+–W*¯\^Sy͹|þëÍÍ×p)>ÿ~)S\èS|yÝÊë^^öùÙH¼·ÏÛdÓTÖ'º6 ºm.Ò(ó¬iÿÛe=ë½²¾-ãloc¥»v…ÿ²á¾í/°Ø„‹ÙÔ†'11Ø8—éÓ\áÁÞÛÚ…„–ϕܽñ$¹9\£ôì,öìëøŸ>lTŠ sáD°bÝå¿oåý×7ƒ–]øn zã¯)¼^œÆO×$mÅwÅ»¢Hw¯ãß?‹±ÅJ;L×0]BJ0±9»Ë×¼ýú'´Fk.Ei`‘9&ãn’þNº­¶“˜|?»6ÍWAI¨aóи/bÁj¤Å í J#òv'8µö§‹€á§úû£-tAJ¡/Ò(B/âlÒ ¡ßæ\› L.ï)ÁdAƒ<Ö7oíGã ­v(Q¢³/Ñ>$ê}—è¾49—6u—œ›³È8ôÍUçå½»óßä³_‰Á˜ÎÕcK”+BÞ…«OŠÓIpÚäY¹KZ¦Ë÷A"O`-\;©qÓ5o.îÛ¢±ý_™‰‘¶Ã +Q·…Á· ®`C·éî öÖÐõFûïq¹G{y´¯'"qy!{á l°Õ”7dýÏÕÊêö½­Vðß>:ÞÆæ  Sì‘€ï£ùBZtçð”âþËöÚ­°ùz?‘5âaRO‡ÔN%¤‘I=|lýþNk»=- +KÅ.º=¬$ôÞ¤tSþì—ûÔ5òÁä +Rï#çk’'ÁQl‹²]\Ík>.æÍ<Ú¨Œ‚ç™åè†õ]¤£ÕV喝 #ZX§­ÐAÄ=õ»éÁÀ_WÉ]‰'€« bH-ñ¡dúœ*ÓÆ qÔÓP6|5ŠF¬w«AKš–1´ KŘ‹ÿ~k;°LÛ±ÌÆG=Ez¾ŒqL¼ +)Ž-”èb +jÿdŒ™ ÷Š¿u„i±¢kGw}aüˆžÝæƒa 0utÈ¡CCÙ|ÚŠ½£F„SNÛ[‹Lh‹÷iF¿gê뇩 ƒÇ8;Ö·LU¿˜¢´©8_K¤#éDà³a²93!nØëdmµ?o®Cý9¸¼Öï³k7¹jUœxž8À`eÛÄp…¬'cÝl{òæÑ +™`ˆÃ©İáÑ´•ØÜ§aaQ!?-‘É«{éëyhUý» µa-È¡ÅÍVÄ ÆÃˆG¸€ŽždAŸŠIø­™œI%î&EJcl¹r«oá¹ïc‰¡§n™v–Ç`˜Ù”ÏO%’XgjnÈ [?s“·C<œTšsQÅj%?°ïCñŸ2î#0WÇ=–ÜÏÝÈi|súc>²„úæåi<”`؆7à/¤«Ó‚Éÿ·ã:æÅSn'È„èŒÞ’]Fw7Ù¥qg’Ýu=n†¬Æ­á‚«þ0@ͶP˜L课ù5üÍõ „™†‘À“×»¹#$ñD}G3‚Aæ"–G)7fÞêÔ÷Q W`&cB2.‰$[ý`¥!í/%‡Rk9Ç…ô¢6f $™µúȯ¯H>r,Žˆ)RlÒA«ŸÄ¸ùáI¸^Hèô²'O£?j#­G·åÛ—[ µy¡ºçȇiþ¾^>ìÜ;Š5»å(¬¨ÓŽ]­Á¢v/ž?hl-toЫßÛ-#‰zêG¢Ü¯–÷í}­lÀ£Š #·/à>³í諪ßr>ÂM@ÞÌz'dÆ!±süÆPr4ÇÓPm‚ ä%~ƒs¾ƒÏõ6Æ2A øá}È4?ÛvÛQ¿s#%ZÏ2åŽÈ.„<ÃÀôGJ$rûJìãN)Q0»é%+ðèÚßÉŽ7µÚUC21‰<÷‹ÀÜÃqâ&_$ÀJ¤˜êÌR&§…Ó½ù]’ž@’¯öÛ‡’ÑûöØ…¡L­¤j¢“þ4°²0J™âÙÊ?žÍ;õ‘=¶֮ Ò¸3&(vw˜ +Ê·E¬N‰/Y9“—:ˆ1‹òX\gEêÁí CCÊ38¬¦ß)h¶‘Ñ|*ƒÍ«í Áñ]f†b®Å~™x<^,nn*â1C]é¡äi&H¶œç²3x—“(cûÒçµ poCUgO);¥©\0÷;„àMºÙB×5&In%Í-Æèãb«åùêZ°Ûd‰ï÷àîN¥˜€28¨Ø¯w”ÎKä=« Ë+¼HE,¯ú{|ª/Ͷ4$µ³'Ï¡‰”ø> .!° +‚¦ó¥’“mÊ ª·`ªMb²û5C gC`W„1 ;4¶` +µð4*’¢‹$4çl‘Dn¡—-%›Fe‚ +l=$!·Ò ÿ d·Ô8²¬êÌ<ów]•`×”ñ¶`E¸¯”íc½ – ’5e’Yߺ.›ïìÁdð%¶ÀÜZ*ø ‹¯£u¥õ*QÄ}Ð~Iø>©¤?´ïX8BÉ9Ë WGåï\š)Hb”}÷$5°Ä”ù²Ã +– G»Ü(UÕ`#‹÷a¯^xj:࿜àQÿísNû¯`ßóßSnÉ ëü}Ürµ(º&_Ô¹=×”w*Ȫ=4r‘›íHÃ2âeþÍ ¾í[ßL·ê.kã;rtZb7>ïÃjL.-¡¤!Ùш/«a»ó½Ñ¥°Î»U¢e¶ï°,0‡ÖÈÊ™ á3ÌdöÕïªRS½R3fw|.ðzQç ¶cÆÑq2l¿9Ú®ò²M§ò1;¨Fö¨,;nâÒ —>PËÞÀI£ÈniTd{R7< l´•$bE"ð¸ v·¤Æ6ŽØËÛI9nqÞJÒê’ï¥tU 3-­¥qϺ†FEŠUטnAK 'Éuæ2½V›ÆÅXÅWݨAK™ÓF7q`}­_Ñð(ùiŽô'ù@…'”b¥FsOt(E臫lQªå9ñGô(ùÚB­ þµªy\uÐÁ“ ÕÑ´Ö¹ÌP*8üD„°H…ó܅ⱟûiLè«‚huÏT1DÐN\ÅÒN›w·Ií ïá„yÙã4‰†1Y˜ß˦‡A° ì~—ÌEÁœàQ ÷9§U,fRå{­dÕÎ1Ëuå¥çYkˆcamYJ +C[í™—ŠÑšvjìE‹ákâeí ÿàHÉ%`Kÿ|©Ñ©Æ[Rô©‰ÌÉ[m·èÖEÑF7 ó\W-¬©Ù,£‹—f*ªrA¯_Æô6kzœÇ[Ž{¿Æ\=<å ´o|ËÃSvp[Õ#v¤a¿3¾ 2S£eêà N3­îDHò0²/Œ÷ƒÝ謮½©iDœz‘x;ã‘tEŸöa^̯ðGÁ+r:(àû%bcœM/ÃKîK/âQ8b +¬6?º¶™‘­b?v"‰1t€7Ý+¨î·zÔjí!!qmÛÕuwßn"ÄìüèÄF+fÚ)¨ê6ø‹‡÷„ðGž6Jɶnë³Ûn.jŒMUä¿÷ÐfÏ¿â +m.Sy…ãÍUE9ˆ¯”Ì"áoÒÆV)î=(PÆì h—Š˜D°ÈÚ»]äµB*¦ëË.uÉáõFXš4i­Ó$Á#«âòkΞFbÕo`Ϲƒäæ A³”ê6kî%èJù™™ _†÷.p~èz öò‡÷Æ9OÝβ™¯ÿloþö3™žŠÉRtÄ{¡™]×êÆ“™‹¢œ`‘ξRm4ÎÓ5ÁYXÔ³œ…æÜý¼œ‰TR¨¥Á§û†8„ñ¦³r˜Ç´J.õéÙo»Ú£ÝÀ2¿h}åÊ=áDÚFGÕð$¥ßR×à|·ºF­màsõ̹EÊÐnDzÃè]ñ2âc*!-"½)‚£1+"KÇ.±WnðÂ#‡Æ`ḵ*Jíl®7Ü Àbô(†îtX]«†*ƒÆûdnwØ5¿¬<2ÜǽØ‹•93"P’Dâ¼’ûkQ÷µl"º¤¼GrS}äfkÖac ½‘hU.æmÔ„Hï›O?Ïêc-j¢°ÆÑ‰1C4N‡OÜDÐ’˜ÖÁû\©öÅ´²°Ñ¹M;… [‚ŠW%úFl|pW|’¨Åu¬ŠI÷F´û³~Ú°j³ÃïѨqÜó¢?j qÏ=xœëG\ÅržÍÃx#èåý·—rû;–Å ,w²k¹qXíýèñÁôºU'íU!Ìíí°cË=¸,ð¨j‰C_ ©?œ÷m%`¥S Å…ª6A«Úõê_a bô|dã5mÕ5 +ß7Süó7²:ü#9hu«KϬ ?·÷þÝÐß)ÁßÙÓUP`Xõ×·ÿÅ–Xô +endstream +endobj +758 0 obj +3563 +endobj +759 0 obj +[ +760 0 R +] +endobj +760 0 obj +<< +/Type /Annot /Subtype /Link /Rect [231.75 148.40 312 133.15] /H /N /Border [0 0 0] /F 4 /Dest [558 0 R /XYZ 72 627.40 0 ] >> +endobj +761 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Contents [762 0 R] +>> +endobj +762 0 obj +<< /Length 763 0 R /Filter /FlateDecode >> +stream +xœµËn#¹ñ ô:pßì$˺ðl²‡ {Éï‡Å®bU±Ù’ÚãÅÀ[&ëý.ú¿'{6åŸ=Û4-®|÷Û§ÿœ®Ÿ§÷弜ϟ¿·1Nf>û ç>ÿ8™ÉøPüvþiŒËå+üýüùïv<ÅÉ&uÜ.tÜxøªÇÜmìeÓ!²îü¿SùþÏ“!±^6ðÙ–Ò&7?GÝŽ/“wêxAOŒYcìµ\)_6•¯yý¾‡Ï ü¬÷.N!(xÁ5ôˆ/_p?¯÷ÍRï»e*ò,,ýó\®¸ (¾ ºwüù† >ðç}°i.ø®Ñ’¸ã]‚ìüß®ø¬CxÀ¶v×ó6¢"Ò1W|ŸÅ€¢ŸR8‡y +ó9¤4¥ùüf¦ìÎþëôûßȬ9/Ó’V–“;¨¼¦J–_©­â2$ÄŸ/ë¹*Ž÷U$!®fZï\¥ ŠÀãùwü‚³³ø]âõ(bÂYÎ8´—æ‚wÊïòŠÖÚü¼~æ +WîùrÖ#p§Þ}G·#:I­-ò‚¼_Ð"‰~tDü}FÕÑ÷áÖ³w#eÙ!P¨Péå®ÏEjUJd—2¨°j;Ú ×i_¹bb;lŒmá …BPEµåĵ½pHhdp胤øÐDþIg+m‚>oYðU±7¡P”Ãj˜#Ü ž´ò}ãÀæõNšb±Cº¸E_ (&í½E1´K!áªH±>€ -ßÎݹ¢V£H»ùµˆ—šÜ5A£.ãÕ¦éSYG×!O˜¸àhc‚+Güj=º~psi¢ ¨ZL ;Î7¤¥?{ýq*„´Ö†[+hÙµ‹ZK¢¬¸ƒÇ½vñR§ò¢:ïÒäû¸þo••±“ÂRþW©¾Þ[}Š(ê1 ž]½¶€‰Iª|shŸñέó´EßàqŽ[#6¹æ ÑLÓa?:u¥ÀE–HÀû +·¦&p?ÛÕ]†A +Hj¾_ ýcM”$· ]~{átMjɈûŠ¿[ÈŒvÇ,É×áš4 ³’ƒòMSƒ)YhöFž4ü7•/Z‡P]o(*‰RW›€=Šd%¯/Í^x„@.Os¢÷]ÊÀ8šíÜÏM)æ}šŠ­*Z8`ÓÇRb©Ó¯*z倜‘W*øÏ¼ÒÁn½²Ô[|î©>ý’;ù½b¤%ÖûþRÃmаðŽ¥BãbÞºi‡=ˆâónš¹¦0ôa +SÈEö`ºÌëœ"[;gY³PfìºíÆ(Á(xθpYIP¿C}ÎeÊL]C)6¹s¦õõz4QÛ….æ†"ÑV¾!Žtk<êKu6 ,¦ïŒª:ª&wt«€¶É\Bˆmeß¾àå๠qí²»î[[ï¤h9’ +6Û-\Q8Zà,ü=¸…E Ý=@ŠÜ%Ñÿ…WÜÉáL,ñ‘jÆÕ"#7?«¥ã83¼Ýá:2N¹Š*á÷hÈQÁ2¨ÅfIz`@A÷ÂÇq†ðô°bx¯,âUÖ c ”ļŒ1ïÁþøZG‰Â+–´]o¼">ÚBÜ·KW³’–''jJv_©tÓϺ˜êd¡V|–œ£-MF2YêN¦Ÿ‰´çé*m£ÃQCLH"ÿ0Ã¥vFüÌ OB„r›2x#ÚÞ>Ý´ÌmžòÒȈð•¯@ +K½+«ïãóôÓÿˆìÌ› +endstream +endobj +763 0 obj +3192 +endobj +764 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F15 836 0 R >> +>> +/Contents [765 0 R] +>> +endobj +765 0 obj +<< /Length 766 0 R /Filter /FlateDecode >> +stream +xœÅ[ÙŠôÆ~‚~‡¾L»vI ½ÌÜæ œø"à@|“×w-g-•Ô’ýC0ò?Ý£:u–ï¬Uóß‹½šüŸ½Út[\þé—ß.ÿ¹<¾/?}-×åzýþ•Þˆñf櫟Ê{ß¿]ÌÍ—_øåúwcLÈOÌOÊÏ”Ÿ9?ËÏ×ï_Ür ×LàûŸ×¼ÄZâósÏÏ#?OøüŸðy›lšóþL×NŠî¬Ey5ð¯mûYôòþ6¿gá}+}”Úeþ³À$öGÙlÆÍl óZB\ªËÐ2—y°Ø;“°sû\É=€Ï É-á¢g%³¯ïÿôecg¸°dN+Ö]ÿwÉ?ÿ~1H¡ImÊwÓKáýæüþ|K+ž 零¤¾ÿùÁ+í0ßÂ| )•…YÉ“»þþ¯Ë¯C4Zs͆HŠ-›–›»N1ܺDÜ3½´mçT - Yµ)½·å½a¿Ðup>ƒÙé |tEój¡K´Ð}!¢f=¸~aPÞ6 ×yöÄ$Gð•îÐ!5#"uâYÚLm iÓÙèÙœÀ2YÃÞ;oÎà…/ˆxÃk¨}&Œ4m÷^*,)lRžêÛ&.‚»Gtd`ä%ÂÇK0î[¨¨J–p]eþså !¤ª_b¬ÄÏFÜN+ÉCò·‘àíÎ-xrŠg“Ø%6ˆÐN6‰·üß;0º ˆ7Üw"ɘ1¤°½A¦® ¨üÙù‡”Š>=Yºÿ‡ztbŠ:{•TãN@TÎUÔ±£üÎåwínQ¾ª‚öÙׄ`‡ÃÖ{EìH˜æ("4‰hŸm­œv›SK˜Zìâ*Å%€HCmMÄ;{©Úî#…ñâYëv ÃÏH‡j[Ã)éÎp®[[εsúäŠsJB6ÿ¡4muÁÁÑ8E&, <ýE.–t]„ÈEÆÜ[€ª?1 Š>ñçò}¡ð¹„ùÙ?Ë箊0ZáÑGpÊE‡Rά 0^û–nHãw4ÓA O|ì8ÁÐð’µå=Ñrhr§Ä-™–2xš†"ó&hÞ1²%3"€¿öÝë!UÅIƒ®*A`§ü¾ô–;|NPv8Ã÷‹€U!Ýûc ùÀQ.É<„™Ôj_°s (¸®ÜTxà·RÑåxõ†a–F,2º.bÛ¥Ãbp~ËFœoÅ©‰a9æ@ndò» A©j>éUl ´Öèú± zÍ–Š­ÒʵaBÑkžeõL y¾†rÓΧã:óŒkº°‹½œòµlFY\Ñö^ºÛ@‘ŸÍz!Tmq=½%¬ë‰Yë”e¾&VrÁ—Wøzˆ}¡™¡*ÔC‚û?û4Ô®‰·°.„è"}o¨’*óÑ~.á¿‹±é8ÎðÝÄq³ïNð,¸ŠË;1 sD°T[¸£Æ¸íÀqÖ¾º…[Þð,n«»¸U"ýHÜ®èDô9õç–TëT"²‡ÕÅXÂ<ލUÀ5jènÃ2N©´ý *@GÝîÁà•l†—lqº´œ¬íÊ%8ÏšGžñ ê· «Ä¾kä+´Ñ[ŒuŽ{Ç-?¨µ í5ò'I‡srr†K‰¸¦[íPje>ô"|ÚoK~¼CÈhÄ¢ p¼ÞlFz µèrkC=¡ÓzP,Ìûz0ÔvT“¨]¥ Ðqá6S¯ÌS‘µo©ÅS,5(/Öu1ö5ÐWìY3ª@¿’ŽU,$h“$9T­ä”jy÷ÈèãmJ´nU†Õ šID=u‰¸Ž£”DZä¨Úi³A|Þ`·”ä÷¶å”¼ž”³´‘‰¨í¦Œ‹MVŽCk«œF²1ѳ¦ììšV±}VäÉ ÏŒ½È4,ËÈuØ b 6‚Lð´¸Ìʾ¸’å³âæ¸Á¾êÞY¸LS).›´Qt"~Ztfk_tÉþYÑý,ÃîYú¤ØDø´ØÌҾ؊õ“b;+|šn1 +Õ£ÏÃ@'§Åf–öÅ–¬ŸÛá$$õ˨‚µJ{,Š1½ÝÍïm‹¥X;'–Ÿ§>Ñ®§À,Ë~Öbg͇<ìÚŽ=+aþÿ´—H¼R~ lÅR5mî™èia™}y%Û‡E†³÷Vëö¥à¯M‘5<˜¸3€íº C¦‰à‡Êjë^Èt½h7Co¢1{*Ȳ'-Åa øÜ°Æn1÷_ØÄ•ñ' àaÅ!Ù¾z ŸBEFëq–UœÓþ»ÍÙ»i(X0ƒ€]z[ĈA‹Gp’í®7‡ ÚëY«ƒ“à°= +Íõ OšC>´_ „6ž>•.Y™¸FßëòDÖÝ¢vÃ}TËyÆG%[œâ¶º«÷^`à¸×m4Cn.z°¥ +éR+42µ×Q l™¹Nɉ‘yw<<ïöÕ ˜½÷¶u+ö oÿTÍÈÜü_MÎ&ûö6F$ vJ×JÐ÷ `¨N"zZ£ÌÎ~®“lÛí@¿»»g,Ä4M+3Ö± ßÇjU” §5q,„ N‡÷ÎTÝìEöSC>Ø?ZÅí`öNCYÅãQàsíUͼׇ:Òs +VVœþå#Ö–ÿ\J"YÁ¸ýk&³+ÊãåcàŽå.ÂÝî\ðbñ[ü±5¢*uÅøÀ×Lü˜ê-Wè Ëzº¬„×yfkÕ}q[ÿ5(dº£6ûÀ©Îæ)•8‚°ðs}ZÛ»¶¦¸Êýª6Ý9u,IR,Dý ¯¯© 8åbæA{Ÿí©ßcîYŸ‘—Þœ”Mq·qÅÍþðkn·×Jaìú9p{ÍÙ0:¡ÀËîÁLy„÷cÞLláôÞfBS|ìWí2‰xÀó•ËrN.ApW.~oS.ÅÛɦÔÎfiÅ`›Î Wg‹ŠX¹ÞœX×À|5|b¹4¨j­‹¥ªe^øxŒÐÁiÿ¸L¼wº'3£ó)|i«¤`ˉ´ç¦zÉÛ¨§T®±ô¢DD¥ÿá•0µ”k,“bF%ÇVO…»PëÔrFx­T‚Ñgt0‰Ä$auÀ»žq…Œ}©;qy±ÓÍ ~Hóèâ˜W­Kõ¾ŸZÇCöa".žÐm€õi·<ð|ë`®ãˆtæÖéEä§û€ÇƒÍ׸ij}ï8ªÔ?aès +LE÷Í×ýs pÕ8ÔýòÍâÚÃ""Ž38DØÉj°³¯w©VwﴊȃžB➥ð¯÷jÛ‚F¿^ý«ôqÿá«>œwA߈wZÈ0}åb ©Ý®ñ±Q¤<€Â`[&üÔy!6÷ânloX®Šì°*cñ}+¾Ÿ1> +>> +/Contents [768 0 R] +>> +endobj +768 0 obj +<< /Length 769 0 R /Filter /FlateDecode >> +stream +xœµ[ÛŽã6ýÿƒŸŒÂ;%`À²Ûïúry›—ýý©ºR”l z0hŒ»›,VºÙÿ½Ø«YþÙ«MÃä–O¿ý}ùç2^~~N×ézýü“VÄ8˜ñêsY÷ù÷ŠƇeÁo×ÿãrùúåúù-Oq°I-·.7¾|Õå??mlʦ9Ⱥëÿ.Ëç/ ĺٔŸm9Íapãë£iù4x§–/Ç£`Ö;/[–/›–¯qý¾|.?3åû Èy‡½àèøP˜_¾Êþ¼î7SÝï¦aÁsé÷ë²ÅÅñ Ž»Ã÷ ñßï“Mãr>Ó5‰'ìEEÿÛõ<ë€^Ûq×õ6 øëyŸ‹E?¤p ãÆkHiHãõ›²»þûÇåÏŸØÂìØ1±mQÈÝ7Íðr°{Ï­™ôn4–hô:šuË! I ùÔ'Ö˜ÖßÛ¹•:§©È»/¶5×i˜ROrï +b`³ y²7Ð ÿ/|8ÔømåÛ"¯’÷ü|ûÑJføþÚÍ%yø~êï+V€ôëþ4–ϬÇ/¿÷xðƒ8:\ûç 9èp&'³¡˜µŒ½= ÍH#ŒõLÚ#’Â?Áû02†$èdø> å$1ž,4)v|zrý^ †âL± UngÉCZ¥>Ö¬öRÙ?oxCi0vk(°¾FVŠ=¬  +22Û³*g(Þ¢­%¹òÙ +†&q8zÂÎ^²Â´îëz‚𞟅6þÞà9 þg0 ,öLð3Œá`D!î){ lKB#­²[åaÆ¢ø¹ôj\áw³àç¶bc%½=O¸PŠZÐЃoÎGœïâ,ŒPÒYŸ¨/Œl /om@éI8Ö)ã,zø±(}…äJ´W +ù Fƒ±GÌv !M5—·%MɉE1…ø)a˜j\ÉÔ=Ó&‹Ü‹iS®âð9bÑ(®¤_{_ùóãêè5JJ£ñ€W¤HãF_çHU•#­è!>#ð7 Jøœ‡è6X€·2•Ü yºMœQÔ¹ÃÓ;†ñ¹¶Í­]æþÙïÒwˆ§ˆî¡¬[î«Ri/FŠ™qÚ¤FɯøL©{cÇêtÒ¹4N)kª±YçË¥hG†¡SŠEeà=£I˜ ŽÙ3ä®lº(î[aˆ½ê°ÖÞ²%éiYjbŸ1¯Z1òóNŒüÁU!† +ßE(“^‚!`©¾KßF ”}¯ØÀ.4l‹rï“]Ð,B|˜µŒÐ'ED]¦f744,Ѩ±­Ð‰ÈC§1ðãTbþoèʉ–eG.'­4¬êVåÿênºŠnåÞÚ­9™íÊî¸ýÐ;ÇšÇÔ©ÜÝÛR·ÅÍFç/MÍFÕV^‹q˜5·Õ\…ú™AWîoÄXîÞE+Ž®†‰¤º]ƒÊXQa°×?»кŠ^&ÛH†Š»æA±ÈF5‰Xޱ4 +¯]¾âmë…aîDœ8†!“]Õ#Ë +ŒŠ‹‚È!¼®@á½tß5>õ`P,r í³¨ Ä%54"ŒTgô‚\Û†¿,K#qxe!¬ç>MÃ4£Ð)]C3yÝ¥ÌÓ`Eß4µy¬ÅnþR¡ QÖñyÃ(ê‘ÖŸ5iu×·-Ë +gߊ€xëðls€! -(Òaûà ¤ar)2ùœ2ìçîÍHÐ_Ç÷«ïR©V4¾-°d’ –ÌG1‰ž9Tko=ÙÝ •ÕÎrþõ²ªŠGŽé;7.Û&‰þ-ù~Å6µ‘Ǭ"Þ‹nŠ´ø„ææ¡=Ó=†„ÖŠw’kvÇ=¶Ï!b£ˆ…ìÐkÍFœ¥ðZ’¨ÚÌ|˜/ß»ОӡBžÆãúƒæ¡øûì»4V¯–=ha¬™š˜â¹ûNíÆTòŒ¤Ïä±Î…T ÚhQçîFù0"¢9¥2P¹ƒˆæRsNíMW ‚Tcö¬œ×í8/9càZ"Û“ˆ¸MÒf§ÒÌ)‚–lÌÜ÷`1ÝYÙ$ÆyO-£ÝF-¥¸J¨Tú‰Ã(BËNa,Ù ç 6jT@Næ…´ivópÓåb›ŠuQGÍÚŒh–Ù¦ªg?E‘²¬]¿çڶϼ–>–¦_0úMw†1w² ÏYÄe¶|è"ËX£]Hm9ÝÍ|‚è¡'ðº3ž Yžz,W³¡TX‡7­€WC ¾ƒ†§¬wø:æ=KJé@+–õmÏ»ÑM°ñß+†’œ^žÏˤ´¯ÎÃ*9ͯ‰IÜåPa†wjpQHoKÀpV?G‘ž; ï3_ª:³)4K—ÿõè®å2ÍcË¥u§,WrlwYÞܾ=E™^×?—8ŸöPvõ¾¬M /aF ÀqæØ…›‰ÃMëNÁ­X_7=i Ñ~ìÆo®3^aÐ+·CĨƒ½.:…4s{Òª›þ<RâÊ~OY +ü´àÆÈaÑív-Ž‹”rÍ´¾ùéMν7&ç¼þì8LÄuÁ÷LÎ{Á¼íPdFO}°ri"ÊgQMÒ\J -¶¾Â ¦™©o,(;ìöÚO³a´§¿Ã¹º¦BIàŠÐw2eÖ·÷i{ƒ†V=åMAÝmJćNÏëÎø½f_ ]÷fÏ] ËR ¶²½‰>=)!#GDkžÙúœï2³(𿸛r!Š7#»µÜÃ8 h_é‹ÅZsä†"µmgukWç·é¦"™i³ò+>Y¼|ÇÙ«YÚœ8&pIçñÉ/Ê Ÿ=6uâú•ßm÷nÛÔoÞ¶ñž³å…:MFW6×Múµ·x¥ôÎ ´÷VQŽ¥cº³®Ðäe?º¡Q—ݵlñ'ËÛ;³Q –½ëãвatE6” 6Nb\ JîzocŠþ­x/Ø ‚‡ÁŽ× v;ì~M¶µ!÷F¯¾kl^Õlj½Ù¥:”ßðߦ46¹<#÷>qµi/ÍÒS÷³RL"î6ð“`mvê½2Ç?i †.ïY\k™] äCŽ-Ö²@%ÂW[ ÉïÔ{i ×Kõ=E¼ËÌí½ñg¼|‘BD§5™REL¥ '¼|©Í9Šg~g¬Œ #~{ß³54‘êJwâš’¤l2rÇo¦{Zé\–[~ÿ05§ÇjHì#QU0r”?…äsõ$¼Z”ü"æ|^~½ü2ûÖ +endstream +endobj +769 0 obj +2808 +endobj +770 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Annots 773 0 R +/Contents [771 0 R] +>> +endobj +771 0 obj +<< /Length 772 0 R /Filter /FlateDecode >> +stream +xœÝÙŠì¸õ úê9pk´Ù² ºª»æ9¡ÿ`’ &û’ß$ŸU–\ve&ábººZ::û¦ãû¯7{1ùŸ½Øùš\þôÓ/oÿ|»}½ýðH—t¹|ýL+¦éj–‹eÝ×/oæj‚Ë ~ºüÑò3ågÎOÌÏ’Ÿô§Ë×?Þ\º†Kðõ×KÞâmñùyÏÏ-?wøý@|Âïc°ó’Ïg¸6*¸Ø‹0ò>kà§]ϳàåóm^ga½*|¤Úeü3ÁDö·rØ‚‡Ù,/jc…pÉ.CÛ\ÆÁÞàì Â.ëïÜ ð \ +×É)x6)š}]ÿÃÃNàBʘ(T¬»üû-þþfÂJµ)ßuDoüuÏçõËuÖºâIð. Ò¯Ä}~ee›*ì°\Ãr ó\6f&Gwùþ··Ÿÿ€ÚhÍ% bîhdœMÙÓ¢eßA¾ï ¨øœ‡z5 ÞûfOßáÉŸÝ*êä®ËÂ:Ùn ËUŸòWS°•\/ÌǯpmBP–aKµ]Ra•&›TË€*í¶Y+ÃÏZ»k¶ERôÚ°qNëN{'ƒè‹ÀWÔR#3˜£ü×ï<Ûd]¿lÔËçÔ‰ÆÐ‰÷Uz ŽºYq• „麄ur#6 +×SPYÀM$ ÁÃÏ þ¨âšbâH^ R TÖ”3Báôž¸AÉÝTt °$j?Áo”Ÿ¢óŠB;ek[«ŒYéæu³ßj‡M¶lQ‡2‹µY»ÝÔQ«xuíÆ$£DE5NÐÕ‰]¢­š·£qÀìaòàö-ï#ñ+4—¹¸ÃÍão›}vŠEWÔFÚg1æÜ»¼¤=U +¤gJoæ.3åiÑoÑ\7¥«wì[8ÖM¨€ú9\ý¬ÁthNHš®®Á¾ä€•8°¨BTµ¸êlµ¹N­ÐïK³.i~dœB£îm%®š¢ç¿‘熈Q‘ÅÚD‘w&ÄE«¢ÎYüì^XQ¾£÷׊3»”ü£§`¼®(˜'=A Mì)—Fmä5Å}¹ÕdªÈ-êõ•…˜ØÝÛa}MÆÄz‹{>z,Œ!gR€¢—\·€ÝÁ1%lyT«‚ö£ËU‚¹ÏT\vЧß0b©Å¼âIðæS¾Ó´µ"ЦàíÕ)tùâ-çÇÒ© +Û ÒÉ>ÑRŠËâ9&Þ¼/ZwJè¯pÞ”ìE‘À©T«ÔRbèчôYã“ðAÓ˜5 +=ø¥¾``û¬¢u§X%Q öÒ®¼ôSÙOÇ™LŽt“=6å\´“À#›ºéy͘Ü`Ç.›Ø>›hÝ)6m 4J‘4½¦Q¶OûŽ›ÍÔqKC.cJŽùîÒå6ÁÜg6.;Åëö€Õ’¬ß§§e.q~Æê *ž&6 €»|æug½…Þç´"ë÷Âêhº.v”@ªWÅ@~dð}¶ÓºSlW¨»_3O°7$³©›ç Ïë’ENM2QÛz³*Á›VL¥-D”ÒI2}ÒºSÜ@Ø"å×K/&?“ç㺰 óu='.se|Æ>qÙ)þ üí8åÀÒó¶²§pužš2›4µ®ÑíÔ™e!hìÜ¡wZ¹Xw›+ua´fÙ%{ÀßAºM"…ÒbÀûâ¢u§ä%ÑæA+°jö9¬ýž9¯´Oú¨Î|fO,ÆŠž’;&–®оhݶ3÷DUa;O4¨²ÐÀßïpÐmйKÖ×Zl +ßýø…Cré[b$°ÃBQÚe)¯;£Ù +Mî‚Ô Ð(*}IBQµÓ ¡£¿é–êL4/_êVÛ\£Î#†ÒÅA¿ \³Ñ*UsßOnƒ>GšÎa¹’KGZ­M#Õ×##{‡™`§Ò}ŠL°K‰‘šH2ÆM«êf[Ìá펊®§´©ÅU)$MžiBíßa… q‡•V·`ô桵WCýçÞ”Uµ$hÑ ?Ä]m™\׊P¢ÚÞ\a†‚õåÃwÐ\ê‹WvU-éÜìÑÄÍsM÷W«[EAëðêJŸ“V1`Ø‘îýóû«à«åþŠ·ž½¿R‡ž¹¿Ò‹û«â›×¨&!Ž"P7@2ÀýIëNH‰®ë¢;Öêý@Z.G{9¿ç£5u€T\xŠƒ¦¦ŽSöiéÔÏijØorM!AÍ2ŒYÓ-?{¨Pæ ŽÉà­Ë‡ tÙÕä-›àß8¯Í‘Nzù\ÂÙ¡©dÿWQPÒduÜ€1­ó<‚%nQž&‚W‰/EÁIcW5íä`Æ& ƹ‘¡?±ÉT÷{a¥Éí:P$È9 ~Ç8°sæÂ‡’bšíóðçC-Ά¿ +÷žˆSéÔªSÅ?oê —Úø[Ä?_ÇeN®iÏòÎ)8­ú¦-"–\'ž*»ZÈ›8¸òF‚~/[êÖæò:Qxù=ìBì±|ilƒö}6Ñüãf.! +x²Ñþ8¸¿;×ÐóãÖµm&}o?׌™—}Ó3 ž~ÿå¸=¤/HuÊaI2tÕ@ùè¡Ç¡Æbä=.gYÔ#‡MJjÎ4nçp!éRhZKnc8z™âÉM€ï]êUÎoÏèsž×á¼B}‹{ï¡g¶9K‡»¯q2Æ^J«á7ì±eæXm|>ýµ²ŠöÏø€]ò4¿éòÙ—óK‰Ùù¾Fåk ¸EùëTtLJaσq/ˆ´Í¦BX'›ï!Ug'!¯¥>[‚ïD»‘! 2P˜aë³Î_FˆWéR‘iƒ•+ÕG`k¹@I¨–}.[Ôn4§©) +\hÖÉTm²+þ]DŠK™·©v>¼4PmÓ|í4C1KÇ»˜¡¯xÝ^è2c# (÷ˆ„@ädžœÈ{çL²Þ~`›„>XÐÕPƒeA$\xH«‹Ö{t4MÁ„8àxâ°RÁsÕ4ŸQ KŒ®´\O9ßgºRŠ‘xjÌË"#rÅçt²àMý­ýz˜£„¯hý†«†Eˆ±ë8:¾×.uhh£b^Øv‡E²Ï.û¿íàfÏÎÛ"qüåGÕ²v ö*“³¯áôfèòZF6û–9Z§É’ËÖ™>WŸ«'7—‚ç«Gç:½4Mžž,lv#Éä°Á9q9~Êa1ò¡á,æ3òúŒ†·Á[çI¥9Øà®fù‡Áª“â¼Ôv’ôAÛ©¶žð…2a¡Òz°TCu·—~B{UŠ%Ê>„â'®Ú öt!XѯŸe1™ÊՎנßïB¾¢ûØ“7}–í¼¸î/x;ð<Ë×ýÈS:¨9{gš7ž$6ÛÐëBé…j®Änllµb%^ó®Z¡a§TlUwÊü&TÁæN8ï ÷¯M½'ZW{+@ðAŽ3ØTRþÀ¹h7°ª€ ‰t˜·ÉeªPùô☢Jýá–ÀÌ;í#kcykKïš4ÑZŒM$‰}°dÔ+ M’¦¢,J¸Ÿõ»œ¤e‡«äÁÄ"n±-œ…“F&µØç–ÎB.Œ¿“!5€ã&çõþc„k˜j "2÷ !7Ym\ +§4ÃX1Z¦PÚßSí ¶SÃ!!H’©Š… =¶Ä«-y®s£”Æ Óúh”M:Éñ¾d#Ò«Þ{J;ÎÜelS–!rgÁ Ñ´ßv»š9—Ô +`oN¤4¬FƒŒÃ&œ4`‘âa +è HãLéù {¥rìÚÖ¡££²iáJˆY&¥3Š,}g¬ÕÓúrÉ$ÎW§Õg×å ¿¡¯ïºú޼ô+BP˜óX©väR×™‡:â@tsl•[s%RïäÑ¢}„ „\*@†%ñQòoéëh" }Y£½òO6yeyä? ôͧfPË”ÀÁ´ F§ü\LG±`Å¿g9&éÏÝtuÌÝ{–¿š¨M|Þ–%ÚÅ/µÿ¤4ÆmkÓi°tLf™¹´1úÆUÝüša!«RvåšÆ\*¬–çÅEigéSAŽeÕÿG!&ì|¿×tÈc`”E–ˆ¦¸|{âˆ"¢PQ/ |„ p7œ[õª—~òZC܈ƒôÎ8°§óÒr³:k±ò•h +OXNB¬Q}àM•ÔÑ¢8‰‚QùÝCµ”Nêëîb/øåŠþÏoÿ–2Î +endstream +endobj +772 0 obj +3272 +endobj +773 0 obj +[ +774 0 R +] +endobj +774 0 obj +<< +/Type /Annot /Subtype /Link /Rect [200.25 177.65 294 161.65] /H /N /Border [0 0 0] /F 4 /Dest [632 0 R /XYZ 72 420.40 0 ] >> +endobj +775 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Contents [776 0 R] +>> +endobj +776 0 obj +<< /Length 777 0 R /Filter /FlateDecode >> +stream +xœÝZÝŠ+9~‚¼C®ºŽÿ]Ë@ÒIîú fw.ÎÀœ›}ý±lÉ–\®T:'Ó C:?ö§KŸ%»þ8è£Jú¨Ã´˜ôî×ï‡ßç÷Ûr\ŽÇßêï'5m„qßjRÖ¥¿ÿ©”‰JYóËñã¿uxð“b¸^h¸²ðÊÿݴïEÕ Òæø¿Czÿã ÀçÉ +¾[kÝdæ}Ñuø2Y#†'ñd˜VJŸÓ”ôÒ!½æòÞÃw +>;gŸœxÎTñ”O/˜Ë|µäùf™’?“Iÿ>¦)Æ O(î?_⊟·aÜä7\%=qù„æ(ü¯‹ƒÉùs,¿Áú½ºŸczÄ|/ïÍÜæ@„ui\„ˆ”NÐÕ Žç²šê&Af È@(¤kâ¹M÷[ÉÛ'DH4^æ™R´²9äÙ³æ§Ð!·X„xK1d}ù¯o+§ fÆ@dZ`óO8¯Ä`Z—˜'m"³5E7ø@èå[pDœtÁÅO¹ c•cçÉ›N޾ÊeH<â^à‡šÛ9°®%§Hw ðe‡XÉŒtÅ\°è²X\fÎøÛBK¼aʃ^==æ,òÅçuP¡5uò,c ÍL'Ãq;¾‹až'QƒŠaÞ[~ÝrÑ\0Ç–JÿÝJÀȼòò¦Až´Ž}™*@YÀmZšÉarÂêÐwZ‚/"§g? Á z~IZ79isU/Oœ1¾ÀÈæÆI­±#£nÁªÝÞÊä˜ =! ɕٻ4í2ø„´K›Ë\y¼º ÃVRÛ†õ ånÕ«£eû™¯ÚÞ´oƽ -óÚ|ƒël°²È^¦*ã†ùìÂ:ŸIý[éºSßL1Hñ©ö¢Áwu»ùù>¶m-ûß•ú4ûYRÓ6zaÕ½÷8†Ö(¨ZµÐ¼±TÙPÐÅ‚oÎw¨"D/-)¢åÜ–=—}’¼78 âå +®óª…ÝOˆ4­Ü[Q„œÜÔ©«êŠdÁFÎ*3ÌÙKüåïÐÈ1,—`“¥…·7/¶Œ+,Êʧ8§).ðÛÈ?;–ã(\†­Ø¢"†Q³rk÷àÒó„ j¡&4¦"Ž"ò„uØ©mJ’VC +|’ö|ˆ£¼…&_þ„K8ø—¸D|Ö%^±Í¯æù#nÐŽmŽ‹ÚLPtÄêá{î!?¡à%™ [ ´iByÖ-Ö²]våsf,±aª;æÐ|¨_j£”êZêš¡Gkˆé¾4•4†ü%„:¡ÂbBÉðYŽÓ +Z¡œe»–^u&À‘Æ>0œtV×ra‡?µÕ(‚?—V¡RäÍ~Lð+B|2Ü23–™‡œù)7HÀ/pƒø¬fÍxÒìÂç¸Q€ÿ•Ü(=Ë.ðó‡ê +Kg*¬*Õ²øîÍ@ö¾ÙÀÏP1J€gÍqÕI-Àïô<à-1%žd*Þ8NB³¹À/I!ð³n*é¨tb_no,4íÐÝè1dÝS9o°÷©`ziÜO’­Ú´t³M'z\Êÿ|”éÊûÚ·Á˜ËÐÐz·IÂÿžMª]<æÿ› N8ËVtÎu£ü9³!Ô£ÝÎéNç›!©Œ=N36ÎuºœYˇ +Æùá}á*” Š>¶^ûZLà;y ˆ¡nåÕê9ËÏôD'.[ù¡Zuö«Ô‚{¸ŽÀO2X¨\k#¶MÃ4ÚÑ Mæ /5YÖd¼îL{\_,dsß1g|Ó„z½.È­Õ/p½µ:t^ElýïÞÙte•3cB~æßõM÷nÚ@k~ƒ¦ñbP\F“îúl+îÌ¢Y²~j!üõÞVòîÉà‰ÛºÔŽnšù¸|Ÿt‡ãqu„ÞË*Yb’¹X±•±†0÷¯q$XÛïÔªp–2Î[[‘eźհk^»ŽŠêþ„³ŸkèýàjÜÁGDZ÷.³~®²¿¢²—Ÿl€ŒS„Pëè~4ß)˜ý¹åß=ðb¨/Üê_~veCn™Iâø|É?q­îZ¥€‚>lqvp²Õ <®2Æ<Ô ™–uðPJ‹Ø'…°(x +¢ xãwê-{äz©|â&´2U«ý;c1ñ¥$42¢¢Y]83^_]%ÿì ±QžÅôÇ‹tè^›à»YÀ·´¼¯‚˜¼Ée=ÓK€JÕå¤%-ÇÒvÃB#èy–ÂxÇCÔmß™kGÁ”Ÿî8«¶%o^S ÁϸC¼ÊQ¯BÈŽ÷Æ;Ow¿ í®TÜͨçl)ÅŒö–%Y»ßßzÀ`›È7°í¬–žá‹rée_ͯ­·øF +xa/«mèkNݸ86ìsþýŠŒasÎÏ÷È·1¬î›o…Ãj½º®¦pIõÌî ¢¤ìëjªwëf+ð–\F +¼Ÿ{tÉ)xH¶œ^ç°vn¶ø\©ç¼z «ö'ݪ¡˜x\Ç%¬œ®åùÖãM±~ò¡[A/¥ê(×Ì®õ iæP»Eü ŸŸP­•¢K‹¿¥—;±ð%LÝeå&ƒŒ¥7y‹}÷y šƒçÁúEEu™ÄLd&PÐ_¦ckásâ,{–K¸%ÂMé:àL%­Š«ö¡$S­ÈÙzVÝQ?oUÛ£U4Ыê=6÷RSÇ^6lÀß÷Öþ±°gã:±êÂ3`?_ðõèùÏ%¬ÈÿUk‘/%‰—ݨŽÃ1ÕV¾†ÜžÁCO"f^´î#¿?Voü¿ã|°®©t«Ç3s§5j˜öÜ¢T;¾Í‘)®‡þ\«$ +endstream +endobj +777 0 obj +2260 +endobj +778 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Contents [779 0 R] +>> +endobj +779 0 obj +<< /Length 780 0 R /Filter /FlateDecode >> +stream +xœÍZÝ®Û6 ~‚¼ƒ¯ÌÕŸ% ÄÉÉý€óÝz1 Ö›½þôCJ¤,;vڮÑ“D¢ÈÿTþ¾ÈA„?9H;zþûøùò×ey¿|xøÁÃû§²bšF1ÚÅuïŸ/bF…‡_„&)àUæó¤zá|ÖIX/§D¥Vÿ pûçxØŒ‡I F†g¶Ñ˜(8…K”m*ð 8;s~ŸÈ-À§áä¼'ÅèIÏdÖiý‡‡œÅ8a¬H5üs ÿ¹¤¥ñ³Žê…­y~x]?–ÛŠ.ŠWA‘*+ñí=Û”h›y4ó`¬ÈN _þ¸|ú ­QŠ!(Âv,ÒY÷ƲlIz`ÏU]Ç÷ÊöŽàfìúï"rì],-j-Z¦|ƒÞÁÀFÕlV…½dú÷lž*°¤Ã{ÌB{TcG`9Í£´ ÉÂŽÌÂé ŒIQÃz€àX~ÀZ ¯DZÖŽ`¦Ñ5g›êuxHò 8,*zÆ `©·Zº¯0™w•¡ôÙÞÇ—)ÿoL†/~¯,D Â\³Â#MÃÐÎÄÁ V‘r|Ã,Éêäøõ`U­§lñ²1IX?‰fݽ¹¡^ˆ?²Pñ]°×jÆQ;Ú5ÑFFc鬚uvl š:fñ?¤(·r69…a±ͪK85:so÷ÔªàsyÏ–Õ¥¯ÜÆ´OöÍ™ŽGÍ6¨8m"½W¢Šõ6~fRìU^!’\«ó¤W|X°IŽ„¼éfÚëBl|ˆ´ŽXÚTZ¿_x¼ +Î÷ìßq/ì™chDx99%}ŒÈ8”ÌìÑÏÁg1èa³Iǧî‹Íè|#þM"ur‹;Ák°j¸17Ú5›Úu)%‚TE¨70¨øúˆ q€mª‘êÞdžµ‚¸%’<(¡FÅ‚ÆíèjZï Ôµ=ÕAbÕg¼cˆ„ÐW¢M)µ“R«b<"qCŠ%Î=À±=Àê²3€mqú{") 6¯ûÔdèd‰™.\óóHkNU˜“ú»¡´- d qþÊÇ8®¬NMm,­IƒŽ.h•ð.neÙ)è×%l¤xÞázUXÑñ É/ s6q†Åž€ž¸LXtî J´Ž×½NSc؆‚<Óìz +µÊi¬ôêÙ˜Ÿ\•E¾ ·Ô¼¼‰Íã5z}\²ÚÑëbÚÔyU?²s &M^¨ ©AÝ!/dS à±¾*ñ]O,ËÎV`ŒûƒÞØå~Û£Š×BUWZ#—'M8b#¨¦Êþ“¼€¦6ÇÆ¥fh ǹþйÑq¦Ùœòƒã_›E+Š}× ±0îÝ4jË·Öï‡ÍÀ(’÷ü\9ÁµBÓAä“fg. (sBSÒÐÆìCKuÅ0¬Óöÿ×ìÁc­Eß¹ÙCÝ{röÀ=3{à¿ÇìÁ(KÛYÇLw²PwîFk~ÀѺ‰ÿ!“#||YÅpÒ y»'Ú™ ¢T í¢T–ÍiœÓê²¾rš,ÕNŸå5†(“P”ÉBqáƒÍõ*œ½XÅ*ËÏgþ*ôöÓÞS™©Öàky(—ç•Xxµ½&J«‡eæˆæŠCOñ’’ò£«æ;ÍR¾Dê˜k¨Ûjd’dðœÐÎÔHb»5¬tÃ6£k•ø® 3;:!>ÖšTÞD©§19¥›à"@MÒivÖ‰)£Âð¾ïY…Õë½ÀêiµWêM ¤µÀÞl§:Ü:¿©Ã7«WåJD-]¼^3§Xo~M—g0åRÚî5ÚmWÓ£òíÒ¹tÑ2Ó8—tâz€Å|zèද Öã<Ý#@™£@uÛ»ý†AͺÞPNõŽj‚tkžg)“ˆ×ÒÕ+ëPî$ °­a~–ô÷€lLþW’ëÏÇÐRùùÚÖB‡P³ò Ý…²†ØÐ¹ö‚ïþËþÂ(Qïø'Òg$àý\cr¾WZߢ–—Ȇ:'úá÷\]¯Œµz­®¯{OÖõìÐ3u=ßø=êúF³.ràçXåîȵŠnðá„j~L¹Q”¼£Àû­Î„Q¡<¯/ýI•×3Xz7E¶{'FglÐclÝ=¿Ü¯m8`ëài:FËs£»~…«B#?¯›—³ŒSÁW^N#’ü·„Xò÷îåZáhùî›õ‰WþšPÅFã®–_ƒ5ë¦xV×õKÒîˆS 9Úu©p0Lê…Ññ&B¼Z88¦¾õ¼ wœö&*‡Üô&OB-–5t…¿gCåÝ;Ê‘¤2ÞìÌéw`Åì¹ýI—‰“ÊR1uËj‰*Ðj£<—¿¶; ßÔø±m“4µ5Ñáx4èé$PªÍºæÊ$FÔùm[¶MéTgL‰6˜øEž±·ï´©{?·|õ8ÂÈŽi–UgM“‰1o™&S˱zqŒ ªÀß.ÿ•:  +endstream +endobj +780 0 obj +2146 +endobj +781 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Contents [782 0 R] +>> +endobj +782 0 obj +<< /Length 783 0 R /Filter /FlateDecode >> +stream +xœí[ÉŠ$7ý‚ú‡<&­])0†®ª®û@ƒ?ÀËÁàÏÅ¿o…2B +)÷œ)wÌPt-ʈPìñ¤ùû";ÿÉNº>¨øî׿._.×·ËÐ…®{û#¯°¶C§=¬{ûë"z¡M\ðk÷“ˆïâËýܽý™—;ÛKW-—– ¯´üLJ´ #/FRuÿ\âû¯AlzXÀwSI½éÕ°Í:/½VÕraóò—øºÆ×M ‡øwÀ÷vü^¸‘¬ôøù5¾ßI‰ëMÅN+ÛSñ3*ó3HhúñyÒó*ôQßqË¿uñeª11Óç;’xÅÏËdÝùº¢ÖÔŸ%°%ªE!½È_‚p½´£_cHü^ߢƒYÝ;Ó™¡7CgœëÝÐ}½WÝ×ß/üPñ³ºŽ¯´žÌtרQR'g(~h*»ú¢Äüþ:‰d¥%SĽÏZ@Ö°Uep‹žE‹Åß$Û–ņm)7>—ÞËñw…ÏRy×ß?PZÍ>“jÿLjæ;”$ÇÀ¾ L6r'2Q„¿°ýÔZBw*æô–!{‰J6×n²07ù‹,µAþŦv à묰‡˜ |eœ—cïŒI>˜koi)ðáıõR”o4®K`h[¸É° ºa k‹CvÛí©5‚é=`«ó¨#—¬‘"÷¶¾Ë´†'œÝEÑ/âkG¹’,Ä“1zLžÚé÷ÙHüêîC+^®‹¢ìì1Ų¢!s=ÝB +š×˜Á*6–KÞødø ~޼°âwŸÐU±õ8]šô›–YY˜æjþ5´˜;¶ÂFbö–ì™»©…‘;Ó"T +õœ±=6*†RóôÉ&êµHÒ +é‘‘€AŠ0¨ðJÑuÇ «¶£+ruûË|Y¾Zå9Õ2¶EžÐ'Þü( Ãzó"êª|´Â‡B7Wú‡(ÙxqÔ*þÁ6¢GñÊÛÊ΀˜Þ°ºåÓ,˜Âت +=?`ý/ µW¼¾]þ¾|¹ÈØÒF¦Fy(Ò Æ')¡Oþú{÷K÷åòyíd}(ÊmÌ$5ÐôÉ­õBÙ€í&Å=#Î +x2_Z?ðv°>]ºãÑúh€f¡t“ámtû¨DÏ 5lÖ•¯}r~b§jÈú„·é[B¨†^ã÷æ\•OäŒÈQIeýzÖàtÙüiƒ§I{Ô”1°t6EÌ¢.{L©£¾òñ;=`ÊÓ @}.úAèaZ·ŽG±`>¨ªx5z¼ÀTü?@ð6Fv¢ Ó¥¡å(:G Ú3O‰ÏEL—÷¼¥×iœªÃ,ŽÎ±‰d,„£•SA«øÖ ½gÆJ³ò&¯f¹Z ?¶`õ¬!D¹2çÏcº6Û ðŒ~•ðÆÊó pK#gÎæ;!LÒ] ü¦²•Ý À£®¿ €GÝG®;øåëÚçŒÎ#ð1RT#uiR–!x‘Q„ h] Ù¸f ÃüôßCæÏÈ¡9j[_‘ ¨o8= +wŽ +ß,Ü…t5‰gË=· ‚‘†J°x)q7¼Ï’UðD|GžÏ¬Û‘YÌÊsU*h˜DØú…*\ßýOî”OÖ»K䮿 9dy!ËúUCr²%Å=§ùoN¸4i®P樧€ ›ftª`æjø¦ò{Ķ‘­{—^¾º›N4è„ãÃÞÊØ}ïêFùp–ò¦BÐО0Uä~$ +óòÕ dDßw_ë› ^©$Í àyàÆ[·£‹Ö}UHzhe‡ÕÕ±®xÍæ†õu_ˆmƒœ¹zñ#8…mÁÕŸÒõ™‰€› •nrwsxjWÂôÓÃöCC;y)uj–=×h}ÏEèÜ7 ,5{]®*:¤³Å¦'YºÅ¬ÙÝØ¼þºgf—ƒ/˜6»â±p¾ X[ŠÜ8Dƒ8tf8ˆ\3"}è"—éO0K¹¨”£z•NÂx1“:uÐôß3NN÷É*QŒïž²J!°nΈÝ&Ûî·fö¦o”0ֻʛší'4´Ð€±U4äÊÝ9ñ„ù¾™­“¥ì°C+Ïûâ›~×!óéøÀœúü…¨Q%‘z¹T<Ì;oÓR¥ƒëêÁµÓrò²~ÝÉ9Ýåfí9c¦T¦@±Íå³Iå˜l¹Ÿ Gçç×5ÌØ|ÔÜ.\?ƒˆŸ4Ã÷ÈñÂpGÛëÆáŒžžã«]Ìñ°žãk*4BÐf› ®Ú·`¡ùÌzìÌ­]-|Î^f«RœÌRže'"¡<¿œÍSÊÀëÛåóå_Á K¶ +endstream +endobj +783 0 obj +2578 +endobj +784 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Contents [785 0 R] +>> +endobj +785 0 obj +<< /Length 786 0 R /Filter /FlateDecode >> +stream +xœÝ[ÉŽ$7ý‚ü‡<pX»BÀ`€ÊªÊ»ü^tîËü¾Em$¡ˆÈ¥Œ¶ÑHt-EQO©úó$Ï"þ“g馠âW¿~9}=]>N?]Ã9œÏ4 k'1Ÿµ¹/'1 £¢À¯çÿ!LüØøqñããgŽŸðßóÇÿN*Læ|üvŽC”iCtü¼ÄÏ%~^Ë÷oEÅ{ù~¬ÖÍq~Ô+=Ó{-c«Ž8NŠò¿ÌóIUôÅùe”“E^Ú¤¿®ZEûã‚Û²„Éæ:™tÅ@0xfÓÌý%l3’,\^ŠasùÚ‡¸b/ß¿çùÒ@Öðù‚™¬bóÉÀœ¢“üOWi»5!î‘¡C¥:ÿÿ¿þvUCv‹€Ÿ­`CèÉ™ýÉQ~žwŽnÈÐq'ä{’ÿˆh´I·™'3Ÿs00î‚Wço¿Ÿþø¡ÂUŠsÜ)·YoÂ$]5«aV¾¸²º€¡û>ùÿZöFçßé÷²G/ùGMô…X¾liã"ˆ=qrnÈÍ›Ÿ¨É5p#Üòùà*gÙ­±Ê¾vrzšéÜ réDæI Ý•–K Ù ²ÀS½d¤%ÇŸéOU¡†{¢åä¹½ïÌ''E¤À=Š øIS 8˜})+s°A~sø ªŠ;¦ø© +bÅT}å2 +~Ïl-Î_G%lY¶<òCq³dLê š|v­*®Ö¯‹¹Uäm3SeÕs'àÄðIÑ[¶P’/{üZö´ìs=Ò߀"kâ‚ô ¡JŸˆrd¾ÊíåÈ© Ê+Il¸¸ÑÛ`óN=9®®ü¼ÊÉÁ¼×l«z[ݼiJ€»{†S¡è¨úl>«ì÷»g!’§˜—î=)„ò¡MA³nDz-aí£Šæ®±“RâÛŒJBB],*“ ™R©Û¡Èu:Ï×àÚ> «/'¾ ýß¹G±äf;Í{´Ú„F¬ÚÖH•ª‚¨‚³FqŒVCÀRye)àaźì$h¤J\»\å>Âa fbÍHU#v=arÞ¢:'lã[OÖñ  €_Ç„¿ÍÃ|Ò9åpƒUòCÀêxj|ç G[§E_ÆJM +´LióÀŠkµ ÎïºV;) +Ó;¤È#uùßêüY.<‘V®·]êF‰9 Õ$ غ]AÜ"UòHŸÕ(YÃRÍîëq'ÔŠ¡k%9obYöI³Ì°ƒqÛ§Ê"+¨Q3¬êÈþuß ¦¯ß:S”דv;+ ·hR_= ´;EŸêšê*ÂÊÍÍÕ΢£f +Šè‡Ÿë£ÁÃU‚Ú‰\ÔN`=$Åü…ÎÏ1shïF~%:åE°“Ÿ~1½õ»<ŸE†,Ÿ}”ãË|¾IßÅïh&#3™8 ýžGEÛÜRŒ_Ck@ty‡MøÅ5 .­ñ®/­l­ãâdëGr¨¸¾¶GÚ·sfqú—i;7)CÅÉ=b¯s{“Ko\©ìz§­Ih\“ÎÉ•~Ë<´ßµ¹þPR}¼àÔ~P¹‚Á{µâKº§ ^ÞÑ×=Z +®Úp(¡Vˆüwð„©•ã¦ÏÝ5ñH܃VO’_#¡¯3Rfõ-Ë~ŠyíiÆcÍ&R¿o§ +‰R£B$ÑCkt6föÀ8f¿‡ŸNÄÒØ>Št`ÆhzøRšÙ²Šý3šÜ gˆÈo!¦–Uú3ô–Ï„ §œ£Z]@.㙾VÝh\ù÷4X7PŽyˆœ™l-­×Çñ5¨4Ëì-UïxÝQTσ:•&Ø|jP¡DÞuë´^˜Ödü%RGëUGhºjÑóÊ"†ž8ÞŒ¬–r¬ô¼Fù&:9¸¥awרEWQÆ£·_&»ó)¿®°RXaÀc¶Yô½¥õ·êu+1@c„n–>¥^k´ÁòÙ½$Dug¹#º'Æ)Ú%ãRB=Û¤DçÛxÝöPdä =T‡ ÝzuÃ¥0k+ë +h:L~r”7ÂqN½ê»Ë˜Î×+¦‹\[ݽB~tàfƒ/?’ÜÝIºÕÞß݃‹yç¹Olî­rAîf?ë­†Ñ\ãã/5àÁ¯™ù=Õ0RAÑ‚ú¼·Τ÷å×>‡°¡:Ó,°Á†ÊŽ6Øøô´`U¸½‘Ú£Fs¤€]ï6(¿y·¡jõÛ4Âp¸dF ·T°‹é¹E–Q’Æ~*k&::Ójýh­$±è¿qT’-‰áñïíÓéÈbù^üñ& U¼ß„afÁŠYwä% îHͽ`Å· K•ŠaçeTzá(ž~«~7F{1} +bPïÀ#ÿÛŠã¹m}ŽÒ5"Fæ´E1á=Žkr~Þú¤ +¹hС—°s(¿ :ªvŒºõŒ»#7™ÿ‚K?tS»D +¯b¸ÿXÜZu¿GÛˆTÙ>"››óÛ½Z翚;8”ßUk†ÅÇî£b.Îç`¡³«Õl¶cž€…‡Œ:^*Ú9Þ_làꇯbWÛ‹ü®HȬ‡Þaû··!q©›]Hê‘qél»5×±ØÌ•úÞÍì†Go7ºËŸJµ9ÉØ€o1u|óY5¬»hwà×ñô,ó/0 = +endstream +endobj +786 0 obj +2489 +endobj +787 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Annots 790 0 R +/Contents [788 0 R] +>> +endobj +788 0 obj +<< /Length 789 0 R /Filter /FlateDecode >> +stream +xœÝ[[®$9]ÁÝC}#‘ãw:%„TÏùõ iè¶íŒ;•U}{`@­TWVÙápĉ§}ÿù¡O*ýÓ'¦Å¤O?ýòñË—Ëi9¾ü,#¼ŸT<Ù9ûòˇš”uiÀO§?¨ô)=ñ§/—áÁO:4ÃõÂÕÍOþÃCûn¡Yu isú×GúüõC1_&«üÝ–ÓÙM&/-×ɚf¸²²±9 ¿Ðs¥ÿ }¥÷{zbzw Iküä\CÓaÁå ¤'¤g^ç«¥Ì7Ë”dš¶õ—Sšb\ÃõØÈï7"q§÷}²!¦õ+]ÕJãAs™FÞŽ¢ÿõºž6D/­¯óöi¼Nëé@ëQ”õî_ˆ¼‚;¹8¹xr!L!ž~¯¦Ùœ¾þõãçßU”Y5€ÙìtJê0ߨŽL^Çù`Í4B—Bþœ·¾jÂN1ŠÈ´­Úc1и™¥½©àe”_GÛ $x½/­NË´„×Ú¤æA›g`ŠbÒ»¹T%½~.J¼ò-½/*Kã}7¯àÓø…Öa²2ˆ^^'ÏÉìðE|0/Â_Z@£~©üõ{Éàãu5¯áWz†ù+=3ÓüМÁ`lËþÖðIôýÎ2áudŸ ì åÈc[DúU&™?©W ÄªÑó7Š‘}±5Úº  Û¼lið»¶­ +Jì3«# ¿ÙºI†àš­Ïbe™ÌÚ¼NÑÓ¡qcBž4œÑ§Çì?C#Eó¶æ^s€€³ËÓúEÑ’XŠhØ2ë Ä/*»&‚‰È {貋œù¿‘5‚«Ô¼–G$ùœ F¬²cí"æÒð—~Ê‘dÇnœ|€qÙwªµN^@¢t#‡”rÙŸ¶"ªQô¢f$_I¬RVoóMkëiEÇs î!ThnCï\ùl`Ã?/5r›³¢UL_ÿFþüc®9©mÒ«dÛ1‰¸¥'cGž™<"áH¢ ëQmŒ¿Ë˶Ñ’ø1“7'ò©dú ' k´T§¼‰רÙm‡ŒÃÞ‘¢ï‰kdÕ’h±ScÑ’¥‰øÙ»\W ­ž E½Oyf蘋M€î…ÜR@ßpc{žß@æ´qL‹‚•æï8x.Ǫm¢a×ì¸a랯—ñ+ʹ=ÎVØÿPF#÷é$Qñ³î“mÙžÕ®\ÑGˆìÎ)¿A·½Ÿ±w’;ƒ’Çyø.Ž×zÙÇüÛ…|‡ÈÆßÞ£oæ‘¾ÌœÓæ¾v9ÝÛaËP(+¿£^Ž û¦ÄI°íh^ó“²Äß¿ŸÛBÔ©\ˆ¶BÔM¤}75\êâ&´›y[˜³=ôšÔ³¨ ´À‘ä _mòNúžz0©17õZ¢?àÐÙ¦øwkìÏÕl.Þò“ýJñ!¹“2skdP +šTºâæ!J“KÈ8ÃfUë®Cì:N4rÞ&ô’ Ÿ;-ùN} ½Ô5Ìu}\ÞªYÓ‘ü”†Ñ~Oï~^ßm¬ëQí*c„ˆ”ý…mbü. —õ‘ĸOŠ’_ðÒŒ·. <ªÙ¤¤¦¹%B¦xhàweoéßpôð‘¶QßRc™TéR‰ âÆë‹¬g%Φ:®†N ¹ ØÒñ}¶…ΪȎS@Œ´¾f&’y ã⌜eæëþ¹ RäÅY ¤šX¼\t&öŸÒâ«ìËï`ˆä²Éî8J‘ ìöu©ßûÛ&¢ÎeãÚ´CÊš/¡NÚsmÙ5Z]ÇÆ)b§Uc+Á“Eoñ¢‡¹‹ ®6t¦_]ù¹²${ޓgšì ( `1½<êeuÊlúä×›tü²òf¹l;©£t8E…€-1‡óhUãØ¡- C0¦†G¬¤vPçLúÔökì‚Òh5 3+ÌŽ¸‚–&=gTP>TÙ·õ£qÛ¥i‚ÀxÙ“xbÒ¿¡70(^êŠ=PP&r¯å4Œ¸¿bþýê™8œÎ%?–I¢¶S÷ìžVØ%ä¾%»‚1>ô(¾c!qmYÑ6æ‡J$wÛôᑊ哂ì}0­àvÙ™~ˉ†±.‘F]±þWÓø‘bÙ¢/PF§´f›;M-c{ñÒ@—88"ÙA†I¥˜év^{ŸbX‘ÁBZ‚t±¼ÿ}|îÓ•Š+Nš‡Þ¡U ´“ƒÏ³ÚÉÅ&rïRåñR…!;„ã…¦"àcX_>kÙ„YmÈ(t¬Þ´äÉë“ñ\3»É*€rlñ¨;µ§©RL&âE¤3¹SÕð¨lÀV_»£)ZíAÒmMâ¤?y]™-iÎYI~‘ßËç»*½åñJ}³VJ5?W jÀk¡çá·Gý½àð^×+tx{Gÿ^y1žèÜ)ZÚñeþ Þý“=^*oæRÓ¹2& p_&Ó ×VgLÌØ`iÊ×q#(úZ¼¢½n÷[H› ™¥8^$S[¬vQ!©×.°}RYê~lÞQ¤qªB¢|æŒ8®ãä»îhƆ‚MàÏ –s-íÁ.Ï:^åü¿R`Ÿ9J½'“ôHê:5˜Ù.µRj3§H¼W)v×)”úŽÏ=)©¸uÎÔ´’ÌGÒoö¡ËpüÀ­³³ƒì„a»øŒÓÑii—¶ S>L q#gðÎìüŽÎUv¢öÞY}ï¹÷:“šóhpÄØRçª +r¨tkÈŠUHrz½NrxD5åbuö]¾^ÜÐo£ÇnÇÃ$t*0|Šðíé÷2yz.&%›ˆ " áî°дJ?yH5´\³@Ò¼µÜy¤ÄfNxö¦ÞîIc‘4< àÖËEµ‡U<:Ÿ£bè8ÇÉ$_iÛ ÝDêES `]òòwâè¨'+Gv¬ñ[…¦G†¥ç ÍQ$ç²xç§ïu@_A9Æ>ße¾ŸíϪݣËÝÒöAôÇódv)ÆæÂktû®¯sù¬Ÿèï$Œœ );˜\{m’vž„vKR,6;¨$¤w ©cŒpì¼4Ķ8¾·S —Å +àH§{V‹%=^›è­ž=ƨZ!Ls¬Òž +Ž +Êaû¢³©†®jã¡voùtü=³«¡çF5éÑÚѵ¥· w tv^4ØÃ†âµÒç08†¶Ó~Ôz ES “÷?íæ(Áî·ïcˆ·å^Œ¯¨#ðÜŸ3åkhþÿ³áÚûÆÜ0[iæ,Mº‚@^¯&ó쪿ÊÚdPn™Ú¨áÍæ¤—¶ÔÍmÜÒÎeÅ$®èö¶^ù['͹4µ¡˜÷øŒU5«Zœl½Öu¨*œóªªügTµ#f=ÏE~•Ÿë¦Q?áû@Î1¿ ‘!Ì^±tLœ_)[žiôØ^ퟛ x}Å{Œ¡åí³2. ¡…sº¢å;FÄþ†ºÐÁæCÙÿ¦sŸÔ2ÙßÒßmÆC‡Ø Š.§M¡Å{â¼²xiÖ§#}•¿ÆJÿízhöËI§‡ª)5f½¥™p~ncJÙEX¥ÃÚô6Çáªj€x)»£j9iäõXúçíºGGâßgåÍÏ? ¯lù·6gYÊŸ²uåø>çcMn5Ô¹qPUÖnºi¨qš¤cYÏ) Ô;]ÀÊÝ"ºçåøjºYËßåvyž«éR–¦þ¿â*ÖÖÐ1:¯Ei¯ôžrsöÄDáýùUågü •£-4«MÎö¬Åuֳžúâk·­Þo#.q +œ~ï§wœ}kž>›[0ûn‘”%}K½œpn ½zâ(jαþÙc+âl ÃS œò+V‘/þ„´–ö@þBUiá®ÿ!VYr"#÷'Ô¥âì÷ö.ßJþ8ôOÿ9ú5V +endstream +endobj +789 0 obj +2943 +endobj +790 0 obj +[ +791 0 R +] +endobj +791 0 obj +<< +/Type /Annot /Subtype /Link /Rect [72 582.65 198.75 570.40] /H /N /Border [0 0 0] /F 4 /A <> >> +endobj +792 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F15 836 0 R >> +>> +/Annots 795 0 R +/Contents [793 0 R] +>> +endobj +793 0 obj +<< /Length 794 0 R /Filter /FlateDecode >> +stream +xœÝ\ÛŠ$¹ý‚þ‡z6L­îÊ„ÅÐÙÕµÏ6ók¯Á°Ï‹ß’RŠB™Ù=c ËPL_R·¸œ8¡ì¿è›JÿôM‡ûjÒW¿þþò¯—íëËOÏõ¶Þn_Ã'¼¿«åfc~îëï/ꮜIüzûY)åÒǧOHŸ˜>Kú¬¾}ýç‹Yïî–&øú·[b±éóš>[ú¼ÕïuŠ÷úý|Ú°¤õÛ¼:²yŸu,Ì‘ÆiUÿ×ûzÚÔùÒú:=§ëóÚ—ùáÔ&í?ý%/¶Àb:Ô æ /l sæî“—²0ÎÆzp8üV«ß¿×Í:>çêîÞ°9õÊnËó?=µï´çÖµÛŽ6·ÿ¼¤¯¿½(˜a?ºÊ?ô¯ì=¸óÅÛóË=pƒ±¨}›¤m¶òüû×dq¾Ìí–»[n.„<0I:šÛ·¿¿üö'0I­nIm+©3Ûe *ªûBËy״¦®{Mûù{óFžqÕ*Ò3æY­ò±?çëÿÎÔgÖúØ­-9V«JÆa"—Kñ£èlò‹}»¥òÜMÃòpD2Dy*ɲÒZwãëéò.Öv*8?9_'¸¬ºŽi’¬2¡¾.©û(Ò~îû(¿­?“¯û0»»,®(ýÏU°öÊ÷i‚¹q$C!ÑŽ×ÙÌ¡:nÞÅFœ¸îÐa·ä¹lC o~îü°C,#'P‡`„e1O õ­ûÝ6ߤ©*w–@&ß”‹þέH# ]ÒœñRŠ–jõ}Ag„5~„¬Ql¾îÇÖŸXç\ì0]¡Å¸•Å¢™SA:ûùûþuŽ,&ïé ,À•Yõ=ðY[% ¡@ëu€’F»Œ£¤ÑJÔÓl×Ô°iòz.;È1[gLT±U©Œ‡À[5®CeíÏ#аƒÈ{ÌûÊͺ6Ož#Ë|&? ¾†{¯ëåo¦˜…è…€H~ ÔtÎŒþ °ìÉøôs«'s<Ûš(“¥:ǡΤàÙ€.p*„²bºÌMž(ÿ×¶Y|~Ÿ˜JhóáÜ(\4Ú°øÆF£}—ÎÂÆh\K¿vt‚.áa4A’òu ñ¶g 1"ÁAŠso ¥>…òXp’k€PŸ}4 9;ßeÆôÜÇÀÞ€ÎÂs^‰œC‹û]ã!hÔÀ¸¨\ɲR³¡óÄ5/5áEÇï{îPdùP x€w¡~z]Ñrc¨“¿P‹ÕÑ€ˆ¾ácæî3êøEIÇ´3¾!|±…Øìe¸ÝÿgsÄg7o{Ó°nÕ‹L„š_@° øø' F\§œP—g"ÜËÑ„Õà,øû$»*Ahò ‚ÆÈ)Zó$¬k†ÆV [¡Yr>9±B'Ò +6æd…o E Zns+D:¸â0* 0p]°`Mžcô€ÐÆ3Ý2c¢éFlƒ†‰2•»WåV«5 Ùt·ÀŒë•a$ð ž…±'abX|ÖßŶ·ùŠ.($tkKÐ2ðâÿ †ÐU“t®&1Å©F§h0XÀŽ~]sõ`—Þ$£acÌ l Ù¬ÐGÉÛ+r|^ÌŸ{'J)Ï]ߺ¿ 9øŒšA®€s²&ÚÌF€ Îí¹?àèX2Q{I“–|}Ö{ì€ùE8·çÖߨ»fRoQÓshðËr7 åØj€Ë®êl"bŒñQåôyfQA\‹Ži©«®Íj ¶cÿÄ<¦H*úÙ¸„i&©Ô!ž¿)¬¹ôq! p¾7Õ«ŒžÔCÊyc5aÉ…®Ä "‰áJ)¯¦U|Ðëš0gQ±~%äAS«l€¢U M“†LÂ^BÊ«ùº¬ŽÇ‚ng(WŠÉÎq¿+ñƒ±¤`Ÿ•ëfEeïÌ]OÆiQ®tLK›¯Ðç>V1²Ð×SàÀ›U!qãË?F§é:ª I:ŒÄP‡‘Ä–ÑCl:š–+|J°œ7–+¢Üé¦dxïi_fÊ +XOÜ‹Ÿ¼ ¯†¸áªÍ²ŸP,sQg&õ,³9?ˆþü|<¤^X—æØm¾>ßɈ$­Éa¢#ÛØqW¹×ƒØ€W™[T´¶¹«ÕWÜ}7²ÉP¤Âç”@Nœ§ÕxÿDù\œãkq\ð2ÆN¡HA +!ö ’£iÓF6O«ŸBqHZû¬ðÄR­—¢¤O3tÖÐÒƒ¬ƒhY¬â +k[hJ¾‚8Ïk ÿBLÔ¼ &ØåºÞL`Ê-®õHLöÒþؘV"\0ýo!÷­\¨¯f1A†»Ìm{X«‚xÀ5«ØY(t!ÊýÕrT±¿J‡†"9)«wÁdH6ò3¨ ,꺴Àm€ä¯Š›àģ̓Ң€‚ìAR)‘(L*¥YâDƒ0_pûšPXoéý+ Ìá€îMb¯#×/­ML{#άè#Š3‚Ñ\Rf“’YÛeÒÍË»’»ylL;Knaæ³˜Š•Àp¦‘îÀå½=)–½ŠM6¦±|]å‹x»5…ñ!VÙ#ÆÔ³„1_5*7gÉ€ /Ýck¦Ì|¯aVNÅêeTk’œ²œ'Ô³z²o`æ+Ÿd~`:‘8qXViø°¬Ô%Öùq;Qn’µ¬lÌÊÂÒnÇû Çîž —0XÖëÇíÓBZ‡[Áæ’†pÿL~R×õA21½CD9-âuprpa\¨îÕ܈2Ù³Xþ®õyñч» \j¡àÏa*Ïšç±b*”]Í=†Ñ™O¤ßKXª¥åâ‹Ñö£%…£ž+³Ã<¡2¹öp嬢’„ò4ëZkbáÀ `=¡ß{®¥W)0ä\Tð¢[²íY³å£Y‚ˆl6¡„\ÀÌ«ÈM26æ"²YsÙ€q™\ro¨8.{ K‹vŸCâ=ýs}K bÆ)& f‰€¶uû$.ÇHcoþ‡Ûï0Ç5wx›Ì4%„‡A^J„Q'“æ›ÆTÿåBR6½+W:°~‚ô_44o¤n,ƒÒõ2Ÿ¨XS•!¨PØ!ÐApÔéz$¦Ñn©&hÕ7eǶþˆ²ˆ½.6fÞý–ÌöS¼ÎDŠsZ8ÊýÔ8F‹)Nó±Üsu¹o™¬žäˆ¥°Š 9ê¼?¯‹ê˜ +Ÿ^…çŸur£ò³ím~ÅÂKh„gÉì'øYŸ áûnKN¡B«'ŽN!¶ëØ£gNñ#à*ýªØ¯ÊnÛ˜þBc--›÷Î?BŽTky}Ûž[?ò0Õ8òÞšóÿþµQžò ôæ€UÞåhæÒUz„ÛUófub£V(! p#SìTÈ¢ ÜiœÜÈAH6Þ[z…WÓ{´Èé *^zV¬41få¾C.òK%8 Û°_BüËï?qeȽ«<«d¡ì¡â Ê ¨yÁVn¡Ñ!‚:ìÈ+ç`2U {F§ÉéÈ”!$±‹G¡ˆ9éðz™áa\þ,/¼Ú¯Ÿª¶FÖíðwXðYº7ïÒ=fs3‰_ôÞˆW½6Éñx2ÀDµ +g[ÖÆÍâ]MZlL³ ¸~!Ý48|íä@Œ ÆÉµ†³ßåWbÞövPùˆÞcü,ÓÌrûl © ?Ç5§Ü¤GHr}R0)½¸œr…e›ÒKÁ6¾ÁöîÍU¡)2 +[}Ëz%Ï~–„ù¹¿ölßÑù!«$ü~Vn0û—#›lÌD¯´mõ÷`õ,À#Úu¾5fªÌ7€Œ¹ÜA轇0? 4ˆ&oÜèŒý>åú¬å;µ­2ƒ}é˵ÊÉñ˜Ñê3¹ÿ…ú†;f¼hhµjàŒGÙ$2 K«’ßf Ä/pɲ:1½m‰Ïü*¡u9¼ ¯vìJWÙ›Ú)|úŠƒ«÷· YænèÛnÆÕYÃ>³p¯¦Ð1T~`ŽK;»Ï¨5uN±@˜¦{¨¼']úy°@­u®ZµU‘YØwų ¡úzXûé/¿­„õ“Ж%bê÷ýe7°ZSë­%Å RŒ\tƲÚ[¬º‰í#¹¯*—ÜÚ,­Õ †µƒPå"0ϘøNÖ%ñ¤º‘/cåM¾,â´Íî€Hu9-TÃל#¹àøLíÆ7Å´BoåëøÜÎMÌWÊ;»•!ùꤓ‹Øõ#cðq÷\ÌÀæ6Ì^(¦U/Ð(á ³~B(ít¶†ŠŸT‡Ñk®´ÉÊËì-."ßGú’§µ,’ 6„“Ù«m~×Þ‡3Bs€ÆÏ{vC–¹ßª½N+›–ó³‹ï³¶ Óî9MéDÏsˆ|ĸòêÁGäÍú}óé ´‰C@„tò±W`Ôü.ç'x˜Pž +ßÍ#A. ¾!Å3¨õ@¹_x=–´œw=ûGý⯿ º·–¼£ØEH¸&ºµÊ9IlÊß.ÁYL~5–÷’'·Þÿx‰ºå¥Ùÿˆ .muÁá¶´ –Ú†a‹ ûš@gï;Y£Ð¯7é\K·ò’õ³i›YË“³ó³7RàM|ÝM“ÿr[Ûò«Þñ±^•4º_×z$? §9'àÝÕ•tõø».Ê”2Ï_AAϘ,›ájòÖò*V°ž\Y)¸ ŽR- oÒ[x>ªñÆÑs¿´ +‚Ó`ª°>\¨¨x1½‡¯•?ª‰m96¦]ü^ÖÁ»‚ ƒ›(ž†ö; ­$ÜJ÷í?ŠÁ¬ xòÃ’Þ׸Xã8ͽ$–·a˜ÐÌ„Áö‘«Sº°i–ýòl1ÑæÈ{g¦ß¢1,ñ¨"&v£èưé}Ê® )¶(VEã÷âÚ[t¼ýAsÓ.ï{6R‡»¿O»¼=0Y»ëÔp¹¥NåC(GÙŠW8ɸÎî7¹@×éì%ð|øÃb„Úïá…¬Îó?Ðaõ‚ÄIþòò_4Ô +endstream +endobj +794 0 obj +3739 +endobj +795 0 obj +[ +796 0 R +] +endobj +796 0 obj +<< +/Type /Annot /Subtype /Link /Rect [117 137.90 147 130.90] /H /N /Border [0 0 0] /F 4 /Dest [702 0 R /XYZ 72 670.90 0 ] >> +endobj +797 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Contents [798 0 R] +>> +endobj +798 0 obj +<< /Length 799 0 R /Filter /FlateDecode >> +stream +xœÍ\ÛŽ3· ~¿ƒ¯ d¢óŒ€¢€í]çºÅ¾AÚ(ÍM_¿’F¤H‰ò· ‚…½ÿŽ$Šg~ääß'}Vé?}Öa‰&}ûñ—Ó¿NׯÓ÷÷xŽçó×Oø„÷‹ÚÎvÍÏ}ýrR‹².=ðãùÏ*}Sʸ¿œ¿þ‰¿èÀ×W6ÿ”Ç¿¿kß´ªî mÎÿ9¥ï¿žlàËb•ÿm¤tu‹ÙÇÅö¸²x±5=~­?·ú™¶Ð·úûgúÙÒïüòÖøÅ9¶§3H‚ËH?!ý¬ûzËz—ÄÓt­¿ŸÓãÕBFþý£nñYŸo¶t~ÛWqnÜëZØ#_GÕO½Ÿ§MÝ/¯óõëó:§C=·°¢œ÷ù•”ÈÛ%¸³Û·]KØÎß©e5ç_ÿqúéO eZムi«w{’¨Õé$§ÃÚ&tcv2Ôòi+›®õo×Å:îW,«¿]¯këg¬¢HϘýÊq£’#úV3ÀáP9~md8·ÿnÖý¨üYžõä(»“X¸¿2|%ÕV‰Ùý+®ñMËó ñµîÚrÝ5ÊyÆ×*ФÈI–QèQtM2GX´Uše6Z[”ù¸MùøÑøc41Îûþw³U‹K°ä{å!êPøp­ÿVùi/D»«µ±¿;ò·ë‹2€5kwn•ZW=Ë܈:V})ƒï¡YøTÖ1Á8¿f#d‚Ñè•L>´W6W2»e\l­îb<´Â„ÅàáGƒ«ZY6Ý:nØ’‡=¼,íÃuÄ")û}ô„A¨É„^J 0K´¼7¤[~‰Š;³KÛ Ú× Íï|(´_2ýf•¼€Ú²q +^ üxQÞ¸&ù~M´íŽsLhsï ž÷ë/ô[,_‘³Ú¯¶"ÃPuŠÊ9Ô`ÕÈPÞR¹Z{º‘µ$JíŽCR€ל Õ0 QþäGŒ˜_”¶–dƒÖ” nzx³‰6‰–6•“[Ñ„$˜<Ži¥È+ºm3„·œ0(Ó}_éõøÌÉ…ÆtTT@fÀVßögíg=“8=|ž:é‰C<È´Œ/¹ä›¹FIîÄŠhD¹ÿÖ­› bÈÙ|·fˆ‘2÷ „ËN¢³pcj¹0“úƺ˜ž/Nc>^œhæÏRnÝ…M Ê 9`€u_¤›2ζ}tÝ‹yø~!B&‰3jbr1ò¼¦ºD®›„Q<óc~§¢½ÓY<q8²ñ:—F“pª•¨tÅäX_¨Bò…z[ _×ôH2>„a¸‚ðÚyèÁ@?>ÚZ”ÿº{3[׿b /ô×4(×jæRk¶úYt÷£3^H[h‰ÎŒ56Ý*w„ô€ê8êÙl£QôÆù>×úw»ßuéaåVnc˹Ì* |¾ñ®ØeãTo¤Bµq WwÝý;Th~ñb¾6xß‹ÃËÌ3³õ a9V½?-àiŽ)8ÈV½ÆÇ!ǧ´Ò0N°§™TsÇ÷«ØVVƒ_®_þöàf#ÉΣdÁ²cÉI׆Öà¦ëbÃÙÇe+pMr;\£Î™’vئ†&?Á(1uÔ{bQWB×öXÊ~¥Àò·ž›Õbç­IÃCm&R«ø-fLœíKé3í>s¿í²8¢o*Ãú7‘¦Ø4 +éKÓæ‰{Ùaß½{Áh²{¨ÞF—r‚ JñÜÇ8Év Lâ?Yƒž½{.dpšíMÄDËvUÕG+q!‚iæOc3¹a6KtŽkÿ³‡b­wMõ\th¶®Úl9ÊkU >Œ¸†«[’nçK–Ñáòv]$®w¨§u6—œë޹#1Ý盬jñ”“ÅÄšÁ̌憣©6†¬±#ɆWÀNéì²¹ÜV†¯Õ„ŒÅ«ûÈ6Hà ÞHÜANÚLËLñúÚt˜éÂïP€=Aókò1ºU%\>·Y5ÁÖ´ù„|W¤‘¸û±0ìèž¶a;H/äˆÏ¥¸ÄÍ[’H0' ew$‡ +5Ý[£Qa.”ü2¡ +ߢ¨péKËê° +päìI&‡½hh!NºV†e›*ûLP®*ºâJ) … !*6x]o %º6±š…Èx&H¡æví’5XíŽF°‹ïòj‚ï°5óŒ ¼ÖÂßrЀôwåãØŽñy€|Bè{u?`ÓËø$­£Ä °wrk]Ó=ô™ù9GÔªú&7vÌL96m÷©H-Ä1Ö®°Vý#ôc&Ó=W’3ÎȖܢЛ7a~Çã–ø#MU2ÉÃC`œ“@~XÉöHsªÝùÞÁ¦þ€Ì´0xJÀ·² ß´½S!•¢ÒÄt¤î AT<ùàëÊP?× V‹Ð+ÀÂ:»S¥&s,lž5ÀˆåZ`À€ÀO?1^9̸\wŸmª+Âýgy¹uA(^ñÎb¯­ùîL]éƒ:²œIZv9Côè%Ðû48{É6Ûû8Ocs-Ä—ly™f"¢I4#Kôdºê-!Ö¿ªæfŸ’¬é)Ý0S6Êi.[#å㎿í‹Ü䙸–‚",º¼!’¬˜<‚¢u"ÔÆ­|xŠ JŒXa—ØÅt|4,= úQcs +µÚHI2‚d–±ì‘(‹ºaŽŒüpAŒ¶î¹ýÝ8Y ÑzÍxˆT:D‹ÊfR@œ‡Èfkˆ[…úñÁ–Ì7ãgæsV¬°5Ä&\êªÒA'|Õ=‚ÅÐÊú:‘4›XÊíML’g©!I{/¤ˆ<öùg‰7j›yå̱¨akæþâ¥û!´ïêæ£É.a‘FɆ¯/܃¦Ü:~$ôEÒ~@ £x ø¸ý\I€:®­‹Õ†kæví¢œÄ³=ºá Éð…y)HÕØ ©õ“A>™ÚŠ a!ï¢3"Uã´c:(Ô~¿½‰¹lKØçÚ¶£1co9p+l»‹^Ï0Ö@¡¯u})|«·ÂSÈý0‡µdóãZº‡s£’ÑaFU²™Ï²5ó¸õÈ6ǨœS¹ôᇳ²¾ õLÖFëØýŠ˜«<Ù½‚{…ØT3IÑXÖ˜°Wó·{Zá ·%8.LWö:&KÞëehg‚àå\”.iï>™îE41×h¦œKw:p1¥OŠï·p_Ó~òU':tàÎmâÕj8ËKS¯Œ-:.`ß¡}oV‚û&Ò³ØÊ­„øTÉ!$øÑEÕ—Y/jSFÊÑ’-tlˆG˜îÅa€ZìÓ÷Y{y)ê ?צ¼"XF¾žœ’²5ÍHŸ1Œä[£yí¿7w#½Ê6 @È ƒIOQƒ+ƒ ©0énÔúéd$àQ!XJë!î&èKçcrØáHsŸ…½1#1Óãò?Ãøhkà6˜ÐÄ-ÑꞃõùOX=²ÊRÔ!­‡QÔlyâhä¡ Ÿ_§¿žþ &ž!ø +endstream +endobj +799 0 obj +3551 +endobj +800 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Contents [801 0 R] +>> +endobj +801 0 obj +<< /Length 802 0 R /Filter /FlateDecode >> +stream +xœí[ÝŽë¸ ~‚¼C® Ô«?Ë6PH2“ûóÛîE] {Óׯ$“)“ޓɠEqœdbJüùø+å_'{6éŸ=Û8,.½ûù×Óo§ë×é§ûr^Îç¯_êã8˜ùì§üÜׯ'3˜àÒ?ŸÿbŒ é5¦WL¯)½æôZþzþúçÉ-C8§¾þ~N$.TŸ^—ôº¦× >ÀŸðY_6Îiÿ¶®Øºw Å55ð¿]÷³ÖKûÛôœ…çíXÖG©]â? \ÅþsÞlÆÍl3Ã3# Á !0}t~ÁQø+l~ƒÏŸÀlàk.a[Ó.Lp_žÿénÇÎzaY:v¬;ÿû”Þÿ~2¸Â*ºÉìoüÃãÍÛóó9`|µ¾™¤<ÿù•7–µÃ<„ùbÌ„IÓ“;ÿþÓ/j,ªï19vðUÉf”«’ÝÜÐæY†' CxŸâ’¹Ö™·æœ %þ³ÌÀ¬*Š«Á2µ.ó0w$ Y­ÌËú*âO`žôÞhå;OÔbºÛê”ù{àY ·w ÿX÷(´Wî,Þ ®gÎSæ +CmC…(@tÂÊHÞ°àþžmGŸ Y i‹»U§Ö NS©ýTJ(’û É̵X$÷+?å=h¬õ’a=A9½Àn)&,¢¤>ëÐ’2[}Ò^8žf÷‘×7 Ê*ààïšú €6V{mûÊ¢OÓ0EMt—D§$ÍÊîcŸ­^\ÍtFñ¥§Õ7Ãs B;¶PTÕ‡ïa­’®OTYy&Yn …”Oj–'ÞÀGõ€HÌ Ï8 ÇÀ“¤ËÂ+†n/Ù1…ÙTKl ì /èï„»…äw½r«SCIµŒagkŽ¢Š'þ³Q\&U_H¹sQ}!ˆa€’4_xgÐüÉÒ´Œ…â q×å/¢©)»æ;’ç4ŸÄ}*nÝžH3­ïë> ¿¬zosÊ×ÂÐMR=%±QS}µº úêâ׿¢)T€ÈR#÷¼~.ê™»ua-ÑÓ÷Þ¶Ò¢ºwUðÛÃê +|Ü &˜8iØrÎÐ¥%Þ FwUþHö*' ’ý\)tÀ~­ Z€Ž†‡ÂÇØt¶ Ÿ¤¸p$¤æ?•õFÂ÷lˆ6tÃÃlû¾ì‰tE×LÞŽ9p(J¨‚õqQ­`R_¤9O””_Ÿ×ƒÖËžCÑt[µãþï ·†L ÕnkðÕPãb¥&EµÍ‡Ì«´=ØæBh(=ÕÉÞ"‚tœ‚ÜO”ô*µh”¢5Êßήª³¢$ü •í`b1ιm³”¸©NHªÅ´^‘åZ¨Ï?ZCTæ/WâDpÁ=ÂGSã) +ꤋµÏ7Åól¡3ÏLƒrT@tüm5}ø`XTA#ŠA¼_òVŒ6mÏÜaüÛxvâ4dÇí~›Žn$ëš?#ľUWb´“L3Ú–ºLŠŠ4 zix,ûÎ6‚ªo5èôYåúÒ0$G4Ô©4iÏ»ù]Ñ "МZ¤(s±‚qííîÀ$@°¹ ¤/®©•=®ŠÂ(iI?À€ ô¸Ï¤,© ¨ë.Ý>$¾ÚߨiN2¨s-=›VÄŠ†Ñ[ +‚èdLR‘E;¨cêÄ_k¦r¼•ól~’„bay¶X6 ƒ|ZÐ ¨wc}S›Ö¾:—€£UÚ»µ“©õcÍráÐ4}a.>0&Œ¤Íˆú‰ne ’bm|Ѥ$­ˆzÝ,Ĩl—z0Öϱ9ü\y6—m|ÂÙŦ ¸+kàwÚ–÷ÁH²Ùó W_4ýx¸K×mà&NÕÉÑ@Ž"Õ’]T3+¢6½¼ö¦—¬Ü>0‘ƒÖËK²B°ÚP3¿¤?#9j…ùP:À"ô$&µÄx!gkX”’4Qa,¨¿€¥°ó–C m6ò‚O¶û. ïŽˆ‰:)-`ú y MZŽ-¯± Dæ"ÒÙÍ#XI‘)`,Ã"•ò¼5*£nJñãª×Ú&Ñd~QÇ¿™¬÷þ“mͶmÚËZ¤ýÞLæKlá7’‡YÇôn-›îÉöTŒ0SË[4H“FÒ¦}·¼9LšHð nT“:&*"vUÿ+ݱ[ûQáÑû#&k­ø@?ï" ltZËâáê Ï®X¼x¦Yñ5¨·+D¥ÜŒøiÎ]¸tÀ*]#9šG–WÚŠwæóé¶tÛê©ÜÁ0§eð‘+Ä,4ƽ<::¹ëš¨ÃplœðT™w¤I¬¡]erGe®¤ilzFc2Ø¢Í7­4°I +#9 +¶ñ]`;¨bg\¹ÏEym¹NVñ³Àûf0;ˆ©ç½ë;p¡7p; Frþ¨aBÃNƒãl“´úFdüO–³>k¤Hk|Jð¨Ï“S…;ñów€Í… lã®d5N­$c(gŠô²= Î$Ué]]% 7¤!¯ºÆÎéP©Mú’·wŒ±+_çaŒDÓ®¹R+£aÙÄf +5hA ’”#§9B]fm>¦õ¦Dlº¹ksÞÞ|/L1Œ£©ºØœ‡¤ãÛg® Ö;A÷G$ˆÔ9ÖÝðcó'FžõJºÃdäý}iüï‚Ã-N(*8¤ÀHŽ_cì‡?î«à˜qÍn1\ÝNxÌðÉP pfWÂE²ó¢Ê“ËiŠØhôDü’0Z  ?!XHNš ¯EýZt¹›¬œG×Äß„<ý®r'+MhA¿‘ÒàŒ‘µ”¡­ÞÇîºÈgÛö¾¯šË…ɶyîЂ§Mr{<ã{tÛíôñ`Ø;ãQÃà• ¦k¼ûë|%Zq8,îœo2Ð!o`MûèÔ Q½f¥‰9dÂĬþn•[ÖN9º²õf^\~W¢9Ÿ÷Ÿ·×fëÁ‰¼êó±c|ç$JÌ Di +p¤“' `CÉÓ#­Á¥ƒ—nì—«ZF¶SØön¯¼æêF.ž-¾{8žìD‡¤‘GuË¥mr`37J¿¨¤6“ªfF¦Wͯùûó¢‰MËX`ë ÕLeféÇÚ4SI]9#kìæ†¶ð üý» LÃ?Z½MÅX8@Q_!/Ì…ùms^­º)ÇH&<™@ o:'‹]µ-ú=~ g©yž5±SÈfh×¶ÉY›¯édÊÃê˜#;jEnÅlµLG›ÙNÞµ»çÒþ@ŸñDàÞ‹i'ÿ¨`0 ôóKÚß°RuÏyï,§|~þvúçâk +endstream +endobj +802 0 obj +2839 +endobj +803 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F46 842 0 R /F15 836 0 R >> +>> +/Contents [804 0 R] +>> +endobj +804 0 obj +<< /Length 805 0 R /Filter /FlateDecode >> +stream +xœÝ\ÍŽã6~‚~ŸŒ†,R¤ Øíö}~ƒìæ ’˾þ²HYE‘²ÔÓ3È.Çm›ÅŸª¯þ©ùóE_TøO_´›VýòûË/·÷—¯õ²^.ï¿–ó<©åb<Ž{ÿýEMÊØ0à—ËÏ*ü¥ø\Þ+ÃÝ•÷^ÖŸ+<âܦ'íQι¸ª>eÿ·´^c:3,”B(íÀÂêÞòœ,ØÖ,¾—8IÃHKÍv<ÎSÖÈ"ÍÄ>çyd›òlÿ&[&þûíûV!Å—¡ùwkäÁ1Èd‘Cu×5ñ ÌOð¼ `à–½P¶`Åœ/Ìa~ ‰¿6ÌeÂÞ-B’µE ‹ïi”~ãp<þ†¤ñ;³å¾’ Ι¬²öf`51XpÀÐFx` 4:¨³Ž“ÎEº[ýÜÓy:énªÅšzš¡Y´Äf'á?ëÿ_è[3mÀ7擧胟Q­+‡2ΉÄòˆ´jÉžÝÆýÇC5ÈÎÚ„(Awlˆ¿k>7‹¸ø|DË…ytÍ|Y•àaÑ*ŠšÍœ (qÍ,#k³–SXÑ —ø|&ÐZÉYãc¼[YKXíŠ-d ë¾Ü|On•¬ÈL Ójfƒ¾ÿÓ÷»’ÂäætÀŸÈ¹•[‘MÃë£8Ø—¹´Ðãʶ¢‰&+ñ—ÉßÓ¢9v$³©hQ¾AŒ°E€¬áÆ5¸J[L}v%Ñüximn$ˆ¹3Û×kþþQÇ"˜¥ùïA)¨÷\2Ô,,(ØiaÆÀiD­˜‰Àq¢$£‰» à–yUÅ’%ù"üý~&¿ÇB ß#û§H'5Ûèi‘çѶµ†½=01€ AÚ­’Ú!öaM@¹åÉ{h,‘5óÄ<2Bóêq¾#ÔÍ>YÍrºj½(é™ziÓƒ û΀A¦vI‰‚½Ö€' +ê*™^2Húží¡dr;ÞfvÐf&H/÷ ´æ\ƒ«ø™k2ËlŸy+³{âìךiöE÷Ö'cò¨gæõ*ÙUt€¼ ‹\èH<éæI¿æ†5°h„rÜ Ù`÷¢"*Cü`6á¶]«ŒŸ•0Ìå<£}1ïcç‘XtwáÖ=±p2+â±h¢Ö$+— ;›æ†X”ËÚd1šÂ{Ò(s4‰M°Æb°˜³Ú:Ã#9ÚØ}œXÐ(˜–e´ •'Šp¼ÔóÛžðì\ |Wx¶k9ÙiáqâÏ^³ÈMFKç —f,ÿ|ÙŠ…j¤‘##¢bÜV1‡aüƒ)i¶×äLVØ‚k¶õÌ6·¾€‡ÿ%Õ£¹i cHJs›!ΰaDŠ)NS&ÐbTu&Dzg=óÒA{@ÖnÚVD„zíí“U@ôªÊ¢ZJ ýMÙ6c§ØÊ„Dìå°RA| 9Ç”êƒØÌçÃ?fF>Ü®+vŠöÄä:bdãâ?U.€²Z^Ù½7áÌ'Š0ý{<.¾y–”jùF‹h@c¨*&ýÝ™Í+)#óM&ï4¬¨Õç~hxïÁŠ“ý]aÅ÷xVœòÓ`Å'ý!°2úXuÓVUùÌÜ<ÄXÄYc…æï +°²ÁsèªçúQÞ¦›Âșՠìmާå& Œ€‘y,´;`Q¹‰Ün¸ë÷"“øêᆓUŽüã=`Þ³Þl“ÒÒÛn'ÍÅ1ºM)[ÝÉPƒ\žÒC AþއGÒ^F!ȪšŸ:.»)ñc¬Íž÷ñƒÂ„ «±ç^Sk»[Æ‚˜ ÈäÈ-x›ˆ-D{[ä8¯'Ón¨^ð);Æ[êWÄ[2¤5÷4>V12?EáH«Ú'L¥i’kö'Ƭ焕›¸õ›¨ÄLLjû5L›1.ŸZÞÆïÄÔM0c©¥OQRI„ËÄÛÌÕˆFáɹg#'žÒÕö^Y¾†¶S÷Šv¬/Ó)zÁÕézu¿ z­©¶uMâÜ-¶9Ÿ¸žô;‹›–îÁ`%~W[P +&y¸ì—g–º—C +2½ü ót¨nšƒ†¶9NÅÄa!žïéјAS‹¢@rÏÝXh)8¯±_«³;‡uKpìóÚêÑYäÖ†¡ö†ìÓXéö#mà‹Œ; –qæ‡ç'šWW¯.L¤ñïÏUsQƈŽé϶;¥öÛøÒ¾½ •Í z(z‰WìʰQ%äSxÁrOOzI¼ «.~£'. dù­=­ r«ü(=‘¶ÂÀ½$3Ú+þý^€g àñöÜ/ùd;¹Á½šVЉػÌ8¸ûR*oE½ëzÅCòF-A«ñ¨dÖ?r7¨QÇÒð’e{ü,µÅùÍÅÆ®iæ×DSä Sv3ÅMã¨'Ü”-gS¥Û‚»(ev]ÃÛ]‚Œõ()œÍøÖ&¤ÓIè)m>Z“‡ã¥OÉ›Y™ŸÞÿ^*q +ÔÒÃ8µ‘¡* €c޹#\X{'y¾zåÏv4UvÐ5Þcô‹´67ÊBqN%ü—ÓÙÏ'æÓ¢°Ç8i 6Eph&Ó‹»û‡VÛ«‹'6óüºbc®<^‘RY¸ÊñŠÂ Ýf"Œç9]Ý(ÌÏ‚§½Öýh^˜yMASl^c¡Ü iÚ #7±8kÞ›l|j%A-ØH0ƒ`if1§~+•|†nÑ–›ék†~O#÷Ά opfÇß§÷žÜ8ÙÎ ”ÅtÒªÃaÏ·ÔÒÁºÎóüxÝj† «žûLÆù¬Ð°ñ tD§j·³½¤ÙZuQ-É뮣‰—ë6‡ªm\š˜Z‚ ÜV-DqóD£>ÒT.âÅa±éƒ‰Ù0óÕjp €S X~â`ÝéHaAór°<“Pâ~OkÄ^4,FA—r[À£Ï¥ð!%ì„`r½ N:sg“=,Íuqr¯´½©ô䮃÷ÛÞ +¼+ÄYÍJcž}D¤üÑ&!kál:[1 ö•C©K2Q;z& ²´¿—grhèê3¿>¬Û>V§q—V.ÇÀÓãɤcÉ×'"3Í8·9‹<ÀÉuMrûþéÕcÙCLÞW|–J|ÒÝÀk±kHÉùB¨¿´‡òüPÇœðfâ;½˜«ª‘õ½º‚ cå¥Á®•Ç Ý:5›ÏQ¨ò®‹½Û 25F¦êP¾§$gx4/ý0˜Ž‚äŒì3 Ïk³`cæÛž f•Úü\0>ßY”Ÿî?,"k°„(6¤T‘ÇÓ†õìRcöüÃZ»ùM¥Õ/‡²»rgÊGËF§s¸×‰¿ß*dùSÜ¥ÊPú¾èm)^Òäiy˸`ž¸{G Ñó#ž×ÐC£Üa]+:ú’êeFœªdÔ9j½î<£a@­âns 5þ…&vjC¹Ä­Oœª;|A–Ê5Af ö:°Ú4 :ðüõ1(vE³þG4ݶ<§b÷eAuï¤?«›¬#Àõ,iëéã®Rß½fÿˆA&QQw,_Ï +¦òŸ/ÿ¡Ù +endstream +endobj +805 0 obj +3084 +endobj +806 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Contents [807 0 R] +>> +endobj +807 0 obj +<< /Length 808 0 R /Filter /FlateDecode >> +stream +xœÍYKŽä6 =AÝÁëãõ±e  ~ÞèL2‹ ³ÉõG’I‰”eW•Ó £Ë¶HQEÿ}‚N…?è`è'~}ý~úëty;}ž§n꺷oy„s½ò㸷ï'Õ+«Ã€¯Ý¯J).®!\c¸|¸¦/ÝÛŸ'=õ¶ +Þ~¶YÄ„ë®K¸®xCw¼ßV;ø0Ñ £Ð;£,ér ð?,óF}a~ãǃKúiÕ:Øœ—ý)Næi2ÐÀh°‚ÖêÞZ—2$gF\8-þ‚“_ñþŽÆZ©s²½ÓB'Lbá&ÿ<ƒ«¼g§©2t÷Ï)üþqR¤aYºŠÏþW¦ìãÉËxß’0&{ߨx¥ñ÷·À8—t[ß[ßÙaˆ‚éQw?þ8}û…( ª Þ´-Ó Ù=j¹Lp‘™…u“ïÇAŠ©ìVx¨/ȹóâb˜V+=I g6 q‘dxbcµAíÇO8+'Æ´Œ‡ Ê^|ÈvdÒÊ’œSÒ7 hÁ7õЬjÆÅÑ‚¶Àæ8 .¥¥K¡®+¾»±d2ãï ÞSÒàp]›z\›Ý2þ[¨µŠÔÞãçµ5óêy 7Ð2nå±*.Þ×K%–m¹, c4àó +ê6 !‡ìGéÐBI}–o™ï‚ ³„_å(ïä* „Ø‹0¸‚aµWVË+[åq¸ÂV¿Ÿ¥àÖ‚«ˆe¤döV.î%B½ÊÚsÌ’ +-Ä` +¡”H-ì«ØÌ÷•â zØ´”òY²8;R:loteY©˜¡YǺ”TÜ·Œ|—¤ÂÈþ“‚°ëÕ¤P„eRˆ‡ÔTaÔÇAçM¤B¬öÛAÝŒ™SR}ƒÀ¨ò‘> +>> +/Contents [810 0 R] +>> +endobj +810 0 obj +<< /Length 811 0 R /Filter /FlateDecode >> +stream +xœÕYKŽ#7 =ïPëS#R `»Ûû}ƒI²02›\?¢DýªTå²ÑÓ™ aøS”H=Rä#ûïL"üÁfö>}ùzúëty;}¾ùÉOÓÛEBëY¸IZ’{ûz³*|™~áSxá/ÓÛŸEÜèL'>‹ I¯(þùz¡ÈŠ…"ÀéŸSøüí$ò:.ôÛÚR«ft÷Uq?K¬âŸ‚¼À,&È;! ¼0¼}×é»x ïöÄðXeIq!{IßÅ5íª³C¢ž•êìVÅ¡x-é·Iðq=ú98"`ñÛ– êŽz¯ «”ÉŒ¸Å+ßÞÖ¸ ¿î+zo¼6ïAÇüI_†ƒôƒ¤ã&y HÆh‡‹ú^ßBäi95)7+7)cfã¦à‹Ó·ßOüTCSŠAlZ$š ûP’Ià&‰³59¬@î»sé³%.F]†m`@L~öfdÄ5 Wîí™™\–´—ƒ)æ^Øe’á$H<‡I°à…r®ÏQ²Ëƒ›¥f¹[úM©ôBCè•în›-ba—–„kZõÙjتSºÆÎË`oí#¨ ”pñ¼_ZƒP(BBg…icI)¤Èéöª0¶žœU¡-Ña=×c,’€"‡v¶Ö0Â|fÃ!yI>ÉèÛzÃJr±¡*K›îƒì!›/­u‘fïBýL¯¥f¯u›7¡pˆÙI×cÄÐñü›åï2…rVþ=>×ìús“aHþ¼Ä˜Ã'ë¸d—·žmnã†-ùÚ8;kS+Íй9NýF¬k‡t»˜M¬C¾O†Òì¹u÷(È­’Á€¼&ïsÙŠp¾v5œËÕÈXÐ;c›1Œ¿]«yÈ ˜Iþá=¢¹9“æ#-‚ÆâŒ9J¶!C&‘ ¤’¶Uº=y·‚›t'+‰Ô2|×áÌyZ7ÁÓnÆáªËù¶‰0®9µâÌÝ—*Ÿ5(ášÆ€ŠÅ¡QžÏær*&€ÖȰ¢ÜýÄÌ–Õ´"’²Ö"l^5¨AÄU¯RÖ"¤Äêk*TÄž-”IÜöøXåêªhÂÈʬ.£|ÙðÍ™/<ëË»¸ëYc±éè1ÞË)ö—æžÎÇøzÄ‚à  +ä&ÎRÕY#Ea®-Êô±Ü˜WQèGÌ%/5ÝæüMûly)R_1è¨ÍK“³nýY&%›>ÉH·–Ísý‹È_žB[Q¿ŒßíHí^vÐ6ÏÌÚÔ˜dzn‚M?¡-Ù½¤ ”’ëž…ì—&K Çw¢ïÝw›¬ØÀ. +£ëw#ˆkË‘a¥s­;V´ós™ôØt!3ß9þ‰Æ¬0i#V™Uffö"JSQ® ¬9™ìÖ>‹tPëÿ;7sÒøÚû×îê=Ès¹ hIôb5}’mA»qDÞi@ˆ@¯›Ä£½_5}ÙÒy ˜êì,é˜ïètJ7Uèƒn£|—ávF–”š¢ô>Ã]k9Àp;•Òîñ-#û.ïòfzלPˆâøµ¬Ú"_RÖþ,w1Š V¬Z°áÍaÃZC«3í=ðŒ¤iêJǾ/]ÚåÎJÜíT,±÷ÇÌ@4/)‹6]ˆ8_æpÝçi•õÏ*ÛY ¢ÒËã<ö¼Ç0p)÷ àÏç”c$«t$›ÂGi*?ºÈ7Ÿ)ý¨ššõa3ÙgKÿÓ3\j‰ðûT}D3—¡öÇNp›“tÅy4½mÍ|ám»ßÑÙm»¦˜0u€MÿSûaè +ÉÿWùÁùUoèa‚E«ÿ+~UuïÒ«Öćç‡+ÈU«ð·:0A$nõ˜1L­Ê¢­² Ö7ƒˆf‚ؘu|ˆØå}æˆÚ‘F‰uÕ&ì¼ 2ÃÿgœØg•­qazvw^(öªòF^ųsAåÜ>Ê7Õô ß$H‡œRp¡Ûà¢uÝ(6â”f™‹ï0Îì‰ÓAžþ¸Pæø&CÂþ ܽ«ø ìðì‹I܆¾8 \Lí€è]‘þÔe»µ›¥$r衪èÉ×Q+Øê +.]ëÊX„&®`Q00#dÜ:qm1Û  +`wd³0c}ÎŒ˜ÀèkfÓ¡ñøõô/NN‚â +endstream +endobj +811 0 obj +1701 +endobj +812 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +>> +/Contents [813 0 R] +>> +endobj +813 0 obj +<< /Length 814 0 R /Filter /FlateDecode >> +stream +xœ+ä5T0BCC3=K# +9—74l +endstream +endobj +814 0 obj +28 +endobj +815 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Contents [816 0 R] +>> +endobj +816 0 obj +<< /Length 817 0 R /Filter /FlateDecode >> +stream +xœµZÛnä6 ý‚ù?X¯î (0ÞɼÈlÛ‡[ ûÒ߯.¤DÊòx’ì"0âÉÈ"EžCÉù÷"‘~ä"ÝUºûúíòÏe{½|¾Ç%.Ëë_m„µ«‹öyÜë·‹X…6iÀ×åW!´J—ûmyý» wv•Ž —‡ ¯2üó]ÚÁƒ!©–ÿ.éþûEà¶<,òßöžz³ªpnº «Vl¸jÃ¥M—L|I¿M½Ä-][ºb™F‡5Å!¹òÇ’-yf)=¦T½W.ýõQóTÌ ­ìj sè6W6›\yóTó*RóÊ0óWðô |¾Á/ðùxZ’ý>¯à¼Ã³8Gz.©üÆh)²\ ‘ÓQv³¡Ø{yM¸³zuf1) a1έ.,ŸÄêÕòýÏË_¿t`j1A¦—>M¡û”VÏ¥ðéƒËƒù³ûCË÷0FC˜04×ê‡ô$i–û«¿ kÀ¹a žúþ¼H–ë¶4Œ`/ò4äùedñ0ºudÈæ»bÈ?_ 3 fõçï<ÁM³9ÙÁÂóßîWZ®lÉ=娵jÕÈQaXe5ÚWâäK&ôµ~§ý9µÙ3») [ˆ¡œäÛz×C€T”±ã k8¿Â½í¡A<«IÕPzÀ±Nãt˜à­Ößå\Âz…¢0iXDüA /éÜp@@Éz/1݃_÷ú\)×nÚŠœ÷y¬‘“l¶øNyÉy"dî;l^áY§zHèÄPY,¿ç86¾@|Ž“³ñǼƒT)èz¹³•¾RÃ$¤™O€õ +0¢óR*6Œ"u‡ÇSN˜DSÑêŽä­ ’ŒñÁ„cŸ/úRùÔkˆ-ÄCJ‡ÈòŠûd™F ‚F  ä™j(Þ¬X[èÞX´ )FÀ+²ö6%Æ or±àtÁ*òÕqP<-³×'tÖ¿½ ;†|Ï#‚íWÜ"ó°-‘(!Õ7Rõï9i“ròO±Ç$eâP“Ð¥î”ð¨í³²óº îªDSލer®ÞŒÖàMv&ÌrZ>gh¼Á5™ç¬3éóŽ’^˜„˜@F8`RS‹b׆X+˜¨´˜iUC£Ì†¹GÆÞú|X«²Z(o‡:ª¬4zúAA?¯é6^²”ö}¤Þ?68; ´ŠD%ãã˜O™Q +ö# ä=w‚ÉÊkà·†x"~«ä£J†Ä:àly^œø…òmå±jðm3©|å>#îï( ògskXÅÁ-Ê)¼§kÆÏD:)Äô°ãz¢néAò¾£nihÝ’€C¿ZEÞwe ÄKnÂi%Ó¾(óq­dMGm$ÛÆh¶á*HEA½u{c7£Õꨊ”ƒ Ú­ºG”6tЬ»¾¶Æ¢aÝÍï7Tj…+4–[N–—ßPaóY “J¢èš¸o¦g•„V鱊°ý]aÅNÃY7c¥pZª`‚¼I Z:Ï€@vÆKØá´ ]! 4Xd$iÙcIâ»QNbø"»  }÷¨~!Âqê¨af¶ž•1`í{Zgúÿ°ãÂ:&LÍzר€¹3Ä™°3Ÿs`΀8‘ýg¶Z.ÞŰëˆ_æ¾>ê©CL”±¹JsG%S^´¦G.g eŽ\Uìy\LÕ}.We¸CºïíÑÓÎÑ9u"j,X¾C‰,S 2›ò}Ju̧}6S×Ô¥~W'õ—K†z_§ÎÛ¹0pÌÿÚ90Û¾IÏ“ZǶ{ù:?ÆRÁg‡Ç£Â´ñVd ü £HžVM9I]>4ç>Y®¨IöhS ÉùÛToðü)Y¹€lœÁô)ësÞMEðôŒŒ ç#ŽS?[Ã{ŽÜ¾” ±öh°ä {77¶{zx@ÊÆæ36­ûSâXßþ6©û\w5BÙ +îÏűRüûaâøT× èl™Ø1nΞ¶›ˆÞ© ·öoxôsEmgÛ[Eëó÷ZtÆ™¶õx–Üv%¦g=p·3åQ”tnR?°ƒ=*–O•‡½Ë¤”AB7ýi¤ò˜”É÷üòOÀÅ)I¥Ó½û÷¨*ZVÓÌZ€Lôù”¬Cé•4Óãë=ÌÎîvžEÏHÏt¦ƒ6AÎF‰'…al9ͯ; këmëȯ]+>Úœ’#™õ ü ÇŽ-õÑÎ5¿ƒÞ«½g“?ÖÊSåqTsg‡ã ø>ß¾å0ãBÊüŸ"ï㣠œ¥° äD<¥cñTàý9ý„\÷»¾m¢×XüÙƒH|?7¾Ÿ1é6ü£È•ˆùÜ:‹T»žÞÝ›£µ` {ötV?ÞgkÅþЋØI¾,&ÏlY‹ÆuÂÚ(°g +¶Çƒ5«Ð©˜é °y½ü~ù½´ +endstream +endobj +817 0 obj +1971 +endobj +818 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F14 830 0 R /F15 836 0 R >> +>> +/Contents [819 0 R] +>> +endobj +819 0 obj +<< /Length 820 0 R /Filter /FlateDecode >> +stream +xœÝZÍŽ7 ~¿ƒÏ2õ7 (`¯×÷ûis(Í¥¯_ICR”¬ÑŒ7  cÇ»’H‘ÔÇÔüs‚³Š?p?-:>}úrúût};}¼/çå|~ûÌ#œ›T8›9{ûrR“²:øtþU)eãÇÅŸ9~Bü,¿ßþ:ée²ç¸ÀÛç8E[žbâç?×øyÁï7\â¿o/ëC”_Ö…¹Z÷Žsi8þ†Uh\/ʇ8p<¸¼>íZGýã†yÛ’°@ÂÀ£‚IáPM´à&k+{é…ç9¡ˆEá74ƺA¦íýÅiZ¯ÏÚ‹},i©ZÅNNWjÀR­eòøwpÃí²4;}þ÷Ÿ¿ž­°ZK¥¿uBF™ÉÛ}áe|˜|c†ÆÄ ÃkÿúƒÔåµm4S8[ïÓÄèœYŸ¿þyúüK‰b°9R"yv~ +–|ª<ëõºú"Y¯~Î> d0{ޱá{KGç­K³,MR“¼žt5)nÛ°:—Õ¯Ú¢çø`“5:â—ø’í*ñÅ7ü˜TP¶Ù…¹ˆ¶Œ^&e/ð¶ó‘ôøûŠ'cFø=…육c‡×‘B1¢‚­ ^ú!ãTT@Ï[f JÞñ„WׂuÉj)ã±'½àß—z>ÿ?bxˆ8§Ñ8.¸>áê­‘Bù¥Sñù^¼­çêXšÅOÆ7Z°ì"È— “ÙIÈzvœJ˜TÀ ØÈN$ÚÌR¯72?bÇzòô<ÆÇën=ÐðÃpô‘£·æÇßÖb@ÜÖ¿g‡ã³¹ ˆp¶uÂ^Kqš]Ö3ñ» #=ꄵDô!8{l)k/Ï)¬ …¶ñÕÇÌÃ0®@Âk‚Ño€W?{Zù8¼ŠI߯ña ¯ª¯«xw(} ±13v$ï ¬M0X‰ösa×Ê\§œKæ9Ï¡¯Óô”ÝAßðà&Áz:èkµˆÑkÙ )J)“-:È-*{ŒoÞX)U1ª<Î!@Ì(ƒ•ÂjàÊg pŒCˆòšdJùÍ:[(mˆÍ1^Úu¥ ¡}ÛLï]Ââ0Ó2”E4Oc;}mƒ¨(´OW@Á2ëo}r+X£¡øÖb£/$æŒG™²]ÿRüLÊó/%–âÆ•LÛõ{»ÊÂ/åoeðØQ6¾ÔàpoI½‡·yÕoÀÛXÊÀÓx[&}+Þ>ŠÙ¥³R<²’E"Øé4 W™:!C ƒ09ßÑoŒÊÚ¶ +>…Êö¨œÜb{Æ¢r¬³¯•£òÿ‰e˜k ?¶Ñ£Cui¼‹ÛÂŽ}ªÇ9ö?ƒwôø±¼×Í0q«¨n+dÍ»qØÅÕ<‹ÃeRÖgÙâ ~ +=ôH‡XÔŠO¥Ä××âÃx—é˜aâmf8•ÖWgêvD¸Õ ì;‡øisG«v„ŸÆ +ÌkÙæŽú-k"V›,¬ñæüNŒž­DWU@²h–´-EÇͨnTÃ82ÃÀ(JéRVÌì}xaP÷$ê†+÷fÑP5œQ;„ŠNލ¬Q%‘IZ‹kÅ4¯(k<ô¹âØc¥ANÚ+H¨Ú¿_/fÛÔ7°ÌA*lL©¨”A»Agg…χÚ̓ ÓôœTW‡ƒÎÆBØSo€«þÜj[±fIz :²W›ôXQep¤†¹æ@ãŠ&C¡w&ZQ´îÐwèVµ­pŠðÝÈx¶Ãâ‰"Zߊœ6š)ÒdD”}?ã®7\!$f]¼¸ÈäB–ï)1“ŽÂi³ºÜ‘+õk_Ù-ÌVôìË|î~гÆ¬î‰³"Du+áæ8®îg·‘{äh«ŽíEítæ µ¶a—f™Eá2OЬ2é»Ð¬ŽÚ×FÊ)æTP>Á‚ŠÛ4C¶Kšt÷÷¨†R­tiYëQ íp¡7Òkv‰Huôò#½‚J7•b‚…Í%ª5Ý4{Å%Ÿ\‚¼ûþœ­j5o´íýmÀõ×ò˜{™ÿtÅüPC5Õ¹‹Q‡kN6mìÒ@ÎS +uàÍÌËÄÁRhùRP6Ðm I …±^Þç—¶gj±.è¶Pv“MˆäF`€ËÇsÐibËVÀS“N”'—£h}ôà›©¸/Ïh{0o© ¬Œá]ú· zÙèÝѯ–[_9:›OleHvuFIŸ©# c/sÖV´m­'¼»& `žìcã—Ôx®Xü­ˆ_ìÅ6ì”tXxáæ-õá‡Ù$Äfõˆ¡î!ŸÞÐmvà&E¡c£ý|”,7#ݲäÍV Zȸ2÷gëWuB¾&£1“x½'׿(;©ÌÍb¨82ù@¶_T êM"†îNb`ºØ„ìÁ³¥]H„rlí!5~‹K”ñÒͺY3VU‘³ ezÕOd#1i¬$a5𦘴"›Ø§TçÁ}“¿Ú:(¼H™~ æóK^Òm˜»ÚNM—/<Ážu[šÝóNßÄ%0õÐ=4aÉ÷s‚ÄxonÒpž#ôÒèÒ†l§ÿÌ~Ûžð3ÜJ꣈_Öï ºVnzLN½+åa^!ºù@™~tµxÇq´…kYS“KºÝª‡­3Ó…Y'3ÁFè8—0ë)¹%¬éÍU']UµhãÅÿÈ¡âÙ#{OA¯wó¸-d¤óIk‹ëStøëÛé÷ÓuQI +endstream +endobj +820 0 obj +2219 +endobj +821 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Contents [822 0 R] +>> +endobj +822 0 obj +<< /Length 823 0 R /Filter /FlateDecode >> +stream +xœXÉÎÛ6~¿ƒÎ¢p§,û×½€ß m ¹ôõË!g£,/- Á’MÎúÍÌGý<ÙÉÔlš‹«w_¿Ÿ~œÖÛéóV¦2M·o¼"ÆÙ,“ϰîöýdfãC]ðuúbŒwõZ~Ÿnóòg›†å¶ÐrãájË?o6îe³SdÝôÏ©Þÿ:Ûf¿Ý[šÃì–תyy™½–;^nc½lÝr©ß¡_æZ¯µ^¥‰ñË\ãPMùsMyÐT·9×ï]ªßKßj ˆ¬ð.Î! fDz@m5Å€ŒŒrºzW´zõg´ô‚ÏWñÏŦ¥ê¹f à†{IFÝAjß-§Üõ9M¨ìè°ù¸UÜE?§0…Ðe +)Íi™>™9»é×_§o¿ 0mhÆÝ3Ç4/¢÷ R!±Pq°+Ú¹à}Äø$3Êðµ§Ê,²¯ù»f*sIG¦TXtSÀ’Èx:‹Ð +­W¬]/±tï1’IöÃZ·öç0_”ÇWñªy@¼È³ èQ•ï6\UºŠ’±¡QÙp Ÿ‘D6^qèCt4{Ñ'º‡ÿè7(o•_„гÈ{ÚÔú‹s·ÏfÑÏ1\ÕžÒ÷ô|AŸ³ä`ŒÁP°˜g—¡{ ä W¬_úMqRAƒ¤e„Ðc4§°€hÇ¢[ Cÿöö%SNª†»–Rºn¹G—ÃLÜG¢ ÖBëgÄù½e Q^0kï´Ž2ΕqVÑ/Ç{U´6+D[D ýGH$™ˆ`NÈ„²_Ez–%TÊAÖ6 #ì£î>ª‡§m…CyPÆ1ØZwüån3xˆèa–Z$š:â†Ø12ÉÑ<#CaUzH.1ÔË.‹ÔÉé â¥0‚iÿ3>¢Nıx’¿7µ£ób?V/~h½pmš©À\<×ûîeq‡bçpWgmóŠQW:=Þ7¼0ðÔ º©2ø]„š#MØû~Ð*ƒ+H†V¹ …N!¸¯*¼jÀºƒºíµÿ4¦ŽŽJGúˆœ–½ÉÀ=8ä¸ÐJeðw ×ýë(#·Ö2FÖ´|–¹hLÈÛ1©’3!Þjýqúæ°@è +endstream +endobj +823 0 obj +1320 +endobj +824 0 obj +<< +/Type /Page +/Parent 878 0 R +/MediaBox [0 0 595.25 841.9] +/Resources << +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << /F10 154 0 R /F9 148 0 R /F15 836 0 R >> +>> +/Contents [825 0 R] +>> +endobj +825 0 obj +<< /Length 826 0 R /Filter /FlateDecode >> +stream +xœ½ZËŽ,· ý‚þ‡^pY¢¨èÇÔ>Àü/Ø@¼ÉïGR‘U¥z´o\fº§DRÔ!yHÝßô]¥ú®Ý!ýöËo·ßoÏïÛÏs¼Çûýû×ú†µ“ +wãó{ß¿ÝÔ¤Ò ¿Üÿª”ÂôØô¸ôøô„ôĿݿÿuƒ8á= øþÇ=-¬KLzéy¦çEŸß$â‹>ï‹u!éorUìäδ–e¤uZÑO½èÓ@ò’~ÞÓô¾Nú´#½ÙŽPô±Ы)ônh{ÒÒþ$ÛÄ~mÄÉB·V÷v›òþϳ¶+çcLnD¹TÃý?·ôû7ÅlY­òwƒãSfrx®¼½&×oÔÔšäñ ]`bªz#G—H~‘Ô™4½{¤Fæ›>?[‰ÑÏñ.ŠU£è6¦êÿ£¦øV‰Šãô™ ‰54ïÚP0Ò¶,Ùñþ±„sl—-Z¹j×&”}»Ð‹ø±k»T-ÅÆ¥Mvfæà ìR"ÙfÏô' +õ$°E§±‘¶”]ÔÕ6x©Òf:؉ÏYSî(¥z7²4›Í·âÄ_ÍtÀvú†þ–)Cåsgœ|"Ðj¤Å–5ÔÛ0ÅaÄÍÀ‡†:èöÉéh +aK²ÑÐwéï(Þ£ +WûGŒ“w½‚Êqwi 8ßPzÏžBÁˆ m9¢>~¸áÑòò|¼y›Å½Äð4µ¥r°ÚÍÇ¢&&myéAʽ‹ïHýQ=ÄŠ]ßó’m–%1³ŠÖ;7’@Qx–Jé[e¤]ªZ \¶Éÿ/lºB÷í-b¦+Ä£¸dŠPÓ˨WEœ\)CsO¬ŽA$]w&W¶ ‡œO×:èÏå'vî¸ç(ŒØŽtz»Ã9ÎT–{6õ™ZŒ·åŒÈʧÛâlXÐÆœå,ãj =ZxÚÏKÕiÖ¾NT¢öŸÂ ˆ ž‚"ÜH6D1sºÛ²‡Hô“ùžÛ;~9´é ýHWÐÊïÖÍàhª¡•›®oEC'"ê•mÚ¸Kä3Èîªù¬¸ÖVI>é¡—"~à='•ƒa¢*Ç/£  f§ýûDã&D·ÚŒÂ<ôNò~{š*ùw· þ½¸j´X JßJÜi¯ÃnDÀÚ%.ÔǺƒ`ùÐÏhèÄJ!ªH½¯@Ê9ÁÄW“•’  °^`º›o¹ó˜-ƒ§K1ëЊëÕ%GíåPQ/,Õäµ0lóÆý 2ž ²m:È©`]2š +ò¥Ú(_ô+æÿ÷~…̲!Œ¦úGs5Ñœr\¬çu›)—¼èØÌàT7–£Áú:ŠMv:i¨ìKæ|ˆŽ’‡û Ú°ç?_TýäìÄu°ÝF}Ìj7™2¬Ä¦Ç ÃZœpK„H6ù +[ Ý›üCÐZpœ9–æsÜÚÔ2ÕI½¸áxº°aµà–Êc–±Í2º9>Œ>ß®Ò 8i@wM@P]Ãmìy Š=áoÕŠ˜¾XÔ÷‹f. sËã+ÆÈ=¶ *Ýù‘ÛâÂADÄŽ«':hWN-Ô‹ ×Âöd ˆ4–sïÕž#SYÝ0Tž ò°€YÞì\^3flt+j¶Š|õÕöÂ>Öõ¦ Èâ± 3fQ1öm2]“`/Å—§óòTP¼ˆ¿’î è©ßËãÂ^5ƒ ÷ÕAí¦b:8FQ»j»Âx B»Ìµf0i.Â÷Z—±ð Fÿµ…‡ò†ïôÍþ¬ˆ…ºØr3\•yåNì@§ [ö;ÐX(±‹A3ÏщÔì¯ +½zµgì9XA‡Ìá$Z/pJHÌO:»Èü°Õ[æÜñå4‚(•.p^ÖêWã›ÇµH§¬ã6)Žo€xØÄ‘RHÌiiÖ>äyÇfŠv”…P<ú&¬ÂªU}3úÜÛÚ€hHZÁ\ØÿÙÐÔ)SÕŠn$˜¹ˆÎ@p.Q> +>> +/Contents [828 0 R] +>> +endobj +828 0 obj +<< /Length 829 0 R /Filter /FlateDecode >> +stream +xœ­WÛŠÜ0 ý‚üƒŸ õZòJa2³y/Ìlۇº/ýýJŽ;™L¦-ËrIG×cí¯”¡?PtFzzy~ãuxš²ÊJ]¿/Þk“”,w}Œ6Ö‘À‹údŒEcÐ}V׋xðÂJr7–¯"þ4ßE³T¿z~L5à‹²áo·žF§1=†^ij¶¸Ç%0¸x ë™®Dšy¥jÑkçVº(ÇŽŠ~œõͬY¹ÿU­àŠw'ºFºÎòÞ»`͆DøÍ®YG=‰nµAz`ä3 Ø#| 9y <‚[RQðž¯Ô,Þêà”KÚ%åBÐ!©FGTo߆ïj7QYç°ÓQ1ÖÙÊž:HIÖÉ%ëºßFq“oQÂáwrÕžÛ»þ}UAñÁeîV©þ® q†Y\8Íß!‹;'ÉXû(n‰^±357ÙµÞ-0{nQcQnÅ-»ò‹*e)t gÄ9åù2·TE%MÏM† \üåß&Á¬Jçܸ¥‹ŽUé~ECF@©hZf‰]èš +§¹é$•AÒ*M cçjèªÊ·óNºB2:-¸±ÇåðÏsZøÎï%e“|›Ö²›4m°±FرwfÅá’ÙQÊÐw§ß³í£Nµì`l—œîضÓbû¨¼ÁvíË Ë È³.îõlÇñ›ï°±©šl[Løc¦Žþ„1wÔº¹ç,^vìû”™—oÈß5}踸3ÆÙfÉnlœrÃ3S«Þ>vLudhhW±ÕnãªñsÐ4W®¾ƒÐtù†­ Ý^=ñ­_N­°Å*Dð.8Þï'36†d&ÄzŽHb‹ñ<³faÆ(‰® ¾¼KŽZÜc¬dT[<> +endobj +831 0 obj +<< +/Filter /FlateDecode +/Length 498 +>> +stream +xœ]”_oÚ0G?A¾ƒ»‡*µØTª*ÑP$ºM£ÓžCbX¤‘D&<ðí|n™:$ˆNüçþŽÃM^mV›¾›Tþ=Í6Ljßõm §á› váÐõ™6ªíšI(ý6ÇzÌòyñöršÂqÓïe™ÕžG™™ÿ˜/§)^Ôݲvá‹jÃ>Ë¿Å6Ä®?¨»ŸÕVîmÏãø'C?©‡t'ô-#Õ[=~­AåiûM;Oê¦Ëý¼øßŒ÷Ë”½ mm4QšùÎi¬›ëþ²§‡ùó¬žÖóçùZê¿ñrÁ²Ý¾ù]ÇÛôtI¤?‘ùD6‘*TBKTZÈ3&´€*èÒÐZA/P Uìi ckèrК™>‘Ưx…ð+I­ñ+I­ñ+ñÓøyêiüõ4~N*àçpÐø94~wŸ“êø9©ŽŸÃAãçe ?ÇIhü'hðsT0øy*üî?Ojƒ_Éž?»Á¯™â÷‰ßÂÏ.!ü<'aðóR?Ï:KjÏ:+O…Óµ¤6¤¶¤¶œ‹%µÅÏJj#µá\¬üëHmIm8OKjdzµ¤6RÔ†çgI]˜ÔLÒ5ú£‡n=gV[(t˜Íøµ ¯/•[¿7ççVOï”ÔãÙÜÐ]n/§qÓkbþfŒý%× +endstream +endobj +832 0 obj +<< +/Type /Font +/Subtype /CIDFontType2 +/BaseFont /YJDRSH+TimesNewRoman,Bold +/CIDSystemInfo << +/Registry (Adobe) +/Ordering (Identity) +/Supplement 0 +>> +/DW 427 +/W [ 15 [1000 ] 14 [611 ] 13 [778 ] 12 [722 ] 11 [667 ] 10 [944 ] 9 [722 ] 8 [667 ] 7 [722 ] 6 [556 ] 5 [389 ] 4 [722 ] 3 [250 ] 2 [250 ] 1 [0 ] 31 [278 ] 30 [444 ] 29 [500 ] 28 [333 ] 27 [278 ] 26 [556 ] 25 [389 ] 24 [833 ] 23 [500 ] 22 [500 ] 21 [500 ] 20 [444 ] 19 [611 ] 18 [722 ] 17 [667 ] 16 [722 ] 47 [500 ] 46 [500 ] 45 [500 ] 44 [500 ] 43 [556 ] 42 [556 ] 41 [333 ] 40 [556 ] 39 [556 ] 38 [778 ] 37 [556 ] 36 [722 ] 35 [722 ] 34 [556 ] 33 [333 ] 32 [444 ] 60 [667 ] 59 [333 ] 58 [278 ] 57 [556 ] 56 [333 ] 55 [778 ] 54 [250 ] 53 [500 ] 52 [500 ] 51 [500 ] 50 [250 ] 49 [500 ] 48 [444 ] 0 [778 ]] +/FontDescriptor 833 0 R +/CIDToGIDMap /Identity +>> +endobj +833 0 obj +<< +/Type /FontDescriptor +/FontName /YJDRSH+TimesNewRoman,Bold +/Flags 32 +/FontBBox [ -558 -328 2000 1056 ] +/AvgWidth 427 +/MissingWidth 427 +/StemV 120 +/CapHeight 500 +/ItalicAngle 0 +/Ascent 891 +/Descent 216 +/FontFile2 834 0 R +>> +endobj +834 0 obj +<< +/Filter /FlateDecode +/Length 835 0 R +/Length1 35252 +>> +stream +xœÄ¼{`TÅÙ8<3gÏÞ/g7{¿Ý={?Ùl²ÙÜ dO€!A‰ Hä&$€ x/h+X­ˆØJ­wû–°A\DkZ­µ­-©¶•j_¡-µjÒi+$û=s΢øk¿ßß?_–™gngÎÌ<Ï<·™Â!’ÿ–-½òj%…~¡q(Yl‡(ºjÍ’óùfˆþuí•×÷)yR QhɆõ¡J¾!mußÚ¥•zýU-»fÕ¦^%8‰Ðâ¹Ë®]½’¿¹¢Ó½}×\«ä·@êÂ’k¯¬<@|®oͺõJþŽUý®ë’lNÉß9 ¢¹«¯¼vi%¿O3›¡_ެm[diýL«Óʵþ©a +…¿Ý~쪳;F¯äv-´ÕAÀÊôà±ðXºŒCgw|nàP¥üË¿ ¸ê«Ÿƒ¹¿êEÿ,è…®”éO!dFÈ| !î_ÙFÈcpEr7"ä…uó]ë¢F(ø:Bᵰܰf‰ûJÿ¡êwª±!”ýBu%„êç"”ŸƒPCÐôm„ZâµÂ0'@¿È·?ƒÐd(›ò5„¦ºˆ 4†8kB]°VÝ»š}¡90Æ9·@x–Æ0÷ï̓wÍ_ˆÐå°æ Íõ-\ë|Å2Š3y%&7Q+z©AÊ"v/y±ˆ°÷ ž)?s?ò!TþÀwùƒ±éåsìJ$Œ­(Ÿ`ª`µ¢J¨üÅÐvE Ð˨ýœ0¨× yH…ÝȃnA30‡\ˆÅz”DL¨9ÐtôglBûQúOAÛp u¡‡QÍBNÔŽîEûðÔò‡hz /GÏÂÓOa %ÐL<­|ÍFÝåçáG»ÑCØŒx¨Ñc¡üô°Ý^@¿Ee´=Èîƒ^ºÑÅhuùy´ý +/À——ýè"´ÝŒDßA/¡“øN<¤bË‹Qº +­Å\…“Ì-å§P3{L÷\ùÕò0¬Öjhûú˜ˆª)åO„>Páò2Ä *T¿ÕèQtý»q3 ™QÞÕƒnDû™$ŒqÚs{߀÷3æòc0›&´mA'ðõxˆ„Ùcì©òfdƒùåa¤w¡ÇÐÑ+è¯ÐÛ<‡¹v¬PžøÓ"uÀ›¶£ÛÑ÷aå~¿W±‡ñEÐóñ{øÌjæ}èùI4‚Πá$^Žo&r ›ÝV~Åa†ôqº ¨þ{8Ž%|9<û0ÙHn&[˜CÌïUIÕ§åæò+@#Yh{ zæõKôPÍŸa4ø·äff½½|Œ7‹–Á,¶£ÇÑaôf±±‡p=n‚™Ý€‡ðH€ds³ŸýZySùë( ´Òƒ–“+Эè6ô<:ŠþˆþŠF°žÌ“Ü¿ŽwâWÉQæ2f!ó€JR= zVõ#Õ9ÖÊþhìWc'`Õi?µ¨~=¨m†µ.Áïôf°¡§ x:ô´÷âñ.üMü]ü>„‚‡ñ‡øSüoâ&_#÷“#äÇä(fLš™Ì<¼¡ +«ÞQÕ\9{yìÓ²¡,–ë˻ʗß-ÈXðÅÐ$ ®•h+Ì~ú&ú¬ùAô ô »ãòï$:88‹Õ@MQ 8«av—áyx#¾ ߇ïá?à“øAÄH"ðK“F2,$·É9FÏL;s=³›y“ù\µ‰ÍÁïYö9ö”ú¤&¦}ãÜÞÑ÷ÆÐØò±Æö–€Õ@yU°çòh"ÐÜtÀòÕ¨~kÑ´Öh3¬øÃ@9ûQA¯£7`í¢wAjÐñÒ߇€‰Óhaød±~ÊØk3“€Z㥀[åw¾ïÀÂo/þ6þ¬ï¯ð›ø-|ÿ sB$CÚÉT˜Q7¹œôÀoYB¶‘»ÉAøý’ü–¼KþH>g8ÆÊðL‚é`®aîdîb˜ƒÌ¯™ß¨âªvÕ4ÕJÕOT¿‚™Oc/b±KØ»Ùï°ßeÄþŒ=É–Õ÷©U—ÔhôšFM·fŽf‡æiÍÍï5emè©FŸº€ÿ߇/WeÉ.\&%˜÷Èzæçä~üì…"‚½ Fp5ZDJÌKä[7îbþÈ|¯UMV$p±7Ћè ö-•ƒýý„xÑ'Àïg®$? {ˆ72ãU·©Þ®³ Æù]rœhÈ~hñWÀÆ"t)ö ¿«æ¢Oaý²wÁšN!ïágÉkd:Pò1ô9‚ö }h)n‚Ñ]žCŸ£{ña&„ÝmAÃèctâËѪ²£IAí&ÔãC‡ñìòOHªüWØõÀ·¡w™ÏöçâY8‹ž@¬ÿç1¯SùЯ€óÑ^ Ú¿ A؃?SEa}†3y´@upžýéØdv=s+>CÚ.™swQn <øAàU”šÑ~ à"òŽþ+úŽÀ*¾¥~=„v¢Š1“­¤Ì¼® +¡o ÌLxëMÀŸü8=]‹–Ã|MÃw£Á±«ÑÈ7ŽáPÓ»ÝÅ>ÃdÀþB]‡®‡]»°øGt¤F/µøýh}"ìžjØ?í0Ši ÃV‘ùÌKhö¢>àIàÛa &×A/· ¯Á~zdÈ/Ñ)Ìá…èèììó%ð~-ô3] +X_‡žîx+„’«Q¥a>ÇfÜLÖÃû(Ÿ}øìŒé÷è}àey\Õx<ž Ø[‚þI÷2¼¡uã “¡”“™7ПQ¤ëDØ£Ás‹6Ì(€ZØ?a‚ªÇf•›Éræ%ìihªš’}î‡QX`£È»PÃØTèíYàeÝìã }E âP]Æ^ +ã~$Ù/ÑÚò<üf2ó6sJÕ×nDsTò¼‡W9àgWU^Á«ªÕ>TRæ…Å*W®¤2 &C¼¥SÙÐVY .@X‘cŒ$•­x}½T°V«°BsꥡátT_RÙ]î-Ôs[)ÔêhÞZ\P/µëTVPmh;+ºDÅîz¹º“öbES•ÒÁÉÊS•â¶Jãqõ|{ò!„>û!œ‚ †Ñ[QÂ.e*9GÛm°Â>'h[¹7m½¥Ý§â †“çÎÁJöA‹UT{c‹J «¢E]QiJ¥/¢Uüaè„ìGÊ Š52,&S9¹¢èõç^R1d(<à¢Ó'× âĉ•Dc³’LgrÇÛõ*„>…@T ¡IËO &kr§^†Ôèø>.rŽÜK̇ÌJd‡V'¡•‹·¼Ä¬FYt&¥A)·«ÝÈ”`š%XƈÑ#r,1o¡#xßÓÌVØ^…À £ CøsÒÌѶãmŸ¶1G;w~ÚÉ}ïø{Ÿ¾ÇÍÏ|ša¤N߸\Ó"¼oCCѵPÀ]XµˆYÃlav2*žÉ2 ÕbCŸa«©5H†nÃB²Ë°Ï0`2 ØõzX}B}JÍv««ûÔ[Õ»ÔûÔj^“Õ4’Zuª}yuÄÚ +ñ.9ÅÉ5CËù]r~1Ä}r^‚¸[N ×ÒúzÚm…xÚŽæˆki‚ÜýwPÖñ.„üNòGj£R”pÑP”€Êp*Ї£'¢d :%CíãÈ1y”Ç`”ÇäQƒ'Éï>ýB +‚£}[n÷6´{[n÷6´£©ÿV¶â>9%AÜ-§ˆkiм]š,í.²z\ñ#ŽC`Pâ„5rާ-È^ˆ%òÐ`¢>y¨ ¢€ ü2ôxs‹Ú-  <á8Ñ¡@så!²§8™¶ÝSœ €qõÇÛ[@ŠÒ¡ìAû!Ôñ#r* qANí—ÛX¾È@|BNõA¼ï‹çÉ)ÚŽ‡pþyy~{ e!›¡t³d Èé=ÞfÕÚJä…âr_"‹IÀ Š´WÖß„?‘ãïËñ#r|¿_&ÇÉ ˜þ-˜~,˜žLíz0*¢P|JŽ?”ã’9jú jz-júnÔôhÔtÿ E ",y#¦?GLÿ1=1=1Ý1-Œ˜fGL3#´«$ +! Ð_!Ç~É2 ™þ2ý + OÌø€–Bc1½ ª +ÐÓW`‹é¾„ÇŠiÀÙboÀçÅÞ €3ÅÞ<€Ï(xÿõèÿ­Øûmè„’´[ü'Ï,; Ðúyåíø jÃ1(.‚æG›}¯˜†Áá§Šé$€'‹é(€'ðÝbšðbo €o{ïð­bïI“«h{PRîçA—áºb§ªû‹´‡¾bgÀšbg€•Ŷ_X^l;I½À@ݸ¥å‘^YìMCõ¢ÊDzPR®^ˆäž§;é’L¡´›pGe"“Á¥Õñ¹©˜®…fmÅtÀeåZ‹½"€æbÖ7“߆•k¬¼ Eñó"ŽÂ0hGB1ý,4⋽)Ábo}UUy« µÉƒ²Ó´WL‡ø`ê•{Ô£8~è? +ýžm+á¹Eþs©¤ÅEþŸI‡ø;¯âÿÚY­—ÿ¶ñ³‡øãÐô½6HJþ÷é“ü»½þgih!ùøŸ¦køWâ›øRò?ØäÀÀz¯â÷÷Ê=|?ù§’%‚áé}½3ùÓ"¿;^¢cø4¾ƒ¾:º-½‰¿%¾¿Ha}ç~]:À÷%¯àW$é‹\üòôÅü2˜È5ðÌÒÞkø+Ó÷ñ‹ä_‘þIƒ<‡½òŒ.j“+¦õ^ÌO@EVÀÆ]æàÑš†#t@[™4ø þÒ¦ Hb¼ÂZ©Fó’æfÍUš9š‰ sš˜&¬ jìZ›–ÓšµF­^«Õªµ*-Ñ"-"öRù„$R·¸]-{ÇÕ*«ä4GhL?:ÁZÆÖ@3ƒÌ¸dâ@“8£¤)_<Ð,ÎÐv_>ïÆ÷ÌÇ3†– W…Î\"”°~ö‚V˜ˆl3ÐŒ9ÝÐx€ÜYÂhμ.Ó'nó Ø&Í;Œ0®¾íë> +§Üöõùó‘sCÁ]°µY[¦Lþ/ÑâJÜ1YüòÏ-Š_ɘqɼgór4QÌŸ1º$´pÞa²Š¬è˜|˜¬¤`þ¼ÃxYÕq1-ÇË&χfãåf¨¬„f¨“hF¢6Ú Ê^Ð ìï¶ŽÉÚÚ”F]øm›¦Kn´@i4éÂFÌÝx’Ühs·ÜèÛÊ Ó0x¡D4cW¡´üÂ4»Jnæ¦ÍÄãÐSoœ69‹Cƒñœ\=ûËê¤Rý?JõÿÐêÆ_Ö7Ä•Ñ&Q\~Cœ$¡øÿãßÒ‰ÿƒ6¬ž×±TèX,t,…°xàî ËÜ[¯ +…¬Þ@+BL|ñUK–QxåÒ ÂÒÉ«…É¡æý—êy´z‚0ùš×1gÞyÒÒÉÅ Ò„áÊÉógmkîÿÊ»v|ñ®æmÿ¥³m´³fú®Yýÿ¥ºŸVÏ¢ïê§ïê§ïš%Í’ß5ãâ‰xF÷¼Z4qþ¤… +$=ì–žðü‰N®¯MÞ:ãÃî›}/¨~ +ÄùFa†­Ê´gÚiliZe†bK¥Ê}óø°ïüT¥Šƒb«0­ww,Ÿ ÿÖÁßúõ×Á¬ñºuÊZ»•Šõb‡\ ÖCj½ü-!MÃ:¹´R¿]÷åŸ(*mÑ:qÒ¼îå“} ÈRÝ[œ¿‰¢òBQDðN˜µ¬ì;eeß vÖÿ¦óÏŸu2C²–? ᄬå†? áhùAf¨m¸íD3Ô9ÜyÚ¾7üÞ‰÷˜¡ÌpæD†iªŒ€¾j>†~ù»N\w-±<[yÞt 0hHÐYŸ_†urÅzyaàO)—¡#ñ‹ÇÅ/ë”ÊëäG”Òu_Ò0TÐî×_'þçŸR +ÃÚ$ØëgÁLÓkâA‚_QkJŒVªB¬êé5ªW0òhÕì+„y·#Žá¹È-rgZG[gq§[;G[QÒÜ9ˆêjÃÖ°5ö«Ð¹3tNbÑYR çg~l?; ˆ ÒBïV>/Ј£‘H£kª–¹¯‰=”*%Ùk¬Ë!³Ûú ó±*õ³&@‘ˆ60GÅL" >ÒÚ2~K€@›¶Vƒ»5XsSõ„çÜ"Œ­§F×ÓÚÉMš'q(ÎÅI¼Ù9{­±7žééü°Çw(ÞYkÇrnd>̃)´Žˆb]íŒK6¸B;i“4]9¯­ÊZEÔÉD*‘N0ê/sDít¸n‡Ç¡RGc"á4/D‰*?D(cŽH ‰\+ÅBšþmÛ†zpÍÖ7Ô盬ùx\Â9—Óæ°›‰F-0V»Óå¬Ï55Z¹D<÷eÆ,:礖 YôûŸ;²ð/ß5áÖ\•¯þÉy×_ÜÞ;- 9–37.Ë'bg•ŽîüÛ·yªòÙ÷æÄõ–µÆ>¼¹šœ¤|BÏdÑ]R&,5ù úP€D"ÞPÀ‰øB ¡€5"ج Dk½ï#¾6ƒžî ÷¡pBkõ’¾O?¤W-‚ˆè=¡0­ôùùaÜ +“Ú°^Þ€ŒzÂÀMOÿZ‘âg­(c¾ÐJ¢®ÃR…è|/X‡Ѩ5j¬…³ž|2:>3>ê5äUø1M[ ®I-±XÌaޏ{•¹+ésÛ! 3]Q>¡ +³+Q ÎH-îÚËRÌڌu¨®u[\bÆ"r)k6£ÕéFñšÔŽÔŽôÓùRú…|UK- ŒKø"ÉXùFÒøt] \ +ð!ƒ^y½4%¸y9/ñ>íH‰mÜb°Xü¿EµÁ²!µ×ò¸á9뵘²TÛPÇ ]>ï"`Á¾’ITTÉlóŽ— ¦üx‹–Å +Šòu5žq%Ür`žLÛ'Gzfqâ™Î‘ž“=¨0R±ºZzú±ÕÖÒÒ‚¸{Nô`näôˆ’–“ÔdÒœyRˆ10KÅņå–͆M–ÛS·‰ß´|ÏpÄð3ÃÏ,&ÔÓ?¿®b܃«@ADí°»œÊÏaW  D(ÔÖz@H®±ð”¨! ùÆz ]ZÒÄüÈ +üi{ïFG@Ê>óÉ%ýó iíÜZÞ;΋UŸ½·ï¶úeÛ?zÙ'ÏMlËÞáóMìʱÖgŽ^;5#dkÂs®[¶ìög>óFíÉAÇþ´yví‚Ùí—oýö¢GOrÆöЪCÎ.ÿ½ °ÅÃÈYÞ: Ä_R ºM¥ù0zu¾ÆªNïíλ½;};üÚ•Ö•¶MÖM¶Ö'ÕO™wýÄõsŸ^íDñIÎvÿVçm®Û}ÛýÏ«ŽõÙø2~£zƒiƒïöª,š&³Õý‚$ì$ÃO[mfvE€1¯pèð¢¬[½}q·ÅVÆ9DQLHgÑó°E:=žÓ”ù *©‘ù³¸`@'4¶´|\Áâ~ª0¢eDQ§_m2Æ]1­N£#j_ÜäÔÇÚ‘ÁmŽ!—a…¿¤EqÛ6ÜÓOQ(+5V‹°…ì6=µZˆDc¶(E-b/KTŸzp˯ë + _}xëo6¬ýçã¿ÛÿüÏñüí|d¡'”Õ‚Ò¥W¿±a÷áCc¿ÙÓ·ãº+¿§”~„µE³õ#qàð&à(1´Sj¼ +oÄ7} Õ.aWô‰(ó%s™QØJTˆ0>!ŠPŒ‹õŶÆöÅØX –¸P8I€ç€‰ ½‰¾…Kd¿äü’ýxâµ )±/ÁL »¡GC=­§O¢B˜øhëéžÖ– [Bf*”ÏbæÿÆV` ` `Lõgg^À]Þ/s·àYÜ¿j×ò,þýXô¿p™}ËZ̺™í“o½ v€]FoàZé¾g°z¹ ÜFáîváÓóœæÓ ‰à¨@PDÂz³! w…Ý—A‡uDÐ9­Ž€Gõ(â\'X¸€Â\˜„ÎX9»ÕÊ D“¤Ùb7›-dƒ›õ›­8lå,*§¶š‰ +»K$šŒ`|’“8 ÛR¯×i-Nì|ß‚\# !½§6ÞßߎŸˆ«c\<—âÝP²+>×ì¼·Ÿë9íñvŽŽô 7,-ü +­^V{´ÕÚbµ¹`•!ê±µô´Üa®µ7q¯tÓDÏ«"P3üs#(zH‰{.Ìh¸ÖVMkkE"kV2°ë±SÉPÌ5äA&†™3nñ×øVŒM¸èŠüç*üá”L¤m´Ï×rª‰Åφñ-Û'Š->N‹–ìU;ûÔ·S<‹9¹ ­J7ñø­±Œ"ÿ4Ë€Zq—´6H1eb]ð† ©mîhìn~½ŽØ˜¿oDý·£;üwöž +|ø<`ìk>ÑLx_ÅÛ¹(c-6K•ÅŽ¢(¦kT_(HkÆâ‘ +Åó㱈 "B©|§4 ü!°†“~ŸÝï÷¡ÆF„2 d Â?Ãc/jl ˜Äc¿ÍªE¨©ÙÇy±·MÔpÜ@ Þf*ouþ`^P3åw:‡3ßä“ÙZg¥u5'jÈPÍp ©ñ45—ðœÁ0HâXÉ¢8ët,ˆAŸ׊gzäÍäI’uƒd¦4¦¢0­½£FdÉÝrâ¼ ²»§g-e:¨_Äø«B»þ¡ŽlµS1AËœîHf÷‘dukÔc18'·T¶*éѹGO±¦ËzÆjÍ™YIJ‘¤ñ/™›a†ÝKÏÝòåndFΊª7Îu\íÊb1Ì糆˙×Ô'bHÁ¹êsÀyž%8U Õ×Ö÷ÕïªÊõ¶ým×û®ºt›ôë7Öì`¾agwèdÔßçxŠyJ¯Ù;R}wý&†Õ3z=©—ìÆÂýª‡u©¾¯{ÂÎ1ÒÌ6® hB¡€;g×Õý¡: ªgcüs6 ‡©ˆ€ÕȨ1!ç §hw8—Æå´Õ¸ë’)\c4ºSÄ­Uk,š. )@´S³_sTs\£¶hÖhˆ&W¿_|Y$Y± v‰‹Ä5âq§øˆ¨oåœ}Î]NÆé•êq=²˜x1µ…Cž\E%–Q[7=ý€QÐÁ² Ù#üFZ+{º¥üA}Œ¸Ñ +8Ÿe8¶²mÅþøC zP)Rojˆ àœf/äºT¥X¦ÒR¤Æ·m=;{¯¬Ê›ýƒ?çbήR¸/«÷Å'fTkâå‹›R{ôÛ£ãÖß_?vK_.4pplöy6¼Ð!€¢=¶æ¾­AzòO%Ðï¿Ê€NV¸Ô»Öû ƒÑ +na†wªjäJÿ’ˆÆ†X¤æXN­ªÍ^ãÛèÛ¹SxÃ÷sa8«Ýãüµ÷ß³^6«5–Èo4‘–êˆ`‚„Ô»Z€Íêã@e„ˆ]"[„»-£´?ìÛ99a¸Hwd8 GpÄ•öG„x¬ÆW”\Bêh¦¦ªÊFBo†Ã‘ˆZ­Ñ‚ÚŒYIgDi.MÒï¹J ‘œÆh ˆÖ‚yLpÆhì6aÓM5clõ´R>LY2왓 197"Ë@@iëpi›ŒÎþµ=-”a·ôP6Ýc†ë–w-¨¡DµÝëˆyâÉXµ=Å /D¢3“Å)w<‹¼¾/ Q1Zz&QçR²ü/É`lµÆ¿»ÊцEÙ î2Àþ™ªln0jœ ;G¨°tÌPz¡ª£@B¾É=£Ó¯˜äH6œ9¹kUÇxŠäK5Ž]:6c~ËÝwuÝû²blûê–H,&4¯fúhjòó7-l-Ämk1B ¥òEk‹±TþKs¦ä˜ZÐyŸÄ|ü…÷­¿G‘•Óp(·rˆbåØÖÀ‘8ãûõ›»_»oì¯ïÅÍ/\ÙµùÒ=×tÌ»êê½ì"ãØê±7ÇÆ^;÷¯W± ×àûfþàá±ß=þÄúœ„=„2Ãj*j@<|¢‡¥NJ§¯f"†éVͪõ`…1qU\7Ä]Ì}—¡W¿A»Þ¼9µ«æ9Õsú×T¯éßW½¯?ÞÑëÍ¡€="BG$Ÿ]]]"IiE"·h±– +]@‹4X3›Ÿ«š`(Z&NŒ]&Ò…ã/ÇpÌ;Pƒk6Y̼™˜Û°É j žŒÝQŒ’$NM¦¨Ýh¡1”ŒE‰C›©yP6'` ð8y+å㭧龇ý/g°Ìù9Ê#z@’ËüòïsïË*<ý³žÿ*2½¿ÂÚeÞNÅôôŠð>ÏÖë Öv¡êé• 0Ë3šëªëSæu×¶> + ý­Æ­×Ž^öÃÆ®¼@tËJõØ ;¶û,€#[ù꟨#jip§î_)r‘{¹çiwÉýºçCχ)M‹kª]`m4¢®Ü¢\wýJ¤µä¸z*£ûê·‚PßW?P¯û>šûú*çØuºužõÉÛt·zö¡'è¤s{R(‘ÌÖ· ‹BSêÖ¢µX‡8WØŠ°ÎãÑètzÇíõj È8ù³ +¨•X]¶€5” BˆÃœÑàxo0À×¥ku’*¥B†Ryû Û •Ê7HËSZMÈ‹´˜4ÚL*iO¥’Fdà@ƒ3dÜ.»ÛíÒ‚®Oº=ö¨5šd* Ò.£A¯â’^N«Q»Õ—¦q:•NAÞí2_1Ô…xØ(Ä ×jtõ.—µëñK(„R¤IÈM +æÊC‡8kžóäêKäšÁ0höçU?ÑëéõºG½žQ÷¬Ž¥“ß—U>Eí£š€­em ØQ¼£³F¤bƒ½CQï•„™êù_¦€eÓâýŠÒÿ_T%óYÏœ¶U{Ó«w™öˆŠ‹âùtHgʇ’õˆóe½²§¿­æv+!†@m`é©Á€« uМFÎWUÉ’%Ñ ù$ž·«[Æ.KŒ ŒÝ›8¹Q"3§fë°þ7Í5¹ö¹·#èpgþù¿×ÜÅÎŒ1јqçÙï0+Î= ºäÉ)êXŒÀV¾at5!»6tôÁzMØáÚ0z3éX0ÑŸÊY« €´Ù ”ÆýE›-\*ÿ øÒFc ç÷[8 `1 he¿š+!ã@¯¬¡€sfžæü.l ÚäïjpÀAV‹ã€+¬–ˆË©µè0µýLxÕº,pÖ¤ùp·#ß7Ed'wº¿g-Uë;é~_«xj©§ê¶Y+U<ªÜ¡ºéU…n7”F(Z^Ų–ò•$±ªY8KZê o m ß‹vYv…v…¢ƒa“*¤ +§U C¤*íUs¥òåŪOHU6z2ÌÙ1ÇíÂûüÜ€_ È¥ _¤ÇÏqZ»¯ÀÑÃCÍ]@ZsU•ʧ*9‹½bø/ƒÐà;E³« È YáÀTµÔöÍÄa¥Æ…ž¨ê‘ D‚ÇÈ·„Ú~<4w|8rnåÊŽÐß7/ Nlcgž{žLÝ,Ž#`( +]‹ÏîV-?÷èuš¬b^Š6F½MÒØ ¡ïF‘òРۛPËj¸ûkt¯Ì@ˆYͼ‚R8!é qC‹Ánä +zP‰æ ”¯ùø¼Hóuy +·ù9*ÅN†RÂîÌs"~À°K$Éš·P¥øäRjìpº\(ò(,áOF\¯ñš„(Ÿ‚„ô9‹l-X$SÁr ˨4(¥ô–¤/B*¼èù]šaÍ £)á$JY\<Ø-i²»âŒ +kó2÷ô….h·9óCÜÁ(ÂEHäô¬Keû´§ŸòhàU§a_Œp'e´jH£xÓ˜9êWê©«E"VÚ*,;ës•£Ù‘äpQ¯‘«ÂÙó +kÿiÏ×Ú›'µ×4ÌÒèMoÊÂc¶yL3AÔêãµÌ“¿¾wQGaÒôÉ*µ3R¸òº·›[8Ÿ‡‰FÙ–Í„ívú½@æM/Ÿdž™@‚Ï‘Ü?ñâ„Û.Óšã&Œ4®¸F§5$­9ç)¨¤¸˜·¨°Ê+(ë"ƒ© +(È`°eBžB)šóC°@ ‹šd%áŠ' °L Я ¡k +Íyƒ‡z ·L44÷Ó}À†¢Tøþµòruë¡JÛ ò6˜ŒÃ\ŒÄø`(HÔö*GQ«ã>¿×ïñ3ÔÖKÀ,AìÔÙ‚È­ $¨­—ÀAÆKÏD~Ö•­³Š—¦ +`ˆÖ%q ¾_Äm2²}ê-Æ-\Ÿg«z§q'·Õó:y×oÑô™ú,[Ü;5[M[-;ÝZê èŸOͺŠù/D衃+"«iN§ÂÑ`ë%âxló›×.Ýüö['?b°(þ`)„¦áiÓÜãJåaÉ4a‡ÇåÜk5¯å58 –d‰QK©ê‰`g ²²±e"?‘Lœæh!'rØÂñáJ +ÙãùZèŠä±%ÏçI^ +ÇÅjú>J«¥d*_- ±¼¥zMõÎj¦»z¸šToìlVv1ݘ'[G‚ R©öôŸkåNŽÈÅÔò)ŒœneÃsÄÖ"feþ ]âÃyqþˆØ£lp¥ø0jƒyÇ`ýèž çÓÃËŠ»ª¥¬-²“±Ø5u)Ëôì*AeŸ³¾)çRø50ŠxC¾±I‰âòQ¤Fi““å#Ñ\‹“oáñƒuUî5/OW¯ÍLhjûŸ7»ú—]ºí©›‡t\qËŠu·_b gú¸î®ÆÖîLèºÞpˆïÞýˆÅw-óðêºdãø«ï»„ŸŠÖé¶Kï×Õ]V[s‘GZÛqKmݾå;~Úv]é›kV?2Ø^{öoV¾¡þ’é“<Ö xÍÂò?˜÷€RëP+Y(9Ô×¢ +q-9©urþî†û4{™Ê®œÑp¨߬y"ó½Öç3¯eŽ…ßÎkx?£kÐth¦WMw]Ô0ÏÕ«ý&ÚÛð8>„iõ¼µmê¡ÌÃu*ÔÖݶŸm­ëÇ~üø¸—ñ‰6½ÖÙݶ~<3MK6OßÒìjùt<ÎÕkÁ¼«“buL¬NµÖ?[¤žQÕO¨ï¬¿©þëõÔÿOýKõ¿¬ÿßú‘zC_=®¯-•ßvëtäR»6¬]ª½N«"ÚñÚ™ÚÍÚÚG´Oh_×þN«3h}Ú>-c·i·)΋Ðwª7;~ÉíF=Ù,qK)`¤n޽ȽÆýˆ{¿ûe·æ¸ûc÷9Ѓݒ™Ë» èaK5_­.T«ª'§&Yb<0·XîôõY]A·E÷²N@Ž}º„HœÔ¶µHm‹ÛHÛSì 7ƒ¤dw²PöaŸˆš¸&Ò”c)Ù¯aO±¤–•Ønv1«b=€ðK¸î6å p×þÓýâ{€åžî¡'%@úgè¡{9Ý ûQ?Ëè铜r ¿V”=ëVÅÈjá~ªåZÍ­­ Óᵕ]atÜõÌ—v®yœ_ÐsŒÊ ÄÃ1C¼%nZƒÈÒqDÇ4ç7±>Q³j|ÉW‹ä%¿ì¶m,dÙJîÝ´1º+`'Äèù¼QŽÖ¡ +¥TÂBVVrM.µ,k­j¥U}Ž\ôìÝ+J¸Á%%ÛÓ^ü¢ñ…K×¾±ú¶½.³Þnòú‚¹•“»è7O„=™Ü]»—w­|öž+V4¥6·ƒ“u3ë§Ý:¥bz÷Ø7%Hîé“f|·LÝØT#ø¨f4!õu°¦Y?•`›—ôÁ&­…~ì7…¯‚…¢ÆMž(o/‘·F2Q> Éiò­BÄå«AJàH”O”ȱçimø®P2 ¬‘5iSãTà £Z2HFbËñh/á1¦'–˜j È>ˆ© +íµe¡ Ÿý‡èæ={}¼×KÕOh²Ë‹½%¼R +zö:ÿa³±qQc Æm›b³I6G_N½]'êìêKiBÒëìäRÅ¡%_³4XòJ.b¦ùq°Ýx36{-yœÍwåå×ä·ä÷çÕy›6D;¡1¹T¹÷zL^IE¼©$ zìêNÒ†|\AK›¹à­d´­"g ²0·ÊÑU¤Ï¬ÿÅ£á¬<ô¾ž§3¡B/2„Ž(,~Ñ—8ÿ¤Ø=H,%ݰÈ~+Dœ"ꯒLN¥!=¡/ +ƒ–B°Tþã Ñ®@hA!uoÉ åv‡[~N²A[6 Ù ´bíç›pŸ†¡Ÿ¿éE' Y²’ÞZÈJ:P)¶i3ÚHiEßËÀÐÀÆT LÕc)Ä2.3ͽ%é Ë8M…X©ü·AOáÉçÝ¡‚Ñï ¾ÜmóQ?hgýô@Ô³ ®Š©Îkitc Ì·Äè på–=&÷["nmO³‡p¼gÖ=s'õ ag˜‹d¾5¥vBë²=™‰ßüúÌ©>«Íéf~8öÃ{–5E}žÔOîž;ëî´!‡»·oŸ®2uEóÅKVíY,ôÃ4ÔU>©ê`g‚mœÁ›%áAÓS¦Ã¦ç*›­I‹‚\¸øŒNëKùÇ‚â衆2~TÍCâòçµâv£Qk ¸HצpÜ®®â»O#7ç&î4>o Zp&°™¼YŤ`pü„|V¶J»³ÃYÒ—Ý—%Y>ŽãG+¨joáp-'qÝÜ0§â<5ÍÛÜ_¨Ô£Þ%7¢øúôŽ*÷ÙÈ9üYÈÈôyvŸŒ¤MUј#j[\¹jŽEªâ ”6A³†8a7µëdfž›­ª/Ò—ÈeÕ}æ-¶ ®-B_ê†Ìí®»2šv;÷V?á|¶ú…jóVË+‘®°õ,Ì(Bž1‡¼@.XT¸°U1ØÙ…Î+²í.4TÉ\—*åòùó¦Z›i»nêš)ƒËæ,{nÙ¤eãuÆÚ‰wL_ FZ6Ÿq%çÍbgž}ãZ{8¤ +wÞ?·mß-/íþts¾{W:þôèí÷Øù‡¿sà™xÕ]@i ]… ÈÞ•œÁ­VWÁbE6äç­œó«]QÞ&»JLQÞ*»JÜQÞDþNMïÍäóûÕX-!lô«mV½Ž"Î¥Š–)1)£Q¹c‘v»$èÞE`\ƒ!!/Ã*— ¥l¦6?àÂ;]¹8qÝ »ƒ„.î UÙ`!¸CÁAu`Ö˜^ =ÏûPd5€£»Xñ¡ŒÈž"‹8÷¥RWõ2,Þ¾àrIZ°àšIcš¶ ½f"»J.¤ËÇÆú–4Qq-!HRé3Ìé‰ìJØ;¢´PÊbu%5ÒðjN£J‹㔕36d2‹œÅå5?Žà(¯†Ýäã}³Tì\üΘo­†& Uê³pK–ÏÏ2YP¯°›®J­Ç—wS `dW*ûÎñ Îü¡TJ‘1iã°[~; "ã·&“-e¤K +å%Måò!ã°‘€¢l¬5n5î2î3ª©#q±œ6ž2jŒžP¶6Kj²? ¿€¯ÆjêPìW´-`ÁöŸì^N½ÏOÿ6!U¸*kÝJN +#Ôþ©rEo¬QX‰e÷½¼F‰½©¢Q õ ‰ü—>¬†¼r}²G—£ÞÛCsGWh°ßy'~ëà §OÈOP«Œœ+ w1£¯pǘhûjg’Wudw -lÎLl ëüV‹Co©mØ¿ñ*ªA[Ǧ0#Ì“(‹—<'S¢‘róïW9ÚTØŽ§£é¦iÞùÞ¾y5+¼+|ËjvøJ¾×}ædUÒÞŒš½SÐÓ5êk4×Ì>…žò¾í1A¯¦¬É˜5«€p‡ÇÉ;8úÿô¨x:U¼=íH$£¢9›âõؽ^ÑdrƒD2]A¬Lf ŽpÖë1›ŒHãHdQ”&1Ëz£‰»‚–èGA‡D«ö"Ãâºu§ê˜:ŠJ“=™¯ª°8²â(aFr±©T(‘OLN0‰Ÿ†Eij„õÔÖAÝ`ø‡—**sçiÀ`OÖŵ_¸ÞA=”QýXñ'¸Zl-whkDÅo®xäQÅÙ𹟆›¶U>‚Q{ᙣìw¯d5˜h*;P¶ª” MøïcoNn¯Á«Kæö];¾® ·ÔŒ›<öÙÒºŽe—\35Ÿ›€±Vkqû’qòÜ·¦™c1qÇûƾ}»ÇǪI,ÆN80:cì\ëœE“ÆÍ”&Å †@úŠŒcz@Gt næ©m3ì=ö5öeŽ¥îMvMLÿ$yüÔú+ò+æ˜é˜ãÌ¿Lú-¡©¹L/³&²‘Ù¹•¹Ýü‘é‡.­-;±V§© imr"<ÅYÂɃ¾x•†-áà Ñ sÊJÈ.§ä‰äËÑy­ ˆQvd™óHþ8ÀÚ€¼ÙH!²(òiD U¶sŽ«x:e´)0^›—e¢„å0‡9O¸ùER.&ÑIzeA¤:Þ°BÅÕ4ªœ¹œÄÜOûç¿5ˆ)ο"¯ÝÄA«/ˆ]ŸbèP¡· %*ÂúqØ©¨!®óâÉÈÓä+g‡ƒé-ët\ÙzUsdfiÓðʹ£ÏÜó«O„˜CȇÇãÏ^Xuɤ˜{·íÛöòGØñá£ß¹ž·ÕÏß+ÀRˆ€¢(h a£’g± ذ…EjÄñ,§æ8µX¦,€w²²üVÊQW½S€'Õ¬g‚*] Št‘Ä™¼ì$¦R†BI13`À; X¹SpoÛg°1Y[Á¶Ó6d;acm• +ejòVYȈ"(ÀJ™ócÈÂÊñˆ”Á/EÉ̳¾ ÌëWQ³Ÿ´¹hS@“®ýL£:<_÷DðÇäÇÂ1üþ#Ñ赸š¤í—ñ½ºkø º úµÁÝUß«ú˜ù/Ø_~<³"ì¨BŒÙ?ŒNÅã˜P¶Fp¸Êáö¸OY±õ¯î¸Až¦2X@Bˆ¸B]²ræÓYóŒ÷áx»?öiŒÄ,~ÞOü9M¥…‡’b~˜zU+6…Æ­PuX*š˜l‰wž\+SÞH?×*ßkîéoé—y ½§/_ƒÂkûc25Êñ/8¨”¢ê42?ñÇkŽœè½áؽÏv4ïÔ©].¾6’ŸsQÓŒºys߸ {_{ùÞýßXÐ2yÖÕ§¾ó‘í/ÖÈwìËÿ ¨F‘=(™wv‰ŒÈS‡ÀúPÙíŒãV‚Õ!ý_%ÃZÝR³0%l–¬áÑëÃ*²°3!ÙL_†d¤¶†Œ|†4./CèD†Ð «k½Éú’×ÄÜ=ãW.¥‰¸l£ÀOÅq6>Ž3´h°i\^†Ù:Jº@4÷TÏRìzÄÔOÑMUÎó¦õ}~ée‘SœÂ,¨í=¢?É.¢ ¼P²¢'"†BH~˜£j“ʹ*°0-²V(ùi‘ÀܶP¶Ÿ·¨éí´–òj0†èµrÇn˯ºtþÓ{óÊ´í3/¿ÞÎ%ÚÆ .Î&zçNO4Œ%*ŽšM³¦.ÑòèØý«4Ѩ&æY‚÷­k ß0fXÞ¬ùŠC†êYå“lô¬jrÙA²âjzþ¤ÍžG Rœ‡8†Si²ö¬3ë*Ø Î‚«ËÞåìrÍcçÙæ¯e{õW–ÙV:Wº®öò¸Í¶›œ7ºÖ7…®Oì¬yP<¦þ½oþ¨ú_è3ýg†3æ³Õqµ^mP›UkU¥šîšÅ5:Œ‰Íf­ªBzÎÀëÝAïVU'&ù„b“¨´¼ÎU‚‘U9yW<ããR©¼aÐÊXóuÒrU‡Äêê)|ÈÎó¡*¤Cjž +ø dƒ*FÇ`æ +å+àšˆL±Ú mãT Q骃U6ŒÔVCÿ5t6DBb‚C<”Z9ÖW'ân—^§®f2ÔÐsìꆙޚó2 …e(¹=Þ|DU˜Ù_ƒk@óK\‹;sHZlí³ëœA!¤;o)ë¶èÊ_üÇ=:O¦¦DæÊjàŸ0ôË7Ùz.¼ÊÖ£‘þ7Ú¨G¾§Ÿª†Ê¶/®²õ›ÿ3E¢ø•ËlâWůè‹òe¶V嬼‚åô|^nªÀIzk‹SkoqAP.2Íg1#0TR€BY¹×‘øÕ6™“et6ÿïæ„§«†vl×3Y|¼9Ø~½7Þ„5âØç~òýÑ‹É{³!Ð,ý6ë¥c÷ákÝ3RÚXŒñ¸œ3 Û=Í›ˆªb1uãJéµåìc ¹Ô€ +þ·Å!n}"’n¾n¾GØ/üB( :ùq`@S#Ó‡ûÈç×aóëÉcÉ’fVp˜¹H(ê "š…?ÈæCfR¯ÕÐOJ#¼üiD:T@‘¨•Þ†Ü.†>+¢:Κ máñ"¾Ìþ¦ÚZ©¶»¶¯v_-[«­\ÊI¥ºÓ8}S¶rË­GaUòÝ~å–Û¼HV #á¤Î¢Çcæ˜!¦Í¢DÒ$pY ëÆ,²D ºÀ ._rï_K½×Uò-›ÊG,•["‰¸òí˜òq‹¢;Æe.¤©%/ +]ã=M7/^½·3È\Œão™i5N¿5°øÖU^i.;3·~tÙ¡ ³–|ÿI]>ËâŠÅjjB—ŒŽ~úëbVzýiòàu-úd ÄØt•¤_ì»õ’Ç–ÕR3Y©!ÎYÕUYP5©õMUFCůø2$ŸÙîÒXmj›U‹óµÆÌ¥pJòymuŠŸª®â§’í¯ZÝuÃu¤¶Nªë®ë«SÕU¼¼i“M2âZ£dì6IÍ=µ³ú•“a™¾ŠÈXq+N JÔ­Ê×&tÊM딦u•¦u4=S¹Ö3¢ø7¨ùŠw+¯vãx"VíN%p<QÚ›Ià¤?ö…WKFߤyÒø¨T˜šh´Å½%¸%¾¥ZµÞ¾ÅÓ¸QèKlo³MxÀ¾Û½'¸'²7ú„ýéÈ3ÑCö£¶É,{¸èÕÂØù B_H•°£±I9T¨`>á<ÿmÈ ¼ßU;eô¯²nŒï¬«¿hî5OÏ»üVtNÊ5ͽªQÈ·Ä¥¥í‹Æ›–wƒ­v-fÞ¥^—¦…²·üyû=½!â}lsËœÿ>ü7èn¼¤|BeW¡z¼Jrê96ÊÄÌ©ëù;ùíÑí±¯§îLë…Êg Æÿã»×4ýLa$–i–66F3?P•ÔÏGŸ?ŸÖO¦¤¤ô©ÛÓìžøîô“êïjž2ü8öó”fºÙMqŸ_¸Fdß•J¶¸°õuºWë/øô5‚Ô>-yÌñ&—ÛaDÆÔÑ)¤ÛpÐÛ èÕ\¾Á–ôä^Ä—€V¶ŸPîuuNšwH¹I¿a8 “?†Ï´Êĺ6½žN¯ªÚäš+ßÅÊG]@7 5tÐr¡´Úb†KDŒZ3 +º2‡ÿŸâ¾<ŽêJ÷ž[]½WWõ¾¯Õ‹Z­^l-¶[e ˲±Œ$cyÅ6l&@<ö€A@ȰØI“˜¸½`ÚÆ³%!Cb“Ì#“0<ôx/"džI°ºß¹U-!Cæ½|ßû¾7²»î^Ë­sÏýÏ=çž’æA$,JÚzLSB‚ˆaѧ•½²ŠUòõêÆ–m +ÆaøUNÆq„ÓÉý²S[FµÊ¨×²=Ð ÔJ$:¹ã™ß›èªŒ?òð—¯þÉ=3®lquÏéWûÚ%í•ß>ôbõåY=ð=èÙ°´áU[ à௪Ä^yý©ÊO}¹ò˧|ýù$Êûá¸}aåݶöÍO]5òÌ„Ç$}_º•ÑÂ|Ä·+œùwÅ.q¶ž¤Ï[~Aß§ø ÁgJb±˜<+°BX/\'ÜhÝ-Üã¿OxP|Pú®ï¨p\ü…ôžä "'|>[¯mB¨>íHò +Šš„>΢­ÃK„㮸‘¼‰W_}µsâÕÎ)ck~¢Ã_¼ŽÄINŠK¹‚Ì‹¢ B! ‚<†„(®€;ìJÇÃØ›ŠguJް3˲\çd™ã_¤ÈeÎ`«žÅ %Q¼"pà¹D! H¢…‚¾&9‚ØÂ²]džž‚—‡ÊPWôÄã²Ëi|«ðûÝU€Âç|#üÒP†­ÇÒF0–áðQËvéXP”]~ÕYÄ¡P¸“ëëÓªØmʧϤϥßNkÒÞ|á4pH©—Àhͱ†ˆ;ïNŒŽM¼+«šÙ!axQ@÷LŒ2¦ˆ…l«$Ú}“†ŸCÄÚêÉd¦†éq;¨˜a³zBù{VË´¹_g¯m‰U Y8ó³°÷ÅëŠ6á[«nÛøæ^o¬©ŒëOvÔÍ­èË/:¿ç_/jóûã 4î^_ùþ+ž +ñ‹{.ˆíO\Õ¬âß«¸“ø—Éa³•Ý2o19ìã¦VÉåûš›Pâ¢ýlg©e1—6©ÕˆNY aAŠI ZÛaË êbGYK•½PÊŠ!=ÄÂ"{E™ìµN®‹‡düØ”x6jt±hÔbŒzEÒBå;®ì(mÙQÀ²3ËÎd+;«ìLÀ²3ÙÊÎd+;“­ÎÚA´CÄ~ÖN%;Ø™˜e;“ƒp®”£ùÜVf¼3W…¨xª\MÂÊÕ$«\M²ÊÕ$.å-8O戺ŒP_—š°ROIKq©š€•ª X©šgJ´¢M)oöSAK•´¦ Zˆ9Ƈ&mû2Óe”­×8;Z[[?'cEU+:)cYŠªS•±,LƲ0ËÂX»å³2–ºÒ³íå$Hnÿw¥ù4kñîîéº9•äL¯Í–ñ×-jíí•dÒ&ÞYÚµ~ßÁÊWšÒE}àÑëÛ£³º+¦õÞ˜þ2£äpõ·pž{‰˜ˆ›Ì§$T¨ˆ™Þ1RU€ÔX CÕÔÌH†·$Æd4‹Pm}R›H˜êRDÂ!°ˆã)C<K<i]Cê#£ú°ªßÊo5mMlÍ” +g +Ú­Ú]Æ]É­õ·äîÌ= ûù¯çžàçÊü ¹×r2¥(,¨À¯P~…éŠÂ„b¾÷©zpVã$)€Û:¹ kUì’ZèÉ9Í=‹J—ÞòÆ—úwf¿“|K&FçÎvÊyObQý¼ÖÔÜøåk‹¾ø7v~ï¾ê¾–Y_ü¤{µ;(å.†çáïÝ”´w]YyïËÚg2ÞÖYÕÌ@Ù>÷³½ gŠõ5÷ÇÏÅ©Áì7×›{ÍšVóÀw倿÷ºô4Æ<³DÙAä‰=ÌKvÍ[:¨ê€-ãʲj“b,N浼ѻÁ`2šH,æpصD[_CÕ!-ãeZäeZäeZÆË´Œ—i/Ó26¦e MËx™VáeZµÑžÕR¢•´T˸™1ÎØb¹X¼ÆÅâ5.¯q-­W‹ñÌñScaÑ‹ÌìLÂñRœæã[ã4Ž“38ëEÆ"Žá‰-5ff©13‹z2Å’ÃŒ7}h¼åŒåœ…³xåK¦Ô× +×R¸ÚtNö¾†lmlН±å#…̘Ó6–•%z$îÉÕg­já©bðÚÊ¢ËRÍÜëÈ~nëº}Ù’[êSsa§=íëf³5ž‰8ã;;û{×ÜúM¸Žq™‰¿_ß²û–ÀxÍÖ&O÷¾ý6úJ±/ܦ¾€ÔFm‡ MøRádg³8ÂÉðôA˯Á[z¾ôã ·^ÇxkXׯûPÇétZD¸É„‡x\1¡;ã-²–õÖn»·ó@Ë©šËB> + ù %,´1Ñm¢NЇuÞ /ìgrµ´Í +·œÒ‚ø°Ö#ºÃ9 ËÍù¦ps.d!­r”½äåéêüÝùÓy.|H<Ôvº[ÝvwÛÇ"w™¸O|¤ öˆmQlËÖV¼1üQñv›³é,,ËîÎÊþ,«É‚M¨³9šxpB¶Ãàï^æ–‡o 5üDXó-áMá#» öÃsÀý\!„‚n+ÚäNDAÌ‹mš0„…p>ܦiËgÃAQ½v*æmiŽËZ¯G§5ì8ÓA;ð–ž­MˆÚX‰HäZÖ1^þÞàó"Yz#i'´çXô?˜Öo|ì£ DcªÆohjmG¥îÖmÛ2û,‹s¶…)Qa>P}›©Œ-À¸³jè¨SC1¤„G͵ùp¡4”!žBIôâï¯ìiT0ôŸ•ˆø7¹¯±èzŒ–&‘,ìbR[èT,ùvæ‡<¿fœüËù¡Œ£0Äœj0Ë_s¦;C·Í¦+C[ráð¡ÈÉð? ï F`fölçý$¢ÇǬMJ¿"ÇÓ—éOO-¼O Ž2µðÆSð1ïDHíæ2g|Öú3’–Ò4ñ¢UtƒÛ—C(<âdò6Lëó öù6DaãcCÒø„µ5ïõáŒæéìô±ý£Ò(±¡1[«Ú]ÀLC¦õÛ·ÀºŒDcSVq5;9Èo(Þ´ê¿¹çÙ—ßpKå'•Ê¡%­ó2Ñ ôòŠ…[ÎÐ'ähë ËnüGáñ']×wWsëã÷óÊ­u¹‹,úGnXuço±?Ùæ˜«q~³Ñú¢ÉF8÷>÷ §ÊÕ÷Š9ÑÄE|AæÛâ½c¡ ?,öyýMmt!ÝÄíân0л¹…O˜ý@×cž/\έ4?Çý˜ÓQ ›ß`þJóú¼!bØVšß0ÿÖü±Yo¢³Ÿ:Ìšß«3S‡ÝH}t'¡ÏPž +À›æÌ{̼ͧ™3r=F­ÐFÕšê|fHYfðŸ$6œ?[­ÆN½Áj³â#˜Ûzázað·…ã„Qœš ”sPÊQàb0;LÔ\ÉPæ’EÁd$6ÉFm60jm,§Nè!ô£ƒ€8˜>ÂS‘IÂ`0^Ü ¦´-£3HŽVRÄù±“T ½–Y:ÐÄQᘂél4Úe蛲LAx>¡@¡ñq¦(•ÆT›¢Ì6¦X<&}À\î I03nex±§µµîËe¶+ƒSÀÙ‰Ö°Y +g' O1õ’–œj(*ùoµØ'íY÷í|…KzMz(Ú36 Âömª¹˜rbDÅvºh°:©xšŽ0wi(fqd[÷ÖÉÖ¨TG>]çÿ…Ò×,o +Èœ½B‹gžÌ\Üryñ:üç_ÃÖ+«c•½òሯh&øxâÕ,ìVÆ‹ô.É/FI‹:£vMò“_V^cßãX…RßãЄR_ì8éÕšíÙ‹¦ˆ¡` ¯ùÚ;YÛóCl“ò¦Ëu¤&ÏAÓt)nQu”{I™[RÈC 6ºv¸¨‘é]œø빸ó‡N®SÏÇ<ž0oH:Ÿ§?FÄñ!ÄžI&%‡Ë`<. ±7ÍeøÍ1âK{ÊôµgD_ØG}Œ1˜Ô­]Þº?þAȘ‘&S‹Äî³æNiTÙaÏÞ‡"€åü £=ž øƒ~ªµ%˜,[ !«o-‰ˆ“Mɵ෇ג¨€UøÊL­Nâû§…êZ&M X?(>ü€9öS¤£f‰ KÜKÏüj—ܼhÞÃÿ|ͯÛùó_­¼¦oÎE³¹]™Þ:~S wßÙý!ƒãß_¸ýí›ïý×FáÎ÷'®)ŽT*M‰«¾ ŽÍó±7‘<½i$Ù_ôt +ÐÀ ÕŒ¼^0^L¦2¬.Jª×Þ$€†<ç OŒT*šõÀëÍ‚jBûgÀë`¸èÉk:5TÔ„5Tã ëR⵨]:ªì ]<®.tâ ú¨Ã:éµG‰¡b+•·Ú¡Q19ˆZ£³¢ÖFºçæ/¹2Vq®¨r›Ï?t¶r +g©éÍŽôñrÄì)úl”P°h +¡A÷ §?ô¬ùíЇ!]ˆé/…æãÉ@¸©ÓµÄµRËé,Õ58)ø=a·*‡1”î’œaW¹zgq‹H Ð#J»% ä +Ñ‚1KÀÜ¥η³0g†¿Tò»E¿$Z€ ïGT¦ “ÿc馂XûEN²ü`“¸b¶ƒ@ê9 ô³;;Ö±¤I¹C¿œj +±IRìIßi¤”ð9h0ô©Áœ*³Uî ïøÐ¸glÊ`nJ1šÉ0WêÂå>~Rú×,ä&E\S\B!v³!v³TB®ì`aÊѪNüé( +F“>y˜Ôzê>¯è„ÿYyµ5âÎÂòVOÃ[š³­0³aöìÊô_o“}†DÂê +%6V…ü­-áM$´-{&b IÌ«ìGq¿‘} ³hý3A/‘×m½f£¦ÏY†ž¢ Ã/ò<}‡ù£Ÿ`ƒw| Î]ÙU­¬>LY÷á¸Ûxýf¾,s0Ó~Ùú‹WÞüteÃÌG–Y zuõÜyë÷^ÿ¿®ùÒöó‹H;¬9Iæ°uÀº¦9ìu}åy=SÞÔÞ ½Â5„Äà€ppNž7—…gÛKsÎÛÁ9 Ë¹sí0WX–_Þ¾®Ì鉥½ ¿=—ËgE ð¨xrÅbÙH0¹:6«}vpRe©-è\-‡#Ìå Ø-ùæ`ËóϽÚ¹:±é²}µ•¨¬EpX,i]õÈêî@ÉçD‹D?GšŠºfµ$ÔåÔiõZ_qÌɪ›Mç†"TòvÌ9M—+û÷½êêù¶IÇsï^(°ÙØ”£gZø¡Ï¬”OúH¸pµ¼æ*AY#Wìok»C‘S2¿b“‚è&5wŸõùYsJ5§ +™q+àß7ô6·OÌíJ­®¼6Ó3¿obù4/ ßêŽûD3|¼9㺌Z/^z?×=ñÔße#Hl!Wýõ°¯¾ò•-MŸñ?ì°D½WVVÁC+“.—HðéHÞÊF:È_EläÒb¬E³¿C,‹šé~Ãcô» +…ÚÍ/ ÑIºÛ†O(Z—H ­tàe6 û¥w2bU=½}4TS”©FÈv¶4Ë\ESöl.b•ˆwÓŒ®Tá²¾¦¡?À’Ê‘ÊÆ\÷E«î.AÔÁÅzšg.­•Ó•+v6wfª£?R,ΰ´(Úzôб:x¼ÖÚâ§_Nîát¡¤ÉdÙŽ ÎäFò‰A¬¨óÙÒêò¦¢N™Ý>§©?}.M ébº?½5}0]JŸIëÒ ½a/õÖ[mÅÉýg¤s/yë.Ð+Kêš¡T[3”>£WnÍ+‹ŸJÕ´Z5]«šž®WžtÈ1ª¬ˆ^° êKh>Oú}Õ’øB5±ÍÞ,a#Æem2>!"Q}è¯/ˆÊ;ù­†­‘]ñõóéŸÕèoÕï5Ð]š]Æ]á]‰ù‡âZÅ:p¬ÓTÇÉ¢«šÕæÌIn‡wÜ=üäðͯ߶hGë×b:c¦öh‹Ú{g´¤æ­äMLܼíÜûÿr[¡eƒæ;Kí?ML|»2¼Knïm;ôöýmÊ—6ª¿¡Hki)‘|:U„L8jâ‡iƒæt7#(½¨òý ŽAd í¬tí†ø«þ²ƒQ$]¸–ÞDçªþаÓx5Œ…NÃxmŽÒ›&NÒ‹áÚ³l~†Þ¢ø~“°¢xßÃn°mðï ; +{žj8:ÕðºîÍìŸóÆ:˜  ×¿‚ú7ÐÛéžÂðÆŸ7¼z/öQèO±?¬ ôÉD OY"AC,&*Ø +‰'¹HaF=I„âsŽ@.‘08â9§ÓAëszö™ïˆ¡‘_{¿aÓøã3ÄΩ¬haž±@s,Ê +#¿êPŽ?búi’“r4§è§s‹ÇØVªš£x¹çÇ//“¾”j^Rñ$êö•Ð2Ù¨ìòð:w"–t'´É†„ìŠä!Æ].QOœdÌ“³|=sUò©ÏÅLmgæà‹¶› ïgi²!Sh 6ÜÞðßtZe¡Êöx6úyÇ‹Z^u¶˜ÔY­:GÖ’Iî^¼dë-UÞžrp2òþK[¿2ñ›¯ì[pñžûaVKÿ¾èÙlñòûö¯¿éSG'˾3´v¿­xýªU×uÀÄ×+‹QH¸xß²/<Ä>Ø®meß ʧ^Øÿ!ñsA’Ö\G¶`|)¿’$1”t÷4ÆÓOj[I¿æ‚ó±a:ˆù 1´a^wéÓ²‹ñ·Zû$Y„ç[Šç[B[I=}’ÌÃ|+Öcé †—`^Ë{ðVü0žÂk,Ãp>ËÇòÃ^‚¿Nl›Çß> ûX!QlïÔêÞû*L/Â_#þ옞‡çÈa[/¶Ëàµ(Ægâ½fŠóV,/vÎÓÑÞÖ:{VsSãÌ…|.Û©O×¥’‰¸‹F¡`ÀÏ<·áaFs8™šMFæØ× àJºåžáH)9\Ò$å ²,-¯ÁŒ5Ó2†KÌê¹°N)2¬T‹\X³ˆ57~¦fQ­Yœª R¤ƒtd"Ýr¤ô“ùr¤ «–`üžùò`¤4¦Ä+ñ{•¸€ñhDº=›æGJ0é.õìØ4Ò=<OwÄdì’»6³ äˆÑ„QÆJnyëpÏ%BÝÝmG(Ñ xS%Ÿ<¿»ä•ç³;(q‰î5ëKýKºçû£ÑÁlC ºÖÉkK„}l$£T!]ÊeJÚ®’N¹Ld3{rWäHÙ‘»ËY;œ1¯—ׯY=PâÖ ²kX3xÝù%÷Í£žO“xr[×À¾é¥~n¤Û³9Â’##û"¥ƒK¦—FÙqpÏmi¢gx¤/}7vbûN‰î(Á^¼d„= {*õùÔµ$†·DJyž¼idË0¾ßH‰\zSô¨ÏWé&=äbÒKúÈ"²˜\B–~r)YF–“ä22H¾@ÖµdYO6äJ²‰l&W‘«ÉÉ5äZ²•l#ÛÉuäzrÙAnÄëÞDn®V§>?ýÊ3þ?]™¡×wˆHŒÄ‚=mªž'¤:Qý}õGÕ¿T_©ž©þcoUOW‡¿ç«/U¿_}¹zªz ãg«åêÉê¿TOTßÀÔ ŒŸ¨ÆG±æ±êSÕãÕǪÏ`î71|Ë^¨¼oWO(}ÿ_óGÕ %/ÿÕò9@ ð èÁF0°€XÁvp€\àxÁ~@B†D!†P> HB +%¿4ÔC 9ÈCfÀLh„&h†˜…ø»åÃvè€90÷ÿùÙ€ÛBO#ëù<ûHHB ¹ƒd#µO©žÓñ<å4„\ø–/îŠ íEªçù«*=Ш‹ÂsÔÑ"½áˆQ¾m^GH-N‘bêjqc-µ¸ãWÔâ<ñÛkq-æÿRêB¤fF¹ PVYŽTúE¤Xćx¼ó¯Åô¤ÙK1}%RëÕ˜Úþ7·ú[ë­Ä4›1ç|ö8æ +øïolÿ¿¦Å¸ +endstream +endobj +835 0 obj +25222 +endobj +836 0 obj +<< +/Type /Font +/Subtype /Type0 +/BaseFont /YJDRSH+Symbol +/Encoding /Identity-H +/ToUnicode 837 0 R +/DescendantFonts[ 838 0 R ] +>> +endobj +837 0 obj +<< +/Filter /FlateDecode +/Length 268 +>> +stream +xœ]‘Ínà ǟ€wð±=Täc[w¨*­Ù*åÐmZVíLÀÉ@„òö#€2uH`ýÌ߯6´ªŸk%Ðw«yƒ:©„ÅQO–#´ØKEò„ä.Q8ùÀ ¡>¸™G‡C­: eT‰É$%ýðftv†Í“Ð-nA`Gè›h¥êas­šäk&c~p@å T"ÞTf^Ù€@CŽ]-¼HºyçƒÿŸ³A("]´À”&¥pï ãh™ê‘2¿Žp8ûu\žúwÿ£ÚŽ3»ªƒ ”ßPqCå’7+Ýz)#Ý:í#=D:GÚGÊB=é奲eÐë ød­o?Ì9ôM|“RáúaF›0:¿É/™?+ +endstream +endobj +838 0 obj +<< +/Type /Font +/Subtype /CIDFontType2 +/BaseFont /YJDRSH+Symbol +/CIDSystemInfo << +/Registry (Adobe) +/Ordering (Identity) +/Supplement 0 +>> +/DW 600 +/W [ 7 [400 ] 6 [658 ] 5 [460 ] 4 [790 ] 3 [250 ] 2 [122 ] 1 [0 ] 0 [600 ]] +/FontDescriptor 839 0 R +/CIDToGIDMap /Identity +>> +endobj +839 0 obj +<< +/Type /FontDescriptor +/FontName /YJDRSH+Symbol +/Flags 4 +/FontBBox [ 0 -220 1113 1005 ] +/AvgWidth 600 +/MissingWidth 600 +/StemV 70 +/CapHeight 500 +/ItalicAngle 0 +/Ascent 1005 +/Descent 220 +/FontFile2 840 0 R +>> +endobj +840 0 obj +<< +/Filter /FlateDecode +/Length 841 0 R +/Length1 5364 +>> +stream +xœ8 tו÷½™ÑŒX6þHþD#ÆŸØòløS[¶% (cø$’eƒù;`,48°4T£´9&m )Ih›‘1‰Ü&à&MÛs6Ùͦ­»'¡Y~K8Ù:åtIجÙûFÂ`’öì\½ûîï½wß½wÞÌ$~uwù:£œÅ6£Q–¤!Ê[·Ñ‹Ÿ…(u½o[OŒ‘ìßÚ+Çøuß³©+¦7`Ïm^µnûÊ(w ùÝë{·Eù$/¿²gÕú߇ãø×ûbã'³y;{6nîñÿŒ¨zA[yEŒF´xƒo}W”O3é{`{èÁðé„çJ®ý\J’tíç¾QÃú?|GÎÂýàÂ9j`|6!^ˆòëdaŒ‡¸úSð,œ†…ÿ3ÎX#D$×µ_B´¡;`>…'`2< ?WàWð_¤Œ#ŸrŸi§´wµÿÆQE0 fÀ2è@ø8€»xŽÀ«p…Ô“nòùŒ&Ñ>zFh›Åæ¸3cÔæh_à‰`Eo—ÀZ؆#¿߇C8òy\ë×WaŒÌ 5¤ŽÜOZÉAòò"ù_j£ÑÜ$.™+á<œ—ÛÉ]ྔ„±‘Ñ÷µmÆ’`Ìã1“M¸ÏvX=°ЇÞõ#1z'TŒç„·áÏpá2\¿JÜc<)F˜ŠPCìdYD"«Èfr˜¼FÂä4y‡|J®Ñét­¢ h+]E{h/ R•†èz‰þzYÍ9¹ÍÜ.î÷÷;îîCøy¼_ÍoáŸâUþüUþ@PÊŸptì…ˆ+²L+Ðj´í€D¸‚1¾wS…¸Ÿ̪Vbåô <Œ°c·wtžÃرè½ax«ô-Ìïoà}ø÷÷g¸×áK Û_:±’R2 ãû-2a)æi+ÙIúH?yã"§†ÉYÜew¸˜zèƒt+ÝIÐÃôY:D‡éfBã ˜ 7‡sqK¸e܃\/wˆ{šû÷w„ sÃÜoxÊWó-ü&~ä_à_åËÿž?+Lj„‚*œÞ.R Ù†é†6CX4HÛñ¤ˆÀIø-„àÔ]'}ÄHBð3ò Çs}ô]ê¦ t„ìæÿbj ý°þ†æ’èL²„󓥿Ýd%Y?âr¸¸yð®°´q-¤ÚøÃpSx|B€pTpcäKzº¡Ÿ®{EóIÐFŽÑ—°b¾ µPÄgÁ­â‡H>-¢gÄŸ“0Ô‰®Š«–’‘;Æ]D7Û¤dò)ø¸ xÿœÇ{«•¾„gÂerV\€Þq¯¢Í·¡Ž‹¤À+‚‡zI=FÛ3öܳÚb¦ÆRÆhVÜ"í8= …Ñ/ùspš~‹ðÔðëwÎßðÞ{OšÅp“&áýÔ†çHO¨=µ!"ÐØH2ð¦xHÇ t\¯ãr†iù@¹Å¦eGYW2[„]ž=á|–eZaª¥¶ñ™öšuE–sÇÍ–óØNVXöÕVXö`+ǶyfWx¼È²±pãúßÙø8?22Øó+E²‡ÉÅץťÅÍ †É{•|S žƒ«Ä`§\"g‹Áb°L ÚÄ`¾ÌÓ¤TÉ(M’¥xI’ /Q ¤´°vÎncO€4ƒ‘uža^§”a}@P"Q<®ÕÉœ‹ºÚ‰Köƒ«CV¿hSÂ$~áRUP‰šêW{£Ies…E­Uis©bË2wˆ~JUº/L Ý&íÍVS›ÜC@ˆ¶÷@v¬÷x ck½©>µ.¥j¶ã7†m·/“íÎËÕ²ý °-ì4%½'EË÷E&mCiP—™4¨KM¹ê!W›[=žëQ+¡åzÈɆSöÎ.ÅéUœ]ؼê[»Mj_‡,‡ì§˜BV¹o‡¿›õ¾.õ”ÒåPíŠC5ìøõ¦nP!Øálw‡vØ» ö§âsx† ™t„Šû',÷Ý[Ë A1éøúŒaÒÁ¦,f+6÷ÊýLÝÌVìg+ö³›íÍúŠÎÕ,-åÑþ$MˆÇ\x³­žÆ cOž˜«éÑì_ð@^†›GMTÕ$lLUÚPÚÀTX0L5 ÅÉ1•éÑkö/ÈË1•Å)J#ضØîº6³ LÎÕÖГ!m˜ö ¤Z*l{YÀ¯Â×sVc¿Ç ú)žG¼Ÿƒxƒàç8š'ò~f©h–ÉÖl¼V;¬¶ÙøEí|ãX-Ô׎ղ6mjeŠ5%ßšb]ÅÃM™¾iàÈü0›™hç„ýÂ:|ÊÄ'ý{e©©Ô\o®žÆ/’ +òÍ&>'ÿÐsoŽ¥|Š¥¨¼<½¨èþ¢ôdK¤[¸„üµæµ¦0©³g[rKJf–$¦Vfff%Z 'Õb0WTöX™k¶ækóGÇF›]ŽË)©U[ËMåÈ׎G¡~´~,E—¤T•Gc—Œ—R3«¦MmÚno,.˵’Lk±%rË¥TLŠO´‘4© Š”l›’÷”æä‘1ÙF’MÒmIE#M¢Ýc=+ˆ¬2¤è˜»ƒ&bA2Åž–QY1cf¦Á L)¸oúŒÊŠ aÄùÁGŽ„£ "#7"_E’‡‰€GþÝŸÓ3Í“ºÚwgºåŸn{úíw^Üù } GyÉÑè(6 oŠôãà‘~²‰„Ò[ZŽyòG+—šw>þÁ›oÿiSô}ô÷ô#îç˜ëpdÐ>)N„¬$ƒ91鯱x^2^†úù£Ó¦’´ÛŽÒF?=2òôáÚíGØlÚyþßqç r¼$â G‹ÝÌz%1—r½|H¹”’¬xñ‚9.>LZOZ層ݮ¦kXJ—Œ£ó‡Ù!XSéùùéV¾ÎwóõÈq²˜^á¯ß8ü³/„°r ÇÓna^U[gJX,aRmO`…cŽò§X˜ÌHüZ™°ÝêePL21ñy,ñy,ñy,ñzºóXºóXºóXºó`<ÙÝqúíÌÒîÁ]}ƒƒ}»í^±|Ïžå+vó3w îÂöh”ß ü{ìÞÃë+П†Vðc>Ö¹JXi··××}«¶¦ºjÖÌû¦WVL›Z^VZb+.º·° ?O™b•-÷äædg™M™éi“SSŒÉ“’âã$Ñ ðÞÅ%Ne¶WV ¼*_ Ì[ÊxŇ߯*£höDUöêfòDK;Z®¼ËÒµ´[£\ µ¥%²S‘Õ÷Š&Kº‘>àP<²:ªÓóuš/Й$d¬V!;MÝY%^Ù©ÎÞÚpz8_(!¾IiêŠ/-P|’ H©™JOˆdÖ ™Îê) ½R³‡S5+æ‚Êå;}jËB·Ó‘mµzJKTÒäW:T`‡©M7&}ÕФŠú2òj¶xB• ö‡Ðáµ%v*¾ån•óyØ)6\סfþÓ%Óm'dzùñ;µÙ\ÀiZ-36x\V.tß©µ2ìñà8–æÏöfãÒû1Š®6W£{=n•ìÅ%e¶¶«èþ¢O£|ïYS•îÀ/æ&+ Bëvë@V–}H;YN9ÐîV¬j}¶âñ9rBihÝ~Òl—Í5¥%!cJ4°¡IÉ1"1éN¢k\§Sº9£\­ã‘%Ì#å~¬UöËè‰[Á=Íb¨kü³Ð /ÁQj'fdµ×ä «™œW…|£">¬eô/%¾˜ÄoüÉêd¼ÖP‹Vm6µ¸˜•ˆØ„9Eëtþ¾Ò’­aÚ ôeì0|Ђ±õyªË1üV+Kða;t £ö-tGy:²À^ŽÏXêešá[šôELÓwK3>Ü«`%êlº*Œÿ’“ÝÕ*ÉøꮨÞÕ¦¸.uË΀7[Wû.ªŸ5®‹Qêä&7—McÍæt-åòqcƸU>½¨;â„U©Kˆ<[5zçF±'Þjý +kWÙ(½»=,æ¦Zm›È×Là'¸—àÐa¾€ºÚ—ñtxƒ7†²oaÈNöµ-uá+´¼¯Ý=@ mò6zBy¨sÉv]JÇ¥Œ“.‚;@%]•=dèÓµ¼.Ðy?¾=ë2é–Œ€?L£2£.ë4úo§Ÿà‰øŠæfß `D ½*_U¯¾~õÌÕ‹Ñï?Møº,ùbò’äæä9ÉVˆ~ÜýORôŸ¢¨µ:¿A á·1Gx|âˆH$wçg'ÿ ‚’ðŒP‰l~´çŽÂJššÈ Ž Tïž´}~“ vô8‚o%³I¥”@Þê»ÓÀÍlç|úœ£)LB.JsHÝ£y¤c´&X£ (ï~ò8 ¿çêÿÉl‡õÐaʺð ¹)lúv_³gØ›a5r@ÆwÏ2˜ŠðwGü’_9) +endstream +endobj +841 0 obj +3646 +endobj +842 0 obj +<< +/Type /Font +/Subtype /Type0 +/BaseFont /YJDRSH+TimesNewRoman,Italic +/Encoding /Identity-H +/ToUnicode 843 0 R +/DescendantFonts[ 844 0 R ] +>> +endobj +843 0 obj +<< +/Filter /FlateDecode +/Length 482 +>> +stream +xœ]”]kÛ0@ÿƒ»‡âêËn R§•§9î7m êæË}ü/âý2eà?oCdÍRšØrë&LuÙÓC|žÕÓ:>Ï×TÿõûÃvûæo=ÝÂÓ+‘þBæ ÙDFÈ%*!y¨€*¨„ÖÐc¢RC HÆ-‰\@/…*èZ1ÎA¯Ö¬ó5‘Ư RãW]ãWb¤ñ+ +Hü–~Nf?É€_ɪ5~N2ˆ_ áç1Òø•’?GÍ´øI$~…Ì‚Ÿ£f¿’}0ø¹„ŸÇψŸôáç©™‘ýÂÏ‘Ïàç%Ÿø±2ƒŸ§.?'³àg© ÁÏãgð3Ò‡Ÿ‘•‰u±W?sÝœDâGå­øñeYü_ˆÅϱ+VöO"ñóÔÌâgd~FÆág%~¶JGKÎÐõ]ïŒÛqnÎÓOrº2ÒÎâyíúp»{ÆaL·@üeŸ®@= +endstream +endobj +844 0 obj +<< +/Type /Font +/Subtype /CIDFontType2 +/BaseFont /YJDRSH+TimesNewRoman,Italic +/CIDSystemInfo << +/Registry (Adobe) +/Ordering (Identity) +/Supplement 0 +>> +/DW 402 +/W [ 15 [250 ] 14 [389 ] 13 [278 ] 12 [444 ] 11 [444 ] 10 [278 ] 9 [500 ] 8 [500 ] 7 [500 ] 6 [278 ] 5 [444 ] 4 [500 ] 3 [250 ] 2 [250 ] 1 [0 ] 31 [611 ] 30 [500 ] 29 [389 ] 28 [556 ] 27 [444 ] 26 [500 ] 25 [667 ] 24 [611 ] 23 [444 ] 22 [500 ] 21 [722 ] 20 [278 ] 19 [278 ] 18 [500 ] 17 [500 ] 16 [500 ] 47 [611 ] 46 [333 ] 45 [500 ] 44 [278 ] 43 [333 ] 42 [611 ] 41 [556 ] 40 [667 ] 39 [722 ] 38 [722 ] 37 [500 ] 36 [611 ] 35 [722 ] 34 [611 ] 33 [833 ] 32 [444 ] 58 [675 ] 57 [675 ] 56 [333 ] 55 [675 ] 54 [611 ] 53 [722 ] 52 [333 ] 51 [667 ] 50 [500 ] 49 [667 ] 48 [500 ] 0 [778 ]] +/FontDescriptor 845 0 R +/CIDToGIDMap /Identity +>> +endobj +845 0 obj +<< +/Type /FontDescriptor +/FontName /YJDRSH+TimesNewRoman,Italic +/Flags 32 +/FontBBox [ -498 -307 1333 1023 ] +/AvgWidth 402 +/MissingWidth 402 +/StemV 70 +/CapHeight 500 +/ItalicAngle 0 +/Ascent 891 +/Descent 216 +/FontFile2 846 0 R +>> +endobj +846 0 obj +<< +/Filter /FlateDecode +/Length 847 0 R +/Length1 31004 +>> +stream +xœ¬¼y€ÅÙ?^ÕÝs_=÷==÷}í»;{ö.»À²,×r-° rŠ(—¨ Þ +Á[Ñx +ì²8àQôG¾šÄ&ù%æ}×+q£IИÈÎüžê™4ù½ß~Ó[õLWWW×ÔóÔó|ž§ªa„ + Ÿ•Ë/­|C¿ƒT» +*§Ø™õš%cçõ}yÙâ«×VΩ0dî%W^ᮞODHòÐÚõ˪×eÃ)ì+VoZ^97BšûÊÊË®¸ºr~Ù)È>_¾vÅe•óË"$Î-¹lqõþ+>„gž]»fÕó+Iÿ~>µ7•©œ_u²Ù—/¾lYåüj©ÐgòÛ$Ðð‚cÝ‹4M_IeRáêã\ñeB¹ù.ÕYÑèmòýÒ4¢ êãÊσÛ<¥N4G~ü¬è_Óäû‘…´sÁ§±JW~7Q ¢†hôÿb„¤íÉoCH™†A>Š«FH»!Ý7éášñB–Z„l~„³r¾‡7!Ôñ5 ˜‚PRRô4Bq ‰GJÝ‚PͯÊ›`Lê£Ð%à]ón„Zåñ0®íПqëê„ó Ó ½ÐDàO×ßšõ'‹!5!4ú6ø2§—Ah&ôe6ÔŸ Ï›3ø$'¼F¦ý 5¡{‘F‹E)=fF¨¹ˆA”ž,šŒ8HzŒ*ÿÒ§$•&•ÏŠ.E¾ÒÊòÓ-ÐÎÞjª|è´+ÐtêDôz ]ŠÖ¢éè<íKü+4ž@W¡âÑ(2áÅh<®ƒ³ÝÈ\~ ®Ì/F} }º]=܈~‰– 7 —à,ò£zôj.¯@zѯQ-ºí-ÿI˜zýºü»r MD?D¿ÆM¸—Þ&jAsÐft-º ›q×ãkQúp5z¢XÙR¢4ÍDsÑ +t”ÁðLš†á_ÐãàIsÑ.œÇ§Ê‘zD Ô†k©Xùr¡(ÊÁøµ¢›ÑÐ}èW8‰›éæ82ÃoZŒŽc56a/>Y~qpô ÐÓÛÐ=h?z½9<“Jщž-}ŠÔh ôp Ú…~þŠåx¾š*ÒÏ•Z˫ʃåÓpw<§M‚~oný=Ž¡SèG0&¿ÆN< ß‹ÿÂ\!ÊŒ^_úiéò©üW¤¾Î ¾mE;€7 WÑoÐ0ú3XеøU*Mý†V3ˆÌeT¾•ÌvàŒÖÕèV´ŽãpÇëØÃ8‹¯À¿¤Ô”†ZM]G >§wÐGèÿa>)+?S~ Æü3˜M>8‚hpu pmðî z ¡"ú1úú‘\…wá#xÿƒ2PÏQ¿`Ί~-ú²üpù,RÀhP¥áÈÂN@]ЗËÑÀ©7ÑO@ý ý Ûq_‡oÅ;ñn¼߃ÿ€¿¦n¡Þ¥~OßC?K¦Ì`&ìí}(ž.Y\º§ô@¹~ÚÎÜ´À.YÜ2ñŒãz„¾ý} 㢇_ëÇx¾_‹¯Ç{ð£øj"µŠZC­¥1í¤}tˆÞÎpÌæ§ÌoD›E»JÁR_9‰ˆÜÈA¡ßsáX„–ÃS6ñ Æáz ¸õ_ µŸ4…¾…§QÀg6báN8f×çâ…x1^‰·àÇñüüŠ¥,”—ÚCý€zœúõ ½Ž¾›~¤N—˜²H!ÊÀÑ-êƒß{@ô7ñ,ñI»äbÉÓÒwF££?ý}IY2–B¥ÞÒM¥ËsËW–¯*?V~ºü\ùPù”0Si]'È—ŽJÂÌéF“ÑBèÿ¥hÈäNtºާá7 ¢£è4HÜOÑÏÐïÑàø} +œý³ð›¾Bgá7Y°×€¼Ôáøb¼¯Å›…ã|¾?ˆã“ø~ ÿÿ +ÿÇ×øøJGé©UGuP¨©Ô j µŒZKm¥î£¤ž¢^ NP¯—IýŠúˆ*ÑàD'=‘l¢¯§£_ ß§Aÿšþ#ý Œ <ò0>&À40+˜™Ea§¥¢U¢}p¼*VˆW‰‰Åo‹?•ˆ%aÉDÉ4ÉS’IfÊ!tÌÒ > qÏà5zIãר£ønüjô¤÷áÍ4¢Ld¼}Lí ¸…¾Ûaߎº(ÆPM=LMé&Ÿ0‹³ ‡3E?gŒøi°/·à• oÞùé†:ÛÑ (ÿiÑåKÑ6ÃŒZV¾æÂ6ÜOÁZA­£þÄœ¥YÐ?Ò€Ü| s?‡ï¿P1¶f´™Pøù{´ »©$š‡î§·§=ÈŠ¢Ìjèpü7zí§î¡vPGËoR`RAïÍc&`Ä€eE‡ÿŒž‡¾½EýœÚ‡1~ O…>8h)ÈÇ!?õ0ZFoÄ µú;ókôU æÑqü7¦†¦Ñ4àÓ¨ÿKÑA|õ ö ½xüúðŸ©Ðèï¸LÒ{¨•øÇø¿°‰Šáv:JÔñÅÐ?ú‹ÈŒ¥TÌ#1ÈÕÇÔ~z9~ý\ô*ý;¦‡>†ü +®£ÎÒnª÷ÐõåC«J¿(CT¹|£ýFgú |šN0‹™Iß}û.eÆwÑ—‰æ–ÿVÚ"º‘jAËEŸIšÑ&jhˆwÁBQüeƒqç ,663w|û-59©/ñWèj¼f‡~ÉLЇР+ü Ômj+ð/êhÍz#è™cè4Hûµ ÛõÔ°3+ñ D•`{ðHÃ_™KÐ&´ øÿ2XÓðÍ%z²Ä£ÿzo6ÌÅßâ]0ë&Rf.ê[zòÒ¿¢ÿʬmS¢™ôO¨ÃdîÒ?ãúm°jýö ØÉ¡6%ýJCâ!= +é0$Qùýâ`gg†/%:ŽdŽ lÁ̶6=ý"Úé¤w!x€œƒDÑ/R‡@¤8¨||Àdî*´·W¿ÔÖW¾ F™?´Éé"úEéã(\¹k0œÌ|Ù¦@ô Ca‚æ_¡O¢˜Péä€?š9N£¯hà4mfz± ¨nHÓ ­…ô!$1ônýÒʤ£ŸøïÜ+ô>|)~Z½Ý-ż’ÛÊl*ÙJS‹^„!ÃåSØ<`]ž)–O .³-‡~oÃHÁËôMØL:T>E¨ÉòE I Â8 4ªPO Bnø*µ­ÙG_‚q: éCêÐÍÓž<èoƒ ÁæÌKô ä@ R4ÄñYW~ç‚¥Pá/ƒdÖ§„1—¼B_c´SÈÕ¤,•aɵéó3JB§LÏx ГQ“&Ægå@xYpBF7W¨4É’{¢Y©Zלѽ 6£lù o 4g-üü æ2â@4«„çË%ÞHd• ©læþÀþÀ‰À›F¨…«™úŒµ!ÒPß@[fhðh8P`^Õ  +HÏrŽtž»š£\: ¿ê¯ƒœð³·‘qPÉÈÕ-’’P‹@ûRÞƒP_v0þ/?Èy3^_lùI["YxÉ lp¹¡µO^pŲ ‘´­Ç&OÍd‚ñl›¼üz+è»lù 1 ‚[²n¸s°u|ÆEhª!£#-%³Â)H©Ð~0ËÓ®I9Ba âÉZ€ðJgÖLg2Þ`¶žÿ /ÂÃeA»'³óx¦·’á‡%¹:Nœ·Šé}Ô!ê$+f}ˆ>I¿K3k ÖšæèÝJO¥Ñ"M[5Ì]ù>H€D£ä­Ög‡@†0š +9´æ!y«ð­•H1Ò@ÎA¢„:‹¾W‡ÌLÐÔ‡á€öx[FĩBÅH†)$Ef3è!VÊ·)¨k(€$nò:!·ó¶œjONuSNµ2§êË©fæTsªxNΩÚX*ÀAEÙIŽÏ +ùkB>MÈã¼Í­úÒ­zÅ­ú[µÉ­ZåV-v«¹UnU› +·€Û©BÍBžr'ÉñèQMÉNâQ°ª*Àš[ÁÁä(ã@0Ç)Ã@°ˆtÀõ"×f¥ÄÈ%ÅpUé$¦JiÄ1¤£¢ð·È‡g}~ åŠø¹ +9@Úl3-NîÂO"}ΈjúX•><à[ ·=DH› L’<rå@0 —WÔ¬çÚ´|$¡x%ò Õ:AXm­Þæp=½ÆÑE‘St4¸‰…ûÜ¿²E)àþé/R¸OƒE gÁµ¸á8ãÜÿÔ sÿ]³ƒûY°HácÜ{ÁŸp? ¨øBPñù ÐÈABýGjr÷áî®´½Ó/Tºó¯çn€Ÿ´Ñ7Ì­…f–úÖs +Mõû„ÌúX8ë…þ™š +§IÃznBÍ +n|ð7®æ'\‹o!×ÀAù1®àæê|³’>áö¨ ~ô$â;À…jp³ê^Âo Þ )Æ'%[%ë$—H–Kº%¼¤^R+IH¼Ä ÕIY©Zª”Ê¥R©XÊH))’Šåùqî b–1CrFøÎRH@å‚ïO”‹|XOwSݽí‡ëbÝEIyÆáúX÷aÙ´ùs`¼»w>µu_ì>üu¯¯ˆåÓçùÚña]7êžÙnʇ©íEŒfÎ-â2¹ãfûaݸ¹`Î0óívBûn¾½¯™®lµ´êZ´…ñÿ!»¨šÇÎ,±ï~,ÎÃ÷t÷Î=¼ßÙw8C¾”}݇'ôºÌ=Nm¡®éì8N]KHßÜãx<µ¥s)Çã;úÎUºªP_[©¶¹H5î­Bµ…•jÜ Õ„jÏ N¨ÆágH53RïÈ®³ãÇ u˜µè€Pç³¶R' Ôùø‚:"},ÔùXÄ +3 Uü~¨Rã'UŽxýPáˆß+\ž~þ²¯ryKåòáòåç/g+—÷W.ï‡Ë±ÿŸ>ËÚÿo5:/émÇÝÓæ‘¢ö¾q *ÔÄ®mä@;Ô¼Í~òHë;,÷µVøÚQk«%Æ6áT¿XyX eH¤z£Çrýƒ`ÈIu%«ª—m‰6r Ä™\RC±¦zÉr]£òLõ ÅZxÈq²äòÒÎÃÑ‹€ø:ú¥ó’ø«’ ä³qãÆ ®ØH>pG°·ûpóôysƒ‡­uôÅ:-—t\ñ¿ ê>…›ZÉMIçanÚ°!&Ü‹m¬|¶É×ﮨ” UQlùrLÚÝ@Z‰aÓbù÷ƒ.‡`€‡bYK0–=^þ’¾þˆ.K*÷á ¤p?´VicƒÐîDØ “ÝŒCD¼[ j=JáoÄ’"µœ×#ó äæŒ¬R±èÀ§xҠ쇿}Ý4Ú4…=ÓÔ3Ú„Zá;{²š´GëÑ ÃuÓ§Îò"ðßÝÌ)Ð+‘ò§ôAÑnT‹§ò—éfJfGЗˆ/‘]êZÚ$Ûäº&xMHÚ‹. R½ylðZózHSÑX<Žô†ÚÎä¼p>]Ûƒ} œDH¢Trv·Ánw£8ªs‰¤!‘HújI".·(ìua·=™` ;õEœÁ©%‚ãöÖ÷á~`5/Ãe! I\?¦7´¼úB…ÍXW›Í˜Œ -6LÙL]mYMù¼Á|®N_›Ï}^pÜÉ!ñá:áT’§úJŸ{§?Í;6›µ +•¶PÏy7ÍñR¾ &«Áèè³lÚù{p—/ÆéFÑî³y¬;Ú^×¾°Ô?YªÖ©âSôù­5©@üj|GwÌ`1E×s¿ßûæêkma1éB_:‡¸›ù!ó¤~€9`C„ÍÁ¼ÌëжJ½:E«T&•‰ìH*3ºÑN;/•·¨ìN{ÊNÛí +Ÿ_'… +wƒÆÈ)£-„º(‚øÍêm½yõ¶ð´V5 íScµ5{Í2ÆÂžOa¿îï\9Ò:¢+¤úc#¸T Ì*Ø7öÄúaÇq$ƒ¹]‘‘9¨•·J«TB¨LÙB΀ +¢Ñ‡úq¿¾ÂàX`Î_að%T[W[á“øŒäºyo¾Ñ8ò«»~PĦ»W-oŸóìÚÓ?è¿æš|Íò𦌧oKã2矋köâúçf7öN^Ò±i#u÷wFs >µü)µfšGøI2„u` 8Þ–Ÿ‰f:¾àþifänEZÁ+¦)…³Ó8/ìH;{„ø–“ætFƒNgÔ(t®°QÇž¯¸Z~¿Múy%Ð!>¥{OG銸‘—»d:³Î%¿jruNÀ(®ÆH3ȬnÕÊ2ÖV6gƒS¥Tï3B©JyR‘gí•ëkõ.µJU•ÚC–‚Ž7¾£)ûðÈð™ÏûcÕ “L˜l0É*³ ±ý„qý1LºÄ+ä9r’aàÐ_Ah£ãóSR™;¸:wòÔâÒ~«^­7å +®EÓóÁ¬k<Á°9%Úýí¼>ƒÆ ÌænÉs^ÿZzÿ­…“@ú›@úAúUÈŠžãÛ¤”ŒËé'ôÏ[µèL¯XÄó-}Ö›õ·Yöê¶<©“Ôê¬ô]Ö9ÒÙº™z‰\©ÔúZ$2ûñyyd[woN²m\~dŸ„’XmÄ­åCˆü&ÄÃ5ÄË#>É•'‘ê4âÑ£H„^³W¤ýëŠÂêù¬"ø=ŸÀƒÂ22Tý âØ@1ç¥TB†HGî+ ß²ã¹g±ý¦›<5âÝÿ¸¨ëöPÓî)ýæà¡]wãðÁçÇ÷/)ÍoÑ +ü8щÒ$úmJáñ¼\l;š“Œ0¯ûãR{Žºï×>«{ÎûTð‰ÐþÄäPH±7øPò€^ޝÞ–¤'Z'ÙgcºhLÇtBžHÕ†è{N¹=¬œU¤å2,MË´î@Ì­e½ èþ°§HïKð;HÌɱËzbE:É+ +¹LͦÖE/äÁÛQ†R’ý‚¥XÐ,„ÄyslÅ4»mPfsæ¾°` ïÒµZ`jYx{Þ²:ÍšÙ´~éò÷]yÑ„fnÂ”ÂæÒ߯¥›{6>Lïøöž)&³Gª ¤2MÇexäGSê_t/ž¼ª·sòÚò3J NtOéXÇ}C¤ü4ð· ßËß$m°6Pº|Í„š™M«L›Œ›M¯£e³’3WÉènãL4ÏH×¢&#å G +Ô.[ÃSËÂ_¿6}U›šô2y0T_h0™EYc“>²7'³ÙªÁIšÑ4§o2èõMµÂ®osߤgå;eÑEŠæíMÏéaèy‹5§çyN?U¿H¿G¿O/Ò©¯Ìì|'î½:;ánCžA¨.Pƒ±Bã9òV_8—¶óöGÁÈX›ev³Þ •_õšÀiPzç‘è™!;ïÓµ + € ôˆ©¢izÎŒô³#BM‚Æ  +"¢Šîjj“1±Ð™ÁTP³M + a :Íb´( +F@È«,4BJCrAÓý˜>o{Æ”[m%þDKˆúh¡êêèÓχT +m¤×5µ·.Š«Øîý]œäãsÜZ¹1:‰ëžÉ×Rá…!«Ñ³êȆ6½nôàÍ>–[mÞÒŒû¼õ“¾)}ö>_Óý ί±+µ®‹LWÔÅRÚ]¥—oòéÍíÿó_L&šb.X®¤È„(†&d¾¼!oº²!¯‹ñº|Œ·Ús}Jlõa“9Òé™§#=J´V\¤âmJIX©QF4œËcp¹>¿½%î »ôî„AaTvn}àåWõ,#!àÁ'€ð²xˆO+½†BžWiryPsyžÍËr¥EaUÎ@7kŸd%uæÖüxól3cXƒ¶}DL›9—çp…Q˜ƒ@qÐÀ„•™t€ R–{༴†Ò‚â"õy–;¢)†ÁzƒÁ ý!-ÆL(Ò†‘‹SiÕi•’Q¤•ÙR¬ˆ¼1,4i°X8Ðà÷1ƒ>7ŸÑ† Zm‡àÁÊ&;hÂ( ݉"‘˜J)ބ宽¶W‹°*[Þµ“+âãÇ,Ãþ¢a8ø +}q; +ƒÙŽá2?¾œ=©Xjá4NÉÌ&”—7ä#Ö\ÄœyÚ"¨ëªÛ6<úñ× ŠGG¦°ÃôD­=£Ã ›Æ·ŠÃVÙ\›µ‚/GÔ³±c8ó¼½fß”HÙ&iÓ­$ßrZ ÕÙÓ§û*\pã1±Ú03ƒ>_G"\30çæ±é  +ÒܵstRixý‹õ:¥/îSà!y÷eÙeîÙ&w­^oКs¾Ë®HGÍáþ+“¢€Ïœ—-²ø‘ÉV•Œ•ƒL(Øíœ<ñú_†ÃÚ`¯uÇO#¾çªÒÃÌÆÅV½Å-÷‘Ù=4ðæzäÂâãHTþ=¿NSЀÆyBôõ­šže߉¾Æ´ßÙ€æ«iÛ馶º¿pS.¤Ö`F$‘ §ÃeÇ6‡ÓeY,E&›ÕÊ0ôÝèQ +‹õ +$‘pà^šLV¶šXªKCs4U¦1½ÚI4;Õ'0F°àJ‰¯-äN™Þ3Q&ÁÏàd0BÜwü AùjLį0 l"ˆLPŽ£ U‡ÉÜ®¨Ü ¬kkÓðh1¼˜H7ª€®[ ;EMM˜˜Yƒ‰VÑY‰ï?jVÁ]”aÊÃÚ‡:X…5béõ,˜Q_ˆ×»Ÿ¾W~ù]ó˜ëK_¶Ž,rhu>à +ë-uÁºXíj\ÈuÕÝd¬£àr5ƒ& òmØo¤éx½P¶P>#²Ÿ>¨ÙoyÒ&»Ù¶×VŽÑ;˜ûÊÅquzþޤQ¦ nŠ£°'¥Âª"ÞÇ{  …°$Œ¡ǹ=·Ûãæäa›MËxÙ4-;Añ$Ü?yÓM¦DÒ\pó¹æœ›çݼ’?7ïpæ#÷>÷I÷{Àä²[ì.âíC1·9#p€èÍʬ›àŸ3X ÅX]2ÆÕ‰"Œ³€`Èðê´n t Cç£$^A ˜Pt)î»ãОéYOÐkI˜= %‘*´[¾wqÔ»ï?îÖ<Æzzz}ɆcWu„íM §K¥jþâ‡Ú{×›¯£.[Ô)YýÎòg˜Eƒ€5\Çwˆt_1$³*/ûJ0 $0Z“®»ÀÆî56E£ƒ$‡DPK¨ü)3´q +5âWùG$.½Ò´*xk^IÁ×6åä$SXrùœ‚Ïdá4“ÏÙå6Å%òKÿ^!n5N5.2ÎÊ2çoó6äjó]®®ÆYÉ[ó÷à ŸBÇpQ>ä<šÌ«g"Äøïy¬´@U9©/ÜÔÌòÍ< ˜fÞ‘7Œ>0¨_-ÇrEª,â¿óÁp2êñ²…tÐÞPë3Ðz¢}i”HHÌúÝ’B±ü›W¡@|%…@¶¾)Ô³¨HÓƒÁCz… Qk¡Ÿ™GrŠr8}¡z> /§‡S{‘žÕSúbyÛ@o^Ooµ`‘Õv°Èvè¤wút=À7¯Mær_رÝÚ¤7ë›ä‚žܨ +ÒúìLlÝð(øT#DúÎ{SìH¬âPU%¯µÑV¢lçÂlý<…\1è‚M_èz¼þ\Ôö»¡€êd¯ûž{¥Ô· —yú¼§…˜™¥gZ™Jçæx7ï»Bw^5£{òºWºfEí”àÅ +‰Rcô˜óöI…ëJ_´'WXÚýíÒ‹\rÊr‘qéµéxá¢k?œÝxë{ñŒU³âY¼ ` +ÛŒj­$0ºŸRºè•î©øU"wi@?ýDyüo‘¹¥ž<¾ ßÝ‹ï³ß½/y0{,¦HfâÍ%Ÿ0=QCÕF'¹)¥×šWª½áœš\+À—VóTó"3ÝœÆJN• ÇM? ÒŒ=2™Ì`ШT™B©L0`bjŒñ¬3Xñ®C~¯—x× Ãƒ£1˜t6j8E$Ge³± +cm8hdU;•/ƒÇÈ€Í6Bÿé‚ωº6V_ ‡Œ¬1m¤ï0bcEdŒ/“X-}=Ò!'Øq'©k†rN¡}Î/œ”3Sk4kå™×¾ƒË…ø¹iZ¸•Ü4˜±V¨¥znôU¨¦Z¨¾r^Eîô‚GtÝ™vôëïˆÝðâ«>|Eçaâ±ÁuÀ³òÖ¿¾H¬,4ž<‰òå÷QRpeˆàJ‚,ûcÄw#ÐÑüÈ: (Mª*·€è½f¢åR¥ÊjóvÞÕ‹™Œ7^>urת“woXÞ<Ý蟸|_Gü²mÚé£óæHPÊXç|ËÊËb‘šiÝ:j6­Ú‡¯šÉOZïhšU¸µcêc¿üã,â©•]¥IôAö|(ƒ{ùîYøvåÃÊç”/©Dc7¯oœ%^¦Þ¨Þd;>.})r<ú¦M=Î; ÍVÓi”óòˆÆ*MF­Œ`N›á¦¾N{?Í«ÃÞ´¯ùq*ˆ‘äèvÞ bB¦F>5g³l6{Ð/WÀ]¶eÃv?‚"e’ÌKˆN‰THH ¼Ñ—ð\~ªó’i’µ’G%§$"É 48;j÷ùŠ6¢Á2yI›ówÀ‰Ý™ûÂ)k3ÛÈΑ†#³«J©âþmþÔ’bGF«¦ð³Šp¬;â9o w¢ÙùwÄ(h¦¦J”§“ÔV¬""FQÀ•`Oíy—NORn³úrˆ‡¬ ]'o‚d¤fsdn©òU'Déa˜Îìã¡q X¿‰³{›ý Äîµûe0ÁÃäÀDŒàµBê'v>æñ†Bǵ3>?äjíÃ… à¶Êý´j%­’Ö¸Žpˆck +5i‹LFÍJ©Ò€¹FE"FlZσ±z®ƒ3sòÌoϱytd46rnÚTº}b‡Ïi„MáÖÓì‹ØÓꦾsF¦ª‹6èET®¾0Þ&W+Å7Z½ÞļVÉ:yý˜ÖéÃ|ô¤$ÂTøQÅIu¢PKPhåKU\ª8¥j›„¢ékÒ%›,hŠrÙ€=`d%2}lÑ$ºùùçÕ½íuñÆÚIOœ¼ éçB6™ÊÚš—·O¤×µ—ºKxä³ÚüÖ°;å5™ôj‰L$©½tYôÏÔ“íæ¶¾«Ûûúz¾´ßʦ¤j‰<œ_×ø'Ð¥'Jã©‘ÐU}rL—á5lNØDf ”wªò‹T‹óƒóCw§E¶Nwç…Séô¹ŽG)Qª”i ©èõ³šø"šp0ÀÊÖ +¨Žæï 1OO£)zÙÌœÄsö ]Ãú[‘ÎóŠàŸkæ@͹e;öë¯GA[÷ ¶ÊÛ‘µ Î…eªAÁ×0¨ jÒ HJHÁóñ˜ ƒ1¸ª©-æ +ÓÌ&Áÿ?¿ V»"J£½­µ­Æí4é¬jŠV*§oH|è‰yTZ•UdC›¥+Î^ÿåû a.¥×èmz…DÄ0+ Ñ:¥%^¹hæ×=.šŒl(þp9ÊŸòYm!›cßÚÛr‰UµS…ȉí‡Ë`4˜TÅ“˜RI ɰÑÀFNÐ[‘ø4·ŠO`3J‘Ș¾°6…Sö÷'hŒŒtçQÆ€ E¼áXRf0’òx´{~i´² d(o#íÀ¨†-å (à-¯>$›ÂöǾŽõ|66ÛZGØ‘1ÏÍr¡Æ¬¬éÔyÜŒÎhPÃoáucã+ güuµ:aÄq\‰`=–=2Ã_JzoôUÕT{XïôéÈMÆ=¥ßxŒ:[ÃÃX5{ó]þ*/ +®+ýõÁ›¿½÷Øœ¥Ô:£[éÜâºP4xV¶ÞκD²6¾ïÏoL6ýØÃZ¼§²R›¨®ÔòU—j¥)²Sö3]2C6Ã5ݽ _“Øáz*ôDøu"¨X€„Obzžlžkž[X_åª,‹‹gG§çWéè»Ëâ1aU›ÒÓ;Jl>ÜžoZZšßŪõªèlýÍ…P"˜Þˆïꎬ–Ä»ÍZö$µ~ÙäaÄ~„ËU½d¦ëùùÖàKC^fµY#ÖfëSÔQê„íh¸˜yƒ~ƒyËú–MÕeï³_b§™št*%rÆ\¶›–I§’‰XØa—zjDb‰T&W(¥f&¿³þ ’øßŒ…\OŸâëj´¼B—Óh9-¥ +7šIÌöó£fjšy›ù°™v›ÓPF›»ê»NÖáÖº©u‹êèº"íãUÌG5$¶RCQÀ‘Ü5Ö|QCO«ÙVC¹kÒ5| ]S¤ƒ…ÌïÉ!xJ‚0p"„†AÅ~ÞÚtfDˆ¼TR ®š€“™Ó•È^M7«)KRcæOŒ$ªÖ±˜Ym$œ án¯MoZ_7½F!V7†ÒþxËêÒ;¿½÷®—j TR½T$kêº.JÖ«ëÛµ2zGò” š|ã47«U¨õYO$ÓÅO}»´à›Àè/¥¤"¹wÒÅ-Ôæ‡;Ä¢iBˆ¹Ht)ò¢¾“¿ž6"c¡=R¯Ü'öK”>œòµú¦úùÖø®óíö=à{Ñ÷‰ûk·BäùDþ´'ëMû;ÞYÞËœK½ËýW6zŸñ¾oü…çW¾_úõAoq“‰ ¸=åH9™omÈy}CNðé ~ŸÏèñzÝrÂ)wzϨsadÀù†€O¯—yít8är™”öj½”ù`Ò›Ì`d;Ÿ_Ù,gêLI¤ qÍYõǺ@[iI\â×ø¬YgsM:1ƒÇX÷Îà%)“Væ ¹Xs6—˜½ýñÒgõÔÑÑÉøÀ?V¸Íbÿ¸§KOÝ襈§„Ôå?2³A'4âYüÍ7ǯOQ U Õ 5«TkÔk4kØ-ª­ê­škØm‰mɇT«Ò°aUå3+[]H#.9ªv ²xR[—¥}Õål¨†ˆ½¨„•ûêµ^É¡ÛoÜÎ¥ÞYâH¾ÿT}†›Ñ V²sWz™Go\yC/ŽÍ½ìMM+ׇlÿ£+½ãàc—tÔ÷þtiÍô¾Ýo)Ä^3E»jJ-MMlž6~kéÍ_ñ£U¦˜fð?8p§“û–o{ã0ÏæÃ¼’:ßGÍ¥1x˜ˆ£ÑÑEÑõ^ +Uj‰E"ÁnÿNô†K8·‚Ó¥t­:ZóõMÈBlµ¥¢,‚ù/,e å¶ð–m–;,ïZD[˜ÛéF]Ar]iÈ·§O™àK0?%€âÜd3C2ç®´#ÿ­`ÆÝ¤ñiîmî;ܺ·;íæÝ´›òИ!¯ÎéØ0+ðKØ+“šÄ8Æ&1¸T]ÞBýú€Àó9ó}óJ€™À8öpz»VªÞb¹ÉàQ)ú³¾(ÏÚv?bx+`™lm°&éî–I=ëœrv§gˇ]v[GÔéÌfS“[4ÿ”ÚôpVHê°Ä)ðyÂXÆgezK˜ÒÍ2í î +í +?^@Çì’PK)'ÖYôNVÆ:µ«Õ%•¤R™Ï.b1ïq'±NKai8äCLT ˤ,z…Ù°;L‡OG­/ƒÓ#£;‘IÁã‰È¤fiDÎÏ‘Óçá­àïH+þŽTОB·wGºÍRótÈH®ë©.MaA5ÑÆb +ß7zº"Gdo€Ÿ×Z¬Åò§ dQ\£o1õ´=ð|×!ò†Àú‘ehIÅ.fÇlb–>pV¯žf8ß®ºÉZ¹’ŠHû§Øt‘?ÛíÚ¦÷ÌlÉ9&ØJ¡s&¯¦ ËÓÁ(üûíg±Ào1iüöZ×U Ðå‘ò§Ô' ÿiô*oÏ`löÚÙV©‚ÑXFMCHVø4÷Óˆë®RµÏJáV@ ‹0ªƒáåÉ7PZ"òG$Ö"âsÆ7,f…Ó¯UP070¯S´Nÿ©nxÏý¡ûK7½Õ½Ç½Ï} +÷QiCp¯m§õ a†èsy Ÿ†äñ浜²P–kkNà¼PûR²Upé( ’aaÇgÓðH%ïU (x´/XÕ$$ß^[Ÿ>kªª ªµ|û:ê“æ€heOK—³æ†ÉÏÝ4q¡G—0šâõK&÷±ŽÁìíkÜ6õ +mÌ þÂOnÙÜ‘ö4Õ_ù˜W™Ä÷]7«%ìmzU~ñ-":”Bˆ.¿YÏÄ`–Ënúìökß™[ˆÙ¯KN¿ñòëÿùn÷E‰ž¾‰ëî^8.¿¤#\òLïmšýÔž·»W7ÒÝ+kS7­X¡pÇY­Á£MsùÎÛ{—æcý.ý,<¯Ö¸{Îî]-øŸkz.nXþÈèÆÀõí±–Å=¡ñ&%Ìò_34 Áêð³üS¼õ¨•ºÙº×ú¤•¾ÕqKèǽ‰§íO'^d†tCŽòŽ+· Z¤1hº¬t–·¯±`õê-6;ÖhÖ°,’ÄÕêER§Äé— ™««{%åLŠ'RÔb‘Sl¿ÉlþÒæ´3à¨bÎ8bY¸~ .§’jƧÌI§Ô_øYñ³²£-%ÁdzvÞlÖí^pNÈÙïJÞ% Q“͑ۗø"A%lj?N©÷kžE÷³$TBE~ì'õsôWa9EZ/ó›ýõBè¨}'PP‰ùA‹‚÷é/V´ª¿EòWµªŸ·\@:óñ™TÑsæl,6œ‚é}>r –ªéßJýÉ‘Ïûþ®T¾ +þÅ­$Ì{n8q2@=\8‚>ß9ÅJ +¿«}}u¡š€C©{ܺ}s<°+¬ó5_|ýz«¶ãê×þÜØöí§ª)ö°Îø‹#ßcTÒÿgf@b󶥟Ñ£Ÿö®-ZⱜµÔÚæµÔ;”n PJ#r#Y’ Æ¥ãI.ïOZtDƒq ·æ¥üQ$‰¢fÜb@&˜È>LöÓî°>ŽŸµî>Ó|¨•`…5/ñlð¼i}Û#’ù”Ñ>š±ÚlT4ká[šø°ÇKÙl\˜7„Ã|KÔÊ0Ú|ûÎño -Y äŒ r9’äß(„’É ‚‰Z[<;÷yß×òM5ÜyO@<öØn“í +Nëp ߨkáù–– n¯Ú£:¤bT¶‰ë„"6§b +;Ì~Üœ#1#ÐÙ“˜íHEBʆÅsñøs;p*«n„Y1ð&!žßù Õ0¹Þta`($Q÷s1÷J„tI(XÙJ·¤Æª‹Ìõ- Zœ±¬Æá7ZR¬ÅÓ2{†Þ¦2:êB¾ÖÅuÁz±ý¡…Í…°Çw»ý6µRŸú¡µEdž4Ñì¢wärþûoJÏaåIOPm•±ŽÜÞÒ3S9sr’îÊ)ñÖŽ”þ:%ã45Ù¨»Ü/ËåÖBÆcÝ:/èKEæs­Pj¢©WOí¼÷€ÃÄzM/ç¬ pÜ" sªF¸gÍû¦][ïæ35SK¸æšŽÖö†¶Ò5[Õj¹DŸh ß–IûÒwâ¶5J½ÎªVǶ~tïçTÿÅ»Í*£u¥_RÛgêe&Ÿ2úî§ ï~ú.ˆjðN~‹Ô$ 5E'¢ÉÑI±yhº]ÅmJÜ#~ ±?zÜ|2z2©}J|TB‰&ÇŽM‡jj¥^åT*¹Sa3X¶ 7à Ö0ŒKo0èõ×ëþM!öàH*i‹$1F6*¨T*Hêõ`ÄÄõ™°AOvÉlE.¢²•×® +Õ[€bó±µYœ­yŸ!ªÐ@é‡ô9ê«Ø›P^ÊNÏk¬-z!ö¯#TÐ|ú6K”Óô ù„Ëð}õ)Â%xÊ6=ÖÝš‘éÍúÌ÷(ýÈHllI˜¼Fu^sž·­Uí©;üÁþ_-é­¬°ËFØ~ê¡Å¡Š´™%ßÁë’ºŠ~%¸Ð,ÁUGŒîý`ò´f§ébÙèß“l½Û7bé¯Ä'~úÍC7¥/ºT1:—Ïüñ–-î8u7fK˧ÕE-:i @+µÎÔUtvF"ÉãÀ3;nüÀYÚp×\q€ú­ìäî5WJÉž¾Z²§O´™‘‹xv¾KåX"›Žæˆ^t0ÁêP +Q>ÞjËiE€œü 2wªÿ6¥Í=öذšìç„R §RT*µÇï*xBŒD5ló+ª@X­bÉ?Ôá5’m½ù=’w%®ÝÅòœ¼QI霪²9S AÇ«H?¥zOõ¥ŠVqãP@eVäEŠ;òÚwwmŒö÷Çέè€ó»p³fE댽 -섪¼í&¼k»´DE1Cøü¶KÂ]u÷5õõ‹öL¹ü¶béO·Þ»§}¬9aŒE–Nžûò®ù-ýAÑîÑž¥“îÚòXéGëó&£M¥“ÿõMÝõ8óЂ•{oû¶»ü¡èÑ¥¨½ÆOÖó†‚_U0jºjæé–sWÈ®PmŠ^»Iyw ÉN#ÿeXk÷8œv›fd:C)tZ­Ëë1xµ/h[* ¡8Š¢Š4Å+%Ùì]µ)Z½4 ³qû%Ëj·£±Õ#½•×Dà©~Bw.²¬nÙ‚j´¼ç3–¼Ÿ0,D©>ý˜ íT€Æó/ˆ}ok"{#ªp7-Ötc;OB¼q@“h‰ŸÊçt‚®ÄÏE¯. Êž»¯ôæë¿úV¦oÞ£-ºÐ¡ ròžñVmpéŽgúYúzëþŸ_¿scÊdõ9D—–fuû/¾·ô»OJÿýJés‡û'Æüzg(„½û ¥gCaÙ‡qóo[ç¤õæ8A¿)ÿQ|#èÄ î=ޏJSD–É.ƒ/{}G•CªML¯h·Au³‘&¥©‚®1Äȱ…Å”ÛÝ0ö(‘q"A%Še2W4aˆFn¯×§3t:0!E]Ãjý>‘.ªË†QëÝ®ãA‘é*[>[„—UÚBZÇë¦éhV‡u/ÑS ´`T0ÒQaá-œh,!P^WÓsGqôê¬,jÖ™¡my‘n=rÎG›˜„á;ÂHëwƒ ^*ùÏÊ«ê¨i ™6§#™Açu3j+"^Õª½†'z$j +8,9÷"_ +A``ý˜aÃŒXI5+ævç»åÑ{—<´fïêDs¿RL—áîžpÝGÞù—BÊÝâ(lMPÎIKKîma¾nÓÓÝ·~r%~äÁ”'%‡­{uIöÕg²·q\|5þÉÒT "&ÿ¡«üGÑc0»Bhï÷³ããØâŠ+äW*®rÝÂÞÃ’ÓyT©zJ÷†Žk0UÄ=¼Lê¿Kš ¹ic‘Ò¿ ]j‘!²2M»Æ¦Oh;AG t†ü*^ç ³ÇÓhŸ;–…—m{¿¿ç³QȺ Œ|Î3°Žì°õ…’tZT_ÒÊhí¯¾ÍU-ó3"ÿÄËÇ Þr`ñ´‹»>èO]^:óâSetË_ð¾Ÿ/¹¦ÖbñGa6t]Þ´°3tñ–á—~ôúŸ¯½þГ»ÎÞù{üÄ—)ƒ!#±!Q$߃c¼&öUŽÌ + ³N¾²ˆÞN¹·{(‹1~‘–"9ò«-xX”FkÉú-åY;+§âDËrP,ñDy^¡—ëuR›7lg?Ó ¾q6Wñ‘cÉ +õE*ÔåÎUœd‹-·Õ¶Ïvœä"åzÁ+³™m^ùŠãô$tÁ7Õ%Ù!Þ¦­‚o+íUö; Ó·ØøŒµµêù€ÐW°h¬µél;ÚÔtîMרföË~lIÅÈ·áK}ì4fGØÑ¿mõ‰®FÐ|¾Êýóî,ö™öá8#^Ô'¼·_Z:“å§'•£ +Û”¨3ÅÖé÷ÌuD“K÷Mmé +8ÎÎ; ÖVmßôkMë/A´€Ò޾ 8ªÃòWJCéâéÖ@kzjz~nUöšìÚÂmé½ò‡ÃûÒOÈŸH2Cò—'ÓúÙñÓ å­K$â±9q<‘cNÞŸJê£I\—ôú³ùdÊ»ÇK$Æ”^ê­‹'lõd ³LJd„ÿĦÄʸ…è­Cb^«Ë‰É³ Øîí>¼qú¼¹9k Xþ„ìtï>ƒÂ(ò‡}ao˜ì¯üãeÚk,d¼žBR5øOð™Ð„œí¾·Ú¥?Ù.€o8¥ÆÃ›O.zöä5W¬||ÃŒçKÕGXk ÿ«ëÑ¾Ôæ|ïík·ûëK?\ÝüÐ_÷>åNŠBÉÛ'o|9‘¼oþ²âr‹6@©´Žàv:¿2ˆþjhûŠ Êoç«_zìš4Ap›Ë#”•Þ‰€áêŽ#1}ç’(‹@t F²  ¼¢òïI¬–˧UTTÏèו=ƒtÁNRú‚ïx0ÚÔ…´Ÿ¼Ìml¤w6F…¢ÆÑxcåýÝÆŠmÅ¿I£oÒ˜F˜Â +ªÛD¨Ÿ¶2'Žã<ª¾ãD‚#BH0ë}4öŸtL´û_½¢ç ­;©iôZhkúèØ?sX–ò"ÃêsÄZ«á‹Å ÙD’¹È¥@(G ù Ã™#/Ÿ F•ó*åýÞPnz׸“™œ_ËØb!¿ÓÌ2œ\…BµFc¸Öd{yXGªé%|#ÒÑûÑTì=*Aè)ÕKô³ÈÞ2zª¶H?;ÔÚª™Œ'“PÔûÃk„U(Ð4££gFá§93Úß4\ÝqVÛu6öul›  õúu8x~«µXr~c5X‡s«€dãAe½©$®­KÆöVäðüÞ“ ÿ…±xkü\2/®‹w´{=‰ö›z²¹îMÝ —««%ÒLýi{ÀeL*Eñ®€ÍáMG"ö‹Zk»¯q‚ñLºœ1tv\€'euø2Sƒ .ÐàÔšìjS{ÈvÕÄ +ãþßâž5¼êÊ{æ!i$Y£÷Ó#<Ö˶$'~;Æây`ÈÃIí@ŽcȃÐP6 ¡[â~,MP´)-…²4KÛ-dwAN8-ô˲ۥ@i³Ë~ÛB ]Øb_ïcköÜ‘äØÐåc¿ýQ[3÷ÜsîÕ½ºsæÜ{sgg}²Mòd÷6-L4®òÚ3Õ6§Õ]‰AO4J×íÁ+Ú +73ã !wT'·20Å:å™·ínm´Ÿ%Ù”¯Ìxjæ¿S Ý†ëcíyœ·FP>faÉ#žÑÑ­ÇÞèlæmÛ]ñÅŸäq<7‚ÍFÀ&ŠÄØPUE=P^ U¦Ä¦lv4)%*(è–<\ bajEÝ.,…³™“©²Ù<1Æë1Iɰd7ìå½·Ô .Ÿ×çòÖͱQè‹úŠ‘¦ÏÖÓÏÎÝÇ£§ëëzÓÿÑÎ_ZæŸY°5º¨×­s"9⺠øË”ìøËáû¯W7_b­²À k_4듣şÔ/z?´`½¹¸Ö¶"”rKµP•¹ÊÂ_zîߨà†ÖéÅÄŽs÷s7?žkŠ't–qJ ·°w¥Ù½æï8gñž2§¤>ƒSœ”SŠC´Ös(;^FNé†_Ÿ$ºðhC×ÂÒ‘¡sB¬J쾉ìwdnË|?˯nXÛuÀ|ßÂo,z€Å‚êr†UœìÄp$œ ³¯†ß 3aÊoæ!ì ÷˜¯­Èý)]æ„K2'\–9á²é,<áïëþ*=™tÍú fWÏœIøêYÓ³ÔvRï·OºOuš>¯2ù¿õ ‘Æ\fQ+Ñã{Ã]úfYÇÂ4K‹1Y4þ’niPy@M÷r’/gÝà”sQÿ„RXX¢b‹`ÁŠu;s–™SB‡Ù´°8}[´ýzûŒîwã–¹­0cî‰Ô'›áw¹°37Ã1á’Ñ&ñËÎ|œŒÅŒÍÑpµû2x¸Øs],^’xÎêÔWÙ¦«:’u:/þ«â`ë’º ÇYƒêª5QcÎS}šv rh¾yjD*"~£ªÈm$"ÊÌßÝ®ã!vBF`%Fp–BÉ €«|‡¹O&˜Ý‚`v:LB$iìþ' àìdf\¸Œ…ˆöw¼€W\(…ÕÒ䱦A'šÝl™ž^^ÞÃ’8 *N·Ñ"‚à"ú¢Þ5gQ_ÙfJ7Ó{ªT +T?Tož|¶ý›\ï 4ŒŸæŽË.šê )”RÇ‹a==–è(Uò(=„(-ÎJÚ-”µ>A7 # tŠtÏߥm®ì Úõ±nW^Ðýh@QìÓ“b™“ôG#ácËÌK¶¡Pƒ'ª¼¶ Z«E¤³±?ȶ˜>ñ…³»Ù…×4k]”ÜËöœþ†H@qékö×øSüVb'5ä¡Gä ê¶P— Ðè¬î¬é ,©^^3Ä|Á¶Ú½Æ³Nº*<îÙR½%²Óusõ_Fns’î2Ü麷úé„ç)éÉpÈh3¹GaƒM&ÁGM«êî°ªë[¬ê%›­ã +Ýs[õsjôâNÅ1æÆQ§Z8Ý_ µÔ X²€×׿¥o(öVEK ¥®雵QsEk­êÂ;†n eßßûÂΙâ¦Wþú—ãAžØøÔË×¾ëЇ¯Þuÿa~ëŽ7¾üJ1z~ÿÙ­§àÆ¿¦Ž½öè«§ýûºm·ÃƒSû^Ä{cJïi¼7z`½¼û.÷wë÷®µo‹þ¨é‘&Þd2yÛül ²±ãb5ÐØ¬ÒöÄçóúý¼ÏçO&© F\-·´Éd +eJVà D¯]3-Y)#’µn@Hë葈M¨’lQ¿,EIÒ©)ÝÑšŒù †‹U|žÔ´BØ›B.Hñ(§?ïÆÛZR¿WàM«RÈHjb*ÙšL£ì«©‰Š6Óãð_Lï#dÇ®.tÜÕÙÎ’ò¶7¥’½¶¯\p™ÍRæ/øæœ?ü4 +•_ G±ëÛÁè@éÜez¶âÎÇI^†àòúÂLYt¢0eÁ`œç¤6^1ä!ÚU.Op5ðÏ–Ño|¥xdÌ÷7.]f™yÛ²ª6¼ºøÓ+–°ísñ"ËšÖË÷CþºK¯0ÃÖÞlÀ¿þW·d®Ð2þÒ˜mä¶âwŠßjÞ6Ðac1¶Ú-W_ kŠO]v:Â.“‹™"ÙpöžXmˆÅŠ×?\<öò-ƒ!¯Ê‰z&‰‘ƒÜÜ3¨ÿöªqÃã•æ3Ô•Îþ w%œ!¦3KŠ'gö0À¬ßû¨¬þ~Ð5Ó…šÇz4Îs,hŒ9p%áhrD=Qã-Šðþ*øc±ê üq¼_W«¨ìŽ—1ÔQí¤÷1Áà\Ž)øêq‘ü-LAÿqÞ¼…çZÕ,öŠ|„gø s +Þœ\QÚ qp›œ™¶ÿžôôè:pÕíìF¥;êjv5¥¾5U¼ÖrÇáÇù/»~÷о|ñÉbñtñ_#ù_fF>z‚è¿ýÇÜw'1oª ÿÄB’½‰ýG–M¢ΰ“*=}Ãr,Ã¥xƒ›ç ¬‘áO±!b`Â)臄eCjXö BDCÄÀ‚&`Ž+õ<`\\¶”ÂJPÑÄÙ?ÎLO—«ÒLL•H“X‰²âK-ôÜû9û½ó£\3s°˜Y ‡áÛWëè3ŒØû+ôÞß®¦ÚØ],ãcéfO,›2ðnËxaêgd9jQàY´ë´Û´û´ë™gß0ˆø}#Çó #@д¸<Ø¥^cï?ÑiSùaŸY@ï´ <€Ÿ×|~{ß¹Ÿ3?…—¾P¼¾¸eüšbè û}ërzp„¤ØƒDe:Èåwᑦ)æ‡ߎ‡á!V"uX¾i <9¢…™Žâwñ8Ÿ֞¡xö ¶ž{]»—_KÌÛ°nw£vŠ•´i,ÿÒ^Â2S†£Ú“ÿ‚?å^×^IJ­Â㬛çn$wPX·ráƒ}ʈ\˜ÖáAþºW!b¹ß¿©O.@Nî/ ìÜ”ïÏõá×MZ̽Jï¸9Ý@&Í-|ÊöIðuƒ0¾þÎI†˜ª°S… Ò×_(}´6Ö?º±°båp_(I7 wLÙP tãðz½éÕ›)z F½y3ý5d¿<ÙðtþÀ”lÈÕ[7*GרÑÚ†£Ûí+øn>ë¿Å/wöïK ±ù~ÿf™fóù½ráÈÊá¹Ô(=Œàw`]&6Ë`Óè ú³ØÚ}úSJ?j\駘ܹ (‹•Mù-9¼Á|¬Ú= ª'µWI°_Î +ÑBOHí«žt“üªÝǪ˜OI7Lڥќ´‰eÀZ5Ÿ¥é^œBËWÍ'Ð)K‘ +ò˜Œ=Vð‡´ÓÓx;ɵc1ü¬U؈—asAèÍåíOëø˜]‘ó¼ìÊôÛó1£eŒ!fÿP2Ç,!½êë uu”/Œ½x!±Ýz¾%ݰsŠyGÙn—1Áá#+†±ÚHgÇ<¥Wuÿ”J6`¦0±r¸”—ɆÐ1¢fëG +LŽRž®PWÛåCór%zû,­ \½Ãlˆ)CLˆÕ©È‰ëg Ó̰µÀÅðcÐ9yã”Ñ„¬¨c@(ØsKJçs4ú9+MiïÑZzr¡Z¹›…ÎúùùEóòóºgͳØa.Î,Z—Ï›çÑPìäóŠ<ÏåGQóØ Èv%’-°…üöþ\åŠNiïŒàØÈ­ Y<©À¾•“*ì[½nø¤yßÐð1\†ôæLÖ"mø¤LˆªcŠ¥Hš‘i†,dôcŒI/:©2¡S9¡çǦ€è8SdlŠ)á쥆âzC*ÎXcS\‰¢VJsˆ3•p¥ÒÉriRì”ò8aèk:(±ôGEEïÐð\~Ðo²‘´þFVç3+áà=úrP¢ž´—_×&“©#õ$M2¤“t‘nr1YLzIé'ú{é;îè[/'+È*²š ‘5d˜¬'W“Q²Œ‘dœ\C®%›Èf²…l%בmäzòE²Ü@¾Dn$Avd¶»[viÚì‹âþ-ãÂ_{ˆ8"ô™‹×´÷µ¢vN;£½©½¡½¨½¢½¥ýVûæ^Ð^Ö^×~¯½„ÿ§µ_áù7ˆû¥VОÑÐþ^;¢ýƒö˜v¯ö7ÚQ<îÑEìw´ûµ»wT»[»Sû!æÐî{U*¿SõÏñ‡ íÝ£?Ñ¢d㟤/Â% ð`#˜@Ðß²h…*°vp€\àÆå—|à‡!Õ A" Cj@ZˆA„ÔA=4@2…FX ¡ šqÉÙ +mÐÐ ‹ ëÿõ›€mƒ¯#ÿšø{ø&Ò1=½”=B®aœ¨I2<Ës¼€ëS2ä‡{eÄÈÚyþPqšŒQøñ¼2ä4¼S8ú\ºi fˆMßÂ,B­e˜Cøª2Ì?ùZ6 þ>2B–!Sž]‚>„ü¹ yõFlaùqòè6äáëGþÝœ;Šûyk}Þrk1OïƒÍˆ¹ï·x§Ñ7†~Îúÿ´'Ðí +endstream +endobj +847 0 obj +22164 +endobj +848 0 obj +<< +/Type /XObject +/Subtype /Image +/BitsPerComponent 8 +/Width 662 +/Height 577 +/ColorSpace /DeviceRGB /Filter /DCTDecode +/Length 849 0 R +>> +stream +ÿØÿàJFIFHHÿÛC  !"$"$ÿÛCÿÀA–"ÿÄ + ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ +%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ + ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ +$4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?ú\x7@ðvw«è6sMygÊXÆîÇËRÌIÇr;äçØ‘Kþ†ßô,Çÿ‚ØƲ¾&ø¡ü +>Ĺ>ŸºŠ±N“£Â'æoXïþÐÀŸì³gWÜû›½úcñ®*•f¦ãh}& /ÂÔÃB¥Tï&ö¿v»£á'ðO‰â¸“OðõŠ›vÖkÁΎnj玘 ¿øF|7ÿBþ“ÿ€qÿ…p³÷ü{ë89áþO]©gbòx–úhc[¸dO³ÜĨþL{°ç%°0:ç뢌œà›þµ<œÃ™R†Êß’6ÿáð×ý ÚOþGþŸð‹økþ…Ý#ÿ£ÿ +Ï}Jþ;é-­ ±†â[øíÞFˆœæÛyfÁˆ#GuªWZÅØÔ4ˉc‡íCí–ŒáH…XKyŒ3¼gïŒ÷­m­Žõþ¿­ ïøF<5ÿBö‘ÿ€Qÿ…ðŒxkþ…í'ÿ£ÿ +¢uMrmn{KHdŠÙ’)d1®72ßÌ¡€Ë”+dóz$þ!™ôË‹˜‘TÅn¨è¨ÌâéÎÑ®ÓÔs‘K õ/ÿÂ1á¿ú´Ÿüü(ÿ„gÃô/é?øøV>—©.›§ÞXY‰A†H¾Î×É +ÜC€ÄÜ2)l¯/àÔµk#ws©$bå)êÄìÝœáq·wS׊vþ¾ïóÍøF|7ÿBþ“ÿ€qÿ…ðŒxoþ…í'ÿãÿ +ƒÂrÈ4[©¶ ä—'l$aÏšÜ.â>çñ«×wò[è—Œ–rÂðÂòy²îùAêT°ç‰¤ì•Ç­ì@|1á£×ÃÚOþGþ xhtðö?íÊ?ð¬éu­RÖ{ˆ'}>ᢎÕÃÃ(IJìl‚Ç äsïíS\j®úÀ·k{iVI`F)¹”r䃞9ô8§a_©oþ ÿн¤ÿàáIÿ¿†è]Ò?ð +?ð¬RúöëÂÚ—†Ym¥ŠÞ˜Ÿ¾C´±l3và/5,š­Îµ¤ÏöËao=¼ò˜#‰ÏÊ );ðXgÀÁÏð Ñÿ„_Ã?ô.éøøQÿ·†è]Ò?ð +?ð¬Ä×µ1¦‹çR › nàŠ4`ÑPB±Üw˜@^~¼XÕ5˸%š+e¶fH-]w‚Fée(sƒÓ#úÑml×åþe¿øE¼3ÿBî‘ÿ€Qÿ…ð‹xgþ…Ý#ÿ£ÿ +]Fþâµ´·¹²kÙgI#))l.~@ÙÉ…ÝÜr{óÐë7º~‡3Ùù\‹›ÉäAô(’œ¶ã"m#ûǞŧAÿ¿†¿è]Ò?ð +?ð¥ÿ„cÃ_ô/iøøU õ½D]Ý´bÈ[ZÜA•Œ² U:p,qÁÏN1“OD[Ë÷1ØÜOu¬ÍMörmŒ‚Xž6àz)#ž´%ý}ßæ+éë¯ùðŒøoþ…ý'ÿãÿ +_øF¼9ÿBþ“ÿ€qÿ…jÑE‚æWü#~ÿ •ÿ€qÿ…ðøwþ€WþÇþ«EeÿÂ9áïúéø øQÿ燿è¥ÿà$áZ”PYð߇O]J?[8ÿ›ÿφÿè_Òð?ð­j(°?ðŒøoþ…ý'ÿãÿ +?áðßý úOþÇþ­E ™_ðxsþ…ý'ÿãÿ +_øFü;ÿ@+ÿãÿ +Ô¢€2¿áðçý4¯üü)†|6zøIÿÀ8ÿµ¨¢ÀdÂ/áŸútüü)?áðÇý š?þGþ±EdÂ-áú4üü)áð×ý ÚGþGþ­Ee xptðþ“ÿ€qÿ…/ü#žÿ —ÿ€‘ÿ…jQ@ðŽøþ€Z_þGþÂ;áÿúiø øV¥—ÿ燿è¥ÿà$áGü#žÿ —ÿ€‘ÿ…jQ@ðŽx{þ€Z_þGþÂ;áÿúiø øV¥—ÿï‡ÿè¥ÿà$áGü#¾ÿ —ÿ€‘ÿ…jQ@ŸðŽøþ€Z_þGþŸðŽøþ€Z_þGþ©EeÿÂ9áïúéø øR xpõðþ’íÎ?ð­Z(#þo й£ÿàáIÿ¯†?è\Ñÿð +?þ&¶(  sá_ ž¾Ñÿð?þ&øErG€:p`Wh #Ç?hm DÒügq¦húuŒÍ¨¢4–ö©òä8Ê€q8ö¢´?i²WÀv$ ÿÄÒ?ý-¤UÑÅ^INÅÝkÂwž)ð?…ÖÊæZÚÊ<‰r sM¸Æ;ç<`à©ñÙþÍý­aäïó6o“nìc8Û×W¨xƒšâpôÕ85eäaü2ðç…­ï–òæ šåÓh‹$ òI®î˜íœœàtÇMÓÿÛÍ…¡¼òܾgL}ìg§47ó¼‰ ñHÑ$à”$ã§¡%k(+#^xŠŽ¤÷dFÖØËæ›xL›Ä›¶ î ·v}qÆ}8¦›+3œÚ[œ‡÷cç/ÿ}¾½êz¥>±¤ÛêQé“ê–1_JŽÙîepsŒ!9=nÕF!6•§³Ç:iö"æ o+[«±÷qЀ=š~½¾É„sÌÓäÆ2÷€çè9$ÔÕêŽkˆ!x’iâæ}‘+¸ÛásÔàØlö¶·¼ûheÞ†6Þ²‡ªœöö¨²t¿²5§ömŸÙœ‚Ñy ±ˆÆ2¸Ç•\¢€#·‚ h¼«xc†<“¶5 +2y'¤ 0 €AàƒE•m éö÷—­ªZÏn°5ªÀ¡‰$t9ÝӪݶ§Û*­µ…¬*½Dpª€ØÆF\qŸJ§oâo Ü^­¿ˆ4™®™ö, yH[Ð(9ϵkQÐ:•LÓRIeM>Ñ^f+T`wÇœóÏzS§iæEØÚ—YLÊÞJäHz¸8ûÜuëS4ð­Â[´Ñ¬Ò+2FX`¸É©#?QRPk}>ÂÚY¥·²¶†IÎfhâU2¼@ç©ëëL·Òt«dd·Ó,¡F •ŽPpr:Ç‘ïW*8ç‚Y%Ž9£w…‚ʪÀ”$Ž<ö"€#¸°±¹ŽXî,­¦I˜4«$JÁÈÀ‚9#¯ ¨äÒt©cŽ94Ë'Hز+@¤)=Hàš±m<70%żÑÍ Š$ƒ+Ђ8"ˆ'†áY š9U]‘Š0`NwGj¡m¢ÙǪÜj2Ao4ÒH¯4#t8EL+uþñŽ´é´ß3Q¶˜<1Û[ÈÓR3JÁbÙÆ>bqŒçœÖQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQES$fÜwŒpÄ*}ĉ· Äã±?ΟEQET6¶–ö¦S{Zi ’1$–cܓϰôÀ©¨ m--í‚Þ?-eÈÊ ÆãÔÐg¯É=I©¨¢€<«öž8ð ‰ÿ¨¤ú*Z)Ÿµ'ü“û3ÿXÿôT´VôÖ‡—‹•ª‰á…4‚:}†ßµ®WN›Z°ð¿‰µ{û4·‚mNH#‡ÍIYbåÊ‘‘œlÿëä輦h:~›y¬ùw6–±Á2}–sµÑB°ÈB ôªúÄÏ…v7iu‰5g‘3=Ö£2‚9GÊž½Ç¿Zk‰jꜵ]™Ýõº ÙÍhû¯3GWÕµ-:M^k+˜m>Ñ«[Gsw4‹@†Î3¸»G"¦X*å›dÜøZâ{¯ÙÏsyi{+'Íqk0–90HÈ`ªNHP3œ\Wü.χ_ôÿÉIÿøÝð»~Ðwÿ%.?øÝ_Ô±?óî_sìGÖèiûÅ÷£ÑëÏo.´ËøƒE¾hÿ·nî.Y-åâå™ñ¯ À/–aÉN"ÿ…Ûðëþƒ¿ù)qÿÆë þÂoúõïüjŸãSõOüû—ÜÊXÊ í¯½潩ÃâÛ#âK«{ÛXmtÕ†<ܫǗ¨ÞÀnfÊ‘·’I? Þ]iÏ”:Ì·sIâ;˜n ”C¹‹‡ +€®òªÙ?†›¤üXøa¦Ku%¿ˆnÝ:3ùÐ\HAHÖ1ó÷d±$œœÕÿø]ßè;ÿ’—ünŸÔ±?óî_sòòò­áínu÷®Í~£m|Kª¶‹uw½öËѤ\ÜÞÚù1IJáTLpÛ—l›‰ÛžÆ®ßjZΟý£k?‰!P--.ÖêïÈ·ù’:ȈŠ+ „ùw†äòOQSþwßúŸü¸ÿãt¿ð»~ÐtÿàÇÿ£êXŸù÷/¹ƒÅáÿ}ëËúù·†®Öÿ@²¼Y.eY¢ äF$aê|¿“ŸUàõVyÇü.߇_ô?øqÿÆéÆÿ‡®ºðãÿÐðX›ÿ_sÅPþu÷£CÅW·Zˆõk«I<–mмûyµÌªòàñò©fç c'#5šõÚXüž%ó4“©,]ÙɈ±;‚ù'÷€G¿n>l}ášÃÒþ*ü+Ón{jnì…¹›P¸\d@À:ã=}MiÂðøqÿAïü“¸ÿãt– oáËî}ÿ¯ëA¼]ïξõÚÃßQ¾š{ Ѫ[y‰a©‹]Fä,qº+Âf m€à6ž `]_‚u©è)r/.oq#¡žf…·•8%Z—Ѐ=ðr+‘ÿ…áðßþƒßù'qÿÆè>ÿÐ{ÿ$î?øÝ5‚įùw/¹÷ôŠ¡üëïG¤×a»'Š¥÷?ò®á¿çä~ôwôW +Ÿ<ÿwVÏý»ÍÿÄS‡ÅonÛýªsÿ^Óñ¾£ŠÿŸrû˜þ¹‡ÿŸ‹ïGqEq ñOÁŠ2u3kiþÉQ‹~'ÚŸúôŸÿÑõSÿ—rû˜}sÿ?ÞŽòŠâ#ø§à×ûº“Ÿûu›ÿˆ«1|Eð´¿rüŸ¬2æ´ž ·§/¹b¨=¦¾ôuÔW4ž6Ð\en³ÿlßÿ‰¥ohkÖàÿß§ÿâj>­[ùÜÊöô¿™}çIEríã¿/Þºaÿldÿâj6øƒá…û×à}c“ÿ‰§õZïì?¹‹ë™}èë(®=¾$øI~ö©ú£ý–“þW„?è-ýòÿüMWÔñóíýÌ_Z¡üëïGcEqÃâW„3íxsôþ&—þG„¿è+ýòÿüMSÄÏ·÷0úÕç_z; ++_ˆþcªGŸ÷_ÿ‰©—Ǿo»~§èÿÄÒxJëì?¹bh¿¶¾ôu4W,|{áÁÖøûfÿüM1¾!ø]~ö¢‹õGÿâi}V¿ò?¹‡Ö(ÿ:ûÑÖQ\¤_<1)ÄzŒmôWÿâjÚx¿Fq”¹ =•¿Â“ÃV[ÁýÌj½'´—ÞtVü%zOüöÿÇ[ü)‹t€pg?÷Ãÿñ4½…_åpýµ?æ_y¿E`èÿóÜÿßÿÄÐ<[¤‘3ß·ÿâhö•ýÁí©ÿ2ûÍú+Ÿohêpfaÿlßÿ‰¦è`dÜ×7ÿâiý^¯ò¿¹‹ÛSþe÷ÌŸhàÝÿ×)?øšiñ߇@ɼÇÖ7ÿâiýZ·ò?¹‡Ö)2û΢Šå¿á>ðßüÿ_õoÿÄÑ|;&J^Ò)?øš>«_ùÜÅõŠ_̾ôu4W0ýÙ_¬Rñ4}V·ò?¹‡Ö)2ûÑÔQ\“üDðº)f¿ÀôÊOþ& ü A#R'Ñåÿâ*–ö¦þæ'Š ¾ÚûÑÚQ\8ø«à²H©$uÞn?ñÊ?ájx3ÿj?éÚoþ"ŸÔq?óî_sÖðÿξôwWÿ oÁ8Õã®-'ÿãtƒâçÏMROüŸÿÓú†+þ}Kîä/®aÿçâûÑÞÑ\"|Xð[ýÝBsÿn7ün¦_Š#?Úïk0ÿÙ)}Gÿ>å÷1ýn‡ó¯½­ÁÍñoÀМK«í?õí7ÿPŒßÁÇöÙÿÀIÿøÝ?¨b¿çÔ¾æ/®aÿçâûÑètWžŒ¾?ó?ø ?ÿ§Œ^=5†?KIÿøÝPÅÏ©}Ïüƒë˜ùø¾ôzÀÿÂÞð63ý«'þÏÿÆé­ñ‡Àk÷µwöç?ÿ£ê¯ùõ/¹ÿ}sÿ?Þ@¢¼é¾4ü=^ºÙöé?ÿ¦ßG]tûs¸ÿãt¾£‰_òî_sÖè?¶¾ôzEæßð¼~ÿÐÿ$î?øÝ4üsøj:øƒÿ$î?øÝ/©â?çÛû˜þµCù×ÞK¢¼Ïþ¯ÃOúþÜñºQñÓá©é¯7þ\ñº_SÄÏ·÷0úÍç_z(~Ôùÿ…}aƒøšÇÿ¢¦¢¹Ž|#ã/ Z隦×71_¤ì¿g–< ŽE'.€uaÞŠµNTÕ¦¬üÏ38Î¥âîÔbIu;§,FéœÿãÆ’;›þZÜû%£ÜÈÌàäŸÎ®CcgŒî_οC ã1ºè¿#æk):’·vscLˆÿËOÖ™.œ‹ÒOֺ߱Z|cëUæ°µ¥?ìûls W—O·ì®+\^ ÿ–iúT2ßGŸõ+ùT©K±MDÊþʆw8§b¡îÇ𭺱˜€Í\ à_ΉM®€¢ŸShHzÇŸÀS†üûgò®ª(í¸Ê¯ý÷Sˆ-["ÿßf±uíÐÑQó8ã¡F’~¨%Ñ™OËmp>€W G§Ú¸åGýöií¢Ù°êGý´?áSõ¨­Ñ_Wofy¯Ø&CÄW#þSÃm0.Gý³®Þ}ávö×ÿ­PÇ¢àñ3ßßþµj±P¶†o#›†)º˜}b5zÞÙØ€_?XÍté!zÌß÷óÿ­W`³HÇÇë%eEüÍiÛH‡ª¯ækך5…(³= Æ?t*³’‰÷­”ýS5¼Œ˜èâhiâŸÆ¹Ýy³uFæn´kw96Ñÿߪ͟ù8‰évfKV?2øÓÖ=ºÅWTã܇‡„Ž?  oáðþi<=1ò~Gü+±û6™ÞQm¤Ž±8úo7Ü+±ÅÍá¢ãä‘Aÿz¡Â÷ªr·QÆ»ym4Â>U”÷øÕ›{$Q/ýöj£‹›Óô&Xh/øs&ÓEÔbë4 =ëJ+;Ôêà?CŠË¼¸†v™ï£TΰÝy‡âjœ*O_ОhCC¨Š À´@}V¥¬E†:äl5IÞÉøšèôëæ e‰®ZÔæŽšS‹6­ô£qÂAº®I*sdI?í +M/SxˆØ?oCâ+•\öMyujW‹÷OBœ)I{Ç-sà†Á¥–…aj>µ|—ÒÙ}ÆzXñÍÁ·‘ÿ +|—¿j\Y;a¸_a ª«ðþÔ71Ý~ +Ø®´å–_0þÇÿZªf¸lnÿÇ zÍjÛâ8¥—S¾Çéþ‡pÅxO§Zé´ßʘ)g?ü q]¾ÙðJ>¾]mI¨yIò¡ÏÐ×|Ò¼“:èåôR»8dðUÒ¨ÿEϱÅAsà‰œaô²sè×a>¿27 +£êøU‹mæ Iq»ü+ŸëX¥©·ÕðïCÍgðB[|çO’?}”°éñÛ‘¥z¥äÑ\Û2oÛŸT$*áu[q ìªêÜöÈ­èã*UÒfUp°§¬Lr§<>µKQ¼KXó!ϵ^ºtE;Ž?À½Ó¡¿˜µJ0zÅwRI»ËcŽ£i{¦Åž£0¼ÑJÝ*@5·gj ˜I [ FFG¨ìjO ÞC¥Ø›caoqÜ;š·ÛÅùEœJã¡øW%z“æ´#§©ÓFœmy=} ~ÞÙ#†[idÝÿ-"dÚGÓÚ¸ÿËå^ÙÏ MöBqp¡9úâ»cÅŸk¹'µŽ)b|ƒÙ½Žk*ÿÄrÍ­G~–ÖÂhøX™~Vü+l7µ¹£ß©•g+Ùþ)w1M~æ6Gœ;²}ªIt«KýKt²Ü­¼iÂ.G>¦µá'»‹Äo¨­•¤w6ˆ¶åzô5©£jwßOzÐÃæÌ>l¨ gÒºçV¤i[Nÿð?š4á'fúöþ¾ã”.˜÷[Sí[}ÎoAogoDR•{û1%‘î¤wËsÒ¨_Æ#S¶bè6Ô:Î¥•ËT½ž¶%imq´oü*…Ê»m-Áo~k•Õ¼I¨Y]yb$1ç#ʵ´-u®°w"ŸjßêÓ„yŒUxN\¥Kí;Ä™w‰#ÃzŽ•ÎÝXx¨nËßÿô+»‰|†+;tí\V­©jBFŠ;Écà⺰Õ'-,Žzôáņ¶ñQˆ´ÓŸÀR[Ùx¦g lÀÔZÚLW׎>Ѭ\a]†—¥$@3]Ï/¹jÖ¶'Ùn—ÜÌéÐöþóÒ´eÔˆ£O^•«¯ÙùT~®[*¯ÔÕ BÈA ^{ĺSµPPZö«ª¤Q¶Ò7Ò¹;ýMÝÉK`?ÞzÝ×m²fÅpú„,§÷’ç?Þ¯S N ~"¤“,½´÷Gxˆ¦Mié>iðd¶vLVN—:BãkOÿ}×Ki­a&?ð1þ½gQ+DÆ’ƒw‘µ§øb(À?`‹ñ­TБS‹H—èsGÆoìÒÿ]úÔÂ~;ÚÈ?í¥yÒ£Š–§tjáâm^说íP>‚¹ÝOD›ˆóK?ŽZNð1YW>(ž\€÷ÅoFŽ";˜Õ«B[¦‘x¤•„cÚ¹ÛÍ6ôû¶ÕI{=ÑÁšUÏûB¡}>INMܧñ®ÙFëß9S³÷NJ=.øœ˜Ûr-"ënLÓÛèňÝw7çZhÈ«µMùÖV§KÔ‘ÄÿdÝþ¤þTÖÒîGX˜WvÚ\j?×ÉùÕ»EAòÈù÷5Qpdµ4rÖV²ÛÌ]Ô€WÑZ7êQAgÏ8äÑ_%E,S·dz˜)^–¤Ò_ÙÇy*´Y`äާ5b-ZÈõ'?JľfþиÂõ­üÍ:6“(¯­Ã%*Q¿eù]vãRVîͧÕìñþ©¿*¬ú¡?êOåY®ÒãÍ&zV®*&i¶m.§iÿµÍ¬·¤Ž?ž9îºyùÒöo£:êåÓ!<–jJ€÷jÈK‹ÁÖgÿ¾©{¢OïÛó£ÙÏù‡ÏÆÊi0K=Z†ÆÝ8ÜõÍù·GþZ¿ëOÝrL’~F¥Ó“Þ@ªEt:Ô·´AËÉNQj<Ù+‹–Yÿç´ƒóª­,¹æi*õ‘jºìzDS@ƒ‰þu!Ô!Q÷Ÿó5çvóIÆe”þuz9I-!¬Þw-b_c¯ŸS‡òÓþú?ãU×S‡wñÿßgük—žCŽ ÅWVù»ÕG ñç}i©Ûž þ.Æ´¢¼—€§þ\6žÊÈÍoÙH¸ÿV¦¹jÐHé¥Y³jIC"CõsY÷“²Ãõ25L®vñ gñ¨fÞs‹h?¬b¬k'q‘Á¸çì¶ß÷õ«FÒßýŨÿ¶YñÇ1<[Z©5~Þ+ž?wf¿4Mù„‘tÇ…ÿWh?àmT.¢^ÿböѿƭ47Du·H³U¥³¹c––!ô€VPÓ©¤—ÛU‰HË[ÀY¿Æµ-åGOÓ5’-¦ŒäÜHÔTé$©É›?€§8óu]ºëˆ\ýšn¤'‹Yà?ƳEäÀ}ïÒ·Î;þ•—²4öˆÔ\ÅœŸ§øÕ;Ó~ÊvY7âGøÕgÖ&Aæ™ý§$f#êÔãNIÞÂu"ô¹Bþ×Q”ô|~"²%ÒïÃn1ÿÒ5ÉqÍÂ~.*¤ì­Öîÿ®ºu$´9§N,Ë·Äy‹ÓÑ…lÙê¢03?TXmä8kØ¿ š³™fÀÄÀÃÿ¯EG |A%ðš±xbýŸø,Þ61 }‘üÿ­Y­¤Ù‘ÿ!$•V—FÓ Ãj‘°T°íê¿3gR²Z?ÈÚƒÇLÌ1fïçÿZ·,-@Éói·„¿¹Z̽ø²±eJ[‡SOÓ~)MrpÆù?Ý5Úðø®_ᣕVÃó|g]›Ê%´ûÎ?é’Öˆ’ñ¢ó Òï ÇxÀ«ðøëtcu’î?íÿõ©º‡"Ž%ŸÏÜ–ãò®Jp¯ß“ñ:g:2¹2Öl¼M$ê‘t±±ëÀþµoO´ÔmcÄšUïÊ2ÇçZ>)ø© +D¢kfŒäy?JæÛã8q–²Ü{q÷~ƒ ¯rÅÔ‚ýÚûÏ&RÃBo÷Œëì–ííšs§\¤kÕ™8­Òu+‹?ì"C +æ´‰«}l-ÙD®s¾V,ã>ƒµvöþ1o²A +@I\‘Ÿ%«ƒ E7nK”gB¢øŽcÄÞÔ¦³ wnèò±2°É?…q7žñUާ›yjßi‘÷[Ì’=¯Tñ/ŠÅÁƒË„Ä!mû³’O¥r>,ñ½ÍLj,/Æ9"¶•çœèÁÖÄÙ.U×þ†*ž÷æ} Ù4oÈì²— æD2Äxå[šn•¯Ixm­­<¹bæHäÁÇãU"ñÅôž+‡SŽÎÜD"£9àã·á]™â›…ÖæÔÍN¸ÆOJuåˆQÖ+oÇï +Q Þ’{þ[äñ¶”Gj¥¡?ÉÀú×™ëž+½±¼0ê[œ£‘^½7‰®’¸ž(Ý.ù¹ÈÍxo´ËÛù.-•XÙë[e©JMUŠF8öãé¶ÍÄM;_µWб¸4ý#DžÒë÷y+éÅyχ5+ÝUXn¡xÔœÙÅ{w‡®à¼¶I”‘šìĹѻ¬YËAF«×qé§]MnÅa.r}+’Ö¼;zîÎn\ö#"½*+Æ·‚HѬƒÂ¹ýNîhÕ‚,paëÔRÐí¯F:œ]…µý‹2Æá×Õp­t6:¬ˆB5…ïýò?Ƴ®µËÈIVµŒúM2Ï_Ûæ‚!ø×uH΢»Š9!(ÁÙ3¬‚ù¤_– €ÿij+Õ¹–"c±U´ÝFGSº$ôj¸×R,dlÀâã-Ö¤¤·8iºÌŠÞ\2zcÅ\è:ñ”î´þUêZ¦§,HsqïŠÃ:üÛÈòSõ¯Z…jª6IujTù®Û9}/Ãú¶ïšÍýóZË ê[xµlWE§jòÈ0cŒgÞ´Eü¾YÂDsêqJ¦*­öA =;nyýíȳr>¢²&еµ?ñå-z5î©rˆ@µFÍXw!æ²ÇКÞzÒ[#)Ñ¥»9Xô=dõ²—ô©ÓAÕq“e'é]^'ÀæÝÿzœ|NäóùÖžÚºû${:=Ì(4ËØ¾i,%#ØU‘˜Í§Ý~ +?Æ­Ëâa°$~dVe׉ãÈÿÇÍ?ÞË∿w™zÈÃsav?à#üjò_C€~Ét>©ÿ×®e|J3þ§ÿ©G‰~\¿ñê—I¾Ÿ‰J¢]vkèˆ8†à}c¬ë©ÙÉÛÇþTO‰_ê¿ZhñùcúÓ'„Êiõ+ë^`¶VxYxäŽø4Rë“_Ù$F=˜6sìGõ¢¾W9OëNý‘èáéèfÞ; Bàó[ùš–&— ª÷¥†£q‚Gï[ùš|bLpÍ_]„¹¢ü3¿{/VK)œŽUv[‚~åLáñ˽BrW5»1D‘CrOÜzÞÚsŒ¬cêj„mácÿ©ã“òË?V£Ð™¢m$Ç"!øÔf:´#òª¯;v‰j#<½£AøR³Ñ "æXJ± +Æ:Ëùü+Í?`£ð©[œýì})8¶ ¤o+~2i厒/åY®YÖ}j)#œõ”Ôû?2¹Ís*̪? +Š[´UâaùV1‰³Ë1¤hØÕrX\Å»›´9ýë~UA§Bßë’Dp>î*¸M)I¡¤™¡± gÍ5if‹rOûê³!>çðv&U!\uD=I8ì‡ñ5LÄ𤸘c„ÅV »J’ 6oiï!#“ùWCe¼÷ã\䀌t­ë+¹kž´ÕR’[,"B½ÿC£gœƳRâM½ê ®ˆêq\J“lëçI°„eúV­«)­q¶×7ßýknÆí03 üë*´š.DtXéPN裢Õt¼·ÛóJ* ‹Û?ï“ô®eMÜèsVIT“÷*ŒÊOr*ulÇ#wëJ³À:íR+et2æÜÿz ”¶>\“ùÔísjLŠ>•ZmCOzp*¸§Ø–×r»ïÏ9…1ƒ ÓÛTÓÇÝ‘ÏÓŠ§>¥lÇå [F2ìdåå謚UÉu^)’éð/ú˰+1ïKd&à W’fôÇÖ´Tç}Èscr}.6®ýÿ +»údcåß¿ýzæ!”–å¿*¹¯ñsS:]ÙQ©Ù7×0¸ÊF}kúr *¿•h» ™ +sëY×K#,y?](¤EFÙ ¥Ü†AÕÓé’ÌÀd‘õ5ÎXÙÝÉߊéôÈ6íýàcíÍ,K´#zÆ Ÿë¢Ñôëæ%AîÆ±lî%á[%¹²]¶¥WÜŽkïíZ÷^³_ÓÇàk'-y@+/Uð¥"ádŽPzá±D4Õ07JõZeçõ0„èµÁãc-Ñ×'…qÙœü¿ o¼ð~̹=óšÔÓ~j¸jêÃ¥dj>8Ôƒaîflú6?Oñ¶¬î¨·rŸNàWt–>QÕ£’/¥¢gooàk„Œnºˆ0ì?­UÔ|~ß꤅Æ9$‘PYx·W1a¥VcÜ®M.£ãD[ì*åG5ç¨ã·Gkxg™Äx§áÝñ9”ćþ‚¹eø[|nùr1ü+¥ñõ(ò¶æI\žX’q\Í׌5Ä\D’',ÝÍ}뼉]-ªs^ÌÚðçË»Džñ§`±¶Só} z=‡…®­´%¼vÎ6F98=ɯ-ÑüU­\*[ˆ™Sv\dàWyi¯j³ØÃjda}â¸ñÑÅ6¹¤¿àXIaÒ÷S55ÿ\YZ[»ºÉ,Ͱ( ®SÅþ–ÏTÓì!’äv\Ö—‰b{š×C«µ·âg†­A½ßð:I´[¹­îÙUUí²MxçŒuÿ°Þ”1aãs^§6¯~4ªÍ™Ô‡ç®kÄ~"YÞM©¼ÞSn†¯,§.gÏò'5ʹM;xtÿÙo„ª\/Æ>â¶¼£¥ÝK‡pU5åþ:žŸ¨¥Åª¸u==G¡õ¯rðÍìz¥’<Ñyscæ_C]˜§8S³^ëü\:ŒçtõüÎŽ+{‰íÚE9U‘Xz¥…Ü‘1I‚Ÿ¥kcŒ„b8ìz×?ªÝKp¬Wñ⼚*\ÚV¹u9ýODÕH êIëÆ*´.®²¯ïŽù4³êש½NG¦ƒLÓõk¢äH¬ éƒþµzëÚ¨ô<Æé¹u:]*ÏPAó€~‚´ÞÞíâ$6Ò³t‹»’¸qŠÒy¥(sÇã^}Nnn‡u>^S WÓõ #;ê+™›GԌÅ®—Wº¸[i?sêwBB¿0>Æ»ðþÒÚXâ¯É}njiÚ^¢N1éÍjÇe}°“/OjÉÒu ²¸''ØÖ²Ý\9Ï>ù¬êóß[Sä·Rí…ñNÔVLúmùn‘ŸÆ´onnväk{˰qó©­©)ùTq,E¥]7 +þt¯¡3©Ý>•½õÈ\e‡ãOkÛ½§ßhý¥÷3^ÎÛ§ðöW‚ËY—>|ü³Ê´§Ôu„,œûÖM橨 † +kx{W»2Ÿ³] +çÃw[¸‘Mç5onÜe?J´À*àÒ¶™!_âQôNèÀ:œÐªst…Œ;©d5H»ç„­yR&<LH!êOéZ=IZ­ä¸m\¥k[I|@Ã7áR[En1ÏéZÖ«~Uœæ’ظÆìÎv¿ÇÞoΨ]-ù'—®½"ŒŽü±PËd$?*gð¬£].†Ž‹}NB$½'¤üëZÊ ã¿øšßµÑÙˆ%HJÛ³ÒUÈZΦ.)YO &Înkݼnü)—6ºÝEaà(’ν+“ëŠû?UÓsͤ·ÔÇñ6>µýº1óJÃñ®òòµ*Á¿ˆ;Yú×U€ÕË/ F>iç϶k¥â)Åjsª3“0íÓŒ“Wb‚I>älß…uvš-¤(0 ÿÀjêG}Ð=1\“ŧ²:£†}YÈ.ŸvÝ!jwö=ëýà¨=I®ªîêÝv–>Õu¬21òàüÅLkT–Èr¥îÈm40¸2È[ØV¤VÑÇ´F£Ü¶kõ;ÉÛ!XöEY‡í’ +¿?ŒßÄ áEÒl ÎòÕ+ëÄuźl b¦þʹ˜ÿ«lûÖÆ™áÁ´Ž=sY¹Ó§«fŠž‰”k>v3WC¥GpTe +þÓA¦XÛŒ¬;©¨ïåò¢8UAùVÅ*šEÃÉ«fTò20<ñÔž*xw`8ú +Å×utBC=aC®æpªxÍtÓÃJJæÄ(»›§9tçޮʹ¼`1\¦‘ª–ˆc¯¿JÜÞí@åé\5i8Èë§QI²ÂÒm>ýªÎ‡n(èq[ ¤,ŒUɽ+FÞÍ" )â"£Ê‡/šì[dÄc'õ_Px–‘€¦»}‹€s\g‰e’LÇæ`ž¾Õ• +^Ò[šU©ÉÝÕþ•¼Œ)õ>µQ®ô¦$…Zåå²v <úŠ…¬˜üªçhëÁæ½xá —Äy²¯'Ðï´›7p…äæº« mŠà.x¯-ЭŠÎ1$žµèZLAcÓ¼ìe(Åîváj9-‹:”–ËÀt5Äë·_Ú°è¹9®›X„ÉŽì1^eâKSöâwdv­p4£'¹ž2£ŠØ×‚÷IQ’Š ÷÷×è·Ö.€!y–MåðÄqÅtŸa +îAé]¸Œ$e ¦rÐĵ+4zéx$‡ t®WÄËiä³I}Ej鬶êCv椿ÓbºŒ‚ æ¼zmRž§§4êGCÏì³äœmŒÏç]®Žm•*ãß½g/†ãŽmʘçÒ´c´6ñäŒ{×Uz°¨´g=r†èÒ¸¸£+»?ιÝTC,L†F ÙäTZÅÐK#ía޹˽R]¥¦F ýà84ðøwºjëfeëMsbå°Î™zUm3]€HEeþUnmJ "d,¬­ØÖÙ¡ó‹Fx';{Šõá%i#Ì”¬î™éš§o$`£qéšØ}B˜$~uÀø~db¦ºT¿yÉõæÖ¡3¾•ir‘ëZ®Ã–Ûü«½Ôa’¬>µ{^·X¬„{W}V<×uq„.µ9*ÍÎVgi¤kn±õÍtÖúŒL£ŠòKÂH>r vÞ»GUÝ ÍMZQšæC§RQ|¬èo.aqÜVTÅ Èéõ®ŽÒi“æU?…-Ö‡i"’´×,jÆÌé•9I]œ“¬c±üj»_Eî¿iêz$±“±ƒzçŒÊGá]Ô¹'Ôã©Ï„ò^DGßæ²ï.Q˜ô?Ep˜&²îKÃVÎÔõFJó. vyLêÕ‹É»­[Ì#9©[ô*Tì_x”ýÖDÑ?÷MV/ £í¨êUΉådÓHÁ*zÑQ§qµùh¯Îšx§nÈôðºSÔ±¨åu‘ž“?ó5•ÇCSê RìÓ8ÿÇVÅ}VøQô_‘Å_ø’õcþÓ/­#\JŽ™ƒéIƒé[]™Y;ž¬M2Ÿƒèi6ŸCR10èië;ŽôÌCI´ú5 ÝG"¯[Þ°çp‹µ½åK™MÕ\ÝÅËØéÓQ|ÒR>­6k˜&_ö©¥\öjŸw°õît’kh:b«É¯Ê+ ktþTmoîŸÊ—¢¼Íf×g'å¤]bíº>µ•µýò­«oøÂæÞ+›o k³C*ŽHôùY]HÈ`Bà‚9ÍDªFH¸Órøuu §3ô"9~]²}êTðWŽ³Ç„µÿÇN—ÿ‰©ÓÁ~8{ÂÚïþ ¦ÿâiÇGù—Þ‰xz½ŸâB»ê?*pží5/ü!Þ4ó)ø…¿î7ÿQ¿„¶2ÿñ5z? xÉF?áÖ?ð_þ&±*ξôk•¿•#ëQ€vÖªK­†šËO +xÀ.[Ãú¿þJOþƒNÞ)^ÃZëúð—ÿ‰¬Õ: i/¼·:Ï쿸š]QØgÉϱ4‹¨]dµROLëK‹â¨ÇÖõþÏ”Ÿý ¸Òü[Ûž"‘½´é@ÿÐj׳î¾òyÙýÅ´º¹gùÖ5üsúU¸n&Ç“øb°?³¼v"ðŽ¸Ÿ÷”ÿì´ŸØß$¼ðö¼ýxKü‚ÐéÁý¨ýâSšû/î:)ï™.Q}‡&³noÁ!¾¼UKxÕÆ‡5Þïe"ý5£„ü\æÑ50Oai'øTÚŒ>ÒûʽYý—÷#šêRBÆ?*ZܶI‡?ZÖ_ ø²øÐõ?ø œ„ÿ*göW‹m>Ö›þÜdÇè´ý´>Ì—Þ/g.©ýÃ, •T~è`+bÚ9nQWéT#Ó¼\‹†ðæ°=–ÂSÿ²âž`ñtcø[['ÔØJöZÂmKí/¼ÚïG÷°å@=ÍH×I%Ø¥s ãTRO…µæ=‚iòŸý–°5þ"L +ÃáÆq¦ÍŸÏmf°ñ{Í/™n´–ÑqÖë(‚Æä*Ðɯ=ñާ¹ÊB¡Aüj•ß…<vÇÎð¯ˆÎ}té¿øš}ŸÃ_ÜrÞÕ¡ôÒÎAÿ²×e(á髦›õ9ªJ¼÷Oî9‹ÍBææBÒ9§ZJÀ‚8÷5ÚŸ†~'0žÕe~íö)1øqTÿáñŸžx[Z<õû ~{kª5©ïξóžT§·+û‰¼5s+º¨Ø×we«ÙÙ¨ÌÞ²,|â¨lBÿbjbNÿè’?Jsø'ÅAUWEÕI?y¬Ÿá\Õ燪õšûÍ©Bµ5¤YÐÂQž\ TðøeFe!c_¼ç€+ +ÏÀ¾#yƒO¤êKõf|·éZ3øS_tùômH@Ÿêá[WçÜñ\rŽ;)#ª2Ä=Z#ÔüMp™3¶3À'«}+›oG<˜)$ðÎ*mOÁ¾-ºÝ#h¯qEœœÊ­i>ñ¢ÜM¡jO9û¨-\ãÜñ]Pú­8ß™_Ôç—Ö'/…ÛЄ]#¯ÞÿÂ5;„UÿV£µÐi^ Ö!ÍÌúUûLݾÌü~•ZçÂÞ!žÿ`Ñu%ˆ –6¯ƒôâ±úÅ줾ó_aQ+´gir">âª?¥tÚ‚¢î$ +̇ž"iæÿ‰.¦‘¯ÝÍ«Œý8¦¯†Ÿv±“áÇŒO…õÍñÓåçÿ®ÿkO•(É[Õ~Î¥ÛiýÅZ_ô›'2DÜàV?öƒ+ulÌW[š|¼ãµS­’_z&4¥Ö/î3´ïÍnÀî$z×Emâõ’ #þÁ³ñ4ßøVþ3ÁÏ„ +ñá>ñÿ¸dßüMmEì×Þc*¥½þâ…æ£»9¬{»õç-]¾ñÓù¼Eÿ‚É¿øš©7Ã9ÉðwˆÿðY7ÿYUÅ©m%÷šSÃ5ºg15üªs曹uÃ]øgã|ñàÿþ:dßüM4ü5ñÁÈ> ñþ &?û-r:í;©~'J¢š³àeCâ5³¹ÿÇU«§ü„î¿ë³ÿèF«×ÙaÿƒEùmâKÕ…Q[Q@Q@Q@Q@Q@}¯ðãþIç†ÿìkÿ¢V¾(¯µþÉ<ðßý‚môJ×Íq7ð¡ê{Ùñ'èUñ_‹Î—ªE¡èúEλ­Ëœ- uc8Ý$ÂzuþTžñ‰/5$²×¼y£y¡Œs¥äWQ áÙ0W=¸æ±µl|)ñWZ—Ä%®·»Ù^LvÄLHUã.xS“»ž9üéhzþ¦~%iÚt?¬ ‡^K=icðì“yŒ¥â•ÁˆÃ¸Iù‡~”GT¿®þŸ0—ºßõÕ/ÔôÝ>úËQ´K½>òÞîÝþì°HèG«Økº&¡{%•†±§]ÝEŸ2nQÝ0pr äs^_ªÙ˦ø{â^›áØÒ(§…ã‚*‘«C—h^@+»øW?¤G»TÐ&µ¿øWdÐß@b}"IVñÁ`¥1‚͸qßœu¢>óKÓñþ¾`ôýÛïuíÈJou:ØC ŠS5Ò&Ç ­“ÁÁ±¨ï|IáÛß±^ëúUµ×Éšò4~z|¤çšãü7á½WñÏŒo5m"ËPš=B8ÐÝD%¿gŒð­{ã5Èø±´ÿëÚû_ëðÙ²¹{QÖ“ ÅõÀEù˜'#vƒÇ¸¥}¥ÿ/ó·õ±ê¾&Ö®tÝSÃöÖÉÇ©ßýžVpI å;åpG9Q×qÕ†5K°{NÿúªÕoZÿÍïý|Iÿ¡©_£aÿ…Eù;[ø’õaEV¦AEPEPEPEPEP_k|7?ño|7ÿ`›_ýµñM}™à»O·|/Ð-~Ósm¿I´ýí¼›$\F‡ƒÛ¦>†¾o‰té§Ü÷²/âOÐèïì¬õ Vµ¿´‚îûÑMt?Px¨t­#IÒchô­.ÊÁå–Úˆ¨P+þOú™|GÿßýðŠÔÉâ?üÿìkåý•ùùø3é/.Ʀ£ hZ•Ú]ê:.›yp˜ ,ö©#®:aˆ$UÃihnã»6°ˆã1¤¾XÞ¨pJƒÔǰ®þOú™|GÿßýðŠÔËâ?üÿìhöTü¼ü^]Ž‚'žxm¡Š[† 3¢Ò0 Ô€1Ïj§máýÛQmFÛDÓ!½bI¸ŽÕROS¸ Ö_ü"Ÿõ2øÿ¿û?áÿ©—ÄøÿØÑì¨oí?—c ‚ÖÖÞiæ‚Ú¤¸`ó: V‘€#©À'°ª×.q©&§q¤ØM}Â\½º4ª=˜ŒŽ§½dÂ)ÿS/ˆÿð;ÿ±£þOú™|GÿßýʇüüüsK±¶šfš‘ZÄš}¢ÇfwZ¨…@€àŒ ÇËÁ#ŽÄռпáÿ©—ÄøÿØÑÿ§ýL¾#ÿÀïþÆeGþ~~ /.ÇK‘FEs_ðŠÔËâ?üÿìhÿ„Sþ¦_ÿàwÿcG²¡ÿ??—c¥È£"¹¯øE?êeñþö4Â)ÿS/ˆÿð;ÿ±£ÙPÿŸŸƒ ˱ÒäQ‘\×ü"Ÿõ2øÿ¿û?áÿ©—ÄøÿØÑì¨ÏÏÁ…åØér(È®kþOú™|GÿßýðŠÔËâ?üÿìhöT?ççàÂòìt¹dW5ÿ§ýL¾#ÿÀïþÆøE?êeñþö4{*óóðayv:\Š2+šÿ„Sþ¦_ÿàwÿcGü"Ÿõ2øÿ¿û=•ùùø0¼».EÍÂ)ÿS/ˆÿð;ÿ±£þOú™|Gÿßýʇüüü^]Ž—"ŒŠæ¿áÿ©—ÄøÿØÑÿ§ýL¾#ÿÀïþÆeCþ~~ /.ÇK‘FEs_ðŠÔËâ?üÿìhÿ„Sþ¦_ÿàwÿcG²¡ÿ??—c¥È£"¹¯øE?êeñþö4Â)ÿS/ˆÿð;ÿ±£ÙPÿŸŸƒ ˱ÒäQ‘\×ü"Ÿõ2øÿ¿û?áÿ©—ÄøÿØÑì¨ÏÏÁ…åØér(È®kþOú™|GÿßýðŠÔËâ?üÿìhöT?ççàÂòìt¹dW5ÿ§ýL¾#ÿÀïþÆøE?êeñþö4{*óóðayv:\Š2+šÿ„Sþ¦_ÿàwÿcGü"Ÿõ2øÿ¿û=•ùùø0¼».EÍÂ)ÿS/ˆÿð;ÿ±£þOú™|Gÿßýʇüüü^]Ž—"ŒŠæ¿áÿ©—ÄøÿØÑÿ§ýL¾#ÿÀïþÆeCþ~~ /.ÇK‘FEs_ðŠÔËâ?üÿìhÿ„Sþ¦_ÿàwÿcG²¡ÿ??—c¥È£"¹¯øE?êeñþö4Â)ÿS/ˆÿð;ÿ±£ÙPÿŸŸƒ ˱ÒäQ‘\×ü"Ÿõ2øÿ¿û?áÿ©—ÄøÿØÑì¨ÏÏÁ…åØér(È®kþOú™|GÿßýðŠÔËâ?üÿìhöT?ççàÂòìt¹dW5ÿ§ýL¾#ÿÀïþÆøE?êeñþö4{*óóðayv:\Š2+šÿ„Sþ¦_ÿàwÿcGü"Ÿõ2øÿ¿û=•ùùø0¼».EÍÂ)ÿS/ˆÿð;ÿ±£þOú™|Gÿßýʇüüü^]Ž—"ŒŠæ¿áÿ©—ÄøÿØÑÿ§ýL¾#ÿÀïþÆeCþ~~ /.ÇK‘FEs_ðŠÔËâ?üÿìhÿ„Sþ¦_ÿàwÿcG²¡ÿ??—c¥È£"¹¯øE?êeñþö4Â)ÿS/ˆÿð;ÿ±£ÙPÿŸŸƒ ˱ÑÑ\çü"Ÿõ2øÿ¿û?áÿ©—ÄøÿØÑì¨ÏÏÁ…åØèè®sþOú™|GÿßýYÓ±WùŸÞÆŸò¯¸Àÿ„+Á¿ô)hø.‡ÿ‰£þ¯ÿÐ¥ àºþ&·è£ë™ýáìiÿ*ûŒøB¼ÿB–ÿ‚èøš?á +ðoý +Zþ ¡ÿâk~Š>±WùŸÞÆŸò¯¸Àÿ„+Á¿ô)hø.‡ÿ‰£þ¯ÿÐ¥ àºþ&ŸâÏÛèÒ§ß꺅ô†;; C4ÅFæ9vXÑUy,ì«Ðgs(-Ó¼Ohwš¶¿§^xV&"äk2Apó$r„(¢Š(¢Š(¢Šã¼oa«Ûø›Fñn¥É¬Iaosesc ÑG3Ã9‰·Äe*…Õ¡O•RÜä#ë^K½GPñ"ͧëë¨XÛJt¡©›e·Ù³äCf\JÍ"ïÏrÈØ+ìôP®—õ¦·Óçù²œ­ýmoÔñíÁÚÜ÷º£{¦ë’2ø¬ê·¿Û“ií:¨°xV]¶€D>,»›?1ÆNø'Å:Ž»©iæþÔ/Š`ÕíÒÂK_>î$°Žc¡$P1õ_•‡°ÑTäúV·ÿ"ƒ›O•¿?ógh~Öç½ÐµÝ7\‘—ÅgU½þÜ›OiÕEƒÂ²í´!óù`ÜÙùŽ2pÏZOÄ_Ûø@Óíu·Ó®ì^-9tÆÓÒmÑr·mu™Ã™7ä¨P¥>lî+ì”QÎîŸoø ô&š}à·úœŸ´}GMñŒ.ïmü¨uR)íz·™ÙÛÆN$|èãŒôÅu”QI»Ûä¾åbLËŸùl?ëÆçÿC‚´ë2çþF›úñ¹ÿÐà­:@QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQErñ;ÀhìâKUe8e(àƒé÷kkÃ~#Ñ|G³è—Ë{,Ý‚†#8É'‡LQX?äØÿ×Åßþ•K]bÇäŸõÍ?›P´W–kÚ„uoŒ>'Ô|Y§i’E¦x[Jš-Bè,riãí›<ÑOÃ[°ØÌFR¥ +‚9ý'Æž8M_Â:?öf‹‰u­DMRóS²x®Ym5i¥ó=¤ùRZnXpƒ/*n~ô÷:+Ã<'ã]VëâÅëÜ[ÙZÉsma¤_j.öD{mSX¶ùP1d{–‹+¶Äg +d‘ÄqÏ>£ñ3â/®^é^†}9%Ö,t•‘"Ý5Õ’]ØVìÍrÒIhÃÈ[hØbˆ·Hí”W“xçÄßð”üøµyk5•Þo¦ßÛé7Öm¾+È™¼‹ %dÄïð7‚¥–[M Ziî­¯óP´„\\"Ek– »XŸ=þdí”WœèÞ3×î¼E¦OpºaÑuj: ½¤vî·6ÏiöÌÎó™ +ȯöý؉ +ùËó¶Ã¿Oáçüßÿìd‡ÿM:uvtWÎ~ñ÷Œ“ÂKs¢iÖW3kz–•e¥i–¶€Å¦nðõµìË R\†! ’-…÷HHCíŸ5O]ð•®¡­YCe¨ù³ÛÜÃÑȪðÌñ|¹$Tc³&1#˜É(YŠ’@: +(¢€ +(¢€ +ŠîâKY®®d0£I#`œ('ž•-fx³þEm[þ¼fÿÐ `ÿÂÐðý ÖŸ÷Ëÿñ5Ñh:Λ®éãPÒn…Õ«1U•U‚±q3é‘ß>•Cá×ü“ïØ*×ÿE-lÁþ¶ãþºýhZ+ÃÍ Oí¾g äò²y†2¬©Úÿ„£ÅW?µŸxfÓÃ:~û›©.5 ›9dÜYèì²:$‰ç¹ûcE‚Ñá3¸ù{$õš+Äþ +øâëÄ,Ô®…Œ:M§ˆ¯­u2× e»èZtŸc†Ñæ¨&Fg”ŒìGýëA‡¾+øîëH²×µo ÙiúN©mgª[ËqäGök»´K†;.ä’dŽÞå¤k†ŽÝcò•1&Ô÷:+È> êW^.ø!ö»­/L¿[ßÙAkm6VÒþÔkÑGlÌÄI˜¦…bbáYYdܪTPGà +ÍñÂ:6·ðëÁ–P[»—J³´ŠæÉ'ûN˜‚UÝ aœÇ€XÆÉ\2@=šŠò jîê÷öWñ´÷73]Åý‘¯Çcq,†FšÉé-$™U­Ö’Æ@C–bÛÏÚg[ºÐü&±Ž»š-M`» ‰ì4mBešå »Ç;]Ç|€S¢¼šoxîË¥.‹ew£éZ•†‘©ßà·Šiî"¶v•$–ðÇmE8Q’™8u¨ÿáqüGÿ¡ÿ$­ÿøÝqºßü†o¿ëâOýÕJûª3¥éÇeÑMl^!T’S{¾¬ïáqüGÿ¡ÿ$­ÿøÝð¸þ#ÿÐÇÿ’Vÿün¸*+_¨açÔ~ägõÌGüü{;ßø\ÿècÿÉ+þ7Gü.?ˆÿô1ÿä•¿ÿ® +Š>¡…ÿŸQû}sÿ?ÞÎ÷þÄúÿòJßÿÑÿ â?ý ù%oÿÆë‚«pi·³éW:¤Pî³µ‘#šMÀmgÎÑŒäçiè;Rx"ÕÓ܆±x–ì§/½—ü.?ˆÿô1ÿä•¿ÿ£þÄúÿòJßÿ×ÐÆ,Öqu ‘œ©€Þ ó·nqÁÏÅEBÀá_üºþ¿È_[ÄÏÇ÷³½ÿ…Çñþ†?ü’·ÿãtÂãøÿCþI[ÿñºà¨§õ /üú܃ë˜ùøþöw¿ð¸þ#ÿÐÇÿ’Vÿünø\ÿècÿÉ+þ7\}C ÿ>£÷ úæ#þ~?½ïü.?ˆÿô1ÿä•¿ÿ¯¨¼ys¨ø7DÔ/$ónn´ëy¦} nvKI=+â +û_áÇü“Ï ÿØ&×ÿD­|÷áèÒ§N kÑ${Y-zµ*INMéÕ—.äi°ÿ¯Ÿý +Ӭ˟ùl?ëÆçÿC‚´ëå¢ +*–½ªXhzþ·ªOö{ >ÚK«©v3yqF¥° “…à}+3Ã~1Ðõûç±²:½ÚÄfX5-&êÂIPã[ˆÐȪYÈRé»—  ýÝ­…ÅõõÌ6¶–Ñ4ÓÏ4#‰e˜ðª$“À¦ ІöîÖÊšòæhšXáW–@Š^Gˆ þ&vU©,äÔÔQPßÝÚØXÜ__\ÃkimM<óH8‘FYÙ + I<* #T°Õ­ÌÖ3ïÙ°K£G, Ѥ%€xŸdˆÛ†@Í]¢Š(¢¡¿»µ°±¸¾¾¹†ÖÒÚ&šyæ$q"Œ³³@’xTÔQTµíRÃCÐïõ½R³ØiöÒ]]K±›ËŠ5,í…œ('éWh¢Š¥©a6¹u¢G>ëûKhn§‹c|‘LÒ¬mœ`å ”`¼ã# h¢Š(¢©hZ¥†¹¡Økz\ÿh°Ô-£ºµ—c/™Š RÖ€.ÑT´-RÃ\Ðì5½.´XjÑÝZ˱—ÌŠE †Œ©ëWh¢Š(¢Š(¢Š(¢Š(¢Š(–¥XiÖqÙØÀmíãÎØã‘€$“ש$’{’MZŠ$‹.ì°–bÝ>¿Z}ªøOº¶¹i®êžÑoõk=Ÿe¾¹±ŠKˆ61tÙ#)eÚİÁ$‘Í\—IÒ¦Õ#Õ%Ó,¤¿o—tÐ)•6¬ª¸|dag˜xÈ?ˆæí˜<= o¡™åj<7©öDÛrŽò;$ƒ:—šf ä+ž¬sKSðŽ‘=õþ¯¦C…âè–µÛ +o·”R‡a’Xœ2‘®0ÀÁŽ‚ŠÌ°Ð4k/ +ÛøZ:Ñ`±]=,ætfÝS˶üï]ƒvr:æ®ÞÚZÞ°Þ[CsËÊ’ÆCÆáÑÀ?Ä®ªÀõAŠšŠÌ·ðömâ+ŸÛèzd:ÕÔBF;D[™mP72ü‰Á8ùWÐU+ßx.÷ÄKâ;Ïx~çZYc™utØ^ä—KÒ4mNÖ/´Ÿ>VíÆ."¹Ž{dÈû@øç0} WÑõ BÛÄÚ<þ6ñ ¦«l’ÎmÃj±Þ%1€ŽÎ¦AïÙŒä¤íâ¼ÚŠæx$Ûmï~ï·mÎ…‹qI%·ŸçÝÁî{%ž¹ Γ>£{¸·‡PÙuyâ }Jm¦ÜíFt@¡wŸ•X’In1Y~×ì¯ô½ëÄÚ¼Wš„:…äi5ü¾{ÂòYÃ|±/<ð0}ëËè¨þÎ…··§Ïkß¹_^Ö—·~º-ö¾Ç¤èú†¡mâmx†ÓU¶Ig6áµXï ˜ÀGgS wìÆrRvñZ2ë º¶…,íis{n÷E&Ô §ì°ô⻳Õɪ:•§'Ù.äi°ÿ¯Ÿý +Ӭ˟ùl?ëÆçÿC‚´ëäÏ£9?Œö—Wÿ¼iccm5ÕÝχïá‚c/$®ÖîG,Ä’k˜ñÏ‚58ô¨¯‰ü[¯ê}§ØG8’;iíl¦Ô­ 謢…‚´qîrUc8* çÔè ñ¾—ã sOñ‰§ÁâkêÛ¶º„S½Êé²i²[Þ­‚Äd"È9'NÄD¿ü·«ŸfñlŸí&²Ö|Mk¦­ÎŸým&•©Oæé¢ ßhšK„¶G-ö°ÿkî†2»œÀ£Üè “KÔµÇi}Ä õÈÿ²î¼X²½âÛ‹ˆ/­&¹kBäê±Ý4cNù&ÜWñ‹ûTb6›ÿ 3m¹oÝèû†ùNÑæLíuË:}¡ZͶ:\m߉èPÏ?­)±½¶ñmեυšÁ¢G~ñ˨0º$ëgÃ)Ìsû² mÿ–µ™ãøM¿³üEýÿ Ÿü%Ÿñ=ûg•öϲgýž÷û?ì¿òíçnþÎÇÙÿ»vî|ê÷ú(Æ|M§ø‡Fñ<š[ÞøÎÿÂìz½ÔÝMw+Èš’Ìa{qç&fM- ¨TE9‘¼™óý&?ê_j5Ñe¹[K­FâÓR»»ûŸˆ8ˆŽHïYÑÍŠ²£‰Y|Áåïé?x{@ñ-ŠXøCÓ5›Hå$ö‰q¸ +à€Øfë‚}jí…¥­…½´6¶–Ñ,0A a#‰aQTpªÀ€<ÊâÇijüÒôù¯üAu6¯a—G=á±mR Ä…•ç‰E© ´’yÛiJ¾ð9™­¼ua­£xµíneÔ¢Õ7Íu4‚ÆÓZµ‚b^9[M7%ZM9ýà2JëÞh  ‹ûCí‹ý­ÿ þ÷Únÿ³¼í_í-þM“æù_éû<ßíLyß'ÜÏËäVÃ]/â¥Ïƒ­¯µimic¢Ãg§¦}$cK;Qt’È.#²‰¼Áx¬.#k…)–ò}%Ex7Ã[M_NÓ<5c­[xæÞÚÚÃ{1ÜĶѥ‚‰V/•˜ÈH6_¤Ññ¾ÝÇ—ï4Q@Q@Q@Q@Q@Q@2Ÿ|ð¶‹2xò]B=b->]Q.§S{½žÝ"V@¦@bQ´í`ÙÚ²2z×À‹{áà{mKVð»xgRÔC\ͦÉq$Ò[Æe“ÈWi¶ï$FX¸bß*¨»kðãâ×Ãé©XXê·>»–÷M¹º¶Ý%¼ò332óÓ-@)}äVtQºÊòHêÅ”•qŒgÜúÐ ªjÿõm+Kñ}îm¦hš}å½´vvÓ[Í<ÓÞ«ÃÆedż`¬rDq» ¤îšoÅÍ:UÐ.¦ÒüA=÷ˆt.êÛJ²Š)ãŠK¸/gEWù±û$ˆîäF DÇË_5‡O¯x!uOO¯ÁâiMwc…õ­„GÔ0¼Î »DÓFßéñIA0†ø /‹tÏÛ,Öré‘[Ciil;hÒÞØc@xP—óp$xÀ0?á߉Pê¿.´xEìÉ6›dm´¡ h¶¸—ö÷Ï!!ktW}ì™U—iPI§ñßÀ¶ε¥É,ÒˤÅ|ÍäÜZ¼“Ég’OÀ&óÑ€†l<±ÇáÈxËíZ|/Ð-nõÛ{ÍN;ëÉLðÝ Ͳ›íw·BXNÎ=üèCnVêÊÎÔ|%œ:‹éM«Z\Kq2xoR¼H4·’åØÜ´Ž–ï3«yÓ·—!–=ÏÂ.Ô1€?ñ||=ø‘y¡<Öº§…¬n‘g’4e `—HèC(G÷‡PÃry?Æšžv÷ÂçÇ>,ÑLQÁ8Õô(ôÛ˜ïf»¶·´ŠßÌ‚Ñ]dó¦.Nà¾R|Éœ?Y¥|>°ƒáeßµ Böùõ=5ìõ}U¤cw},e¸g¹ÞT »‹UD*€:è–ºþä“GWÖ—ªb 6ûkˆîƒò—‰Aï‚pAäciÞ<Ó¯|E–ºf§¥ÍõÆeªH±}šêîßÍó E•—ì÷3ƨ|–ÃÉ¿ÏüIâxÚÓHñ‹_TÒBÑìü>³é—tûY£Šâçì­å«Í+-qT`w ÃW iÞÓ¬¼E¨ºž§-¥µõÆ£e¥ÈÑ}šÖîãÍó§F‰™›í+ÈÈ<æÂ©³gFÑ-t­G[¾·’f—Y¾[Û!UÖÞpav@‡œœ–ç†ð¿Ä¨aðçŒ.õÑ{u7†?´õ –ŠÆû8õFcŒ ºÇbWæÆ~RX’ÄušŠ­ujz4v§ÓåhZêX†GM›Ða‹FÃÌŒ*ÆdWEæGó×3¬üÐ5-;VÓÆ³â }j+¸uE´ºHÚí'¸¹¹TfØYV)nç*¨`ÛeóWå®›Gð­®›â­CÄ+¨êw3ÞEä¬7†ŽÞÒR;®÷vQ+8ˆ;,^Z3)è(¢Š(¢Š+3ÅŸò+jßõã7þ€kN«jÖŸoÒ®ì|Ï/í<[ñ»”Œã¿Zà|ðûšƒ´]BòÊî[›> ¦í‘¹Ú5,p$ÀÉ'¥vžÒtýÎ]?L€Ãn’’¤gbJ©$³Çñ=0: +v‹¦¾“£YiV× +ðÙÛÇoIXª(PNÀôvÙ7—pÌí¸áp:ê}(ʵísÄÚtÿ<[‰/^ËÁ÷% ÐÚÞÛì—G¦ZÝHŒþWžŒ²íq&ŠŽªQ¶nþ"ÙØxÏQðÅ®•âmwVûLË­µ½¾Äòm¬$uI‘Q6ޣ_ÌPÙ1#]»ø{gu¯ê÷÷öµ&™­\¥Î¥¢³ýŠé֠ß+Î(V÷Gæì|`È̦îŸà­*ÇÇwž1Šâõ¯îüÿ26uò‡ŒM·<.Ÿ9êÒuÈ +Ïü8ø‰kâk¶67SjÖí}o=†‹g§Ë¦Z\G,Û‚²¬’Ë @Ù‘‹6lRéxwã¿uë³o¦Ë4ìòÛ-¯•qk3\G=Ü«)Hæg…CÜÂJN±I†8BÈê»^ø_ x^ÒÎ=*óSK‹9mÚ¶‘<à‘Z[Z4$„ +ÑK¤[Ђ |ëµ’6LÍoáµü>›Ã~Ö¯n-¤¶];NQ¼XâÐ-À\öË !§šŽŒÌåÁ"hÉrà|Cñ”ð¾ë^Ðo5=-£ñL—Y¥ÅÊÕÒÊàÅÉC±]ƒc•ùwqY–­â KÄžÑl>"øÎ-CMÕ5 .o4‹+[Öh&±…#h¦²]ˆ<éXf0͸Åv×suá _ ZxzšÖÆÖúÚù<¹7HóAt—Aßs;<±åÙ‰g,ä¶ãº¡ñg„Ÿ\×4ÝnÏĺփ§Û\Ú¤ºrÛ7™í :°¸†Q÷­ã €_Zçõë/ðž'…á´Ö´‹f$žó¸±{ˆDÊ»j³Á¼#ÚigÆO3?‰üQc=³èþ ñn«¥É}§A}uâ/®Ÿ%»ÍªY@±BÖßÌYa–ì9Û!B‘Ñ’7úf£á ïÀZ‚£I­4½BÆâÊfŠMÓbua,…ßqiX»9wÜY‰fÜIÍßè–ºþä“GWÖ—ªb 6ûkˆîƒò—‰Aï‚pAäs3üPÐ"ðî®5ž§ö}_Ãòköëå d·O³²ûcoô¸òÌÂ4 +ì«¬Ñ5íM.Óe{bï¹d¶¼‹Ë–V*ÊÃ$0 2–FdfRñšw­+O¸¶žÓÄ^&‰ì4×Òô°—ª«§Z™ ’8âP€7–ÖÑÒi•˜Ì»@ë|+¢ZøsöZŒ“Iog–)ˆëÀPžQUU@fxkþAÒÿ×õßþ”IZu™á¯ùKÿ_×úQ%ywíuÿ$ÛOÿ°Ä_ú&j)ßµ¹áÆŸœÈ^>¿õÆj+¶‡À|Þgü’>vÖÿä3}ùø“ÿB5R®kò¾ÿ¯‰?ô#TëôL?ð£è¿#íüIz°¢Š+S ¢Š(¢Šèeð_ˆã³7FÎÝÀµ[Ãw°<âyJæM¸ “·É¨HCâv.å7h«œõQV@QEQEWÚÿ?äžxoþÁ6¿ú%kâŠû_áÇü“Ï ÿØ&×ÿD­|× +§½ÿ~…ËŸùl?ëÆçÿC‚´ë2çþF›úñ¹ÿÐà­:øãéŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Šóx“@‹XOÚÚ,ÒÌ‹ ÑÒB¡%xþöñœíÏAÖ» ZëVbâo[]ZSµ‘ÒÑmÕ‘ œœŽ¤úp9ÈÅÆk~*ñ$>8¼ðþ…á{-V?MµÔ/$“U6÷³Ër‚8#1wųcÌ–%%”Q–lüqịxu&×t[}&ïM·Ôm'žôC,‘Kòïx¤U(žTá‰É 6UDDšŠæl|g¥]x’ïN[›!a›¦ß[j"íLW_nšâ(‘C–6Çy”:fìÞ,𬦡¥Íâ]+ý2ØÝßÚ½ôB[H«eBÙD +Êw0 y³Esþ3ñE®àßø‚ÜC¨Ëáë‹›‹Xç +ÛâƒÏ9ùlÈPò éÁg"¹ðå¾¹¦M­ZÄ&¸Ó£»F¹…Òâr¯Îœ‘™}Eqš¿ÅK]>çâ5“èó}¯Áv-{É0Hõ4[8î\FØ$2Q +Á°±'Ì +=ŠÌ¸ñmâ+o\kšd:ÕÔFk}:K´[™n%Ò"w2üÈù[ÐÔ>ñ6•ã/i^)Ñ&ól5;d¸‹,¥“#˜ßi :¶U€' ¤v  š(¢€ +(¢€ +(ª>!¸šÓ@Ôn­ßdÐÚË$m€pÁ Ž´zŠóÿYøûXðö›«ÂqiÛm"¹òÿ±¶o@Ûsæ ã8ÎuÞƒR¶±x5mLjWI!Ý:Û¬*A€Œg¹<çè4¨¯?Ô|}ªØjþ(¸ŸÃÖ_ð‹ø^åaÔõԘݢ}’ —™m¼¬ˆ³‚ÀK¼ª9UfÚÐ^ø»@Ò¦Ô†½¯øLŠÊ\›TEe@–ä´¡öùLæ!·,1,'9(è(®FñE­ö»­é79tí]t»2qºñÍŒ7‡b>`’¿Ê7DÍÓ OiâÏ +Þ\_[Úx—E¸›O¹ŽÒö8¯¢f¶žI<¨âÊ;H +8%¸gØ·f¹û»3¸“€èW'©øâÖ…Ú׎m,f™t›éå±™„r ­<Śݙw(e’'B˽r2¥—šŽ-u½[ÃÖ–v3G³¤^j,g`³Y½´¶Ñ=´±ŒâU{†W²)ôë(®M¾#ø-×FšÇÄZf§i«êãG‚îÊö K£“,náð„aBŒ±i#ù³]e™á¯ùKÿ_×úQ%iÖg†¿ä/ý]ÿéD”åÿµÏü“}?§ü†#ëÿ\f¢“öº |6ÓóÿAˆ¿ôLÔWm€ù¼Í~ýú#çoþCWßõñ'þ„j\Öÿä5}ÿ_èF©×è˜áGÑ~G‡[ø’õaEV¦AEP^â_imõ¥Þ—jo5_ì{AuöÕx!-GýÒ¦w…,¼¹œ‘Æ+Î(¬jÐV¹º_ñ6¥ZT¯Ë¿üžªÞ&¼g ZÍ­Bt¸4›q´»í¡¼¥RGQòîY +åˆÊãœÁa©ÛÅwáÕñN±e®E-ÑŽñîÒímգŸ–UfS‰²Ã$í'¼ª¬éW÷Z^¡ ý”‹Ä-¹‘\Œr¬?B+–XÛGÒߟ^›ëò:#’jëk~:í÷¶{.…©j:‹wâOÛÝ\¥Î¥²yµ8î•ÑTó72ýâ>\Ÿ¼=k™ð.©{5¬úµ×‹õWÔ$»EšøHRÄùj£»M»ÎõA /=@®#ZÖõ`[¥ìùVÊË 0[ÇQî9b5Už§8•JžFåk¾ËMÛõê9ã>ÆöWõÕ~k_XiúÕ¬f·gkc/Œ.á ¹E­[ËlyGž¿)ǵfØxnbÒîçÔ,/µ MVý`[»ô…£€Â»r6D@|²FÐÀb¼šŠQË`–ÿÖÖa9JöëÅ¿×ð:ÿ‰Ó­ÅޘͬÜj3­¡¥ÅüwÏn|Ç!MÄ`,™wªçõGÃù'žÿ°M¯þ‰Zø¢¾×øqÿ$óÃö µÿÑ+^?SöXzq]ÙédÕJÓ“ì‹—?ò4Ø×Ïþ‡iÖ.­ygcâM>[Û¨-£6w*iwÁÆO~ Oÿ ÿAÍ3ÿÓükäÏ£4è¬ÏøHtúiŸøŸãGü$:ý4Ïü Oñ  :+3þþƒšgþ§øÑÿ ÿAÍ3ÿÓühNŠÌÿ„‡@ÿ æ™ÿiþ4ÂC ÐsLÿÀ´ÿÓ¢³?á!Ð?è9¦àZðèôÓ?ð-?Æ€4è¬ÏøHtúiŸøŸãGü$:ý4Ïü Oñ  :+3þþƒšgþ§øÑÿ ÿAÍ3ÿÓühNŠÌÿ„‡@ÿ æ™ÿiþ4ÂC ÐsLÿÀ´ÿÓ¢³?á!Ð?è9¦àZðèôÓ?ð-?Æ€4è¬ÏøHtúiŸøŸãGü$:ý4Ïü Oñ  :+3þþƒšgþ§øÑÿ ÿAÍ3ÿÓühNŠÌÿ„‡@ÿ æ™ÿiþ4ÂC ÐsLÿÀ´ÿÓ¢³?á!Ð?è9¦àZðèôÓ?ð-?Æ€4è¬ÏøHtúiŸøŸãGü$:ý4Ïü Oñ  :+3þþƒšgþ§øÑÿ ÿAÍ3ÿÓühNŠÌÿ„‡@ÿ æ™ÿiþ4ÂC ÐsLÿÀ´ÿÓ¢³?á!Ð?è9¦àZðèôÓ?ð-?Æ€3>é—ú„m4Ëëbn#’iËu y“<€g=@`¾zõ®‚íq$ ( n#œèO­Rÿ„‡@ÿ æ™ÿiþ4ÂC ÐsLÿÀ´ÿæu'Æ–ßuwÖÞ–ÓSÒ,´÷šþòd’ÑàšíÌ‚ˆ‰×*vy±PËß‹á'Ù|gáK‹v²¼Ð<;m¤ÛÅñó.ì6Ú¤I!6ylàŒ`£‘´ªƒèßðèôÓ?ð-?ÆøHtúiŸøŸã@g ü/×ôj>,†óL“PŽY¦Ó`’Gh$2j:¥Ã¤ §îØÃ,È ÆÞ`ã/Ùz÷Âè­¿¶›ÄI{q Msª\›»GS½»ÿ‰Ú’25h"t޾r‰r¨ÌcS#4~Áÿ ÿAÍ3ÿÓühÿ„‡@ÿ æ™ÿiþ4Ã[ø;Äš·Á¿Ùkeoâïé³I¨Ä ¥¥¥ä¶Úˆ— !Ø‹a›sî`ì0Q§¬|8Ð-´!càßø@–M_J½¹6–Il³%¥ô77–Ÿ3lI猷P 5ÓÂC ÐsLÿÀ´ÿ?á!Ð?è9¦àZqš7ƒ5û_i\6˜4]#Ä޽owõÍËÝý³0<0±ª}¹ÿx%rÞJü‹¼ìÌø‰ð·Uñ'‡¾ C§jVZvµ¯\»éW¸fòà“O´µžÞl¹/Ù܇ û©2F›}þþƒšgþ§øÑÿ ÿAÍ3ÿÓühÏõ_†××_o5­ÝiÚ†¯e«I$ºíü+löÑÛªÆ,"" †Íª°–GKŒ£ˆ‚¿gðãDºðÏ€´? ^I ²é1ië4D•™!QHAk:*±NB–*ÀÜnÿÂC ÐsLÿÀ´ÿ?á!Ð?è9¦àZiÑYŸðèôÓ?ð-?ÆøHtúiŸøŸã@tVgü$:ý4Ïü Oñ£þþƒšgþ§øÐQñ ¼×z£kn›æšÖXã\–(@bŒ Έ /îðèôÓ?ð-?ÆøHtúiŸøŸã@–³ðóíŸ cðŒ’Ùj>~·©¨ý®¶÷µD¾»AÏ„lʨŒ[‚ªÌyj5 +꺉<;¨ü?ðï†RÃKÓu Ó¥ºm6(þÓ5¬¡ãÛÊ>õ»äm^_9<×[ÿ ÿAÍ3ÿÓühÿ„‡@ÿ æ™ÿiþ4Ì꾺ƒ^#ð]ô3j:ÅŽ¦æU1Bn¯LÒ;™"ÎØ\»*€ r2q|_ð®ëYñVµ=ޱŸ¡kÕt—³–6··¯ ’ê5È\DÐÔ¿-4^ÿ ÿAÍ3ÿÓühÿ„‡@ÿ æ™ÿiþ4ç>øq¬Zëú‰g¶²³¿³Ô­æh$ñ¡«4ð$6n®†SjßÈëÄèÈ/ûÜÅë5™ÿ ÿAÍ3ÿÓühÿ„‡@ÿ æ™ÿiþ4§Yžÿt¿õýwÿ¥Qÿ ÿAÍ3ÿÓüi¾’9´––)HÞòé‘Ôä07`ƒÜP™~Öë»á¾ž3ø›Çÿ¢f¢ûYíÿ…s§îíxúר®Úó¹—ñþGκßü†¯¿ëâOýÕ:·­ÿÈfûþ¾$ÿÐT¯Ñ0ÿ¢ü·ñ%êŠ(­L‚Š( ŠÓÒ¼;â ZØÜéz©±C%µ¤’(aÎ2 Œò8÷¬ÖX«8 ö¤§ÚOTS‹JöÐJ*[{[›„™ííæ™`O2fD,#L¹±Ðd“ê**w‚Š*ÅÕõ­½½ÅÕÄÜ©x$’&U•GR¤Œ0úPÚ@“ez(¢}¯ðãþIç†ÿìkÿ¢V¾(¯µþÉ<ðßý‚môJ×Íq7ð¡ê{Ùñ'èoÑEñÇÓ…Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@=ûZ®ï‡x'ñ7ÿDÍEµª†øq§ƒŸù ÇÓþ¸ÍEvÐøÌ¿ò>uÖÿä3}ÿ_èFªU½kþC7¿õñ'þ„j¥~‰‡þ}äx5¿‰/VQEjdQEwúv­êÿ 4´ÐôëëÉâ×'bmbf1“X$»ÏsŠÙžÍõê—Ú|ð^ËkgkðµÒ!Õf¹¸ØGŽ7ùJ†t€ŽHëšòz+ŠXI6ß7~Úûö:ã‰QŠVü}Ïú¹ìËnúo‹¼W¦èšlj¹ðüEiý%"p!!ÔubcwÚ1ÃÏ^ÜK§¶±§Çqõì‰um†­å[Ÿk¤ólÝHUÎÑ‚ÈäVo.G-ZZÛ²·sGŒMß—ñôþ¾f¦‘¤É«xžßFµ5ÅÐ…HçhÝ‚O°'é^âc¦ø“FÕm4ÝkOÔIš;­2Þçó#´EXdBdWV7!Iä1÷¯%¢º*áÝIF\Ö¶ßü tëÜÆ8…d£ñ~Zéøþ M]¹‹J¹ø›â%ôÛWOŠoì«[=*f—*#;|ö ½‚;‘ÀèµVçD{ŸY M>M>ñ4·žæ+Ÿ[‰®¶»(1XîeÞF8ùxV¯–QXG(¤”öVÛÊ×ùïn毥{Çw}ú];~Líþ-iÐXÜh’%“Z\\éþeʵ‚Y;8•Ô XÛ +8S‚kê‡òO<7ÿ`›_ýµñE}¯ðãþIç†ÿìkÿ¢V¼Lþ›§‡§ï«=\ž¢©^rJÚ/ÃOÄߢŠ+å¢ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ ++ɼwâø~)ßh’x¯Æz=…¾‰cu^ðòê;å–{Å‘¥?c¸)òÃPJƒ†ÆyÆž‡ñ"ôi‰c®x[S>'·–ÏN¹²²6þ]Î¥%‚ÞÏ»<ûBÅf-+*0#p@=Šòoˆž?‡ž#»ð–‘­\k%åÕÃF–ÃûXÍÄ!§JM³ÚÜ)ùÀù yVBý6£ñ+Ãzn‡·¨ Ûk 5-GOyZÞKX­ÛO#$”Ûc1] ±Ê|£'çú‡uxµ ØÂ­iÓjzÚØ][_¤Å»Z]L&ŽX§hNÖ·Ë.òá¿w—‹túÃkš÷Ä]GÖ^(Ôü=i¦iWªúl¯%ÃÜÍvŒ$7Ê6¨µM»œ»î-òíîh®1¼sŸª.‘¨Ù^Þ}’æ×MÕ5›X#ŠÊ ùÖ/./)¦3æâ mY|å ÿ+•äõ?Œ6öšö›­]ÙjzoƒçðýÞ¡osuöET-s§Åk$GÍ-Ÿ´‘ûÿ$0/·kõú+“øwãÝ#Çv&÷C‚i ŠY`º\[M´È"a’]™&W&u2»#µÖP\çˆüac¡ëiRiº½õÔ¶æáRÂÐÎBÚI ÈÁÇlr+£¯(ø½ª_èz¿‰5½.³ßéþÔ®­eØ­åËFÂõ ›þø?èTñþ e£þø?èTñþ e®_ÇÚ牼 ¡ø‡OO^ë7-á_[Óõë{e¸³žÍa]¤EE"1¸€( +˜ß%Ã:÷ˆ“x5 :Ñmsl%]Â+„Ù"óÑ—<cÈïƒÅZ¨­?Õ7ýtýБ~Öí·á¾žqŸø›Çÿ¢f¢—öµ$|9Óöõþ×ÿDÍEvÐøÌ¿ò>sÕŽu[³ÿMßÿB5Z¬jg:•Ñõ™ÿ™ªõú&ø1ô_‘à×þ$½XQE©QEQVll/¯ÌÂÆÊæëÈŒË/“?–ƒ«6 +=OZØ_]ZÜ][Y\Ïoj\KLÉ= 0¹ÁëIÉ-ÙJ-ìŠÔQE2BŠ( Š( ¾×øqÿ$óÃö µÿÑ+_WÚÿ?äžxoþÁ6¿ú%k減øPõ=ì‡ø“ô7袊øãéŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š(  ËmÖ_ø$˜ÝßXÛYJ„,$;¡ÜMËç$ŒÀ9ÆÔü§]Üßß[êzžŸ¨Ýjë¬C{nÑ-.šYÉFTÀ¬¤H¯ÌŒFR½eç:·Â-"÷F½Ó-îÙ¼=á'ÓµÅÖõOë^"¿ŠÚK[Yu¶O³E#FÒª‹xb{C %Ãå»rÛº&Oùú›ò_ð£É“þ~¦ü—ü(Z*/&Oùú›ò_ð£É“þ~¦ü—ü(Z*/&Oùú›ò_ð£É“þ~¦ü—ü(Z*/&Oùú›ò_ð£É“þ~¦ü—ü(Z*/&Oùú›ò_ð£É“þ~¦ü—ü(Z*/&Oùú›ò_ð£É“þ~¦ü—ü(Z*/&Oùú›ò_ð£É“þ~¦ü—ü(Z*/&Oùú›ò_ð£É“þ~¦ü—ü(Z*/&Oùú›ò_ð£É“þ~¦ü—ü(Z*/&Oùú›ò_ð£É“þ~¦ü—ü(Z*/&Oùú›ò_ð£É“þ~¦ü—ü(Z*/&Oùú›ò_ð£É“þ~¦ü—ü(Z*/&Oùú›ò_ð£É“þ~¦ü—ü(ZŠÓýS×GÿÐLŸóõ7ä¿áN†1l [’I=I'?Ö€<ƒö·ÿ’q§òüMãëÿ\f¢›û]~iøÿ Ä_ú&j+¶‡À|ægü‘óñÍìä÷‘¿CRÞÞL}doçQWèxàÃÑ~G…[ø’õaEVÆAEPwð‡S¸Ñ‰5K]¦[]+Ì +ßu±gŸ.ÿí/vóŸnÛ·>›~\zq@ ‹{®Iho|ÛÄ ˆ€>]‹¸D, ‰È)¿…`@a¶›c®]\Ï J•’gpÅ‘X‘¶L€e¶Crq’¹EfZêw3i«t4Ùfrå vò¡úœÈPŒ”†ƒ1ÆhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇhþÓ½ÿ¡{Sÿ¿–ÿüv€4è¬Ïí;ßúµ?ûùoÿÇjÖ™x·öbáa–ãhäÆådrŒÒGU= y'ítHøm§ãþƒ虨§~Öë¿á¾ž9ÿ¼ú&j+º‡À|Þf×·ù#æû²MÔ¤õÞGO¸ÏÚ$ÈÁÞr?e~‡‡þ}äxU~7êQEjfQEQRÏks0Í5¼ÑE:–…ÝY8%Iê2㸢öˆ¨¢ŠT³ÚÜÁ 3Mo4QN¥¡wB@ RzŒ‚8î(k[•³[Æ·˜[;˜Öb‡c8• Ð8÷®‡fEESWÚÿ?äžxoþÁ6¿ú%kâŠû_áÇü“Ï ÿØ&×ÿD­|× +§½ÿ~…ËŸùl?ëÆçÿC‚¯\ÛÃsŽdÞ¡Ò@2G̬O„Tnäi°ÿ¯Ÿý +Ó¯Ž>œ§.™a$·2µ²ù—J‚gRT¶Ìì9g†Œx-´Ë+v≼ÈÙ˜HÒ3;ÌI,0†$|«ýÑ‹•Ëë:Ñl5´ø Ôµ[«vÛs›h×Üã >Þ<ãýÓé@‰¦X$PD-•£‚Ý­cF%€ˆíÊzƒ±zç§¹¦Ûé60I«¯,o½d–w‘ÁÚÊ>f$à|ƒq8ɧhº¥†µ¦C©iw)ui6ï.T †*zû‚? +®-Õ&vž%X3ç1p|ù½8 󨿀#´°´´ò~Ï—äÀ¶é†?ê×îƒÏÍŽÄ䌜u9‹û&Çí_hòåÎÿ3ËóßÊßœîòó³9ù³½Ï^jõE´=žgk|™³Ÿ¾RHbSŸ–‰\À7P é|òïæ]¤.¯·pbÄ–ÈEç…§zšdŒJ±HÊYS<1’ ÈüÅEeiœF8€fÜÌîÎìze™‰$àÉèèOEQEQEQEQM–HâPÒȨ¥‚‚Ç$€Ô’÷4ê(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢²W$凃è)à ^KY5¿WµÞŸðwÒÛ«Ñ‹Ò7Û¢ì®ÿ§™éž ¶Òìõ¯j6ºE¬rjz>£,°‰&)¸yÀË–û«·©à“ךÌþÒÓá[iÓËá­6Xæ×'U¶3\¢TY+‰w’}ØÏ1ÂCªjpÉk$:Üog‘jÉ3I'aåä“Ç­?QÖ5}HçQÕo¯?yæ~þáäùðîO\3è¥WÔäês7›ï&¿o—™?Z\œ©[ä·qKóWó¹êMáO éÚž›.Š—«wâytÏ6k‰•¢ƒ‘·c¸o8$p{dÅ£xZk}?S¹Ò¬Zí¥ÂÂóȲ$Q«FòòÎOÎSgW &µ¬É2M&­~ò¤æå®²Êq™Ï Àùºð)-5bÑã{]VþŠVš6ŠáÔ¤Œ0Î0xb8'©1ÁÖKZŽöîÊ–*‹–V¿eÝÿÀ5üw§ÛÚ2êÎÏM‚ÚòÔÈ’éóNð͉KŸ÷ˆF0Aàã#­}eðãþIç†ÿìkÿ¢V¾2ÔõCTº7ZõÕõÁL·´Ðe‰8¯³~É<ðßý‚môJ×Ä”0ôÔÝÙédÒS­7mrçþF›úñ¹ÿÐà­:̹ÿ‘¦Ãþ¼nô8+N¾Lú0¯.Òt/A£EköÖÓobÕ.$»¸qÿ™•”7Þp ‡ÆqèŸQ¢€+iªëÜ Ĩ#§×'ñ®K_ŽKh|Y¨ÃH²+[\Fƒ,A¶‹cd,ùéò±$ ÚŠænõM|Pm–êÖ–xÒ;w“4eT³ˆÄe›œnª6r0­šzEƱm¥éÖ6›®ì²#R­o:3Ç>L<ò»³ÉV®ÊŠä&Öo¾Í%ÃjI0=ÎÔnÝ$¦8ðF[äü«†ùùäŒçP}J Öiecý ŒË³ÃÜÄŸ»P>bŽO$á°õôPf©¨-ºé×iuXÉ?ïç,<¿,ÄåIcÀö`ç’@ïYV:½Ì÷Ve¯™k‰Ñb6ûYÔNê2¤ "€vááœ2“Ž¢Šâlõmj{|ɨÀ’JÐ,É ¬’Z»ÏÛåÃ8Û!vÈã;XÖö—y4Úåí³Þy¢<Ÿ(DŒgÑõûÙ0È@Ü£bŠä?¶o—í/g¨h^¬÷ˆÖQ¼¤ÍòÎÔù)ä“þ¤S´½GRšîÒ«Aq —Ц[yRrG•3²"c(œ¸rF客ÚÞhÌp¦Å.ò’~fbÌyõ$š–€9ŸêsZê·qGªýžXlcšÒÓ÷éR–—äÃ)fÎÔRÏ˳8ݵIÆ{t«5ݼ7v³ZÜ&øfFŽEÉR0FG=(*-nHîÌ7öÐ["J`–U¸Ü© ˆÍÝWäòú±Á Æ1óUdñJEÒêmk»!¸“â8ßxVãWc½à.>`sÁ^m2Âgw–Ùd/)™ÃC1‹Ê9ÙÆ:~5¶‹§ÛÜ­Ò$ï2°`ó\É)+¨ûÌxÄÇOš€2[Ä7ó\ 4Í +<÷j×eŒk03„H'÷¸©9hØjÒOªfÏj±N‹'šR]è +ˆH +J‚AY—’#ž´èô&8^´Â< nÃÌncdD#¯÷bAž¼{œËq¤i÷I$¶ûšGß!ÃʪTàò¤"‚§å;FA  «Þ^¤-›´qžèÞ4 9 „8P¥†FI pȽ6°ÆÇLº²³iΤÊ"Gp…CDÒÇžÞq“Œã$g´Ò4ûE…míö]dçc†y@ò¹Çëך–+ H¡³…"ÂYcìãqù0…~~V#œõ  Åñlõ)¦ÂÕ¦uó8gW™AÇLÂpØäÀéQKâ+ˆ„ò>Ÿ“Údȸ%ŒVòlãf7giUÎNYqÍëI¹ãšÓrI¿Ì_1€}ìÌw~l33 ýÒr¸©dÒ4ù#xÞß*éÎiõ|Ë_µ^,r¤Åå>[ÌûJc`>cÑxñ=ž½w<Öð>”ÑI5ÂŹüÔM¥$rAxÔ³ãn>eù¹8¿‹¦¤²H`i#4rÊòF çyĨ'st†#¡4ë}&Æ #•c•å÷¬’Îò8;YGÌÄœïÐn'4­«Ie-ÀŽÕeŽÎÜ]]3K´ˆÎÿ¸6Íû¶à•9äâ =BâßBÕµK„óŒݺ/š~t‰™TtÂp˜ÀÏMÇ’kB÷L²¼”Kq3mÚÁde/÷\¯'†Èäúš{XZ5„ö&/ôyüÏ57›Ì$¿9ÈÉcÓ¦x  ›ßMhÆ ´ÖlÑùQ+´ƒk‰ݱX†'ÈU`9 ’#ƒ]¼kÖ’K6H Vªb“(é$—` +‚T¸gxŽ5îôË+©^i¢o5•ÌIBîÆÖR +ŸÆF Aâšt<Àð}Ÿä’‚L;fDbIÜs–9,wœ³üÇ ‰âˆdù6ÛÌ»‚|ä ™!X³Ç–xÜõ* $b Öµ»Ãc¨Ù-²Áu ÓM$wˆŠE)C´'ÎN»pAëû‹ K‡™å‹sLˆŽÛˆ8BYqƒÁ‰`ƒƒžAý‹¦ùO@Î$ŠH]žWgu“h}ÌNI!dœ€  +ŸM»ûl p±ìŒ»,y?1à–ÂrÊyç*3—\‘ììgŠÁ¤{»¼«ä®<¯—’?y’@' Â’@­XíáŽyg6¼Øó0N€qÓ8ÀÏR†(®ƒ¤«—Ÿ1Co1²‰•`«Ïʪ• ¤eq“@n¼I,OG¦KpÆžQùAF,ÆcF ŒFâ™zs¶í«Ÿ$L4õ(×’Û©óðG(9+€ìÀ…S…'¸$iô]5ÕÀÁUv°Y\ FI"LÞK¿9,ßÞ9tºFŸ,kÛåCÈøÃvö,êyù•‰ÉS•ÒÂÞÚÔ8oŒ‡z‰K+9f$±“IX¤h‡W“T[›˜®e•&E©Ínꪠ´jáÊŠG sšÖûU·üüCÿ}Š–Š‹íVßóñýö(ûU·üüCÿ}Š–Š‹íVßóñýö(ûU·üüCÿ}Š–Š‹íVßóñýö(ûU·üüCÿ}Š–Š‹íVßóñýö(ûU·üüCÿ}Š–«ß}ØÿÞoý©ÿj¶ÿŸˆï±Y>)Öí4­=.Ú;«ÏÞmY@ÓÈIVÚ½¹ÀüHZñ%¾“¨Eeq§ê<Ø´1« Iã ódœœcéê+?Äû¿á=ð9xÚ67w£JŸ³·Œý ¦Âue½øsÄå£$¡:D„©ÁppHük=µƒâxRK]Z¶ŽÎêfšK» "@æ#p?@­Yžÿt¿õýwÿ¥VfxkþAÒÿ×õßþ”I@aû\`|7Óò3ÿxÿôLÔSk OÃm?ñ8‹ÿDÍEwPø›ÌÒöÿ$|Ý'0÷4”éqæ¶FãƒM¯Ðè +>ˆð'ñ0¢Š+RBŠ( Š( Š( Š( Š•-nd´–í-ækx™VIBˆ[;A=88õÁ¨¨¸ìö¿Ãù'žÿ°M¯þ‰Zø¢¾×øqÿ$óÃö µÿÑ+_5Ä߇©îä?ÄŸ¡rçþF›úñ¹ÿÐà­:̹ÿ‘¦Ãþ¼nô8+N¾8úp¢ŠãõÜ6§waáï ßkMc1‚îA*[Æ’`ªÒ¼òsŽœzŠì(ªZ¥­¥Ã¨Emwj’îÄWP˜¥\1_™O#¦~˜¥“S°A}ºåA°]×C˜ÆÍù#©yãÐŽ ÐÊ(¦Ã$sD’Å"ɨdu9 Bq@¢Š‰®![¨íYñ4ˆÒ*àòªT1ÏN¬¿KEPEPEPE@nà¿cÜÆ`ªÅB16ü@Àcuîî3=QEQEQEQEQEQETwpZ.éÙ•v“ŒAä8x–/RzSÐEPE@nà¿cÜÆ`ªÅB16ü@Àcuîî3=QEQESL‘‰V#"‰K*g’2@ô˜§PE¥Ä7v°Ý[¾øfE’6ÁR2=(Z(¢€ +(¦¼ŠŒŠCí´aIàžHè8êxÎR(ÔQPCwÖpÞBÍ$3ª4l¨ÄøÚqŒÈÎzN1@ÑEQEQMŠHåRÑH®¡Š’§# GÔA÷Èn!šIã÷4#`­µ[ü2ŸÆ€%¢Š(¢Š(¢Š(¢Š(¬Ï È:_úþ»ÿÒ‰+N³<5ÿ éëúïÿJ$ .ý®Î>iÿö‹ÿDÍE'íwÿ$ÛOÿ°Ä_ú&j+¶‡À|ægü‘ó{Ì[Ôæ’Š+ôZâ>~_:†òQ<=ÿa(?ô1[~'×’ëP’ÚOx›Ä/¾m.ú6Ky@»¹n½†?JáígžÖæ;›i¤‚x˜nϳ·1É<–ÿgåÏý‡.“âmrãÂÚ{\ØêÛÅžåc;Ú]ìãÍÜIÚ:0î +5 ñl–Âúä@“yé•¶¬½7œ÷ëV5-{\ÔÑÓRÖµÕ}»ÅÅÓÈnvçq9ÆæÇ¦O­b°•4¼µïvºßòÐÝâ©ëhéÚ˳_›¿àw†´ë9¬µ}?E¶½“Hšþ%‚kÃzFÒFíË@eNc\Ÿ€o#Óü[e6™.¥¹y$‚$áBÈe>øÏ/8ëU¡ñˆaÓ†›»ªGd ¶K¹ANr6ƒŒœýMQ±»º±»ŽîÊæk[ˆÎc– +:PG"µ Újnê^oÏî2•hZªÍo·—ù?¼ôuµ›Åzm—›ãMkQÒdÖ­í']Z’DÎ ™$‚َăÅ6÷ÃÞ¿½‹N·’ÆÊdÖ!³v²¤¬.̬&7dF6Íòð+ƒÕõ­cX1¶¯«_ê,ˆÍÕÃ˳8Î7Œà~TíO^×5;Xíu-gQ½·ˆ†Ž+‹§‘€@b@àâ²XJªÖ•½?áµû‘£ÄÓiÞ7Ó¯ÏÏMÿ«Ó­´}CÆVº¾ŠÆÝ5ˆmf”\\y •1ÊYÊîoU È8ö·à i:„—†ÿNy#Ä6–(Kº»‰ ŽpÜ{f¸½CÄ:þ¡mµþ¹©ÝÁŽ)îÝÕp©.¼Sâk¦F¹ñ¯;Fêèd½‘в’U†Op{fœ°õœm[n¯£_˜½½+¶ãߢì×átïät²ZèrèºÖ§…ijúf§koYç`Ñ–—výÎrHU½8¶|Y•¯üT×¼?6‘ik{pÓ%•ÜRÌîp=ᜧ͂œ(85æ?l¼ò&·û\þLî$š?0푆pÌ:2y>¦µôÏj ­iwúÅÍö±™(’ yï +W@';FBäÈã­)aj'̤ݓ¶¯´U³ÓR–*NUºèº9~Ž×ßAþ8Ól´[›-@¿µ¶S©K¸’g˜¦3°¼w>ß[|8ÿ’yá¿ûÚÿ蕯‹õ ¹ïï§½ºÉ=Ä,Žz³1É?™¯´>É<ðßý‚môJ×Ä”pôÔÝÝý­O&”]yòím=?Ï¿™rçþF›úñ¹ÿÐà­:̹ÿ‘¦Ãþ¼nô8+N¾Hú0®;Áz-þ¡*î-ë ÔæSæ2ÆÒ³†*3°üÇŒž9É v4P{ž([xÚÌűéÛúW1¯i÷¿gñ%啬²O6è| ¸ûDmoäz”!ˆëüj[#¯¢€9›´ÕžÓu ãò-ådhv®ü°qçÌûà¸íŸUm6ËZ‚ÂÆÊÑ¥ˆ‹ƒyÏ&Øå€¹e'ÑÝ£pѫ〵×Ñ@„ßÚ†ÚI$þÓÍͦªy¿$Ï$¬P¼ ªaR$ù§}“SkØ¥E¼bZÿÎ˰vŒÜGµ˜â2QFÜ` +“¼u´Pf©<¡tëØ–ëìé>ùÕ"rþY‰ÀÌ`n?3'Èê@ÁÆU‹j/ug%Äz¬l×þìç¦w#$„Ú~6b;†¨¢€8›85§·Ûqu¨¼²4 x‰ ñms<{ö»9 æs Œ“¶·´¿´n^‰>ÜS“™r#ü òôäû$€'bŠãc“P•n[I“Q}D\^«™L† Ì# æ~ë!ÄCå烞7Tº\æîÑ~Õ¨ÍiöÅgÌ7ˆ¦'&Wi +îd&pIjêâŽ8”¬Qª)bÄ(ÀÉ$“õ$’}Í:€9Ç«rIt¸ç5º*:°Šó“òà9¯+žÔË噬‚érëZ×í qð]¯ªYg?7•¤N7×WEr \ÙÞÌnµ9$·Ó„–€+ÆPó”ù2YˆQÚÄ’Þ Æ,¿ö‡úw‘ý§ý¯þ“åýï³íùüŸ¿û®žWÝù³÷¸ß]5‡áD¹O´ù—7SÀvló­æ‹ ÎìyÎÒ6ú/§;«rŠ(¢Š(¢Š(¬Ïù¿Ù¹í\8, ß–ðL¼œ ¦H$ +†NŠä­ä¸}VáRMU¯ã¼·U\ıyp™CíýÀm¦Cõ?/;j =5Ŷ‘¦¹¾’R‘ý¹¼Ë´ù‰ælfs“³ÍÇ=°v +ì’8Ñ’5V‘·9ŽÉõ8}§P!©[Ïtm µMa¬YÆ|ã a‹›SœŸÞ )¾a†#åÅièÆõõ‰ã’IZ+7¸ŽRÒe]¥t–0£9;# Œàdf·*+[{{HÞÖ …s¶8Ð*ŒœœÇZ䣓P•n[I“Q}D\^«™L† Ì# æ~ë!ÄCå烞7Tº\æîÑ~Õ¨ÍiöÅgÌ7ˆ¦'&Wi +îd&pIjêâŽ8”¬Qª)bÄ(ÀÉ$“õ$’}Í:€9Ç«rIt¸ç5º*:°Šó“òà9¯+žÔË噬‚érëZ×í qð]¯ªYg?7•¤N7×WEr \ÙÞÌnµ9$·Ó„–€+ÆPó”ù2YˆQÚÄ’Þ Æ,¿ö‡úw‘ý§ý¯þ“åýï³íùüŸ¿û®žWÝù³÷¸ß]5‡áD¹O´ù—7SÀvló­æ‹ ÎìyÎÒ6ú/§;«$A­Ã£ØySê-=Å‚½ãͽÊ0x26‚ +°F”a0íŒä°»*(‹OÔ§Væð±·¼†ÒwI¡òÝÒ-»ƒ3I·+!Ë÷Á™î?á"™|ë_67¸Io!FÈòȉÑ"`ß(?4 ´ñ¹e9àWWEröñÏ&«h¶gU`¸›ÏiÕ·ˆç-“'ϳ"ÈOsV|å¶™koâSgÂAª¨Í¿Àà“œòÙÈ8S~Šæ^mLIoh±jfT¾ºydx²ÎbŸån©Ê©6S¸]Iì­O¨Ãh]îa¹‘™¾M„*2ÎþðáÉär<³]•Êyz’Ø^Évú›ËçÂnõÜ«dü±P bήåU¯ÿiÿa[}íßhÙ.ýŸë3öYq»Ëã;öôãv1Úº(3L†âÛU»·in¦·ò!‘d™‹n”´ðz>UÂŒðk+Mº”øcK°‚ F+¸Ée i,x $BA¸¨cvpzg¶k¨¢€9%ÑØ@Úªj&(þÞÒ,méæ”‚Nß7:s²¥ÙßÜ][Cq{©µ–ˆÈYm÷sÕ%™¤7˜Af ÁäàõtP/£É}+ÛKª T_ºÀшÕÖ=†(üÍãýP;ü܆ùñ÷yÙNð’j‹tZþæêG0¥#Ûʨ³ez3¹Süê€Cíò +騠Jâ ¨,^Ûmäïîf’dK‰pZBȪ°²¶ÖGÎAÚ +FãÄ8¿i¼ù£ÔÓUž{I1ʲy0 ‹ ³(çF WiEQEQEQEQE™á¯ùKÿ_×úQ%iÖg†¿ä/ý]ÿéD”念ÙÇÃm?þÃ虨¥ý®Ž>iÿö‹ÿDÍEwPøœÌÿò>n|n8éšJW9v#Ö’¿D¡ü8ú#çå» +(¢´$(¢Š(¢Š(¢Š(¢Š(¢Š+í‡òO<7ÿ`›_ýµñE}¯ðãþIç†ÿìkÿ¢V¾k‰¿…SÞȉ?B}Vai¯ØÝI ÓÂ-n#- ¼’á‹Â@!#![ò©·,¿ç†§ÿ‚Ëþ"´è¯Ž>œÌþܲÿžŸþ .?øŠ?·,¿ç†§ÿ‚Ëþ"´è  ÏíË/ùá©ÿà²ãÿˆ£ûrËþxjø,¸ÿâ+NŠÌþܲÿžŸþ .?øŠ?·,¿ç†§ÿ‚Ëþ"´è  ÏíË/ùá©ÿà²ãÿˆ£ûrËþxjø,¸ÿâ+NŠÌþܲÿžŸþ .?øŠ?·,¿ç†§ÿ‚Ëþ"´è  ÏíË/ùá©ÿà²ãÿˆ£ûrËþxjø,¸ÿâ+NŠÌþܲÿžŸþ .?øŠ?·,¿ç†§ÿ‚Ëþ"´è  ÏíË/ùá©ÿà²ãÿˆ£ûrËþxjø,¸ÿâ+NŠÌþܲÿžŸþ .?øŠ?·,¿ç†§ÿ‚Ëþ"´è  ÏíË/ùá©ÿà²ãÿˆ£ûrËþxjø,¸ÿâ+NŠÌþܲÿžŸþ .?øŠ?·,¿ç†§ÿ‚Ëþ"´è  ÏíË/ùá©ÿà²ãÿˆ£ûrËþxjø,¸ÿâ+NŠÌþܲÿžŸþ .?øŠ?·,¿ç†§ÿ‚Ëþ"´è  ÏíË/ùá©ÿà²ãÿˆ£ûrËþxjø,¸ÿâ+NŠÌþܲÿžŸþ .?øŠ?·,¿ç†§ÿ‚Ëþ"´è  ÏíË/ùá©ÿà²ãÿˆ£ûrËþxjø,¸ÿâ+NŠÌþܲÿžŸþ .?øŠ?·,¿ç†§ÿ‚Ëþ"´è  ÏíË/ùá©ÿà²ãÿˆ£ûrËþxjø,¸ÿâ+NŠÌþܲÿžŸþ .?øŠ?·,¿ç†§ÿ‚Ëþ"´è  ÏíË/ùá©ÿà²ãÿˆ£ûrËþxjø,¸ÿâ+NŠÌþܲÿžŸþ .?øŠ?·,¿ç†§ÿ‚Ëþ"´è  ÏíË/ùá©ÿà²ãÿˆ£ûrËþxjø,¸ÿâ+NŠÌþܲÿžŸþ .?øŠ?·,¿ç†§ÿ‚Ëþ"´è  ÏíË/ùá©ÿà²ãÿˆ£ûrËþxjø,¸ÿâ+NŠÌþܲÿžŸþ .?øŠ?·,¿ç†§ÿ‚Ëþ"´è  ÏíË/ùá©ÿà²ãÿˆ£ûrËþxjø,¸ÿâ+NŠÌþܲÿžŸþ .?øŠ?·,¿ç†§ÿ‚Ëþ"´è  ÏíË/ùá©ÿà²ãÿˆ£ûrËþxjø,¸ÿâ+NŠÌþܲÿžŸþ .?øŠ?·,¿ç†§ÿ‚Ëþ"´è  ÏíË/ùá©ÿà²ãÿˆ£ûrËþxjø,¸ÿâ+NŠÌþܲÿžŸþ .?øŠ?·,¿ç†§ÿ‚Ëþ"´è  ÏíË/ùá©ÿà²ãÿˆ£Ã!¿²Ùš9có.®dU’2µ§vRU€# ƒÏ­iÑ@5û^ÿÉ5Óÿì1þ‰šŠ_ÚìðÛOÇý"ÿÑ3Q]´>ç37ûÿ‘óoN( ŒQ_¢Ñþ}óòÝžƒð£Gceâ9|9&¿ 3Ef–©hn3½ƒJû@<¬`€OBâ«j±Ð¯ÎexãŒ&K`1n3Êœdñ:®¥{ªM×ÓyÏÀ‡h\FŠGtsÖ¬Ÿë?ÚÖš°¾t½³Ž8 •T¢"íUÀ#o9ÈëœÒެV’ÖÏïèüüûé ôÞ¾éëêûßç¦—Ý +5è¥f¿ÙýÚÛÖÞfÝ÷…ô ?û_S–òâÿL²6Ë6wP´$Ê[cL¡ÐlÚÀ§qf¤ðt^ž?Ìt›ë‹Ht…–$žâ/:&ó#µü¢3“ÃdÏô~+×#¿¹¼[˜ \ÄÍ ZBÐ: É+åávŒ|¼v¤‹Å:ÔZ¬ÚœsÛ,ó[ýšEû>KE€6¶y{~Uãojn…yE©>Ý_——{ë¸*ÔT“K¯eß×·MޤøsLºÑ4ýVâïXm6 "âûìr®êÉ"¶a, 6ÓüGðÛ_ xz[)u¶mTi£6£ °™âDœDѳ”ÚTœÁGpqƒÍ'‹uôž Rò$û<2ÁKk‹Ê‘‹Õh,äD‚4A!„jª¡PdòßÔÔý_Ò]_^—zmé®ýí¨ixöéÚÞ~OO2i:}ž©i‚ê;mNÕ¦Üʲÿÿ˜já?Ÿðä{5âç㜣þe‹cÿqCÿÆiÇIG_ ÛÿàÐÿñšêöcÿ>ÿÿ˜¿µ°ŸÏø?ò=¦Šñ…øã3̯l>º¡ÿã47Ç)@ÉðÍ·þ ÿ£ý_Ìçßãóí\'óþüg¢¼Xüt”̯oÿƒCÿÆhÿ…é/ý +öÿލøÍ?õ{1ÿŸŒÌ?µ°ŸÏø?ò=¦ŠñŸø^ÿгkÿƒSÿÆi§ãœ ãþ‹cÿqCÿÆi«ù‡üûücþaý«„þÁÿ‘íW‹Ž’ÿЯoÿƒCÿÆh?e?ð‹[ÿàÔÿñšêöcÿ>ÿÿ˜ka?Ÿðä{Mâç㤿ô+ÛŸûŠþ3H>:JOüŠöÿø4?üf—ú½˜ÿÏ¿Æ?æÚØOçüùÓEx·ü/IèW·ãþ¢‡ÿŒÒ¯ÇIXàx^ßñÕÿ£ý^Ìçßãóíl'óþüh¢¼gþ„¿ô,ÚÿàÔÿñšiøç(ÿ™bÛÿ‡ÿŒÑþ¯æ?óïñù‡ö®ùÿþG´Q^,~:JüŠöÿø4?üf‘¾:Êá·ÿÁ©ÿã4ÿÕìÇþ}þ1ÿ0þÖÂ?àÿÈöª+Ä›ãÄêüRPÔWÿ´×¡|.ñ¤9ð캬VXÉË[M È +¬ +° «¯P9Èí“ÏŠÊ1˜J~Ò´,¶Ý?É›PÇP¯.Zr»ôg û]’>iåè1þ‰šŠ?kÀ[á¶žý"ÿÑ3QYPø#2··ù7±Ëêi)_ïœzÒWè´‡D|ô·aEV„…Q@Q@Q@Q@Q@}¯ðãþIç†ÿìkÿ¢V¾(¯µþÉ<ðßý‚môJ×Íq7ð¡ê{Ùñ'èoÑEñÇÓ…Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@oÆ£‡çÒâÓÿJ¢¯šõ;–7³ázzúKãyÇÃMDžÓZüšŠ¾a½m×sx.ßο@á(sadÿ¼ÿ(Ÿ-žÊÕ£éú±¯3±ûÆ™¹¿¼:J+ë¹lxszŸÎÇÔþt”S°\]ÍêhÉõ4•-«ÅÔROš%p^0Ûw¨<ŒóŒŽôž€tš—…™lôÁ¥}¢âöb"»Š¦5•@é…ØÄOð:G­øVöÃO²¹<òöé%ÉŠâ9UYå‘aBwr äõ®ÙøÿRûUùÕÆ¥it[e´·M¶Ü6åas·äwQ€1{b™eã+{ FÊk!…­¥‘µOuæ>i•\°@2iÆ9ÛŽ3^JxèÙrÞÚï¾ún½Ÿ3ѶõòôÕk÷jõüôÈOk;îãÛ¬ÞDš{ ”ûø~æàúT÷>ñ nö(Ó4ÞAŽ;˜¤d|‡ +Çg +N[ž•¥¢xßû;DûYݼ†+ˆÜÅ}åE1—wÏ,a÷]Ø·@*+yZ†«rtÕxõ+Óq,Fb1$¨Ñä¤Jp݈èjÝLuåh-6óütïø¡…²¼Ÿù+zz#?þ]pI´Ãl#òÄ‚àÞ `IQ‰wì' ŒÏŽ*Ö‹á-Fw¹“Q…­`‚ ¦Áž4¼1±áîe $:ò*Æ‘âëM"‹=/OÔ¬m'T.öú«GtÒ!bÊn0Äm;w¥o[Ì^âóJš{傿Þ¾ÜÄ,soûÁ•™ÙL‚Xduõ¥:˜çt ½t¾ßâïê:q¦œ¥Ûóôíþ^fn›c¥Á ÿlk {:ÍrÖöðẔUUÙ™[¹@ç'‘Žmê +ÕDÆM5êÊP­jï1ÓÚÆÆö{6£g}$ÖG;$vê±Â‘Êê<¾ùy<Ó«,T'x+ïéåmU¼ïøè*J„¢”Ý¿>½lÿ¯™›¨ø7Q·‘a¶¶ÊâØ¯’ñÌÑ3ÄHvãiç n$ f¢øCÄÒ£[ã“3_@±&v!}¬ÖÈÇZÔÆÈ‹ÿ ¦f–8#ºÝsÄ‹@Û@PSr¾zœß8µOEs£&‘k§=½¤- ƒ}ǘêÊNã´,ÓŽôBx壊é¯ç³þ¿’ÂÚ齟ßÓ¡NëÃZ嵄÷³Ùùq[–2yŠü²Û7nÚåÝŒg½cä×a¬xÒ=GKÔlÛL5äÒH<Ë¿2(‹ËænT+ò¸åw)PGU&¹¦“Mó [K°›Ü€nT¥~ACrOqÀ ÖºpÓ®âý´lïÒÛ}æU¡E?ÝËO?øb®O­7-ž3Ö–Ž+¬æ'ÔÒQE 8¦{æŸAéM g#Ž;×Ð?²¯üˆÚ¿ý†_ÿIíëçæ8#=«è/Ù[þDm_þÃ/ÿ¤ðWÎq_û‡ÍÖIþñò+þ×xÿ…m§çþƒ虨¤ý¯?ä›iý?ä1þ‰šŠø +Ù™ä|Þßxýi)[;ŽzçšJýðãè–ì(¢ŠÐAEPEPEPEPEP_kü8ÿ’yá¿ûÚÿ蕯Š+í‡òO<7ÿ`›_ýµó\Mü(zžöCüIúôWœüq»ñE©ðiðÌɨ·ˆͬr*.¢‘i÷³›7/òªËåÞÙY\  ¬ÏxþkKÄm¡ÄòmKÅÉ¥é^ÝIm »&os,RŽðm1\îO,°”•eRY—ã§=fŠñŸø[Z­¾«âF}'ÍÓtí6ÆÜØÅ#HñꯪÞé̱ùp´’Âò@>p»ÂF¥agvAµgñ3[ŸC²¾“À·¶ÓI©ÅÔ“YÂÇj2æÞS Ž?:8"iUã2©1@=2ŠòÏŽZþ³¢M4ºV£5£Xø7ÄÌ3òý®Ù-RqÒEQq/ÈùBJ±RÈ…nÛx×QÒfM>M¥éÚv…©Ü6³-ÅÌw—)l# "ÍÄ@ÝÀi$ŽCûÆØHÀ=Šá´¯]\ü+ðçï4Hmå×%ÓÙEzeXRúæQŒ†5ÜÊ“«•ÚAPqóV-ÏÅ›¡m®ÞÙøjm<5åÞ´Òê&9Ö ËÛ`Öê"a4¬,'-Ú%£]ç,ÊêtW™ø«â¿öÛÄߨ?hÆ¥­XýŸí›ä û÷l?ë>ÁŒcåóz¶ß›¦ñ7ˆu]OÐíãÒ,®5ýfäYÁj×ì–‰8·–â@ÓùEö‚P¬"%›`* ’ 5äÓük°³KÏí#ìÒXùKrË:†KB+â„G–H"Òî§RB´ª¡B£°RMñ~üKâ)`ð›aá»k›íNèêJ»m­ïoíœF›2ó2ØÔ;™ZHö©Öh¬kÍwìþ8Òü3ö]ßoÓo/¾ÑæcËû<¶©³n9Ýöœç#:ñÂØ|]‘ôêš×J /ˆ¤òïQî fóä1FÁX“"`âE‘ãÝÇ"J@=NŠò ¼{®ëZ]Ï¡j~¿Ó¼A¢Æ’ˆïc¶¹†îú;icÿJ··iXFò†S*o‰Õ·åú̓]=»ßC m™â†S,høù•\ª–PrRG8(j(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€1|sáôñG…o´'»’Ïí*¥'CÝ:œÜ£#ŒŒŒŽµägà NOŽc$õ'Gäÿäj÷j+ÑÂf¸¼(NÉ벚9kà¨W|Õ#vxGü3ýÿýñà£ÿ·Qÿ ÿÿC¼_ø(ÿíÕîôWWúÇ™ÏßÂ?äcý•„þOÅÿ™áðÏ÷ÿô;Åÿ‚þÝKÿ ÿÿC¼_ø'ÿíÕîÔQþ±æ_ó÷ðùöVù??ó<'þþÿþ‡xðOÿÛ¨ÿ†¿ÿ¡Þ/üÿöê÷j(ÿX³/ùûøGüƒû+ üŸ‹ÿ3ÂìÿÿCÌ_ø'ÿíÔ‡ö~¿?ó<Åÿ‚þÝ^ñEëeÿ?ÿea?“óÿ3Âìÿ|:xÞüÿöêìÿÿCÄ_ø'ÿíÕîôQþ±æ_ó÷ðùöVù?þg„Ã?jô<Çÿ‚þÝH?gÛïúâ?÷ÿíÕïQþ±æ_ó÷ðùöVù??ó<'þþÿþ‡x¿ðOÿÛ©ìÿÿCÄCþàÿýº½ÞŠ?Ö,Ëþ~þÿ þÊÂ'çþgƒŸÙúüõñÌ_ø'ÿíÔ¿ðÏ×ßô;Cÿ‚þÝ^ïEëeÿ?ÿea?“óÿ3Â?៵úcÿÁ?ÿn¤ÿ†~¿ÿ¡æ/üÿöê÷Š(ÿX³/ùûøGüƒû+ üŸŸùžÿ ýÿCÌø'ÿíÔƒö~¾ó;Åÿ‚þÝ^ñEëeÿ?ÿea?“óÿ3ÂáŸïÿèw‹ÿÿýºþÏ÷ÿô<Åÿ‚þÝ^ïEëeÿ?ÿea?“óÿ3Áÿ៯ó“ãˆýÁÿûu/ü3õ÷ýÐÿàŸÿ·W»ÑGúÇ™ÏßÂ?äÙXOäüÿÌðsû>ßùž"M#ÿ·W¦|+ðT^ðÔšJj2jÏr×3NÑÁbª *‚p¢÷<ä÷Àë(®lVoŒÅÓöu§u¾ËôFÔp4(KšœlÏý¯À? 4ìÿÐb/ý5~×ßòMtïû Eÿ¢f¢²¡ðFeüsç;˜·©Í%ÇWè´‡D|ä·aEV‚ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +û_áÇü“Ï ÿØ&×ÿD­|Q_kü8ÿ’yá¿ûÚÿ蕯šâoáCÔ÷²âOЋƺ…4»ûÄ÷QÛIgt÷:|Ž\›ÉxXü¼ÝÎã ‘ógŽ2mOଖú„1j–Ú‘Õg–Êk‹YEãF±¼ñÉW‰Ùk+¸3îÎ÷ÝÓxÃþJ'¿ëâ÷ÿIZ¼÷À_&¼Ñô=w[ñwƒ5›kÍ5¯õ› ÒAu¡D¶os$ÓââfdFŒ@A ySpñÇÓ›ŸÚ~ÇöUÔ- ·ÙÒk…’Açyë#È÷™f-*ÎÄÊ’<ެÜ´/sðFK­'Ô¢¸T•ä’Yïnäžè8U’;‰™Œ—:Ç´R³£,Q©R¨€vëãÏ RÛN7W±Íqä®étÛ”Š %Uh¡žVŒ$0xñ ¬’$cn]AÅðßÅ ê^Ð5ýCíºkêÚl:„Ð}†æUÓãpr÷€†Ë&ÙåÙ¬nêJ© #ÅúÿÃ/ê–×7þ)´{oìÛí&öÕ’M·6wkš—k#î‚,8' æ e•ÒkÝ{àý爗^ŸY‰®üØæxÖêåm¦šHŽîÞÞYlƒLªÐ£]"˜äDg ÞlXÌMÀޕℚ]ÆŸqc«ÚE6Ÿmqmo!y™¶\I³—-“#É$Hí#îvl’rÌM(u?‚°èwZ$z…¢Ø]èèÅç\|ö¬«9ÎFyFàwÜ“†ü2øºšÇ…†¥âˆ¶^Ëö3®¦ÜÝÊë&—cw+ù1 dز]•ߪ%'sÞªø§BÓ´;Mj[ï´Ù^ìûXÄ÷y½K¯“!ž\ gù|ŠÍ÷TÇxŸÄÿ …˜=þ¦WÊA"è—­âá^ÙÄ%nU¤¸€ pÂE#*sZzï<3 Þ_Ûk7W¶a¶’æY§ÓnRÝÒ8LÎ"˜ÇåÌâ5w1ÆÌøGãälTÿ…¡àú­?ï—ÿâhÿ…¡àú­?ï—ÿâjÞ‰ãÏ ë¤:e¥ÕìW“nUŠóM¹µ"@¥Ì-çF¡fòÁ”Bq!‹(CUÝWÄúF—®ZhúƒÞÁ5ÞÁía?Ù7;DkžJ;0 +¨Î™K¨ ÿð´<ÿC5§ýòÿüMð´<ÿC5§ýòÿüMlxcÅ:‰~Ñý‹}öŸ³ífÌOøß>\ÑïÌ…ö¶É“toµ¶³m8ÌðßÄ_ +ø†Åï4«NH…‰Ô!Yt{Èd»·%ºIµÂÉþ¨?2F:ºä/øZÿ¡šÓþùþ&øZÿ¡šÓþùþ&¨x›âdžt¿ ßj6m¼¿·Óu èôélnmåÿC…e‘'mr²Cƒ*®á4eCn\ôú¯‰ô/C´Ö/^ö8o6 hÂw»™™K„[eC1p¡™“fåTrÀb1ÿáhxþ†kOûåÿøš?áhxþ†kOûåÿøšo‡¼qmâˆhZYßa‰¢f6“ny$¹š±[¼Mm"´R1™ˆÂyÏÛü_²>&³²½´šÒÒYuÛF‰,®.nn.4ûÛxì艺ehä–F£íØÀ°ò¤4ÑÂÐðý ÖŸ÷Ëÿñ4ÂÐðý ÖŸ÷Ëÿñ5m|{á95Kk5o´ý§ÉÝÛÛË-i•Zk¤S<ã(Œá›Í‹ù‰º–§ã_ìÏÿn[ï¶ðæ›·ØÓ.ö- ¿+n` Þm­× °ÃÎK`ßð´<ÿC5§ýòÿüMð´<ÿC5§ýòÿüM7Ä~-šÇÆŸØÑÝYXÙZ[XÉ{=ͬ“3Ë{|¶Ö±D‡Þò®Q™¸FxæPëF‘ñKÀš¶–u=?]ó¬Í²\Ã/Ù'QtŒÈ€[å¸q$‘ÄÑŹÖWHØ`¤ßð´<ÿC5§ýòÿüMð´<ÿC5§ýòÿüMeh?t›»xßC©¤Vº¿Ø´ûXt+æ¿’³´šI$µ™‚¬—K˜Õ@h‡WRÝ5‡]ÕÇ‘äÇÀçwÚ`ù†ToäŒ61|?ñÃ7Öú<'Zûl×öÖ¯öë}.æ+#$ñ£Ä­#KwIHe“ÌýìC’ë¸ßð´<ÿC5§ýòÿüMð´<ÿC5§ýòÿüMKð«ÅñøÃÁº>£+ÂuI´‹ÝF;hÜC×,¾Xc fâʯ7¥©hú—%ø³«hš¯‡äÑl,mµŽ-"d¹t¹’î4ŒÊnYC'Ù”—òðûˆ +hÇü-ÿÐÍiÿ|¿ÿGü-ÿÐÍiÿ|¿ÿRÚ|Gð}Ëb=NeW–íä–Ââ8îÄÓÇr[» [ˆŒ“B<Ø‹ ÆKu&âxËïâÑáHï&“Xóf‰ ŽÎfT1CÎ]ÂlE uoó3LŠ –â€3¿áhxþ†kOûåÿøš?áhxþ†kOûåÿøšìh ;þ‡€èf´ÿ¾_ÿ‰£þ‡€èf´ÿ¾_ÿ‰®ÆŠã¿áhxþ†kOûåÿøš?áhxþ†kOûåÿøšìh ;þ‡€èf´ÿ¾_ÿ‰£þ‡€èf´ÿ¾_ÿ‰®ÆŠã¿áhxþ†kOûåÿøš?áhxþ†kOûåÿøšìh ;þ‡€èf´ÿ¾_ÿ‰£þ‡€èf´ÿ¾_ÿ‰®ÆŠã¿áhxþ†kOûåÿøš?áhxþ†kOûåÿøšìh ;þ‡€èf´ÿ¾_ÿ‰£þ‡€èf´ÿ¾_ÿ‰®ÆŠã¿áhxþ†kOûåÿøš?áhxþ†kOûåÿøšìh ;þ‡€èf´ÿ¾_ÿ‰£þ‡€èf´ÿ¾_ÿ‰®ÆŠã¿áhxþ†kOûåÿøš?áhxþ†kOûåÿøšìh ;þ‡€èf´ÿ¾_ÿ‰£þ‡€èf´ÿ¾_ÿ‰®ÆŠã¿áhxþ†kOûåÿøšê4»û]OO‡P±—ͶwÅ&Ò»—±€p{ýjÍEiþ©¿ë£ÿèF€<{ö¾øk§Øb.ÿôÆj(ý¯Áo†ºpô‹ÿDÍEvÐøŸÌŽ|Þzš(=OOŠýðãè›–áEV‚ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +û_áÇü“Ï ÿØ&×ÿD­|Q_kü8ÿ’yá¿ûÚÿ蕯šâoáCÔ÷²âOÐÍñ‡ü”O×Åïþ’µ7þ_ø²ð­?µ?æ[þÂûÙÿéÛÈó|½ßð-»½³Þãù(žÿ¯‹ßý%jìkã§8mWÀwWž"¼ž=n´]KW²Ö¯íȵË]ZýŸÊò§ó¤Gìvû•¢v?¼Ã®åÙÌÞ|Ó§‡IæðýúØih~v¯áدæŽÎÝåòÜÈû"¸Ù)#$‘»"7”ª +_¢€<þ‡·÷:^¹á‰üMåøOVþÑi--ìUow_4Ï0k‡fBŠ÷2‰mˆ`®$Ô°ð¾³müI{â(d"Å`º†ÛOòLî olÛ‡ß*#‡–7‘öÏ廯ÝeÆKà\øÚ?Ūl„kk­ÉlÖû™§þÍ—Oe¸†3 ´É'$8òz—Àí:óSšúi¼?}-Ü·BæM[ñ_I2ßÝ]¯Ù ¶Wí’)wYUÌq +U½~ŠÆ¼Ð¾Ñã/ÄßjÛö 6òÇìþ^|Ï´Kjû÷g¿fÆ0s¿¨Ç>sá_Úvƒ¨è×"oß5”ZyžöïñK¨™¬íà>ÏpîD0¶Œ”Øì¥å+"³+'¯Ñ@Màÿ„š¯ƒâ²ºðÿŠì¿µ­-’Íf¾ÒZkvƒìZ}´€Ä“£o-¦Äá¼Ì(wR¬pãO[ø[k¨xBð›\i—–ž–ÜèñêúX¼’+Clî-ê'l<® @7–pvþEy—ÂxmµjQjvV÷^ØÚJÙi1ÚÛÙ4·ú€ŽØ&ˈ]`PûÚ ÷<…¦øSð¯Nð ð–Ê?¬Vö?`µ’ÇAŠÒîhrŸ5ÝÆæiåýÚe“ÊRÅÙ’ž_£Q@2~x“Ä~ÕôOkVZu„š—ˆ.4È ÓË\B×Ï}K,¾yISɼyj‘°%aµƒuº¯€î¯§Eqš°¼Oa{¤êŸdÑl4Øôø4ô·ÌžLh8^bß¼…0dPèÒ¬!äx›Ÿø™ðÏ_ñ§ˆítC§Xø‚_´ßÚÉnâiœÚ%¤‘$ë'—RA¯ï-ç(ÌÒ(,±„õ:(ÏüCðöÿR×.î,üMö2û[ÓõÛËO°¬’MshÖ 'šX…£´å +Ióy…3‡ÀõŸÚXézW‹!XŠÄê*Ú^nn&¶´·µýÔ†B‘Dékä1ÈÃt›dRT§£Q@gÂÿÿ¡險yºm®›½Å±·ÚtŠŠnb“æaÚHþeg!Æ×2´»VzÙüqªx›í[¾ß¦ÙØýŸËÇ—öynŸ~ìó»í8Æ6u9ãfŠòÈ>]giv7^%†H¼;c —‡ zqF…!¸´¸ŒÝæSö†ßalËòn—Sßü;ÖtŸê>,—Åßë±^Òé{aŽkˆtèÆ$ÅÓÆvâ²ÒS#ú5QEQEQEQEQEQEQEQEQEQEQEQETVŸê›þº?þ„jZŠÓýS×GÿÐxïí€Û~iÇþ£1虨£ö¿ÿ’i§Øb/ý5ÛCà< ÆÞØùÃŽÝ;QF6ñéÅú-áÇÑ4÷ +(¢´QEQEQEQEQEWÚÿ?äžxoþÁ6¿ú%kâŠû_áÇü“Ï ÿØ&×ÿD­|× +§½ÿ~†oŒ?ä¢xþ¾/ô•«±®;ÆòQ< ÿ_¿úJÕØ×ÇNQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE§ú¦ÿ®ÿ¡–¢´ÿTßõÑÿô#@;û` ü4Ó¿ì3þ‰šŠwíx»¾éãþ£虨®ÚóùŒ­\ù´ŒúÒÒFikôZ?â>mîQEh ¢Š(¢Š(¢Š(¢Š(¢Š(¯µþÉ<ðßý‚môJ×Åö¿Ãù'žÿ°M¯þ‰Zù®&þ=O{!þ$ý ßÉDð7ý|^ÿé+Wc\wŒ?ä¢xþ¾/ô•«±¯Ž>œ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š*+OõMÿ]ÿB5-Eiþ©¿ë£ÿèF€<ö¼8øm§?æ1þ‰šŠ?kÏù&Úý†"ÿÑ3Q]Ô>çs+{‘óh9ÒÒ”µú%áÇÑ:÷ +(¢´QEQEQEQEQEWÚÿ?äžxoþÁ6¿ú%kâŠû_áÇü“Ï ÿØ&×ÿD­|× +§½ÿ~†oŒ?ä¢xþ¾/ô•«±¨å·‚YI`ŽG@B³ $Œ€}ð?!Iö[où÷‡þøñÇÓ’ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÑQ}–Ûþ}áÿ¾e¶ÿŸxï@ÔVŸê›þº?þ„hû-·üûÃÿ| +‘QB¢…QÐ@7û^‚~éøÿ Ä_ú&j(ý¯F~éüÿÌb/ý5ÛCà>w2þ?ÈùµrT×´Øþâý:¿E£ü8ú#ç^áEV‚ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +û_áÇü“Ï ÿØ&×ÿD­|Q_kü8ÿ’yá¿ûÚÿ蕯šâoáCÔ÷²âOÐߢŠ+ã§ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¬ïj/¤xgTÕ£e{+9®à1D,úâª1rj+¨¤ÔSlÑ¢¼ Cø±ñCÄI,Þðž™w ,B°ÈÛIçó[oŒÞ+ðýäpøÓÁMkœo‰^,ú•ßß@ßzo&ħʬßk«žzÍ(5Ìî—{;åEeøWÄ_‰´Xu}"àMm/Œ20ê¬;þx5Ä|+Õ~$_ø¯XƒÆy·Ó¢Vò €"¬›†6o]»¹ç æ¸£†›ŒÛirîžäuKâ–¼ÝVÇ¥ÑEÎnW3ñKľð&£¯iñ[ËskålYÔ”;¥D9ƒÑz«ðƒÅ‡Œ<³©Ãk ÃO$emÕ•0§Ž“ú×BÃMÐöÿföù˜ºðö¾Ë­¯ò; +(¢¹Í‚Š( Š( Šâ¾2xÒoxQu(­æ¾žáa'§rÄ€AÀ÷êEs¿¾'j¾0×u ^³²´º‚,+o¡;[k«cÈÊúw®È`+Oñ {¨å–2”k*-ûÌõz(¢¸Î ¢¼§ã‡ÄsÀú®i¤ÚiÓ¥Ì #›¨Ýˆ!±Æ×Zõj諆*p©-¥{|Œi×…IÊ xÚÿ0¢ŠòŸ…_uÏøÿUðþ£i§EkgÒFðFê䤨ƒ$¹öëE,4êÂsŽÑÕ…Jð§(Æ[Ëc;öÀü4Ó±ÿA˜¿ôLÔRþ×­·á®œê1þ‰šŠÖ‡Àx™“~Üù¶?¸¿AN¦ÅŸ)3×h§Wè´‡D|ãÜ(¢ŠÐAEPEPEPEPEP_kü8ÿ’yá¿ûÚÿ蕯Š+í‡òO<7ÿ`›_ýµó\Mü(zžöCüIúôQE|qôáEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPXÿäžx“þÁ7_ú%«~°>#ÿÉ<ñ'ý‚n¿ôKV¸âÇÕÖþ½æ_²gü‹ºßý}§þ^³âÃÄzÖ©B²Ap…rFJ7g„Ey7ì™ÿ"î·ÿ_iÿ W |Lñ¶—àíââ{˜Ž¢Ñ‘ik¸‘Èà㲃É=? +õ3Tže%K⺷܎ ¡ ]M¬ÿSÉ?eKû‹ëz ¹1=·Ú +ç $ŽØØÎûV*‹=vnæã'óÁ¨þ€i]t šß¼jïiÂùI‘y Üš™ºñTè{(µ$¯¦ºöì8*³Ãί´w‹v×·~ã>,ëVÞ"ýŸou»E+ä6Ò=Pý¢<©úGá\ÇßÚx'àBêì–ò[¹ã³€Ÿõ’drÙIü:‘Lÿ›Bÿ?ô¯2ƒÃ> ‡ðxÎ)Vm>ÆìÄ»ÊÉ©ãir϶x­0¸J2£:3vЍ׭–‹æF#V5cV+WM|µÕŸ@|—ÇÚ¶Ÿý¿âíaÚÒá?Ñ,ͬQ–þZ1TAžsŸJÉñ/Äë¾6¸ð‡ÃË[V’Ï"êú|R§ ŒðŒà’z^×ᇌ-•—ðUñF¿á5¿ê&ìÜÎVÐyÆ4àŸ‘FrÛ‡?ݯ ÔüSuâ_‡ðE±ioc¾h™sË…€}1!ð +ú‹BÓí<9á›M9%¶Ÿj¨\ñ¯ÌÇëÉ5ÍŒÃG†öm{ò“×­–Ÿ‰¾,UhŸ»½.ÿÈñ?Ž27‹~.è €³EEŸiåL„3ŸÂ5SùÕOà?Ú&ÏXP°Ø_#ðÍüuär´þ|îË嬅•P­ÎÜ 5câÿƒ~ iú<ß‹u«MZe!ŠWw‹~NNQ~\¨z‘^Õ*P¥8a¥5n^VºÞZ³Ë©Ru#:ê.ü×O¥–‡ÓZÆ¡k¤éWZôž]µ¬M,­ŒáTdãÔûW„é¾:ø­ãýVéü ¾§Û¶2ÑÆ@ƒ<€å¢ýk¤ÖµKþÍÞÛ³=бE¸îs ‹æ“õÇèi?e­GO—À÷:dRF·°^<³GŸ™•‚í|zq¼j#†ÃT«()J2å×T¼ìzuªË^8ÉÆ-_Mò<“ãN©â«Í^ÆÃÆ|VºŒ|ȾåÂ1ÈqŽ;Çä"½ëã7Ä%ð.‘µ†;Rð‘o™ØŠ1¹Û‘Èdg>Ƽ£ö©¿²¹ñ†io×ñWY»ÙåùÚ|òmÎvîž#Ö¾…‡VÓ%Ñ—YKës§4^wÚw€›1œ“Ú¾}ýšæŠãâÖ·qú©l.8ÇÊgˆŽ+–…m…Ä?f£eÑ[äΊ´}–"¾åwÕÜêkõÝð×NÇüN"ÿÑ3QGí|qð×Nÿ°Ä_ú&j+Ç¡ðæMûsæáÐRÓc9O¨_¢Ñþ}óp¢Š+AQ@Q@Q@Q@Q@}¯ðãþIç†ÿìkÿ¢V¾(¯µþÉ<ðßý‚môJ×Íq7ð¡ê{Ùñ'èoÑEñÇÓ…Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@QñœºÆ¨é-)…ome¶2É@èW8ïŒÕê)ÆN-4&“Vg‡Û|¹´v>;»¶‰ˆ,±Ù•'ñåZÚÀ Z] ^þÿWprQØG}@ùýõ^µEz3Íñ’Vsû’_’8£–ábî¡ù¿Ì†ÊÖÚÊÒ+K8#··‰BÇjTÀ•À|%øaÿ£}wý¹ý£ö¨V=¿dò¶àç9ÞÙ¯E¢¹!ˆ©JzK;2¡NRŒšÖ;uá†ØŸ¯üeý¹öµÍq'Ù~É·gšÅ±¿yÎ3éϵoüLðŸü&ž}íÿaÝ2Içy>f6ž›wç]5RÆV•HÕr÷£kmÓb#…¥:ih÷ùœü+Ÿø´ð¯ÿ¶í÷ìßôñç«ßÿûÞþÕ£à[øgÁoá‹»¥Õ-äi<Öh|°êýT®ãÛÞºÊ(ž2´âàå£|ÏmûŽ8jQ’’Z¥o—cÌ~ü*¹ðWŠ¥Õt¿;ØÍ¹%²’ÏïÇœ¨/¿ï/m¾¼`‘V~"ü$Ð<]~Ú¤sÍ¥êO2xT2ÉŽ…ã'ÜïšôZ+G˜â]_mÍïm}?ÿ2 +‚§ìù}ÞßÖÇX|nb}KÇZ¥ÜQºº¢C°‚AË;Ò½CÅ> Ѽ7¥K¨kW±[Àªp¬~i÷Uz±ö«\gćzWŽn´Ùµ+›‹qb\J­·å$ƒŒôîj¾´ñUcõ©{«²_§r~®°ôåõxêû·úžEû;xb=kÆ÷ž+ûƒL°•ͬg‘æ¾v¨=ö)ÏÔ­{ß‹ô©õÏ ê=µ÷Ød¼„Âgò¼ÍŠÜ7Ë‘œ®G^õ>ƒ¤iÚ•—¥Z¥­¤ ~¤ž¤“É'­^§ŽÇKˆö«Kmò}›ë¿Ìã>ø +ivk~/纟Ìyü+å +®77O˜ç?Å[^6Ð ñG…¯ô+‰<¥»jÉ·w–À‚­ŒŒà€q‘[4W4ñ5gWÛIû׽ΈЧ~É/wk_ÂÏÉà÷HŸW]ZÖæ_4+Zùa ]¬ÜÙéÐú×®üÒ®5g¼Ñ5Û"mÞG“æ„ÏP­¹H\ײÑ[C1ĤªFZË}µùlc, ÁS”t[oùîxÞµðH¹Ò¬,ôÝf[9 i^âæ[a3Ü—ÙŒá—h]§Ÿ¼Eñׄ´è§LÕâl+o†hÎ$…ñÊ¡àÖý51øŠŽ.SÖ7·Ì¨`èAIF:=þGŠé³þà:‡‰o.ìîû,p·{Ü@ uøc„¼sªxŽ×SY ½ŽXã²[_,@¯*¸·… · ¯B¢´«šbª§ÎééÓüˆ§—áé´ãW©âÿ¶áYéØÿ Ì_ú&j)l ´ӳÿA˜¿ôLÔTÐø31¾>]‹µJ;QEl!îMsþ¬~ʘÔŠ( žƒGSô¢OõcëE ô!^‡ëJŸë?:( ·±$?y~´Ë¼ßZ(¦Jø‚µ<_y¨¢‚f1¾í$]?( :Ÿø~”ŸÇE  ÷ÿT?:ÑE1-‡¿SøTK÷ÿ +(¤Ê[~ã}jYÿãÚ?­PŠBÚt“éRÇ÷ŸéEÉ‘Ÿwñ¤©¢Š}EÐeïðUy:¥RfÔþËÐÐ(¢’+ýÑõ¦ŸõŸPÁlM'Þü)‡ï(¦‰AÝ4§­Pqï¥T€Þ˜~úÑED“øj%ëE +=Ij;š(¦  ¥R@3½J: +( r}ÓM=(¢¨‘žý(¢¤:þ*“¿ãEÁË÷é©¢ŠE­‡ +Þ¢Š øH:QE!Ò¢þ#ExÿÕÕs÷袀†ìž?éHÿvŠ)‹¨È¿Õ­<«4QB·>éúT#¡¢ŠLQ ;})Ñ÷úQE1½†·QHh¢†41i{(¤PÁ÷©§ïQE¤=úŠ`ûôQ@!ïژݨ¢ n´QECÿÙ +endstream +endobj +849 0 obj +65434 +endobj +850 0 obj +<< +/Type /XObject +/Subtype /Image +/BitsPerComponent 8 +/Width 616 +/Height 581 +/ColorSpace /DeviceRGB /Filter /DCTDecode +/Length 851 0 R +>> +stream +ÿØÿàJFIF``ÿÛC  + + + +    ÿÛC  ÿÀEh"ÿÄ + ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ +%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ + ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ +$4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?ìmûøNßá'…üsã h¾0ñ‹´èµÔ^µTÓ´Ë+¸ÄÖ‘Ei0kvsm$R<’Fò,’º«*¨è/ö3е»nì¿g¿†×v³®ø¦‡á6“$r/ª°²ÁJÂø ¹ý›~ÿÙ8ð¯þ˜ìkï¿­Œz´­y.Ÿg²Î±Ü\Áo ”Gw4"óÑ•8∕@ï2†±ñ7Ä5ÂØZ8ú´UHÉ77få¼R²K]d¯µ‘ñYNñ•*P§7Á¥´_Ö‡Ä÷Ÿ±nƒ¥ÚIsyû>ü4³·„n’YþéÇõ,l€ëUmf‡—@cáÁ^êœèü‰_|x2Û7±C,Ûî6æK@¤-¡’Þ$€ËÌ…nŠÁz+âڛĿ€¿gMgQðö©6‡¬ ìm`¿‚&–ÔM{.è³$‘ #cz0Ïc^…þ*ËŠkæ8|^4žj>ë¿72nú¥nšt;sŒ–x'IS¬åÏ}Ý­kvõ3­ÿd_‡Ž2~|ÿÃq¡ÿò%h[þÇŸ ä^~|ÿÃs¡ÿò-rŸþ#xƒöV×µ¯ x§â‹üS¢ê~Ô á¹Ñ?ù‘¿co†ÃþhïÁ_ü7:'ÿ"×1ðWþ +Aá?ösÕÁG~~Ñ:–Ÿi¤Çh÷ú­ÎˆÓ5Z[^Åf·Ë \Ø]ÜÀæ[o6D1Hê>Ï29ÀFšXÌ<Ò|‹Tž©õLO/73ûßEw×±PþÆÿ ÿèŽüÿÃs¡ÿò-5ÿcŸ‡ +äŽüÿÃs¡ÿò-iþÎ?´eÇÇ_Ú ÅíÞZx%|á¿èöwöÐÃ4mŸWNÅrØ–+[v +îv€>TbâªéßðQ.‡kâxÆ>ðF³¦^kŠ5{kOìïZÛ[½Û=¼p\KtŒö±É +?ê›è_ü‰X—~ð4-Ç¿‚£þ鶃ÿÈ•ÖêÓCë\–¯sµ^+²nùÜŽ9f¸•ÿ/ÞÌû +ø% ~ á¶Ðù¨ÜxÁ±ôø_ð_ÿ ¶ÿÈt^êž••{©`õÍtÃ*Ã?ùv¾äsË8ÅÏÉ}ïüÉ®t¿ÆN>ü÷MtþCªW~Bvü4ø/ÿ†ÓÃÿü‡UnõƒÍfÜ_çŒ×T2¬/Zkî_ärÏ7Åô«/½ÿ™ztðÊ“†¿ÇýÓOÿòTžo/O†ßÇýÓ?ÿòPžðžõXÜœ÷®ˆåOùõ¹‘Í<çÿ?e÷¿ó/ÉuáõéðãàÇþ?òC%î…ÛáÏÁÿtÏÃßü…YòÜ.­BÓ—ô­c”`ÿçÔ~åþFO9ÆÿÏÙ}ìГPÑÿÉ:ø1ÿ†ÏÃßü…P¶©£Ÿþ û¦^ÿä*¢íÇ^j6úÖ±Ê0_óê?r#ûcÿ?e÷²ûjº8ÿšyðgÿ —‡¿ù +˜Ú¶’æž|÷L¼=ÿÈUA°½zÓXMe8/ùõ¹ý³ŽÿŸÒûßù—›ZÒsÿ$÷àÏþ/ò'öÖ“ÿDûàÇþ/òPdçž´Ó(YN þ}GîAý³ŽÿŸÒûßù—ι¥ù§¿ðÙxwÿ©?¶ô¯ú'ßðÙxwÿªR)¬»ª¿²0óê?ríœwüþ—Þÿ̼ú á²ðïÿ!Tðé˜ÿ’}ðkÿ —‡ù +©`úc'_J?²0óê?rœc¿çô¾÷þeïøHtÅ<ü>ø3ÿ†Çÿü…V!×´—?~ û¦^ÿä*ÅaƒNöÒyF þ}GîE,ãÿ?¥÷³£‹UјsðóàÇ?õL¼=ÿÈU Ô4Qÿ4ïàÇþ/òb[IÆ?*¸ÍÙ8/ùõ¹‘K7ÆÿÏé}ì¿ý££Ñ:ø/ÿ†ËÃßü…N[ýƒÿëàÇþ/òP ¸S‘M(Á[øQû‘K7ÆÿÏÙ}ìºo´_ú'_?ðÙx{ÿ¨ú)?òNþ ÿá²ð÷ÿ!UB‡Ýœ÷ÍGöN þ}Gî_ä_ö¾7þ~ËïeÆÔ4Qÿ4ëàÇþ/ò9oôB?ä|ÿÃeáïþBªTлOµÙ8/ùõ¹ÖmÿŸ²ûÙy¯´En~|?÷L¼=ÿÈT¿mÑ?èœüÿÃeáïþBªTPò¬üú܆³lgüý—ÞËmy¢ÿ$ëàÇþ/ò4ßh˜ÿ’uðcÿ —‡¿ù +«u¦”¤²¬üúÜ‹þׯÏÙ}ì´/ô\óðïàÇþ/ò;íÚ'ý¯ƒøl¼=ÿÈUA—u'*}i¼§ÿ>£÷!¬Ûÿ?e÷³CíÚ'ý¯ƒøl¼=ÿÈT«y¡í9øuð`‘ÿTËÃßü…TȦ»m©þÉÁÿϨýËüŠY¶3þ~Ëïæ\“RÑÿ’uðcöL¼=ÿÈTÑ«èdÿÉ9ø/ÏýSògÊ»@àî¤òŒüúܿȥ›búÕ—ÞÿÌØþÕÐÇüÓ¯‚ÿøl|=ÿÈTѬhcþi×Áü6>ÿä*Åi¸¨Þ|Ëû'ÿ>£÷/ò5Y¶/þ~?½ÿ™¾5 XŹø.î™x{ÿªÄ:·‡äòN> ÿá²ð÷ÿ!W*×8<ÿúéc½Áö¬¥”a?çÚû—ùG6ÅÏÉ}ïüÎÆï±¾|ÿÃeáïþB«ÖRøbFù¾|?÷Lü=ÿÈuÄÅ©zâ®ZjûÖÊpËþ]Çî_ätC5Äõ©/½ÿ™éºF›àÛ Ÿ þ +1?õM.øÿÇ>‚m[F>Òbœ]34ÿhóØnq´,~çßo½Û§øëñáN‰ð¾þçá¿Å_ŠšïŒ£–ØXØêÚQÙÌ­qÍæ7öT8Û•‡ï•~éùЏzp«ì\ïkÛO¼újS©:^ÕM[{_SмMû1ü½°±~ |RúÞ~è±3#ê¶‘ºåmÚÈì¤t!ˆ<»'ìáð(±üø4ÒÈ‘G|9Ðw;³P3l$ޤ +ù{À¿|gªx‡NŠïP/ ÖtC³Æ9þÚ°ôZ¯àï~0‡ÅúT·ú©P^Ã,ÍöXÎÕY‰ásÆ;WD²´¥$’ÑÑÌn•ï«ÿ#ëÁû|'ïû9|?÷Oü5ÿƪµ¯ìÑð]ë'Àß0Ë‘¿Ã r21VÄpAèH¯_ˆöÇÇŸÛGÇi·ûGíþGönÿ[æló6çÛ?§jä¼IñûÅóx¿U–ÃT-c=ìÒÂ~ËÜ­#0<®yÏzÆž]ÌõKnÆÒÆÚÖoï=5þ|ð¬÷–±üøÈ5`)Ÿáæ‰;]^ö4PÏjHUDUUÎTU›‡$ëðcà)ÿºi ÿò%|ŸñŸâ—Ž ñaûû,O­1ÿGŒå¿·µ1Ý}¬+âŸÄF:ƒûu‹ÿ‰¯È3,ê­²ŠrÐþ¡áþ ÂbpЩ5 µÕ/ò>ÍÒ~ü-ño´¿ xwözø'â=WŽyml­¼á[W™a +Òk¨áGp­»b±r©#mÚŽEY¾|4±ðt>%¼ý™~éž›W]j—à XÿÄÀ¾Ç¶[y¢K™^'²yP¸Cù#É—gÍß +üQ«x³â>¼g¨xGÃöw ¨KªØi²Ín𺺠So ¼W°VSÒß1 +ì_·íwmûYÆú±âoø«Ã­6‘†5{. šÎI·-õ´©à î…<åw„AC% ݘ<ÇÚ`yMóYÙsY»uµô<\ß!Ž9†•(ºmÅJJ ¥~—ë~ýÞo†Ðqðcà/þMÿ‘)šOÃ_ƒ7ší»|øÉ<éð­´X Ç¥|ƒ¨|Rø†ˆq~ßø ÿLð/Å/ˆRüHÐïØÆú•¸qöXùjçøkÉÁçõg$›—õó>·4à< *r”T4]ÿ!¿µwì+à~ÈÖ~1ðO…´¯ øÛÃ?´Ÿ4ÚJ +]^Þ "Þêùn`\Dd0 ‰„Ê‹+ÊŠ˜1Á^ß<Ò]~Àw’ÊwK'ìó;9é–>bZ+÷*y¦# Fœ(ÊÉÅ?ÀþG¯–añ5êJ²ÕI¯¹ž…ðAsû5ü!<ÿÉ8ð¯þ˜ìkï»/‰~Õç—R±ñV›bšï™F¶¶nÄò ‘yŠD€arËŸ— +øà­Õ®•û*ü1Ôu šÛNÒ~øwR¼•c24p[øvÒiYT}æ axÉÀÈë^Çÿ Åñ/ÿ…Mñ+Ÿúoá¯þ]Wç~&xi€âì> bqµ0“¢›R¥%ù’ºnÏMϒ昼zïIMJZߥ›·æ}/įxx¥Üºæw5œË0¿‡W‚â{ˆ‚ö÷ æ&`¼Bê±UÒ|³ñGÁwÇ?…ú…¯õ=OHƒQ0¸¼ÓŒ"êÕâ™&ÓÎŽHò5áÑç ÖÇü3'ÄÕ/‰øá¯þ]TþÎ?àû¿ +~%àG†¿ùu]|ÀùOR©â]iÔQRœ’R—-ìäâ•ݯk»#lË™c' :¼·i-V¶ïé±ÅÇû#x{Ä^ñ|)ñ‡|g­øÏLþŹ׵i¬’úÆÃ!¾Ík½´V°¡p]ŠÁºF »>ÈÂô—Ÿ<+xº}CYUñ§¦Äñ|·¶ßfòã_Ýÿ©?e*rÇ-†Öÿ…ñ\ …_Çý¼xkÿ—TƒàŃÿ4¯âgþxkÿ—U÷1ž4Ôâ­·Þ¥ù«žt©c¥w*mßü­ù3Í´oø'§Ã ÁÚÆ‡£k+Ðtß#ͩǧ][@o5tníõSûƒ²þÞ\lš=»Ö8–a0Š0µ¿j_ÙïÄ> +éÿ .üCãßë¶·—~/Ô®4:_ ZA,/:cœŒg·'• ¬MÉc5ëÿþ+ÀyøSñ,ÿÛdž¿ùuVWà¿ÅP1ÿ +—âoþøgÿ—Uœc—¤£í—Nš4Í£,ÅË·×ïµ®sš÷ìéc7Æùüo¡xïÆ–ûKÓ´]GGÒ Ò¤Óu;K.¤[«¥A‹©‘¼™c%Xc\†•ûø/Zxs^ñŒ¼aàN½Òt k7–­§øzÚê -]-ä†Þ+§)k,F÷ÌñÆä)æ¯Po‚¿{|'øš?íçÃ?üº¨äøñ]Ç +>&ûxðÏÿ.«¡UÁ;Þ¢wîßõ¥ÝŒÿáE[–›V¶ÊÛ_qåúçìAáoøkP°ñ¿|sñ¯t¸t8®|Dút’ÚX%Ì72["Ágn³Éoœó$’H"P_ŠÙøàM'àW…îtSÕn4¸ytÍ6îHäƒC…¹v¥Q\[¡ÎÄ‘œÆ¤"Q°›àʼn—ðª¾&àG†¿ùuY—¿³Å{¼çágÄ‘Ÿúoá¯þ]Vô+eð—?´WÛ;üõêrb(æ5!È©;o²ím;'Šü@³³kŒ¿¿zõ›¯Øçâ¥ÑçáoÄ‘Ÿúmá¯þ]U ŸØ‡â¤Ý>üGö×Ã_üº¯j–s—E[Ú£À­’æSwöLñÍFôa¹®S_¸äà×аgÅiÏü“ˆ¿÷÷Ã_üº¬ÝCþ ÝñZõH >".駆¿ùu]°Ï²Õ½TqO‡óGµ&|Ë©_lsÍdÝ_’x5ô­ßü âÕÁãáßÄ1õo ÿòî©Kÿ°ø¹'üÓ߈Ÿ†ÿùw]1â<­ËäsK‡3Wµ~æ|Õ-á`rj¬óîôÓÿÁ)¾.1ÿ’}ãÿÏÃü»¨Ûþ Eñu¿æŸ|@üü7ÿ˺Õq.V¿åò2|1›?ùs/Àù}§5 ²Þ¾£oø$ïÅÖÿšñóðßÿ.é§þ 3ñoþ‰÷ÄÏÃü»­Weóù~?äfø[6ÿŸ2ü?Ìùi›m'ÞÁõ7ü:câïýÿˆŸ†ÿùwH?à“@#þ÷ÿòÛÿåÝWúÓ•ÿÏåøÿ‘?ê¦mÿ>eø-¶;ÔmžÕõ0ÿ‚Jü]=~ü@üü7ÿ˺_øt§Åßú'ÿ?? ÿòîšâœ¯þ/ÇüƒýSÍ¿çÌ¿ó>Ueçš]¹WÕþ )ñsþ‰ÿÄü¶ÿùwBÿÁ%¾./O‡ß? ÿòî¯ýjÊçúüÈ_ê®kÿ>eø+ì4ÒžÕõYÿ‚Jü\?óO¾ þ~ÿåÝ'ü:WâïýÿˆŸ†ÿùwGúÕ”ÿÏõøÿªy·üù—áþgÊ…=)»}«ê³ÿ“øºæŸü@ÿËoÿ—täþ.ÿÑ?øÿ–ßÿ.èÿZ²¯ùþ¿òú©šÿÏ™~Ê%1Ò™$…}\à’sÇÃÿˆ?ùmÿòîƒÿø¼ÃþI÷Äü¶ÿùwGúÕ•Ïõøÿ.Í¿çËü“vÓB{×ÖMÿˆø¼Oüˆ?ÿËoÿ—uÁ!þ/“ÿ$ÿÇÿùmÿòîõ«*ÿŸëñÿ"— +æßóåþæ|±nåOÒ¯DÙô¯¦ãÿ‚E|`R?âßü@ãþÅ¿þ]Õˆ¿à’¿£òO¾ ÿåµÿ˺?Öœ«þGúù¸W5ÿŸ2ü?Ìù8)Å1Ò¾Ÿÿ‡P|]óNþ!ÇÃ_ü»§è¾.ãð®þ!þ~ÿåÝëNUÿ?£ý|Š\-šÿÏ—ø™óŽ=i=+éñÿ¡ø½ù'Ÿ¿ï¯ òî”ÿÁ(þ.ÿÑ;ø‡ÿ}xkÿ—u/Šr¯ùü¿ò)pÆkÿ>eø™òøR…¯¨áÔŸè|Cÿ¾¼7ÿ˺ü—âçý¯ˆŸ†¿ùwKýiÊ¿çòüȯõc4ÿŸ/ðÿ3åð7zÒÁéšú‡þIñwþ‰×Ä?ûëÃü»£þKñ{þ‰×Ä?ÏÃ_ü¼£ýiÊ¿çòüÈk…óOùòÿó>_ +CzÐÉé_Pé¾/Ñ:ø‡ùøkÿ—”‡þ IñxÿÍ:ø‡ùøkÿ—”¬ù_üþâRáŒÓþ|¿ÃüÏ—]9¦ì5õÿ‚R|]?óN>"~~ÿååðê‹¿ôN~!~~ÿåå/õ§+ÿŸËñÿ!ÿ«9§üù‡ùŸ.•Ú3ÍDzó_R¿ü‹âógþ-×ÄOÏÃ?ü¼¦ø$ßÅæ?òN¾!ÿß^ÿåå Šr¾µ—ãþCÿV3?ùôÿó>Zu =ê´ªTúŠú³þ7ñþ‰×ÄOûëÃ?ü¼¦?ü[âû>|Düü3ÿËÊ_ëFUÿ?×âêÖiÿ>_áþgÉÒžj zñÍ}c/ü3ã‡þIçÄ?ÏÃ_ü¼¨›þ ñ…ü“߈Ÿ†¿ùyUþ³å_óú?ù¸o3ÿŸOðÿ3ä¹%ÁëPÉ6rE}jÿðG¿ŒOÿ4ûâþ[_ü¼¨_þéñ<|?øƒÿ–×ÿ/*å_óù~?äZáÌÏþ}?ÀùIoHÔÐßí=kêAÿqøÈü“ÿˆ?Ÿ†¿ùy@ÿ‚8üeþIÿÄÏÃ_ü¼¬ßeoþ_#Hðîgÿ>Ÿà|Ù¦k&ë‘]Ÿ†üC£wë^Ëüçã,l?âßüB?†¿ùyZZwükã-ƒÿ +ïâcßÃ?ü¼¬eÄcÿ—±7†E™-é3Í,5a"ƒŸÖºëÙê3=ÕÍÿÙ.¥†g‚çFþÕ²¹0ÄÅ8E»´–)„1Ç”£¬Qe.ãÞØÿÁ2þ0[¦ÃOˆÍô“Ã?ü¼«ößðN?‹Ñ~üH?öÓÃü¼¯?šåu’檴ììÏC –ft]ãMëèpj|ŸóðïþwŸüÐT«y`zjžÿÂóÿ—õèQÿÁ;þ.Fä—üIÿ¿žÿååL¿ðO‹jä–üJÿ¿¾ÿååyÒÅe+~,ô£C2ëKðGC¨[Ã=´–úæ…lö×–— Çà;’]­®¢¹E;µæK°Û<‰Æœæ#áÿü!îÿù}^ˆ?àŸŸÿ’Yñ+þÿxcÿ—”ôý€~-'üÒ¿‰GþÛxcÿ—•‹Äå·º­ø³eK1µ½—à9óôîŸÚ>Ïýˆ÷ü¾©b¸ÓÃq¨øxÜwÿËêô/ø`_ŠÿôJ¾%ÿßï òò¤ö ø²£þIOÄ¿ûûáþ^Vo—ÿÏïÅ—8ûéKðG”/aÔÙš_è7ÜÝ܆—áýÎðnnç»uùuåNáxÎй$ä/‡¶ð·_ðÉÿ¹ïÿ—Õê6Ÿ°×Å‹b?âÔ|M#þ»x_ÿ—•~?ØÇâ¬óI>'ßÿ ÿòò¼*¹'ÔwŸÌúª[Äôb£Nm%ä+ +ˆ5ï ÿáuÿËÚ_øB¢óðßþ7_ü¾¯X±ßÅOú$_?ð#Âÿü¼¥ÿ†:ø§ÿD‹âþx_ÿ—•‡ú»Ã]£÷³£ýuâ¿ùøþåþGÍànü‡ü4=ÿá»ÿåõCeð®Ö¿1üO§[®ït¿½­ì|uŠYõk˜£Gh$ +pvœb½Œ~ÇüÒ/Š÷ÿÂßü¼¥_Øûâ ?òH~(ßÿ òòªžGð•à’ù™Õâî'©Ô“OÉ‘ã_Œ1þοmí-a±°Óþx’ÂÎÖ,ì¶·ƒÃ—ÃÉ$…Ž4\’IÆO4S>+ÝZjŸ³OĽCO¸7zn­ð£Äz”Í¥·¸ðÝÜñ3!åXÇ"å{ŒœfŠíÎH¨íÊ­èyL§*rs–¼Îþ¦Ç†Æ?` ßà=—þ¡ñ×êF©ñPÙMrs0(Ç÷¯Ë¯ &àŸúý{/ýD#¯Ñ߈+>£ëw¶š]þ·uk óçY4+s~ê¬Ë Fi#ˆHäS$ˆ™a¹Ôe†9­5:4×^]=HÈdÕJßâgÉŸ±÷ügZø×ðÇÆž$øÕðæúõ4C} økÂ×W7¾žúö²^*k3Ê^F“ÈGh¡ÈÞc«*4uéßÿàª>•à]KRñð¼ƒQ0ñ.…§XxoÃºŽ±wqe¥êSÚ‹†¶´K‰ö¤i šm¢%yT›ÑO–üýŸüOñöKðwÀíkÀ_<mà{}å|Sâô ­µ'Òµ+‘Ûéú½Ô©$·ȃq.HTv|Qÿ‚BXxú}P:Ÿ€5í[Eñ‰µxíüqàüM¢Ko­ßýµák&º…ÖxbT¸I× J dI…ó%J*V„nµ_/vÏ_ŸSéÜ Ómë{ü¬þ[Øû_IøÙm¯iV×ÖNnìïbIàž"9£`]H8 ‚#¨5‰¾,jÃzÒQª-¤û¹„É›aò÷¨u,»±Iäu®Á^ ÿ„SÁºN—åé±fÙCk³M²ûšyh«ˆ`ÜþTC,{Ûjàn8ÍIâƒ>ƒá­FþÓJ¿Ödž:ÉáKAÑ ,¤Ž!#L’"Ãs¨Ë *ᨴÔn—GÔæ¥RvN[é~ǃÅÿ<ÕüIð«ÁÚÔ £øU®>ê>7ñþ¥£\ê0xcì°¤f?²Ãq®EãMò,ñØÎªCqéZ×ü£áï„ü^<=¨jºÌú¬0G%Ýņµ>ÖG·ûBC5ÔQ=¼Eµã¶–Q3‰b +¬dwÊß¿føÚóã…ï¾ü^ðnŸñÒÇPÓ-5wþ‹;ÀÖ·÷r¼B;-jk‰Õï®îæcuÊ!*‘ùƒ¿°ÿ‚]iÚí_?Ä»EøW«®«s§ßß|;‹V×lçµµŠÐ7TQ=šD·:n›™ï3ìòåÎJýYý’= t*š½­ååºÿ'æŒ\¦·óóÙýïUäSøÙûUY| ø=âŸêV—÷6Ò®uYá·Œ4³$14…g–m¸æ¼kÂ_µÇÆ_†7ðøª¿®ôO‰W¯¥¥—‡4Ë«K¯ ^µ¬×pÃ-Ì÷r®£X$„ÊZûGµÊ§qûJxJüñV“uàísÇöZÖžúeÖ£Íg î£Æ!•c{ÉíàR¨ìä¼É»›jŸ–þøwãoˆ~)ø ~%øâÞ·áïÝãC—û;šg•,½˜Ôu™añÛÞI ¼²1vÐ)w‘ÄÞRGÍVœ`Ü’Ù+uV[«.¬ÖíÁ$õ×ïÓ—å¹ë¾3ÿ‚Ü|(³øâ¯øRë]ñ|š…n¼U§ZGáýRÖ/APÂÚvµ+"Ç,‘G;Ä$û.âf±Õi_ðS E§¯ëzüº.ƒeá7_}ÿÂz•ޝb.®®m£v󶼯y¡òa¶Keœºdy‚x€ù§öNÿ‚xxËâ¯ìWàÝ'âWŠeÓb_…·~ÒtHü1&™¨øuµ;H¢¹’ù¥¸´ÍÆ5Û…÷‡b};ÅÿðNsâ2_jzï´Ñâ¹ü?áÝ:ÖûLðÛÛYZß蚭Ƨivm¥»•ž&’X’H  •öʦAåèðéKU×ðÖýwÛúÚæãk'Õüõµ·øRºÿ‚­|)±ðm¾·s¬ëö±]kð&Ÿ?…µHµ…ÔͳÝ%›iÍn/i Bñ£B ¡£Ù¸È­é_ðSφÞ!Ó|+s¥ßxŸY3{„Ó Ó<)ªß]Gö{kpn †Ý¥²X§at±|† ƒ;Ñ?a-gPñ¯‡ü]â¯Øk/°ñ¬~/Ôî4í´ý>íaÒ.t¸lííÞæg9Ä…äšvgÑY>{]ÿ‚mkS *=ÆÚöž0Ö|Bø]ã=kÇ^ ];\ÓôÍvÛQ»²³þ˽º’Xâ‚ಞP´” ÅH¿ñ_þ +Ëáé~ÝꦟUÔí5­ÍWðþ¡g§êVWÚÍ®Ÿ-Õ”Ò¬1ÞÄg+=´’Ä¡$•u Âø¶ÛÆ_|QðzÂÿàgÆO Xøİj77÷·šÚHŽŸw§±”A®¼Ñ¢‹Ã+£™ñU™†9Ï„_ðFûO„?§ð–¨|,±ÓaºÒ$³Ö´Ÿ†‘iž'»ƒNÕ­uãÔ¯ã¼ÙzΖ¢6A]„¤ +2…(:–kNkßËN·&2²‹¾¶I¯;»ß»µµ>’ðüáw޾)/ƒt½{P¸×U½ÐAmú+#©Y™EÅÛ!mö¥ÈþG™æ4j$UdecëŸðµ¿éÇýò?ƾ!ý“ÿdokÞ#¹Ô¼U­ÿex7Ã|Uâ3Ãrøv[MJêâMKQKižõ®6ÉdÑÜyè‹l˜ÆÞsGò°ÿ²G¡«§B›¦œ•›×ðOä*­Æ¬£î§o¹µù$mÿÂÖÿ¦w÷Èÿ?ákÓ;ûäbdCGöHô5^—c>yðµ¿éÇýò?ÆøZßôÎãþùãXŸÙ#ÐÑý’= —aóÈÛÿ…­ÿLî?ï‘þ4ÂÖÿ¦w÷ÈÿÄþɆì‘èhö»<¿øZßôÎãþùãGü-oúgqÿ|ñ¬Oì‘èhþɆaK°sÈÛÿ…­ÿLî?ï‘þ4ÂÖÿ¦w÷ÈÿÄþɆì‘èhö»<¿øZßôÎãþùãGü-oúgqÿ|ñ¬Oì‘èhþɆaK°sÈÛÿ…­ÿLî?ï‘þ4ÂÖÿ¦w÷ÈÿÄþɆì‘èhö»<¿øZßôÎãþùãGü-oúgqÿ|ñ¬Oì‘èhþɆ—Õévyðµ¿éÇýò?ÆøZßôÎãþùãXŸÙ#ÐÑý’= ?«Òìó6ÿákÓ;ûäðµ¿éÇýò?Ʊ?²G¡£û$z=….ÁÏ#oþ·ý3¸ÿ¾GøÑÿ [þ™Üß#ükû$z?²G¡£ØRìò6ÿákÓ;ûäðµ¿éÇýò?Ʊ?²G¡£û$z=….ÁÏ#oþ·ý3¸ÿ¾GøÑÿ [þ™Üß#ükû$z?²G¡£êô»<¿øZßôÎãþùãGü-oúgqÿ|ñ¬Oì‘èhþɆaK°sÈÛÿ…­ÿLî?ï‘þ4ÂÖÿ¦w÷ÈÿÄþɆì‘èhö»<¿øZßôÎãþùãGü-oúgqÿ|ñ¬Oì‘èhþɆaK°sÈÛÿ…­ÿLî?ï‘þ4ÂÖÿ¦w÷ÈÿÄþɆì‘èhö»<¿øZßôÎãþùãGü-oúgqÿ|ñ¬Oì‘èhþɆaK°¹ämÿÂÖÿ¦w÷Èÿ?ákÓ;ûäbdCGöHô4{ +]‡Ï#oþ·ý3¸ÿ¾GøÑÿ [þ™Üß#ükû$z?²G¡£êô» žFßü-oúgqÿ|ñ£þ·ý3¸ÿ¾GøÖ'öHô4dCG°¥Ø|ò6ÿákÓ;ûäðµ¿éÇýò?Ʊ?²G¡£û$z_W¥Ø\ò6ÿákÓ;ûäðµ¿éÇýò?Ʊ?²G¡£û$zW¥Ø9ämÿÂÖÿ¦w÷Èÿ?ákÓ;ûäbdCGöHô4¾¯K°ùämÿÂÖÿ¦w÷Èÿ?ákÓ;ûäbdCGöHô4ý….ÁÏ#oþ·ý3¸ÿ¾GøÑÿ [þ™Üß#ükû$z?²G¡¥ì)vyðµ¿éÇýò?Æ¥±ø£çÞÄž\ÿ;ªýÑÜýkŸþɆ§Ó4°º•¹ÁâUþbaJÛ JGäíñÝû +jãþ¨ çþ¡rQI¨ ~Âú·ýÏýB䢽LÓâ‡øQáe ÿÄÎïÃ+ÿûÐýP{/ýD#¯ ¶ÿ‚‡üpºãº_ÿ"Ó“þ +7ñv6ÄÚ†˜§¾ÒÃP‘®c®Xú׃ŠÃaé6Õ%÷#ÙÃâ+ÕÑÔ{8‹™|vÊM¼š3XŸå`j:ŸÅ(؈_Ã@ïøzËÿW×ðGƒ.­”Í$^f9&L#]ÇÂjQc+¸ô+rÃú׋ý·„¥+KŸý¸Wû+R7UÚÿ·™ð&¹ã¯zJ“ —„.€è?°mŸü„kŽÖiOú&íþÐ¥ÛýÍÑÿÈ"¿Cu¿ÙçÂsBæ)#·œOô¯+ñçÁ;O¼‹i>HÃ18ü+ÚÀg¹]Gia`ÿíÔ'”fWŽ&KþÞlø²_ÛOãgkx7H í Úý¢jæ›û`|^½p$ð¦™=Oö™ÇþA¯£îþižqßñ°õ‘Æ+_Áÿ4íFù!G•2zùì1úöªf:…þ©¸ó)à³G+}f_yáÞý þ%êÊ¢mDBzîÐíüƒ]Ö™ã_jQ‚m´(Iô³aÿ¢«ê¯~Ì^û$rK-ä‡lOÇþƒ]D?<¥ÄU£b1üs1¯ÅñXåjXeòHúL6M˜rÞ¦!ýìøÂûXø„c&ßþ¬öA³ÿãUÎ^xóâΟuƒ§øNXê4[U'ÿ šûÃþÏõFÛ_?ûó¨ï?fO ϱq÷–|ÿ0k|I—ÇIá—Î(Ú¦G–°®þRgÆþøŸâë–U¿Ò<<9Á#IµÿÈU×/Œ¯{=9ÿ‰E¡ú.»‰>ƒÂZ£Ã,]c“ú\MÞŸ‚J†ã°¯RS®•HRŠOÉ|劢ù%Q·êÉ%ñÄûx·ÑWõ´?ûN¡ÆÚ„ñ±ŠËG˜ñé„þ^UrÒ<¸×#ùWtrœ2¡*òŒR]ÒýÇ,Ê¿µÊM¾Íþ§©h¾7¼ÕÝ”ZiªÉË)Ñm3ÿ¢«qŽ£q¡M}:kC ðÐí Œûþë5éžýœî4MhÝ¿‹,­õQÁXU$I”õÜ­ëZr|?‹Ãº¬šwŠí„޲}¢É£ŒÇ/+´ž=±_3[‚çµ(.?à~'»KŠå½I¾½àŸ9xâU÷‡ü;s«Üý†ƒ`Bþ>MXƒÆúo‰J©GrÎðsúÔ÷ÿü!¨ÅºæÌÜïå‰ÉÿëVô²ü%)%ˆ¢Ÿ¤WêŒjcqUèÕ{ýæ"ýµõ;WÛŠ4䢸kNÇÓ&ëX“~ܾ&¾¹f·ñfo}CxgMv?ùùÖ×ÄO‡¿ ì®X]ióGç*úW–Þ韎 Ë«\2œHäoë_S„ÊòŠN8[ÿÛ‘ÿ#çq9Že ZUíÿoHëÿá¼üFPºx»B`§•o iy?”oMý¯|kâ)U­¼k Â§øÂú[Ÿý'®gÃ_| â›Øä¶ðæ½µÝ(QM{‚fO +hå&‡@¸ŒõÄŒÇúÔb°Ù-®7ÿȼ=|Ú«Ò¼­þ)™‹gñƒâf¤èÐxÓM1±çþ)$ÿíµtkŸ^4¾=² ŒíOhëú›c]5ï¬tè?ѬD;F¥y§äº³Š`Æø*çhŠòiá°X‡ËN„ý¹ò= ×ÅÑWY?ûz_æ\×¾:xóÂlwø’ÊðïøsGAú[ +á¼aûoü@Ó ?dÕ´=þ¿Ø:[cÿ%ëÈ~#j·×’°êwäæIxþuÍøwU†êùVmëi<‘‚ZúÌ' åܪs£ Û±ÿ#æñAæpY/ûyž ?nŒšÆËm{CÏû>ÒOþÛWIáÿÚ/ãÞ¸Wn» ¢·wðÎ’?öÖ²>ø?Gžå%kMOk`•ÆÜ~B½ÃÂW‡màPöW' „Ÿæk‡1ÂeT]©á!ÿ€/ò;pXœÂª¼ñ2ÿÀ™Ëéž;øéz¥ñ‡"°ð¶”Oþ“UÉþ"|^ÓЙüg¤±Ýðž‘ÿÈÕéÖáÈ#m€>™ãPêšžƒGäþ{×Ïòᬰ°ÿÀ#þGµ|BZâ%ÿ¿ó,iHÛ¾Ñÿù¦ÿ‡’üwoù›´1ôð†ŒöÖ¹ßü9Ó%p?²5<×&­è¾iäœišŽ?ë™?ê¦X¾*Pû—ùýcÇ¿†¬¾÷þdßðò_ދׯAúx?EÿäJ?áå_W¯Šô¶ÇýJ:(ÏþJUIþéð©?`¾^+#Pðf™lN`Ÿ9èqGú§–J-ÆŒ~äë=5z²ûßùžã|ùý†õqßþçþ¡rQEòûêç¿ü(+ÏýB䢿ΕªÅu¯å2nœŸ™é>_ø×fƒž¿ð¡ìñÿ„ŒuãwvæÉŠû^Ëá¡ÿêÐýP{?ýDc¯•ì~(´_~êøúò+õN¤çNVþX~§æ\OS–¥¿½?Ðí¯g»uÏØßq¬»›ýCy+g íËÕ;‹7Íxß\kÚ|\Ó³ó ‚Ýz_¢¨TŽÐ¹òœð{ÊÆuÓj’ÅŬ˟G5N#©Å&M­Ã1éó]Dÿ´Ä@|»ƒžœ +ˆ|eÓ•²!¹Ïáþã*¶þœiÿ9…6¦„n³˜tês]Ž‘y¨(X±ÏC޵ÌCñ²Íp œç¨#ü*Ê~Ð0ÚGÄ7_÷Ðÿ +å­F´öÑJ­(}³¸¶Ôo"{éÚ<ÖÖª8`ȯý³ä¿´æÆ;bº>Û‡øT–?µrU ¹=¾òÿ…pÏ-¯%ð¯¼ì†:Šû_ô†¨‹ÍlœuýÚóúÓ¯.à¸BZÖ&ÿ¶iÿÅWˆCñîKÌ2Gt=·Še×Å›·‰˜™À#?ë+ûµõÐéþÓ¥m5=Rí¬ÅƳá98ÎÄû5]Ó¢¶™°–0&}BñUà7_¯bs+ùÖ–ñ.úi×h`Aãç5ÓS)¬£{˜C1¦å±ôM–„$¬P ú/ÿSÍ¡4Jp{åGþÍ^qá_ê2¢î1|Ý71®¶Öæ{¥Ì¢Ø“êÕáÖ¡RÕž½*Ð’ÑÔ­¦‡!a¶cêf­eÇ©]Á/ËchØ?óùÍXÕ´¨n-o`sýé‘™m¼Úh¤>iV´¢šÔÊm§¡×h^&½FQýŸb¿[è¿Â» 3ÅwJƒ6¶@ÿ×äuçZ7Ø `M·‡—ë*ä+¥‡XÓ£ˆ<>¸÷ÏþË\š1oHÿ_yÛ‡ªÒÖFæ©ñæÑ~[{-ßõÿ¬h¾.ÞÍq°An}º”mü«'ZñF|§ÃÄŸúbÍÉk/A¹_ì_ÝÚ?øS£ƒ‹Ü0©Š’äz®‹ã›Ëœ°gþžþUÑZø†îUÿ\=„™¯)Ò™_é\ðv ¾L룊Ós¾}~î01vÀÿ¿M_^¹9¾oûù\9¸Óåû÷÷gé1bÐh„÷—§×ý%ÿƹþ«µ_¯Ö{þ&ö³­H#%îø=rõæ¾6ñ&b|^Žý5ÕjqxfU*d¿“·ü|¿ÿ\Þ¥áÏ Í¸‹{¦¦é\çõ®ìavŸÝÿåÅJrVM}ÿðñ‹îm®mÔ¬ àÿëRøgÆ3=Ø/4¹ÎH'ÿ­]æ¯àß ¨fû îÍþ5ÍÞè:D9û=š¡÷ñ¯§§^ŒáÊ¢ÿÀ±•ù‘è¾ñ1eB‰>¦½gž( 'Îï¡_-ÙÅ=““sí·'­iê_,' wƒÓ¯•B«Ñž¦15ª>ÑÒ|i»æe r7ð«Kãkmç7=>eÿâká=[XÔå¶ÇyŒc;ˆ¬a­\]å^'ûÍÇé^lxFœï'Rß/ø'{âYÆÉBÿ?øég†ü_m1'v9í çÿ®¥5Qy-$Û™?û +üïð&“¬J´7#Üîÿ +õ¯ hW“¨óç=Ç#àã¸f9]Tü?àžÆ>œÕ¥Oñÿ€}Ww§A9Îg×ÿd«Ú.œ–ÌT~û%xÃßÇâ=nVIØóØ#ó¯£üû1øjÆÎ9.cžIý~Ÿ•|®cìp«–soÑÁ>‡êW|ÑŠ_?ø?ˆ$´¶Ú<Õêdcür¸øµÏï•pS#ÿEWª^|Ñ™]#Õµ+Hñ÷#º +ô®3ZøàíAäYüc¹zíùkÍÂâpÊWiýÌîÄѯËeo¼à4$wˆO”äžÐcÿiWªxKÇWrY§—¸(aÿ®BÏà—讑?á3¼fh/óí]ç…þxa•NŸâ-Já´zžGé[æð²Ã/œYŽž!=×ÉœçÅV»Öô—y#‰FrmòߘA_:|BñÕ§„àÌQsœ+ëWàV‘â*I­k.Œ0P_’¼sÆß°ŸÃ-ñ¿×o¦š=Ì#7ê +à}Ewd™žŸ¹ZöòG.mÄÔ÷©Úþlù“FøŸ/Œu3Éä)ûÙRë^á˜Ê@QžÇй ~Ë ¼=§†»wgq¼:«1Ɖ‰~®ƒÀÿ¼sã$¶_j·1ª—;u ¶éüR9çðZú¬fa†q~ÍI%ýÓç0¸:é®v›~cRáâL®3þþ+–ñÊIªÙ;A<¶·ÑýÕ;¿÷O…¿¼#â?jk>¡q©Gc‚ +O‹týš4¯I%…¾ªÅRY¾Ør1e;£úc³Õö”3¬©§IK›—m/o]Qòµ²¼Tj59ÅÆ×ß§ùœ7€"·±´7w! Råä•wlwöïÓæ½ÁZ·ucö–Õ­ˆ!NGåWuÙ·áŸ~xn÷ÆÖÝõ9#7Ũ…à “Œázúb½3Å_¾izž‰o–ú|W«ûÌJp?‹œ~•àæÆ£M)êßOåßKžÆ -¯ëË¥º÷ÛSÀ¾!üZЬåtîž’t -ÆÒ:ðÿŒ^4ÙM½Ôw,€ãË›poʶঠô†w׃@´ŽxÓn%IW'§½|ð[öšÕ| âTµºœM`îcá¶Œûó_såÑžÌ3w{&|Žq˜J‰aqÑnÑè>Óµ‡úè†H$Š ØÏ’Oô¯§<¨K}£¡.W?êˆÍgø7LÓ>(éV÷q¬2™1+ŒʽkÀŸ 4ëY­¢œ,VîÀ9߀£úW>sšÂ_Ĥ·:rœºqø%x½›>;è³±,Å9*AÀ5æž ‘­u dŒ$›ºíûgâ¯Âï &­$[\Yãåqq‘ùŠñÍoàïƒ$½uH9_.ô©Nk£,Ï)·#‹Û±Ï˜e5n{¯¼ßøq¬bÊ5”äqÈA^ctŽ€8#®+Ãm¾èÚiX¢ñ« Ïñ5pGë]§…ô[{i#5ÝBáOg½ó?™¯+‡„›œ[ûG ZQJ2_‰ÚkÞ@‹Œuãu»+(_x“€yŸé^Ãe¼$³¼ˆGñK\Ÿ~xkV2¥Ê#©é¬òê°¥QsÝúc©Îp÷l‰>*|H¶¯D œðFJâ4ïÉv»edõߊú³Å³_€õ †3|®OºãUtÙgÀ‰v‚9ý.Aþµúï N $íè|E\¦¼äîÕýO ЦºKDd˜ÆAiu{Ë„„æiOóÐ×Òúì÷á™#P6cþ{T:¯ìùàéddt]¿Ò®5ŸaœïÊþã«û¿.ëï>=Ôi~U¸?K­ßÖ½Eœašº‹ûŽ•âŽKï<]nâóË+úe›üjÞ•ÅÌ¿xœú¹ÿúÙ§ÁQ\p£ÖsQKðÁ¶×,±É"ãÒë­g˜v¬“ûŒÿ²k^í¯¼ó=Fº’Ì`ýŸë[úw…&F äóþ}ëgSø[¢Ynßê:— ZÀ›Â¶pLkÊŸkìÿZÇë +®±vùÁ4T=ž’_‰Ùhú$ÉÄdc­]¹²’ù°8ü«Ótøât7„Ôò¬JÅOˆ51ìn®Q“–ÿƒ;#U%·â‰óâÂDHTl{ ¬»¯‹2;~înÜœT©WêW-.†¼>´Œ×.qèƒü*–¥¦ÛB„¥Ì­žƒÊÿëVL߯§'€ eßx²òàœÊWÛÒ´2w“þ¾âZOD‡ê’¦Â¼äúgŠf›;¼Ÿ+] °ïµ›‰“pÀš“NÔ¥?òó)>Æ’®œ¬/bùNóK{•EÀ¼#¶M[¸º˜FC¤Àï×+§]Ë)͸lú“W®´É=ÎíŒq“[r'«3ækDMurܰÙ­o ë[0úýMqsÆ‘ÍóJ£§ÿ¯[>¸¶ŠeÝ(8Èš&”¢Ó[M4{/…µd—fK¶8ǯë]ö{±Ñ= Ïõ¯.ðާfª¸•Ûß­wú&µg)ç¿&¾OIßDÏ¢ÁÔÓsræWA›xãÿר-4ë_ cny.üWhªq7Õê¬^;„>_}¤ÿJà)ÛDÎÉNÕÖ…áÛU"ÆÐŸêÅu6ZºÄ1ký#Q\†˜þµ•½ÙuœVÈk¶Ü–‘sí¸ÿZ­4ë»%ÉÏ¢ÿ‰¨Z‰$Žz è 9´ë†'¯L]©%»9.û\Þ…bpìzÿ›¨x‡ËBªXV…ƘåH, =°?Ʋî<:Ò9ÂÉžÛP‘ÿ Šè¦¡ÔÆ|Ý +‘øŽh¾`å€= ?ãN;¹ŒçìÖíé»wøÔwº9µRXJqýâúÕKMbRòÛ «v®¥NZ+œîR‹ÕØžïâ-â‚N²sê"fþµ^ÓǺåÄÃÉÒa#ý›N”íCâÒB`³@ã$ÿõ«-¾1_1>[[Ç“Œ*dÖÐÃÉ­ ¾lÎUâŸÆþãÑ|5âO: iðÆãpUη®¼]¯ivžd¶úvqÓדÛ|HÔîµ\döRù +–}fòõO™#ÉžÒH[ù×Lœ¯$‘Õ jQ´[:mwãö­¦‚®šõŒaÚ·WWÙ›Xûñ\gŠ#wÁe ÿë®âÕ!ÔpnN3ÑXŸå^¶+ÃÊ>òG™ˆÌkFZ6}+áÚTÕy·n3ýÕÀþuÞh?®ŸÍ‘·zžµó—è!R»DŽGsÅ{Ïí6ˆ—zŽ=95óù®…+Ú'µ—âkTµäwZw‹î¤Ã+2–︊ßÒüC©HÀÇ,ìO÷ Wþhº ÔáŠÅË3ž}!àŸˆ_ <7jÚ¾—¸ù›ÈÁ?ð"?­~}šf +Ž”è¹zg—àÝMeUDù{Ä^)Ô--[3穯 øŸã³ý›"ÿ}ÏúM©øÇá¶© ý¥ôYCýìÂ2߯6ñ^³ð^Ñ]OY\ô0¡údâ§*â.I^XY7éò+1É\ã¥t¾ðçÀ^¿ñµæ ²Ýß\('•†"sùÿ…{§Ãùõhl×ÌûPr:¹95îGăvÒy/£ËS•%·–üzO‚~.|/¢ØÛéö²cï=ª‚?àDW^kÄ5g0­|—èa—dƒ×ŸÍþ§Îú¦¯k¥2Å=Ä{‡!rúׇ|pÖ¼CkbæÖæèœ„$…úãúŸÂ¿Hnrb +ú⼇âwˆ~\‰aJŠL©"(ŠÎ>ö:šáÉóçºá¥÷ެÇ'½=+¯¼üñ¯Šüce«Í3ßë[±Á øcеà?øËKÕmŸÌÕ¥óÜ*™™ÌxöëîÿøáRêŠ ëˆ .òlŃýÞSNð‡Å…ž2µ»û%¼ÖöÄïg(IÀèƒÞ¿P|EzWú«zy—Sóõ’Z¥¾°·3¾øÃUÕth-åŠò"P¼2vq^™{ý”ö‹q2÷tRp>µÙþÎþÛø§UÕe†Þ%(M¤Œ›~ê€0½v^ø«àm3¾#¾1¢]]4®«( î¬>P§·5ùže˜TúĹpíZß{ÿ#ïp8(ûÞºë÷/ó>;ø·§jzׇµW™¦³òœ»°ªnž•ã¾DÖ>1²+é—— nIsãøzgõ¯~7x Â?³‰á»¶§†YRcŽð€zûb¼kÇ_þ§ì}¦¬E޵ÖÒÊâ@A^8®úõõùN2»‚°væKo/ˆùœÇ IM¿j¯ÊßüKáÊùºE´ÆÑ[°Â.ã…>Ÿw¦kÕ­àgÑãqr€`ó)œSõO‰ÿµÏ‡þ}ÝDÀ^HaÃcœýkÓ|mão,¾¾Òm‘’QuùC¯+µ×šùÌ~2£šn”•ܾVÿ3ÛÁa`¢ÿx’üÈù[ã¬VŽ‘,zšÚÏq‰›iÓ8â¾Vøû8xÇú|·z­®§'ËŽ`aŒÀ×Ò_ðT/ióßøužÞÚ]»@;AÊòúæ¾ðÇcá§áfžæÙ¤Ì¶ÒHvÈ=½¿AáøIàa]6¯ö^ÞŒøÌæqX¹Ri;u_¡ï¿²GÅûï…Þ!] Y[¶T’¼úwJû£Ãþ)·Ô´Ä’)K+ Žk柇žð·íáûMjÁ£Šý1»ÆÞŒ=kè?‡VáØâ†ör‘`¬Ãë^/J…YóF.3[£ÕÈáVœy\“‹Ù”¼s¬Bcua–Á8*M|ÿñ/ÄLÒɽ3$yä#)˜Å}+ãOik~ζN°Ÿà$¿ã^Qâø`_ËÖq0— Œ€ß÷Éë\ù=W>GòfÙ”9´æ_3瘼U¦Eyæ$Î +ô,¬?•zoÃØÞëhÜìC^4j®{¨³Ötß&²G„x¯OÓî¤r“É=ĵÍÃáçf BNxÉa^·â [ÃI+£XD~ª1úVeÿ†%œ*Ø Çt`NÕô4qRŒ>ø\:rø‘ÀI¤jðƒå\;ŸPÜšÈÔ!×afÜ.Ž:óšöÔÕü3 ŒZÈàæ«\ø§Ã^sæ'ÔW |“þþDÏÇÍÞ"ºÔÁmâqêvšå//ï_õ’ƒî }3­øÃÃ?:¬Öïþò­r·Þ'ðÔòÖö®êyüëÑŽ&UÀÑÃ*ƒøÓÈã¿ÌqZ¶ž¸\o†%ÿyÅ-¯¯ea²Å}rqúÖµ§ˆõypE½´^ÅFkô©Î¢è‘ò7»e | èE¸úÿJνð|ñ“ƒýÔ8­íGUÖœðñ(=v.qX÷6Úµó|Ï+wÆÍêKíIቔÛÁ“,Ì=8ÅP¼ðJ¬w)'ÜVì^Ô®9òÉÏbqW!ðýÀþNjH/ŠHJ +gœê0ó”\Ôz~ûöùƒa^“'Âi¥süªKO…>C‚Ò öü+>zºeòÖµ¬rº^ƒ!Œ3=)uÄg3ší&ðy²‹Äý×5â bHbØ#ûÀV´ëFnÉ™N›ŠÔâïôвfÇ5.–±Á ÝqŒ{Ô÷y¥#ïU­3áûÍ(O¥CƒŒ¹’·Ì¾dãkO…uË u]÷g# ®ÛNñ¾›múÉØt»Éxgá˜#æ_Oâ®ÂÇáŒCƒŸrq\˜™ÑoßgN5WŠzßÅK(Píó‰íšçGÆ{t¸?$„ýÜ×I«ü$£'c~xÿÁ !3ýÂ>¹4©ý[—AÏÛßS¢ðÏÇ”‰—m´ƒþ+¾Ñ?h Z1µsø‘ùWá?‚±Jê~Îíøõý+Ò´‚¤@y@@Õåc¥‚OTz85‹{2 CãÍËDxê;ø×9sû@mÞKtßðzŸmæB LF:çÿ­X:Çìùk¼“ÀpЭ€½š:êÒÆn™ÌÇûEÀ~÷žçý§n?Š'ý¥RÝ2ßî?2iº÷ÁÈt¸ÉHããô¯>ñ_…ÖÄ3#P;^¶ ‚¬ýÔyµ«â©îίSý¨u"ÛbÿµþUñß[ÔØ´2ƒýÑ“úä×Á£Í=ÐX!–á÷#&»|1Õõ\Ú´`óóž!]õp˜:1»IÄâªÊ×fŒž7Õ¯”º˜vÿ?ʡ׌É31ö5Úèßn¤®f/û)Šë,¿gë­ƒ%•ˆäÉþ•äÏ1ÂÓÑ~ï§ÄOWø³Çg¸U1lú3c5^ÊâI®6Ç1Î>Q“^×/ÂJšÚ!Ž?y'ZC.‡á¸K+ZÇ´tF:•™Á«B-–òù§yÉ#ŠðÏ…5}UWm«ªã†~+i|#{É…²ÏÓ÷x}Mm[üEÓ[îFÏîÄãü*®³ñwOô8‚ašä•jÓ—Ãc¦4éF?ÌÝSá\²[´—ÅO9aøW'‡ô>ÿ9®XrÁGéÍtQ^êÞ&¸h·ÊàœmZ×Ñ¿gÍ_Ä3†:©=1Åm G±_¾Œ¥CÚ¿ÝBâx/Q$TŽ xz ŸÎ½?FÖ…x‰uÀª^ý›×@ 5ÝÒ«ŽÇš“ÅmiáûS +Êä(ä W‡‰¯J¼ùi;žÅ +5(Ú¦†³xåÖ0^ríš¿¢xÀÜ8ØÍ“Åx¦©ñ.;†÷q€xÉÉ®›áÏŒ-ïçBeÉϯô©­•¸Óæhtsiò¦{,š”÷VD Ü>:\Ž—Q[y +Ë*“ïÉ®¾ÃÅV‰á¤¢üÄÿ…s~3{Ï#${£~É,~¦¼Ì$9*j¬ŽüL¹¡£»<ç×·òê^L—DKps¹ÿ½Ãáü2 t îòË“œ× á„÷—£ÜNB(ëõ?á^µ h«¢Ú(r2£€JÓ5ÄÓ’å9u +‘÷¤\Ô.nÉŒ%ƒcó¯*øá}_ÄÐÉ7O oø8àõæ»O|A@´rpJ޵ó·ÄÚCT»ÔeKxÊC#†ëS“àkÔ—54½XfxÊP-FþEmCöjºò]Vævs‚ÜU_ þÊ’Ùj‹²âeG?¼%ÏOJÃ?õ©$rÃlh2Í»ÿ׫¾øù«Ýj&›åôõcøWغY„`ÕÑó©‚r^ë>–ø]ð“ûÊ(™bPÜ×oâ/KýšaPWq^•æÿ ~ ÞêÐ ÚØÏS^ƒâo\G¥`¼Ž¹ü+óìlkýcßzŸi…t½º´>~ø÷û?Kâ=)£Y¤ŒnMçMxt_²ÝïØ…³\LS™ +8ã8â½›ö€ø«©iv3¤h@ªƒ»wþuàÒ|xÖd”Ê“æéÕ÷ù5•óoüâ;?4‘ò‹Vº²tÔ=”¤­æsg889ª‘‹¿‘cöcø)uðæýnìd–&| #c•q_VX]4–Kæ/–àdƒ^ðÌjv1ÄdR9\à7ÓÞ½ +ûÆW68˜â¼ÌÝN½{èÙèeœ”(Ù^ÂüBº7Nñ,,$u·`_6üQÖâ‡Ytº¶–9ÐðÙÚßàkÖ‚¾éð¶ïø%΀øÿš iÿ¨¢Wç7C_«xo[–4û0ýOÌø¾—5HúËô=GKÕ­Á¤@?:êôZÀ¨ä1ö¼NËÄßïgò­(>!µ¯ÝÜkôªŠö>:<ð{\ö϶Ú8ÈÚºŽ)‰ulªO›×â·.ÛvÒàÖ³çñõôäüägÞ¹½ŒÚ7ö“}zmzÖæâ,p*¼yaj똹÷ɯŸ§ñ-äýfaôª²êÊ~i¤?N*]:}nZ•O#ècñON‹þ[CŒu"¢—âÖœrîÞ¾|[„ yõj½e¬ÁoŒ®ÒˆÓ¤Þ¨RT´g°êRømŠ@äñ÷p+"]Fâõò΀QÿÖ®:ËŶðù²kRÇ«0>•èB4â½Ër•I?|è-í'‘Æ$P?Ý­K+;ˆXsÓ5ÇMãyTUO÷ÿ^³çñ¼’6<ð3ýÁšSWݤòG²ès4 +›ïb=—ú×W¥ê¶Ákð}zWÎxœœó1=Ù°+kOñͽžß6æ(±ß;êk޶3WR:©c%nSèëhôýIÀ7 ¦kkHðÆ‘€½Élô蹯ž¬>2é¡s=ÌÅ{/·´_ÚÒÝÀ‚Û’~óœãò¯&®[Y«Soð=*xêKY¯ÌúkBÓtûtОq]=˜·¶@I‰G¨¾cÓ~=ÜÈËûÅŒu\Uöøç#¾Ã9©â¼jÙ&"OVzt³zZEÞë¶P®<Ô v®o]×á”0Yb\ô¯—â|ú…ÎïƒÙEI ëßMóÍ"îd|úÒ§“:zÉ•<ÑOH£±Ö´ˆµf"}JAþlV[|3ÐÕ·Kw ­ìƒŸÄÖ$¶ºm¨!®$šSÿ<‡OÄÓbÕ´[‹DrÏ<…åÒ»áF¤U¡'òGªA¿}/¼î¼?áÉÔCöCmçô⺫{{dÜn!1À©ÿׯ%?<1dÛþIqü! þ`øë¢IvVÎÞBç£H µsÔÀbj;´þãjxÊVM}ç©êzä6¨LL²?c³us·þ;œFRIÒr2X ~ÂÉ㸵;²³\H¡º&qøæ™io¦êÅžWu ç󪧀P_¼_€§Œr~ã-x–s«Oˆï¥}ÝJ¢²t߇cS¾ÃÞãØešº»;Ë*«3¹^ª£ôãó5­¦.…mrvÉKé»? âº>³*qå‚q°S•ä×ÞSðçÁ›a“%ë9ÿi³úë]Î…ð[N–&VfêI8ð¨ô-SE‰–ÛÀþ68úVÂxÿ@²@¯xŽÊØñ¯‰ÄÍû­ýÇ«‡Ãáâ½ë}æ÷†>躪ѪË'rzWX;h¿Ö¤˜ùEy^½ûAèz¶áq ´j9f8Ïõ5âÿ?m½.ÚIÎY®Ÿ ä.~:㥔âñ2¼“·vuO2ÃP£oD}ãŸi´‘羇*;¸ò·ÇÚ[NWš+K…ò?vx?xÄ¿õ$’y9ás€? +åmtËÝzãjG$ïÜž‹ï_S€ÊiaïÍ/Ãþ óØÌʦ![áâvÿîµë̬ŒªNzàW¥|"øˆÖ8È8xŠøeô÷ÌòŒŽª£"»Ï…:ÕõEO6@ˆ¹-^ú\ðpª´Åøc©6¶c*ß)#;z~&½›G±Òôû ÒÉË×òkäâ߆áûœ”öÛ¿SëO‹ã^«0y|ùŠ¡Ã6Þ¿JøÜfKV´¯d}F5§F6’»>ǵÖ,>W‰ïÞ£Ôuûfµc±¬c«“À¯™ü5âýNóK]KT¹šÓOäS÷—²×š¥ãŸ‹Z–›l'½ ãv)×ÙŸßüûו›©Ê¥sÑ–uf¬zoÄí^Þö&Š+¨ÐÉò—ldû^Yuà¨îä ^[3“Ð`íÿ^A/޵Á²F°ÇДcëRi¿þÍzˆ’Æ7Ž9?ç­t÷¾èH÷’<²c|„ööúV*êM‰xÑ•ŽV +™É5’ÄTš|²º/ØB/Uf{GÃm94[J¥€ì1“ë]¶­wm5¦Ò௰øŠÚeÌqFÏžÆû:Õ9ìqñø^Oê+{Ë´¸ØÿúëÝ>üI‡Lº·Iï#ýàU9>¿ýzò‰´™®ôà +H<ÈÀ¯^8®WÆ>Õ,4ˆï,žq$Y,€…ëüˆ®ÌN¸òT–»”+O .zqÐûëKñm…Ä[e0zôÅY¿ðý†¥Ÿòº÷€¯Ïï~Ó÷šp×× æF6ÝIü+Ö~ þÚöi~Ú.§s¶–7lþòx®¯I9Ñw·cé0ùýB¢µÏ¥ °ÒBžj¡#åÈÀÏ¥yÆO¯ƒÞH°|„ôo­qš¯Æí;Fñ“Ø]\°Šìÿ£Ê À'¥y—íñ{»9´}Ueón¶˜ oôæºrÜš§¶‹©³×_ÐÚÃÙµ ×õ¨çø‰¤x¯Å o{|öLçÉœ úé\·ÄýOXøzs#ÝÙ71ȼàuë^¬_jjRÀ|Öu'¹ÿë×Kொº½ƒiz²Ëw§ã˜dÅô5õ”¥Ï–*ËmQó•¥io¾†ÕßÅ3|wKóëžõ®á÷Ľ:ÊùL¤ÄÄŒ£r¿¯ñÖœ-n ú{HÐÈzv5æ_ÀGÝÿJU±’‹t§¯ ¥†RJ¤e¯™÷÷…>%hú•š¬s¨“ ŠÍñ׈¡6r u á|W£øßWÑdU1Ç8ç"ºøÉ©Ï£½Ã`|Ês\T¨PççM¯&Žº•ªòòÙ?C¨ø©Aq{+mÚsÔWž^^ý’}Ñ¿ ý* sÅój!Ÿl øâ¹}BK‡;± ÓŽ+|f57î-Œ°ØF—¼z§>.ŸÞFeå#&¾‘øEûGèÚ‚"K{l;•ð{Cz\ ?=3È¢ ­JÆ\ÂÒ£/¾3^}\j«JÐoÏ©×K +éËšœ­ù¬ZÄÍ6öÍLWpÈÜY^/×´ÍFó¢…Áî¸5ù½áO¾!ðè_ÞÜ^88®ïKý¨µ9áUžW$÷<\ôp8w.hNÞªÇE\eeYBþ‡ÐÞ6Ó´GÞèDgùNå^[â¹ìm™¼™”õàŒáõ_Œrjäï•‹7¯Ëë2’bpÌO9ôT«B„~.céJu¥ðØßñµßýFq\^§âK[i HëXz÷ˆî$V)»ð®NÿT¾“%ãr‡¾+ÄÇf·–ˆõ°y}–¬õ '⓼+Jé×¥o[øƒLÔ@ÙqOc_>]i’\Û$V=Ç" HuI1Ì1èkŠž{VJG\òzSÖ3³>1ÄFV@Aôj«sŒ6~Ÿýjðk?kzK K6³ +Ù±øán1™ùÛÿß7ýEÿÂOÿ»)üvOüÖEÿÂOÿ»+ôOþ~ÿ?Þ0ÿ¯UÿäŠ?áGèßóýãü*õ_þH¥þ¿gßôÿ’Çÿ‘ú™“ÿÏŸÆ_æ~uÿÄ7MÿE•ð“ÿîÊ?â¦ÿ¢Ê¿øIÿ÷e~Š‘ѿçóÆøVj¿ü‘Gü)þ§Â™?úWO“þ Ø‘ÿæ± úxSûy_ ¿ð£ôoùþñ‡þz¯ÿ$Qÿ +?FÿŸïáWªÿòE_üDÿþ‚?òXÿò$ÿ©Y?üùüeþgç|ÿðn —?ð¹T}|'Ÿý¼¨üu1éñ §„ÿû¶¿E¿áHh¿óûãü*õ_þH£þ†‹ÿ?¾0ÿ¯Uÿ䊇ÇÙóÿ˜ü–?üˆ×e þ]~2ÿ3ó™ÿàÛYdûßK}|&OþÞПðmxçøÉ»éáLíå~ŒÿÂÑç÷ÆøUê¿ü‘Gü) þ|aÿ…^«ÿɯ¹ïüÿÿÉcÿÈýMÊ?ç×ã/ó?=m?àÜhm'âØr;Ÿ ÿ÷]méŸðo¥®žÙ?Ä„zøsÿJkîïøQú/üÿxÃÿ +½Wÿ’(ÿ…¢ãþ?|aÿ…^«ÿÉ¢ñ ˆ²Ää°ÿäLßäÍÝÑüeþgÅvßðB{{hö‰)oÿ·5nø!Õ¬#âlÞ­áüÿíÍ}“ÿ +GEòùãü*õ_þH üÑIÿÏáWªÿòEføû>{â?ÿò%® ÉÖÔþgÅ×ðC{«‰3ÅT·‘ødýº¨dÿ‚ß³e~- >­áÇÿJ«íøR/üþøÃÿ +½Wÿ’(ÿ…!¢ÿÏïŒ?ð«Õù"šãüùm_ÿ%‡ÿ"'Áy;ÿ—_Œ¿ÌøjóþK­^Æ“ +ÑøWóû]dËÿ÷Ý\Ê^OŒ#¥¼0Iýnëï³ðCEÿŸßáWªÿòE'ü(ýþ¼aÿ…^«ÿÉqñ ?[b?òXò$¾ +Éžô™ðlðo˜ƒ“ñcÌVðÖGåöºÒÓà‚«jÀÏñNI€þ¼=å)ü®‰ýkîøR/üþx¿ÿ +ÍWÿ’(?´^×¾0?÷6j¿ü‘Mø‡Ä Yâ?òXÿò ¸%Zª?Œ¿Ìù+Eÿ‚*éº[SÆÑ¶z“¢rò=hKÿx³Ú<¯Äwmwéç_RÂ’ÑOü¾x¿ÿ +ÍWÿ’)áIh Çï‹ÿð¬Õù"¹%ÆùÜÝw÷GüŽ˜ð–T••/Åÿ™ñþ³ÿV›R“1üLŸÿÛ *¬ðD{«` +|QŒÉý÷ðÞò>™ºÀ¯²‡Á-þ|_ÿ…f«ÿÉ‚)ÿ—ßáWªÿòEh¸ïÿ¿¯¨áIh¿óýâÿü+5_þH£þމÿ?¾/ÿ³UÿäŠç|i5onþèÿ‘ºáLª÷ö_‹ÿ3çÅÿ‚[[<¨òxº7hF!Øà,?AçW9¯ÁíµýQ®îUðOü³OðeíÅÚøÎï'á$m!ì<óϾk¤ðWüÎ×ÂsM3ø¹o.¦bÆVÒ~žq¯¡¿áHh‡þ_|aÿ…^«ÿÉú7üÿxÃÿ +½Wÿ’)Ôãâ¥ùë·(ÿ©ð¾YNÜ”­o7þgÏ3ÿ‚[Û¬Mãa {Ã8:>íàvÿ^*žµÿž‡V»°eñ¢C‹nò¿±sæ~>ô¯¤ÿáHèßóûãü+5_þH üÑqÿ¾0ÿ³Uÿ䊈qvm”kmåò)ðÎ[&Û§¿›ÿ3æöÿ‚QÂþ'‹xÑ +¬^ZÅýÂûçÏþ•ÿ™‹LÕõ·ñºL×Çå_ìM¾HÇLùç?¥}-ÿ +GFÿŸï}á,Õù"“þŽÿ?Þ0ǯü%š¯ÿ$U®9½¿øGüƒýXË/gø¿ó>Q±ÿ‚9 =&öݾ G#ÝOìyY9éöŽ1Nºÿ‚:‹ÛékãøÒX\Ü`ç~þ´wÏ­}[ÿ +GFÇü~øÃ?ö6j¿ü‘Gü)oü~øÃ?ö5ê¿ü‘Z®Ù×üÿóÚ?äeþªe[{/Åÿ™ó=ïüFÚèZmñ¤q›n¿ñ%ÎÿüÅJÿðI[)%bþ/‰£u*SûñêúOþŽ‹ÿ?Þ0ÿ³UÿäŠ?áHè¿óýãü+5_þH¨ÿ\sùýøGü‹ÿUòÏù÷ø¿ó?=þ!Á¹iãO©X|]þÈI›w’9ÿÒºû¾#|rß´Ðsñ:çÿ“)ú7Ž> ø‡ZµÓtÿŠvWúü«omkmñ.êY®$c…DE¼,ÌI2MÄ,ýÿÌGþKþDk‚reÿ.™ñ´ŸðnTrJü\MÀáçÿJê1ÿáF²ÿ…º™?õ*ôÿÉÊý ÿ…!¢ÿÏïŒ?ð«Õù"øR/üþøÃÿ +½Wÿ’*_çïþ_ÿä°ÿäJ\“¯ùuøËüÏÏ ?àÜäˆø[¨ î<)ý>ÙPIÿÚE$`ÂÞŒcþ¥N?/¶Wè¯ü) øýñ‡þš¯ÿ$Qÿ +GFÿŸÏáYªÿòECãÜõï_ÿ%ÿ"5Á¹BÚ—ã/ó?9¤ÿƒk°+ñ…ßð‰çÿo)ÿÔ«1'ãsÿR—ÿv×èçü)þ¿™ùþÿðlb¸?ñz#çþ¥ÿɵÁ°`®?áu¨ö'ÿ÷m}ßÿ à—ý;ÿuÏÿ&Qÿ à—ý;ÿmÏÿ&T¾4Îç÷þKò)p®V¿åßâÿÌø2oø5î9[?ðº#V +ø?û{Q·üò®Ùo±·×Á¿ýÝ_{7Äo‚®[âΚî~'\ÿòe?FñÏÁkVºnŸñRÊÿQ¿•`¶µ·ø—u,×1¢"Þf$€&¥ñŽpÿå÷þKò)p¾Z¿åßâÿÌøÿÁ®)Î>6&¨>ÏþÞÕkø5~Þàsñª!ôðoÿwWèïÆ/…Ö>øGâNÃQñ„Únwuo/ü%Z›yr$.ÊØk‚^ªÙ ñPø»6z:¿„Èk†råµ?Åÿ™øÓªéûà™úĸÿ›»9ÇýIÒQ[šÖœþ S«ÍŽáŸ.þZEi˜T¼Óò'/§h5æz¿‚-ü9¯A“þ¨¯þ¢é_¤kÐWçgàþ­¡?øgûoýEÒ¿DÇo¥y9„¯~Ÿäuå‘´ªzœì÷ÿ$Àÿö/Øé4u™û>þÕk#]ÔþxÏÃþ;Ò<5ªÿb_jZ%ÒÞX-൷º1Gp™ŠlCw-:«3!!ÑÕtÿg¿ù ~ÿ±~ÃÿI£¯;ý”¼'ªøwãÇí5y¨iš……¦¿ñ*ÎÿLžâÝáQ·_øjݦ…˜$bx'ˆºä†EÎä`<ã×4>þÝß þ-|R¸ð~©ø€jðjº–… Æ£á][LÒµ=GOšxol¬µ›hìïn"k[²b¶šG)ipà†F_Pðωm¼Y§Kuk£Q]ÜÙ2ÞØOe!x'’!&DvŒ¼lR@ +J…$ž7Go„~Øëþ\ü±ðÄ ;ÅšwÇýKÆÚ…î³áSKЬô{?‰Søˆ]&¥qn–·_h´Š‚;9'‘伄²$)q<ÿ€¾>ëZ_í7â™u¿öÚ¿€|+â-wᮑoy¨ÃgªkÐø¿Ç’én¿òìcÑ‘,I{K‹[›!5µÂ-™ˆôwá§Åâÿ‡nuo_ÿhéöz®¥¢M(†Hv^i÷ÓØ^E‰Iòî­§på,¥Xôuùßð«Â~|)øÒ4]3ÆÅ~'»ø£Â4µ·6úv‰«Mâ={P¶:¥ÀòZKÒ¶—šÙk3álÞo3Xãþø‹âwìå£é>>o|_øðóÃ>?Ð!ŸÃ÷~ñ…¯õëR×VÐE•ªø»Y¸¿ºÝ¨êÞžEºšÛL‰m°3Ý-Ò€¿hOÚsÂ?³‘ Þø¶oøIõ_ìM&ÓDðÞ¥â ýBóì·f(ítø'±ois!m›UbbHã:~;xgö‚ð¥Æ¯á›­BH¬îÚÂúÏSÒ®ôOK¸’y7V7‘Eum#E,3*M†xePc•¾aøŸû2|O¼ø/ûø3Sñ§Œ!ñׂñ®sQø¥¡i´o\_y~&ñ•­éö^L‡ív3YCu/˜Ë]’jkµ˜3yÙPÁ\¯€þÀþwü-Oˆ?ð‹Âßÿ…9ý•¢ÿcÂÇÿ„‹ûWû{ÎÔÿµ|¿øHâgö²ÿbmÿ—Mþo“ûßµWÆ:g…>"Þøçáö»o¦~ÑÒüQÓ¾Íañ·P¿·ñSZÚÜOâO¿ˆaÐ¥œ}‰d’ÆÛÄ +xl‚Â͘,–˜ýo¢¿;þ üñÏÇÚHÐæ×ÿhí övž+¸ÐR÷Zñ‰©êV«ƒ´•åÙMj ª|G-¹žhnš$H´çheòûoŠ?~x“ãE÷Çýã&·â¿„©¢=Œ>#Ò<7ý™{'…bÖ­õ8tåE†â]JoE$’-Î$Š0‚#f´ú{ð£âއñÇáw†¼kákãªxcÆU®·¤^ù2Aö»;˜Rh%òäU‘7FêÛ]U†p@9|Wø£¡|ø]âoøªøé~ð~•u­ê÷¾L“ý’ÎÚšy|¸Õ¤}±£6ÔVcŒN~YþÄ ÿh ë´ís_ø¡àÉ|?áÿXh~‡À¾"ºµ:ŒºÄ7·+©[xvÒOµ v)SU³—Sˆ&ëq$‡L}þ ;áMwǾøÍ¡ëZgÆýkDÖ¾MaðÓOð¿‰.moüO*k)£† +I£h*©«jÀÌ"Êûóž+ÒüámO]×uK CÑm%¿Ô5 û„¶µ°·‰ Ë4²¹ hŠÌÎÄ’@©_”¾~Ñ|Eû@øhø“â©âoi_tEð§ü"šÜÞ‹sc«[øz/í{ÝU|2›‘ôFݦY. $;.HÚ“W~<7ñgQýº´+½Æ_ô Aªøgþm&çÁ¾-Ô¾Ýá1§é‡PþÒ¾¹Õ-ô{{‡—ûi'þÝ´›YL̘éÑ€ÐÏx³KðfŸ泩Øi6s]ÛXG=åÊ[Æ÷3Çoog %žX¢Dêï"*‚ÌÔ¯ËûÏ…¾%øÁû"Úi:Ýí=¨üF´ÿ„;[øËäÚì:Rjz‰4;ý^]ÎË!¸Ž;mbKeð¡û3"PÒ)I®xsö§¾.jñ—ÄøY¿ñ[ÿchð†êÿØ_aû>¦¾ÿ‰¦¥ªÂ-×û +Oø—Ø}»ÌýÝ×Ëý«5~Žéß´-_â–³à«{ï3ÄÞÒ¬5½BËÉ}žÎúkØmeó +ùm¾M>ñv«_',2èëâßø'„ô_Û?ã6¹àÍ3ã|^ Ô|àûµ‰Vþ-[««ø/¼L÷0ÛËâ1ö¦Ž8®lؤD¦|à;¾~Ò Š( Š( ŒfŠ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¯™U·ð·Æ_‹º‚Ãn··^*µµyÊ1¢MJuBq’H䀻zšún¾Aø¥x-~*|O®O‹á$u#þ)ý‡é@\Ÿo¦1ºí>Š3PÇã›÷´25̨»¶oÆv3ŒúךÃâÙlð–’ ÆkwSø‘mw«Øê#ÍžC#i²G[Lޱ†&óóFz†?9µâ¯ˆ:„hc¸g`è<Á÷—±í_>þØ^)¼Õ>xÅ$™ü£¥LvgåÈRAǨ8#Ѐ{W§ø¿P7š¼× ¨\j‚l?Ú.¤ÍžÎ #Ž]*êbÖÏr¶Ëg:%Ó^£‹AÚ —ÊÞ¥kà/ÛGŸ¼{ð›ãF…¦iŸõŸŠ:Õ§Ä›éío®\ø^ÿÂRé>!OæÄàè’^;7…Ô&˜¢ÎgÇP¯³¿à ÿ ¯.à–Ÿ<á{xƒP“á^½¢i^uÖ±ªêR"â"ó$i.n®$m«¹Ùå•Û$³1$è*(¢€ +ù‘õ[ |eø»¨,6ë{uâ«[Wœ ó$Ðt§T' 4Ž@è ·©¯¦ëäŠW‚×â§Äð +äø¾GR?âŸÑðqø~”Õ·Ä{û•w +3QÅãMFf–6žeš Å×o)ޤިï^gŠeƒjTÉ9À÷â·5_Å©j–+«Ó÷Õ|¯ô—ÀácU!°1…ó¦?ÕŒ­Xñ'Ä›Écxä˜J1»æ¯ý°¼Syª| +ñŠI3ùGJ˜ìÏˤƒPpG¡ö¯Pñˆ]Ö&º†ßìñ¸)Ú°0XíU\ŸöT©É>)ûW_#|ñh.¡›L™G¿Èhô«ö„ÿ’ãûïÿôšJëÛ¡®Cö„ÿ’ãûïÿôšJëÛ¡¦„ÏÊ wOþý«MÇü›ÍÑéÿR“ÑZÞ ´ÇüV“?ðÎ÷?ú‰½îâåy/CÄÂGÝ~¦/„?iûk_ø&FàS¦Lfo€Öp}§Ì~o £çÏ|Wë\ŒúŠü@ðô_ñŠ>oú¡ö?ú‡Ç_·ÊØ®Ž"ÂÒ£Oé«sE7ë¡åp®6­z˜•Uß–m/Dr³ßü?ÿØ¿aÿ¤Ñ×_\‡¾ _øWA²Òì0ÿÀm+ÿèÿ…k­ÑAñ‡þi_ü‡@…sž!øQáoøóþ)Õ¼5áýOÄþûOö¯w§C=þ‹ö˜ÄW?e”É› '–Wz€#Š¥ÿ +×Zÿ¢ƒãüÒ¿ùøVº×ýà6•ÿÈtØQ\ü+]kþŠŒ?ðJÿä:?áZë_ôP|aÿ€ÚWÿ!ÐaEqÿð­u¯ú(>0ÿÀm+ÿèÿ…k­ÑAñ‡þi_ü‡@…y÷ü2ÂÏø^ßð´¿áZ|?ÿ…›ÿCwü#ÖÛ¿ñïö_øýòüÿø÷ýÏßÿWò}Þ+Gþ®µÿEÆø ¥òð­u¯ú(>0ÿÀm+ÿè°¢¸ÿøVº×ýà6•ÿÈtÂµÖ¿è øÃÿ´¯þC ŠãÿáZë_ôP|aÿ€ÚWÿ!Ñÿ +×Zÿ¢ƒãüÒ¿ù€; ++ÿ…k­ÑAñ‡þi_ü‡Gü+]kþŠŒ?ðJÿä:ì(®?þ®µÿEÆø ¥òð­u¯ú(>0ÿÀm+ÿè°¢¸ÿøVº×ýà6•ÿÈtÂµÖ¿è øÃÿ´¯þC ŠãÿáZë_ôP|aÿ€ÚWÿ!Ñÿ +×Zÿ¢ƒãüÒ¿ù€; ++ÿ…k­ÑAñ‡þi_ü‡Gü+]kþŠŒ?ðJÿä:ì(®?þ®µÿEÆø ¥òð­u¯ú(>0ÿÀm+ÿè°¢¸ÿøVº×ýà6•ÿÈtÂµÖ¿è øÃÿ´¯þC ŠãÿáZë_ôP|aÿ€ÚWÿ!Ñÿ +×Zÿ¢ƒãüÒ¿ù€; ++ÿ…k­ÑAñ‡þi_ü‡Gü+]kþŠŒ?ðJÿä:ì(®?þ®µÿEÆø ¥òð­u¯ú(>0ÿÀm+ÿè°¢¸ÿøVº×ýà6•ÿÈtÂµÖ¿è øÃÿ´¯þC ŠãÿáZë_ôP|aÿ€ÚWÿ!Ñÿ +×Zÿ¢ƒãüÒ¿ù€; ++ÿ…k­ÑAñ‡þi_ü‡Gü+]kþŠŒ?ðJÿä:ì(®?þ®µÿEÆø ¥òð­u¯ú(>0ÿÀm+ÿè°¢¸ÿøVº×ýà6•ÿÈtÂµÖ¿è øÃÿ´¯þC ŠãÿáZë_ôP|aÿ€ÚWÿ!Ñÿ +×Zÿ¢ƒãüÒ¿ù€; ++ÿ…k­ÑAñ‡þi_ü‡Gü+]kþŠŒ?ðJÿä:ì(®?þ®µÿEÆø ¥òð­u¯ú(>0ÿÀm+ÿè°¯ÿhÿ„¿´ÿ¾/¼ðÇ€%ñ~‰â{û}ZÞòÏY²¶kf]>ÖÍá–;™b`Á­K‚›”¬‹È ôÇü+]kþŠŒ?ðJÿä:?áZë_ôP|aÿ€ÚWÿ!ÐÄð«ãÑcƒº¦=õÍÿ“i¯Š8ø;ªàïGÿäÚûsþ®µÿEÆø ¥òð­u¯ú(>0ÿÀm+ÿèâ þü|¸ˆ©ø=ª}5Íÿ“k‘ñ×ìeñÏâþ‹w ÍðÖçFMe ™¾½ÖôÃmbåódÜÉ!DÎâ6b&¿CáZë_ôP|aÿ€ÚWÿ!Ñÿ +×Zÿ¢ƒãüÒ¿ù€; ++ÿ…k­ÑAñ‡þi_ü‡Gü+]kþŠŒ?ðJÿä:ì(®?þ®µÿEÆø ¥òð­u¯ú(>0ÿÀm+ÿè°¢¸ÿøVº×ýà6•ÿÈtÂµÖ¿è øÃÿ´¯þC ŠãÿáZë_ôP|aÿ€ÚWÿ!Ñÿ +×Zÿ¢ƒãüÒ¿ù€; +øßöøKñ[OøÛâûÏ x_èž'¿·Õ­ï,õ›+f¶eÓílÞc¹–& Ô¸)¹Jȼ‚LÂµÖ¿è øÃÿ´¯þC£þ®µÿEÆø ¥ò|Hß +¾=8ø;ªcß\Ñÿù6|*øø£ƒº§þôþM¯·?áZë_ôP|aÿ€ÚWÿ!Ñÿ +×Zÿ¢ƒãüÒ¿ù€> Ÿá/ÇËˆŠŸƒÚ 'Ó\Ñÿù6¹~Æ_þ/è·z ß ntdÖPÙ›ëÝoL6Ö!þ_6A Ì’Lî!#f `kô7þ®µÿEÆø ¥òð­u¯ú(>0ÿÀm+ÿèhOù ~8ÿ±~ÿÿI¤®¹Žý+‚ñÁkÿh7º]ÿ#$ÇW« +ŽOi´½ô÷†£Ïì‹áÓù¡ö?ú‡Ç_¶è>Qô¯Äï ¯üa¾Øÿê!~؈ëÎ⃠þú ƒWïqõñŽ¢Š3_&}ÈQEQEQEQEQEQFh Š( ¸ÏŽß|û1ü3ºñŸüCaá_ +X]ÙY]ê×ìRÖÍîîá³€ÊàfyâV‘ð‘†.쨬ó¯Ÿà¥ß ÏÆïÙvÏÂÒøhøÇOÕ<àíM!ôïínôèü]¤K{çÁµƒÛ­ªLòïI!”1 _Ó¾)hZ¿Å-gÁV÷Þg‰¼?¥Xkz…—“ û=ô×°ÚËæòÛ|š}âíV,¾NX(d-Ñ׿ùø]ñÃáoįŽÚ=Åõ=#ÂÞø[á=7dzOs­øó¶šî¯>¹t²ÀÍruˆt›Û¸&û+ Ùn"[«X {ËHSØ>ÿÂÓÿ†)ý¡ÿáXÂößøšÿÂÿ„ÛíŸÛ¿ò³ò~Ñý½þ›ÿ!ÿí-ŸÚŸòÏËÛþ‰äPØWæwìÅðßâ•ïÅo†–ÇÆßüQðßþU…æ ×>ñ§„cµ6Þñ4ó ‡×µkÍf{7¼MIÆ=-mãfškÔg†~1øKöHð®«'í/ĉ~è7¿ÿ^È>%O£>¨<@ñ»Ä±‹¹41åø„>$G¤)xŠú¡E~wx³Ã_¼?ð§L¾žOÚ>ç\Õ~/øÚ÷ìšEþ¥,’©ñÝ®Š"fwûqéñÁqeì'ÃS$2¦ °›»kȽþ +£qâS¾Ðô·ñ‡‡ü;wws}¨ø§ÃšO‹µË«¨R4µÓÛOðµõ–¤ÑÜÇqw)¸y¬'OT’6–âÝë*+ó»ö=ñ/Ä¿k^Ö~6GûGCñ‡Vµðc©Xh §I èï¬ VÝQ!óã¿EÔR=«h« ÓÀÓmþ+^þÇú„>½ý£´ïŽ2øEO‹WzÕ–¹{ ZßOLôš\Ë ³H¶ŸÛ¦ü#,p´a„N“!€é…fxŸÄ¶ÞÓ¢ººQ–)ní¬•l¬'½<óÇ£ºÆE/!"@òHÉ;¯ç‰¢üWðÿÀ? +ñ7íâûñ¥Óøy´¯ kžº–7¶±ŽØjW÷úÊIãj7òx˜¶1ŠæÞõ ³“I¼‹°ø…ÿ N?>=MþüÌÿ<5ÄÒý²-6-8øÇGYmÒ1ºÑí×JKÉVãFuG°¹¹‹[/m£žäôŠüÀð_€>>|/ýš>¿ößÇÿj~:øW¦êŸ¦Õo5ÍVÉíµo­íµ¼jš~¡‰wâH’=="ÔnÞ)7Z„)8ôïÙÅ~-ñ'ì¹ûdY|Ôþ(_ø‡@ñý‡ÃH<}q«Ë¬é×íàÍâÚ_“sgRžYU.ñ ǔ೴ïŠZ¯ñKYðU½÷™âoéVÞ¡eäÈ>Ïg}5ì6²ù…|¶ß&Ÿx»U‹/“– + tuù_iá8,ÿiÿë¾ +Ó?jè¾j6ž°ñÞ¡ª[ü@_][ÁœÃ§Ë|?·š8õŸ´‰¥’'s =ÞtÀ?u¿‡_¼PÚßÇûkŸü+›]øI¤%æ£ö¦£·ã9t¹€´ßêé1è)qcz]î>ÓÔ­®.#èïÅŠ:Àï…Þ&ñ¯Š¯Ž—áéWZÞ¯{äÉ?Ù,í¡y§—ËZGÛ3mEf8ÀàWG_ðQ¡ãoÃ^&ðµßü4߯_ê¿´+"øIäðŸˆ4𧌥Ð,¬àþ$ iˆâ+P×fhœÊ>з${ÿì×áßðñ½KPñWŒ¾ È×â?í]þÝû þ­÷Ë¢ÿÄÒçTÿ„wýGö4Ÿñ)°þÒó?wqÿ1I¨ôŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ‘þáúRÒ?Ü?JhOcù¯•1áídÿÕÔ?õšŠ–eÏ…õ“ÿTCPÿÔj+ôž"øèÿ׸Ÿœä oñËô>œð¿ü™ï‡ÿì‡Xÿê!~ׯݯÅ/ ÉœèöC¬õŽ¿kSîŠðx£àÃ~‡ÿ_m®SâGÆ¿üKWñgм7áu¿,-ޝ©Ãd.JãpO5—v7.qœnµà‹>!ñÄ67–ÞÙ¥ÞÊÝjD|´QßaPÇnñÅp´/?·gì÷ž› Ômü?á¯ü^´Ð?¶£&M2i,ï¼…”4^|“Çå‚èè›*N+[Æ?µÄêW^³ñt·Rh¿tŸ6fÓê6Wví4Öò¢Ä óáf^$CÂeAݻөT¿¹%f“óIÛ{_g+5¾úXóyN)ûH»¦Ö–³k›mz¨¶ºo±ÊóÀ¬¿øÃHðe½¬ºÆ©§éqß]Gcl×w +Ü\Hq(XÒ1áTrOA_ÅûRüEŠÒãÂ2øªà]‹íàSâ™tûAyo`!6E·Úþé\÷’vç¹OüVñ/ÄŸµŸ‰æ}ÇxžaB¥ÕmsÉ[M¯{;+ín½Z~B­ŸSŒ_$]ì÷µ®”ž·û/cô$¨<`Öþ'xsá>ˆºŸŠuýÃzt’ˆëT¾ŠÎ‚B‘•K¬@Îp§Ò¾9пko‹>%ø©k6ÃR·Òô߈Íá6Ò®¥ÐlôCh’ˆ æ5~ÀùË´”f¬eM{íüwGðcŽághÿúÅsË*•:ЧVIóvwk­Ÿõc¢9¤gJ¤éÅÞ +ú«'¾ßq쟾'xo⾈u/ kÚ/ˆôÔ• k­2ö;¸€P¼l˸Œç‘ë[û¹ö¯„¿iÏ:çìùñÿ㟉¼FKxr×TdŽËQžéáIÝ]–3*Zº‘¼íâ=ß.áX¿´ÇÅŠŸ³ÏŽYÖxØÇp]Xº‚}>ISqšQ’»Õ_–úys/U©ÉS>%8Î.RŠmÙimm¯­ä~„OÒ¹½sâ÷…<5.´º—‰ü?§·‡cŠ}X\ê0Ät¸åÿTóîaå+àí/€Øã5ñŸíuûVüEøK7Žîü#ã]Bò…?ÙZŠjVúU½ÔóX‰“$÷RÎ%lùBÆ(Ö6Ø]”ç/öÕñ…Ö¹¤þÕÖç¬^ð̱46GpÆBå„“¢ e´Hìgn90¼;V§$§%Ë/[­`¶k´Óóßµõ©žSMÂ1|˾Ýz¦ö±úŒ³FH!†A‚)ìÆ¾7?´Ž|+û^ÚéÚŸ‰æo]xŽÓÃú}®m¦jvLòس›kÜ:ßZ\ Ì߇Œy?cdÇjò1ØaœT¤š’ºµô¿G¶«ªW±ÛÇG“Mhïù¯"J+…ÿ„ïÆ¿ô!årð£þ¿ÿÐ…ÿ•È?¸Ï@þ¿ÿÐ…ÿ•È?ÂøNükÿBþW ÿ +þ¿ÿÐ…ÿ•È?ÂøNükÿBþW ÿ +þ¿ÿÐ…ÿ•È?ÂøNükÿBþW ÿ +þ¿ÿÐ…ÿ•È?ÂøNükÿBþW ÿ +þ¿ÿÐ…ÿ•È?ÂøNükÿBþW ÿ +þ¿ÿÐ…ÿ•È?ÂøNükÿBþW ÿ +×ø£ðŸÂß|}áoøgÃþ/ðÆ©åý·HÖôøu ¿.E–?2 •£}²"8ÜŽ@4|.øOáoޱ𷂼3áÿxcKó>Ťhš|:}…§™#K'—*±¦éÜí,ìO$šÈÿ„ïÆ¿ô!årð£þ¿ÿÐ…ÿ•È?€;ª+…ÿ„ïÆ¿ô!årð£þ¿ÿÐ…ÿ•È?€+ü?ý”>ü(ø¥­øëÂß <á¯x“Ïþ×ñ•áë;=WUóæYçûEÌq¬²ù“*ÈûØîu r@5èUÂÿÂwã_ú¿ò¹øQÿ ßèBÿÊäá@ÕÂÿÂwã_ú¿ò¹øQÿ ßèBÿÊäá@ÕÂÿÂwã_ú¿ò¹øQÿ ßèBÿÊäá@ÕÂÿÂwã_ú¿ò¹øQÿ ßèBÿÊäá@ÕÂÿÂwã_ú¿ò¹øQÿ ßèBÿÊäá@ÕÂÿÂwã_ú¿ò¹øQÿ ßèBÿÊäá@ÕÂÿÂwã_ú¿ò¹øQÿ ßèBÿÊäá@ÕÂÿÂwã_ú¿ò¹øQÿ ßèBÿÊäá@ÕÂÿÂwã_ú¿ò¹øQÿ ßèBÿÊäá@ÕÂÿÂwã_ú¿ò¹øU=ãÚ7Š®tm{NM Q£UˆÞ,æM뻂ª¯s÷¨Ѩ¦[ηP¬ˆr¬2)ôQEQEQEQEQEQEQEQEQER?Ü?JZGû‡éM ì73'üRÁÿª¨ê 5é‡üQºÏýýCÿPi¨¯Ò¸{ôëÜOÎx}ûµ¿ÆÿCé +ÉxþÈuþ¢×íb}Ñ_ŠÞ_øÃú¡Ö?úˆG_µ)÷ExQða¿À¿C»ƒ‰‹ÿ¯Œáÿfïù"º7ý·ÿÑòU߉¼ñ…-SÅžð߉ÖÀ±µ¾™ ð¶-Å<Õm¹Ú¹Æ3´zUÙ¸ð[F÷óÿô|•äÿþ+ügñ/í›â¯ü:Ô~Yè~ð_‡üS=‡‰4;éî¼Eq¨ßk5¢ê^"iñìÒ#Q1²¼(nü©B›äá)EóE»÷>ÞQŒ•¤®™íið{Âq|<ÿ„I|1áÿøEv¿±ÿ³á ï+ämòñ¿æÆÞ¼õ¨´ß‚> Ò|5¥èÖžðݶ‘¢]CN²‹L-ì.C3 â@»c31 6XœòkÊtOø)‡Â‹ï…¿ü[}¨øƒJÓþ xSNñª#h—ßðŒé7Љ`»Öf³Ž{m*ßh›7“Goþ‰tVV[yY4>Ó톮õ};VÔ/í.lt:÷J{¨X˨OZ%äÚ\\µ±—Î6‘°†Ø‰ûYëï=Höô÷VŠÛ¿fKo‰¾¼Ñ¼<ÞðÓêºÄZƨ·~´Õ¬u·VRëwo _0¸TÌŠé((¤8ÅPýŸc­àïƒu bÄ·Z¯ˆŸÄÒÑÒÖÆÊïäX>ÉlÏ/°ÇjŸ;0 Ã8gâÏø*¯‚ákøBѯ5 Î}|ÃãWñׄµŸ I¡èÏáßêß¡Ôà´3?‡åV˜‰#TŠà6ÖÚËíß¿i¿þÑSóø‚ÛPÑ<¦¾Óî´Úd?Ú+û¿+‰öùŸêþO½÷xéÅ\øƒðÃßt5ÓµñÃoø-Gü,OØ[örñÄ:߉Ÿ¼Uá_ kž68ÿ„wíº†›¥¨Íl.LöÚ{[ßÛIi<ŒùþÚÑE+v¡¾¸ý¼þXxóVÐo¼Uý“ý‰öå¹Öµ=2òÃÃ-ŒrË}o³4I§Oql–÷M<Ü<°‹+Ï1ì³ùx{IÝ;êŽe U–»èwø5áxBóÃÚ/…¼=¤èŽñw¦ÙiÐÁisæ(I7ÄŠ·( +Ù `ñU´/ÙÿÀ¾ð]ÿ†ôßxVÃú«—½Òíô˜#²»b$*ª2Àð£ÐW€øKþ +áM_ãïô›ûOi^ðÖá«&Úûáçˆì|Q­jš•ψÄÚ\Ö‹{{[i1̦ÖÕÂ$W®ÎR<ž¿àßíÁ§|hý©µ¯ +i ý£á/øE#ØJìm$c¶uO‚ÞÖãÕRó¾»Mvmõ%›M†A¨Eú˜æÊþñcçj¶BöÅu]hÇÒ›ÄUiý⎒Ú+îG&~ xEþ ÇâÃáoŸžZkM‡íè»<½¢}¾` \nèqÒº•Ž;Sv zVrœ¥ñ;—F7åV¸´QEEPEPEPEó÷í-ñGâŸü57߆Ÿ 5ï‡þÿ„£Âž#ñ6£©xŸÂמ ÿmæ…mÅo¨Øìßý­#3³¿ú¤FI  h¯—lÿà§ðÏ„ü=âoˆÞ(Ð>iòÿoéZÞŸoqw :Ž•âk ÜÜŪ.ÈcÓâÔ®–1%ļ±^ÛÎÂÑ`¸J5/ø)—„Sãg…í ÔE¯‚o<+âMO\MS@Ô¬MãÍ#òjšý®¡«ý†#-ß…ukk*êö8¤´°Ôo$¶[m7P™n-‚XÞÉ Ó5媈·\B®ìTWÅ¿µ×ííªüý³µo‡S|uýœ~èzg‚´_ZOñ+L{»­~âúûY·-ØëZràM6ÜC›®YFÐ{ØCþ +{ûOø·]ðç<=ÿ +ÿÆßè×úo„涺û~Ÿf¾𦧨Cy,ˆ«ö‹[凉 3.ÌE”•€Ô4WŽ|(ý¼þürñ'†tÏ x¬êsx¿JµÕô‰ÿ³/ ³¼[›Ô`´ûL‘,)¨5ƒ­çö{ºÞ Sç˜D9zö:(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š+óþ +QñRð_íÑðúÖÆv†=J[‘0V#vØl1Ÿ_¾kôr¿2?િò ÿëµçþ‰Ói­Äö?E>Þ¾¡à6W,Y¡_¼ÛAÞº:åþ É5Ò¿ëŠÿ!]E!…Q@Q@Q@Q@Q@Q@Q@Q@Q@#ýÃô¥¤¸~”ОÇó{:à­`ÿÕÔ?õšŠšå1à=gþÈv¡ÿ¨4ÔWéL½úõî'ç=nJßã¡ô§…Fcg§ü(ëýD#¯Ú…è¿JüXð§±Ç‡ÿì‡Øÿê!~Ó§EúW…Åü ô;ø7ø˜¿úøÎömÿ’-¢ÿÛý%y·ÄÿÙcâ6­ûSkß< ñ?@ðVŸã +hÞÖí®|Ú¶«Zuæ­p·Z}Ó^ÇmopWW”/ÚlîâW†&h¤]Ñ7¤þÍ¿òE´_ûoÿ£ä®æ¾Lû“äï‹?ðKûmoÂÚ„>ø›Oð?Ãïü5Ó¾ø›H½ÑçÖn‡†¬P†Ú=.í¯"6—‹«|†âé/•ˆ¶cîäç|~ÿ‚dÙüEý–dðV£­xƒ\ÓìÀ¢€>ø¿ÿžñWí;ã­SÆ?¼kðƒÇ>'Oìì]:ïá\ÒøN?ìÈüEüLtË^y/·ÇâK¶M—VþTÖÖ²|á7ôÿÙGö +¹ý’þ! cA×¼!k¦ê^Ò´WEÒ¼‹§Ä–—¾#ÔiÐÚÌ‘YÆ×zô{D¸u†É–Yng¸k¤úFŠ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š+Ã?hßÙËǾ=ø÷à_ˆ¿¼sáë^ðþ¹á¹àñ'„.|Cko©Üé7 ê°j6/‘¾“»†7ʽΊù;âüÃKñ&­ðÊm#ƆŸÃë©õ;É/ìòëÄW÷^2ð÷‹/¯%xÞ¡’âïCœ2C‡R&8ãŽÿÁ+´¿þØZÿÅ»ÿjšõÞ«©èo¦X%¾§á[ûÍ3š|w–·nò!’$ðÌ’HˆuI­æŽH<Øî>±¢€>.ñ—ü;Ú÷ã=öðÃÆþ+¸»Ó<]­¼ ôë_ë:]…”Ûh:ž£zÐéVs6Ûl 4‘5ÅÛ%ô/$sÛ÷ÿðN/Ùçöjøi&¡®Á¨Zx‹T´‹BÓtË»¨'oøOO»¾oøtÇ$–6w¬³LÒ\Ë-Ä·»¹‰`eúJŠùûþcþ5iÿ Ñÿ OüÒ¯øV_ð‘ÿfÿÔ#û7íßeóí§•æÿ³ægxûöÕ|añ“_¾·ñ®Ÿeðûƾ5Ð~"xE“Ayõ™µi_cšˆºXmìØèza–,§‘‡ÚÂÏ·úJŠóß| >ý©¼eñ/ûPÍÿ o…t g}›oÙ?³/5›Ÿ?ÍÞwù¿Úûvl]ŸgÎæß„ñÿÿÁ>5ëoÚgÅT–ÊämaõòïìŸÿø×¿eï|5tø•ý­£ü>ð—à‰­áðìv7šâØØÅisγ4o§¬‰-ì0K —–×WwB-Amn'³“ê*( Š( Š( Š( Š( Š( Š( Š( Š( ¿2?િò ÿëµçþ‰ÓkôÞ¿2?િò ÿëµçþ‰Ói­Äö?Cþ É5Ò¿ëŠÿ!]Erÿ?äšé_õÅ®¢ÂŠ( Š( Š( Š( Š( Š( Š( Š( Š( ‘þáúRÒ?Ü?JhOcùÄœçÀÏýëÿýA¥¢‰¿äŸë_öCµýA¦¢¿Iâoއý{‰ù¶AðÖÿ¥|)ÿ&káÿû"?úˆE_´ÉÑ~•øµáAŸØÛÃßöCìõŽ¿iS¢ý+Á⃠þúÿÿ_ÃþÍ¿òE´_ûoÿ£ä¯ñ¯Â)?h/ø)Ä=*÷Æ¿<9ƒþxCSðøð猵.×K¿»Õø/€ü?­`|ðÿƉÒ&·6•ýŸ§jVw— lmî¾Ùp¿Ùz‰]\Z Åªý¡¼ÙÿÁ\®~xW^ñ¯>ßèÿ 4ÆÞ´Ôì5è/õ}^÷Ã)®ÝO4V&8ãK9¬ô À²Kr“-Þ!û;[í¾}ø×û|<ý¡|Uo¬x«FÔ.îÒÑtëØìõËý6×_²Ww[RÞÚháÕ,ÔË>-¯’x@º¹P›n&Ÿñö&ð/о7‡,ü; ?Ø5mÄšLZõ½Æ±¥C¬k0ê‘ß\]Ù›ˆþÙo7ö΢$µy2—,©åmåÚ—þ +Gãÿ€¿ü-gñKÂ:wƒ->]k°xÆW:ü~&Ñ¥ðî £­ÍŽœ ‘ÏáÑ*Å&èÙþÎÛÑ£Èú?öý²ê’Çq6›®ÛéZœWx ºÎ“¥\Éq[±™Õ¢DžÔ‰¤xâà?fßø$w‡| â=oÄõŸø\þ¯ö[xÓR¸×.ô«{[{fÄDÐk:¶«<Þe¿ˆ5h¥ŽK“jÉ4em£•^Y}ûàoìÇáÙÙµ9<;ˆ.µ oÊ[íSÄ>$Ô¼Gª\Eó ¹½Ôgžçìñ4³¼p <¨ÞâwTVšF`€¿àŸ¿µWÄ{Ï„ÿ°¿‚>$øÏÄŸ¼S«[ki«^]43|Fðå×€uIe”'Ëqö é`²dyf2ØY^Î#7öŽ¿ÆŸðVSKø'ðÄÚÃm?SÖþ=ø+KñNŸ¦ßø¡ì­t»‹ýgšTV’Ü¥”ÎÑ«ø¡di–âÈ2æ?~пc/†ƒáYøCOI~Ú\¼’ËuáÛs§6šðÇ;9–HÞÑ‚:JÎÇŒH£uä4¯ø%çÀ­Æ6ý¿¶êúWÙâÓ§}gP“û.ÖÛTÓµkK eiÊÛéö×Ú]”¶ö1µ·Û*E%Äé(δoüÇÞ5øq¥èº_„4ÿ x¯Xñ®“máé,|gsö}NãBø‰áÿø‚Âöu±I-læ¼¾ò!–8îMÕ”“I4Î~È݇Å?ø+‰~xxü%þÔø»§jº†³¥i7zZÅgc¢_<Ð]ézæ¡.è|E¥eÓ ˆH.Ñ¥]¹ºöïÿÁ9þüJÐâ°Õ|1¨,V·z¥ý´Ö"Ôôû«KK^´ñäÑ\[ÜG,R>­ait®Ž F‘”Œ²çþ Ûð® Yi©§øÂÊîÊòâ÷þë¶~(¼yÒæ:ÜW‹©]FñÚÙ£G=Ë¡K %Û¶ÒÜFGöTý°|UûVx·Å-iðÜøGÃÕt6ãþ=Zk?Áöß Yër­Æ˜-8.-äÔì-ZtÙ?krè`Ž)þ¯=øwû.øàýÔá= þh%Õ`Ö^ËH½¸²°iàÑàÑaCk‹ ·ŽÂÚÚ$¶Ùä+[Å(ŒL‹ ô*(¢Š(¢Š(¢Š(¢Š(¢Š+Ã?mÍÃZŸ…ô9üS­üPòšíì4_ +xÄ×z§âíZTÝ1Me=µÓÉPܶƺŠÎ8ZææìíVâÛÜëË>=þÇþ ý¥»†Þñí^æ—Mº·yc‘ì­X¤…€0)ÐÆ^Ö¾)øoG×÷ì‹gxÃZOøFbµ¾¶¿··ÑŠÝƒ¢Û¥Õ•”‚ 4ÛEþƒj¥ +ÛĨà-ðsâöaxÚ'íã³jº­Ï‡|¤üA¼Ð~ ÚA-®Ž4ë»ýBûS±¾k>Ìm.µž4Õôä–ÕÛÉÓüàÏüKQøÛûE~ú&µñŸ@Ñ®N• ÿÂÁѤÕltûÏëÚÿ‚5 ø|ÛAåJ–öÓ0Çå£Z]]kðF›n,»n¿àž¿ ï<-e¥Í?ÄùeӮ纴Ö⇉Û_µ¤+=´z©Ô>Þ¶r}šÝÞÐN-ÚH"ÄdEqèüðkÃà!ðöŸaið²ì^xRÒÁM®†ë§\éŠ"†"±ùkgyq +ÆT¢‡(dB ˜^øñãë/…^¿&øŸ§]üVðV‘©ë׺ŸŠ®o#øÃqsâ? ÚMyáEûT§ÃñÝA«_ÚÂ’&„ai®c·[9&Ósÿn/ÛÏ]ý›¿aŸ´¯ˆþ ø?ã]CU×!ð´>4ñlw¾,ð>™§ø[KÕ®¬[Q¸¹¸]GP¾¾½‚+u¶Ôn®`‡ÄK )Óeµ¶ý Ñàœÿô-;V³‡Ã„Öš¢ØZÁuâ-Næ? [¬ñ\Gˆ²Ü0Ñ#Ž{kIcM3ìÂ'°²d +Ö–æ>ƒNýŽ>ißü[ðÍ´}CQð§­/,¼Ký§®_ê:ž¾—vÂÖcu¨Ï3ÞÏ!¶ Èó—Ža(Õ@>Rñ¿ÅûÏøïâÅx÷Äü"_~ø/Â3é(ºo ÜxsZÁÍt¦Â¿³¯¼ô×õ&K¹¡–e4r¯ÙíÌ_ åž&ýþx»ã$~;Ô4Aõ±wm¨Ïo·¨ÞÛŵõÞ–“ »È|›o*æâ &ŒÙÚu6Ðy~§@Q@Q@Q@Q@Q@Q@Q@Q@Q@~dÁUäþþÿ×kÏý¦×é½~dÁUäþþÿ×kÏý¦Ó[‰ì~‡üÿ’k¥×þBºŠåþ É5Ò¿ëŠÿ!]E!…Q@Q@Q@Q@8¤ ¡†ESÖu«?i“Þ_][ÙÚ[!’Y§GJ:–cÀZ,L¤’¼‹dŒû ò×µ|?û\Ár¾ü‚æÓÃL¾.Õ % Ë'‘atæCËóÙ@ûÕù­ûHÿÁj~1~Ñ’Ü[YjW.9!-ìI±·ÛèHýëÿÀ³õ®ªx9ËYh¼ÏŽÍ8ß.Á·KžK¢ÛïÛî¹ûñOö«øqðV)?á(ñžƒ¤ã„øŽy¶S«ÅÙ¤î¾DàäQEÊ}hR?Ü?JZGû‡éM ŸÎKŸkkžŸõýA¥¢ª$ù𦼜qðCPÿÔZ+ôÎ%øè׸þ§ç<;ðÖÿ¯’ý©<&ã|=ÿd>ÇÿQëö•z/Ò¿<"Gü1Îëÿ +BÇÿQ«öz/Ò¾Š> 7øèwpoñ1õñœGìÛÿ$[Eÿ¶ÿú>Jå¾0þÜÞøñRojéñTñ5¾•k­ÜYxgá÷ˆb“‹—’§Ùãÿµ…>#xóö@ø§¡|GÓ?híkMÖ¾kö4ÿ[xªæêþâ]OÄ©g¹” òHú;xMYe曨øŽkȦK¶¹’Ûdz¥“+N±¬¾kˆË˜¥ åþ6Ö~%ø‹ö ¸ÔHøá |A¿ñ§….<¦+êOá;Á¯ŠÚü“YI/‡ âgÄêMä’^X>Ìíÿæ gj?´-#â–à«‹ï/ÄÞ Ò¯õ½>ËÉý¢ÎÆk(n¥óùk²MBÍv³o;*+•èëòYð_Å­bûÂ:·†¡øýgñ¶Ïá]Þ›ñs[×´¯ßéZ^£q⾸º:É$V¯ºÒß^xáðÌÑ<©nŸbuu³eû7þ ¥¢ëš…„,ñ/Äÿ\µÖ«'…nõï x“@µIÙ¤‹ˆåƒW¿½¼ið”Á&³*ÞׂÍ‚†`¬¨¢Š(¢Š(¢Š(¢Š(¢Š(¢Š+Ë>=þØ ýšüSáí Ä­ã ½oÅ6—·únŸáÏk>&»šÞÍíRæf‹Mµ¸x£ïmT¼A3¨œ×©×Ëßµ7ÄH¾þß+ë7×ÿ<$MH5¶¢#n4É%Ñu™mdŒ\·öTvdD/Ÿ Ox£öíøiáOÙê_Úž ־ߪêú5½‡‡¼+«kÚ¬Óé7Òiú“‹+i®¾Ïmw“%쥊о~þýÿÂߊ:ÆØø“ÃwßÚN¡æ*;A%¼ÐKÖóÃ*¬°\C2I°J‰,2Å$r":2€¿d/„ÿÁ=%øKy'€¾ i þÂÞð]¦‘á}cÄwútWþ9³»ÑTÚÚÃq|öóiúlÒ%Û£DUb/.éáó>­ÿ‚zxGUðŸìá;êÚf¡¤Kâx¿Åv÷öïkt,5Oêš•“Ë€Kiw´3*Ms‰Šè çEPEPEPEPEPEPEPEPEPEPEP_™ðU_ù?¿…ÿõÚóÿDéµúo_™ðU_ù?¿…ÿõÚóÿDé´Öâ{¡ÿ?äšé_õÅ®¢¹ƒòMt¯úâ¿ÈWQHaEPEPE@ #'ëHÎäà_9~ÛðS¿†Ÿ±‡qýµ¨kø‚4%4‹W˜qæ·H‡×Ÿjü‡ý¤ÿ೿i¿]Igâé¼1áC‘K£é²ù1Ò¼7áÝ6]GV½µ~XFyv=ޤûV´¯-[²<ÑJJ†Ó–Ë·Ÿ¡ôoü£ö3Ô¾7þÑZÝÕ›K¥xzXõ BRHÑ!IÏVl }k÷åPà+Å¿aoØûJý~Ùøv×ȸÕî1>©z‰´ÜJGÝö¨à~'½{NÓǰ® Uoi;­‘ûO +äk+Á*RwœåêÇÑ@éEsL÷Ò–‘þáúSB{Í8›f¼¾¿uýAf¢ Ü~Ï®ú¢Zþ “Q_¦q/ÇCþ½Çõ?6È>ßã‘õ‡„&ÿŒDÐWþ¨…þ¢Wírô_¥~&xP‘û%øÓþþ¢Wíšô_¥|ÿ|oð/Ðôx7ø˜¿úøÎ#ömÿ’-¢ÿÛý%w5Ã~Í¿òE´_ûoÿ£ä¬_ +|jÕuïÛ;Çÿe·ÓÓDð·‚¼5â;IÑ]Iq©_x‚Þt‘‹1ªiVå@AyrÌ +…ù#îOS¢¾Nø ÿVðF³ðá>«ñóPÒ|cã/†¾øƒâ¤xGY»Ð<9oª[;}ªîþ(&µÓ¬Ä¶÷¿¼¼¸AvÒ<ŽK×Aãïø(6ŠŸµOÂφžMCY—Å^5Ô<3¯êrxgU:4 g¡k7³Ei«ùK§Kyî“Êñ”»£Y"Äôón­ÿ4ðD¾6øo£húgŒ/.üuãX<ycªxWYÐõ \éZ­õ® úmÝ’]½œ²irÁöŸ--Ô-Ô0[9Â÷ÿ?lŸ‡Ÿ´/Š®4 +ë:…ÝÚZ6£e%懦ÚëöJè}¥Ü\Ã:¥š™`ÍÍ‹ÏVÌ_mÄ%À=NŠø{áçüÅ>1ðGÄH¯ü7 i-ð7Æ3ÁpîšâÛYð½ÿ[Âöú¶Õaäܲj°yfF"};Ï1¬3Å÷ïþÞ¿ +>|,oë¾+6>MW_Ñ ïöe丼СÕ&ÕbòÒ#'î#Ñu6Ý·lŸfÄeÌ‘ö:+äßÚ'þ +­àŸþͼAàÛÝ@xãÂ> +×uý'MñO„µÝõ+ 6æý4Û‘u±KÆ‚µýž;·²"é#û;,ç¿¶ÿ‚‰|+ŸÂ׺“ê0²»²¼·²ÿ„zûÀÚ퟊/tšHM¶‰-šêWQ¼v·Ž²AlèRÂõ·m´¸1€{ãž ý»>üIñŒ:‡õOkZ¼šU–³4^Õ§þÍ‚ëT—I.ÙmŠÚ\%õ½ÔS[\ç·ûÛÍIm;ÇìtQEQEQEQEQEQExgíµñïÇ߳ƋàWÂð~­¢k5ðç†üE{¬j×0]ivúž¿¦i›í-"’êB—“s%Ÿ„¤o¶àf"îtQEQEQEQEQEQEQEQEQEQEQEQEQEù‘ÿUÿ“ûø_ÿ]¯?ôN›_¦õù‘ÿUÿ“ûø_ÿ]¯?ôN›Mn'±úðcþI®•ÿ\Wù +ê+—ø1ÿ$×Jÿ®+ü…u†QEQYž%ñV›à½]GU¾¶ÓìmÆdšy"ûd÷öêh¯Ä_é? <¬x—^»NÑ´+9o¯n\Å–fÀäð:OJüWý¹¿àæë¿Í{áï…º}÷…´gÝj—%´®GL¨RD*}‰oqÒ¾Åý¶ÿà¢Þ øÁkªü$Òï4i_¶1\Ã{v±Ý_Ãq;ƒ*69,2Fx×ä¿Æÿø'%¿Œt]kPÔ,¯4ÿË#ËeiáÝ;~œÑµ"ˆ:–i0Ià Îñ±£.i+¯K˜×Á¹ñ¬öúuΡqföËo¨Ø<oÕ/D¦G˜HV#™{¯Ù·þH¶‹ÿmÿô|•Ü×ÉŸr|©Á/üeŠüIð¿Ã>&Óü?ð#Uøá/„:þ±£[_×,¬_Ä6·1ÚO å´vW‘ÙßÂßhšÎâ’æ6Xˆ†H›°ñŸü'Å^.ñŸ£Ûü\ÿ„wáž‘â¿xÊÂßFÐ&´ñ•†£â v ©!Ö…ñ‚?"ãēەÓÃÆ!¶FiY>Á¢€>ýÿàŸð£~;EñßUøAá½_NÕt-JÃJø{ð¿þ-ý†ßÄWMuj5†žââÇÄw‘¬Ë,~L–ÖnÉ:FðI×ÿÁ?¿à–>ý‚|R—Z-¿Ãí4mx[H¹ðÿÛ- _Ô¬ƒÀDÚæ¨$šmFó°–’g ’Iq$–îÍÙ¾²¢€>Nñßü¿Jñç€<§Mã BÃ[ðÅû¿ŠVšµ‚D×Ö÷^-“ÄSèw*\¼–nín¬ŠãO²¹(L qÿ´Wü]øõàí[ÁÑ|^:'€ÛUñžµ¤é+áXî.b¼ñN—â [éo.M›³ÝkóËj°-ª¬ +ðÎ.dhî û†Šøûö°ÿ‚RŸÚƒBø—eÿ ïöü,Oêž&ßý‰öŸìÿ¶ü<—Á~F>ОfÏ7í»þ]Û|«Ÿ8gügÿ‚S꿵¡q⿊(øcã_ˆPÝé/a ïÃwŸÁ/o¦Á­Áwº-Æ¥4×RcÄZœžbß±Ø8AöyVãí(æïÙ{ö ¹ý“|A¨ê~×¼c.¯áýA›NÓ¼‘£Y%–·­jw¢ÎÎÒh’æMrx V2<¥ž[ùS'Ò4Q@Q@Q@Q@Q@Q@yçí+ð0þÐÿ4ÝjƒGþÏñW‡µÛþÐ?´Çƒ¿dÏÙj>*¼»‚Úw¶±C ÜO;3 ä–#ñ5⟲§üÁ¤·Ò¼I³Á>.l.Ù¤ÿD¼nŸ»ãÿu°} ¯ >$®âM¢ø£L³×­µ%Ùž"/xO@±õÏû\cÖ¸§Í *møKáßñ<{Ä? +| ûeköô›?Ç:LfÌélë +BÇ–r0 ”+’cœ‚§šøgö¥ý‘­þxž÷W‰ítÝçý͆Ÿt÷Mƒÿ,<Ò¡C€NO!z ÝÿX~þÆNÞ¶Ó›Kµðo„`;¢Ð´åÓ2grIç žç5äßðX¿‚z\¿³VŸ‡´ ZöçH¼òPéšl“ÛÀÞdˆ¥Pä§'šŒ4§*¼ÔïoÐÒ¬T){ÛŸ¶~žûW{k Y%vc´˜…í“ô¯¢?eÿØ—_ø•¯ØE¤i÷šî·¨²‹[Kx¶óÉ8©í_YÁ'à‹_¿iLx“\²›Â~¸`{ŽYŒù1žXœžxõû—û.þÅ¿d_ E§xGD‚¯,,ú”àIyrq‚Kž€ÿup=«éa8AsnÏŠÆå¸¬ewM>ZI«½Ü»¯$|›ÿãÿ‚'iŸ¦Ó¼añ9­µÏÀ¢Km!T5žžÄusϘà½~„Ám¬+H‰ ªª0ª=§‚O¿xz +å©VUäÏ—PÁÓT°ñQC±E(¨;‚Š( Š( ‘þáúRÒ?Ü?JhLþieOôdÿÕÔõšŠ{ø–k'þ¨–¡ÿ¨,ÔWéœIñPÿ¯q?9á߆·ý|—è}EárOì¡áïû"6?úˆE_¶ŸÂ¿JüNð’çöPðöèˆØê!~Øÿ +ý+縧àÃ~‡wÿÿ_Ä~Í¿òE´_ûoÿ£ä¯™þ,üøIñkþ +EñÄ?ü?á «Oü ðv£iâMabµºðzjxÂIï­5Vm6DG/Ú`–'ŒÁÕ£V_¦?fßù"Ú/ý·ÿÑòUoˆ²‡Âߊÿ´Ox§á§€lÓjšpÓ¤š};XFÖZ“Â`%­lQ\ßðGíKñ—Aø5y¡ø7Pÿ„ïâg‰>*|GºÐ´Ù<0ºÍͧ…ôŸ^ØL²½ö¿¥Àßf¸¸°Ž6[¤)ÄÇg"Ã-Â}ñÏöOøYûP6—ÿ /á§€>"aù¿Ù¿ð“øzÏWþÏóvy¾OÚ#/•í¸Ýå¦s´a¿¿dÿ…Ÿt{ý;Æ¿ <ã ?SÕc×o-u¿YêÝê1Ú­œw²$Ѱ{…µD€JÀ¸‰Ú ˜¿iÚ÷Ný¥`o‚?ÚZ¿g¤~ÔV™}â­Ãú]÷е]'Â÷rßêÑ‹K v¼žÞe{}KÈcˆÚ¾·ÀduÑÿà©~>ð'Á­R¿‡O×îþü5ø‹âZëºΉâÜxTépع¶o$èRj°jVÚ¡†âÎs½äˆU–c÷w†þx[ÁÇ@:G†t (xSJ} Dû ØÚ{}Ÿu•¶ÕM¹û%®bL!û4<~ípiÿ ü/¤xòëÅ6žðý¯‰ï|ï´jñiÐ¥õÇœRïœ/˜ÛãÓì²~e±¶"€|c¢~Ýÿ´ +ø—Â1ðvŸ¤|a¾»Ò`ð-šh:CÝkÏvšÍÄhÐø²xâŽ+=P™/.µ‹Dœ¬±ÇIk²ç°ÿ…®þÝÿðMwâ”ðÿ€|Muâ¯øFõ}']»ŽËJ×ï4ŸfϢݘ庎}fK±’’ýQ56ˆ@'öíö"ø1áσš·Ã?áà ‡ÚýÚßj~·ð­ŒZ6£p¦"³Mh±d !Ù ùùþýŸ<àσRü9Ñüá 'áì¶—6xbËF¶ƒF’ÞäÈn!6ˆ‚¦YK¦Ì9‘÷¸äãã‡û<èžð–‘à/„¯ü-ñWUðþ·ö‡“ZðoÃëÁðóR××TÒ 8[[ý•­~Ô%cu«½;^Hï~Ùÿµ^ˆ|ák/xÄÞ/ø€5ïè׺wÅ…Ì>Ó?±­‘¯t=SÄ–FÖââëUyFíM¦Š·Il£ž[„³úúËöOøY§ü,Ó| oðÓÀþ Ѿ×öGáë5Ò¬~Õ Ì^U°ÊO:ËÈäÚ£z]έ‘#ƒÿ÷øÿ +³þ_øQÿ?á þÕþÝÿ„{þÝ;û+ûGÉò>Ûöo'ÊûG“û¿7nýŸ.qÅo~Ì_5|;ã]q_ÝøƒE𶇠+Z\Ç'Œn-|y«øwÅwvær聯§A©´(Ó=.Õ®%ž-®ß^ülýŸ<ûIøRßCø‹àøÿDµ»[ø4ïèÖÚ­¬ +Ž‹2Å::,$‘C$aœ1¬þÉþø}ñ–ÛÆwš‹@ðùð·„ôíì¬ôoir /´ÚXCmo˜ç}:ÅØ\¼æ#l«‚6xØà/‚¿ðQ/Ú'À²GÁÛmÃÚÄëÏ +| ð¿ÄÏø‡Qû´z¥¾£ù† ËýS_³:t‰•/Ÿ©ùz‘å–v´bX'û;àí-⯈¿µ7<)­ÝøûÛíÒxz 2Yžòx,o#²šh®÷¼ŽÛ†–Ø„vsé7QGo$Wq]Û^Éßø‹öOøYã cÃšŽ­ð×À¦¡àýVç]Ðn®ü=g<Ú&£st/.om]£& ‰n€žIc*ï(Ä·5Ðx{áG…¼!ãÏx§IðׇôÏøÃìßÛÚ½¦ ú×Ù£1[}ªuQ$þTd¤~amŠH\(£¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¯Ìø*¯üŸßÂÿúíyÿ¢tÚý7¯Ìø*¯üŸßÂÿúíyÿ¢tÚkq=ÐÿƒòMt¯úâ¿ÈWQ\¿Áù&ºWýq_ä+¨¤0¢Š(¯ý¯?a‡¶ÇgÑ|s ZÞ»!÷èn­2?^=ìtT´š³ù»ÿ‚‘Á»ßÿf½×<#þ4ð”lÒ,ö±æêÕ颽zN†¾Œÿ‚CxVùdV¹Ò&×|c6£>›‰P‹Ÿ)&d ª1…„OÛ)í£º£‘Dqµ•†U‡¡ƒàï…>ø}qw6‡¡éšL·Îd­mÖ3#’xõ<ñÞ±©GÚ.VôüK„ù_2<‹á/ì·q­Ù%ß‹¢{sƒ— Øw³:ôÏ÷ýIè=ËMð펉¢G§ÚY[[ØB‚4·Ž0±ªŽÛzUú+HSŒ¢‰rmÝŒŠ%… UUà0?¢ŠÐAEPEPEPEPHÿpý)iî¥4&5R.4­gþÈŽ¡ÿ¨,ÔT’§üIu“ÿTGPÿÔj+ôÎ$ø¨׸Ÿ›ðì½Úßõò_¡õ…Wþ17çÓà‡þ¢Wíð¯Ò¿<)ó~Éžÿ²#aÿ¨„Uû_ü+ô¯žâŸƒ þwðgñ1õñœGìÛÿ$[Eÿ¶ÿú>J©¦~Ò¾Ôj}gàá»x×G𥇌¾Ë4°¯Û´ë»ËÛ?2ßæ¿“5ž&>XDû]¨ÜL˜ÿfßù"Ú/ý·ÿÑòWÌÿµ?ì ã/¿¶‹üsáÍSQð=Üþ ð·…´ßiº°ÓïšÉï¼Mˆm#–%{„’+ RÒöØ2¬'R²Ò¥s"Úº“>èú;öbý¥|+û\ü"‡Ç^ »þÒðÍÞ««iVWË,3C¨gêW:t—0I ¼r[Ë%«ÉŠß;|(ñ¿ÃOxëÂ> ñ/ü#ZV—/ˆ|/ý½§Þjº¯‹àðV7>2þÑší|Û‰6¿‡?³¤”[³·ö“H2d »~>üjÒÿg_ƒž!ñ®±¡}g Ú£ÓôäIubáˆK{ 8Mys;Åo;–i¢~gŸ¦þÒ¾ñÅ?x_H»þÜÿ…‰á]GÆZ&­¦Ë Εu§YM¥ÄÒ,êç›ý¯jñ Ž‹!ܸPüí§ð{â?Ç|.Ò<w hG†u[jZο¦6¹¤OygÁ§é·:\w–’ÜnšõõgY¶Û\èVÌT»ÄÉñÇŸÙoâ'ÀoiGÇ“xBßá¯Â+]wM¾×îµkh%Ðux'[þÀ·²¼¼xìlæ³·Ö<=mcupmš;#–XmîÕ +ã>9|iÒ¿g¯‡×Þ/ñ‚xS@´¼ÔµýRÝX¼?akeqw5äÑîIÂ[G4Åæìó?0¿eO¾øÝ­ø·ÇÞý˜´ÿþÎ7¾5Ö²¾ixFóL–ömÁÖöúí¬GPþÁ¸Ž ´½~Ù®-¯$š)¯æˆ.æ¼hx“þ ñ—Æ_µÿ jö^Õ>&x¯U];[ñÅæ¨³ÿl@¿®<.·÷7L ìÖã_»ºP¯œ}¦i¼²3ÒφŸ´¯Šž3ø‡¡iöú„7 ¼A‡57¸DX縓JÓõExJ³ÈÔ RX)Þ’ »B³v•ùÿ¢ÿÁ>5_øÏ⇾ÿÂâÙ¾*xUðU³_XÅsá ÚØøBÏY¶³K{™-l?Ñ,µk+¨íMä© 70‹`|ÿöhÿ‚Yø¿àOï…í¤|/ðÿ…üMàß +ü!aq¦6›ms¦kknÞ¾§_añm¬Þ'š+»dyV;mBÚKÝ9­õT’ßí2ˆf@÷ùí—ûüuø•û>k ü7ðËûRÛMñ_Å/7ˆ´ø-µoøItoeAg Ê%;&×­­®žä[y3”1-Õ¹–æÐÏÚã^•û6üñÇÄmvßP»Ñ<áûÿjX¢Iu5½´—¤JìˆÒ‚†u‘–ší+òûö·ÿ‚Yø¿þ¯ŒZÂ…ÞÐιªø‹Ãþ‡Dm7HOøD¯~Ý[&—‡O—ÅÓƒfvÇöÉñ£7¿?àž^'ø¥¤j’x+ை> ü›UÐeÕþh–Þ [ÿËikâ$»¾L–[¿ ÍæÏ©xyË_H%eÐY¬¶¶@Ô ++àïØ«ö¾ø!ñBïÄ^0øc¨xžÖxSÃþ}zãAÕ5GâíT{raK[KHôèî´;“md‚ÞÜiðCd×e 7Þ4QEQEQEW–||ý¦ãø-âÏxkJðgŒ>"øÇÄÖ—º—‡ü8út7_`²{Xîï]FîÒÔG·ÖQ”ó¼æ7JR7D•£õ:ùûö•Ð<_àŸÚ›áÏÅ_xÄ?4ÿ øWÄ~¾Ñ|?y¦Ûê©.§y¡ÝCt?´n­-šÝG$ÄþhyàÛ©‘âõï…t?Ž? ¼5ã_ _SÃ0Ò­u½"÷É’µÙÜ“A/—"¬‰º7VÚê¬3‚È®Ž¼¯ö$ø+ªþͱÂ/‡ZíÆŸu­øÁz7‡5 ô÷y-f¸³±†ÞW‰QÚ2ñ±RȤ‚2 ñ^©@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@~dÁUäþþÿ×kÏý¦×é½~dÁUäþþÿ×kÏý¦Ó[‰ì~‡üÿ’k¥×þBºŠåþ É5Ò¿ëŠÿ!]E!…Q@Q@Q@Q@Q@Q@Q@Q@Q@#ýÃô¥¤¸~”ОÇóg4ñOk éðCPÿÔj*YÓþ)m`ÿÕÔ?õšŠý3‰~:õî?©ù·ü¿ëä¿CéO 1_Ù3þŸð¤,?õŠ¿l£û«ô¯Ä¯¾ßÙ+ÿöDl?õŠ¿mcû£é_?Å?ÃÂÿ~‡¡ÁŸÄÅÿׯq³oü‘mþÛÿèù+¹®ömÿ’-¢ÿÛý%|¯ûXþÐzî‘û|xÁW?~?øÃ?€<;­ØY|2øe‹þÑyy¨ëðÝKy еI ýÝ…šÆ¬Ð«m”¨r¯Ét}ÃE|}ñKã¯Åÿ°ÿÁM Á^.Ð<ûAüuÒ´[å×4 [?i‰ ¶Ô5½I"i."¸ÓÒö̯,Os©i±™Ð\,ëÐ|,ÿ‚ŸxWÅÿð«ÿá&Oøþ?‡ú‡‹üOý§â8cÿ„Q³ò|Ý÷ÌHöÜ/“¯îó|—OøFu<Åþqä}CE|Ûá?ÚcÆ ?àºgÅ躆¥ñÄÖ‘jzo„oáEÔ¦·záidò€†Hg¾±Òšîhf#q:Ç™ù†³ûzkßüðÁ>#x«ìZ‡Ãë> ø¿ªfG'öµž—à­w\MKÉ‚&ý¶ÖßIÕ¼‹=ÍÚ~ÊYš9P€}ÃE|º?à¦ðØxîÿÁzÇÁ‹úÄdþÊþÇð•ܾ–ÿÄßÚëGöYàÕd±Ëƒ@Õf“íw6ÿ-°Tß$‘£çÞÿÁO¼%ãUt]?Hø¡¢Ë§]øeuFÖ×IeѯõIá¢\ §“|ŸÚ„2ÛG,"Þ ä·º2=³¸ÖTWçìÕÿ}ñ6¹§iþ3ø‘àïÛøzÿà_ƒ~&ëvš.“húwƒâ¹ŸÄ'W×%œÜ1ûAgc,VbyïÞýÕ£KâÇëÚ¯ü¿Â^ŸÄSj>'Ùèž»ñ\ëö²é>Ô_N×õ¸Ñ/ÚàÙØ\CÄÑ-äÂê#mkp_(ë*+Çh_ÚÒ_ÿü%à½'á¯Ä‰~'ñ~•ªkvö^—Gƒì–ztÚ|7Í&¥gúÍNÕUQŽ\àÍyŠ¿àµÿü7ðßZñ—‘â |'iªèš&‡¬ÝÝiZ-‡‹o5M +E¬Ú•í²[yZeÄSHÚ‰³VfÄf˜ˆˆØ4WÍ¿¿à§þøï?óáÆ"±øiqwöý6ÖÚò×FX5칼NJvûlqj·šãK¶öÁḞXlî-î¥óÿÁÀþ"Ûj·<Úþ±—öuÆŸ‰&â ýjÆ÷X°ÒRò; 6îæúÛdú¥ƒKè-¯feŠÖY¡šÀ>ᢾMÒÿoÏ|\ý§ü9ð¿Â¾Ô<+­ê~ñjxŽØÚ_]x YÓ¢ðõÆŸ%âÚêBÞêÎ[}v ;‰¤cwj…íÌwF.Çö=×ü_7Å/ˆú ߎüAñ[À~û®âýrÏM·¼—\Y¯¢Ö4ÈÛOµ´¶šÞÍaÓ‡˜1K©ï yÞKy ¶úŠ( Š( Š( Š+Ç?hOÛ +Ïà/Å? x×Àÿ<{ãéZ¦¯£éž³µ“Í‹N›OŽäMquqµ®PÕî%Ž&òž1'Ÿ%¼3€{óo†à§Þñö££ßxkHñ‡ˆ>j—z™?Žíím¡Ñ´»ýr ô«9­çž=HÉq­¤ðÙI gQŒK$~UÏ‘ô•QEQEQEQEQEQEQEQEQEQEQEQEù‘ÿUÿ“ûø_ÿ]¯?ôN›_¦õù‘ÿUÿ“ûø_ÿ]¯?ôN›Mn'±úðcþI®•ÿ\Wù +ê+—ø1ÿ$×Jÿ®+ü…u†QEQEQEQEQEQEQEQEQE÷Ò–‘þáúSB{ÍíÂcÂÁÿª¨ê 5%ÂãÁ:Áÿª¨ê 5úo|t?ëÜOÎ8oà­ÿ_$}á´ßû%øtÕ°ÿÔB*ýµî¥~&ø`cöJðéÿª#aÿ¨„UûeÝJùî)þü ô;8/ø˜¿úøÎ#ömÿ’-¢ÿÛý%K¢üÒô/ž&ø‹ Æ u¿xIðÝÜèmc·Ónu;ˆ5 +HϪÜ%È!"© Z/Ù·þH¶‹ÿmÿô|•7ÄoÚ À?¼WáÅþ9ð…µ¿]ýƒÃº~±¬ÛXÝk×ãO&Ò)]^âMóB»# s,caŸ’>ðä?g?دÂß³?ü"Ù‡ˆ5øAþé4Oí‰á¸þÎÓ¬7î–-±'—qy‹_µ²mIÿ³¬~Eò¹ÿÿÁ5>xàøÇíúIøM¼Weâ›ÌZÙŸ³yûF›èÝ>ûÍÕ¾×ÝöøHµ¼°û|¹ú +ŠóÏÚöið¯íC¤h:?m?¶ü1£ê¿Ú·¾»Š#Äxµ¸‚;mFÚdxîmã’tºHØ ·6v²ƒ˜€>!ñOþ ð“Rðþ­…¼§èÚ–³ËÃí"æ/ øGU½“D×ty¤l­Z[y.í5Ù!¸»…LÛl,[l“ë*(áß¿ðM¯‰ž(ñçˆþ |døâ ˆ²bÃám_DÕ4bÿÂÿÙÑëqˆç:c/Ú ñ£nmî4¹üµf‘gikêÿ‚axÉzÑêÞ0žïX»ðÞ¥©ÝKumæj7ú/Š/¼R·Ž‰%Þ©¨Ý½ÂD©IpGlª¸öý3â¿…µ­Âú—‰´ ½?Ç[?ẇP†H|A¾ÖKÄû†ÅÆëXeœye³NãåRGG@6éŸðKÿèß<{à;}_Æ)áß|6¶øLñ«c&áûS¬-œ®`É’Þ fhYüçtµ¶iL²ùÒ̾.ÿ‚axÆÞ ñ…s«xÂ;Oxâ†î^+«a$vþ3ÕcÕ5GB` Iñ*Û’D$H³7Ì=÷Gñn•â=GV³Óõ; ë½ílu8-îRY4놂+…†eRLr'‚P‚RhÛ]IÔ ŸioÙ+Åÿ?j‡>5ðçÄŸü4Óü!á_è—×¾‹MŸU»—Q¼Ðæ†!£aymö}ºdí#ICˆ’­ ¬ÿÿÁ0|ðëÁ#Eð>­ãɦxƒOñ'†õ2êÚîëÂW~µðÄij/`¸ŠXÛI¶h^GrI¹š@Ë ‰â÷ïø¯Kð…µ=w]Õ,4]E´–ÿPÔ/îÚÖÂÞ$/,ÒÊä$q¢+3;IW?ðOöƒðí'áKsá׎<ãýÖí¬'Ô|9¬Ûj¶°\*#´-,è²’6(N@‘N0€8a/QñO€u}GÇŸ5kŸÝNE¿ÖÒq¯_«ÜÈ—’“û9ÞÞ+&–ÖPËopl¥Ž[ŠÎ>ÃðMOøwÁš?…¥ñÿÄýOÁ¾»Ð¤ð‡î5 (ôï +Zèú­†¥ge +ÃkÝFL²„ͨ5ÕÒËÄoqq$¾ýâßé~𶧮뺥†‹¡è¶’ßê…ýÂ[ZØ[Ä…åšY\„Ž4Efgb€I +Ô ð÷ìUá_ +þÒúŸÅ‹ CÄx·XÕnõ Æóáki »Òt6âÃËhŽ-ßûJ¹ÜœOk0†I`@økðêÏá‡.4Ëó!ºÕu-]Ù-mq-õô÷²–ÑEÄ—7²™dÆùd–f’Wèè ŠÌ·ñV—yâ›Ý +-SO—[Ó­ ¿»ÓÒáêÖÞw™ šHÞ±Èö× +Ž@ `”J69ýgö„ð‡~2é?µøBÃâ½h×úg†.5›hµFÝD¥¦†ÑœM$`A9.¨@ÉÏÈØì袊(¢Š+‹Ö¾ +izïÇÏ üEšãPß…|?«xnÒt²[êW:eÄï"•.dWÒ­ÂàòåX•+ÚQ@/|,ÿ‚Sø+àöáMGñoÄàŸÝÞøbiô÷°ñ&§ ÚéöÚf©y7Ùâ\DºF”Æ;K‹{iÁ7ÀÂ[…›ê( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ¿2?િò ÿëµçþ‰ÓkôÞ¿2?િò ÿëµçþ‰Ói­Äö?Cþ É5Ò¿ëŠÿ!]Erÿ?äšé_õÅ®¢ÂŠ( Š( ¿?¿`«ígàçÀoاÅ6¾.øâMCö‡Ò´Í;ÆÑø³ÅÚ§‰!½ž_jçÛí…õÄÆÊán´ò›mŒpŽÇÄïwo}¬éþ(Ó|#¨C{#ÙDÖ–k­j¶¾MÌQÜÉ5’Í;ÛÁ2­›ú÷‡ÿàœÿ¼5pßÄÐÛ]é÷Zeµçˆµ;Ë_‹F×Rµ¶Òàšá¢Ó,ÖîÆÅÍ¥’ÃnâÊÚ7‰£†4]gö øO¯Û,W^Ýån´.§yÖrë:ž·q‹(xn§imwñ•–ÖX#kw‡h  ý¥ÿjx»þ ¯û[\\؇ÿ~xSÄZUüžצ½·°ÔWÃQjÖ·:}ù†ÖvÛo¨Y·˜Ð@ñ⪆TI¤:k­+=GMñÕ­ä·÷Z}¬«åÍá«ÑsZ»Go$rÂnæÿC<ÿÄø+OЬ¾|Dñƒþx[Ô> xWSñ?ÄcÆ“iPÛ}ƒR×tÉ Ò¦‹N¹7Û®¼7ª•{ˆì³Y±Ui¥ŽßßþþŸ þx‹GÖí4¿jž ÐuUÖluŸx«Vñ«ëc}a»ë™§{xíõ=DGlî`ïg‘#Ydg>ûZÁ!l¿hÙï4Oø›OøyàOZjv¾)ƒJ‹^‡_ÖÆ©¨ß_꯭u«kY£2ê7oo¨Xß[ÛIurV'Šy càø*ÿ‰~ +I®xFÛáïċھ‰â¿kZܶ6ZÞ9ñ-……žž,4Ûèžá!ÒgŠ8oî4ëuXíQ')ç5·éxgˆ?àœÿ¼KpZãÄ0ÜÝêZµŸˆµ;;_ íFëRº¶Õ †ábÔìÚîúùÅ¥êÍn‚öæ4‰cšDos Š( Š( ‘þáúRÒ?Ü?JhOcùÅ?â„ÖO§ÀýCÿPyh§N¿ñoõ“ÿT?PÿÔZ+ôÞ&øè׸ŸšðçÁ[þ¾Kô>„ð»ãöMððõø!aÿ¨„UûgÝJüLðÀÿŒLðéÿª!aÿ¨„UûgÝJùþ)þü ô;ø/ø˜¿úøÎ#ömÿ’-¢ÿÛý%|¯ÿø¡~Ïü_â‹øïÄþ6øm¢ßü/ñ®%ïü-ë; µYmt- +Cqo¨\É©^ZÍé2ý³N-h¢D[¿ª?fßù"Ú/ý·ÿÑòWs_"}áùýñ_ö¸øÉ§ÿÁOn|eãoxkÃúgŠ´=Gðf«­¬Z¯Œt[›]>mCT·Ñ£Ñnuï-îµ8’ößSµ²ôÂ׬¯|‡?·'‹µ€:?ŒSã·öÿ¤ÿ„KZø©àÆÐ´Ùáø8²øƒF]zÎyííÑ´‹{[b)aÖZ{Á”“$ñ>òGý ¢€?3µoø(ÏÄÿŠ´Åû¿„Þ&ÔEÔ¿jV“jV&‘§‰¤‹k2ÝC缓Éå\Ú(ûŠüßýŽþ,xWÇ +?àŸ¿ t?xZøðû?þ¿ +Øê0Üë~ +û/€5½2ëûNÍÍeäßÜ[ÚIç¢l¸ž(›:©óÿÙçþ +5ñųGÃíwAøûÿ rxEÖþ(ë_gðý×ü)kË[Ãv·’ÿĺÎl<« OÄ7{ud¸TþÁóm¯_Ö +ç>|.Ðþ|.ðׂ¼-bt¿ x?JµÑ4‹/:IþÉgm +C^dŒÒ>ØÑWs³1ÆI'&€?,´oÚØøKøÇ€ÿh½?Q´ñGÅö»‹ã½ãO ø@ÕÓÁ¾‰ôÙuQ¡_é­xò\~âÚ ÞHô›Ç3«[Ê³ÐøwûcüXO‚>(øeâÏ|=Ö>:x«ÀÞ$ñ-Ω¨ÙøsBðf“{ðßNŸûjÞú÷NÔE¥½æ¯`t¤žöËy$µ6°ˆnŒ“×ú(áïüAñWÄŸø%w‚|[ã}cÃúíæ—ãÿ kz¯ˆtwšM*]MñÎ;jïs%¥šKnºe¯Ú翊ÚÞÊDY® T´hÈÐý¢n/†ž1ƒEñËÑ<;­x‚ÇÃ?>0xpé·¶¾ÒãÓµ«ë(›Y¹†ãKI?´c·¶0Üù¦®(Å-ý¬­öùûnþÙ^#ø•û +üeÑþ#ümÿ…oáöøWâOøA/¶èzü/_ø˜x›N‹÷—¶²%矦iú ×üI…®ïíÿ56Åsf±z÷€m?Ž:Ïí‘ãm2÷ÇÞÓ¡Ó5_ØËà?ßø—]ðþ“§®¢ºV­ÿƣŪÇök¦\y·ËÛÞG¨l·Hæ¿°ŠÒ(ãß?µŽõ¿ø&wÄ¿xc]?ý±5¯x—XÔ/<7ዽÀ¾:Ô¬ôA¨ë]Ÿ‰¾)xwJÙÚBÒËyu«E ï]>&iܤQ[ïDú;Ã? +ü]ñ/À¿~|F±Ð4/x§JÑþ'|UÔífÓaÕõoønOH![{vU—̾[Ešò$šm¬ÕDfîÖh~Žøð+Ã?üWá[Ä6º†£/„nþß§ÙVî=1îÅ$S\ؤ¢ÖîHe†) {˜¤6óF²Âco®Ò€ +(¢€ +(¢€ +ù·ö Ö>"x¿öÐø[ðÛÂõ‡^ñ/‚¼W¯k·Zfa}©Ìú}÷‡"µ6²^E40H¡2³IèÐË2ùBS Å¿ÒTPæÀ_ø(ÿÄ?vÿù©Ÿ¿ð¢³ÿã”Ã[|)ÿ¢›ð÷ÿ ++?þ9@ƒEy÷ü5·ÂŸú)¿ð¢³ÿã”Ã[|)ÿ¢›ð÷ÿ ++?þ9@ƒEy÷ü5·ÂŸú)¿ð¢³ÿã”Óû\|)Q“ñ;áèö1ÙÿñÊô:+Ͽ᭾ÿÑMø{ÿ…Ÿÿ£þÛáOý߇¿øQYÿñÊô+Ͽ᭾ÿÑMø{ÿ…Ÿÿ£þÛáOý߇¿øQYÿñÊô+Ͽ᭾ÿÑMø{ÿ…Ÿÿ£þÛáOý߇¿øQYÿñÊô+Ͽ᭾ÿÑMø{ÿ…Ÿÿ¦Úóá88?>û˜ìÿøåz%#ýÃô®Eý©~x—Z¶Ó´ßˆÞÔ5 ÉV{[m~ÒY§‘˜*¢¢ÈY˜±2I»÷û‡éM ì9Wþ-æµÿd:ÿÿPyh§Ü ¿5“ÿT:ÿÿPyh¯Óx›ã¡ÿ^â~qÃoúù#è? E»öFðéÿª!cÿ¨„Uû\é_ŠþÀý<=ÿdBÇÿQëö úWÏqOÁ†ÿýî _¼Åÿׯq³oü‘mþÛÿèù+¹®ömÿ’-¢ÿÛý%w5òGÝQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@~dÁUäþþÿ×kÏý¦×é½~dÁUäþþÿ×kÏý¦Ó[‰ì~‰üÿ’e¢ÿ׸þf¼*K]?FøÃñ‡[û’ë#Å6–)|`Sp° I(>7lÝ“·8ÉÏZ÷_ƒÿòL´_ú÷Ì×Οu/±ø×ã + ýèñ“ŒôÇö”) Ð?î¦$%܃>cU¥ñÝì2÷ÓíÿfC^puŒ’Ô2êsÉÃHMz÷ÄÉÀù/îAôÕ«&ŠÚ’ž5£ÿm qŒîÇïnÖ´Ù§uÛí&òî;Û—·´*³<‚»É ò“’2108ÏQU5_xI³³º¸’ò+mA –îe8‘AÁèx>ÇœzšŸn¡mj]>îxí¬õxÒIe!R"pѹ' *}3]ÖŸ¬øwSºidO¸ž&¹·ÓÒimâ ‘­ºE½¦GŒÈWÌR»‰Æ Í;|Îþ&±ÿ?·÷õ¿Æ¬i>1×µÍNÞÊÖæâK›©(ÎWs€2Hñ5× CÂó_^µÕ¦‘´¸HÄPËÂO´F‘ÊÁÑ7”UÜm˜mùpkžÓïllþ3é¾L¶QXX]Áž…c…Ä{Q¥ÝÀÃ-¸õÎM%º@ö¹»­x“ÃÐG5ÍÙxe%[kô¸‹pä©x”68'85Gþ­n[GŸÏ¼h„m&÷جA Ó$¡®‡Â:}¿‡¢û¥}¤ù·×©rˆ—6·qŠ)¸g%áBìêƒ~@åŠà ïøšëL¹ðü6pOáí4Osc5ðI,.L#ÌÇ”¨ŽTyD¬kÀ'# Ä–ÓîümùÜóÁñWÇü~ÜÿßÖÿ»?ˆüIk ÛêrMt¶724QK矙—¨Ær>¤`àã¡­‹ÿÙòéºT–ÐéÐ]™'IVÖæÊrPy{ }•1’_ºòF1»á][òk¾ºyV+nÍwq{ØÌñ1’@ o2a“!ŒFª¿õæFp§â6¯øý¹ÿ¿­þ4ÂÅÕñÿ·÷õ¿Æ»u½UðK%–ˆÓIo0¼6ÒÍâ˜#Ù€Ì~_/6 +Nwãç&¿Äèt¤ðX[s¥IsäqÁqo5™u–ûœÅnŠñ‚BJY†@È9Ênß×Èqÿ3–ÿ…‹«çþ?n?ïëð±u|ÇíÇýýoñ¬*)ˆÝÿ…‰¬ÏíÇýýoñ¨¥ñæ§/-w9žccùÖ=Ctû{àP–þÙ:ÕÆ­ðoÄâyeXí®%]ÉâÞ\0¡ê=kõ]þáúWäçíd¡þx‡<âÊäÿä +õþáúSB{Î…Èÿ‹i¬ÿÙ¿ÿÔZ(¹ÿ’e¬ÿÙ¿ÿÔZ+ôÞ&øè׸ŸšðçÁ[þ¾Kô>ðÃcöEðàÿª!cÿ¨„uû[ÝJüRðÂÿÆ"xpÿÕ±ÿÔB:ý­î¥|÷ÿ þúüüL_ý|gÉk/~ž¶Òn¼>u»kMûÂÕ¦s–.r^XÁcÐv¯&?ð]9?ñn k'þæ=ÿ’éáYüoÿ¢'­áE£ò]~€Q@Ÿ²|2øàÃ঴?îbÑ¿ù.š>üoþH¶¸îbÑ¿ù.¿A( Ï¿øU¿ÿèŠë¿øQh¿ü—Gü*ßÿôEußü(´_þK¯ÐJ(óïþgÆñÿ4W\ü|E£ò]#|+øàW‚úà>§Ä:)ÿÛºý¢€?>ÿáV|oÿ¢+®áE£ò]ð«~7ÿÑ×ð¢Ñù.¿A( Ï¿øUŸÿèŠëŸøQhßü—Gü*ßÿôEußü(´_þK¯ÐJ(óïþoÆüÿÉ×?ð¢Ñ³ÿ¥t­øßÿDW]ÿ‹Eÿäºý¢€?>Ûá_Æóÿ4[]ãþ¦-ÿ’ê­×ÁïŽS‚?áLë@ú˜toþK¯Ðê(ó#âìyñÏã7‡ÏÃ;­ 5PÖ¯}¯émf²)ŒÊâäªîÜB#1à€MŸî¥-#ýÃô¦„ö? Ÿù&ZÏýëÿýA墋Ÿù&ZÏýëÿýA墿MâUïÐÿ¯q?5áÏ‚·ý|—è} á„ÿŒ?ðéÿªcÿ¨„uûT>àú +üVðÏÍûxtÕ±ÿÔB:ý©p}|ÿÿ þúüü\_ý|bHÛP“ÎkÉ¿bŽzÇíû5è>1×`Óíµ=QîÖh¬£xí×ʺ–Ú݆V0NXòON•ë2)hØ`s_;þÆß þ)~Íß +ôjš/ô.{ƒ6©iâk¿´渖l­³X,¾f6™€8ÎE|õRxj‰ü|ѵûZ\ß®ÄN¤kÁ«òÙÞË®–ýM…¿¶ŽŠß¼?®øÃ[Ò¯õO_j6¶iámS»‚Öy•ü«S ]q5Êl ’Ö\ïë¿¶çÃ-BÒ5&ñ$—öšÞ–úå¹Ó4˽IÖÁu2[Å#A +“´¼¡ee'*Àx÷ŸأâÀý#áÆ¯¤ÏàýcÄþ }zÖòÂïP¹¶°»µÔnÞá9Öt–2"È0À°Ü6«¾+þư†é$i#š'³i%žÞ:´2•Ý´0e,Búµp¹oµ÷fùuê»»+5ÚÎ÷ò·o5bs¹Õ·¾ÚktýU`ñßíðßáΧ¦£âfš}x’1¦é—zšÉ¦î+ö°ÖÑH¦ A%á~c…æŸãŸÛ+áÏÃË:çR×åx5=+ûv°ÓnõŸòÿ¦MöxŸÈƒæ¼—jõçå8òØ?a]c@ñ—J¹ðý¾oð¢oÛ¯r…/f:¬†g[pø¦‘ÇO›ªŸ?d߉ÿn<5«xBoêºÜ^Óü#©C¬^]Åkiug“Ô&8Y¦ˆù’‰„$íRK1X\½­&ïê•÷òvéÜo˜'ïA-É»iöoVûlzïŒ?lŸ†þñ ÓoüH¢Hb´šêêÚÊæêÇOŽé±n÷WqFÐ[,™LÒ *Á¾éØ›ö¶øÆð!×Iñ+Ý ØÜµ·Ú q¹ùcÝå™7c¶x¯ ø«ûx›Äÿ|s¨Á&‰¯iŸ~ÂúÛ|I­é6ú|‘İ\ƒag(Kè™2$³ÄT…ÊÇnoØÛÆ:gíIkâïBð΄5{[ÝB÷IÕõ(.õ›(-Z!gy`åígråÒ7«í,y¥…Ë9~97Ë~‰^ÑÓ½“æ[]Ù[¸¥‹ÌTŸ¸¬¶w¶ºïk½=:ŸSŽE€(¯úQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE÷Ò–‘þáúSB{Î×ü“MkþÈuÿþ òÑE×ü“MkþÈuÿþ òÑ_¨q'ÅCþ½Äüׇ> +ßõò_¡ô/†üa燽¾Øÿê!~Ô§Aôø¯áù3¯Ù±ÿÔB:ý¨Nƒè+ç8§øx_ð/Ðïà¿ââÿëãýO‚ÿcïØÿÀ?¾éÞ"ñ¬_j÷Ú†¨“Lž!ÔmÔ¬ZÌQSª(XãE¨éë]‡û0üñWÃ}kÅšV™â½[EÐ.µ[³c«x†æèÜi—Ww°Ål’™ç‘.-gV(ÜÊPyaÃ)n·þ áÿ&¡ÿØKYÿÓµå|Øÿõ¯þ´7Ã-ÿt¯‹“]|W¾ð욀Åÿ/øF¿ä#ÿÿúŸì?øðÿMûGü}~ïûN¸?‚_þ*ø¿Å> +Эþ#üw½øs«øîÚ=bî? ø«ÂsZÛ/‡'ã/ÁÒá¥fÐ|:|:¿›Edoço´^È»¡}¶)oÐx‘õí.`–ÒdÖ­ïa¹ô;ö>øªüMÖ<oa®IâMK±Ö¯ìÿá#Ö‡‘i{-ä6Òï7|–cj±eò²ÁC!kþ*ý†þ øÃ–·­Ú^èÚ.k-õýý÷Œu;{[x¼“K#ÝHÑ™™ˆ +$€+•ñŸÆK/Ù×þ +#ãýoÄ~ø—u¢øŸáÏ„ìtëÿø]ñ%¬×šŸ‰Þæ“N´¸XäD¼¶b²$L¤+ä¿ÚWá¯ÇAûFYÞë¿õkXÐ~!XÉá;x‚ãM¾Ñ%Óõh´(b¾›R: Èñ¶ŒÊºMÔšR"˜u)hìÿ‡ß±ïÀ¯ŠZCÞh–åÇÙü•¼µ›ÄzÕ­ö—,ÖÐÝ$v²Ü,ö·g¸‚C蒪̅”dTºgì ðºãâ·bú6ºÖ¶zv<)ÿ Fª6<²_,‡?iÉȆ>¼ ¼c',ýþ¿Á/Ú'öƒY­¼Y~!×´+í"ãSÕ5 J×PÒ ðÞ—§E2Í<’F÷j±¿IÙ˜Þ8ŽÝî Fö®ÞÏ¢ÿÉUñ/ý‚tŸý©Ð‹iß±÷À­Wân±àÛ{ rOh:]޵gÿ ´<‹KÙo!¶—y¸ØÛä°»U‹/•– + /ý~xÄ>Òµk rÒÿƺ£èº,_ð‘ëR}¶í,®¯š,­Á ‹k+™79UýÖÜîeVíÁá_ø[Å ø¥ðÃM°Öüo Zê> +ŠÃQ‚âæÈ[ë¯f‘]ɸùvÚ­–5ÌÀ‹NMQ¼¢¾iû4üø‡ðKûRTð§ü$SþÌ^Ô>ü4Óé´ÇñÔR}–öšîâ?%·ØØxnÔÝF#Š=AuÀc1%¹ÏÿñøMÿ@=sÿ +[ÿ’hÿ‡xü&ÿ ¹ÿ…N­ÿÉ5ñ‡ìµ£üXÖ?iÿøeüGñ§Ä? tïèzÕÍýχ;Ç«xïÇÚx_Tøqsoá >)üK©ßÁ{°4„ ç[‘]JHœÝ•UÜbDð{;öŒÕ~ éöúαñkAÑäÿ„gοmÄz½ô éÓÿ´m´Û›]ZODX®³ý—:*«iìÛ­–éíÿøwÂoúëŸøTêßü“Gü;Çá7ýõÏü*uoþI¯—î`2nr?y0~\t$¿Ž³À/Ù×á½Ï‹ÂFÓÖWŽ -í•PL ÌË)¯ýœ|U­x‹âŽ£iá­Kö¥¾ø¡xËÀv:D>0¸ñ¶z†›ÃÞ¸ÖaÖ”“ G©›)õ‰gYñrn¦ÝóÞØ°<+û +|ñ‡†tÝZÓÃÞ+†ÓUµŠòïµÍvÆéD¢[yçI¡7G*+¡Ê²«%ñïà'ìõû4é:çŠôÅKªbéVº-ljõëëû¿³\]£µ°içl[ÚÜH[fÕX˜’8ÏÍŸ³½ñ‹àÀOüRø€~4êzž‰ã/iºÏ‡µMbú=CÄ–÷ÞÒôhí-­u â³óŠ5³5ËÊð†šÖw–GšÖ4ññ3Añ_ìëðwö5—ǃž;Ö¾kÖøÛWðîªø®êk…ðV¹§Í|Ém·“G%ìñ3Å’gRûI4Üü3ý~|`ðEˆ¼;a®_éWÞb£·ˆõ«y –9) š.X.!•$ŠX%T–)c’9EûØoàç‰ï4H­/eÖ´ûX/®¬Æ:›][[Îó$<êŸ|gã›âU·Œµ¯i~Òuù´ZIqáÝ/ⶺ”³impº‡Ú×÷z|¶Âyÿ¶gI§ûÌ—Fæjû·þãð›þ€zçþ:·ÿ$ÖÅ?Ø/á†þøQ²ÑõÈo,4»›˜$ÿ„ŸUo.D‰™[䃂Oÿ‚ièÞ+оêÑx—Ä~-ñ=“kÓ>uâêº Ôv?g¶ Á¬_^êí»„I¨Ê²’Ì"Ah¶¬Þ½ñ¿þHÇ‹ÿì {ÿ¢€8Cþ Ùð’ éÑt-p*HÊü%Z·úù¯>³øû7ê<'ñ®?ƒßÿ‡xü&ÿ ¹ÿ…N­ÿÉ4ü~Ð\ÿ§VÿäšñÙgÀ¿~~Ñß|3ã]câÏŠuÀzf—¯êßk»ŸÃ“Ëm¥EÍÇ06W–÷7åß|‚EuXO¥]kö|õðßöø]¯ü6ðÕýÞ­Ëw¨höwWÂQª¯™$–ñ»¶È,Äàx¨þ~Çß¾5ü1ð猼3a®j~ñn—m­i7Ÿð‘ëPý®Òæ%švIp®›£u;]U†p@9í?¿äx;þÅý;ÿI"¯Œ>$|-øð_âv§ÿï‡?·üð;ÅŸÆ#ÊÓîîµOmËwöý&ÛËUŠêþ8¯¼aåÛ'—µî;|sÓ¼¨üAÖ~,ñf™â»]ÖêÎÄ›[Ä:¥Ô×wPÙÛCµ¬²Ï4’\O j±ÆÄ—c&ƒ³À/~ŸUðޙⷎÊé¬om5-[Ä:N¥¦\I<›«+¹b¹¶Å$RªÍŠxdPc‘¸oˆÐxÎßþ ßn¾!Ò|y­ßø/ã&œÑ[ÿdßëäžÒ>$Àm'ò’9//vèöÍç•–kˆ×Îf•¯øÛPñ_æøÝñ{Â>ñjh¾0ðo†ü¥Å¨é𮮬Vz†°Úž±ÙõO.Ö e¤ŠÞ3m}w&›2[„Z\Êëðï„ßô×?ð©Õ¿ù&øwÂoúëŸøTêßü“_øSZøò¾ +Õ<3c⟉z„~8ºñwÂ?‡WwÚˆ<%u£©øwEÕ¬u¹b×®¥Ô¾É§M§xµÜ·77h\ÇiÆÉ_aþÍ_ð“Åûi|RMKþÌÚ[ù³µß6-,Ϋkorn²}°#Éo>Œë¾ —‹W…5 xf¹Ððìð»[ðÃ\]hÚä³hj0nÿ„£U_’-BæÆÎ8Ž4§9$šóûÏ~ÍVßõ‡è5?hú¥®‹¨¶—¥øÓQÒôë»›{{˜¢ŸQÊÜ]ÛÈìó*Æ’†rƒ8ú—áoü‰mÿa}_ÿN·•á?³—ÀÿXþÙÿ|asâßh>½ñå¬ÖžþÏÓ“Cñ$C ±½ó¥²k×Û:Ië{´‹Ì²ÚT••\¬ÿ‡xü&ÿ ¹ÿ…N­ÿÉ5Ÿqû ü³ñ=ž‰-¥ìZÖ¡k=õ­ƒøÇS[«›xždŒÝnhã{‹uv…3Ä ×?þÍV¿´…~xÆûĺ×Ä¿ø§Pðh²ñÞ“7„üS¦ÚèzÍÍÕ”WwöwW³›é,a}bxíü%¬b ‘ɾ–+’ð§Â/Žl|OuauñkY¿ð×…þ$x;ᆿ&›âÞKSðÿ†nôõ•u‹¹uno ×wZ̶ñÜÛ@XYl"@¿áÞ? ¿è®áS«òMðï„ßô×?ð©Õ¿ù&¾zÖüuãïÚ[þ +)àÍGFѾ]Í´ÑîklÜ¥”«OÛöjÕ>>~Û_µ;íú%߃üâ}GHñLZ{ÜÁ ë «øVkhåe(|»¨mïmæ&†K›)/áY]Ý~Z“ßuٛᤞ#°ñçÁm+VñGÄ}oÆ>“¡xŸÄ×Ún±wâ¹®´»cÿ½åŽ¥-¹µŸSeºY „ª"wFylÙ@>ÏÒ?a¿‚~ Ô5[K KÛë½ +élu(müc©Ë&ŸpÐEp°Ì«tLrg‚P­‚RhÛ]Iä¼7ð/öoñw„¾kºp×.4¯Œ~Oü"ÿnëÉý¯çi·¤+LÙZÏ/ï‚cfÓ‡*¥ßðN_…^/øo㯋÷ÿ—Å“xׯ^Õîïõ8Eµ®¬‘øWI°–ámíf›L·»:…–¦³Åk#:ˆí÷3Û›)Íe›-_Wð'ìeðÌøOÇšŠ¿gÿ±ÿÂqý©áMKMÒôϲx7UÑgò5+ˆÊûý>òÞ4ûóù¨æh÷Â"€} ÿñøMÿ@=sÿ +[ÿ’hÿ‡xü&ÿ ¹ÿ…N­ÿÉ5ñÿŒ´ÿŒšŸÁ­NÏKÖ>Ïa¦\ÛêÂá5Ò-î?á»:3¬QÜÙyvÒêvqnü2ðůøE<uâO|w½ŽËá~‰a¡ê¶ÚV©dÞMLjüB÷®ŽÚ„—2ÜG¥Ã¤ ÚOˆ~È,°jWhê?øwÂoúëŸøTêßü“X·°7Âäø‘§Ø \“è÷×Oü%¯Í$w(Ÿ´ç…šAŒàîç ÇsûÜj—Ÿ³O„¥Ö,ü[§ÞËjïö_Þ=æ¥m•Ì1¼òÅ̱¬[R^ÅóD#7ˆ—fuU×ü–+þÅýKÿJôÚóoøwÂoúëŸøTêßü“Gü;Çá7ýõÏü*uoþI¯j¢€i;¶ðµßŠ®m|O{äýŸH—Ç7ÉqçGy,[ 7^coO¿uÀù–ÆäŒˆd+ÑÃ=øsþzx§ÿ +Oÿ’+òcÇß´Å(þ?øKâ, áÿˆß4o +Øê^þĶ¼Ô¬q-¹x̱´R«*IáŽÉb}²(wÿ ÷áÏùéâŸü*5?þH®;Åß +¾þÏðj:滬Aà˜|Cu-õþ¡ã½5u;‹}=¤–ie{•ód‹OÓÙ™˜’–ö$’#„íù[ŵŠüñ»_øañö„Ô~ü=ð?ˆ5]*O‹œ^Ó5=Rõ4o +jv]ÕÅå‰ÒI—^Öc†Î¤‡G…•¿svóÐÿ‚~Ñÿô?ø'_ìëñwP´>ø¹g¥k/º´þÍhá×á_‹nÞ?²Ýy…|› G•>ò6m}Üäìö(ømâ¿x{ÄÚ®ƒu©ø“Â_iþÃÕ®õ‹é¯´_´Æ"¸û4Í1x|ØÀGòÊïPdqW¼5ð§Á4Óä¼ÑµcU³†îæÂIì¼a¨O\[O%½Ä%’ä$SÅ,NQãu`HüDý°þ4øÂ|[oñ[Ä_غWÆ/Øé76Šl-×Á&n£¶+;i÷V÷CílÓÆkhLV¹”KéÿðO_ø›âwü;âlj¼Yâ=C̽ðþ¡á½"Åí­-íuÛ}âlƒÇˆD²É¦Ú>— ˜¤F©\,’O€®¿ážü9ÿ=´Ól´mÛþÙß +´xÏQ·ðïÂo‰V–òë0éö1x¯¾*x]'½Û˜RMTéz5”¡$7»mÖYâõ>€8øg¿ÏOÿáQ©ÿòEðÏ~ÿžž)ÿ£SÿäŠíè ¿gÿ yVñFºõ´6¶ñZ÷ˆ5"Š8£XÑB$áFTg'$ä’JÿÃ=øsþzx§ÿ +Oÿ’+·¢€8øg¿ÏOÿáQ©ÿòEðÏ~ÿžž)ÿ£SÿäŠíè #þïßóÓÅ?øTjü‘Gü3߇?ç§Šð¨Ôÿù"»z(ÊáŠ~ÿÂÌÿ„Ûûëþ?ì¿ì?íÿí‹ïíOìÿ7ÎûÚ|ï7ìþoï<­Û7üØÏ5¿ÿ ÷áÏùéâŸü*5?þH®ÞŠáÿáŸü5•½¼k¯A ¨"Áâ B,—•ævb³‚îÒHä³eŽqœ¬7ÁÿüeÒ~j<‚Ãâ½h×úg†.> ÝŬê6ê%-46v&’0 œ—T dçäl{U~w|pñ^•¦üdøËðæãS°ƒâ¿hŸ†þ,ðç†$¸EÖuýÌxÞjv–„ù×p /S2ÜFcN»ÜÃÈ—hÛ_ðÏ~ÿžž)ÿ£SÿäŠ?ážü9ÿ= +ßõòGÑ>ÿ“5ð÷ýûýD#¯ÚTûƒé_‹>ãö4ð÷ýûýD#¯Údûƒé_?Å?ÃÂÿ~‡ÿ_àßðL¿ù3/ØK[ÿÓÅí{Õx/ü/þLËßöÖÿôñ{^õ_"}àQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEGÄßò-ê?õí'þ€jëýÃôª^&ÿ‘oQÿ¯i?ôW_î¥4'±üèÝÉ4Öì‡_ÿê5·_òM5¯û!×ÿúƒËE~›Äßú÷ó^ø+×ÉCø_þLßÃÿöC¬õŽ¿icû£é_‹>ý|?íð:ÇÿQëö: ¯â‡zxoð/Ðô83ø¸¿úøÏÿ‚eÿÉ™xsþÂZßþž/kÞ«Áà™òf^ÿ°–·ÿ§‹Ú÷ªù3îŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š(  +>&ÿ‘oQÿ¯i?ôW_î¥Rñ7ü‹zý{Iÿ ºÿpý)¡=çFëþI¦µÿd:ÿÿPyh¢é¿âÚë_öC¯ÿõ–Šý7‰¾:õî'æ¼9ðVÿ¯’>…ð¿ü™¿‡¿ì‡Xÿê!~Ô'EúWâ·…ŽcÙ±ÿÔB:ý©O¸>•óüT­O þú‡?Þbÿëã<þ —ÿ&eáÏû kúx½¯z¯ÿ‚eÿÉ™xsþÂZßþž/kÞ«äO» +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€(ø›þE½Gþ½¤ÿÐ ]¸~•KÄßò-ê?õí'þ€jëýÃô¦„ö? “ÿ×ZõC¯ÿõ–ŠmÑÏÃ}gþÈ~¡ÿ¨<´WéüIñÐÿ¯qýOÍxsà­ÿ_$} ásÿuáñÿT:ÇÿQëö²?º>•ø£áù3ßÿÙ±ÿÔB:ý®î¥|÷ÿ þúüñâÿëã<þ —ÿ&eáÏû kúx½¯z¯<øðBOÙïáNá=7VKëm>K™Ì÷6¿¼’K‹‰n$8W/™+…¡A,AcÚy:ŸüýXÿà#ÿñÊùï ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÝþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ»üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ»üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ»üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÕþ?ÿ  ôU'SÿŸ«üþ9G“©ÿÏÝþ?ÿ ñ7ü‹zý{Iÿ ºÿpý+.ÿJ¿Ôl&·{Ë0³ÆÑ±ÁÇï+QþáúSB{Îtç?5¿û!×ÿúƒËE%Ïü“kþÈv¡ÿ¨<´WêKñÐÿ¯qýOÍxsà­ÿ_$}áfÏì}áÿû!Ö?ú‡Ç_µé÷V¿<.qûhþ¨uþ¡ñWíš}Õ¯â¿ááÀ¿C¿‚¿‰‹ÿ¯ŒuQ_ }àQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEÓØt¤ÛéÇRœ+ãÿÛëþ +¶Ÿ°çÅÝ7Â_ð‚Éâ‰õ "=WíWJæš!ß&BNa'<}áÅwe¹n+]aðæ›»µÒÛÍ´Ž~a‡ÁÒöØ™rÇkÙ½ý.}€Z,=? +üÚºÿƒ5 -D—ßo¬í·2Iâ&~v`gñ¯¤ÿcßø*7Ã_Û]M K–ÿ@ñSBfM'UEGºÚ¡¤ò$Vd”/'W*¬Û«éc¸O6ÂRuëÑj+vš•½lÝ? Ĺn&¢¥Jªæ{&š¿¥Ò¹ô–9÷ê(^jùCþ +›ûqxÛö%ð„o¼á½;Võäð]ßj0O5­™DCDDé‰%Üårý |)ê¿Cüñ…ïÄ_„Þñ§¦É£êZæ“ku`ùÝe,±$ÜÊ3äÇJó*嵩áaŒ•¹&ÚZ«Ýouº=xúU13ÂÆüÑI½4×mNªƒÀ Q\GhÀ lÿJQÓ­~uü]ýºþ)x?þ +ïmðÆÇÄÁ< .·¥Ù6–Úm«)ŠâÒÙåi‹ÎÉy]³¿‚qÐb¿DÓ îkÕÌòŠøQfš«5kèŸ{¥¯¥ýO3/Í)båR4“Nqwî»jô:QFh¯(ôÂŽ´Q@ è}èÆ1×4?|‰ûpÿÁRÛö3ý 4/ÿ ÿ Ö´ë}Cí¿Û?c0ù·C³Ëò$Ý+vw îÆ2{rì·Ž­ì0±æ•›µÒÑo»HâÇcèa)û\CåÒ½›Õú\úöŠDmȨÍ-q‰…Q@Š( éÿꣃָÚ—Æ:—ï٣âˆ4[£c«è^Ôoì®<µ“ÉžYd¶¸*Øe 8ä_2ÿÁ¿kŸˆ?µg…|u/uÑ®Üh·v‰i/Ø­íZ%‘$,¤BˆÊÈ'¯5éáòzõ°Uqñ·%&“Þþó²¶–üQæVÌéRÆSÁI>i¦ÓÒÚo}O¶éî¥.iyˆôžÇó›:çáÖµÇüÐíCÿPyh«7ÿŲÖÛ¿ü(ûÿýA墿Nâoއý{‰ù¯|¿ëäsðÁÇì…áñÿT:ÇÿPø«öÔ}Ñô¯ÄŸ ŸøÄ-Ûà}þ¡ñWí°û£é^/s þú¼üLgý|c¨¢Šøó( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Œ×äwüþRàûôÿý8ÞWë~GÁqå ÿ±oOÿÓå}LJò9øeù!Æÿò,âæ~²Üéð_Ø<ÁÐMI#t ²)*Aà‚0kòþ û/é_±ßíáü? á¸|JÒÞÁmb<¥Óo­$‰Œ°€͉•W…d|`ì0XTät×äoü»ãíŸí%ûGøGáçƒök×>2Ù1²>s\j7rD†Ù6ä3'•ü¼‡wSÊ4ðòuÿµ¹ceË.~Ö³µúoc3—]ÿë—½î¯o‘ô'íÑÿ>ñ·ìïð[àŸŠ|1¤xZy>&h¯ªßEª[Ï2Û°‚ÎEXü¹£ fåÁÝ»¢ôç=·í·ûxø¿ömýŠ>üFÐtÿ]k¾+¸ÓỆúÞi-c3\?–©*8!ãP2çå'9<×Ë?ð[O‡²|$ø-û7øZY’æ_ è—ºSÊ™Û+C›ažpJgšï?à«øÿ‡Tüÿ¯ÝÿMUéá²|JYtýý­I©y¥&’û6¾iŒ§£ÿÕÿ‚¯ÉûaøÆçÁ~0Ò4ÝÅ«n÷vSX;-¦¤ˆ~xÖ9%U!±¹Ã*¹ùvàú/ücJ·Ó?àŸ_DÇÚ-îf“ì×Se©þ€ÕðßìÑe•ÿ漆Þ5‚øIµó±fÊñSšRʱQÇá)aÔÊQ’“m¸>·Ó_ÁVc‡–:îj³Š”ZI$ÒÛЛö‰;à¾g§üTº ÿÉ:÷ÏÚ«þ +§ãKÚºÏá'Àÿ è~-× ¸m>þ]B)fIo/B9c*¿›#±‡áeŸä¿ø(ÍŸ‰uø+—ˆí<f_ÞjM¾”ð¸ÒáôëD•ÉHbâ@\g#®ãþ÷ñKJý”¿koü8ñö…k¥x³_tk}Vb­5ÔR06eù9ßaVFÃ:E÷Ã#'½ŽÊhTË(cêEU•<<9ißWÞM^íEt[ž>1­ }l$éÆuçÛ]"»6~†ühý¦cýÿfˆ|_ñ:çMºÖm¢Ž àÑax¡¿¾pH‚Ùevm¼7Ìí¨Ì@û£ä+þ +CûTüWð×|ðGG“Á*Åà3[ÜÜÝM<ljâyÀÁâ„ŒŽ‚¨ÁÄsß.…ð¦(ÌßÙÏq©´àgË2…µç¶í¦\{÷ª¿|ûnêßü3qá/xF? O¥[6“[éÁR×Ê_)y´$a6Œ‘Žy¯Ê2L$ršy…_dçROø’”RIÚÉG«µîö=ÌÏ4ÄË0ž +›šŒ"¾›m¤îïÓó=Ëà?ü«Rý­¿d¿ëþÑôÛŠ^ +²73hWÑÍyms´ –cy˨Š2I´6T«…ý©?à¦ÿü%ûzXüøq¥x>íf¹±Ó&»Õ­nn.®6»¾a™Š8äMÃi`RCžÃÀ?à¸9ÿ†ÿð>è[Óÿôãy]üãÁW_´ßí½ñãN¯¢éÓ\Ý[¨fÄW—ï&dœ¬py©‚N‰\÷ü çþ +àûôÿý8ÞW«”`ðØ,þŽ„m(R|ï«›ßõæyùŽ*¾+)©‹«&ã*‹•vŠvGë|D´hqØW›þÕ´÷†¿d_„7¾1ñ<’›Xd[kkXv™ï®%aŒb˜äð¨Çµz#âoø*oí=ðCM°ñăE—…g‘|×}í‹€OÒ´Òˆ]º2>¿ÂzW–þÎfͿ๺ ñO—»þílZ}³<Ý·?fûüg_—Žwy{yÅ~”þÜí£'ìsñ0ëßfþÍÿ„nô7œ3Éo+nî<Ï3fÎûöãœRÅa²ì²¦<2ªêF2”›w|ÎÖ•º ˆÆãáˆÅªîŸ³“QŠJÊÊúÝksÎüWûRøoö½ÿ‚iüLñ†šhà—ÂZŭ夠yÖ)c!x_)pU”ñœ”à‰¿t?€?³×ÆÏøŽäÚèú–ÎË‚ò|³*F€ »²¢ŒŒ³‘\wüØ]Øwö°ó<ßìóáVç;<ϰj>f;go—Ÿø |«à¿‡<ñÇÀ_ê:-µÝÏ‚<'wk®ˆæUŽ9¤ß É !PÒ ¨m‹#€I¯¨Ëøk còŸiËOÚRÕ¾ŽÏ–ýõå^v<,f{^U0™‡'4ù'¢î®¯é¥ß‘ú…û~ÝŸÿnŠ—÷±x_Ážø_¤ÝºÝß=­Ì·g?4vqIçªKp»ùaÅAdFûˆä©õ"¾^ÿ‚JþÑžøßû'hÚG‡ôÛ-QðLiš¦•o€±I´‘r½ÊÜònl±s(,åK·Ô,Ž+ò®"Œiæ(ƲQ|ª=têßV÷¾Ç虥<*Σ¨ä®ßè—Kl;—o…úÐÿªÿ¨D´UK¹÷|;ÖGýPýCÿPyh¯´âUïÐÿ¯q>3‡~ßõò_¡îþl~ÈÚÿªcÿ¨|UûqÂŒökñ'á²ø¿öfð^Ÿisg¿XøA¥éPK$Ê‹‰µ¢¾H?ðW¯ /_‡Þ9÷ðÇÿ-©§þ +ÿá@ä@ñ¿þ|1ÿËj?±±ßóê_poeÿóú?yõÍò7ü=ÿƒþiÿŽ?ðsáþ[Òø,„ÇüÈ7ÿÁφ?ùoGö.;þ}Kîíü¿þGï>º¢¾Eÿ‡ÂxOþ„àçÃü·¦ÿÃâ<#ÿBÿðsáþ[ÓþÅÇÿÏ©}Áý¿—ÿÏèýç×”WÈgþ áÿ2ÿðsáþ[Òø,7„›§€ÿ¡Ç?ø:ð¿ÿ-èþÃÌ?ç̾àþßË¿çô~óì*+ãïø|§ƒÿè@ñÇþü-ÿËŠCÿ”ðxò xßÿ~ÿ彨y‡üù—Ü?íü¿þGï>¢¾9oø,ï‚Ôóà?ûø_ÿ–ôÓÿ¢ð@øÆßø;ð¿ÿ-èþÄÇÿÏ©}Áý½—ÿÏèýçÙWÆÿðúOÿЋã_üø[ÿ–ôßø}G‚üȾ6ÿÁß…¿ùoGö&?þ}Kîíì¿þGï>Ê¢¾5?ðZ¿ù‘¼mÿƒ¿ òâ“þ[à_ú¼kÿƒ¿ òâìLüú—Ü?íì¿þGï>Ë¢¾4ÿ‡Öøþ„oÿàïÂßü¸¡ൾ~žñ©ÿ¸ß…¿ùqGö&?þ}KîíÜ¿þ~Çï>Ë¢¾:þ 9àÉ—+à/0öÖ¼-ÿËŠÁd¼ ÃþIÿŽOýƼ-ÿËŠ?±1ÿóê_pnåÿóö?yö ñïü>SÂþi÷Ž¿ðuáoþ\Qÿ”ð‡ýïàëÂßü¸£ûÿ>¥÷öî_ÿ?c÷ŸaQ_Ÿø,¯ƒÇüÓïàëÂßü¸¦ÿÃåüÿDÿÇ?ø;ð·ÿ.(þÃÌ?ç̾àþÝËÿçì~óìJ+ã³ÿšðpÿ™Ç_ø:ð·ÿ.)?áóž ÿ¡Ç?ø:ð·ÿ.(þÃÌ?ç̾àþÝËÿçì~óì2zWÁ¿ðS_ø&?ÄÛ#ö‚ÑüaágÂÚu¦›¡A¦•Ô®n!›ÎŽââ]ËåC Û‰—9ȇ°¯UrÝ=¶?¶:g‰~9Û6‘r¦+˜¢ñ¥2ÉpÊÑcY?…Ž?:÷ŸØ›þ àÙÅxšóR¼ñ—‹­7 [눵½ŽàT´Pl9RAgwÿd/9Ä“þ uàlÂãaÿq¿ òâšà·~#þDûŽx[ÿ—êâs!­EáÕ7Ku(ßÖÊ矆ÃäTjªÎ¢”–ÎRnÞ—v/ÁW`~ܲxþGÃZxð¸ÔßöµÄðïûGÙvy~TRgCç8ê¸Ï8³ûnþÁÞ/ý¤¿b‡ßtÿÚ뾸Ó廚úyãµ[ØÍnþ[$Nä—‘HÊ”àñY#þ wà ø#Æ¿ø<ð·ÿ.(ÿ‡ÞøŸx×ÿžÿåÅrЩžR… +p¦íE·w«w~¦õ¿±ªÎ¬åQ^ªJ^÷E¢·cÞb?ú·ìßû-øOÁ:äÚ}Ö­¡[ÉÄ–.ò[±i¤lgTb0㪎s_7|+ÿ‚hø÷ÀßðS«Œ÷šŸ„äð´ÚƧ¨ hn® øŽâÚâ(ÁCpiT·ï08'€uÿá÷¾Ïüˆþ6ÿÁç…¿ùqBÿÁo¼‚ݬÁk¾júUÕ£x3Ç‹¨š’x^)0#*묬3Á ò+áïØ›Ä? þ|O¶ñÏÄ+Æ.ñ›uöÍ>ÖÛXðÀµ†ubËq#ɬo–@v°P¬3—àg‡(â(cjg8ÈIN Ý„anvÓVÑY%×O?_;;Äáªá)å˜YÅÂ_¥+ò¤Ó¾º¶ú¨ðM/ÙŽOÙWöKÐ4+ë#^Õ7kÂr +]N÷dpÑıDqÁ1Þ¼+þ +oÿÈø…ûd~ÐÚ7‹ü!¬xSN³Ó´84Ò5+ˈ.hî.%Ü¢($q2`î ñО„ÿÁoüØÿŠÆßø<ð¯ÿ.)ßðûÏ“Çümÿƒ¿ +ÿòâ¼,=Lò†a,Ê7í%{Þ7^öúµoìj¸(à*U\‘µ­+=ÿ‡mþÙ +qÿ Þ0=á3Ö1ÿ¢kéí3ö½øÉû i þ2ë2øÄÖm5Äšå½ô·sCsçÎÐL’̪îVDd:ò»—¦ pÃþ qà"OüPÞ7Áÿ¨ß…¿ùqKÿ³ðïù¼oû ø[ÿ—¦/žWå~Ç•Á©'(´×š_ž–KG›÷ÜÊI¦¥+«;tgŽøgþ SûLü ´Ô4‡´› Ý;mC¨^عÏY) « ‡¹ŽLð>c^×ÿÿÿ‚Péß²_ŒüS­xíÒEŠXÑ…®œedhËüòHÊXoÊì6òI¬à¶Þó#xÛÿžÿåÅ5ÿà·~Qÿ"Gðwá_þ\V¸Üψq4gFtÚSøš‚N^­+‘…Âä4*F¬j&ãð§&ÒôM–?à ¿ðIûÚËÆCÇÖÓž; Ï,¨ÆÛQ1X™Ù>x¤EUE Â(ÛüCÆ|ìŠp3°|ªv¢Ç>oÿËÿ‚yx‹öJðÄÇòø_\³ñ‘‚/³ØK5Ì2±ʒÇ(–ÆIŒAÍfø.GÃÖÿ™#ÆÇþã¾ÿåÍ8Áp|ÿwÀž8?÷ð§ÿ.k…nû´eNMUjRmjÚwNþ§c–KíiÕSŠpN)'¥šµ¬p¿à–c¯ÚæO|9ñƒo<nZÓõkë¨n®ôé-o/—nëæ'1ãF+‚R¿Cˆù3è+âßø~€@ãÀž8ÿÁç…?ùsHà¸>#þDOtÇü‡<+ÿËšÏ3¥œæ#WI¹%kòÙ´»÷~f™}|« SÃÕJ-Þ׺O˱ù;psàkþÈ~¡ÿ¨<ÔRx…¡Ð|-âëYo,¥]á­¤Ïq êöæx¼!=«qÃ0ؤ}âT¢ŠúŽ*¼*ÐŒ–ªœSæxg–TëJûÔ—èyŽûzÝþÄ–0øgTðä^7ð]¼ÓËah—ÇLÔtÆ™ÞgŽ+¯.d0ZI +I°ik ;ka๞ #þH—Š¿ðá[ÿò¢Š+N6½û:Si.‡–`0Øœ-:Õà¥)-[ê ÿËðNÓÿKÅ_øp­ÿùQIÿÆðGý?ÿá÷ÿåEW?öž+þ~?¼îþÅÀÿϤ5¿à¸¾ ÿ$OÅ_øpíÿùQIÿÈðGý/á÷ÿåESyž/þ~?¼?±p?óé oø./ÏüÑ/ÿá÷ÿåE1ÿà¸^Çü‘?ÿá÷ÿåESYž/þ~?¼_Øxùô†Ÿø-×üÑOÿá·ÿåE1ÿà¶^sÏÁ?á÷ÿåEUÿiâÿçãûËþÂÀϤG'ü·À„sðWÅ¿øpíÿùQQÿÃç¼'_‚¾.ÿÇoÿÊŠ(ªþÓÅÿÏÇ÷“ý…—ÿϤ0ÿÁe| ç࿌?ðáÛò¢ ø,‡Ãÿú"þ1ÿÉmÿÊz(¥ý«ŒÿŸïì,¿þ} ø,Ãñÿ4_Æ?øq-¿ùOMoø,wÃìÿÉñ—þKoþSÑE_ö®3þ~?¼?°²ÿùô†ÃâþÑñ—þ;oþSÓOü#áéoù#3÷Q-¿ùOEÿµqŸóñýäÿaeÿóé ÿ…øz㟃3ÿÉmÿÊzrÿÁb~F8ø1ã>?ê¢[òžŠ(þÕÆÏÇ÷‡ö_ÿ>‘4_ðYo"ÿÉñþKoþSÔÿðùÏÿ$_Åÿøpí¿ùQEŸö¶3þ~?¼¯ì,üúB7üƒÀ@ÿÉñþ;þTRø-€‡üÑoÿáöÿåEQý«ŒÿŸïìLüúBŸø-€‰ÿ’+âÿü8vÿü¨¥ø-/€ˆÿ’+âïü8vÿü¨¢Š?µqŸóñýáý‰ÿŸH­7ücáüý~ xÀ}>"[òžªMÿ†øxÍÿ$_Æcþê%·ÿ)袵Y¶1Ë×÷„ò,¿þ}!­ÿ‚øy´Řñ§þKoþSÓ[þ +ýðñxÿ…3ãOü8¶ßü§¢ŠK9ÇÏÙ}æØYüú@¿ðWχ„Éñ ÿº‰kÿÊz_ø{ßÃÏú#>4ÿÉkÿÊz(«þÙÇÏÙ}áý…—ÿϤ0ÿÁ_~Ÿù£>4ÿÉkÿÊzüïáÙÿš3ãOü8–¿ü§¢Š‡œã¿çì¾ðþÂÀϤA/ü§áÄ­øS^6ôø‰kÿÊzŠOø+ÃrßòFüoÿ‡×ÿ”ôQOû_ÿ?_Þiý…€ÿŸH„ÿÁY>‘ÿ$kÇ?øq­ùMIÿbøiÿDkÇ?øq­ùME+9ÇÏÙ}åaeÿóéŸø*çÃSÿ4oÇ?øqmùMCÁV>ÿ$oÇ?øqmùMEªÍ±Ÿóñýäaà?çÒÿÁUþ‘ÿ$oÇ_øq­ùMBÿÁUþFÙüuÿ‡×ÿ”ÔQGö¶3þ~?¼ظùô‹Ö¿ðV‡6ƒàßÏ×â-¯ÿ)êâÁ`¾cþHÇ?ðâZÿòžŠ(þÖÆÏÇ÷‡ö.þ}!§þ ððÿÍñŸþ[oþSÒÃà¾ÿÑñ¯þ[oþSÑEÚ¸ÏùøþðþÅÀÿϤÿøvAÿ‹/ãOü8¶ßü§¦ÿÃß¾ÿÑñ§þK_þSÑEeý³ŽÿŸ²ûÃûÿ>Öÿ‚¼ü:?óFŸðô?†ÿ’9ãßü8ÖŸü¦¤ÿ‡ ü/ÿ¢9ãßü8ÖŸü¦¢ŠÏûsÿ?e÷‹ûÿ>Ÿðóÿ…ÿôG|{ÿ‡Óÿ”ÔÃÐ>Ññ÷þ{OþSQEkýµŽÿŸ¯ï)ä˜ÿ ?ðSÏ…û€ÿ…;ãïü8öŸü¦¦ÃÏ>ÿÑñïþ{OþSQE/í¼üý—ÞOö.þ}!Gü÷áxÿš;ãßü8öŸü¦¥ðT…ãþhçðãZòšŠ(yÞ>ßÅ—ÞWö.ßÂCÇüá‚ÿÍñßþkOþSTƒþ +‘ðÀù#~;ÿËiÿÊj(¬ÿ·1ÿóö_xG$ÀÿϤ8ÁS>ù£~;ÿËiÿÊjiÿ‚¨ü2?óGÐÿøzGÃú#ž<ÿÃiÿÊjþ +‘ðÇòG> +stream +ÿØÿàJFIF``ÿÛC  + + + +    ÿÛC  ÿÀL¤"ÿÄ + ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ +%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ + ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ +$4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?æÿbïØÓÂ>øGáoxËÂÚ‹¼eâí2wý¤z®Ÿ¦Ù^F&´†+Iƒ[³i!‘ä’7I+ª²ªŒûå—ìùàÝFÝfƒà·Â á|íxþ茭ƒƒ‚,ýAª_—þ1ëáÿªoá?ý0Ø×Ó? >Çñ³à_äðÖ£ê~5ð׉å2ØÝÛÇ#ÞØTŽÝ\áâcìØÉ÷q_x²¶S4¨áã^¥xÎO™ëî(É¥£mûÏNËKìpð7áów‰Uñ2¡N„©År¥eÎåÞ©$¹V½Þ­n|ó/ìëàËXL—¾A “áŽ†Š 8›>äøÕÍ?ökð æ1ð‹à§?õM´/þD®ŸÄ~ð÷„5ÿE¢ï.ÿ¶¦±:Ýù°Z»lV²ÆÁ½qæ.vÈ7€Ri¿´Ö»ªøöxÖ5êshš¸žÆÚ ø †imD×°Bì«2Im’67£ ãƒ^WñÒÏ)⥈‡/Âù¯Ì›ê£µ­ëèz|}À‹‡å…ú¶*u~o‰rµÊâº9hïC:/Ù3ÀR&áQ|ÿÃm¡ò% û$xòH¾ +ÿá¶Ð¿ù³~!|C×ÿewZðߊ~!x»Å:.§áÿÙëQizBx‹Ckìá%¼VSFâò#™o”e38t÷ûfø~?‹ø]¼#ã±Xø’/ ^x­-WH¶Ôf‚9¡˜Î'e“ÍÇ *»…r™¾ñW ÜcìÕå¶‹ù¹?ô«%ݵmÏϧJ´Sn£²×wµ¹¿+¿“8çý“<  > +ÿá¶Ð¿ù£oÙCÀãþi/Á_ü6Úÿ"VwÁÿø(o†¬g­Kľ,»½Öcð‚]ë¶Éiav/Þ ]5åi"Œ]Ȧ/‘FØ”£Nð‰Ÿ¨ø ÿ øuûBêºTW¶¯}ª\è­+Þé·ö¶×‘Y­êÂ×67w1–ÛÍt1Hê>Ï*¹ÀVÆ–; R*JÕ)j–Ïoëç±¢Ââyy¹¥÷¾Šýû–æ#þÊ^ íð—à¯þmÿ‘)‡öSðHÿšMðWÿ ¶ƒÿÈ•å_ÿl_x¯ã-ËøGž3ðÌ:†<7©ø+@—Ãv’iZíö£{C©Þ=¤ßdŽå`¶TêÝñ#l@P{F¥ÿø]¦~Ó1ü,k¥›[:ªhRÜÇ©éž\íñµk±~Ü•O5-Z Í‚ãk•ÑâpêJ2§Û¶Ëum=uJÏ[¸«]¤ÔèWÛ¨ôI½^Í_ò¿Üû3 þʾ Ïü’‚ßøm´þD¨ßöZð` ¾ áµÐù—Â_ðR xûLÑî4¯†®›ÅTÚχ`E¢¾»o"Ý4ln¼¸×-vÐ$™_%¦ßý­Köððƒé“kZ7†¼_âi–Zžµâm2 ?ìí ¨åušæ;‡)m$sÈ-ᘤr)#'m\kÐ’º„~å¦ë]4Ö/~ÅO ŠŒ¹%)_µßKm®»­¿FsÍû-x@Ÿ—áGÁoü6ºÿ!Óì·á$ëðŸà¹ÿºk ÿò%;Lÿ‚†éŸn>+_|DðÕχ4øÂ èWr_iv©­<¶V·ÃæÍ~"IXK$Þd­+G¹„‹"/г·ÇþÒß®>#iöz†ôé.âÔ§½Ô,ä‡LkR|ã%Í´óZ²*þds<{H;ºã æhýˆì›ÑhšO];5~×]ÕÚÁb[Qç–®ËW«×nû;w³ìíàP~ËÞ aó|%ø-Ÿû&ºÿ"S¤ý—| ¾ û¦ºÿ"WКŸˆ|7ñö{ñŒþøŸÃ¾'Óí4ËÙ¬õmú JÐÏ N~Y#/uäsÈÁç~*׬4ŸÙÞîk²ÑøæÑç×BÛE›íºל|£aóP7É·¦:qE<ÓÜÓ§È¢Þ‹ió[ÿHwùZæpؘ¸ÇÚJò涯ìò߯÷—âyÄÿ³'ƒÓ§Â‚ßømtþCª“~Í~Sǯ‚ãþ鮃ÿÈuŽ¿à¢–·ÿ³Æ¿âß |<ñ­–¤Þ—Ç>‡Ä¶PÅ­Ù*Æp‰y¼GM •\ÆìŽ "PÊM?¶&±ðëIÕ¯ô¿ xÊóÄÖ°øUï<5~šAµÒ¡ÔõíK¤‘Ý+<î!t ÜI»Ûùå}o‡Qrt•—÷WwÝiökR#ƒÅÏ—–«×oyÿwÏûêÝú.?g? ¯O…ŸÇýÓMÿë3Sø á»D$|.ø0?î™èü‡N׿n½#àn©ãë¼Öë‹­´MGšëL°žÜ6‹e{,s=Ä6ƒcI;–çˆÎZ59¿?o½Æ_5=oáÞ‰â] Ük“ÜiQXܧ†—uÄÉpZãdØžÖàmµûIanì)Bõaÿ€¯òíloüþ—þÿÌÙ>3²ÿ¡ à×þò'ü&Vyÿ‘ àÏþòey|Ò³GöNþ|Ãÿ_ä/íloüþŸþÿÌÖ>1³ÿ¡ àÏþò*øÂÈù~ ÿá°ðçÿ!V?•ŽÂœ©e8ùóü‘/6ÇÏéÿàOüÍøL,¿è@ø3ÿ†Ãßü…M>1²Ïüˆ_GýÓòel†?ÆŸöFþ|Ãÿ_ä/ílwüþŸþÿÌÖÿ„ÆÏþ„/ƒ?øl<9ÿÈTŸð˜ÙÿÐ…ðgÿ ‡‡?ù² + ô¤)Í?ìŒüù‡þ¿È?µ±ßóúøÿ3`øÊÏþ„ƒ?øl<9ÿÈTÓãK0?äBø5ÿ†ÃßüƒY[8Å5“ñ£û#ÿ>aÿ€¯òílwüþŸþÿÌÕ>7³ÿ¡ àÏþò !ñ½ ?ò!|ÿÃ_áÏþB¬w‡¾ 0ÇRòœüù‡þ¿È¯íloüþŸþÿÌè`ñ¥‹ýïüÿÃaáÏþB«öÞ)Ó%ü?ø3Ÿû&>ÿä*ä¡&6«örŒŒ÷©þÉÀÿϘà+ü†³loüþŸþÿÌé?á!Óÿ’}ðdû&>ÿä*_øHt¿ú'ßðØøwÿ«&1¹iê9Ádà¿çÌ?ðþE,Ûÿ?¥ÿ?ó5F¿¥‘ÇÃïƒøl|;ÿÈTÂA¦Ñ=ø1ÿ†Çÿü…Yˆ yLÔ¼«ÿ>aÿ€¯ò)f¸ßùý/ü ÿ™¢ÿä*ÈÁÚ•_ÔÒþÌÁϘÿà+ü†³Lgüý—þÿÌÙ¾‹Î~|ÿÃcáßþB¥:¾ˆü“¯‚ßøl|;ÿÈUŒÍÏÉZ_Ù8?ùóü‘k5ÆÏÙàOü͵Ö4<óðçà·þò?û[BÇü“‚ÿøl|=ÿÈUÏ™<Ð.°$‡”àÿçÔðþF‘Íqóö_øÿ3¢þÔÐ1ŸøWýÓòHš‡ˆÿ’mð[ÿ ‡¿ù +¹–»*)WPÇzÊYNþ}Gÿ_äo×ÿ?e÷¿ó:ø/<6㟆¿ðÙx{ÿªÔMá–çþ§ÁSÿtËÃßü…\l:‘SÖ¯[ê|uýkžyVþ}GîGDsLOüü—ÞÿÌìm ð«°ÝðÇà©þ©—‡¿ù·tÁ—'ð·à£Ý4ðÿÿ!×iªã=+sGÖ¶° óõ®ie˜où÷¹1Ìqóò_{=OÂ? >ø±¡ŠÿáGÁ“k~Êøy¢@Å$ñ•ªY-T•xe•IÃ+° ƒ_O/ìÝð ÿÍø ÿ†ãCÿäZù_ÀÚÔƒ@Ôd…±<7þt8ÎxŸG ×;©|ø…•tðjngH˜Æ¬Dîãœó_5ŽËa*òäŠI%Ðú,a5F<Òm¶úŸeÿÃ6|ÿ¢)ðÿ ƇÿÈ´Ù³à8ø)ðÿ ƇÿȵÍþÎ8ÿ’Ùñ»ÿò–¼â¯Æ«ý;â~»mà?kÚ߃ –!¥ßktPÞ\)·…¥Þ¿fƒ¤æe»^uûÇÆÃP…iò(5ê¬{Š•(ÃÍ?F} ~Ì_à¿ñ4ðWàkíµŽ1'ÃÝÖ4þÊÓ$Ú€Û«¾Wl.]RkWLý•~ kÂfÓ¿gÿ‚7ÑA'”òGðïê¡¶«cçOF±Í|µ¬üdñ•Ÿ‡§–@¬×É2Ÿ³Æw¢è¸þ:šÚð·Æ+ï|2}7Zñ@Ò¯¿µMîæÒþÐD"1ò…Ûëÿ|ôïVòæ©©$·ìguæâï·ùEjŸ²·Á­BÚìÿðFÆ+‰<¤’O‡~e-µ›$ z)íŽ+Žø¯û<ü Ó£ðÝÕ·ÁŸÑ¼Z¼ÛÄtTYi:”]E¶wFµ‘N2 $ñoÆ+ïü/M3Eñ@ÕoÿµEî᥋`Ša1žvú~};מøŸãµO @%Ô ÉíÓEþà Y#ø}@¯?3ºX•íðÿš=®©FiG ö—}¶{žëgàOƒscwÁ¯€Ÿøm4þD­~üqÏÁ€¿øm4þD¯†´Ÿ‹IÔúu‹ÿˆ®–Çâ—Ä'Œ··þEÿÄ×ä8ž"­¼¾ÿø'õÃì MãKî_ü‰õþ‹ðkÀž"Ðü%©X~Ë µ Jmü7=—ÃO +ÞG«N§ç‡t(âÚDU‘nŒ%Þà¶ß&]Œ‹á¿Âu_LÔ~| Òµ]ùôëûI~øbäÛΊ¥ÓÌ·†X˜®í¬ÉWWF +ÊÊ0ÿd?Ú÷Dý›~j6©â¿ßêŸfaâ 4 iì!ð:5»Â·Pn‰|ÛܼfI!VâþD~ͺωüQàNïGðçˆbÖ46C …ô:CY-ÜX_Éš5tnpÊAƒaœa·šæWÃ*´äÛm]sÞ×[o¯ôö>#…ò(f”ð˜ŠPŒ“Œ';;^íièý7>¬¸øsðb1ÇÁ€ƒþé¦ÿÈ•ÄüDýž~ |E×ÖO„ãµo ë $zg„4ý)™—RÐ\Ig2¤Š³J«":º d +Ã{gæ½Kâ·ÄA¸ A‡ýºÅÿÄצ~Éž.ñ'‰¯ücÇÂ3ÿTߟúb±¯§¿c¯Œ¾ +ø âoxŸU³ñ-þ·­]Ê`ûå¤vÑÚ±ÜH¥¸Œ´Ëd²6‚„ƒ“ó7Âymtßهᖡ9µÓ´¯…>Ô¯&™+{ZO+*ŽY„q¶Œœ Œæ½þÇ¿‰ÿ’Iñ7þÿøcÿ—uáq`s5‚¯‰®éΊn:'ñ(¦ìÓÚÚv=ŽâlvV±¸l5VÚRÕ¯…É¥tÖŽú÷6¾:|lÓ>+øºMZÓÀš^ƒs&¡ÅΧ¯’ßE¡ã/meî q¹²ÛIaÈ|Gðnñ¿á†¡á{íKSÒ ÔL./4óº¶x¦I‘ÓÍŽHò5áÑî+]?dOŠ‘ôøKñ7ÿ<1ÿ˺µoû,üX·û¿ þ&ÿàG†?ùw\|9ÃY^Rñú×´u­Íuí}¹#ùÞþg_ñ>gœÇMá=”h^Ör•ù¹wç”¶åVKEØä!ý“ü;â øºxÃÆ~3Ö¼e¦bÜ뺬öi{ccßfµŽÞÚ+XP¸ÞÅ`Ý#]Ÿbè¯>xZõ50÷ú¸¯Œ-/IÓáWÄÁÿoÿåÝee±Š‚¨¹U´é£M~]5¶‰£hK1‹º¦ï¯â­øGÕ=L|ðWеOÜ]µð‹Ç^±ðÍí¬3$PÚ[YµÛ@öûP4r©»s»qÁŽ2¡J’s| ðB/†ž<¸Ö4Ÿ‰^=†ÃRºú¦‡)Ó%Óµ;£ +Å,ï¾ÈÏJPHëo,Hd,ÁsgªÙgã >|KößÃü»¨eý”>1Iÿ4»âXÿ¶þÿåÝk)eòŸ´•U{[~½;­•öVË“ËËì¿à%÷ÙY=Òõg/à/ÙûÂ? -|Ž¥­J¾ðÅß…4ó<ñ1šÖàÚ—yvÆ7J>É +í_™²§#ì?àïøR/ é~4ñæ•á;­#NÑuÝ «iâˆlíÒÕZ轫J’KopÊÖ²A½G^·'ì‰ñ•³†‡ý·ðÏÿ.ê¬ß±¯Æyz|3ø?í·†ùwZƦ^—/µVÓð»×º¼žMK•L;gNWÿ‚Ÿæ‘Ždÿ xçÅõõ§‹|cáË­s]±ñE´šLöHÚ«kVÂòÕ¥¶‘·Im +Á$S`xÙ×ËØŸ¬¾é·>ð¶ªx¯]ñä,ìú¶³”Ws†bB²ÙÛÛÁ…hÛ8$œ“àžý”þ/è:‚KqðÓâ1U뙼7ý5£^æü=øk¦›áÄ-ã¿Ú¹û>øPÔ®u{oøÇJñLúÔzòëÖsY-ä7+§Å§È5³[´rà +—áeÞw(]©· âïìë¤|DŠækψ_ ¿Ö4Eðþ¿yescm7‰-Q¥h…ÆËP‘´fy€kU€‘+,0ª·üçãkù'Ÿï熿ùyP\ÿÁ;>6\©áçÄN駆¿ùy]äÒMN´Z{­m·.ßáÑ®«sÌqÎ4jŒ®½:4×ÜÒk³ÕkâÙèÚ¶Ÿo+É ” or E + Æp=+ÉüS«}¶á°x5ôußüã5çÞøyñþûð×ÿ/*›ÿÁ)¾/Èrßþ!Ÿø†¿ùw_AC=Ê¡«®¯óÿ#À­‘æ“ÑPvù™òýWºMÀ×ÕðêO‹›qÿ +ëâý÷á¯þ]Ó$ÿ‚P|]pâÝ|Bÿ¾¼5ÿËÊê\M•ÿÏåøÿ‘Éþ­fŸóåþæ|ƒ«Ù Ås÷pln8¯µnà’?®ð¯> ø†¿ùyY—?ðG‹óçø€3ïá¯þ]Õ®&Ê¿çúüÈ?Õ¬Óþ|¿ÃüÏöšr'>õõ÷ü9Ÿãÿ™ ÇÿŸ†¿ùyJ?àèAñÿçá¿þ^Qþ³åóù~"ÿVsOùòÿó>BØsŠTL0àW×Ãþ×ñ‡þ„~~ÿååðæÏŒ?ô øûÿ-¯þ^P¸Ÿ*ÿŸëñ%ðÎiÿ>áþgÈ› zW×ðæßŒ_ô øÿóðßÿ/)Gü»ãäAñÿçá¿þ^SÿYò¯ùþ¿òáŒ×þ|?ÃüÏöJpQé_]ø#wÆÿȃñóð×ÿ/(?ðFïŒ_ô ü@üü5ÿËÊ?ÖŒ«þ¯Çü…þ¬f¿óáþæ|ŠTI³ŠúëþÝñ‹þ„ÿåµÿËÊ?áÍß¿èAñÿçá¯þ^S\Q•Ïõøÿ«¯üø‡ùŸ"„õ §¥}t?àß³ÿ"ÿ? òò”ÿÁ¾0ÿЃñóð×ÿ/*¿Öœ«þ¯Çü‰ÿUó_ùðÿó>C*E4¦y¯¯áÍß¿è@ñÿçá¯þ^QÿoøÇÿBÄÏÃ_ü¼£ýiÊ¿çúüÈ?Õ|Ûþ|?Ãü϶ +Bž•õ÷ü9¿ã?ä@ñÿçá¯þ^Rø#oÆ#ÿ2ÿ? òòõ§*ÿŸëñÿ \/šÿχø™ò!#¦4uöü9¯ãý?? òòšßðFŸŒDÿȃãÿü¶¿ùyGúÑ•Ïõøÿ× f¿óáþæ|}°V ?/ò¯®?áÌÿ¿èAñÿþ[_ü¼§'ü«ãtðÿòÚÿååOúÏ•Ïõøÿ‘_êÆkÿ>áþgÊÖr`sŠú¢ø#·Æ8ü“ÿˆñð×ÿ/*qÿ‚øÂÃ߈'ñð×ÿ/)­Wüÿ_ùþ¬æŸóåþæ|¨§¥8.êú©àWþiïÄ/ûëÃ_ü¼§/üã +ÿÍ<ø…ÿ}xkÿ—”¿Ö|«þ/Çü‡þ¬æŸóåþæ|§´ƒÅ.ú×Õ‡þ ñ€ÿÍ;øƒÿ}xkÿ—”ŸðèŒ?ôO> ÿß^ÿåå'ÄÙWüÿ_ù¸k4ÿŸ/ðÿ3å=˜>´å\šú¯þñ„ù'Ÿ¿ï¯ òò…ÿ‚E|`_ù§¿ï¯ ÿòò—úÍ•ÿÏåø•þ­æóåþæ|ªSñ¤)Žq_Vÿã>0ÿÑ;ø‡ÿ}xgÿ—”‡þ ñ„ÿÍ;ø…ÿ}xgÿ—”—eóù~?ä †óOùòÿå@„ÐTŠú­à‘ŸþißÄ?ûëÃ?ü¼¥?ðHߌþi×Ä?ûëÃ?ü¼¤ø—+ÿŸÈêÞgÿ>_à|¦ »ƒu¯ªáÑ?è|Cÿ¾¼3ÿËÊCÿŠøÃŸù'ÿï¯ ÿòòõ“+ÿŸËúùáÌÏþ|¿ÃüÏ–6Ônv““_Vø$_Æÿ4ïâýõáŸþ^PßðH¯Œ-ÿ4ëâýõáŸþ^Qþ²åóù~?ä?õs3ÿŸ/ðÿ3äé0rzŠI +ç<ŠúÉ¿àŸI8øwñ óðÏÿ/*7ÿ‚?übnŸ~!ÇÃ?ü¼£ýeÊÿçòüȥùŸüùòkË»¡¨Þãg^Õõ‹ÿÁ~1¶âÞüBÏ×Ã?ü¼¨Ûþçñ‘¿æŸ|Büü3ÿËÊ—Ä™_üþ_ù¸{2ÿŸ/ð>Qdt=jx5>qž•õ!ÿ‚7üe?óO¾ þ~ÿåå ÿ‚7|f?ð¯þ þ~ÿååfø‡+òù~&±È3%ÿ.YóU¾«ïZºn³±ÇÍÖ¾…þïñ™ü“ïˆ?Ÿ†ùyVaÿ‚Büfˆ‚~üB$µáŸþ^V2ϲÇÿ/‘¼rLÉoIž[àOGkÕ¥Ë\‹-J$‚vµ—ʹ‡dÑͱ9,±ÍR! ®è×*à ú%¶»§\*“«è³>i'ð$þd‡»7•®GO}‘¢ú(é]Ÿÿ¦øËbÀŸ‡?áŸþ^×A§ÿÁ6¾0Z»á—ĆǤžÿååy˜Œ~UV\þÙ'äÚ=,> 3¥EIµæ“8¸¯ì¦©áÏü!/?ù ©–{#ÿ1O þ>¼ÿåýwðÿÁ<þ.F?ä–üIÿ¿¾ÿååXöø¶˜ÿ‹Wñ+þÿxcÿ—•Ç,N[Ò¿þLÎÈÐÌçÏà=†òÝ-î’moB¸K›Ï¶…Ü }šÚÛjí×AÛ²Ö3ów9Á!›NÇü„|?ÿ„5ßÿ/«Òì ñgòJ¾%ÿßï ÿòòø`o‹'þiOÄÏûýáþ^V>ß-Z*ßù35öY‹ÕÒüæÂ]8ù x{ö#]ÿòú©ë6vº—ØŒZö‰h,î$¹Úž¸uœ½¥Í¡WÝ®ç.¤#ip^HU°7ÅxøSñ3þÿx_ÿ—”§öø°æ”|Lÿ¿Þÿåås×yeh:u*Þ/§3:pµ3L=UZ;Ilì´ð•„1®x?ö ]òþ¶¬,ù¥ý¶ð¿ÿ/*Å·ì/ñfØø´ÿOý¶ð¿ÿ/+ÄŸðÜ·IüÙô°ã>,ŽÕ$¾Kü8OÂãþCÞ÷!]òúœÞ …Æ?·¼7ÏýHW_ü¾¯U‡ö0ø­ÁøGñ8ÿÛ ÿòò¤ÿ†5ø«ÿD‡âþx[ÿ—•êç ÿ,~ökþ»qoZ²û—ù9uðÖ ®ºÿ†GýÈü¾­-Ãö>Yå‚ñ5-BîͬXô‘¦[YÛ´ÑM"C ¸¸´’A;É3dAª _Ô‡ìsñTuøCñCÿ<-ÿËÊåüð›Ä µ, ÅáåK98=ôGåŸü ÿ' ð—þɼú~Öè¤ÿƒ€¿äà¾ÿÙ7ÿOÚÝÉŠþ4ý_æNø0ô_‘ú¤&`mã§ÀK?ýCc¯Ö-W⩳žäæ&&`>QŽ3ï_”:2göÑOýP;?ýC£¯Óoˆ+>£ëw¶š]þ·uk óçY4+s~ê¬Ë Fi#ˆHäS$ˆ™a¹Ôe†ùÅ>zÒß“O[dͪ•¿Æ|—ûÁVµŸ¿,¼iâO®¯¯D7Ú†¼-us{áyï¯a·û%⦳<¥äi<„vŠæ:²£G^Ÿàø*Ž¥xRÔ¼|/ ÔGŒ @šÛR}+Q²¹-¾Ÿ«ÝJ’L ` |ˆ7ä…Gâ—üÃÇòèúÔþëÚ¶‹âjñÛøãÀ1ø›D–ß[¿ûkÂÖMu ¬ð:Ä©p“®@”È“ æÎ”Tš§¯y|½Ë=uþe«Ñ~?FåM¦Ûךÿöï,¾[òôí¦ìûcIøÙm¯iV×ÖNnìïbIàž"9£`]H8 ‚#¨5%߯±´–yRuŽ.çfpÉï\¯‚¼ÿ§ƒt/ËÓbþͲ†×f›eö+4òÑWÁ¹ü¨†>X÷¶ÕÀÜqšw‹b—Hð¦§w‘{¯Oki,Ñé–mÜj,¨H‚3<‘ÂÈÚ¦Y2Ãs¨ÉWÃÓ÷•/;_ð¹ËJs´}¦ú_õ>|ð×íÿñq~øcãµkàh¾ø¿RÓÒ Ã¥ÝE¯éZf¡q½¥ôº‹ÝùÊ<èf–ØYDZdtY¢ /¢Áÿ`øO}âëí +Ó[×/µ=>÷QÒäKo êsC%ý€˜ÜéñÌ¥½U‚W[TfšDÑYXü—á†ÿ´}/ÃÞ¼øMñªëàß„5+mGHðü6~ƒYhí'[‹; ­Hø£–Î 0;H¥hà…gĦnÿöSýüsâ?]j+ײ¼áߊž*ñF›á¹<9-¦§u<š–£¼ïz×d³hî<ôE¶ Ìco9£ù4¨©' +JÚ6¯º^âW{7¬¬îôº­¼Ý ê7w{i³ÒoN«XÅy'³•ïéß³×üƒÃÿ¾øÆš…êø Lñ?…u_èÚæ…±%¢Ú<÷j‹x~Ën·#t†YüÅhÝDNMgÿføG?µ¯]kÚÖ‹¦øxØõÖü3©épÇ}:ÛÚN-® Žw·–Vس¢‰WùþFÇhðJ‰oþøcÁ>*ñÔZ®á_ëÿ­ßKÐŽs.©%ŒqÈï%Ìëö˜VÌ呤ˌ.ÖÜÕÿàŸž+ø¤_Üxûâ.‘­xžâOAm{¤xUô»+k-'U‹RòͳÞNï<ò#+ËçQåì‰v¸“c4’´zù')y»Ùré}.í)YD%(¤šwwuãoÙú¥t®íéÖÿðU?†7ž þÚ‚óÆk/áöÒáð^³&»ú[‹—´µ¶7ÊDJK@FÊÙÚA>Ãeñ‰oìáž8o'A"‰!18dnVÃ)õ:_'üqÿ‚wêÿn~!]hž*𮙨øïÄ–þ ‚÷VðÅÕõ߆Þ" 4=„öºœÖ÷cÈ2-ÊH¥DŒ›%Ѿð›xö]Ýê2Y[Gn×WL{’ŠÉ!팒äš)Ѓ‹sV~ïþ“ï}ÒÑywÜÊri®Wtï-t_w^ë¦ÇM?Å£Â)òªHùGø×Äžÿ‚íxOŲÃÍvËÇ¿/~0øªçöz‡…-µ¸$š ¯uK{Ø£³Få^(¦™‚±% +Á€ ýcâÔŸEð¦§yi¥ßëwV–’ÍdЭÍûª°Äf’8„Ž@U2H‰–FX|Kgà/Z~ľø;ÿ +ã“ÿkïðhûgö]õ­ßúøHþO7ìÛ?Ö6Íùù±ƒ1£RòZ^w3æü-~ý !?w]Ï ÿhø*Ÿ†| ðÛâ—ü"WZŒ| áÝgQ³7Ú 4;Ëí>ÚI$µ[í‰kq$n›e‚ ƒ*yr‚Æûv"ÿ‚ª|2Ó¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èhú½.ÁÏ#oþ¿ý3ŸþùãGü-úg?ýò?Ʊ?²G¡£û$z>¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èhú½.ÁÏ#oþ¿ý3ŸþùãGü-úg?ýò?Ʊ?²G¡£û$z>¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èhú½.ÁÏ#oþ¿ý3ŸþùãGü-úg?ýò?Ʊ?²G¡£û$z>¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èhú½.ÁÏ#oþ¿ý3ŸþùãGü-úg?ýò?Ʊ?²G¡£û$z>¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èhú½.ÁÏ#oþ¿ý3ŸþùãGü-úg?ýò?Ʊ?²G¡£û$z>¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èhú½.ÁÏ#oþ¿ý3ŸþùãGü-úg?ýò?Ʊ?²G¡£û$z>¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èhú½.ÁÏ#oþ¿ý3ŸþùãGü-úg?ýò?Ʊ?²G¡£û$z>¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûä|“ÿñ7ü$¿¼ &×_+Á¾&_˜cþb¾÷¯¦ÿ²G¡¯–?à Ö¿fø©à‘Ó>ñ/þ|/]X0Ž"+©Ç˜É¼4ïØüSÿƒ€Nh/„¿öMãÿÓö·E'üüçöøKÿdÞ?ý?ktTâÿ?Wù˜a¿ƒEù¢ú(ÏüÿEÿ² gÿ¨tuä_ðòg§ˆ4ƒÿr–‘ÿȵëúÿÆ¿toû vú‡G_0éžÔ\‚"Ïá_¬ðNW…ÆB_Y§Ú4íÍí~kÚû^Çæ\K˜âp³ÿgœ£yNöm^ܽ½OBOø(ÿÇé®éGþå-#ÿ‘iáãŸè;¥á%¤ò-sÚw‚u" ÿ€Š¿ÿeò!Ͳ“ß寺|3“/ùsOÿù.¸ƒ4zûiÿàRÿ2ôŸðR?É×_ÒGýÊZGÿ"Ô/ÿ0ø×ù¼E£¯„ôþE¬_—„Ǧ=‚×=¨x:ý‰ÿD|D4¥ÂÙU¯ßý¹òx2½¥Zø¿Ìïü×ãGoè¿øIèÿü‹H?ি‹`x“E'þÅ=ÿ‘k˧ð \•´ÀM:Ïáö¢\k/¯Ý5‡ú³—ßýÚŸþò6ÿXqÖ¿Ö'ÿËüÏXƒþ +Añºç§‰tQÿr–ÿȵ£eû|r¼¢Lå]t²Œ‘퇥ÿ€CüŽY晲zשÿÏüÎÒËþ +%ñ*loÖ4ÕÏýJúWù-Z1þÞîÐlñ•=Ï…´’þKW§ü?d â$#Œ`ü«Gø;s­þÔ +súS©”d±Wúµ?ü?üˆSÍ3fÿÞ*àrÿ3§³ý²>*^È»|]¢'¡ðž“ÿÈÕ½eûPüV¸PWÄþ“Œœø[KÿÉzÊð÷Éxi éÇ÷í–ºë[ÅY"vϬ +3^E|&Shá©ÿà¸ò'¥C™µyb*àrÿ2´?µ7ÄØÎ%Õôf÷_ éƒÿmêy?iO‰s·]ӣϧ†t®?;SVÁö8 Èã²ÖÎàk` ¾A癫†t2¸«ýZŸþò;!ˆÌ^ŸXŸþ/ó9føññj䓊lvÿŠWGoý´§Çñkã5Áý©¾+jR/á½" z‡ðý ñW»Û|+Òã”afNç«W¨ü.ýžtp$—Ü*@KƒŸÕklnm“R‡7Ô©¯ûtË —æµ'Ëõ©¿ûxùßÃü¬/ïô­ + úh¶yüŒ5Ñ/ˆè><Õï-Á»Ót8˜uÛ¥Zsÿªññ¼éÃZhÃþàö¿ün¬jºbÅ!\AǨÅö™Ú7“hÎɯAap³wT¢¾HâxœL4u%÷²ÔÞ:¹WaÑ '£iƒÿiÔW¾>Ô,dA.Ÿ¦¢ÈxeÑ­è®kÆ~&xÓTÔ5¨¬ìí5C6<Õˆ¾ù¯¢>~ϺNJ>ÚÜj>+°–ÍÛ/îÐsŒž?ZéÆåø<%Ö­¤ú[_ÁaqؼMWJ”¤íçþl­¦ê×wòB•OŒt[B­Ÿ+¥Wñ6«ªx{W6rÁ¦Å9è¡Ú?8«ÜOÁ+m+EÓ¢¼ñ|2YÚÈ>Í9Ž0ñMùä}køÅàwñŽ4«ŸÚʳFD:¡D!Î8?|þ‚©Vʶ¿g·ý»÷¯¸ö«PÅÂÜå}>×ûxðSã^¡eãEðø‡LþÔT˜¿°ìþd üßê}«Ãö„Õuo_höë¦É¨éãtЮ…bvöýOr+¦ñ'À‹|mµ¯í ñöý­×Úr1m¡›D² +£ÔŸ&½áÃdÔìµëÆñ,6-nÅ“1î’çýÑÓ'µÎhzf¡o«M+µìê§æþ/|+¢0Ë[”c‡§xÛxõû’0•LzQ”«Ï_>Ÿ}ÍÍÅ>.–ÍEËhþqå‰ÐlT/·úš¼þ ñQñ6+žË Xÿ¢k VñaÓAß3B{³ùÖ¿ô׸0¶½ ’¨$ÇøW4rÊu5à üއ˜Ô†Ž¬¿ð'þfÞ½ñGÄZH‘§½ðýŠÆ3‡Ñ,þA¯9ñí…©ÙXÌS_ðõ»Æp ðíƒ1ü<œ:ím,t/!ûc‹…ë…n¿•`øÇá—€‹É6–ÆLuäס„Âe±—-l:oÊýQʼnÅcåjUÚ^r—èÏ8¸ý»µØ,öèO;>Ó@‡•T›öèñ=€UŸÆ>g“SÂúbªþpéY3ðßÂ=0´Ú_,¬pBãò¬+? |.ׂÃA×f-üksøšúºyFRã̰šyÓ‡ù;<Ï3RåxÇ?ó;(ÿn^Ì`‹ÅÞW=$ÿ„gKÇþ“ÖÞûDüBÖâWô‡fèSÂZV?ôš©ü=ý—ü©D¬¾ÕG9 30?νsÃßt/ Ù·Ò<¢2Ùþ¦¼¼bÉi{´ðÑ¿:äwáe›T÷§^VòœÿÌä´üRÖÔ©ñ¾›Ä<¤Ÿý·«º—¾"h0—Æö·,¼‘ÿ¦ŒƒÿIj÷‹ôi4«söX¤ˆîÒ¼3âÝåÆ×ui¶ó…|úŠË—a15¨ÓKþ½Ãü18üNõj7ÿ_'þgo­~ÖÞ8Ѓ#k;2½&ƒ¥o^wâ/Û×âœ7n¶ºÖƒÀ>Ò˜ÿé5xÞ¯¯?Ûvˤ]‘Ÿã|“ú×Yà‹?^‰m:þìQAô¯«§Ã™]óÔÃS—ý¹ò>ryöcV\°ÄMÛòÿ3µÑ¿lŽzó³ëš#ëám$ÿ’µÚè?þ>k( ø›ÃPg×ÂúIÿÛZ³ðçÂúŒQ—³ÔXŽ»Ë ×©è¶¾…ý ”ÿµêkçqÑËi¶©`éÿพîy„Òu1SÿÀäpx×ãZGºoèð i'ÿmªŽ¯ñ£â¾„·‹ôÇ#ÓÂZG?ù-^¿%áa +|ñ®kÅz¿‡|†ó·a^mªJZá)ÿฑÝUâc13ÿÁ’ÿ3ļEûZü^Ò ìñ>’6ÿº@ÿÛjàµßø(OÆM)˜ÂS¢qéáMÿí­z‡Žoü+r˜¥,=ÿ­^1ãÛ/ \3l³½,º¦¾¯ ”euãi`àŸý{ù9‰ÌóR¼qSkürÿ3/Sÿ‚£üg±b?á'Ñøÿ©KGÿäZ¥üOãeËáÑÿù¹MgÃÌä.Ÿ©ÿr“Mð‘#/JÔ¿–Má< –”)Ûü ü‚®¼ÿåÙÙOF+ã=ÏT¸,7X·ãÓèú¦Tj¨(?ƼjI!¹#§Þ_ð­[?ÚKí㡞>òÿ…qÕÊëËh¯¼ê†aF;Ëð=óûN7Lhùëû´ÿËÕÚՔÉÿ¦iÿÅWÿÂæ¹»@\Žÿ| +ÌÖ>+ÝäÓçÓÍ5…,šµÍgšR±ìV†Ñ›ÙÐðºŸüUniºlW µ28áxÿÇ«ç+_ŠW­(áÉÏS!®ÓÂ<ÔnÂé׿sU‰Ê«A^⡘S“µnO™Ûl/ÿU¯ô¹!RDpMè?öjçôm~öþÈ+ÓïÑ’s;Gϫ׊éÎ2´™ê©ÆKDQÔ$¸·“‹[WÏOô¨Çó5.—¯^Àã}›S{fj:-ºÊXÚéYéóJ´ë[8˜³ÐAÞš?ð®žX¸ê¯ýzœêRRþ¿Èô ÅW€.lìT×ìá[ãKˆ ɶ²ãþŸc®/F¾ÓàP<¯/ü OòrïÄd1O‡ÇÕIþK^ML:”¾ÏüÏJv£ñ_qsTø³wjØö{O¦¥©t‰—×Ì3Kž˜½FþUÄjž)³i¿wýýÛgoý–¦Ò<_.û료~•Ðð1äÒ™ŠÅË›YþG®i~+»¸Aó¢ÿÛpkM5»¦ûIG¯6ÓüGÄvTz¬e¥hhYËÖþäé&+Ê©ƒ×oÀôaŠÓÄí›Ä·Šp/X÷é—:ýÌÑ|÷„ñÝ뉴–`^öðƒépÕly’êùN._üj+£ûŠUäúþ$>,×Ìhw^Oû|בxïÄr+±Žõ³ìúÕéZ¾—á{Ïà¾ö&áÏþÍ\æ­á ÌÛ9›KHçú׳€•:v¼_Ü¿Ìòñ‘©=šûÙ䯷M>Ó<ÅAë»ÿ­]×|VÎc #±ëÖ›«ø[ÃÖíòX Ž™cþ5>• /þ‰ B;=?:÷':U£eD#R”®ÝÏ~ðo‰ˆTùŽ?ÞÅzo…ü\" ºB÷ ?¾B³½¼ƒ +±Üƒô55Þ±¨"±Þe¸ï_=‰È£UüV=Êæ¶>Ûÿ„ÚÙcÏrÞ_ð«zgí ãý%úô.£ÿe¯Ï]nóX¹— æÞcWü'e¬Ï:f¼“ܱþ•É>¦¡Ì꯻þ Ñ'›•?Çþúa¢x‘'‹ 4˜n8ñnçÊ»\1fú°?û%|CàÍSÚ‚HîcÇé^•¡x}Ö%3,üôÉ5òø®…)]Tü?àŸC‡Î§R:Ãñÿ€}o¤BÓä"~_ý…tšDçNA±_þä$®à¯ìù§x¶Ê›ä¹T<œLb½†ßà†´›0¶­sfGüµKŽOçÅ|¦>¾œý““oÓþ ôX:5êGÚ(¤½à‡‰üTDÉ)Œщoç¯:Õ|Xw2"þ(wÿ«×¼Mð_éëßê–ªý7_ªƒôâ¸Ý[à'€-§Oã;å Ï:ŠÖ¸,N-oò‹3ÅÐÄ·ÓïD>ñ»A*ˆC2"Æòz ¾)¾¿±)ÊG!âèºåü'ð{ÀäoÞË#.5§ò®Ý~éÙ¾ZkºÂ†é'ö‰Éþ•Ç­…u.“ùÄêÂRÄ(YµògÏ¿Sû#S–iãPò‹`þB¼#Ç?­ôûï³[2cÀTeÎûâwìŸáOÚ#êZ^[Ð7©ÅxÄØWá†|Qgq«;G /$²j¥ý’M}nI›eÍ%[™»tŽš|ϛͲÜuÛ§Ê—›ÿ€yÏ„/¦ÕãI¦R¬ü€Øãò5èZ 1À>î þö Esð#À:]¬¯gâ­Ix_ø˜³9öTçêH®ÂÏá„ôŸØÝ&¿z²\0fY¯V{©A8ÂĹÇâÃÓŒÇЕœyµvøYÏ…ÁÖŽ’¶žhæµ;ó$VòX`²¾vþä?<[ðÎSÜêZK¶É6 ˜Aþ.=>µöêþÏ^ Óí´ûSç îÊü²Ü–’QŒFxúö®3âÇÀŸéÿ4-h2ü1º€ÎÍ»ž78U?äWŸ—qUåp“Z·¦é|÷ìvã²\C§u$žz¿‘ð¼?´ÝfKWœùº>£¸,þb´ˆAÀÎG8ëŒUÛ cÖ’0!–ÖæO9-%¢ïœ¯üà×´_þÉ¿ +tÚýôKì‰qiçOnoF®A9Ür9#+Sá·ìÕð‡Åßµ½ýìf·Ðƒ5–u’Û‚Üaò g¯_Júê¹æ +票ò)|=Ýwïý#æ©å¹O–£‹|Ü»õ[ôØæ<«ivWIi=ü6³7ÌUÉ%G··Ò»ø»AðæWû^ÙF9rÅTýN9®ËàwÀkš‡‰b¿Þ&+%¬uûÅNyÁ?OjÊø‡ðÀº—ÁmWR[˜/o­Øˆ¢iUH\€SÎq_7W0ÂÔĨKŸt¶]vþ™îÓÁb!AÎ<»>½ñÄ7ÄX-5>ä7ˈîA5óoÅ„º†›¯hÙÄ× +Níàÿó/½ðÄ‹“¥†°û<¤.†ü«Ü?foÚж a©˜ ÒŒ…ëõ8åÔÕl;æ®ÓÞÌüö®.éû*Ë•ßFmüñìƒÈ¸< 4ü+Óü_k=þ‹ Vßòäü¸5µàÏ„Ö&èN± Ürv×¥ÇðÏA›Á7Ï,"ú6ÂÄÓ…${õòy†mGÛª‘]O¥Àåµ}‹„™ð'Œ´ùm5y>F–2Ù`Ç$~èÿ5#M˜ +1ÆÁšõ_ü(ðÌFIÒ¥Ï$\•?Î¸ÇøIá{)Öš¥å®[ÉÔYWù׿,ÖŽ&‡#M|¿àž,rÚ´+s¦ŸÌõß êI< ‚Cwq[RKÐryÇJñßx[O·˜¼>'ÕXº¿ÚŒÀ~f»ýJ†Kí¨]LGvœ6kåñXhEÝ7÷A‡¯)+5ø™Þ9¹¶¶Ëo8Žk毌Þ7°Ó_–\ÿ¸Ü~•õV³á­'PÓ3;nù—¼§âÀÿk#tѸ|Ä\ã5ìd¸Ê¦½¢—Èó3\5j‘ýÛGÄúïŽþßxÁLqÎ8­¯]Ü\¸d•Î; {Ä¿²×Ãé.‹«íçö¡þ5ÕøSöið]®øÉcŽ3=}N ÃF YýßðO–†K^RÝ}熛‘3J=¼Ã\׉5k‹w,&™qèæ¾¶“à„~ûh-ÿ]ñ\ω¿gOKfUœÿ¥ãù×6ˆ0¼ÚÅýßðMëd¸Ž]ûÏ”âäysé÷Ûüh.º»'7S¶áÝÛükßïÿfoÉ9ÚîÞ‚?X³ý˜¼%ö\ät&ãŠô·0ËW÷Á8¿²+½.¾óçhîg¸¾üžìßã]/†t뙤þ\ÿ{lß³·‚­¬ƒfUoSqŒU;¿‚þ´ƒu½ÍÌg¯Éx(žy‡š´Sû¿àŠ9Mh»É¯¿þÅØøjâç¡Èúÿõë¢Ð¼9,.‹çTµoi¶mû½SVPyâû§ëU,ô(-ÈÙ­ëJ?ëôà~µ„çí’ü ¡GªüNúßI™#åv€;‘TuXŠDrG¡ã5‹ä$quíX{µÑ?ΪÝljÿ# ÃÞeþµÇ +.÷¿àΩUÒÖüQ“âˆÒáˆ.§Ø©â£øj-¾4ê¤26ï_ôíÿm§¸ðÍã3W»lõÌŠ3Z ü9gáÿŒFÖwŸÏð^¥¼³îÆ5]Ì×/ÔŠË' õ‡OïÄÛ$¦Þ>2ò—þ’Ï…?ààù8„ŸöMãÿÓö·EðpüœÂOû&Ñÿéû[¢¿Ÿ±ÇŸøŸæ~Ñ…þ =ä~‘h ÿöÑýPK?ýCã¯lt˜KÞ-} .?àžz!ÿª gÿ¨|uñ•ƒÀŒn†köomË;ÿ-?ý¸ü›‹¯Î­üõ?öÓ~ßG·1ó*«êe¤cp$ú +’ÒêÌ(Ìrsíš/ ‘\‹y›ðÅ~¤Òk¡ðÉ´õ¹-…°~%ý*kM.Çïp?Z°!².Ù& zšÒÓmìÀiîÞÅÅaJû#YTvÜm—‡"“˜×ï +±'„”'3 Ïûb·4›«Xüƒ ¾i\¹×í! +Ïý6­šÑGò%+«·ùœ™ð¬a‡úLxïÎ¥O…#,?~¤}ü+aüUŸõzzÿÀ‰4ÑãHb~~À>‘“Š.ÖÈ]ÃNð*¿>hÁÿe«E|±.Dñ=Gÿ^£´ø… +t0àvÜsV%ø¡1ð7Ó÷ ZÂR¯Ð´¨õ+7ƒ#V;®"DúÒ§„íÐäÝ~U¼ø¹Á “Ó Ÿ7Å+¹ÃÇ4Ô«u×Ü´ú#vãB³Š1‹™Õõý+Y‚(mšf¸‹ÿ­U/¼y}t˜?»í‘Xºˆ.¦4äf´ŒœäÉqRÙ½Áà<çž0‚¶t‡Šíûa5Æ&©3MÍËþ¯§ê?p~„ÑN²–ˆ'I£¹·šábK£õn*®¡rÎ `TûšÌ´ŠkØÎ_Äš§©Y}ŸïI©­Tw3çm–w‰À—Ô×sá-z7+†b0À5åV- +J3"“]ïƒoìÓh3Ž8¬1PR…ÍpòqaðÖ£Åù]½óÿ×®¢7·š1˜¿Ö¸_ ê¶d'2Iø×Umâ;8 ËëêÀf¾CJ\Ú&}5 «jÉn--Æm!lüÿZÑÑ4M>gè¼ú¦M`\øÎÚ 2°GùçúU­+Æ‘Ü̸M uúÕ„éUåêk +”ùFѼ=h€m³¶H…j¶‰ O–—èª?¥`xgÄË*/ß#ÜŠèWPiS*„þ?ýjð«s©j{4œt(Þéièƒþþ±î×ka]ç<3¿«Ü\9!b<ûçîEË1SÇÔüÉ­èŵ«1­%}by€Èó8ï…cýj¬×JüÌG°‘Y\H0>üÿAM—L—¶®?ÄŠéIw9ÛeKYmÆJºúgÿ­Yž"y&8v^}kJÿG3dãw¦Ïò5B_ º©8œ÷1üñ]TÕ=ÙÏ>~„cÅ÷À€‰/»güi%øƒsYY°¡‰?­R¼·®A›Fìÿ*™~!Úé6åE”Eǃü«£ÙEü0¹´kyX­qñRi?u¥Úäð6Û­Ox»Äw2 šTjë€Oækûã âOÝÃmN9?Ò£·ø³©\È@¸Ú:~íþu¬°²qþ^¬Î8ˆ©|lõ½+_ñ+Æ ÚÙ¢ã?9ä~F©kÿõ}е®œHï³?ÌןÇãJú?šæå=å ~B¨k3ÏÒÜÌú“Ãÿ¯o—¹•Ž3Žõ®ËKøs~ª¥™±ï^3ðîÙ ˆ tù{‡„4[BˆZ=éì+ãs*4i="}F­Z‹VjiÞ'½—eu›můêKmºCrñŸ\â½GàÔ¿ü?iúÀ°3ã;dC&Óôé^½Å?‡ššÇçé 0¡PáŠøQøbþ#/Úî/îXuùv(ÿ?Zö]ïSÚ„4Êdƒõ¯ið§ÅƒL:1¿’f‡Ì øs^“añWáåΟ–úLq3n ÃW™™ñYNÿU’ù†%§Ûë üÏ‹¼¬kS$…®î2£ +Y¹ý¾Eý è°:}Ž>×÷#GA,Ÿï6:~×øwâ_È<e§XÙZ¥ì²™$òJ eþèî}Í}vcŸº´]?ª=zé÷Ÿ3É•:ªXZ¾Õoî,â¼w•¿’p}dxöëRÉr.æÃ!˜’ÍèE} ¯üSøy¨h~Ó-¡O²[I²¤)µcCqóçþ9|Wð=çÄÿ‚"—JÓWuÀ…B«Ž¡@ã8¯ÍðÙ…IV_¸j÷éÑ™÷UðTãIþù=¾÷þGÃ?¼9z<~³K¸jwˆK†Ú ?ÝéÍMðúyî¼q{9òJ`’@ÿ8ÛÐ7ËýÒ+Ù> ~Ð5ÛM$ÚD·ÓQžuC¸· vŒþ5ìÿñ£áœ´ÿŽSPC.™$Ë%´eÆT€}Èï_pñøª9J„®©©}í+$°t~³hÖZͯ¹^æ¿€ãS/žŒñÈÃl™=¿Õß³¶‘÷*+ç9?!?•zìÿã_&­¯ÅªE‘¾ô¶ßóarHÍ‚9öªž ñG…n~kºdШÆå­%<³.zp3õ¯“–.YqtåºûŸùu>Ž8h{e5×ðÿ3⌞ +ð‰µÙ­õ K2óã|2·Ð Ã?Jð}sá&¡ðÆPêú<“K¥ʲ¾ð¹?˜¬ßÚkÅ·–^=½KkË•[iŽÆYeçÖ½öSý¤l|l‘øgÅž[™¿wÔÇä—ٳѫõªq–š¯//ò?7“yÉ|:èüüϪÿfO޾;ðÌšHn@*ÊqÓ±èkÕuf?²³b zW“|1ø5Ãëç¹Ò˜µœä1ˆr«^Â5> 4SX7Ú;HåǦ1_œæªƒÄ9áÓqonÇÜeβ £Yêøâ  v™T£Ó2sùW‚ø¿^Ñàº*¥âÎHIôÍ}9ã_è©dEÍ¢‚VƼ×ĚσuTI汋|g²?àC‘_E”â9¼%òg‰™PçùžgàïXGt°¬À©ìCZ÷‡ÚÍœ¶ªЯû Œ×+áñá²× §EŒãÌXßCŸÎ½#Á–~—O *€ôà µY®"_—Ü,º„¢þ$ÅÖµk8mNde_÷N?Q^;ñOZ³XÈIãç ÚAý {Ýûi‘iå|‚ÀzkÍ~ ]xrkv76q_ïaOç\Yed§~Vþã§0¦Ü-Ìž‡‰R+ã˜Î éÎ?•z‰ Œz€¹®WÅz§‡ÄA¤²ŠE9ükÍÂÖ´ýس¿FñÖHð­[A·šsäÞ̧û»Á[èËî¯]ÀþÝ+Ð/uo ¼ûŽŸ}ÎÓWôÛï Ço¿ìl£Ó#ô/5…ýÈñ._<«Q±×båyÙÙzçu§Ö"ˆ‰çàš÷éüEá«{lyRÇùV^«âÏ Go“(^ØuÖ”s)ßø_5p1kø‡Ì:Õíú»o3/Ô̇S¼G#Í’¾ƒ×<_á¶9Ŭ¹÷úVTZß…å“-gb¦»ý¼å¯+G±„tæLñôÔ/pB=³M’î÷-qǹ¯k7¾ÿÇ´*OªÄT7>( +,ëÃ?­RÄ·ödK¢—ÚGZÜ]4˜i&ÇÔÿZõÙ›þÞ¯»vá ¾ûÇþ¢Ú-X7š DóèA­¿…·¶7o>Š»|¨À9Õ´!ÿ‚ÿ®ïÚá'?óMãÿÓö·E'üá·||øHê›Çÿ§ínŠþvÅ/ßÏüOó?nÃ7ìaè¿#ô·@‹?ðN½ óÏÀK?ýC㯋ôûa‘¹‚Žü×Úþ‹þ5Ç¡¶?æÙÿê!|g¦h’Ìqµ€ïœ +ý“Ã¥xÔÿ ?ý¸üŸ‹Ý¦¯üóÿÛM;(!*»¥íëÒ–òœHøíÅjèþi•I?›ü«px6ü¨`l×ê«èÙñ§'ª<îh×v3)§µ²Þ í~}믾ðoÙ‰8N9çëT™ÒÁù¾´AÅêµ s-†dhÇÜ4’éžgHä#éZËãí +mF;ùy©â Ä sÑ#©ÍöBP[ÜćÃRL~[y›ð5bÝJr,æõäZéñ…àJüý)WÇ÷¾#´-õbjŸH¢­²dîÈɶwËýkJJæKu?ï•KcâÝNaòXÀ õ%sδ¶õ‰" TúXN¥Tí¢5„)ù˜w^ p‡^Ù?ʨ¼­ÖNÙÅjß]ëW# #dç…B1T×DÔçc‘#ç'µkJÞô‘œ£號uàU=_§PH‘©øOÊàméëšì ðn£1å0=KU†øcwp>/šN¥/¶ÑJ>Êg—K£4SHƒo ¯¤h²HˉHú +íÇÂ7ËĽø"¯Úü:[5Ϙ@Mg”bî™Ne£G(t7H°'nœðx¬MkI(I3~•ÝjþšØ)oÈç\v³áוÏ'=>õn¦§æN<²ìsñÙ¬SdÍõæº/^Û[:ù—Xü3Y°x%æ|ìÎè4/‡ !V*qõÅgᾈ¹5+[SµÐåÌHz–ï[UÇR§O–µML©á*Nw¥ Þ ¿ŽEŒ€ú*Šë“Ųڿ”$dQߥCkðâËÁv|܇(;Åpþ1ñ„\¬ë™6úW€¡ LýÅt{.R¡Fwñxä<àK“Åtº?ˆe¹@D…W§Zù÷Lø“íò«J€g¢ñú×®ø#ĶidŒî¬êDZÇeîœuF¸û øw®PðF¥®ê¢D.ñ·;ä ¥—MSÖi!ã¢ç¤.Ë_ ÍÅÓ¬²\É"©÷@?Nµìº1h­—¶‘À«ðÃvÑ;>ãÔ³éÚ»+½F=ÔãQÎx¯/1­µ- OCIÓ§yèbøÙ¯®£GaýÒ;W†øûàv§âHOu{3:ýÀ­£úWYñƒããøv[XüÇ<ÝÖ¼OVý õ¿0±™Ž~÷ò¯&ÀcTé$4Æa\¹*]—5oÙfmNãt³Ìvž0üšô„?³³è³Ç<²<“(Â’Çä•äïñÿX‰‘Y L~lná©÷¯GøKñ—RÔ$C*0g–õ?z¸øf*ƒR’±ç`¥ö©¨»ŸIxcÀ’[ÙïÉfA’Ùè: +ä~%ü4“XY ;‡(FCFk¤ð‡‰n§²/ #Æ{×%ñ?Æ·š}´ÒD¥Û!W&¾ +«ýcG©õ؇GØê´>]ø‹û.]¿Œ$¹yŒìÎáŽHíü©¾ +ýšï4ím/~Ó0™äF-»’ lóø +§ñ7㎭‰/#N›n[  +?Ä×=í ¬i—P‡ËüÝ9?ã_§Ó£˜JŠÕl~:˜(Õz=Ï´~ø ôÛdGg8‰å½+©ñ7ÞâÍf“³ú×…üøïy¬ÛÅæcAíÚ½ÞÓ^›WÒÂ’s”çµ~u™PÄѯy³î05¨U¥h!~Ðß²\z–«=ähUä$È3‘õ®À¿²gÙu„+ ÊÑž}}Cñ»Âº¾«fße$2}ÓžGµy¿4M{O¿ r¬@çƒÓé__‚ÌjË Ì䮾óæqxq¯Ê¢ìþãß> +XßøwA†Òéšâ8T*99`=­u¾#¾X;2 r¸_ ë–6i¼À ðßýz«â‰ãM,·d"žŠ{ûŠøê¸YÕ®ä•ý¨§^訶r_oÓM–³Höï÷‡\}GjðmS\°‘Ùø•Ï +_åÏ×µ{о$-ÂH¡ÖTaÈ‚+Ã~-øß]¶’ûN˜Û\òÆ Øô¯¶É©òÇ–¢±òy¤ùŸ45:ßC r-Ÿa= ãòaýkÞ>ZA U :ñ¯„¼®ëZþ"žT*pU¾øOñ>þ[X㺠àn©ÿ +¼ã-©(sÅ“•ã¡òIBjH,ÈL:f¼⽚ˆ\2§ÔñZzÿ5ìËDVE#Ö¼CâÇÅNtç•5åå9uWR鞆e¦¡ª)\¬µ²®ãѸ¯DøzÖÒÄ£j2úƒóù×ËßĻֻ%Ôuìk§øuñfâÚå³"ž§¢þ¦´în­m# ö„rAƒú +ò~8øbNÖ»ºbz¶UOáÿÖ¨î~/Û궃ìÁ­£õUÛÿãyey;É?š:VaF*É£Ñ5OÉg'îv¤}ÎеÍx‡ÅÚp°{ð‡uã\¬úÍ–«j Ï+îêÀç‰â´´‹-Ò Í/_©?™þ‚º#„5vý e‰”Ý“ÓÔ¿ÐVbÍxø'wÿ"¶<=ð†;¸ÑšýðzãåSøÖí­§‡–Ü2îÉ9ß!Çóçò·ô›­@fÜÃøTò­UlmEBëäM<$¯+?˜¾ø5a檵Ë2ÿ³×ó5Øèÿ´xYZgG ’jµŸ‰´m<†yâ·ÝÏÌjÊüZÐ4ÐÌ’‰ŸÔœãü?ð+ÕÅÏá¹ìÒ§†‚÷¬w:…e¤ÛµŽ„®M.µ¨ÚÙBZâñAjñ~Öúg"ðdÇ ÌGÔôóoÆ?ÚöçÅ0µ¶˜e…C6IfüiáxZ\õ_*îňΨS-5Ìü¥~6|tм7lè·°3Ž0qü…|›ñöƒ:Æ¢ëm#0=ó“^_«x‚û[˜¼ÒÈÅL“š}¿ƒ¯$€M"}ž6è\rß…}~ :å œŸv|Ö/*ïš«²ìŽ×Â^:œj)4³7'¡95ôWÂßÿjEî$žó“ùWÉúFž-®L¶yb+Þ¾ðF•¢æY€*̼gÐõÛŒ¤ªÑ÷—½ÐäÂÔtêû¯C뿇ºtW#Þ0Ú9Ëö®Ò+Í*ÊM±¼oŽäð+䯎ÁXÃI,k' LÊ®h?µígTŽÎØË$íþÎ_jø¬GV›s”¬«£ÒŠPŒnϯ[]²’2ç¢×1ãMzÝaq$莟ƼVoê:DRZØÎnõéWn¿ºµÂö'üŸJòOŠ?µ‰­ìg˜Û®D×%¦nüúVXJšKúþ¶/žÂÕ§ã;µýAä7ÖÊ ã± ì=MsÒü= |Èå†G"œS\ÃÍ;Wñ‹Ë¹¥†Æ!’äp=‡¹ý+Óü á}CÄÓ¼ì$¶ÓmøŒcLw?Zú´Þró­?«-*‹ù¹71OÂóÜóFÎ~o»×ëõ®Ûá/„ ¶ ³4Ñ²ŽŸ(ÆkXŸþ& e3ÎÜž:óýj_ø´ô"¹œ>Ñ÷F?Ãù×-yÖ©I«îtQ:u±ôG‡/!‚Ì©EÀ8ê}kÇÑZÝZJÞb€ŠX}qÿׯ1OŒÛOIJ!ÏÌØ8¬ŸüO’ê%óDIÁÁ üÕáQÊk*¼Ç±W2¦éòœÄOý«ZyVd ;0éÏð®_Røz%ŒÇæÆ PßwÖ»}Rðß^Û!]òÁqÉÎƲomÞkñ +Fþdq²88ÃWÚáëTŒT[ØùJÔi¹6Ÿ 5i<1vÖòܪzç¸ëýk鿆?í5M3sÎÆÁ•òÿ†&½¿2®õÚ\Ãúʸ•ñÞ¹ð‹]‘dše¶s…'!HÏÍÊiã“jV‘¾ 2ž¤ãt~ŽAy§kë±eGŽ@ÆO¡¬íCÃÚn›)óGÆp|U¢þ×Ϥ5½â\1hŽXsÈïùö-Wö—Ó¾$ø +=ZÎä«qûØÁ ŒWËÖáÜM¤âûAK;ÃÕ‹ºÕ¿âϲXho=”‚P£,£­|×ñsãM¾dFrW8'¿¸5§{ñ³ûsÂm©h$âÜw\{×Ë?¼Ru½VmKOó„s0óc˜¬8|k§YÌD³¿Çëšåô’ŠííŠÀ¼yõ+$O‘×±¯šÄfÒæ¼ïPË£Ëi3Û´¿éQ'ŸzÑŽ{KµÝѶ}+ç 4»ˆ~xŒ«ùŠ’ SXÓpRYÀ9Í(q Ö•)ýÞG­9ŸDÍ#‡Î?õ_Ø^2ÿ´ž@õ4ú+õ0Û©õ¦ý•}Z¥¢•\ˆÚ)îi>Äž­SQG*ÈMŠíMþÎOWüêÅr »+63Ý¿:Oì¸ý_ófŠ\‹°s2±Ò£=ßóßìx¿½'æ?­ÑG${3*cÅýé?1þ#üOùð«tRöqì>v~ºÿÄ +Dsÿ ÄÇ?íj6'ÿm+îúù×öAÿ“«ý¤ìeÓ¿ôÛ(CŒ³§'¬ËDßNŽ+·÷¿ú.|/•(§ì#«Kð“ý$_ø7ûàÔk…ñĤ×ö?ü‡QËÿû|˜`ø£âá¨Øý³¯sø™{§Úþßÿ #ŸHÓ¥¼ kS&§$·âÍ#{`Qd•a!Ü^6nyÏðÓöøùûAy>9ðG„þ…—ZƒGceªÞÝGâVÎ9|§¸G_ôx‹ír« ùvàîᚡƹäÔÚe­ûYZN=ºÛóµÒ¸¥Â¹D\¿q-êï/×þ»pàÞo‚ç?ñT|Qÿ¨‡ÿ!Òø7“àÁÿ™¯â újvÿlë¨ø»ÿñf§ñsÅ:€¼Cðšwƒ/ßIº—âˆÞÖóV¹@<ÓoN¬‘£e7IÞAá€Ý×o¿øÏá‡Áísáç…´ WUø“¬]h×zeþ¥û›9`Ža!K¨þVD’&}áÌ~UÜÃÇŒ³©AMb%­¿òm¾OðëbåÂÙTdâèGKþ +ízèþæy±ÿƒv¾ +7_|R?÷°ÿä:|?ðnÿÁ8[?ð’üOoc©Xÿò{ŸڻÇ^ñ/Ä?ülÓ¼!k©øÃÉâÈï|&×gw§‘(uÙpw‰UáaÉ·`Ì|ø·ûDüKÔ¼5â½g l~ø˜¥ÈÓm¯îˆ4Û9”˜¦’FÿGª”fUˆl­ã å½12·}-»]»Å®ÊÎú +\3•%­é×dÿ&ŸÍu<¶×þ ÿø1hÝâGº…—ÿ"V½üÃá€5¯œzúÐÿíµakðSïxªãSñ?„õÙëNðf—s2áx—ŦÛÅÔ09 ñª¸Š˜)¬ªJœ¸žÛã¿üZŽëÀV~¾ø_á…ñ§†“ÅI¬|EÔ¦²ÓZ*¢Ò33r †9lSÁÎE®6Ï\U±3×§ªm~ ¾ú[} — e +M<ÙRx¾a¨EVù”8VäêéOŒ3´ìñ2ûÂ<1”µuB'Çÿðåo†'9ñ?Äroí <é-!ÿ‚*ü2 …ñGÄdìßYý´¯°h¥þ¹gô/Ãü‡þ«e?óâ?ùŸjðBÿ…Ú®Dþ1ø§"ŸáþÓ²ò•PÁ>ù™¾&éý£eÿÈ•öõ¢ã|õh±Rü?È—ÂyCßâÈ?à„ÿ­Wø‡â*Ÿ_·YúÚV†›ÿIøK§¸fÖ|{tážþÕÿO³b¾Ã¢¦\kžËGŠ—ÞáL¡m‡‰òÔðH¯†PñvûU·ÿ¤ºÿ‚Dü3¹‹bêÞ4„¾]ݰ'ñû>kêj+õ³7ßëûÍ¿Õ̳ocägÿ‚1ü1y2|Cñ/÷Eý ÿ%³úÔÃþåðÚ5Û‰> ŸݎöÍsøý—?­}gE[ã åáþD.Ê–Ô"|‡7üá•Âþ&øŠG÷´-?_ôj¡¬ÁþëÛÅ¿`ˆõHu%ÿ%+ìº*—gklL¿òál¥ïB?‰ðÏüÛðj퉓Å=ާcý#¨âÿƒx~ +Fù>&ø ãѵ+é}åE'Æ9Ówx™ p¾T••Ÿøoþcð_þU׌gtèóÝÚ;ü–ÇéVõOø"Â=`“6§ãbÇ¡vŸ/Óý¾¿¢Ÿúåß›ë2¿¨¿Õl¦Ööû‰ôÿø ¿Á› H\gâÁS¸G-ý™@~‚ÔWh?à‘Ÿ þÌ‘ÿ²ÇÂæêÛüŠú’ŠšœaOYâdþc‡ ePøhDùe¿à‘ Þéfkÿ€MÕ·ÿ­M#þ kðçC†Eµ¾ñLO/ ¹·Þß‘ü«é*+)qNm%ib%÷šÇ‡²Ø»ª1>nÔ?à—ïô¦³ŠàþðŠæÝK}q\Õ÷ü“á=ý²Dú—ŒÕä¼µçëþ_[QUOŠóx|‰/˜§Ã™dþ*1gÌóÿÁ)þKcij·þ+†ÖÏ!ŽæØ+cû߸ɮàž>ŠÉmã¾ñQ(Æxò {ÅŒø“3ŸÅ^LÒ9_†’>n°ÿ‚\ü=°Ô.®†§âÙ'»ûÌ÷VÇo°ýÇ —ü·áÝŽ™sjº¯‹Ø]Ï#][oçÐùý+éz*¿Ö|×þËþŸõ.ÿŸ(ù–÷þ Mðâû@‹N:§‹Ò¶á–êØ;cÔùÒ“^ÿ‚Q|8ñÙ<ÝWÅñ 1„]Z€ÜcœÛŸÒ¾›¢©qNlÕyÉðöZôtQòúÁ&>&½¡ý«ã2ر›«_/ë³ç??Nÿ‚Nü6Óu;Ë¥Ôü_#Þ1fWº¶*™Îvâß=û“_NÑMñVmk{yváÜ·cækoø%/Ã{h£âÖ IË\Û>Ÿ¸¬‰_ðEï„ß´U²¿Ô¼in«Ò[k»T~&ÜÒ¾¸¢ˆñ^o̱¿¨>˳£à›_ø7o൬l£ÅŸ][³jvù'Z:üá†RD³ñ‡ÅXÒQ†_í;ü“¯¹h­cÆ9ÔvÄÈÍð¾T÷¡ä…ÿðE…ß +.nä±ñĵ¼’;ËÛ7Cø-ªÖfµÿ'ø5­Ü];jž;€]ÎÞÚØcŠûFŠ#Æ9Ò“šÄÊïÌ åN*.„lˆü+àÏØ–®üDeSÆúËwçöJlÿð@oƒ7#â0d_؃ÿ¤•÷ §úížÿÐL¿ò#ýSÊ?è?‰ðÓÿÁ¿¿ÞäËÿ Ä€ä`âþÇÿ%*!ÿùü±â‰ ?QöûòR¾ê¢“ã\ñÿÌL¿òáL£þ|Gñ>oø7¯à©oü$_ÂÿØBÇÿèÿˆzþ +ñIJ@u þD¯»h©ÿ\³¿ú —áþCÿU²ŸùñÄø9¿àÞ/‚lûˆþ&“Ûþ&6<äDàÝ‚?ñQüNÉïý£aŸý#¯½¨¤øÃ:{â%ø× e_óâ'Àçþ Ôø"Soü$¿ñÿaþC¦¿üŸðAñŸüPãþ¢6ü‡_}QSþ·gô/Ãü‡þ¬åóæ'À‡þ Ìø['Ä¿Iéÿ!+þC¦ø7àx$ÿÂOñO'þ¢Vü‡_QKýmÎ?è"_‡ùý[Ë?çÊ>?ðn'Àæ\üSúÿiXgÿHéÿß| pñ?ÅN?ê%aÿÈUúE/õ³7ÿ ‰ý\Ë?çÊ?>dÿƒm¾“»þŠ MJÃÿªÿƒm~>wx›â›g×RÓÿù +¿Cî¥AKýiÍ¿çü¿¿Õì·þ|£óÔÁµŸTkÿ?ä?õ.ÿŸHüñ—þ ¡ø 7Þñ7ÅCõÔtÿþB¯9ñOü÷áÿü»ö‡ÒGµ?ê?ð™ø#\7ßÛW6óùeÕ|=åù~Tc?h|îÝÑqŒþªWÈßðP+_¶~Òÿ“ϼRò©ázß žc±ãN½W(¾ï0Åå:4e:4ÒhüÿƒŽ û?íMð±o†°ÿéóZ¢®ÿÁËÿeý®¾§L|5·ÿÓÞ³EUWyÉù¿ÌΚ´"¼—ä~¯xFÄø#Þ‹'øgë_ýE¿6+ôóÁÖ™ÿ‚1h’Õ¾Ûê*•ù‡_­x]+ÃéOÿn?4ã¨Út½gÿ¶…Q_«ŸQEQEQEQEQEQELêáºWÊš‡À¿Úá‡íñ'ÄŸ î> M¡x÷Q·¿ âY56»„Åm8ź•'«vät¯¡¾#|Cÿ…i Çý‡â͸X>Ï£YýªtʳoeÈ ¸'Õ—Ö¸ŸøkOú¦¿?ðŸÿí•üo…Ê1uãí¨ÆëUº]Sêû¤TN¼#îK½ÿ¿VaøCàÄoühøyãMàí?hZ¾—¬A¡=×Ù¥{©á0e,TEϽÜxtã¾~Í¿?gÑ|âÿ†Çám­ûËc©i÷Rx‡K´’S+[ÇŸ³ÈP³*´‡'q'(ôßøkOú¦¿?ðŸÿí”ÃZÕ5ø±ÿ„ÿÿl®¥cÓMSÚú^6Õ¹wîÝ»]®¬Íâ)»Ýïú+~KúÐñ_‹¿ðOßiÓt{[-CJñ·†ž¼·Ü>×mª”A |ˆÛ”»>óW{ÿ iÿT×âÇþÿý²økOú¦¿?ðŸÿ픫ØþUgÛ¬zm×ÏÕ½]ØÞ.›“•÷ýu×m6/þÈ?îf¯g…o5 mBò®/'û$F+Y'™æh-£$”‚2åPœ àgÓkÈOídÙÿ’mñcÿ ïþÙGü5“Ñ7ø±ÿ„÷ÿl«–C˜7gøÇüÉzIZç¯Q^Cÿ dßôMþ,á=ÿÛ(ÿ†²oú&ÿ?ðžÿí•?êþ?þ}þ1ÿ1ýfŸsר¯!ÿ†²oú&ÿ?ðžÿí”ÃY7ý‹øOöÊ?Õüüûücþaõš}Ï^¢¼‡þÉ¿è›üXÿÂ{ÿ¶Qÿ dßôMþ,á=ÿÛ(ÿWñÿóïñù‡Öi÷=zŠòøk&ÿ¢oñcÿ ïþÙGü5“Ñ7ø±ÿ„÷ÿl£ý_ÇÿÏ¿Æ?æY§Üõê+Èᬛþ‰¿Åü'¿ûeðÖMÿDßâÇþßý²õÿ>ÿÿ˜}fŸsר¯!ÿ†²oú&ÿ?ðžÿí”ÃY7ý‹øOöÊ?Õüüûücþaõš}Ï^¢¼‡þÉ¿è›üXÿÂ{ÿ¶Qÿ dßôMþ,á=ÿÛ(ÿWñÿóïñù‡Öi÷=zŠòøk&ÿ¢oñcÿ ïþÙGü5“Ñ7ø±ÿ„÷ÿl£ý_ÇÿÏ¿Æ?æY§Üõê+Èᬛþ‰¿Åü'¿ûeðÖMÿDßâÇþßý²õÿ>ÿÿ˜}fŸsר¯!ÿ†²oú&ÿ?ðžÿí”ÃY7ý‹øOöÊ?Õüüûücþaõš}Ï^¢¼‡þÉ¿è›üXÿÂ{ÿ¶Qÿ dßôMþ,á=ÿÛ(ÿWñÿóïñù‡Öi÷=zŠòøk&ÿ¢oñcÿ ïþÙGü5“Ñ7ø±ÿ„÷ÿl£ý_ÇÿÏ¿Æ?æY§Üõê+Èᬛþ‰¿Åü'¿ûeðÖMÿDßâÇþßý²õÿ>ÿÿ˜}fŸsר¯!ÿ†²oú&ÿ?ðžÿí”ÃY7ý‹øOöÊ?Õüüûücþaõš}Ï^¢¼‡þÉ¿è›üXÿÂ{ÿ¶Qÿ dßôMþ,á=ÿÛ(ÿWñÿóïñù‡Öi÷=zŠòøk&ÿ¢oñcÿ ïþÙGü5“Ñ7ø±ÿ„÷ÿl£ý_ÇÿÏ¿Æ?æY§Üõê+Èᬛþ‰¿Åü'¿ûeðÖMÿDßâÇþßý²õÿ>ÿÿ˜}fŸsר¯!ÿ†²oú&ÿ?ðžÿí”ÃY7ý‹øOöÊ?Õüüûücþaõš}Ï^¢¼‡þÉ¿è›üXÿÂ{ÿ¶Qÿ dßôMþ,á=ÿÛ(ÿWñÿóïñù‡Öi÷=zŠòøk&ÿ¢oñcÿ ïþÙGü5“Ñ7ø±ÿ„÷ÿl£ý_ÇÿÏ¿Æ?æY§Üõê+Èᬛþ‰¿Åü'¿ûeðÖMÿDßâÇþßý²õÿ>ÿÿ˜}fŸsר¯!ÿ†²oú&ÿ?ðžÿí”ÃY7ý‹øOöÊ?Õüüûücþaõš}Ï^¢¼‡þÉ¿è›üXÿÂ{ÿ¶Qÿ dßôMþ,á=ÿÛ(ÿWñÿóïñù‡Öi÷=zŠòøk&ÿ¢oñcÿ ïþÙGü5“Ñ7ø±ÿ„÷ÿl£ý_ÇÿÏ¿Æ?æY§Üõê+Èᬛþ‰¿Åü'¿ûeðÖMÿDßâÇþßý²õÿ>ÿÿ˜}fŸs×_î¥A^Rk#þI¿Åü'¿ûe7þ·þ©·Åü'¿ûeêþ?þ}þ1ÿ0úÍ>ç¬Q^Oÿ [ÿTÛâÇþßý²øjßú¦ß?ðžÿ픫øÿù÷øÇüÃë4ûž±_+~Ûvßký«>'¯¯ýH~+ÿÓŸ…ë*j¸|\iÖVðc d£<<œ­OÁ/ø9òßì¿¶Ã4Æ1ðÒÛÿOZÍsþ—‡ìÿ·Ãuôøgkÿ§bŠô»oÍþgš•’^Kò?M¼#ñ×ÂpÁ%ô? +>¯ñøkÙ0wî>F¦>é­~sW¶è«ÿK@÷ø#aÿ¨\UâUûw‡øa¡7ß<)Iú¾sñÞ'Ì*bªZi.IÔŠ·eÊQE~Œ|¨QEQEQEQEQEQEý2˜È£É?ìÔ•äŸl}àGÄ[/ ^xÆþ ÖoôӪLJôgÔ™mľS3,gr€ûA$cç^rq_ÄçõaêþAõžAõà_ðñ þ‰Ç?ü!®èÿ‡ˆhßôL~9ÿá w@ûäQG}Exü¢¼ þ!£Ñ1øçÿ„5Ýðñ þ‰Ç?ü!®èß|ƒê(ò¨¯ÿ‡ˆhßôL~9ÿá wGü¢ úŠùúçþ +7 Ù"4ß ¾7į"B¥üt¡Ø"(ÏvfU©$É©?áâ7ýŽøC]оùÔQäQ^ÿÑ¿è˜üsÿÂîøx†ÿDÇãŸþ×tï¾AõyÔWÃÄ4oú&?ÿð†»£þ!£Ñ1øçÿ„5Ý{ï}EAõà_ðñ þ‰Ç?ü!®èÿ‡ˆhßôL~9ÿá w@ûäQG}Exü¢ úŠð/øx†ÿDÇãŸþ×tÃÄ4oú&?ÿð†» }ò¨£È>¢¼ þ!£Ñ1øçÿ„5Ýðñ þ‰Ç?ü!®èß|ƒê(ò¨¯ŸüoA[Ä·? ¾7‹‰#i–/øB.·²)Uf©ºzëê*Oøx†ÿDÇãŸþ×tï¾AõyÔWÃÄ4oú&?ÿð†»£þ!£Ñ1øçÿ„5Ý{ï}EAõà_ðñ þ‰Ç?ü!®èÿ‡ˆhßôL~9ÿá w@ûäQG}Exü¢ úŠð/øx†ÿDÇãŸþ×tÃÄ4oú&?ÿð†» }ò¨£È>¢¼ þ!£Ñ1øçÿ„5Ýðñ þ‰Ç?ü!®èß|ƒê(ò¨¯ÿ‡ˆhßôL~9ÿá wGüò¨¯’ÿo_‰'Â/Ú{áγâ+øtí2?x¦6žLíVmSÂáG¹¯¬4]KûgF´¼ò&¶û\)7“6ß2-ÊÖÚYr3ƒ´‘‘Á#šüâÿƒ€ÆëŸú”¼Cÿ§ ×­‘aã_JŒ¶“·ÞyYÝwCV´wйùÿ0üDÑ~+~Ø? u½ö-GKºøkn±Ov¹]oYVêB¢¼kþ +Ê6ø‡à¯ý“¶ÿÔ‹]¢½|mÑÄT££&¾æÏ'ˆu°ôêËyE?½#ô/E‡?|>ÞŸl?õ м&½û@LüÐýQýC"¯¯Üx+ø÷—þÞ~1œ§ý}«ÿ¶…Q_tx¡EPÙ7O¦j´gÃ…³ø?Áw>ñ‡<=m|°xrÊßRŠK»8[ľŠ%º«±—-!VÁ¬¤Šàüû0x]|;Ðu»¿_ë¿n® Ó5-2â¬tu²XÛ¼´25Öébgp’õ +€Xó\ïí‘ñ +÷Ã˧jévû4¸ôA}k iöÚ ²Ž5‰`ûtp-ÖÏ-BæüË•l‚AÎð/íCã†þ‡EÒ5{xl¬Ìíbóé¶·WZQvÌm.%‰¦µ/Ô˜9ùºó_) §Z””_[IûÚOÞo—GwôwQ³mh}Ìp’²¨›²V¼S岊v\Ú§ihíkÝjÙëÞý–~Ãyð‹ÃúòøÒëÄ_e–Îk» VÚÞËH•u)¬–U‰í]çS±X¡xÊ~Ÿ [áì½à[/ü0ðÿŒcñv­«|OÔä¶ŠãFÕ Ó­´›q~Ö*Åe´œÏ!x¥rFvI$xΛñßÅzF¡àË«}WËŸáñ  7Ù¡?`"á®zÄŸ¾voÞn뎜W´þÍß¶6ðƒGе_Xñ&¡­x{T¹ÕâқºMõ´²»,Š–úŒíö­=$uýè‚6±Q¹,n2¥NRŒÜ®å¢rï>T¬Ÿ-“…í¥ãfívÕ F +¤¹99t›IÙÚ<íÝ®k´í~÷I;#µÕ?g;â¯þYßÞù:/‚¼¬j2Æú­¦—%øM~âÞ(~×u‹x I*fI„f!OÏÿ´ßÂü.×ôCáÍFÞâÛXÓEÝÅ‚ø‹OצÑçÉC%݉òdÜeRYB•Ê’hÛþÓÞ7´Õt«¸õ„Eµº°µ…ì­å·6×2É4ðK¡Iâw•ÉIƒƒ:'ÄŸŠú×ÅBÊãXm1³­¾Ék¥Zé–¶ñù! ´qÄ y‰ ’[’k§.Ëñô+'RiÂóm&ïïJRÚÖ{¦ÞúY;^óÇ`jÂJœ•¢“²µ£G½×Ã+wOU{[è/„ Ó~/~Îß<5¨éÚ-¢x§âDÞ¾Õ,´[uf³ dÊ¢ïÉ2’­q)™³UUG+®üøwà wÄ: —Œá‡Á*°Ñu8ubÚS­[\€d‡ËµO²IþŒ~VóÀó:¶Ï›‰ð×íYãøCú™¤ÚiþÕZÒ¶h:y¸µ¼VVó¼óšìJ ;݃**U@ì|Aká­kGMCnâø5=B"3ö‹ˆL†7Ý·ríó¤áHw àaÒËq‘«)©$œî’og4å}®]lúõXˇt#MŶ ÕÚZ>YÚÚì¤àztXþÙš_…ü]ñ3ânµâ'ø‡}á…šµ¿‡4ßÃâ(DI5ËK·ì¬Öm…¤pÚãÊJY„cxë_3þÑß +,¾|FK-*æîëFÕtÛ-oM7jÔV×vé&ý¶<ðÏÆ>+Ò5­~ÿ]Ôô{û*-à Õõ}bÀ&—¦ÞJ%·³Žæk˜ÐjÒ=äQ%¼CP´ñ72óÿ´7€ü_ã¯ŽÞ ø…ð÷Äoá-kÂZµáÙ¡ñ­o_µ¾·Ô®4«†eX.lš)#}*0 g %o” pvŸ²·‹ü+ñ£Wø©áï=¯ÄÝvêáîçÔ~kwš·»Ò<7c{vIwë#\xfÖx¤7l"Žâh™&m³¨µÃûsü,¾ñÆ“¡Ùx§ûWûkìKo¬iºmÝ÷‡’[Øâ’Ê µxbm> ‹”žÕ¡‚[„–a{i±[í0y˜?¿à¦Ÿ>*x!üI øÛíú#épë7cG¿‰uØ%’Bi¡àQ¸K››kI-ìÄÓÃws ¬‘¥Ä‰y¿ðO_IûSEñ&æ/_ÞjšF¿«k¾%ø#ý©ãYu 6ÒÊÖ6²Õ¼ˆíìmå]:ÙäŠ;t’{ׂ[f–¶/¿`+;Ÿ„ÿü=‰|aÿÀ¿ÚxWL½o‡º›C¨êZ†µ+;é¡à‹qsá¨D¶« y"º‘VâQ!ö»ø('Âø<1g¨ÇâÛ˻˩ìÿ°l¼­ÝøšÑàH^cs£EhÚ´h—6ndšÝ-õ›nÛu“Ö¼+â­/Ç^Óu½R°Öt]fÖ+ë û„¸µ¾·•Ç4R!*ñº2²²’A ×Ç_bmCö›ÿ„SÄ>¾ð§ÄøcûNÚü]ðÿXð…­¥÷Ø<Ä´Òšu¸Šá[L·e¸šþvæücËší¾–øYq¤|$øcáÏ +iúwŒ$°ðΗm¤Û?ü!wV›â‚%‰“kg¼YT$GôDE@}Esÿð²lÿèãü%µ?þ1Gü,›?úøÃÿ mOÿŒPâßù<ÿakŸý5_Õ/Žÿt¿Ùóá¿ã-^ ûëM +Ô͆ž‰.¡«Ü1 oci2‰®îfhà‚ÀË4Ñ¢üÎ*SÄã_ño†d¶Ò|TcÓ/.¯.^_ß±Æ4ÛÔÎ^¸—tP£,Å€šáÿiÿ‡_íIáøsVØxZÏ^¶Öu»+ ë6—ZÂZ¤³ZEíºÅqe$:ŠØ^,ð8|؈þä¯@¾~Úº~•û<Øë_Ûû3Ç:>©'„¿l¬gM?Ng¿šÞhcmBØym+i²Åtê‘îeÁ“þ +Eá?|\¹ð¶‘¨fXG¥øSW¶ñÞ…¨ÞÛÍ.­â[­ +]"âŽ#a~·6¢Ø%Ì‹,SÏ3InVÂå+Ÿö ¶ðŒ_]øsâoè—z~½gãøWÄ~0uåÒõööúâêu¾»Ž}*òÖÝ [¨VÝôÈ$RÊóD÷üaû'ê?ñ,öµã?j:ö©ÿœ¾"¸†÷ñÃw/‡¼R|Af–QÆ«ö[ô‹ûM“5̾SY;Lò[Î×€õçüÓà†‘áíGYÕ«á»›÷ŽÊé¬om5-.ëIÔ´Ë€‰'“uewW6Ò¤ŠUY£BñO Š r#7É:/üêát_‡z>­ãÞh¿-tMÀ©iðÇUµº‡GÓõÝUxµ9ZIòîTðå„"âí#C%ÌŸgpñÇÐÿ|7gð«âÅ=w0¿ÿ…—âˆ&øºËWÒ¼]ö; ¯øFþëÚ7Ÿ¤›ý­a/Ÿ{vÇí¶^eªÍC%·œÒ©w ·Å¼Oÿ ð¦½>‚’Ûèzõ¦ Çà›vñ‡À¹üMuáÿZj„úU®Ž÷@Çkwkg¨}•î®â¾[£ei,°YR`¦ÁM>|TðCø“Añ·ÛôGÒáÖ,nÆë°K$0„ÓCÀ£p—76Ö’[Ù‰§†îæY#K‰&ñO‚ðO«‚Þð·mücâïØÝxC\ñ ¼Ÿ uTÖ5McÃvz5µ¤¶—bO&ÒÒS i¯%¼–×2a®•nÍ Þ°ý‰cÑþ|(ðůˆ|C,Ÿ ¾Ý|.fÔ>ÞjˆRs —’îÎdekISDhgµ Ho¤Xî`‘ZúŸá—ÄÝã‚,|EáÛï·éWþb£´2[ͱÈÑMÐÈ«,Ê’E,ªK±ÉŠŽŒ£z¼ËàD× þhÖµø¿SÒmD­ç…u_2ää É“Љ§¸(ˆg¸¸˜É*KÛO†t‹Ã·ó¬n-bÊîHYrA^5û9|:ø‡û?ø»Q±ÿ„ºËVøoâø“û'þþ½o®Gý­©^ê^OöÛZå\^c؆øãÆÔfÞ: cþ +[ðsHÒ—wö§]ê±üÎaüñWÃkß…úæ¥qªÜxò?xÓSÖ¾j—V2x†oxŠËZñ–‹q§ûJ[Ý6!cm2ChЬ‘¡C0®·Â_°Ô>/èÿàÔ|âÍkÃ7Oâ{Ý Oøym'ˆ566¸ºŠÑ§‘c¶Ž{¯KäG<¬!K(ÒIä24èõ?Á¿ÚkÁ´ØÿáÖÿµ¾ßá}Æp¡Ü[ùšN­ö¯ìûŸÞ¢ãÍûÏîÎ$O/çTܹðØïö¸øâ‡_|MñFçÀz͇í¥ÙÍ£GámïG›Ã:„ÚÆ·ö{q}v.íÚÚÖé<ô0øÁì<=ák?‡65²ñ-éKM> ƒu¬ ÛK›¹e¬ŸcÓ¾Õ j™òlu9Y¶CòÐý˜?à¡1|RýŽ4Ÿ‹>2ð—4/íßkÚ,:›à}[TÖt¸¬õFÒÚ+Û îç‚ámìÐ\1ýÒϹA]Ȕߌÿ²oƒ?h/Œ¾$ñ?ŠíÒt>ËÄÙ~(ñgˆ²ü{ð{Sñ?†.?·u©õ_1ôÏ6ß7ö~oÙà¼ó¾X§¾WúWî€>‰ð¯í‡ðÓÇZÖ›c¢x¶ÃY“Y×¢ðÕ„Ö1Ëqk}}.„*Z~‡{ Îþ¿Fß-ÖŸ±UZÎHÎ18šå¾/xnÏâ¯Ä…šîNÝ£~åÃÓmo ü&ðG†cñÿÄ Åš®¯¥¦½sâ/xWQo[isÉ!µÔîž/âÓ,$r.ï.Ö ­Ô‹ H¤µ?ü³„~#Ésc¯\ø“À~ÔüEic¨hÚŽ“¥øŽ[=6]DØÙêÒÛ}Šâá ŠF1ÛÉ4¨Ü9Œ‹yBy—íƒûøSö®øìž8»Ñ4;»½GA´ðƦÞ0ø)?‹n´û;k‹Éã—G{”XlnÉ¿¹ß%ĹŠÐ´at›ƒøÍÿ¦Ð>:|hÕ5½nùÿ±u«¯MªÃð‡Pÿ…ƒ{o¬é¦™%Œž!we{KdÕ[BÖ$E …Œ'x‡{}m¦þ׿õ? j¿ö½ý¥¦“¯hÞ¾ŽûE¾²º²ÔõdÓ^ÂÖ[y¡Y£’A«éûƒ ÊÊchå Éi¿ðR߃š¿‚<3â[kÒh>+ÒÓ^·¾>ÖV7K’I-OR&×þ%vù3¼wwÞDÅo4©#Gºù—?døãÄóÝKãÿéÚgˆ|eáoˆ¾)±±øW©ÖuÍôehâ–WÛi“C£[•·îb¸"Cy4!ídàõ¯ø%…5 |6°»·ÐüKwá‡:ÃMORñ‡À¹üIt,ô¤c¼ÑÖätÛ¹ ÝË9¸Žþ)iºX]gûÀŸ´×‚>%üNÖ|¢ël×´??ͬî!·¼û<«ߨî ß²Ü:Asög—쳺E?•#*ò¼á'ÃÍCá¿í ã¯ÝøƒÆž•âí¬šLïìšIC ³ßH‘˜®n ‰RÒ á‚ÖSi1]µûÛÛÍ­Âɳÿ _Œ?ð–ÔÿøÅtÏüIÿ>—ÿcÿ§;Z?ádÙÿÐ/ÆøKjüb³.øvú嶃à½Wð‹üAãEÔowÂ#«x{RÑôûû6½cokqw©G-ÆÏ.O²Ç,n#9~ëö§ðÝŸí/û1|GøqhŸð°"ºµÓì.›MÓn5;xÌ 4àIŒw7FK{Aw2™chai¥VZ¿yÿ-ø9cáýGU“Ä÷Ø,¾ÊÖ’§„u—ÿ„’+›Û{'ÑÀµ'X·{›Ë(Äúp¸‹ý6Õ‹ž&~Cÿ²¼u‚6~ñ?ô¿ üÐlü7o×€¯.5‹«;Xw±Á¤w‰ { Ä0È--d¶ŽÆêüÿ‚PxSà¶‹¥éz=¾‡¢Úxbëë¥jÀ¹ô½wT³ÒuÝ/UZÔ@y¯îæL1´Ðý’2ââi-¦o! ûÀŸ´×‚>%üNÖ|¢ël×´??ͬî!·¼û<«ߨî ß²Ü:Asög—쳺E?•#*ò¼á'ÃÍCá¿í ã¯ÝøƒÆž•âí¬šLïìšIC ³ßH‘˜®n ‰RÒ á‚ÖSi1]µûÛÛÍ­Âɳÿ _Œ?ð–ÔÿøÅtÏü"ÿ’=àïûôïý$ŠøY6ô ñ‡þÚŸÿ¬ÏøœxGáï†4Ëý'ÅI{c¡éðΑxvþuŬY]É .Aà€r à‚(Ø|1ÿ"Öÿ^Ñÿè¿:àà›ÏØ¥âý;ø^¿E¼1ÿ"Öÿ^Ñÿè¿;?à¿+ºûÀßö)x‡ÿNþ¯{†?äkCüHðø—þEuÿÂÏÂOø+PLjþ +ÿÙ;oýHµÚ)ÿðVñüÿ²vßú‘k”W­›¿Vÿ¿6yy_û•ðÇòGè¶€˜ýŸ<>q×à‡þ¡±V¯ü9ÓöŽÿ¢uÿ•ý/ÿ’j‡£ÿŒtðùÿª!aÿ¨lUû¹_K_‹±™%:TŒeí)ÂüÉ¿†öµšîÏ“Éøo ›UÅ}bR\•gnV–ýîŸcðÇþéûGÑ:ÿÊþ—ÿÉ4Ã?hïú'_ù_Òÿù&¿s¨®ø‹YÇüû¥÷Kÿ“=¿ø†ùgóÔûãÿÈŸ†?ðçOÚ;þ‰×þWô¿þI£þéûGÑ:ÿÊþ—ÿÉ5ûEñ³ù÷Kî—ÿ&ñ òÏç©÷Çÿ‘? áΟ´wý¯ü¯éü“Gü9ÓöŽÿ¢uÿ•ý/ÿ’k÷:Š?â-góî—Ý/þL?âåŸÏSïÿ"~ÿÃ?hïú'_ù_Òÿù&øs§íÿDëÿ+ú_ÿ$×îuÄZÎ?çÝ/º_ü˜Ä7Ë?ž§ßþDü1ÿ‡:~ÑßôN¿ò¿¥ÿòMðçOÚ;þ‰×þWô¿þI¯Üê(ÿˆµœϺ_t¿ù0ÿˆo–=O¾?ü‰øcÿtý£¿èåKÿäš?áΟ´wý¯ü¯éü“_¹ÔQÿk8ÿŸt¾éòaÿß,þzŸ|ùðÇþéûGÑ:ÿÊþ—ÿÉ4Ã?hïú'_ù_Òÿù&¿s¨£þ"Öqÿ>é}ÒÿäÃþ!¾Yüõ>øÿò!_*þÒž(¿ðGí‡â=kJœÚêšGÀÝröÎ`Šæ£½Ñ¶°e8eH8ä•õU|‹û` ß´×F3Ÿ€~!ãÏú\>Çùü¸ýùãHý´ÿh gá­âèü|ëo§]–ì]3÷°©.%ÜaÈò¥¼ÓÓnÒ_í@Ž"“þ,þؾxG@Õág=ïöößÝÂ=§EänÓ4Ûî¾SnÇö——Ш üeG–xkö’ðÞ‡qá­1ü9iu£éš1ÐgÕçþÚ†Öñ%þÑ*Ü-«7™{yä"8V‡~H5‘ñ·ãvñ/À¾Ó,#¼ŠãEòüæQQñ¤hö_)V$þöÂSÈ+Æz’«ýKC‡r ãááé*Mɽcµ½Õñ7}.õNòjÖJÿγìî8)Êê:‰E-%½×3øRëe£VIÞíž·ã/ۇ㗄~/ø£ÂŸð°µ-CþË­J×ϳðÆ$“}OûÕòGû½ÎÛ›Ë@Íóí!¨_~Û¿´Îý‰ö_ÄVÿð“íþÇó<-h¿Ú»¶íû>m{Ÿ2Ò~.j~.°¹ñÒøÂþúûTÓî--šÃKkËk¸ØZGME¢7ìPÊ-Õ• +pLS›‡y"á…¥'ìîï¥ê$ï×/{Ù§k-Z*Y¶}Ï.|MH®{+kh6¬öwík¦¯w¢g\Ÿ¶GíG?‰'Ñ’ÿÅ-¬[ÊKb¾µ71I$RLˆÑý—pfŠ7‘A)7 1¬ûOÛËöÔ|wâkSh2ù:œ~²k;i PåÛ³$|Ÿ™=yä¾'þÒö~(øg«xgNÔµ9b¼—KŽ9L²Ñ­®-mßQãkK3対}ô,¨Z]ÏH]IHÖÇÆþø³â=GÄ]ø«KÔ þÖ´Ó­-£†4½·½¾½¹WžàJZ/—P)$ ‚Eoš¾vcÒ–IÃ÷Š©„¡fítÛÒÉÞͦ¹›²º÷,ܯ­³©›çv“§‰­t¯f–÷jÚ&Ÿ*Wv~ýÒ´¿[}ûnþÓ:wö'Ú5[ÿÂO·ûÌðµ¢ÿjîÛ·ìùµýî|Èñ³9ÜŸÞç#Vÿ‚Ž|{ÐõK«ß]Ù^ÙÊð\[Ï¡XG-¼ŠJ²2µ¾U”ðAyïG?k­#Æ$kø/u;(µÝeµBÞÇÃÚE°gŠâ1º«>ª ^:°¹0¬Ñùˆë›ðøïÄÏi¾*ñÅíæ–×‹¦·— š]Îd’8c#çvHÂ… ’ClC$»|ÆéÊò­$±xZ1ÒúK­öÕ­¾w³kFŽ|Ë;Ïé&ð¸šÒÖÚÇ¥·Ñ?ø³Õ3ÖÏüÇã‘ÏüWn3ÿPm;Ž¿ôïïú|Ï¥ÿÁG>=ëÚ¥½Œ®ï/oeX-íàЬ$–iíTEä³@IÇãóø¹±‰ç§Ì9éþ#óÓ|"ñå¼j//|É,®ì/´¹Ú ¯,1ÞYËhÒ¢’² ÷„,¡Ê…Ü›·[Âü! +3:4\’m.e«¶‹~§›‡â>)XÆ¥jª-«¾W¢¾¯cèý?ö¦ý¦u #XOøH|Dž%ÒµK7ûþ+C}'Úm¯nwùgÞ6Gk»UÃdws6Ÿ·—í¨ø>ïÄ6þ Ö¦Ð,eò.u8ü5dÖvÒ #Ê-¶+fHø'?2zóçzïÆ-KøA¬ø;@Ö“­ÿdj–·µ¤’ÚÊ“F³ÅÄLÊA£pÈêN2¬ +°8 ƒŠ©p§ÛJToþ%þd®&â»ëV¯þÿÈúÛà¯ígñï⦿­ØÝøÛÅ6’é4zÊÚé~ +°Ôµ ÈäšÚ8ü«r‘nR—I.íØòÓpžGÇ¿ðQOñ†¡¦ÙøûZh¬e07ö§…´Û ÈäQ‰Hryl¯¹q¼Ÿ‚J×âßÚÏã/‰xäðö—&k¥<žÓ¬’Whb´RÓGÁö˜]í•’‘Vñ”$Dù/‹~<±ñç~Ùcæ-•µ…†—nÓíYgŽÒÎ D••KiJå0C&ÐÏÇÂËø_‡%‰¾.•œoÊšq‹÷~ÖŽM¾m:[ªižÎ;ˆóèáí…«Uµ+s4Ó’×ìëd½ÝzߣM¦à¦?Žâ»qŸúƒiÜuÿ§Ð{ä?ðSŽG?ñ]¸ÏýA´î:ÿÓ¿¿è=óàÂæ6Æ$CžŸ0ç§øÌP.clbD9éózˆüÅ{ßêŸϪ?øÿ3ÅÿY¸³þ~UûŸùòà¦?Žâ»qŸúƒiÜuÿ§Ð{ä?ðSŽG?ñ]¸ÏýA´î:ÿÓ¿¿è=óàÂæ6Æ$CžŸ0ç§øÌP.clbD9éózˆüÅêŸϪ?øÿ0ÿY¸³þ~UûŸùòà¦?Žâ»qŸúƒiÜuÿ§Ð{ä?ðSŽG?ñ]¸ÏýA´î:ÿÓ¿¿è=óàÂæ6Æ$CžŸ0ç§øÌP.clbD9éózˆüÅêŸϪ?øÿ0ÿY¸³þ~UûŸùòà¦?Žâ»qŸúƒiÜuÿ§Ð{ä?ðSŽG?ñ]¸ÏýA´î:ÿÓ¿¿è=óàÂæ6Æ$CžŸ0ç§øÌP.clbD9éózˆüÅêŸϪ?øÿ0ÿY¸³þ~UûŸùòà¦?Žâ»qŸúƒiÜuÿ§Ð{ä?ðSŽG?ñ]¸ÏýA´î:ÿÓ¿¿è=óàÂæ6Æ$CžŸ0ç§øÌP.clbD9éózˆüÅêŸϪ?øÿ0ÿY¸³þ~UûŸùòà¦?Žâ»qŸúƒiÜuÿ§Ð{ä?ðSŽG?ñ]¸ÏýA´î:ÿÓ¿¿è=óàÂæ6Æ$CžŸ0ç§øÌP.clbD9éózˆüÅêŸϪ?øÿ0ÿY¸³þ~UûŸùòà¦?Žâ»qŸúƒiÜuÿ§Ð{ä?ðSŽG?ñ]¸ÏýA´î:ÿÓ¿¿è=óàÂæ6Æ$CžŸ0ç§øÌP.clbD9éózˆüÅêŸϪ?øÿ0ÿY¸³þ~UûŸùòà¦?Žâ»qŸúƒiÜuÿ§Ð{ä?ðSŽG?ñ]¸ÏýA´î:ÿÓ¿¿è=óàÂæ6Æ$CžŸ0ç§øÌP.clbD9éózˆüÅêŸϪ?øÿ0ÿY¸³þ~UûŸùòà¦?Žâ»qŸúƒiÜuÿ§Ð{ä?ðSŽG?ñ]¸ÏýA´î:ÿÓ¿¿è=óàÂæ6Æ$CžŸ0ç§øÌP.clbD9éózˆüÅêŸϪ?øÿ0ÿY¸³þ~UûŸùòà¦?Žâ»qŸúƒiÜuÿ§Ð{ä?ðSŽG?ñ]¸ÏýA´î:ÿÓ¿¿è=óàÂæ6Æ$CžŸ0ç§øÌP.clbD9éózˆüÅêŸϪ?øÿ0ÿY¸³þ~UûŸùòà¦?Žâ»qŸúƒiÜuÿ§Ð{ä?ðSŽG?ñ]¸ÏýA´î:ÿÓ¿¿è=óàÂæ6Æ$CžŸ0ç§øÌP.clbD9éózˆüÅêŸϪ?øÿ0ÿY¸³þ~UûŸùòà¦?Žâ»qŸúƒiÜuÿ§Ð{ä?ðSŽG?ñ]¸ÏýA´î:ÿÓ¿¿è=óàÂæ6Æ$CžŸ0ç§øÌP.clbD9éózˆüÅêŸϪ?øÿ0ÿY¸³þ~UûŸùòà¦?Žâ»qŸúƒiÜuÿ§Ð{ä?ðSŽG?ñ]¸ÏýA´î:ÿÓ¿¿è=óàÂæ6Æ$CžŸ0ç§øÌP.clbD9éózˆüÅêŸϪ?øÿ0ÿY¸³þ~UûŸùòà¦?Žâ»qŸúƒiÜuÿ§Ð{ä?ðSŽG?ñ]¸ÏýA´î:ÿÓ¿¿è=óàÂæ6Æ$CžŸ0ç§øÌP.clbD9éózˆüÅêŸϪ?øÿ0ÿY¸³þ~UûŸùòà¦?Žâ»qŸúƒiÜuÿ§Ð{ä?ðSŽG?ñ]¸ÏýA´î:ÿÓ¿¿è=óàÂæ6Æ$CžŸ0ç§øÌP.clbD9éózˆüÅêŸϪ?øÿ0ÿY¸³þ~UûŸùòà¦?Žâ»qŸúƒiÜuÿ§Ð{ä?ðSŽG?ñ]¸ÏýA´î:ÿÓ¿¿è=óàÂæ6Æ$CžŸ0ç§øÌP.clbD9éózˆüÅêŸϪ?øÿ0ÿY¸³þ~UûŸùòà¦?Žâ»qŸúƒiÜuÿ§Ð{ä?ðSŽG?ñ]¸ÏýA´î:ÿÓ¿¿è=óàÂæ6Æ$CžŸ0ç§øÌP.clbD9éózˆüÅêŸϪ?øÿ0ÿY¸³þ~UûŸùòà¦?Žâ»qŸúƒiÜuÿ§Ð{ä?ðSŽG?ñ]¸ÏýA´î:ÿÓ¿¿è=óàÂæ6Æ$CžŸ0ç§øÌP.clbD9éózˆüÅêŸϪ?øÿ0ÿY¸³þ~UûŸùòà¦?Žâ»qŸúƒiÜuÿ§Ð{ä?ðSŽG?ñ]¸ÏýA´î:ÿÓ¿¿è=óàÂæ6Æ$CžŸ0ç§øÌP.clbD9éózˆüÅêŸϪ?øÿ0ÿY¸³þ~UûŸùòà¦?Žâ»qŸúƒiÜuÿ§Ð{ä?ðSŽG?ñ]¸ÏýA´î:ÿÓ¿¿è=óàÂæ6Æ$CžŸ0ç§øÌP.clbD9éózˆüÅêŸϪ?øÿ0ÿY¸³þ~UûŸùòà¦?Žâ»qŸúƒiÜuÿ§Ð{ä?ðSŽG?ñ]¸ÏýA´î:ÿÓ¿¿è=óàÂæ6Æ$CžŸ0ç§øÌP.clbD9éózˆüÅêŸϪ?øÿ0ÿY¸³þ~UûŸùòà¦?Žâ»qŸúƒiÜuÿ§Ð{çôGöøŸ®üeý•|/âOßKZÔZóíáó<»ÙãO–5UDQÂóŒòy?Ž¢æ6Æ$CžŸ0ç§øÌWëWüü†ý†¼W3jÐÿÄÆçžƒüúõ¯É¼YÊr,‡öL)ÆR“¿+MÙ/Vív~›á–gœâñU¿´å9F1VæM+·èµÐöÿ ȵ§×´ú¯Îïø/ Î¥àoû¼Cÿ§ Wè†?äZÓ¿ëÚ?ýWçüÈgRð/ýŠ~!ÿÓ¿†+ò®ÿ‘­ñ#ôŽ%ÿ‘]ðŸ„ßðWQ·ÅÿìŸýHµÊ)à¯ò6|ÿ²võ"×(¯[6ÿ~­þ9~ló2¯÷*?àäÒ/ÇŸÙ³Ãçþ¨‡þ¡ÑWî¥~xq3û3xxÿÕ°ÿÔ:*ýͬø«øxOúö¿C‚—ïq¿õö_¨QEñçÝ…Q@Q@àoŒÞ%Ö?ि¼s©yžÐ|áínÆÃìñ"òêûVŠy|À¾cnKhÖb£f@±< ÿíã‚~.üJ𯇼«ë¾9Ÿâ=Ÿ‚4;Ï\6Ÿ«ßIáû}Q®åIJ³ŠØJdKx¥Üai)%”©ï~*þÃSøëö‹Ô¾'økâ÷ņ~"Öt+/êør æÖòÚÒk™¡,š–™xÊá®æÉFPAVMÏü7·öýÍÏŒ¾ MãsĶ1Åâ{u}+X´Ó`ÓVòÙc´[Pd·€‰b’Ýà´L¦?-„jSz^]^o÷‰éÓຳk[mdÖ•\åËÕ+vMS¶¿öþ®×Òïwgñÿþ +âØóབ³ñÂ|âx¢/ x~9>"cÂ÷M%±¹ûUÞ¯scnÖp¢Çpu£¾è”F²™¸_Ábn~)xCÃx+ÁÞñ׌µïˆ’ü8–?üF‹PðÄW#H›UŠòZ;2ÓÛV%“ý%Œê#‘¢ '¶ßþÃcÄߣÓ|GñWâ—‰¼S¦ëÉâMÆW²éPë^¼K³)´ŽÚÆ+‹É2£E%«¤¢âo1_y§i_°ÕµÆ©à½OÅ>%øÿ\ð7‹_Æ:–¹q§$’\6›6œ-ÚK8-ã¶Xfw Q±”—fbͺ©¥Ìùö¼mn×…ý]”ïÓUÊúËá÷–_ø§ËÿnÝÂÝnÕ¯>Òÿà¥Z÷Ùu_ +ê ¬ã-Ÿá寇4ÿ½Ö‰y}&”ºº\RK8¤ŽÑlY¤•Í™•Z'T†S°½ÏÿðP¿þÇŸ쵟‹þøsàø‹ÅxcÃñÉñºi-ÏÚ®õ{›v³…;€û­÷D¢5”ÈµÔøÛþ ÏàÏk~1Ö£Öü_£x›Å^.´ñͦ¹§][¥ï†u[m>:9lwÀñìkhJÿ±OÄ?úwðÅ~ˆxcþE­;þ½£ÿÐ~uÁåònü ßõ*xƒÿNþ¯{…ÿämCüHðø›þEuÿÂ~ÿÁ^xñgÁoû'GÿR-rŠOø+ó|OðXÿÕ;?ú‘k”W¯›ÿ¿Wÿ¿ô¦yYSÿb£þþHý/ðÊÆ/x|óÿ$FÃÿPè«ô·þû8ÿÑEÿÊ©ÿÈÕù¯á”ÿŒYðùõø#aÿ¨|UòÍ}îWÂX<òœ>·)/gN¹Z_5ïx¾Èøq&')©_êñ‹ç«;ó&öµ­f»Ÿ¹ßðø¿ÙÇþŠ/þP5OþF£þû8ÿÑEÿÊ©ÿÈÕøcEz¿ñ rùùWïÿ _üDŒÏù)ýÒÿäÜïø|_ìãÿEÿ(§ÿ#Qÿ‹ýœè¢ÿåTÿäjü1¢ø„¹?üü«÷Çÿø‰ŸòSû¥ÿɹßðø¿ÙÇþŠ/þP5OþF£þû8ÿÑEÿÊ©ÿÈÕøcEñ rùùWïÿ ñ3?ä§÷Kÿ’?s¿áñ³ý_ü jŸüGü>/öqÿ¢‹ÿ” Sÿ‘«ðÆŠ?âäÿóò¯ßþ@?â$fÉOî—ÿ$~çÃâÿgú(¿ù@Õ?ùø|_ìãÿEÿ(§ÿ#WáÄ%Éÿçå_¾?ü€ÄHÌÿ’ŸÝ/þHýÎÿ‡ÅþÎ?ôQòªò5ðø¿ÙÇþŠ/þP5OþF¯Ã(ÿˆK“ÿÏÊ¿|ùÿˆ‘™ÿ%?º_ü‘ûÿ‹ýœè¢ÿåTÿäj?áñ³ý_ü jŸü_†4Qÿ—'ÿŸ•~øÿòÿ#3þJt¿ù#úh¯¿ÿ” i?öKoôíi^õ^ ÿ)@Òì–ÞÿéÚÒ¿žÛz¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(†?äZÓ¿ëÚ?ýWçü''•ÿ9ÿ©W_ÿÓ¿†+ô{Ãò-ißõíþ€+ó{þ8‹Áþ¥]ÿNþ¯…¿äm‡ÿ<.&ÿ‘Uð³ðËþ +¿/®|o_‡mÿ©¹EEÿQmÚ§Á"è·þ¤zíëfÿïõÿÇ/ý)žNUþåGüü‘úáˆóû)xtú|±ÿÔ>*ùJ¾²ðÄgþ3ÃÞ‡à…þ¢Wɵû' ÿ׺_ûyùwüIÿ×Ú¿ûhQE÷ç„QEôMåŸÃï†? ~I«ü9Òµöñ¾—us¬j_Úš…¾§…Ͳ½¶Û³#¢"ß©eù×ÎÕëÞý¯n´/xOLŸÀÞÖ/¼m5¾‰«j0^ÍsgæO$áÌBäZÊÉ,¬Ê%ׅʰù™µ?f›JW’RåmrÉnšûN/å{;؃©ÎÒn6‹k™'Í{Yý•%·[u:m3ö'µ½øóãý£âV©7„µv°[ ø'û}ÙVkŒ]BÐð:|á°xÁ½gû0x#À? +þ0[øçTÖ ñ€|[e Å¨èúX¾USöµm‘Éun¬$hy.7 vîÞÁx~ÖZ½Ÿ†otŸè^ñ͵޷'‰µÆ¼C¨H¡d¸ÍµÄ>i`«‘0‘FÞÜÛ¦oÚóUÕ5ÿÝë~ð§ˆl¾#êI«êšeâÞEk ÒI+¤˜."•6ùÒ Œlp y0ù»\’›²PÕr«¸Ê ´ßó%;©$¶Z¦z±¯–):йY;蚨’i;hÜi·£Ù­w~þÆ#ãÂ+ïéRüC‚k*÷Sk»¿2øuͪ<’B5$¹|1XØ)0dÂg5äß ~êþ#è~Ò>¡¯_Ec~ê³°]ÇÑFrO` zU‡í±«ÚiÖ­/„¼y®ÙxrO +C®N—Æò-=í¤µ¬kt-•– +†XCq–,Kà>|^Õ~ø½õý mÓXK+›KK·2 4æž&ˆÜBQ”¬È®Ûä)9Æ@Ç£‡þÐ^ÚS³ÓÜNÖ¿½¥Öñøuv{èpWú“…(ÓÑßÞjûZ=—O›k§§{/rø—û7xâçÄo‡‡á˜Ÿ@ð·Š|G/‚o&v–üÚÞEr«Ûoq“qm,Sya•w,¡pÞý‰ì~(êÞ)“Ã:ÇŽÿ‘kNÿ¯hÿô_›ßðpØÌ ÿ±W_ÿÓ¿†+ô‡Ãò-ißõíþ€+óþ‹Á?ö*kÿúwðÅ{ü-ÿ#l?ø‘áq7üŠ«ÿ…Ÿ…_ðTßù |ÿ²xÿú‘ë´QÿOÔþ ÿÙ<ýHõÚ+ÖÎ?ßëÿŽ_úS<œ«ýÊø#ÿ¤£õSÂÑgöDðëÕ±ÿÔB*ù¾Áð¤yýŽü8êˆXÿê#|}_±ð'ðåÿ^éíçä¹ïñ'ÿ_jÿí¡EWè€QEQEQEQEQEQEMà·ÿò” 'þÉmïþ­+Þ«Áoÿå(Oý’Ûßý;ZWñ9ýX{ÕQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@|1ÿ"Öÿ^Ñÿè¿8àá5ܾÿ±SÄúwðÅ~xcþE­;þ½£ÿÐ~rÁÁ£?ð„Ø©¯ÿéßÃïð·ü°ÿâG…Äÿò*¯þ~ÿÁTÆ5o‚ŸöOÿR=vŠühcZø)ÿdñÿõ#×h¯_7_íÕÿÇ/ý)žNUþåGüÿÒQú¿á4ÏìgáÓÿTBÇÿQëãjû;ÂháŠü:{±ÿÔF:øÆ¿aàOáËþ½ÒÿÛÏÉsßâOþ¾ÔÿÛBŠ(¯ÐO(¢Š+ݼ[û+hÚ쎡©Ÿˆ:u…—ˆµ2VŒ[C¤ÞÏ$04jÌóýG%¶ì¼L‚Oˆi’ÛÁ©[½Ü2\Z¤ŠÓE‚'•”9 ´‘ÓŽ¸=+è ¯ø(Ž»­|J×õ OÃ~¹ðψ¬ît‹*ßFÓ­oWN’ VÃR[_´Ÿ%[Y‰É…r¤q^Fj±¯“êkgÌõµíosgñ]öJËTzycÂ)KëoF¹V—µ÷—O‡·[è†|Zý“¬d×á»Ò¯t_øWLð—‡õ-WTÕ¦»–Ø^ßYÆûEó4’Èe`ˆ…UQÏÊ«XZßìQ«øgVÕN¥âÏØøwGÓ´íJoH÷ÇOu¿ŒIiF¶Æé¤tÜvˆ>PŒX¨®çÁ-ÿhý/_еmCM hz ³Ù]xÚÇ÷²Üé°ý–;‹k»ÈŒr<Åáe'lƒker]ûD~Óž—Ǿ#ð”šx›ÀÓéZžÇIÖÖí¯tËA’Úñ •%Œ.",a+*êWƒ^-,Ng‹ ®ÚJÿ ÓÜ»»wæÖv¿ºì´vg¨è`%OÛÊÉY2÷ìì´VåÑ9}­[Oc‚?±F¹¦C⛽oÄÞðîáI¬}Nö{©-¯¢¾ŽIm'¶[Ë$±ÈˆÂnÁeP®Sªðßì{¥ø‚ïÅñø—\ð׃äðÿ4ßXËe&¡-œßh6¡f¸ÌËÊM™0¸’EØ»må>&~×/ñÀ¾,ðúø~:Ã]ŸF]5#»Þ4›=2Þkx 9@ffIi _™IÛ†oÛþضWþ-Ô.5o ]]hzׂ,¼¨YZêëorém°[ˆ§h$TböÈÛZ'b¹<5tN¼âÛÑékrÿ,ëk¹s­tÑ[M^4å–B¤Vë­ù·çjÝùT,Ö—}u÷WG¬þÆz'Œ<ðšx¯Ášˆ¼ciwBê}K>'»]JæÞ&„}Ä +Ȱª™Åº’yäHW˜ðwì#âx{Bº'ð^›©x“O¾Ôôýöæê;É¡³’d¹,ÂÜÁO"Fùå]À|¤@­iûWYè¾7øG©iÞ¹ŽÃá5Á’ÚÚçUY¦Ô#þÑ–õUåX# Œ°B ]ÛFv 7öÖþÏñ„¯ÿáßÿ¾…­è»?´qöŸí½o7>WËåý¯îàîòú®î"PÎ! *Wm¹µ~Wmj8-ö»O²m.UµFYdæ½­’JšÓ›_T{oÎÓêõ|Ï|Æý‹µv¿‚hüSá ¼1?‡ßħĨ×ßÙÑY¥É´bÑ›aw¼\ÁnNY[î凛üCðl>ñDšu¾»¢x’ÝbŠhõ &I^Öu’5pš‘Ȭ»¶²º+++8¯UðGíyiá½+Á–·GŠìçðf…s£Ûj^ñ[躈y¯¤º2¤¢ ©I&‘÷¸2ž+‡ý¢~47Çߊ7>#k , ¶Öö¸žëíwwR!5ÌûSθp›žM‹¹‰;EzX)fYqÄ/qsYû½%î¶–·q³{%·-Î,BÁ}_š“÷ýÝ=î±2WÒÊ\Ûݽ5ïýW‚ßÿÊP4Ÿû%·¿úv´¯z¯¿ÿ” i?öKoôíi_È'ô±ïTQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQðÇü‹Zwý{Gÿ  +üæÿƒ‚†O‚?ìTñþü1_£>ÿ‘kNÿ¯hÿô_ðp"î“Áþ¥?éßÃïð·ü°ÿâGƒÅò*¯þ~ÿÁW?ä7ðSþÉãêG®ÑRÁWWn»ðTÕÿ‘kNÿ¯hÿô_ð_åÝqàÿRŸˆ?ôïáŠýðÇü‹Zwý{Gÿ  +üîÿ‚û®ë¿اâý;øb½þÿ‘¶üHðx£þEUÿÂ~ÁX×oˆ~ ú§ÿ©¹E;þ +Ô1âo‚ÿöOÿR-rŠõ³÷úÿã—þ”Ï')ÿq£þÿé(ýjð‚göðáÿªcÿ¨”uñ }ÅàÕÏì+áÃßþ}þ¢q×õû_à¥ÿ·Ÿ”gÿÄ—ý|©ÿ¶…Q_¡Ÿ<QE>ÚÙï.c†%/$¬ubN¯£¥ý›¾ißàø7uâÏøM^é4I¼L—  YÎѱ6þs@²‘ “í*Ýdòÿå™ù¾7hœ2’¬§ Ž5ïƒöÊЦø—oñ&ãÀo?ÅKp·Ú_Û*º,·è6­óéÿgÞeá\¨¹™Fí›I޼|Ö©[ê÷jÒøZO›NG«WKÞºÕ]«Å­½¾Tý­“¼mÌ›V»æVI»¿vÎÚ%+4ìTÿ†XÐl?fÝ?ÅÚ—‹ôÍ#ÄMâMCF¸Ó/ñ–³GEäÚ¸–‘‰g•cÚñüÊÁÀÚý«?c‹/|Rø›ÿ^·á‹‹]5ÄþµžömGK²iã…¤–&L4±nT¸‘×ÌW Âhô»Ÿ‚2xCĺ««ÜZkw Ó5-b;#ÌðÇ‚xÞÞ_:<ÃaZ6ûÃw#Þ"ý¯[]ø™ñwĉ }þ)ÙÉj°}»öQ{»{û¼±æãÈÛŒ&wg¶ž¨æ‹§vÒæëWyS²K{(óïªèõ×ÐurçK•$®ãüÜÉ^¥Û{^Î]>©ÛLÿ~Țσt}`Íâ ]kþŽ µß[Ïqý£¢Ç+ÇiKB°>É%‰ašFFn?í ðoÙÏÆÔ|Oák]°¸’ÚþÏI{©NžÉŒo’H#‰·È»•Á†ÚôÏ‹ðPKã„õˆu)>#6«®Çº·\IáȤY"y7ÉCymˆÞw „ªáQWÉ?h‹ð½~5øŸÆ?`þËÿ„P’û잟ö}ç;wí]ØõÚ>•Ó—K4•Hýmr¯zöåzÚK¯-Üí×Ewߟ²øÓ—ÕŸ3Ò׺ÓÞ»}9¾-]—oGðoìßáï‰ß¼s¢Ã­[xëÆÞ/“‹=ö¯öLN«nÂS +Zùª\ª‘æ6ß,·Í¸*àx“öPŸÃÚ+êQxÓÁšÆŸ§kvú·6œ×Î4æ2mi·Û'›îeùí¼àvqË»oáoík¡|0ðÃÍ2/j×z§€üZÉöcr|­»>}ßhûÙ\lèsÄRŽe²jê<ú]ÅÝ9¤ú»% ´´ÕmÑ’– Њ•¹¹É«>Yµ}o›‘7ª³zõ^»ûMþÉÚŸñCÄúW†õ‡ÞðŸÃ©ÇT×%¸Öæ•§‘ü¸b»WŠC%Óùr>, òToËaF<âÇÂÝOàßît-TÛK4QÅqͬ†KkëyQd†â ŽHÙYIàà€AÓ¼Kû^iügñ*_øFêóÃ_5Xu©,,u…µ¾Ó.¡i<¦ŠéíäB6M20hàùHÍyçÇ‹/ñ›Ç­«.Ÿ‘amim¦i¶Éæ‹+;hV#2 Œç nbN É©æ4¹)b®ÒŠ»m=ybÞ·m¾g5ü¼©[]ôÍ'¨ç<=“»²I­.ÒÑ«[‘E¿µÌßM¿£šð[ÿùJ“ÿd¶÷ÿNÖ•ïUà·ÿò” 'þÉmïþ­+ù$þ=êŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š(  +>ÿ‘kNÿ¯hÿô_ž?ð^õÝàqÿRŸˆ?ôïáŠýðÇü‹Zwý{Gÿ  +üóÿ‚õŒê>ÿ±OÄúvðÅ{ü-ÿ#l?ø‘àñGüŠkÿ…Ÿ…?ðW!·Å_ÇýSÃÿ©¹E/ü×þFσöOþ¤ZåëgïõÿÇ/ý)žNQþãGüÿÒQúÛàÈóû øtÿÕ±ÿÔN:øf¾ô𠯙ûøu±Óàuþ¢q×Áuúÿ¿r_à¥ÿ·Ÿ•ñ mR_õò§þÚQE~ˆ|ØQEQEQEQEQEQEý4W‚ßÿÊP4Ÿû%·¿úv´¯z¯¿ÿ” i?öKoôíi_ÄçõaïTQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQðÇü‹Zwý{Gÿ  +üôÿ‚ô ê~õ)ø‡ÿNޯп ȵ§×´ú¯Ïoø/ Ϋàû¼Cÿ§o W¿Âßò6Ãÿ‰Ȧ¿øYøQÿx]¾.ø0?êžýHµÊ)ßðWÁüÿ²võ!×(¯_7_íõÿÇ/ý)žVQþãGüü‘úÿðôãöð÷ýëýE#¯+ïïG³þ õáÖÿªeÿ¨¤uð ~»ÀÿÁKÿo?.â5i¿úùSÿm +(¢¿E>`ê>ü6ÿ…Éñ‹ÂÞûoöwü$º­¶™ö¯'Îû7"¦ý›—v7g†qÔV߀þ·Žâ*¦©ä?€´É5fÝý Vò o/ï/>vìüØÛŒs‘Ï|!ø‰?Â/оñU´ u?†õKmM vÚ³eY6ƒ€vã8ã5ëGãÃïiž;ÿ„2ojz¿ÄqžÑk:mµœ-«^Gu(Eq)º˜cŒ#›Â'SÊ4oi$••ìù•咽ï~ÚkcÐÂGé¹V·ºÓÕÚñ³º]Ýíç¯kœoÄÏÙÇÿt½Vë^Ò,-ÿ°eHµK{}fÆòóLÞÛQç·†gš(Øí # FÞ˜c½sÔøGö.Õ-~øï_ñräOáß &µaaµbu$—ÉÚlƒµÔQ´S3eã’Ÿ7 7£þØÿ¼%ðãçÇt[k>.ñ•ãéq^éñYiºT?jŠâVGK‰$¹rÐF‹¹! +Ø‚pµÎø¿öœøs­]|Zñ-¹ñ³x—⾑öitÉtëe±Òn$¹¶¸˜-×ÚZI£Ý „>Dd¹SÛÄ¡™fXœ-:Š6çåwQ—^Gk6ÚZÏÞzZ;j›öjeø +©S”¯Ë+YÉlœ•Û²ì½ÍõßF—‘êÿ³_‹4Üø™bÐ5-Â8¦¼}+ÄZv§5Œr¨óÃm<’Â¥Š©2"€Ìà+«ø½ûø›á¿‰¼3¥é—š?Š.¼Qe§ÜZÛXj–2Þù×VÂsÙ£¸’_)2ÃíDLl€Ew>6ýªþ7Â/h^Ó/´´ñVm§iÚT~ Ò­Žcºµ–]U&{Ûш\o”)f!ŠSÓ?k h?| ãÛdñ Úî‘áëo kLÚU«YˆN{ . æJûJºÅ5¶Âr¬JõÝc³Y'QSµ¹¬¹^¾êqO]=ë§$Ü|ÚÕó¬&\—,§{¥wu§¼®Öšû­µ”¶Ooø™ðOÄ_ Ó§Ö ÓžËWY Új¶w2ˆ³ÚÉ$[Ô•Ü›·(e$Àχ_´­Oá•Ï|_â¿xd_"Ëû?K–¡©]„Yc…æ‚1q²—v”`ºW,vìþÒ´ˆ~ Ðt]V½ÔíôëÛ«ÙUü£øVÚ• @R=¤2;¾g‘ú,`/šÿþ*xGÄ›áÿŽá!Ó­´ÍV]oEÖ4[8¯æ¶–háŠâÞ[if…^'XQƒ,ªÈéÈpØ^õ_,$g5iskÊùoºŒ•ïmÓOK´›²9$q<±wží[›•Ù7k7mš¶Í«6gÃû>Ÿˆ!¾_‡Ú ñ¦ÙCyyªëBßñi¦FØ"¹{‰Í¼r8P³¸pFÓʵtïÙ‡ÆúuíèðÙ_xaVMV]CQµ±²°F*#wºšD· !eòÛÌÄBÀŠë¼;ñ'á¦àxÝxê? øôÝB-piÖ²_­í§œuÚR1 ¥ÄŠí,Êѫ峱wüSûQø7↟⿠+ëø£Dðõ¾‰o£ê6v‘jŒcIí¢7=Ä1·²3m—÷l àn¬%ŒÇÆN0…â­fâïgÉy;5v¯?q%/wÍ_háprŠu%gÕ'¥×5£­÷´}û¸¦ÚÕ-1~0þÆZ—†~&G xgì÷pYxoJÖu[ýC[°‡N³–êÞ'aöÖxí|¶•ÊÅûück?ZòoxWø_âÛÍ]²k NÅ€–"ë"Ê] I”«+¡*ÊÁ”A¯¦o¿n?\jZÖi¯gáOFÐ,¡Ô5 iZõÔ3év¦ß/avæÝÒ@òË*:¤7!ðÚ3â]·Å‰òê–w·º…œvV–POu¤Ùi2:ÃoX¶cÈ…R¨Š[&Œ§˜Ê¢§ŠŠQåÞÏ™»G_åZ¹.[ói}ƒ0¡TùèIói¥ÓKºîûó%Ë}7?¢êð[ÿùJ“ÿd¶÷ÿNÖ•ïUà·ÿò” 'þÉmïþ­+ù$þ=êŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š(  +>ÿ‘kNÿ¯hÿô_Ÿð^_Àÿö)x‡ÿNޯРȵ§×´ú¯ÏŸø.èγàoû¼Cÿ§o W¿Â¿ò7Ãÿ‰Ȧ¿øYøQÿñ—ÁŸû'gÿRrŠ_ø,Ç~ ÿÙ;?úë”Wµ›ÿ¿×ÿ¿ô¦y9Gû…ðGÿIGëÿƒeÛÿüðàÿªeÿ¨¤uð}éà×Ïì áÁÿT>ËÿQHëàºýk€¹?ðRÿÛÏËxÞ¤¿ëåOý´(¢Šýù ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(úh¯¿ÿ” i?öKoôíi^õ^ ÿ)@Òì–ÞÿéÚÒ¿‰ÏêÃÞ¨¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š£áù´ïúöÿ@ùõÿÙ]Ú߇ýJ^!ÿÓ·†+ôÃò-ißõíþ€+ó÷þ §íïg§ü"^!ÿÓ·†+ßáoùaÿÄŠ?äS_ü,ü(ÿ‚ÃFGþ Ù;?úë”S¿à±O|ÿ²wÿ»¹E{9½þ¿_ürÿÒ™äåî?Áý%­þ ñ€þ?õCìõ޾ ¯½<¿ñ€~?õC¬õ޾ ¯×8øsÿ/ý¼ü³ˆ‰/úùSÿm +(¢¿D>l(¢Š(¢Š(¢Š(¢Š(¢Š(¢Šþš+Áoÿå(Oý’Ûßý;ZW½W‚ßÿÊP4Ÿû%·¿úv´¯âsú°÷ª(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€(øcþE­;þ½£ÿÐ~~Áuù×< ÿb—ˆôíáŠýðÇü‹Zwý{Gÿ  +üüÿ‚ês¯xþÅ/ÿéÛÃô+ÿ#|?ø‘àqGüŠkÿ…Ÿ…?ðXŸù> Ù;?úë”RÿÁch(¢Š(¢Š(¢Š(¢Š(¢Š(¢Šþš+Áoÿå(Oý’Ûßý;ZW½W‚ßÿÊP4Ÿû%·¿úv´¯âsú°÷ª(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€(øcþE­;þ½£ÿÐ~~ÿÁu?ä=àoû¼Cÿ§o Wè†?äZÓ¿ëÚ?ýWçïüOþCÞÿ±KÄ?úvðÅ} +ÿÈßþ$xSÿ"šÿágáOü7þG¿ƒ_öNÿ÷a×(£þ ÿ#ßÁ¯û'û°ë”W³œ¿×ÿ¿ô¦y9?û…ðGÿIGëß‚þ5ùáÏû!ö?úŠG_Wè‚GükçÞßì¿õŽ¿?ëõ®ø'þ +_ûyùo_õò§þÚQE~Š|ÐQEQEQEQEQEQEý4W‚ßÿÊP4Ÿû%·¿úv´¯z¯¿ÿ” i?öKoôíi_ÄçõaïTQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQðÇü‹Zwý{Gÿ  +üþÿ‚éÿÈ{Àßö)x‡ÿNޯРȵ§×´ú¯Ïïø.Ÿü‡¼ ÿb—ˆôíáŠúÿ‘¾üHùþ*ÿ‘N#ü,ü(ÿ‚ÆÿÈ÷ðkþÉßþì:åÁcä{ø5ÿdïÿvrŠös÷úÿã—þ”Ï+'ÿp¡þÿé(ý~ð;cþ ùáßû!ö?úŠG_Ÿõ÷ç‚ ÿ‡øpÕ±ÿÔR:ø¿Zà‚à¥ÿ·Ÿ–ññ%ÿ_*í¡EWè§ÍQ@Q@Q@Q@Q@Q@ÓEx-ÿü¥Iÿ²[{ÿ§kJ÷ªð[ÿùJ“ÿd¶÷ÿNÖ•üNVõEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP ȵ§×´ú¯Ïïø.—ü‡¼ ÿb—ˆôíáŠýðÇü‹Zwý{Gÿ  +üþÿ‚éÿÈ{Àßö)x‡ÿNÞ¯ á_ùáÿÄŠ¿äSˆÿ ? +?౿ò=üÿ²wÿ»¹EðXßùþ Ù;ÿ݇\¢½œãýþ¿øåÿ¥3ÉÉÿÜ(‚?úJ?^¼?ã_þÿ²cÿ¨¤uð}ýàùGç‡?ì‡Øÿê)|_­ðÁ?ðRÿÛÏËx‹ø’ÿ¯•?öТŠ+ôC悊( Š( Š( Š( Š( Š( 颼ÿþR¤ÿÙ-½ÿÓµ¥{Õx-ÿü¥Iÿ²[{ÿ§kJþ'?«z¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(†?äZÓ¿ëÚ?ýWç÷üOþCÞÿ±KÄ?úvðÅ~€øcþE­;þ½£ÿÐ~Átÿä=àoû¼Cÿ§o WÐp¯üðÿâGÏñWüŠqágáGü7þG¿ƒ_öNÿ÷a×(£þ ÿ#ßÁ¯û'û°ë”W³œ¿×ÿ¿ô¦yY?û…ðGÿIGëç‚?åžÿ²cÿ¨¤uð ~€ø?ø×߇§ÀûýE#¯Ïêýk€> ÿ‚—þÞ~]ÄÄ—ý|©ÿ¶…Q_¢Ÿ2QEQEQEQEQEQEMà·ÿò” 'þÉmïþ­+Þ«Áoÿå(Oý’Ûßý;ZWñ9ýX{ÕQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@|1ÿ"Öÿ^Ñÿè¿?ຟòð7ýŠ^!ÿÓ·†+ô Ãò-ißõíþ€+ó÷þ ©ÿ!ߨ¥âý;xb¾ƒ…äo‡ÿ>Š¿äSˆÿ ? +౿ò=üÿ²wÿ»¹EðXßùþ Ù;ÿ݇\¢½œãýþ¿øåÿ¥3ÊÉÿÜ(‚?úJ?_¼.?àŸž_ú¡ö_úŠG_Ÿõ÷ß‚N?àŸþÿ²cÿ¨¤uð%~·À ÜŸø)íçå¼DïR_õò§þÚQE~ˆ|ÐQEQEQEQEQEQEý4Wšê?õ?k ˆÐÜÙ=­§„¤ðÚÙ9e’G–ñ.RÁHDH `–.ßwhÝéTWñ9ýXQûF¥ÿ>–?øÿün´j_óécÿoÿÆêõGí—üúXÿà[ÿñº>ѩϥþ¿ÿ«ÔP´j_óécÿoÿÆèûF¥ÿ>–?øÿün¯Q@~ѩϥþ¿ÿ£í—üúXÿà[ÿñº½EQûF¥ÿ>–?øÿün´j_óécÿoÿÆêõGí—üúXÿà[ÿñº>ѩϥþ¿ÿ«ÔP´j_óécÿoÿÆèûF¥ÿ>–?øÿün¯Q@~ѩϥþ¿ÿ£í—üúXÿà[ÿñº½EQûF¥ÿ>–?øÿün´j_óécÿoÿÆêõGí—üúXÿà[ÿñº>ѩϥþ¿ÿ«ÔP´j_óécÿoÿÆèûF¥ÿ>–?øÿün¯Q@~ѩϥþ¿ÿ£í—üúXÿà[ÿñº½EQûF¥ÿ>–?øÿün´j_óécÿoÿÆêõGí—üúXÿà[ÿñº>ѩϥþ¿ÿ«ÔP´j_óécÿoÿÆèûF¥ÿ>–?øÿün¯Q@~ѩϥþ¿ÿ£í—üúXÿà[ÿñº½EQûF¥ÿ>–?øÿün´j_óécÿoÿÆêõGí—üúXÿà[ÿñº>ѩϥþ¿ÿ«ÔP´j_óécÿoÿÆèûF¥ÿ>–?øÿün¯Q@~ѩϥþ¿ÿ£í—üúXÿà[ÿñº½EQûF¥ÿ>–?øÿün´j_óécÿoÿÆêõGí—üúXÿà[ÿñº>ѩϥþ¿ÿ«ÔP´j_óécÿoÿÆèûF¥ÿ>–?øÿün¯Q@~ѩϥþ¿ÿ£í—üúXÿà[ÿñº½EQûF¥ÿ>–?øÿün´j_óécÿoÿÆêõGí—üúXÿà[ÿñº>ѩϥþ¿ÿ«ÔP´j_óécÿoÿÆèûF¥ÿ>–?øÿün¯Q@~ѩϥþ¿ÿ£í—üúXÿà[ÿñº½EQûF¥ÿ>–?øÿün´j_óécÿoÿÆêõGí—üúXÿà[ÿñº>ѩϥþ¿ÿ«ÔP´j_óécÿoÿÆèûF¥ÿ>–?øÿün¯Q@~ѩϥþ¿ÿ£í—üúXÿà[ÿñº½EVÑìÛOÒ-mÜ©x!HدBB€q_Ÿð]SsÀßö)x‡ÿNÞ¯Ñ +üïÿ‚êÿÈsÀßö)x‡ÿNÞ¯ á_ùáÿÄŸâ¯ùb?ÂÏŸø,aÏŽ¾ Ù;ÿ݇\¢“þ ÿ#ÏÁ¯û'û°ë”W­œ¿øP¯þ9éLñò‡þÁCüÿÒQúïࣟØßöCìõ޾¯½¼ã|;ÿd>ÇÿQHëàšý{€‡/ðRÿÛÏ˸þò_õò§þÚQE~ˆ|àQEQEQEQEQEQEý4QEüNVfxÃÆš?ÃÏ\ëþ­¦hzEžß´_jImmæ»ärr̪2y,SZuòGü"8$øàSsSEŒ’b² eÊiZ“)Áã €G¸ìpþYÇ1¥‚œ¹TÝ›Z¾ú}ÇiŒxL%LDUÜUì{wü6gÁÿú*ß ð§²ÿã´Ãf|ÿ¢­ð×ÿ +{/þ;_Žw_’1‘mh¾Ÿ¹\*áu¿ÚëÁÚ?Œ‡‡î|Iá[_I,p.›.¡oÑ’@¦4–¹·.ÑŒÃE~×?pIÔÄJ)»+ò­{kÔüÖ"b§u +)Û].ÏÜoølσÿôU¾ÿáOeÿÇhÿ†Ìø?ÿE[á¯þö_üv¿¿ágÎ Ä1ãÝE/Ä›© +ˆ=Wbð.üÿ—Ý/ø‰u¿çÔ~ö~×Ãf|ÿ¢­ð×ÿ +{/þ;Iÿ Ÿð{v?ál|4ϧü$ö_üv¿ßâÑ^ýÑþ})°øöá$ÜÌÌ=)¯ðÿóþ_rüDºÿóê?{?lÿá³>ÿÑVøkÿ…=—ÿ£þ3àÿýo†¿øSÙñÚüU?¦Æ6'öо"NNxÿ¾E/ø”?çü¾ä?ø‰u¿çÔ~ö~ÖÿÃfü?óUþñÿS=—ÿ¥ÿ†Ìø?ÿE[á¯þö_üv¿-þ#Í쪾ïï(8¤—âMõQí˜4Ä ¡ÿ?å÷ ÿˆ—[þ}Gïgígü6gÁÿú*ß ð§²ÿã´Óûh|Sƒñcá ?ö3ØÿñÚüOoˆ7L¸ÈðPMã{ɉYO·Qð+÷ÄKîB~&WÿŸQûÙûoÿ ¥ðsþŠÏÃ?ü*,øíðÚ_?è¬ü3ÿ¢ÇÿŽ×âñEÑÏï4ÖñeÊ.ß5¸üÿ:Õx…ÿ ™}Èø‰¸Ž”c÷³öý¿moƒI÷¾-ü2_XÿñÚî¼ãmâ/†íµŸjúf»£Þîû=öuÕ´ûX£l‘ VÃ+)Áà©E?ž"•ó•BX“Ó¥~šÿÁäóeÏžüW×' Î™¦“úšù;ð²†A•ÿhS¯)>e4­­ûEÃÿÑVøkÿ…=—ÿ¯–?à³rÛÙøÃá…ÔðC9³Ó5é" }®dÒ—#=ŒŽÄ×Â÷ qoh_õ)å_²pŸ†sŒ²–=Õ’sæÑ%ei8üö¿Ìüó?ãZ¹~6xXÓMFÚ¶ú¤ÿSö?þ3àÿýo†¿øSÙñÚ?á³>ÿÑVøkÿ…=—ÿ¯Ã{_ÚçÁúÏŒ_ÃÖ>%ðµÖ¾²Éi°ê6ò]¬‘†2'’~å +Û†2»NzVÿü,ùÀ#Éþøô”<ÂVNT±2i;iÊõí§SÈ©â6&›JtR¾ºÜý©ÿ†Ìø?ÿE[á¯þö_üvølσÿôU¾ÿáOeÿÇkñAþ#ÝHÝG AÅ1þ Ý2€¿Ê+¡xC­y}ÈËþ"]ùõ½Ÿ¶#öÏøÿÑVøkÿ…=—ÿ¤¶oÁóÿ5_á¯þö_üv¿Ä9óÿØŠ|f†"¥Éç, šOÀÊóþ_rø‰u¿çÔ~ö~ÕÿÃf|ÿ¢­ð×ÿ +{/þ;Gü6gÁÿú*ß ð§²ÿãµø¥7Ä‹—'hEé°TOñé׆þ)¯èu¯/¹ þ"]ùõ½Ÿ¶öÑø:ü•Ÿ†ŸøSØÿñÚ?á´¾ÑYøgÿ…Eÿ¯Ä{ÞL8•‡¯¡ªçÄ÷DcÌjÖ>ažø™}È—âm~”c÷³÷þKàçýŸ†øTXÿñÚkþÚÿ“ï|[øb>¾)±ûV¿ßÅ·!@ó ÇÇ_­gÝëòž +¡>¸«€ØG¾&_râf%ÿˈýìþ…4]jÏÄš5¦£§]Û_é÷ð¥Í­Õ´«,71:†IÔÊÊA г_/ÁŽàœ>¢ÝkJ=€Öo†+êþxÍð+¯ƒNêœå÷å“WùØýcˆuðôëµnh§÷«…Q^qÒQEçÚÏígð¯ÃšÍÞ¨|Lø}a¨ió=µÕ­Çˆ¬âšÚT%^7Fe ‚Íz ~è~+¶ðǃ4+Xm- .ÚW"Ë3F®ÇÜ’I'Ôšý €ø.—:ê¥GgËk%¯77~Ü¿‘ò|SÄu2¥M +\÷Ýö·ùŸ²?ðÙŸÿè«|5ÿžËÿŽÑÿ ™ðþŠ·Ã_ü)ì¿øí~3_|SVãȃû‘¨5BOгe`Œ{lWéPð:Œ¿åôþèŸüJ¬¿åÔ~ö~ÔÃf|ÿ¢­ð×ÿ +{/þ;Gü6gÁÿú*ß ð§²ÿãµø§7ÄÛ—S¶8”ö;Gÿ ä¶N?ïWÿ.‡Zòû¿â%ÖÿŸQûÙû^ß¶wÁåüWøj>¾'²ÿã´Û7àùòUþÿáOeÿÇkñ-¼{tíË3ØU˜¾#Ë +±[·#&›ð.…´¯/¹ x—_þ}Gïgígü6gÁÿú*ß ð§²ÿã´ŸðÙ¿ÇüÕ†¼ÿÔÏeÿÇkñNOˆÓ¿@þ)£âáÔõÚz``ýiÄ ¡ÿ?å÷!ÿÄK¯ÿ>£÷³ö¿þ3àÿýo†¿øSÙñÚ?á³>ÿÑVøkÿ…=—ÿ¯Åi~&ÌùÛ`žŸ â ?.™¹Ûø /(u¯/¹üDºßóê?{?kÛöÎø<£ŸŠÿ G×Äö_üv“þKàçýŸ†øTXÿñÚüL“Ç—oüdgÐbªÉâËÉ&V?^kHø†{â%÷"_‰µ×ü¹ÞÏÛßøm/ƒŸôV~ÿáQcÿÇií§ðqG?~ûš,øí~ ÂUsnó}ù•Wºñ<ò›Ö‹Àl+ÿ˜™}ÈŸø‰¸Ÿùñ½Ÿ¼_h‡ÿõ©tß +xçÁÞ'Ômá72Úé:ÕµìÑÄTÈɳ Ê2F2ÀwØ×âoüPkßø)Â2À ]jª1×F¿8?¯Û*üøNŸfQÀҨ朮Ò[¹+iè~ƒÃ9ÔóL#ÄÔŠ‹RjË]’ÿ0¯Îÿø.¯ü‡| ïá/ÿéÛÃú!_ßð]n5ßÿØ¥âý;xb¼Žÿ‘¾üH|Uÿ"ŒGøYøUÿ‹ñ×Á¯û'û°ë”QÿŒ9ñ×Á¯û'û°ë”W­œÿÈ¿øåÿ¥3ÇÊ?Üh‚?úJ?\|ßñõÿ…cÿ¨œuðe}áà–ÿŒ ðç·ÀûýE#¯ƒëõþø%þ +_ûyùnüIÿ×ÊŸûhQEúó¡EPEPEPEPEPEPôÑEWñ9ýXñÿüŽcoû:xIÇQâ¿ýÄjuö|yÿ« ~ÍÞÎ1ÿ _ûêuõü¯ÄUýïÑž;eUß÷OÉø“\Õ|i¦xcÃ:n•©kºÖ¦SÔd°´ŽÚÚKhäýäpÎæM÷pí_/i_0—Rª{Dýž|Jß±7Œ>ßI¡ÛøŸÅ6ž#E0]K5…¼ºÍìÑ)•¢IP\ fòù[ +xÏ=â +Ï©ëöÆ—®jþÖôûyìãÔ4Ôµ’Sm3DòÂRæ¢ÚÏ »fðb0 á³m¿kSá¯ÙcÅÚn£ñ H“ã¿k£ØÞÏc·yp—7k¥âÅQ’KµhÕaÄÂD!X8ÏçŸMŒ¯ªãp³Nʽµ/a¯8Ööræs´oˤž­«5mooârì÷O +òç SU©Z)MÔU?,åh¸û$îÕÑ_ÄŸõï†?<'áèZE†¥ãß¶¶Œú­&¥‹8DÓý ÍolÑü¬6,›‰lìÀ-ÙW3qð°k;ÑüCâxƒÆšç…¾Ðº%Ö©öK쯴Gå\lK;{u“Ì@ ùÂM»]¤¶zjþÒðcýs\;Npá,JÚTíiAÝÇkm-RwN÷Üý=áëQÃR†6¤'‰÷½«¦¤©ósË——ž1—ÃkékÞÚzìÇðÔüOø­ ³è‡Š-4ËKRëJ²YZkô†&e„y_¼dž\d¯#~AkÏ«kBñÅχ¼#®é[Ù˜üB°EqpêÆtŽ)<ß-í¡YÖ6l©?º\ÎNÇÓ«S*t¥-/Úú7£Né]­V«qaåÕŒªj–­w¶¶ùí~—¹î¾ý‹ Ó¿iˆt¯Þ隆›ÅPévv:»^Cy¬Äþ\ÞDb(™‘ÄB¥h€iTn8å¬?gK/|)ñ–¯¬êšÚÕ§‡íu[9n¾ß§$÷Ö©òb1 ¤ìóY€™ @yX¼ûgë~Òü1osá¯ëÒx5£—H¹Ô¡ºi­%B@—1N›`‰0À¦Ûx¾]À±ÈÕ?i½KXø}¨hsèkÝWM·Ñîõ±ÇöŒö¶òÇ$1Ÿßy?/“n*Š $f¾V–<ö‰U“²tÓi«5;´ž©J?ýæì—º™ïºùc\Ê:¾gfžôÓM6’Z]£Rëöd´Ô|×ôè´ròÒ ¸/á¶âŽæâ;…V :‡U|27*žyñ^Á¤þÝ%е›íRÏ@ð…®­©ê_Ú7w±ZÏݶ­è‚TY„r •p¯"4ʧjÊñý{SZÖîï"²µÓbº™¥[[f‘¡·çbܨè73RzÖ™%<Ö5fóud£k[KßÎú¥vÝìÛ¶˜Ï饅Zß[ßoËåm­n¶©Q´9$ç­IE}"gràÛ Õú‰ÿ +MŸ²çFsÿíÇþšôÊü»¾š¿Q¿àßòkÞ>ÿ±öãÿMze~Kãoü“Ÿöü?Sô/ü*Ûô>䢊+ùýÈ(¢Š(¢Šüýÿ‚ä\}šÿáÁçLÖÇ?õñ¤WÀßþ üAý©üyâ|:±ðuÍï„l,5UüG®\éqyw²^Gn 0YÝ67÷ˆÂƒÒû›gÞŸð]& yðÛ8ÿv·×þ»é5ùéàÏøÇá/Šu=kÀ^9×ü¨ë¶–ÖZ¬º]ž›wý£³ÎöÊë}kr©åµÕÉ …¼ã¼¶ÔÛûål/Wð³“Ú”©æ—ýÜ«YÂÊ¿¾ã%wO™+­í¶ç㹬ò¥ÅRþÚMв½¯{ò+lÓß±÷WÄÿØsÆþ!ÿ‚Jxà~•uáIüsáÁÖRKy{q‘u>w¦Ï8­¼’¬r )7O̹QÎ>ø£¤x—özý¥bøIãÝ?D¶ñdžÆIáýN]KLþÏk¶´PÓMom(ŸÍGÊJÚ|ÂIUú‹Ç?ðSØüCÿÆðBøkã_„ö‘Õt¯ C­iúmö“sâ;;Ù®´äÖ·in’,rà ß4¨Öø€G#AÛòçŠ#Ô¾$üX?ñ§ˆ5xí4qáØõÍJ;KibÓDæámD6P[Û•3¾öˆË— ¹Pª?„?göUâ¾ 4Çûe¯ësúÔ%®«Q^ÒŸ4SövO—–Wm;Çcô¥ÔÂAâÛöÜÙ5{z;]okߦÌöÙ á~ñ[Wñm†¹f·R E¥È׳¾¸¼¶µ‚cµ”0Wœ­•#<+¨ñw쯦7ÁImökp[ß^ø³WÔî. ´ùvSÛ†HÖF%ô…Š2Ìòsœdx·ƒ>"êÓµË{ +ÿoZGg4¬Ì…Ræ…hÈ# ¾ä‚0OÁ¬?µ×‰ïÚkvº7‰ Õ.o®u85dXõ3t-·¬žD‘”TkH<£FN»~ZÿWñø Õã#SܽùoÚº'îêÛvzs(·u·àX,V +4=x{Û^ÝÚo]·G.¶:„_±áoŒZŸ‹u¿ [hWZí¦Ÿ’âï%Iȵ0ÂYU žº_'zU·ØñWì—¥éß´ÅÓ®|2|[¯<×ÑCw{¨Kz°C¦ZÞýž°Gldq31YÞ‰#2»WáÿÛ?\ÑüI§uáÏë2iú„Z– í½È‹A’(cÜE:‚(`]²™3䣶X¯‡¿jYµïø&óÄû´ý3Á—ñj1>f%º™¡¶´c"Y‚aÖÊ [øKÈÛ\a+Ï­†Ï¥YVœÚQÚ‹VrJM%«MÛšú¶¬½Ó®|²qQ»m­{7mÞ‹O…ôÝêŽ9~Ùx#âW†´ï_,:^ ¶Ú›Xîyìm.JA?Öˆ68€ä‚µêÚ÷칪|añ=ŽáxkB‰RöèêþÖ/5ý2òÖ&‰T”‰®îêÒ dPÆZÀ,|wVø£y­|W¹ñuÍž—syu¨6 ö—©5‘Üå¼£¦0>P½€Æu–ßµ5æ™m›§øWÂzw…šˆo<=½{HÎa2<¯%Ë\îͽ±&P¦À}Þ®;šKÙÔ ýõu÷S³½£ÍÝþe(¾¼¶»âÃTÁFS…MaugmZO¥ÓµÕÛ·+ZZûõçüÿIJéš^œ!ñ4WÚ”ú…ïÙ¯åCa¶$-Ҹ宱´[ù É‡Q°íã¼GûëÞÖ®¬¼Q®øgÂxºŽÎÂ]a®í“V‘âI€Œ}œ¼JXK5ʨeŠÁj[þÖ­­¡ÓÓÞÃÒ”ŸEŠÖhl®aš;T0¹IVRÙÁ"È$™³ÈåŽ`µý¥åe‚çÁ~¿Ób»[í3OžÆuµÑ¦$E¢T™L¡Ö(·‹“0ÆÃŸðÔ¸‚ +Õfš³½’½Ü¯£ri>Ž:ÅGá|ÇEJ™T¾Ùß»¶Ýl“jýt–Únv×°^¥âŸ]i~Õíµ]?LÑ´»ûëÔ³Ô/Ö îíÒA[[7‘ƒ”XöïpüUO~ÈRø[ZÖ!ñÅî‡ag¥k“ZèSMt/ïÎÚà ˆÌQ˜„k‰}•+òêÔ¯ü÷¾‰ò[•ó\¨UÊ•HÏ—fž·µ“Õ5þµøïuÈy9ƒÞ©Î¹¸Ç¯¡ŒÕ ¿ãè}E}ÌYàSzŸ±ðFq·þ Çà1×z×þž¯«ê +ùþÓÿ(åðý}ëúz¾¯¨+øŠ¿äwŒÿ¯µ?ô¶Odÿî?Áý%Q^è…Q@;ß>![|9øgq¯ß$òYhŽþâ8i^8lÖF + ± +p '¨ë_Ñ ;ž4ðå‡|ý‹©Û­Ö›«èÙ]Ž“ÍŠKUG]ÊC ©# ‚;_Ф–=R·5¡kíÞZþW?.ñ)Á}WÚ|7•ý=Ûžk_ŸøA|3ÏýMSÿòA©þÚ"ðΛq©jÞ ÑbÒ´øšæõíãSñƤxÁZoØ58´Ÿ]h^%—RÔf»–ù!‚ ¸Môâ$"rZX¢Ã ì?$øSC²ð>‡¥ézU°´Ót[hlì ÞÒa…#MÌK6@É$œrkÒôŸÚ[ÄzÄ¿ø²Él-µoÌ×3•Ìv“}®+´–%,pÉ4HWyaŒ‚_Ñõð™½zjÎJ5cæ“’‹àÚ÷ef´’×™YÛ­ÏâÊuðTª×„W4­Òo—ßWwWëígæ¬w)ÿ‚{ø»Á[gWÐô"ÞÚK‰µ=BÓT³‚3ðBшå³YÝ·\ÄAH™ÚÄ©^ýŒu¯ j¥ç‰¼!†œ÷ÐêÚˆšé­tym–9qo½Ø½Ì +¾JH¤<61uÏÚB{ý/V²Ó|%àßÛkp47‹§ZÜo•šæ ‚þd³I ù­ã7yJ íE,Z¯¿ís®ÞÞêfÿGðæ¥§ëwúþ£§\Ep-¯ ë[¼‘±I–ET{h] +:º²òÌ*)SÏÔbç4÷¾‘NÖV¶­s^ýyn•ì®mRyK“Q‹KKjß{öò¾]º0²ˆ¦× ±‡SðíÀ›U‹Mkˆîeò`Žk_µÃzäÆ +ÛIn@ØÞRE#ljbx_àÉñÄÑ$ºZYŨº%•ò•µ•Õc›Î{u¶`Ûãm‹1+åm}¹P~Õ&´Ô|a<iP§Œ´ÄÒ'-ÛÊÓíãŒCÛe²Œ„3b’>If-Yþ#øísâ¿E¥ßh¸Ô㲃L:ô–ò¾¤ö°•ò¢ù¤0¡UHÓÌH–Rˆ¹·tFç<9¥Æú&Þž÷Ue{¤ÕÞ‰Ùݘ©e––Žö—V–þí·é}úÚö=ïökÒ5ïƒÞ¸ÓuÏé×rèø“\ÔïTóâC¨Dˆ¢Âñ•Vd@"œ¼rÅ {²‡ìW­É©Éi‰ü,Ú|“[ë;n.@Ð&ŠÒ[¦Šà˜[Ë‚q˜|Õß) ã<€øï¬/ƒ† Ó–Ôhc@q(€joßøó<Þ3Œlãù«£Ôÿl zý/ :/†l.5u¸mbâÚ ÄšÔóYÍhnfÝ+*Èâv!{åf(܃ÃgT¹Õ)Þò¯gdÝã}/k6’[5ks +Ùtù=¬meÚë§½o>k;¾œÝlgüTýš¯þøYõwñ†µ»x¦³ŽTÓ^äÉ]۽Ŵ¬%†1¶H‘ˆÞ¼Uȯ@ñìa'nôSᄵÓ!ºÒa¾º–yî®ÕviºdÓ8·†ÞY²e¾ÎPÈ0Çä‰#,|¯Åÿ5øjóJº·Ó£·½:YvŠ7?³íÒä|ѹ/Ç-‚6Ž+¤‹ö¼Ö&J‡Pðï„õ{]"1][ܶ²·YXæIb‘VÆ £niv¶ÑU¨g\°”d¹—5öëÛM"Ú—2WÒÖ¹4ªåüÏš:;wß™ß]Z\¶îÌßÚ ànðwHðƒZxK×o5« î/~Á;Ü@’Gy<â“ÊDh˜D*ÎK#ž¡>auÈ5è?h WãÜÖ:冒š•‹\“}l³$× =Ä—$ #! $²m`¡ÈoœàןÞÜš÷²ˆâ£†ŒqŽó¼¯³ûNÛ%¥­m6ßS‹*¿û7ÁeߢIïÝÝžÕÿ·OøØ×ÂFÏü¾jƒÿ(·õûq_‰?ðKoùH¿ÂOúüÕ?ôË_¶Õü¹ãŸü”4ÿëÔô©Ÿ´øwÿ"¹þQ +üíÿ‚ìk~ÿ±KÄ?úvðÅ~‰WçoügþC~ÿ±KÄ?úvðÅ~uŸò7Ãÿ‰çÈ£þ~ÁbŽ|sðhÿÕ;ÿ݇\¢“þ ÿ#¿ÁŸû'gÿRrŠõsŸùWÿ¿ô¦xùGû…ðGÿIGë_‚%ÿŒðòÿÕ±ÿÔN:øR¾ÝðEÆßØ—ÃéÛþ…þ¢Q×ÄUúÿ|ÿ/ý¼ü¯>¼Ÿý}©ÿ¶…Q_¡Ÿ>QEQEQEQEQEQEMQEŸÕ_ÿÁr^KÙ'BÔ¼›¦²ÒüS ··BòGg–7Ð,’²‚ ³D››tŠ3–öeìpþlòÌÆŽ=G›Ù»Úö¿•ìí÷?C‡3Á,f¦»s+_±ü㟈ú"ŒÿjØa-,ôˆ× ¬Y <&¯èÞŠýº¿1­JÙ|d»:—_3óª^ªošž)§åíÇóÿ Eÿ ®Ÿÿiácèasý­`O WôqEkÿ?ú_ø3ÿ¹‘ÿºŸý?üÿ¶?œ„ø‘¡º­ÿ¶‚†ø Æ«dí ¯èÞŠ_ñåÿ@?ùSÿ¹‡üBêôÿðþØþq—âNˆzê–#þÚŠQñ'CÏ:¥–=|Ñ_ÑÅßÒô¿ðgÿsø…Ôÿè!ÿà?ý±üã¿Ä —T²?öÔQÿ #CÇü…,ïè¯èâŠÒkþ`Wþ ÿîaÿºŸý?üÿ¶?œ„ø‘ žº­ÿ¶‚”üGÐÏöµŸýö+ú6¢§þ#ô¿èÿ*÷0ÿˆ]Oþ‚_þÿÛÎ9ø™áüq«ZçëM_‰:+sý«§ãþºs_ÑÕ×Òÿ ÿƒ?û˜ÿâÓÿ ‡ÿ€ÿöÇówñBbö­¡8ìà×ëü2Âå?d?j[]Ee­xÖêïOžXZ8ï¡[ ±0è%†Tܹ£qœ©¯¸(¯’ã_¥Ä9oö{Ã{?yJüüÛ_Kr®ýÏ{‡¸.9V'ë*¯6ZÖßæÂŠ(¯È· +(¢€ +(¢€?;?à¾÷‡@±ø_ª\¥Ä:X]ZÂKÃýš)äm>Hây*ŒéÌ¡ˆ,"|giÇæËüHÑqªØ7ÒQ_ÑÍû7ø½,*§–,/´äæ÷¹í~i9mÈö½·>=àHfXÙcgkiË}’[Ýv?œ‘ñ;G ´kA}<î)Ÿð±ô_ú +éÿ÷ö¿£š+è)xñmºytW3»µK]÷»Õždü3SIOݶ¼vÿÉç¾#èj?ä-b~’ +Tø‘ ‘ΫdýtýÑZ?æÿæàÏþægÿºŸý?üÿ¶?œ‡ø‘¡š­‘ÿ¶‚š¿tC×T±öÔWôsE5ô€šÿ˜ÿƒ?û˜Ä.§ÿAÿÿíç~$hDóªYëæ +Fø“¡ƒÆ©dGýuýÑGüGùÞÿQ_ø3ÿ¹‡üBêôÿðþØþq¿ádhxÿ¥ýýäø ‘ΫdýtýÑIøÿ7ÿ0+ÿ÷0ÿˆ]Oþ‚þÿÛÎK|HÐgûZÏðpiñ3@ǵ¦}Ú¿£š)Ä~—ýÿåOþæ ÂêôÿðÿÉÎ*üHÑHÕtñŸúkUî~ h^fF«jO³Œ:þ¨ª_H ­°+ÿ÷1¯ )§¬?üÿ¶>gÿ‚=iš/ü£áâ_YÝØËru;Ø£¹…¡w‚}Rîhe +À’E"H§£+©úbŠ+ð<Óñ¸ÚØÆ¹}¤¥+onfݯÖ×?MÂaý…PNü©+ú+Q\@QEWó¡«xºË×ͥê·KÕ4•K Ë;ä{{›IáQ‘I€ÈÊêÊA‚+ú/¢¿Dà>— J¼•kíy~×-¹y¿»+ÞçËq? G88ʧ'%ú^÷·šì8£âNŠsÿKõ”RŸˆú&ä+§ÿßÚþŽh¯Ñÿâ`'ÿ@+ÿ÷3ä¿âSÿ ‡ÿ€ÿöÇóŽ¿´C×VÓÇýµ£þN‡Ÿù +YcþºŠþŽ(£þ#üÿèàÏþæñ ©ÿÐCÿÀûcùÉÿ… ÐZËþþ +aø“¢gNËõÔWôsE%ãü—üÀÿåOþæñ ©ÿÐCÿÀûcùÇÿ…‘¡ùŠYûj)ádh[3ý«eŸO0WôoE7ãüÿèàÏþæñ ©ÿÐCÿÀûcùÆtCÿ1K!ÿmE(ø‘¡îçT²ÇýuýQCú@Oþ€Wþ ÿîaÿºŸý?üÿ¶?œŸøXÚýì¿ïà¤o‰~SíkOÁ³_ѽ?ñ§ÿ@?ùSÿ¹‡üBêôÿðÿÉÎ)ø—¡³á5[´ø¦ÍñC’#»V±éÑd¿£Ê)¯ä¿æàÏþæ?ø…ôÿè!ÿà?ý±ø‰ÿ’¹_ÿÁF>>޳êpèçS½¿’Þ&‘, :]Ü"YX ³E,@-"¤ +ý»¢ŠüŸŽx¹ña{¥ìí_›fÝïeß±÷=’,« +ðÊ|Ú·{[{y¾Á_¿ð]£kÀßö)x‡ÿNÞ¯Ñ*üìÿ‚îÈkÀßö)ø‡ÿNÞ¯;…?äo‡ÿ#Š¿äQˆÿ ? +¿à°üøßàÏý“¿ýØuÊ(ÿ‚ÃÈíðgþÉÙÿÔ‡\¢½\çþFÿÇ/ý)ž6QþáCüÿÒQú¥à¹±ûøy?êˆØÿê%|[_ex=±ûxtzü°ÿÔF:øÖ¿aà?‚_õî—þÞ~Wžÿõö§þÚQE~‚xEPEPEPEPEPEPôÑEWñ9ýXQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEù×ÿÜÿÏ¿ìSñþ¼1_¢•ù×ÿÜÿÏ¿ìSñþ¼1_CÂò8Ãÿ‰?Å_ò(Ä…Ÿ…_ðX_ù¾ ÿÙ;?úë”Qÿ…ÿ‘ÛàÏý“³ÿ©¹EzÙ×üŒ+ÿŽ_úSðáì~ Xê%|s_°p'Á/ú÷Kÿo?)Ï¿‰?úûWÿm +(¢¿A>x(¢Š(¢Š(¢Š(¢Š(¢Š(¢Šþ˜ÔåAöôÅ-$|Æ¿O\þ´µüNÏ뢊(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¯Ë?~ܴ߯ßÛkÆÿ þø›GÓŸF×uK[dÓìUVÚÖâHÆé'‰É;TÜœ×êe~RþÂMø-çÄ~qoÄî3þ•/¸þ¿Nãï8*•cÄÕ¥Ž>h©ÅI]y3㸮¥_k„¡N¤ ªNÏ•´íêŽçÅßÿo_ÙçJ}{XµÑ¼o¥Y-Ìvö7>ZƒüQ[,S•À'(I#·»Á;?à¨/í¶·:§a†üs§ÂnÉ%/o¨B0Xò +’7FÙ Aa»oÕuùñ?B¶ýœ¿àº:4~…l­¯üQ¦1‚ºŒQ%Ò€:)ûDÇ`ÇjîÊåƒâ +Œ5\<)V„ã*k•>^’W¶·Zöó93ŠÉkQ¯N¼ªRœ”%¾f¯Õ=ô±õïÆ_ƒß´n³ÿðψü7âYmþ[If÷V©©,V±Û&ÑuÖ¤æY¤>iI6Ðéó)Zúî¿4>)|xñÎÿɵ𕷌üY…[WÓ":,zµÂéåL·w_ 7—†ff#n $žy¦ÿÁ[¿j¿~η×Ãù|3âÇ¥Ùèz~¥>k©Ï ެãP» °¡Úþb"ÆIRHÇ ¨¯ÃX¼Â¦ x'* +q´mukÚO¬¼ö.–}†ÁC‰´ÚU\]ÝõÚñì¼·?Lh¯Ì_ÿ?lçøkñCWø.Ÿs¦Ú¶©qá­XžÉì`Q½£B«ŽT»– +pÎß{è_ø$Oíµ­þص‹oMߊ¼u½ÕâF±›Ø&V0Êê¸óªp;êMx˜þ ±ô+¬`ÒŸ#~ë{n•Õô¿Üz¸.#lbÁÖ£:r’n<É{Éo³v~GË_ðo[Åêø„3×D€ã?ôßëý?ßõj¿?àŽœêMÉÙ}˜ó?zO¢üú¢ôWÅŸðQïÛƒÆþøÉáo‚Ú/x¬ÄnuQ_û9%b±¢UŠ«;»)Ø€2r¾eñçögý¦ÿdo…—߬>?kž.¼Ð"KÝ[IœÍ%²F I3¼R"¹³yUcŒ€Èà¸RUiRž"¼)J·ðã.kË[&욊of÷>›Äq§R¤(Ñ•EKãjÖZ]¥v›in‘úAE~wþÑß´GŒ¿kÏø%î“ñÁž!ñƒ|Uàû¾!¶Ð5K›(ç¬WFÀ²ÐΡ‹lBë’rO·ÿÁ0¿j³ñö³ñ‰µ[‹ÍOÁ‹sa®_]Êd•źù«+»±6í,Ç%ƒkg bpø)bäÓq¨éÊ+xËõOK?4k…âñk e()Æ]ýÖþ‡Ô5ùcâ_ÛwöœøÛûoxßá‡Ãoé:shÚî©ico&b¨-­n1ºI¢rX*‚{’OÐu?ðH/ˆß?jÏÚƒÇ~<ñŒ|asáMÍ– m^áôä¹¼‘Ìq¬%¼¢‘D²aBáIˆŒq^5ðã×…?fïø+ÿÄÏøÓU:6‡ˆ|Gn÷"ÚkŒ;ÝÊl…Y¹#®Ò>GÙä|8²üF7RÄU§II'd¤õJÏw¶Ýϔͳס…¯ Ê9Ôiµ.Vâ´½ú-÷=?â×íûlþÅÚ:xŸÇGBñ/†¢•RyÚÆÊ[XK8UUŠD H`3œ +û—ö-ý©ôïÛà•ãK_ìû‰Ùíu 3ÌûÌg›°2*àõÚëœ+ãÿø(oüOáçÆÿ€:¿ÃŸ†-©øÓ_ñŽÅd‹Kž(­ÓÌFl$¨²I! µB¯ç<Ý—ìÃïü›þ ƒ©ø‡Æ6E|E{y.¬šC¾]Ü,P[Û±àí‰ñÊü¼ófùkÅeT§ˆÂƆ*uaÇ‘Î-náÓ^¯ð¾½9f=a󑣈•l<`å)Ió(µÚ]téþGÜ”WçÁŸ´ßíãðæˆú¿ÇOáí¦µºçFÒô˜å‚7XªHdˆ$gŒŒ@ç5×Á9ÿl¯ˆ¶?´ïŠ>|_¾‹Zñ‡çfjÛq,晑˜æ$‘,nÀ8 +Cgp 󘮕:U¥B¼*Nмãk¤´m6’•ºÛcÛÃñ,gR’«FP…]!'k7ººMµ~—ÜûºŠü®ý¬jÏ‹ß ÿà¬Þ#ðç€õ­sVkƳÓ4\êS¾—ÅÞ—n«'ÙËù#d²ù¿0Ú$àdÖíM7í_ÿû×|?ã¿üSºñ¶µtb‘ Ô¦ºÓ"¸y·’ÖTHºÚcAÂ> +3èáø +­UE}b•h)Â.÷wW¶ÏeׯCŠ·S§í_°›)¸É«YYÚÿ>Ý:Ÿ­ôWæO‰ ý¬?o…¿¼5â¡à ùsÜè^Òõ{‹+ËÈ!, ß1˜¡ +euFB¢Ï©ÿÁÿo­sö€ø[âý/â¨/u/Åïö´ÈK‹WÉ—hùš#Ëã,s’ <Þ¯CÁU¾8ëÚOÃ/Kð×À^ùžæ Þh¡ve…¥’<ÊÓȈDeEØÜñ¹¢øëâ/ÚWþ Oâ-ÄZ§Äk¯ŠÕ.þÉ Õ'–ád“iÁ'œ^H]•\£Æçý[g”õ.«íxŠqÄ5uM·}¯fíÊ¥n—üwÅôý›ÅB„ÝíÏ¥·µÒ½Ú¿[¢¿´Çm öhø?¬øßÄ¿lþÅÐÖ&¸‘ fc$© +*© ^ErMaþÈßµ.“ûa|#3Ñ4ÝGKÓe¾žÎ(¯¶ ØD@ÞÁ Qœô që_ÿÁV-õ¯Úö0Ò>1øSÆWÚoÃäÑí&Ô<;ö‰•59'½K‘42°åÃFqÐá?à‘ÿ²ŸÅøgÂ^=Ѿ)jš/ôï´—¾Žúò8/V'S(1«›Ìèr=ý+¢‡ +à¿°gÄVPª¦âï{E¥ð4—Ä÷¾Û.æx‹ý±%\ÔÜ•­ªoã¿ò®ÛŸªWÁµ÷íƒñ;ã‡í…À‚:¯‡î­ÿnkΠ¼,#ó%U|7–‘©PJí!Úæà¿i_~Ò?ðMŸ ÙüG³øÕª|HÑc¾Š NËXI¥Š#&qº)ey%ÀMѼl ¦É#ÎÂð}JŠ”*×…:µRpƒæ»Ok´šú]êwb8žÝIÓ£)Ó¦í)«Y5½“i»u±úc_ð]ÓgÀßö)ø‡ÿNÞ¯¸g?´OÁ xÛN‰­í¼G`—~C6óm'I"-»c†\àgnkáïø.ñƱàoûüAÿ§o W' Q,ò*ŠÒŒì×f´fœKV2ZÕ îœ.Ÿ“? +¿à°¿ò:üÿ²võ!×(£þ sãoƒ?öNÏþ¤:åèç_ò0¯þ9éLò²÷ +àþ’Õ__ØÃǹø%cÿ¨”Uñ}}á)ü1ׇþ¨•þ¢Q×Çû«S—ý{¥ÿ·Ÿ•q½Iÿ×Ú¿ûhQEú ó¡EPEPEPEPEPEPôƹÚ3œã¿ZZHø~ž˜ý)køŸÖEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_“±‡‰4ÿ +ÿÁjþ$Ýêwözm¢ëž&Všêu†0~Õ.f`?ŸÓ¸ýg¯~-Á~|aø‹®x¢ÿWñå–¥âJçT¼z…°ˆË<­+…nä(f8èy&¾Ç„ó\ž*†:N1­TÒ½¾Z/Ä™v/<=l$T)óY»_æ{ÇÛçá'ìÿừýsÆúÅźšnyåýÃmʪŒHÏ3mQ‘–šüùÿ‚~ø7Ä?ðP/ø)­ñ§WÓÚÛÃÚ£ý©3Q&X¼»UcϤLÄ‘s·z×Õ~ÿ‚ üðeìSÞiþ$ñ1ˆ‚UÕHF w,Y眦8¯©üà=ᧆ-t_i:~‰¤Y.Ø,ì X!ˆu8UdžIêI$ó]Tó¬¯+ÂV£•sέXò¹É(¥ºŠM»¿?'ÒÇ<ò¬Ç1ÄÒ«˜òÂ7Ì¡Ûr[]»-<¼ûŸ—×wüiÆâw¤ž™ÿ˜U·±ÿ=ÇZ?೫»þ +Mð¼c9Ñ4¡Œg?ñ4¼ö?Èý+íÿÁ7< âŸÛ?·¯ŠÓÅq][^ Hîmÿ³÷Áoº †& +F¤þó9$‚8ý§?à›žý«¾6è^=ñ«â»-cÃÖ¶övÐé×6éjé Ä“©u’bKJÀဠ$ûXN-Ëéâð•¤Ý©aýœ´ûV¶ž^g•‰á¬lðØšQJõ+s­~Íï÷ù½ñ—þHÿŠÿìwÿ¢¿Ëö¯í{ˆ&òþÏçlòü¨cÆ|æÎsœ.1ƒŸ”Ë3|= “€¨ß=WO—M=Ù]ÝôÐú<~Y^®m…ÆBÜ”ÔïßÞ‘ùû~Ä÷ÿ¶æ©ãMOÖ—J¹ÐtVÔ­!q˜ï®ó²ߟ• fðJ†às_gÿÁ?m«Í2ò€¾<ˆòê¾2ð·‰ÃÁpfÐ/mí‘®a ¥Ïï ‰~Tù”òÙ'ìó¾3ËsZ•ðx¦ý„’tåˬ&—mÚzßËNº|®SÂØüºV/l›Sô”[ïѯÏÓ_…¿à¬Ÿ ´í+þ +im}ãÛ_Lð7Œ¡Óå“Q³Œ;Û[¤Im)*A1¼eÙp͇2ƒêÚ?üöt×´$Õ,þ7\ÜéΞ`¹XÓL{@’vàcœç§~•÷ÇoÙ—Á¿´ÏÃäðߎt˜õûH@h§—ÝA.1æÇ$aJ9ï· +zŽ+æÿ‚üMP\câDwÙŽ¥kåýÜ‹møÿgÞ°Áq¥)à(á物Bt¢¢ùb¥%¢zÙ§múbøV¬q•kÆ„+F£æ÷¤ââÞëK¦¯±ì?±·ìuà/ß³6¯àïk“x×ÁÞ4žæòâî{ˆgŽò;‹xí¤Dx@SHºŒòO=1ùc/Åsö °ý¡¾ +NÓ³ø‰K¶\…œ&8ÂÏe4‡ß)Ôp_láïìû2Û¤vgv®zá@ù§i¢ÚÁ_?à¦ÇWÒ´Iì¼£Çnú¬òDzK‹+~šAÀ–výÚ€w*sÏ–Õ·ceV¶7޼ðÚMÎJ×”$œ<¹ŸT¼—c>(ÂF,. hâ>ëîÎ-KÏ•toÌû—þ ;û>ŸÙûö,ðÔW04¿ŠAñ aƒNªbR:‚°,@ƒÑƒpð§ìÍðÃ?¿à±ÿ´höZî‘/ˆ"³{;†…‚ËaĈX ¤‚(È#Šàd؃¿±¿€5¿ ø{Sñµ¢k×&îâÛ[š „GhÄO´G cŠƒg;NsÑ‚ã,‹nuèUR‹zÞbå¿}û.Æ8®“ÆUXd¡Fµ7%¥¥ÒVþºŸœ?±Wìðö¥ø?§jz—Å]SAñr+&«£Íygnöò+º5‘7|Ógÿ„zƒ4{‹û­3ÃÖ¢ÖÞ[ÙIÝA'.UUIÉ=jò¯Øßþ ½ào؃ÄÚέá=WÅš…ιj–“®­u±¢+ïDPÇÎ{’x®l'á¨Ò̬ß5yFPÓ´å-{hÑщȱj`.—-(ÉO^ñKNû3ãOø!wí ῃ~"ñ×Ãÿ^Zøg\Õ.àžËûDý˜Ï,BHæ¶rø "»Q¹%¤d`ú/üOöœðŒÿ4ÿ‡Ú~«¦jþ$ÔµXof‚Úe™´è!W˹Rv;3*€y ¹í^ÿûNÿÁ.~þÕ~$›\Öô›íÄ#ž‹p-g¹ÀÀ2++ÆíþÑMÇ@±~ÿÁ¾ |ñ=¶µ—ªø§T±q-¬Þ ºK•·prD‰E‡,‡0FkÒŸdUs8çÕ=¢ª¬Ý;+s%ei_áÒû_ò8!’æôð'‡#¦î”îïÊÝß»mõïoÌñ¿Š_õ†ð@gðö£mrš¤:ež¡4ŒIn³k]•aؤrr#i‘ŠÛÿ‚üoð}Ÿì…®|I¡Ùø’-zå›qy7SvÊFÄ3†è +ç%HÏnx«ÂÚwü5£jöpj^©nö·v³®èî"u*Èø ‘_-ü-ÿ‚3|"ø?ñ£Jñ¾uã%¼Ñ/RþÊÂmF),à‘2ÿË5€#£H}ó^m ÁbòÌN0r„êUuSŠºæká}Žê™./ Ãâ°IJ0¦©´Ý“Ý~Ðß|/ü;Æžø·­ê¾ð߉5›«øuxm…n‰šÙÙ™Y|œ°›Râ±BOÿzý­ôS©?ÆëˆôížgÚ›ZÓ!OFß·n9çùñö·í?ûü=ý¯´;{Oè‚îæÈg¨[È`½´’AÕO÷X2çœgšùëHÿ‚ |ÓuE¸›Tø¨DMµÆ§l±7±1Û£ÿãÕïÓãŠ5ðÔ”±5(JQqŒc(ÊÝUìÓ}o§æüzœ%VzŽ8zu£)9')8µ~ŽÛÛËþô¿ì©ð+EýšþxwÁžÔ®õ}JŽi-/.]K…žy. eR3)ÆLuë_Áx?ä/àoûüAÿ§o Wè'„|+cà_ éz&™æèÖ‘XÚFò¼­Q DRîK1 + nbIêI5ù÷ÿá8Õ¼ÿbŸˆ?ôíáŠøÎ¯*Ùõ*Óm¹Ní½Ûm»¿6}'Q,Ž­(«(ÂÖ[+YXü,ÿ‚À6è}Òÿ#íÏøcogþ<ŸÿßüÎRØÛÁ ÿÇ“ÿáÀ›ÿ™ÊøþÛñþ‰oÁŸûñ®òΑ¿à½ÿÇü*σ?÷ã\ÿåRãÿÏê¿zú·ŽÿŸt>é‘öïü1¿ƒçÉÿðàMÿÌÝðÆþ ÿŸ'ÿÃ7ÿ3uñü?Ãâýσ?÷ã\ÿåðÿˆ_ôK> ÿßsÿ–tÿ× Ïêßzú¹ŽÿŸt>é‘öñýŽ<?åÉÿðàMÿÌÝ'ü1׃?çÉÿðàMÿÌÝ|Dà½ÿüÒσ?÷ã\ÿå'ü?»âýσ?÷ã\ÿåRãÿ?«}è?Õ¼wüû¡÷Kü·¿á޼ÿ>Oÿ‡oþféìyàÁÿ.Oÿ‡oþfëâ/øoÄú%ŸïƹÿË:Oø_Äú%ŸïƹÿË:kŒéõo½ú·ŽÿŸt>é‘öéý|?åÍ¿ðàÍÿÌÝ!ýü?åÍ¿ðàÍÿÌÝ|GÿêøÿD³àÏýø×?ùgHà½>??óJþ ÿßsÿ–tÿ×ÿ?«}ñú·ŽÿŸt>é‘ûƒÿBñ‚ Âð×úœuOþSÓOü#Åãþd߆¿øXjŸü¦¯Ãæÿ‚óxûþ-_ÁŸûñ®òΘ༾>=~üÿ¿çÿ,ëæ,‡ù*}ëüÏ¡úÇÏÊ_sÿ#÷¿à©þ.Qσ~ÿáaªòš™ÿVñ`ÿ™7á·þú§ÿ)«ðý¿à¼õþbúÇÏÊ_t¿ÈýÂ?ðWù“¾á]ªÿòšš௾#þDï‡øWj¿ü¦¯Ããÿ¾ñ‰ÿšKðkþýëßü´¦Ÿø-Ï‹ÏüÒ_ƒ_÷ï^ÿå¥?aÿÉSï_æ'‰âŸùùKî—ù¸Mÿ€ñÿÌðãÿ +íWÿ”ÔÃÿ…ñ +Ž|ðãÿ +íWÿ”Õø~à¶Þ.où¤Ÿ¿ï{ÿ–•ÿÁlüZIÿ‹Iðkþø×¿ùiG°áßä«÷¯ó¬ñOüü¥÷KüÜ1ÿ‡ñ ?ò'ü7ÿ»Uÿå5HŸðWï¿O|6ÿ¿Uÿå5~ø-‹ÿ’Gðkþø×¿ùiOOø-ϋӧÂOƒ_÷ƽÿËJ¯«ðïòTû×ù‡Öx§þ~Rû¥þGî`ÿ‚¸x†Gƒ~cþÇ Wÿ”Ôø+wŠOOü5ÿÂÃUÿå5~/üÆj0>|Çýs׿ùiNð\¿ù¤ßïÞ½ÿËJ^Ç’§Þ¿Ì>³Åóò—Ý/ò?qáíÞ)Î?á økÿ…†«ÿÊZ?áíÞ)Ïü‰¿ ð°ÕùK_‡Gþ •ãBä“|ÿ¿Z÷ÿ-)­ÿÍñ®ä“|ÿ¿Z÷ÿ-(t8wù*}ëüÇõž(ÿŸ”¾é‘û‘ÿmñIéà߆¿øXj¿ü¥¦?üËÅ ×ÁŸ ð°ÕùK_‡Cþ ãQÿ4›àÏýú׿ùiMø.W$ëð—àÏ?ôË^ÿå¥ +‡ÿ%O½˜þ±Åóò—Ý/ò?p%ÿ‚Âx’†ðoÃpGýMú¯ÿ)j3ÿŒñý ¿ ÿð¯ÕùK_‡²Ánü_)ù¾ü?öÏ^ÿå¥Fà¶^,?óH¾ ßÿÿ-+E‡á¾°«÷¯ó3xŽ+éRÝ/þDýÅ?ðXïù“¾á_«ò–ÿÁd¼@?áøoÿ…~­ÿÊZü:?ðZÿŸù¤_¿ïÿ–´‡þ [â²ä‘|ÿ¾5ÿþZSú¿ Ϻ¿zÿ0úÏÿÏÊ?t¿ù÷ÿÁd¼Bü‰¿ ¿ð¯Õ¿ùKAÿ‚Éx‡þ„߆߸Wêßü¥¯Ã£ÿ¬ñQÿšEðkþù×ÿùiMoø-wŠÁÿ’Eðkþø×ÿùkGÕøkþ}Õû×ù‹ë¯Ã_óî¯Þ¿ÌYâ¯ùùGî—ÿ"~à·üŸ\Sσ¾á]«ò–šßðZÍizø;áÇþÚ·ÿ)kðí¿à³¾%n¿þ ~Zÿÿ-i§þ 1âFòGþ ~^ ÿå­Wá¯ù÷Wï_æ5ˆâ¯ùùGî—ÿ"~âø-޲?æNøqÿ…v­ÿÊZcÁmµ…ÿ™;áÇþÚ·ÿ)kððÿÁeêýëüÇõŽ)ÿŸ”¾éò'î/ü>ÿVÿ¡?áÇþÚ·ÿ)jHà¶úÄìø?á¾OýMÚ·ÿ)kðÐÿÁbuãÿ4wàßþ\üµ§GÿŽñG+ð{àØÿƒÿ–´*5ÿ>êýëüÇõŽ(ÿŸ”¾é‘û©üsÄýßü5ÿÂÃVÿå-8ÿÁe¼Dü‰Ÿ ð°Õ¿ùK_†pÿÁi¼Qù~üüF¾÷+Ooø-ŠÀÿ’Cðgþø×ÿùkOØp×üû«÷¯óÖ8£þ~Rû¥ÿÈŸ¹'þ /â ?äLøkÿ…†­ÿÊJoü>kÄ_ô&|5ÿÂÇVÿå%~ø-—ŠÏüÒƒ?÷οÿËZOø}‡Šÿèüÿ¾uÿþZÓX~ÿŸu~õþ`±Qÿ?)}Òÿ#÷$ÿÁgêýëüÇõŽ(ÿŸ”¾çþGî?ü>—_ÿ¡3á¯þ·ÿ))üŸ_ó&ü5ÿÂÃVÿå%~ÿÃé¼OÿDàÏýó¯ÿòÖ‘¿à´Þ'Ûÿ$àÏýó¯ÿòÖaÃ?óî¯Þ¿Ì>±Åóò—ÜÿÈýÆ“þ ]¯G×ÁŸ ¿ð°Õ¿ùIUgÿ‚ãjöùÝà߇õ7êÿü¤¯Ãöÿ‚Ñx™úüø3ùxƒÿ–µZoø,v¿q÷þ|?øPòÖŸÕøgþ}Õû×ù‡Ö8£¥J_t¿ÈýÂoø.¶¦¿ó'|9ÿ»Wÿå%7þµ©Ððãÿ +í_ÿ”•ørßðWÝiºüø5ùø‡ÿ–´ßø{ưæ|üüCÿËZkÃ?óî¯Þ¿Ì_XâùùKî—ù³?¿à­6_´‡Â[Áž'ðGÃù´]dF'X ß^!ÿåµ)ÿ‚ºêäÉø5ÿ}x‡ÿ–Ô¾­Âÿóî¯ßóÖx§þ~Rû¥þGîGü?Qÿ¡;á¿þúÇÿ(éü—QþDï†ÿøWëü£¯Ãø{¦­ÿDcà×ýõâþ[Rø+–ªOü‘ƒ_÷׈¿ùmOêÜ-ÿ>êýñÿäƒë ß^"ÿåµþ +Ûªù¢ÿ¿ï¯òÚ…C…¿çÝ_¾?üÖ#Š?çå/º_ä~äŸø/ð?ò'|7ÿ»Xÿå'ü?Îø¶?áøoÿ…~±ÿÊ:ü5?ðV­Hõø-ðkþûñÿ-©?áí–ä‹|ÿ¾üEÿËj>­Âÿóî¯ßó¬ñ?üü¥÷KüÜôÿ‚ôê2tðoÃoü,5þQ×Ïß·_íæ?l«M>òþÇÃ:-Æ…¤^év¶ÚF©}¨µÛ]Þéw î×6«tâˇo?–‰ÿoÕ§ÁƒCþâ/þ[S5/ø+W‰5+·Ó¾ü$ÐofÂèZÛê÷SZ6Gα]ê[¹’Äëꦺ°U8s ^šêóEÝ]Æ×ûÎ|l8‹Bxjõ)rÉYÙKo¸_ø+v§©ñ+á~Ÿlþuî…à(­µT֒˫ꗑ#ú¶º·”z¬È{Ñ\}ÍÕÏÄ­FïÄ> »¹Ö5½fSuyytÁ¤™ÈØUUPUB¨Ez58fX¹Ë)Ù͹[µÝíøžd8–8HG ]A(ß½•®ÿÙ +endstream +endobj +853 0 obj +86414 +endobj +854 0 obj +<< +/Type /Font +/Subtype /Type0 +/BaseFont /YJDRSH+CourierNew +/Encoding /Identity-H +/ToUnicode 855 0 R +/DescendantFonts[ 856 0 R ] +>> +endobj +855 0 obj +<< +/Filter /FlateDecode +/Length 436 +>> +stream +xœ]“MNÃ0FO;x ‹*xâ$EBH%m¥.ø±Nãi‰DËM½=®¿¡"µÑ³Çžy±'oVó•ëG•¿„¡[󨶽³Ã1t¬6¼ë]¦IÙ¾…Ò·o}–ÇÅëÓaäýÊmU ʽDæ¯ñuÃI]Íì°ákey›åÏÁrèÝN]½7k[½ÿâ=»Qݤv3ÍcëŸÚ=«<í1YÙÔ§I\üñvò¬üñ8X–m4JéâÈÁ·‡Öí8»»‰Ï½º[Æçþœêß¼1X¶ÙvŸm¸„§W"ý‡è‰HÈ$ª +P j@HƒêDµDN¡[Ì=€f Éð*A ö$Ðt Z€ %Ö™D~¦Á¯@e´Á°‹†C=Á¡@v ‡RêÔp(f 8TR‹8H>q˜‚àPËžp(ñ]%¾Á¡†;áŒ*ÔI8£ +¶?ƒ|?w‚_!ëàGÈNrF¨šÄOjŸ‘ìð+eøR'üâàù"ÊÓ?÷ïr_5´Ü®©Dcþ|ƒÏ yé•îBl“Ô©?²Ø ½ãKcûÁ§‹¿ì¿ýÿš +endstream +endobj +856 0 obj +<< +/Type /Font +/Subtype /CIDFontType2 +/BaseFont /YJDRSH+CourierNew +/CIDSystemInfo << +/Registry (Adobe) +/Ordering (Identity) +/Supplement 0 +>> +/DW 600 +/W [ 15 [600 ] 14 [600 ] 13 [600 ] 12 [600 ] 11 [600 ] 10 [600 ] 9 [600 ] 8 [600 ] 7 [600 ] 6 [600 ] 5 [600 ] 4 [600 ] 3 [600 ] 2 [600 ] 1 [0 ] 31 [600 ] 30 [600 ] 29 [600 ] 28 [600 ] 27 [600 ] 26 [600 ] 25 [600 ] 24 [600 ] 23 [600 ] 22 [600 ] 21 [600 ] 20 [600 ] 19 [600 ] 18 [600 ] 17 [600 ] 16 [600 ] 45 [600 ] 44 [600 ] 43 [600 ] 42 [600 ] 41 [600 ] 40 [600 ] 39 [600 ] 38 [600 ] 37 [600 ] 36 [600 ] 35 [600 ] 34 [600 ] 33 [600 ] 32 [600 ] 0 [600 ]] +/FontDescriptor 857 0 R +/CIDToGIDMap /Identity +>> +endobj +857 0 obj +<< +/Type /FontDescriptor +/FontName /YJDRSH+CourierNew +/Flags 33 +/FontBBox [ -122 -680 623 1021 ] +/AvgWidth 600 +/MissingWidth 600 +/StemV 70 +/CapHeight 500 +/ItalicAngle 0 +/Ascent 833 +/Descent 300 +/FontFile2 858 0 R +>> +endobj +858 0 obj +<< +/Filter /FlateDecode +/Length 859 0 R +/Length1 23656 +>> +stream +xœµ¼ |SUö8~î}/{Ò¼¼¬/I“—¤I—tßKK›RZ6¡AZ P@d¨€ .Ô™Q¤ â.¢#3.£âÒÐ*êà‚èàŒ(ê8úEQqû¢ãM~群¥à2óÿü¿¼Üý¾ûî;çܳݛ(ŸE 枟ÌÁ{ÊaE²Hle,]>°\‰ÑSËæ^²"U>‘<ÿ¢Ur²L±¿f㊠¤Úu[ô\¸ôÒ ’e>§æëEËV]’,OnŨÿ‚ —%ËSõ+ó—ÍMÝߊó!W,_¹*Yž±£GšÏ-(N–g²ù÷˹ˤÊK1:ìÝÔŸ^½táœÌ9æšo´:­Òzox²òo¬7'4ßoâOj£l’ØŸ$_o{h`3ÿZB“˜ÁŸLÕŸþä§Ò_žΓ^‹÷ýß¿@»‡= +`¸ Œ°I{À|€e7€•"®°opÔbø À‰mÎcÒ$ ½ À‡cùõ^„]ïÉ@Ø„‰dîÈ)Èóâ”–…‡J\(m(ÃgW!ŒF,Á€ãÖÜÄ஼M>÷›@ (€6îÕtàòãÜL}Ü<ð$ޤÂñ+± Ûã‰=ŒãLM…äg*^·*ñT21™Âùp–Áp;Ö•?ÁC3ÖÞ +5p3\ o´ÄWX€{á È…*X”ˆƒÖBœ\÷Šó4C%¼ `­á¢ü§ø9¤ÛF~y8ÊT¸ œpGÌIè±¼¦Ó¼k*àæhs…‰¯É³üþÄ<ø=©¡oñÁ«pœyˆÿ:±!±%q¤Á .}à‰¢Ä2¼ktÀj¸gп…×HI÷&ÖãœZqkáI8@¢<ð Âìý¸vÁ3pÞ† !f’EºÈä +öÅ÷%Æ%æ%–C#L‚èÂÖt&õt7ƒ{”;<ð?ñ£ Ž=.‚Kà2¸q³ Ã;ðWÂQ=J§q‚F ˜‡Ð¼çôì‡#DKJÉ#×GèE<7°8Ä¢!8Vþ°az?<ûàuø3Žù”#‰’id¹‚\M®'·ûÉ#ä1ò)UÑ·9޻Бÿ4þVBŸ¸3ñ>×^!1S ç >_ƒOðýrH.©#¡QšËÞ8—$Æ$Ö&^H†dbß‘0ßy"LÇY_ +¿†=ð"Þûü >‚!”8¢'"ÂB&!2…œKVã,%_ê@üUÒ¥´â¢Ükütþ±q{¼/þE<‘Ø–èIü1ñª‚ßr|Nb VÀJc;ñ9/À1ø'|ƒÏP?Îu,™€ï{Ž„œBrÒÒ+é#4Áä6qûy‰¿#>)¾,~G|{¢41i‹HPŠ×¤¦i¸BV¯š÷ÂÈ™íH=oÁçÄE|¤Œ#ç‘VÒA‘ådé$—‘˪‘dy‹ü•|Nyª¦v„S”Χ¿¢7Ót}‹ã€;—kå:¹Ë¸›¹ÜëÜ?xÏå ù‰|)¿F*NíоzÊyjÙÀ¼;þÏŽÿ"¾!þ\ü­ø CboâC\Å…8Ç6Xˆs¼ßÿ¸îAúxçø>| Ÿ"οFXpDGÜ8c¿‚·œ÷DœùtÒF.ÀkY‚ðï"ÛHyŠ^Õ¸ +¦Ñ ðî¤Ûh}¯o迹—Ës%\-×o³Ž»ßçvî=îCžòv¾ˆ?—_Ë¿¤âTç«nSmQíS½¬úD-¨g¦xÄÔáÌ•{•>Ç×rKa+´PŽû„þ…Ö+èIòšNžÃ§¥s-\ m Õ@ɤòe`ÓlQÔ”;‚¦C‘@›i7pFX…ë è z í€ÈSp’ŽEJ»ˆ{n¥s¸-üM|-9 kñ™@Mä[¨‡zR‹¸{:CyÜãüŸØˆ*-wJµŒšëøU”û òÁ‘„r¯ä8i¡„V5½BXÈqLÇá +|)™•üQn#OÿŠuKáfò¾ãXJ÷ß#^*q=^HZÈ]\\I:U°„Þ‚ì~ "=Oƒÿ%¿"v\¹'7ôà9‡hbýu"Ò|r%Òé2Ø@º!— gáUz#”“Ü3§¤,JN'½ÜXè%'ùýü~ÊãHÏ!4 ‘{ÄBîE1 Wf€‹ ÕT‚Šæ"ý·#<,ôr9] +‹ÉÜ?Éý´ša·’6‘Ûâßðõ\ Bl7r“u•T5ªt¾1þ1Ô"5.DIºˆ?¢úËsop'm‰@|Ž*-þ¬AèŒEî¶×ÒXx—8Èl2™OÐ |"ql£óï%œÄHðç®°øNRC22éLÈd¤ðÙLFóø«ùÕüå(›N"×¼n‚;áy”&÷¡ÜÊD8žƒÐœ…¼g1ʈB(†2|»Z…\i¶µÀyÈO;K^€ò»9ïÝðô¢„š€ð˜÷]K°~%J¨ËàJ\ÿë`#ò€Ûàø3}˜ÞÃèµôz] ï»ÜK\Œœ‡øõüZ82`2±â“+K~¼ocâ |Z6xû—â*EºO|šx+ñàÀAïœûMêQ𩺲 ™|Ë»‰j7vy–{¶oZI¬“J²=-£¸‹¥“’öéJêê ¸ga†Ç1ÄÀÌצj8ðc\‡ÕÞ ´oåö@†g1¼ŽÕìÆšÝX³kvcMׄ{’{¢/ÃÞ±]Ê(þ¢ÞÍm‡ÊÝÈm@‘íçf§Ò9©ôLs0Ý”J¯ã6ôUûÍõ:,øãŠïvWߘæâ]J¦¢FÉl¬Ù²küõwÎê.œÕ]8«»pV_`LpÔ-X¿ë·`ý¥~ e¨@vj¨Tæ®>³#Uƒ™z=ׯ‡ÔàGÞ›L§sçõû÷ÖwpÓpèÇ•x+7ã”xŽ7+ñZ¥u­’_®ä—+ù:%_—ʳ¸`XìWb3‹¹)ܹH~n27^I[¸FcÚŒe–NâÆ)éDnŒ’žƒõ.L'`?Óñ\“R‡åјŽÅ2KÇpM}£ý…õ+°<ÛPgâXýhœÃhœÓh«¹ÃV G”š9¯Åp§ô$Üh¼ðªçêñŽŽÖp\ ¯:¼j¹Zl‰}Gbãj”w¬Á^5ø¤„U Ž\ƒèA…AÃÕ`,sePˆ!†¡CŽ“‹÷åâ¼ï $Éõãǵµl˜Ê©ÔO7àªös>º¡ÏçÕëè”; à + ]tGŸJ4×Û°ë[€¡Ã k1܃áq Z¨K¶Ä ´ŽÖqÍ´™ã‘º³·×Ô+iIy2õ¦'S£»Ø\!—`ʆ{0p8ålœr6¾ê`É"édÂ^ 1ÁÀž‰ÀÈD`dâ fâý™J/µÒï Q&Žf•r·CÁ°QXmÖda) ïɾYX{c¢ÜÁÚ[0Ü€aoª-¨sP!Î ŽÄÙ`\§äÌû¹`Õ™û¾d„¹¾áÞŒéuÍën×1VBÙ"6+qA*¿saðŽ0<ŽAÍíÂ+¯L¼²ð +âÀKÆ 1Êù››ðº¯ëñº¯xm@ìØîÒ9eËËÖ–ÝPvOÙãe{Ë4{è\¼:hGL +fÑ¢u× (Òf‰|¯Ä*ñ…JSbgÌ=Ëtl–éåY¦Í³L·Î2µÎ2Mšejše*˜eê'óbΨé¯QÓ¦¨é¼¨©«ŸV°~a–$ûù”~¾3úõŽ 4Žî ûŒTúŒ<³ÏÂ3û,Tú,Lõá’}ÃúhŽB@éÐýAßÑ'ü£}†AsÁ¨èÏ|È.OÞêmXÓ¸ ÔØj\€¡£gÃE‹\=]ódy4·X“ÜÃE:æÍ_ÄÒ¹ úÉ[¡£{B£åÞñk~ØÞ³†5î…5S[{×ÄŒîßš;ºmû˜¹9žñ¸õƒëÍ™û#ƒÍeƒå°gyôGšeÍcسeÏz”=kLlŒò,…ê‘,µ0ª­aV2ÝN z$àO m”CXQ«PsuÀu¥g7äA0DÛzŒ¡Q=& ¬)¯>¯ž5á*cMiXmN5¹®¬xv“SMV[B£ÀÕ¸x4~W®LeþËïJöY5{ål%U¾+W­ÆÀ…ŠéÊU€ïPoT¸²ù3U83ãÈŒks+W¶­«+Wo‹N?”[#“•ÃÉVžýa´…dÀáV®&Ø‹u\"œ•q`“L‚3B;€_¨BÓ4ÐÔ«ÖôãJ@ų zµ +3Opuë4¬î ’¶ù2Wt’p¢fâ@Í$áÛš‰Â*55,–X–pÀXÈÃ)™{öTL'AæŸE·-q„ŸÀu¡âùå΀Þ`®³÷'¾åbæ%û{áw2ú> ’©É°g:FËÃ3§Éíá™KÌK¤Åáõ’ÑÑŸø:¶Òjk³žgÿEø‚ÌoÝ*µ[ìîl![ »»…-Âm®[Ý÷ÛïǾ¡ˆh1K6N›&yfp\k dk Ûyµ÷÷Î@ÈV­mÛê'›üÏú©ßk Dbf]ÝÖ1Gü‘M."E÷]ïêG¶É^º½“D'Ç×nïœxâ8Ô?^‡×1‹è¬²ˆU„¥bU•…Š +¡³½²’t¶#2HYiyI±ÃnW«CÁHf$ +ªí6GIqy…RoÓ`=”•BI1÷‚K´ºˆÓjqRõã·ìyþ­‡ç˜b,Î÷¾| ~’<Ç™¼~·ÛÿŒßíôŒéúäö{m±9-ÑQ¿ ÜKˆ‘ ”=ˆ[Ú{.h•γ¯´ÿÚΙuÆVAê¨VÕJHP+ºì·Z,Aè´z ²Eš…½'HÒäµ +’Û–»uljðÍ¡ÎL‹ +I;±Ø ¨C`„½eÀJfèd<›å€ËçvûÈø¯}·Ÿÿøä2§Utá;:ùZænBÊ8)# mãy±Ékîó?œÏE4a5¿Êz±û"O—íj÷M¶[ÝÛ4[m÷¹+Ø©y*­×¶Ã½Ëw íD‘]†náî´Ü⦗åwçoÉ8m[þ Eo}X¤Í +öÓÇbîpA ‚YbºÕ™]€òl•u¹åýähl¹6 ô%Π @®»"—ËÍ®6³lw t k0,b&G9@ +uæÀœÀ=Ç{GÚ€»ÒyCa@ÍÚ—«ïQïUQój©"gÏiâAÚøH!M‰ç¸XUp¼ R͉ãH8HCHHUHH–*Fb» ¡}bRÔ„éÜ =“g´îMâ;(M| e¤Ä‰í¢6_[©|Ú ½»°« »îv±&že-HŽí2u +GÅgY)£&YQ‘"GKI¥\DiKQ*×úäë·?|ôðˆk›»ºæõÊ:Á©O›WË=}+ž_¨þ͸'NºøÂe{æ_zçæåkž0 ×6^P¥w‰½Ùs÷üC õä÷¡¹zÊ9‹¦Ïatz0q„‹#îG“¯b×Úê¼õT<Ú`ñèGäG*~Wùªuÿ¨¿[ßr¼Uû×QŸZ•þcÔ)ë‰ÒïF‰«Ú¡ªÕò[í{­gԆ୥{̆éÖ•‹+—T¯©¼²z}åúêûm}6ýõÕ;ýt²6šŠÅFÖ”º]æ4ÝX¥Å…!>¿ÜœfäôȤê‘#‘w5èûIÙNÎ'ùý䶘7R@µfZU Ù7Ç·ucwSÑÔPu¶=ëO<s˜¥ºXÛòl’-56h8uD0ÌîJâêðCö'ž ÑãÂÀ1FŽã"Ž·c4`A +H"Þ’B~’ŸT1.Òpi¬²b”({ÃÖ°³Öî‡jO•ŸTȉ£°è¨sùÁéª9"½ÆO<îêšJ¹lõ?A Ô5Ɉ$ùþUW!iXRT´£ÚVª÷>•øœ‰Ï`tâ³¾Z[Eâ³íAG·rðÓFž:Û˜úU™ø,¦C¯¶aT‰]c.ÁŽ%ŒFÛÌ6ŒŒFÈÔ½l„ ëô$¦`cÑi1†TJR\і䊙)js:Ø¥P`0Ó¦°Ì²Å6F‹e¥™‘ŒH’„¹ËÃt)ü²rʺë&U7^óøè¹sþôÒKkµv“èBª“œ¡ÍËïÛ:yJü¥kÏ9tóc\4Iv“Ïíj2+«¢e5Y^³Õº|ì/þ° hKsûõ¹%{¾¿°nÍèIr颚¥k½®E^uÿ(T‘Ø%y6RuÐ œÊawœç\`;ß±8…m¥c…k‡S_á-/ï_>Ó9³l‰sQÙÕÞÍú’"³ì *RÉá¬(–C>&™DChGT W6ð¾p´‚ãiT—Ñv"÷OÄ\ä/*(ª+⋤ªu—žf)Š0R¨ ÉŒ»RâˆQÐi‘¤pC +ï»À‹¸¶Ø`7¢==ñÙN‡Ãéu9†ã™TÙ¡‡]XÃeÃS>‡8>ÞvZ­NE~©Î[uËÜób‘Q™^"ìXº­ÅbÑ)¯-ž9{ììõÅW¼îuÞ_ÍÄÃ?ýn—gj}[ÔŸ7iNSëÍOÅ?=Çî°8 fµ‡&© À- ¸ÜÇ%LÚ1%)x33E¬“ õÚ-6…Š“D)³”2±­(/Ç ävØSMË‹Eç¨"¿Þä–šËÆŒ*ñ:ÞÒúK¦ºÜ&\\ŸE¾Žój㛫Ʃ8…gqã|²¨bÏ9lVÇO¨ ‹f_áE£žS¯ˆßQ7åj^üJ~:òÖ0‘¼X]‘Þ\•‰¡,o2™FÛMç“tú¦U䲜 ó T?«GóŽîÝÌwŠ>R¨×J\.w™f#·™{„S;¼LФ‚tIò¦v³R_NEsZÐö³r}°À ú}Á01e˜«íÞj\Èiƒ>;@næ5௫#³–hÝ%¹&ûÌéÍésÒ—§óéRñìaª“5 +³dŠVMÝ1ED&黪j¸`„Ÿ,(DoL}_–±pwâä%NìˆM2ÙøŠëÍ ætíÐÉ6{9Câ}ƒò0¥â” ª8¤ô´"Gr&<²úò¿¬Œ<ýþÆWMÇ—³¸³“ÅÜÝoܱùСͷâæmž9kÕÁ wÆOÆÕL ²åÂW3](¾øÆƒ¯oºñõƒÈgf"ŸiãæA&±ÇŒz~§ƒf9ˆ[kÖ)`7hF6hö¹”²g’Óãq9ƒ¾Ì+ç’|“œ‘ƒ™Äa¶ÉjÈÔ;]Õ~ŸÏ¬ÕU fµ UYp:úé½1]¶`‘µ5€O·g™›D‚¿F!~ G rÄØnè'ówF:9@0Ëá¼hbit†ô€µBªv焦‚Q¶Û˜©a¶-·±q6){8ñ'Äcƒä_WW# Ç\HûÒ1×1w ÿÕǦ.Ñ‘BCaƘ¬ó²ÎÏz(xÆ“d—á)ß™ûT´‡ø÷´ÇTŸh-¾ˆ«FH³aœï<2MÕ®i7œO.P-5¬¦—é/ó]ê_ïÛí:¸3ì ý‰/û BVâ“^Ÿ"6˜bÙÙF,¸j ¹h졟]-wî'êø¿v¾wó ÖÉoß½é¦wYà?xãÅø7Ïï‹ùâý§­…S/ßó·¿Ýƒ±ó4Z8•­W/¬å¥b)&M‘æK«¤ßH«Ihµ!–ÔF]«J4:¼Ò­vÄ÷í'·<áU›Œhóì!sð~Š@Ï«d{³Ø¤ôáÖrý¤ ôíqág¬ {¨Ìú“–ЦËמi }Ãl!•åwâ““ÔÆÞîbŠ Ó1–â›1¾]IÖÅ*ÞT¿©¥ûÔû´ô^mŸºOËujº4t¾æ|íùn‹ç~5½Ì¿ì œ×¿ÄOð”úвc´)˜í~;µ7Iv»K +ŠÙ +çÎ*ÌÍ-( f[ ¬œi$­IŸ–fÐ-I[I€°¦áY)ƒ©²˜UšÊšŠÊÊŠ‹‚ÅÕ•j²›‰Ûšà5ÙYY"*ù:½ì>"‰ñaä¢M…[ i¡T…ìä4@O´'!ÊIÝÀ dë?NÈí?S:»)É_v±m¦íŒÃô'Žö g26W¥ÕhÕZªöªÜ¨'kÓ™zL¢9 +£ñ Š¿ oý{¯Ç¦p™ÎNFÕíííIyÀ”ÒA¾2DÝ +Uk~RDLo½¾­£¹r¦ÂpÞgDÐô«eç®éœ£ˆˆÏYÔücž›ÍV0ÎeK]h §à=XCî"²wÏ ×6P»að¸‚ä¹’”ê¢eqÿ ÕrŸ †cÒǰ;^‹ONù ÇP:þƒÿ<ÐÛ'j=ý‰ïbf‹´:OÌÓ"¶xxy7}ŒdKL'fá–²ÖˆD¥¢ä­äbº¶U#zl»éa°Ð…O‚J§5JÔ¶‡^pÒ?Åô°Ðb! A ÂÓtŠß‘?+¥ç(¤+0¯^MÝñ¤Rÿ³Še;{?ô~©†\)tSTK¦/Ç?·é̪Õüw'g 9Á +ÏS3ÚÔê€Ðöø)îqÔ7<ÐËÌ6æTåL³êE‡Z­œ«½Öªš¨ÓY·¦e(%ï+»‰ +_AJ™ƒ'˜†|Œ½CMÊþcv "»T‡VµÛÄ!Ó„Fh{ÍÙÆ4QÒüröì_j$1Í~0F¾^I(™2¸,zã+ñþûî÷ï7ê-’!HÆÇÑË‹Ÿ¢kS³ÍÖQ[¢’›g3Ö‰j§CP©q¶z=Nçk?Î×~ßn2qp¾Ìr☢YâtϘ­Ò!Ÿ”XVJ3“¶¾Ó!:èÚíW+ã‰ø£A£„³ÝOÆÞw?û +ÎÖeÆŸÀÙÂG‰éÜ'ªe¶e±:ƒH:®ªtMdœn¦îº‹È%ºõÚõºÛÈfÝýä!Ýðy‰ì×½E>"ÿÔ}K¾Ó9 :‚ªÝË;9C-ÌÔõ“>ÔggjŸ.àwØÒOöô>…ñDûÀñÇAÁq|„¤Þƒ”'ÁϘeñX$=½×`K³HªŒï[Ã’ÙhW=èL“Ì„ìk‰8_ ¼øˆ>­Û ¥-ÛE|I† XDE…á3D–QÙ2¹‚E_5WŽ˜ÄŽu ÒT•b/¿³æÉšà+ÁO‚ÜÃAâÍ ç•ºú‡bi˜Ibäg‘³…(¦v”„,u0£:€»m"UÌk³Ê7Ñ1d ZØfbNZØÑ™1fkÇÒ“vʬvÚf· ì§èP‚Ê×PdHʶN&?4°1Uä ‘Ý>´!ÖÞy!‰ Z×C4’´½hRæõsS1½é%4¶eI’ZJÇ4”xœNOé¨KΕ$£~ÐØÎ­%‹*ÇóœÎ$Š®’ÑçÇïPŒm«M1¶ãw ±m:N…–÷ºIŒmC>vX¥B‘VÑK[£­1!Ûd óA½ÇcTT°‹Ì= ¼ZRw¼¤€q˜Â"Ï.4lþËE­e¬yMÚ5™×d]“ý@ÖÙ{Œ;rðézG™±2‡Ïåø¢¶L_VÈh30·›ô‰xÜñ½8àà³´Y9¢kÔ´¨²Æ÷žLqFÕÓäèÀ@LH 3wètz£»Ÿü{›ìÁPÿ¹Cû¾ed¸ÞD—C8±Ö‡ý tä’‰zIž8.|‹Ô-$·>]ǘy3ÅÑ5ú›—ä^íïνÑÿ{ÿ¶Ü—åý¢&ßžÄwˆ3½ ÷¨"ÂÒQ„õ³²ªDASºÖ%²r5jv»hIwåúåœh@ÌË ùó¡<"IbÄEóÀW3ˆu™ëòóµ®ìP$'G§Ójý»éÈ£[c&Àñ %a/DH¤Ÿ´ï\ë½ÁK½ý$+ÆŽG´·_~äQ×OGQHêT*Ç/¶Õ¥(ÇÚ)>jT<¾=žTÚ3ÉR€ª5s ÔT|×UÿA`ž%=I%jÝâÖm”™c& 8fÊþþÄ·}¥rZ—ƒä‘ôÌ([i?¥i'±Æáp²EÉD‰‹É(@¦maÊw|ëik“œºûðÕwÍèº.ÆJ+îÚ¶<þ͇¿Ü>ù¡Kã¨>>þ ÆùÒ3î)«½K1׈󙲩-K+§ÞôÓ…ºxZkÈðzl±Þ±ÙN‹é(:…Χ/Ò­¯HïŠïJïyþÇõ¡ÿ{‡IòæxKi¥o¼çÿ,Ï ÿrÏRÿ•žžÍÞ;'UæÕŽÝÞ}Ü>q¿w¿O­}Áâ–e\·–ô€SÃ,ãTwõV +ßô“cΠ\Mª·ÚÈrÛ^ÛAÛo“9 ÃâÄãÇÙŽÓqEAg›MÌ…süLǘæFƒ~‡Çæ÷Qä-C›HÈ_IÀq¶2žÜ§²‹©áóN=èøð¡Ùª·¦ .¡ð›«ÞŽ!æ—ÿDôÓ¥7o¾ù›Ü}ïKµ%fÉbЧÏþ'Ñîÿß«6<öÈuìÔ‹"ë¸y(ëXFvµÛ-Tëiµ^§Î¨Î)ªŽFsÒÀ×â£+|G}_²c;¥-**A%«V¨Žª¾T©URIÎn¤žcíÈb:‡xLÍqæÑfߺ”…³N›U]!ì[—ïŠbâí_ùª¹Ì°bûYåŸj, +g÷Öh…mb*+¾¤4ƒÕ7BÝâIÃ8DΔº4¾Fò¹MvÇGŠÝC¦“)Š\øÐïlùŸýZYû +í gr‰&»Nq›7Ó^Å™k594'_ܧfüÀŽRb/êsM4'Vc®0W¦U™G˜kÌ#Í1sƒ¹Q'FŒåÆž¾\>“”:Í;O3Ï»J³Ê«*×{5ÞiU¡¶b¤BGFMµ#FŒ¬ V$Ïød‘´ˆ¯‹GÅ/EDAŒ‰œØtÆ1‚B›Rg Ê “•%B -i*()),–7ÅXå‚# ¤¡©®¡!VÌ+Pû"ùyYé^5ÑäTĪ¡IàÜŽÓT”—‡Ãv½)Mv:bþ²BG—ƒ:NEÒ}rf„•#]9U r]-;äµ{kÖrµÒ¶rzÏ3Ñš¡dp›«&ENC¼ªà¿Úç:«ÔÞùSʉ%™C‘dgK´”–"ge»$½‘WÂÙ|¦Ÿ¨Ô’Þé'Yª?qÝÊa1j˜æÂ3íöÅêõ O|<Mâ]|Ö»(9ßHéÀ(•“a6w­º?™²™ôaªÌ€´[í +·,O9è ø¬Ý³ÐÙšÏÙ{ÈÿøÅÒúyÊ•#f–QvͶL*É¿ ¾IÉ6ååŽlPª?`јԾڴ•MMÕçÌØÉè˜Þ›Ú¸`à %cÃôôìó“…a[l3]%o)ˆ…cÆU—êׯ«Š¶ûŒ;¢ÏGEõN­Yg|™§-͇"‚¼ ˜â¹u"7;a›‘„p{v @”¥ü<—Z§ÕÑŒéË!—ÈIxkÌT`ÙWØ_·óv©lõ.òêÐé£veƒí#ÅG^Ã\.ÇÑuæ6tûp!ÏöÙr¢oŽ7×QOvR%½êªŸÜóÜW’qŠØ³jDáÊ–O°ø‰G®¿x]‰ÝeÓZo_ôË‹ÉzÔ¦1grí’»Z‡(:9çÒÆµƒç}¡F±5 +HäT,±ßü‚DŹþ-ü[<á8!©_r¼#¼#¾å8ìú§ðOQãÜ¢Ýápñ/‰ß›¿µrwën5ÞGR=¤»ÏøŠú­ö×t£ê:m—q½u½ýºE¥­PWhKt5ÆB‰XâáÒæÐ¨±@‹aG«šjž2ïúÄ>kŸ½Ç±×µ[Ò>j~L¸_ü½õ^û}ŽÇ]KÚéÖÉŽv×=­֛w¹6KÚFk£½Ñ1ÞuŽ4ÚgÃYd„Bh.ñEÍùþ|šŸ¯“òr#nkÄ-Q÷nÒŠ<£6fˉxØÑ!°³Ç¯ì󴃟(¤K^DÜMjÁ‚\Ø¢g…gÑL×Õ™QW²4[¾°$,¼ûn/h\:d;³oÌ«ŸÌ({ ÌçËü¼íÊa/”aëTùÑ”â³îŠ3ŸöΟWuþƒ"ÄîÖ55,(»î,ÃwPÍ œ¥ß”p\ˆã.x»ówŠó"‹ëÉJeŸüÜY¯T¿Ä ¯­7ÿÃÿ>YíL·îÉçËd?p7£¡¤›_ÌŸdEŸ&ƒôÓïb{†Ù ¹Óùf‘à×,ˆu¨˜HÞÔbP8×ßÖ@ÁÄo™g20Ü-ÍQâ‹N){ÂÜ-,–§O&u.Ñ#iC ÊE‰žþ{Žÿ h‘º;zÓTýôš˜žèuì¿qô‡u»é}` ÏÄŒ²e¯å åbYeÙM@é3Ûµä0 î,Ô.×RíSt3ˆðiIm¼!–¿m?® œ)*'ü\òW*§3ø¬&µ,I²š,T².·¬âÿwGüþù(™"Ü~‹kï"\{éH¦ÆXàzýzõ"²dÛFû þäîÀu™ÝÙ7ä Y$“9zØ#u›3whƒÖ™®ì‡¸³ÁíN‡tgr¤L•Ú±ä›ý>‡#ÝçÔF}:õiiFÄl&f³l¦fw~®ÏGdhf›ây{H;;1ü$iÒ˪œ$e¾fŸ}>凇UJå½=Íl2Í3¯Ž„3ÃYáì0¯¶²MPu œ£ÏÈ'²=”OÂæh> Šþ|€äîVNNNj 5÷ð°M +åT°²79DŶIÁδ3{3@Ò½…ì[òx~svú…WÏÿU¼FQpHÑ’]íRƨŒ“ã§&é·µrÎ’‰‹W]õõŒQŒˆ»Ÿ›}Ǥ‘m-¹ã6ö">nF¦Œöï‚l¦—™ê²™~f3*i¬Y4Ô-´>`¥ûJIŽ-'œŸSšUV•Q™]WºÄ¶$d¸ÀJBÖr+Úš³ß ¿SúYø³Ò“á“¥Úá¥K2–”m³m ©3ÊB! ZÅ?¤*ЩTZ]*þ¢€\ÏÏВĝ°#ƒ¹Î?+åC +A^‰b6•–”óJË’Ó i©Si»rÒÒìò»¨Ëµ9ål²Ys#¬~Lvö¬pvv$Ì g„32ä²RB3d³ŠVB6€XË2lªaî&{µG©Î-©ÎËËÍ¥†jÑÚjBõ6ö3 Ýò ÝΘV¶›l…0Ö˜V”v•R¹´°´£”+e^Èô ++jsDÖ¯Ðu騠“u…˜ÙªëÑ©uRùr7t!íz-¹´Ú;ÙÎé‰v…¹2þªx(O#Ú–|~TQ¥­‰CÛ}5L Úî­H¦Rq2uæ)iŸ-+õcŠ6²NužuiÈ—UÿÁ"-ø£ó§û" ÿ »& 9ô ÅaE-ÁQjS´ K©•Y˜¦,2|/"”ø¬Ï¦ ïN| ¥‰o‡Z£°ÁØ«%Õë»ía©Tú[FÄr¶ Pb!gìø1+ølqAžv¨ô² ª,(sãýäž¹ÊVà—¬¶:~;¹(Þ=ìˆé÷$7ù‹äŸÇÛ†ÄÃJ\QpÿDç‡Ã±¼>_2Ê&Ù&Û ¼¾ZU‰±ÐVh¯óÖù&©Œ1[Ì>ÁÛœÞì³³_ï³ÝßòÔî¯äWÊÞrðzý. î—Ÿ±œi/Oíû#’‘\”F´æÛíEÁÒŒ¶ƒ$obdq®¡£[ÁêÙý=ª°’»¿¤€ÐñÏά™›ªQ‡…o€e ‘¶æ{¢ÑžœF"šÄ)αV)—åå^ÔO‡V2&>hAØÎmQ€à‚7ôÇ`zº&·&Ë2ÌóôA¬ ÚÖC;X˳ƒ-öi¬¥k°eèöŽRòå¯=í=ÚÈÐ×,8¬‹FôÇÏ4/H¶O874$¹±»#Û SÏ(%Û+‡ÚR¹kC+ç¡©õpJ+嬡άÐjìáÃøU+D}~¿F‹T©Ô¹©G蛌ÛôÀySâKv—’œ¾-5ÍžÑ3ËÕg”Ϙž±›Ã ó:aêŒînýmMȺ»›BrSwG÷ÜþD×¼,„ºwq.Ò½¢±c£ý‰Ý<=MÛð%‘H­Fõ†Èµ“{cäÚsQñäk§¶öQB:Fµõf`[ë. ¦ÔRVË*YAf˜@Ðû¨VéïمµKiå• +¥<¿Ÿ€R§¬#0¿Ÿ&ë„äƒ"ʃbh²Îïç“-±ÁÞ<Öi“u]ÉÞY©ÞZlXËn ìƒXcòøªæÃéAYd +ÃÀ–ê¹,tI oê¹0t©’éî‘‘·`¯žùÞ¶în¯Ž?ÿ¼ÖdŒàï!3Y¬|•{Ë!äűÛ“g3«µ{V÷ŒPyH:Ž’¬ +°bš·Mñp‡CêŸ|9…æÀ£Æ0 b oê&e*ÿhšPÅP#`$ÔCŒ†&‡6þ8fB;Ì…y0·p,‚Åð X +Ëà—°VÀ…°VÁj¸.ƒ+‰¡¿±d£gý?Mü¨ŸI|œø0qÿ1þgâXâ ¯$ÞO¼™x1ñZb_âO‰û'~—x2±#ñtbgâ¾Ä3‰Í˜nM<š¸3ñHâ–Ä–Äm‰×'6ÿà?Žÿï~h2‰‡”ÿúüá³ò %Aš¨‰†h‰Žè‰‰Iñ¿ +ÄBDb%6b'â$."7ñ/IWþÍTF…,HB$ƒ„I„d’,’MrH”ä’<’O +þ?Ε &´ éD«ºSU‚ÅôdÊÍ… ¨ˆf“†ÓQª¢<ö›LØ #…ɉSüÇ쟒ÕÑ…gôQÃ$F‘<ó§Ry +iXJæ9̦ò<槤ò*p!$ój¬ßm0)‰ÑÐXˆ"U-G*¹©gÆ“0¾Û º©i.Öýçþÿ¹ÇyJ~%Ö-Gú”‘®óq¶…ÿùÎÿ)¥ô3 +endstream +endobj +859 0 obj +15777 +endobj +860 0 obj +<< +/Type /XObject +/Subtype /Image +/BitsPerComponent 8 +/Width 676 +/Height 588 +/ColorSpace /DeviceRGB /Filter /DCTDecode +/Length 861 0 R +>> +stream +ÿØÿàJFIF``ÿÛC  + + + +    ÿÛC  ÿÀL¤"ÿÄ + ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ +%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ + ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ +$4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?ç¿bߨËÂøCáoøÏÂÚ‹¼eâí2wõ¤z®Ÿ¦Ù^F&´†+Iƒ[³i!‘ä’7‘d‘ÕYUF}Ê‚ž¸|~ H„‘¹~hDppåÓÔÊ£øCÿ&ñðþÉ¿„ÿôÅc]ÇÃ_‚úçÅÿ%¶›¤jwúdZœ—³ZG¸YÂÒmûØ!q±z`WÕñzð4èTö*¬ê¦Û–ýgßåcŸ€82†vñj¶%Ч‡åK–Öwæ]Z_gÕ¶r𣾢ƒ'Â/‚±‚BåþhJ2NæÓ©|÷M´þD§ÛbïÆ¿|£è¾ ñ4>ñgƒ5zóRhì#¿Ñnlîmíä’K²[¼’$ª"—t’Aå™JWÎ~&þÛ¾.´øoñ"ßú/‰Ëß ,¼c£x»QƒK7-sqmvë=ÌQϰ—0"„ŽÔ(–9ò¢#oFJ-ËN?rï5Ûû’×gÒúÙ,."NÊ£éöŸWùÉ_ª;‹Ù“Áñ—áGÁoü6ºÿ!Ö&±ðÂV +HøWðXcþ©¦ÿÈuÑk_ðQÿ…š/í¿ î/QµD¿]æôjz`ŠÚôÅæy-jn…ñÚ¦Tµhƒ6 ¬W޶ý¨oþ.~Ñ^Óôßx£Ãþñ‡5}^ õkK4‹ÄÇ%€¶º‡Ë–I¢]“HÞ\Â1*î m¼>+ 6¹iŦí¤W¯âµ]ÖªëSŽtqVþ$–—ÖOm|üšòz3ŸÖ¼áM4Ÿøµß†?êšhü‡XZo…!b?áXüÿªgáÿþC¯Tø‹koÀQ^=âü«’­}N/ÂM]Òþ¿Èù¬NcŠƒ²«/ü …Ä +vü4ø,¿÷Lü?ÿÈu…­^hV ˜þüP?ê™x{ÿªinÉ<ñYÁóŒf»£”àÿçÔðþGͱóö_øÿ3>ïÄšTlqð÷àÇþÿòT“ÅÚ`ÿš}ðcÿ ‡‡ù +³õE(Ì9ü+5˜çÒ¶YN þ}Gÿ_ädó|güý—þÿÌÜ>0ÓÉ?ñoþ Õ0ðïÿ!SÆV=¾üÿÃaáÏþB¬,í=è`XUÿdà¿çÌ?ðþD<Ûÿ?¥ÿ?ó6¿á2±ó ü?÷L<;ÿÈT‡ÆV_ô ü÷L<9ÿÈU‰´mßOû'ÿ>aÿ€¯ò!æØßùý?ü ÿ™´aÿ€¯òö¶7þOÿælÿÂceÿBÁŸü6ÿä*OøL¬óÿ"ÁŸü6ÿä*ÉòòzRhþÉÀÿϘà+ü…ý­ÿŸÓÿÀŸùšÿð™Yù~ ÿá°ðçÿ!RYÿ"Á¯ü6ÿäÆòǽ8&Ö©eXùóüžoŽÿŸÓÿÀŸùšÿð˜ÙÐ…ðgÿ ‡‡?ùøÊÏ?ò üÿÃaáÏþB¬£°¦˜ý±Oû#ÿ>aÿ€¯ò'û[ÿ?§ÿ?ó5¿á2³ÿ¡à×þò ð™Ùù¾ á°ðçÿ ÖG—ïI°Ñý‘ÿŸ0ÿÀWùö¶;þOÿækŸYÿÐ…ðgÿ ‡‡?ùøÒÐù¾ ÿá°ðçÿ ÖIŽœÓY?ìŒüù‡þ¿ÈÚøïùý?ü ÿ™®|ogÿBÁŸü6ÿäoü'¿äBø3ÿ†Ãßü…XÏZiN=j^QÿŸ0ÿÀWùý­ÿŸÓÿÀŸù4±“ðÁž?ê˜xsŸü’­ i²/?þ ÿÕ1ðïÿ!W#nÛHÈ­ 'ç­OöNþ|Ãÿ_ä5›cçô¿ð'þgEÿ ™Ÿù'ß?ðØøwÿ©GˆtÀäŸ|Çý“ÿòe)Ü´åPE)ÁϘà+üŠY¶7þKÿæki˜ÿ’{ðcÿ ‡‡ù +“þ/?òO¾ ÿá°ðïÿ!Vj/½)LT¼«ÿ>cÿ€¯ò)f¸Ïùý/ü ÿ™¦ÿä*?¶ôŸú'Ÿ?ðØøwÿ«)AÍ:—öN þ|Çÿ_äWö®3þ~Ëÿæj oIÏ?~ á±ðïÿ!Pu­'þ‰çÁü6>ÿä*˧¡È¤òœüùþ¿ÈÚ¸Ïùý/ü ÿ™£ý·¤ù§Ÿ?ðØøwÿ©?¶ôŸú'¿?ðØøwÿª…4¦j²ð_óæ?ø +ÿ!ÿjc?çì¿ð'þf˜Ö´‚8ø{ð_?öL|;ÿÈTméCþißÁü6ÿä*Ì+ÇZPHëGö^ þ|Çÿ_äÚ˜Ïùû/ü ÿ™¤5Í'?òO> ÿá°ðïÿ!S$×ô•òO> û¦ÿä*ÏqÞ¢—z?²°_óæ?ø +ÿ!¬Óÿ?eÿ?ó4ˆ´äž|Çý“ÿò#øIÿ¢yð_ÿ ‡‡ù +±¤àðMFòqÍ'”àÿçÔðþE¬Óÿ?eÿ?ó6›ÄºJÿÍ<ø-û&ÿä*ÄúG‡Ÿ¿ðØxwÿ«Ÿ–^=j).8㜲Œüúþ¿ÈÖ9¦/þ~Ëÿæu‘x“Eqÿ$ïà·þÿòX‹^ЉçáÏÁoü6>ÿä*â’ô¡ëSǨô¬¥”á?çÔðþFÑÍ1]jËïg}cªøvVþ|'þÉ—‡¿ù +º=<%u3áÁF?öLü?ÿÈuå–º¶ +œô®‡Cñ–Ëó~µÏ<« ÿ>£ÿ€£¢9ž'þ~Kïg©ZøÁs('áoÁOü6žÿä:¶žðKù%Ÿ?ðÚhü‡\΋­ ÝknßQÜ0MsK,Ã/ùw¹0̱jKïgQá„ÿüWÿ$Wà7þ} ÿ‘hÿ†sø +G>á·Ð¿ù¹ïøL¿f²9øÛñ³ÿ1ò–¾}ø»ñ®ûKø§®[|?ñN»®x2 a]ö¯§Å äêmâiw¯Ùáé9•Gî×…~ññ°ô!Z|‘ƒ^ªÈõñ*Q‡<¦Ÿ£¹ôžû3ü‚ÿIJ?Áo¬?¶Ö(ÄŸtWTOì­2M¨ ±»åvÂàeØõ&¶4¯Ùcàξ&m?öø#}¼žSÉÿ¢†Ú­ž=vÇ5ò~·ñ—Æ–~–hu³\k$Ê~ÍÜF‹¢ãøxêkÂ?¯¼Að½ôÍkÅ#J¿þÕ7»Ž–.¨„F>P»}.êÞ\Õ5$–ÿ©œq×›‹¾ßä}3{û)üÑ|ƒ¨þÏ¿lc¸“ÊI$øyáÖRÛY±ò@Äp­ÛW#ñöpø¥C᛫_ƒ¢xõ‰ƒˆþh¨²¨Òu)º‹l:ïk7"œeA=¯üg½ð÷ÃHôÝÅ#V¾þÕ¥—KÁÂc<Ûéùôï\O~0xÓV𵯙¨–;û¦‹ý1†þÁÖHþP+ÏÌðΖ¥{|?æo‡çFiG ö—}¶{žÏoàƒRõø3ðÿÝ4Ð?ù®ÅðÓà»/?þÿá´Ðù¾!Ó~+üE$gPoü‹ÿ‰­û?Š?Ìcý=ý»EÿÄ×ä8ž"­¼¾ÿø'õÃì MãOæ—ÿ"}}¢üð'ˆ´? jv²¿ÃûJmü7=—ÃO +ÞG«N§ç‡t(âÚDU‘nŒ% ‚Û|™vFŸ þA¬júf¡ðàf•ªè7ϧ_ÚKð÷Ã&ÞtU.že¼2ÄÅwm`®J:º0VVQ‹û!þ׺'ìÛð‹PѵOøêÿTø©3I [OaÛ¼+uè—Í½ËÆd’n!ßäGçü×­xŸÅÕ.ôx‚-cAÓd0Ø_ä›$º‡«ù3F®ƒ†R  ã }¼×0ú¾U§&ÛjëžöºÛ}§±ñ/‘G0̧„ÄR„a':N*vvºmièý7>«¹øyðf0qðcà ÿºi ò%q_?gσ_µ¤¶“áÂ(í[Âú»I™á ?JfeÔ´WYÅ©"¬ÒªÈ޲ –@¬7¶~jÕ>+|DÆ ÃþÝbÿâkÒÿdÿx“Äž.¼õÁœ/„õÃbTéªø_ÐSZðÆm•9ݦÖþ¾£ñ„°Ù~Q_EA8¯²•ÿ$~{ÿÁD~/ìKûA Gû\¾ñ›ˆ4s?›<²I, ·¼»›{˜ÕŽY‘˜îcEwßðpüœÂOû&Ñÿéû[¢¿`—c¨ÉÑ„ô‹iz#ùª9ªUg ZMú³ôkáü›ÏÂOû&þÿÓnifëMñ®·g¼¯g{ôK3ªr’‡ÀzŒqÆA#â|&¹´Óf†w÷ó›]?IøUáÍJòa‘¢··ðݤò²¨å˜GaxÉÀÈÎkÚìñHù$Ÿ1ÿ]ü1ÿ˺ós¼£Ãá–*³¦á6Öéwô>“‚øÏ0È+ã>§‡U•V”¯}9\­³ëÌÏ3½‚÷Wñ­Ö·q1É{%ô‚V!¤ÈU@$õ8œ2@×uñ#ÁÚwÆÿ†‡…¯õ=OH·ÔL./4æ„][.ƒÅ>0ñ§Œõ¿é¿Ø×:î­=’_YXä7Ù­c·¶ŠÖ.7±X7HÄgØwoþøVðjAõ ` WÅöž5—ÅòÞ[}Ÿdkû¿õ'ìÑåNXå°Ã#£öoø¸?áT|Möñáþ]ÓöjøºÇ…?Gý¼xcÿ—uëFxÉJ5"šÛÿSÿÒ’“îõzŸ*8Ùßš“wÿ._ý%ÛÓCɬ?`?‡^𦯢èºÇŠt;ÄÓjqé÷VÐý·PFêßU?¸;/­åÆÉ“iuŽ%”L#Œ.oí5ð;[ø«ðjÃá­×ˆ|uã±âvÚòëŚƓ§Ëá‹He…§@l¢´™ §• ŒLî$uŒ×³?ìÉñ}¿æ•|MÿÀ òö]øÀÝ>üLöñáþ]ÖP†[Æ +¢åVÓ¦5ùtÖÚ&£,Â.꛾¿Šµÿà=Tõ8þÆß¾%xŸ_Õü]௠øÆû[ŠX¤Öô«KÆÑ­b·XRÚÍÚ-ðD0Ò`1>d®Ùè)­~ÂÞÕt©´Èþ!|M²ÑµK}95« mNÑb×籆8 »¸v¶2‰Lp@$X^8¥òW|m–Ýë¯û+|anŸ >%ÿßÿ òî¡Ù7ãù%߇ý·ðÏÿ.ëEýœ¯j‘×=÷ï«o×]õ3qǸò:NÖ¶Ý4ÑvÙldøkö.ðlj>&E«/¾ Ùhøª/Eá{]BÙ4tÕVT™æ#ìæáÒIÝ¡yš ò»ª#„eû Ëw³C‘_=|>ýžþ,xvð=ÇÂÿˆûG¬þËY5êpøOâY"®ø‡¹éçÃÿü¶¯ *µ:2N+·¢_’IvI%¢=l,q2n¥X>gþmþm¶ú¶ÛÔ§ñÇöuÒþ<]øwP‹Ä>!ðw‰¼'u-Ö¯hMjolŒ±43G²ê íäŽH؆Yaq¬6º+ ¿ þÅžðt> ž-KĆ¥àíWP×ýÜð´úÕýô3Çsqu²%B_í0XV$BQU%u:g‡~ ÛM¹þüBÇý|øÿ–µ³¯ŽU0ß ~ ûyÐ?ùiEá—½Ïfÿà’ùë¹­h×’åpºÿ‡ÿ7oWÜùgÅŸ±†¼©èWšv»â>mj̺KjÿÚº­Ð»º·˜<  –6F‹Ë‘|µØ å^2ý’üªøfïB#ñ]†›¨ø"/jPÛÏhN£a r¤;In̳ÇçÌCDQIì/Š? > ø¶Å£´ø[ñ ç¥Ç‡óÕ…xˆÿbŒÚìÈÁXñûß òìWÐàk`"­*É|ߟáïIÛk¶÷w<,U,Â2½*múz§ù¥÷.Çað³OðÏõ}_KñÏ‹ôýÄo©ø]Âm"òi"Êß½µ{˜„›C²ÃJ…Ê#Q$®ò•w|.=Ž_Ø+ãdŸóN¾#ßÏ òî³ï࿯AÝðïâ/?ôÓÃ_ü»®úÊ ÓöËM·é·É+¤º&Ò²lójÒͤšT_á׿¯wfõHò_xÊ;áXû×–k7æâv9Í}-uÿÀøÉvrÿþ!Ÿø†¿ùwU[þ QñzC“ðëâýõá¯þ]×ÑPϲªjÞÙ~'Ï×ȳZŽþÅþÌ®û‡$Õ+¼°¯©ü—âñ|:ø„?à^ÿåÝG'ü{âëçþ-×Ä>Úð×ÿ/+¡q.Wÿ?—âsÿ«y§üù‡ùŸë¸%†:ÖÌl­}§uÿø½r¤»ø…Ïû^ÿååf\ÿÁ>0ÎN>øügßÃ_ü¼ªÿYò¿ùü¿>Í?çËü?Ìøëg½*Šú÷þÍñˆÿÌ…ãÿü¶¿ùy@ÿ‚3übþD/ÿåµÿËÊë6Uÿ?×ãþDÿ«Y§üùòLžô¨˜júøÁ¾1ÿ"ÿòÚÿåå(ÿ‚5übÏüˆ>?üü5ÿËÊk‰ò¯ùþ¿òú³šÏ—ø™òÀ;P_^ÿÛ¾1ÿЃãÿÏÃ_ü¼£þÝñ‹þ„þ~ÿåå?õŸ*ÿŸËñÿ!.ÍçËü?Ìùœ5õ×ü9»ãý>?üü5ÿËÊü·ãÿ™ÇÿŸ†¿ùyBâ|«þ¯Çü…þ¬f¿óåþæ|ŠSŽ) ++ë¿øswÆ/ú|ùøkÿ—”Û¾1ЃãÿÏÃ_ü¼¦¸£*ÿŸëñú±šÿχø™ò LûPTŠúïþÝñ‹þ„þ~ÿååðæïŒ_ô øÿóð×ÿ/*¿Öœ«þ¯Çü…þ«æ¿óáþæ|„Tf¥}zà¿üÈ?üü5ÿËÊ?áÍ¿¿èŸøÿóð×ÿ/(ÿZr¯ùþ¿òõc5ÿŸðÿ3ä/.‘—õ÷ü9³ãýÿˆŸ†¿ùyHàŸ¿è@øùøkÿ—”­Wüÿ_ùú¯šÿχø™ò.W¥FcúŠû þÕñ‹þ„ÿåµÿËÊCÿgøÄæAñÿþ[_ü¼¡ñFUÿ?×ãþC\1šÿχø™ñèLVmÎÑžx¯­ÿáÌ¿¿èAøÿ–×ÿ/)ñÿÁ¾1Çÿ2Äÿ„×ÿ/*?Ö|«þ¯Çü†¸c5ÿŸðÿ3å{Iw/Ö¦ +7f¾ªƒþïñŠ/ù§ÿãá¯þ^TßðèŒ8ÿ’{ñóð×ÿ/(ÿZ2¯ùü¿ò+ýYÍ?çËü?ÌùMTdS¶ä×Õcþ ñ„ù'¿¿? òòœ¿ðHŒ#þiçÄûëÃ_ü¼¥þ³å_óù~?äWúµšÏ—ø™òCô§ÏNõõoü:#ãýψ_÷׆¿ùyH?àÿGüÓψ_÷׆¿ùyKýfÊÿçúüJ\5šÏ—ø™ò–Þy§Ü1Ž•õYÿ‚D|a#þIçÄ/ûëÃ?ü¼¥_ø$WÆÿšwñ þúðÏÿ/)>&ÊÿçúüJÿVó?ùòÿå3;b.Ó_Wø$gÆÿ4ëâýõáŸþ^Rø$WÆ?äüBð/ ÿòò—úÍ•ÿÏåø‚á¼Ïþ|¿ÃüÏ•4WÕƒþ ñ„ù'ÿï¯ ÿòòƒÿ‹øÀæüCÿ¾¼3ÿËÊ_ë.Wÿ?—â?õo3ÿŸ/ðÿ3å:+ê¯øtWÆú'ÿï¯ ÿòòøtWÆú'ÿï¯ ÿòòõ“+ÿŸëñáÌÏþ|¿ÀùSj7#œŒWÕÿð诌?ôNþ!ÿß^ÿåå1ÿà¿Xñðïâÿxgÿ—”.%ÊÿçòüÈêægÿ>_à|›4;†}j¬ÊTŸJúèÿÁ ~1Ñ<ø‡ÿ}xgÿ—•ŸðGÏŒN?äž|Bÿ¾¼3ÿËÊ?Öl³þ/Äk‡3?ùòÿä ׎85Vg+×ô¯°ßþçñÇü“߈_Ÿ†ùyUåÿ‚3|d|ãáÿÄ!Ÿ ÿòòõ›+ÿŸËñÿ"—æóåþDzM‘Ö]ã½}zÿðEߌ¯ÿ2Äÿ„Ïÿ/j3ÿXøÏŸù¾ å³ÿËÚ—Ä™Wüþ_ù¸2ÿŸ,ù.=CiëÖ´tí`Æã&¾£?ðEŸŒÿô ü@ÿËkÿ—”èÿà‹ÿ#lÿÂñ ÿòö¢\C•¿ù|¿Hä9’ÿ—/ð<3Ã>"ÈuuÚv³æ(ɯWÓ¿àß,\øWß[‡Ã#ÿsµÐXÿÁ,>2Z€á¿ÄVú?†?ùyXK>Ëü¾FñÉ3ÿ.™å^ñV±]ÚÜ¡g¨Ä°ÎÖ²ˆ®aÙ,sG,NA ,sEˆH+º5ʰÈ=2ëºd nÕ´iŸt“x6SÝ›Ê×#'¾ÈÑ}t®þø&GÆæ™üG?öÓÃü¼«QÁ5þ/Æä˜üH?öÓÃü¼¯3ʪ˟Û$ü›G¥‡Áft£Ê©6¼Ògž&§¦8ÿ—‡ðƒ¼ÿ悞5 7þ‚^ÿÂóÿš +ôuÿ‚qü]Qÿ$»âIÿ¶¾ÿååJ?àqÏÂ߉_÷÷Ãü¼®'‰ËzWÿÉ™×Z?‚<êÛW³û5ÌskZ-Ê\^ЯàK!o²Û[m\k íÙiù‰;‹à€·ÚWý4ü!®ÿù^ŒŸðNÿ‹ŠyøYñ+þþøcÿ—•'ü;×âØÿšWñ/þþø_ÿ—•·Ë–Š·þLͽ–`÷¥ø#Îà»Ó ùuÿá wÿËê—QÓ ×’ÀCâ +ÌXÜÉsµ|rë1{K›B¯w8òî¤#ip^HCþ ûñn3ŸøU_óÿ]¼/ÿËʹiû |Z¶ Ÿ„ÿÒo ÿòò°®òÊÐtêU¼_Nftajf˜zªµv’ÙÙQiðÞÖ.F¿á£ú.ÿùZø>Þ1íß þºÿåõz¼_±WÅxÇ?þ'ûoáþ^Sÿá‹þ+ÿ$‹âýÿð·ÿ/+Ä—ðܾ$¾ö}48Ï‹#µI/’ÿ#Ê¿áƒþƒÞÿ +ëÿ—Ô7ƒ aÿ!ï ÿáuÿËêõqû|UóH¾'ÿàG…¿ùyJ?cOŠËÿ4‡âþx[ÿ—•êç ÿ,~öiþ»qoüý—ܸøkotüT_]ÿòú´4OYx='’Þñ5+ûË6°icÒF™mgnÓE4‰ &ââBÒI ï$Í‘Jª€9T±¿ÅQÿ4‡âþx[ÿ—•ËüAøKâ…ú„'ðÇŠ|#©^XÏ©ÙC¬ÿf:ßÛÛÏkíXß]€ÑÉ{k•—ËÜ%%Km`;òü§$¡^3Â¥ÍÓVÏ34â> ÅáåK98uÑ–ðpüœÂOû&Ñÿéû[¢ÿ®h„ŸöMãÿÓö·Erâ¿?Wù‹ ÿsEù º>Gì/¢ÿÙ³ÿÔ6:ýmÕ~*›9î@Žbbfåã>õù%£øÁ½þÈ-—þ¡±×ê/ÄŸGÑõ»ÛM.ÿ[ºµ†yáÓ¬š¹¿uVe†#4‘Ä$r©’DL°Üê2ç9§ÍB’[û==lrd’j¥ñ³ä¿Øóþ +µ¬ümø eãO|kø u}xš!¾Ð|5ák«›ß Ï}{ ¿Ù/5™å/#Iä#´Pˆäo1Õ•:ôÿÁTt}+Àš–¥ãáy¢%3wÿ²Ÿì‡ãŸøŠëPñ^»ý•àÏüTñWŠ4ß ÉáÉm5;©äÔµíç{Ö¸Û%›Gqç¢-°fcyÍÈy¥EI8RVѵ}Ò÷»Ù½dígw¥ÔmmæíQ»»ÛMž“zuZÆ+É=œ¯Nýž¿à¬øíðïÀ>4Ô/WÀZg‰ü+¨øŠÿF×4+ø%‰-Ñ縋Pœ[Ãö[u¹¤0²Ïæ+Fê"pzk?ø+7Â9ü ­xŠë^Ö´]7ÃÆÀß®·áOH»†;éÖÞÒqmus½¼²¶ÅÄJ¿Ïò6\av¶æ¯ÿüñ_Äí"þãÇßtkÄ÷xz kÝ#¯¥Ù[Yi:¬Z—–mžòwyç‘^_8"/dKµÄ›û9¤•£×É9KÍÞË—KéwiJÊ!)E$Ó»»û¯~ÏÕ+¥woN·ÿ‚©ü1¼ðoöÔž0¸Y¶—‚õ™5ØïÒÜ\¼ ¥­±¾R "RZ¢6VÎÒ ö/ŒKg ñÃx©: I ‰À##r¶O¨ Њù?ãü¿Wø“sñ +ëDñW…tÍGÇ~$·ñº·†.¯®ü6ðéi¡ì'µÔlæ·»A‘nRE*$dØA,~ðß„ÛÃþ°°’îïQ’ÊÚ;vºº`ÓÜ”P¦Ild$ÑN„[š³÷ôŸ{˾æS“Mr»§{ùk¢ûº÷]6:iþ- vO•RGÊ?ƾ$ðÇükÂ~+ý¾k¶^=øA{ñ‡ÅW>³Ô<)m­Á$ÐM{¨Ú[ÞŘº7*ñE4̉(P ë¤ú/…5;ËM.ÿ[º´´–htë&…noÝP•†#4‘Ä$r©’DL°Üê2Ãâ[?xúÓö%ð?ÁßøPÿ˜ø4èû_ƒGÛ?²ï­nÿÔÂGòy¿fÙþ±¶oÏÍŒ*—’Òðû¹Ÿ7ák÷èi ûºî}û@ÿÁTü3ào†ß¿á¸ºÔ|càOë:™¾Ð5¡Þ_iöÒI%ªßlK[‰#tÛ,\SË”¦7Û±üSá–™ã8|)«k·xž ?NÔã‡C¾’ËJ¼½† mc¸ºXšÞÜOöˆÖ&šUY”VgGQàsÿÁ,,µŠ‹¥Ýü,µ±ø™oâ]bãá´sxËJ“XŠa(Â^GçA³ÈV7·bÛ“€ôÏþÆ>9øƒñûã•wâáÿ†×¾0ðõíݬþ”Þx’; #GpÖWßhDŠžØÅ7îgÈÑZ'ªhQMÅN;Æ-ù>kI_¦l¥¶‰Ù•U­y‰ÎÞkÜä¿þM¦žmh}Õÿ _þ™Ïÿ|ñ£þ¿ý3ŸþùãXŸÙ#ÐÑý’= mõz]Œ9ämÿÂ×ÿ¦sÿß#ühÿ…¯ÿLçÿ¾GøÖ'öHô4dCGÕévyðµÿéœÿ÷Èÿ?ákÿÓ9ÿï‘þ5‰ý’= Ù#ÐÑõz]ƒžFßü-úg?ýò?ÆøZÿôÎûäbdCGöHô4}^—`ç‘·ÿ _þ™Ïÿ|ñ£þ¿ý3ŸþùãXŸÙ#ÐÑý’= W¥Ø9ämÿÂ×ÿ¦sÿß#ühÿ…¯ÿLçÿ¾GøÖ'öHô4dCGÕévyðµÿéœÿ÷Èÿ?ákÿÓ9ÿï‘þ5‰ý’= Ù#ÐÑõz]ƒžFßü-úg?ýò?ÆøZÿôÎûäbdCGöHô4}^—`ç‘·ÿ _þ™Ïÿ|ñ£þ¿ý3ŸþùãXŸÙ#ÐÑý’= W¥Ø9ämÿÂ×ÿ¦sÿß#ühÿ…¯ÿLçÿ¾GøÖ'öHô4dCGÕévyðµÿéœÿ÷Èÿ?ákÿÓ9ÿï‘þ5‰ý’= Ù#ÐÑõz]ƒžFßü-úg?ýò?ÆøZÿôÎûäbdCGöHô4}^—`ç‘·ÿ _þ™Ïÿ|ñ£þ¿ý3ŸþùãXŸÙ#ÐÑý’= W¥Ø9ämÿÂ×ÿ¦sÿß#ühÿ…¯ÿLçÿ¾GøÖ'öHô4dCGÕévyðµÿéœÿ÷Èÿ?ákÿÓ9ÿï‘þ5‰ý’= Ù#ÐÑõz]ƒžFßü-úg?ýò?ÆøZÿôÎûäbdCGöHô4}^—`ç‘·ÿ _þ™Ïÿ|ñ£þ¿ý3ŸþùãXŸÙ#ÐÑý’= W¥Ø9ämÿÂ×ÿ¦sÿß#ühÿ…¯ÿLçÿ¾GøÖ'öHô4dCGÕévyðµÿéœÿ÷Èÿ?ákÿÓ9ÿï‘þ5‰ý’= Ù#ÐÑõz]ƒžFßü-úg?ýò?ÆøZÿôÎûäbdCGöHô4}^—`ç‘·ÿ _þ™Ïÿ|ñ£þ¿ý3ŸþùãXŸÙ#ÐÑý’= W¥Ø9ämÿÂ×ÿ¦sÿß#ühÿ…¯ÿLçÿ¾GøÖ'öHô4dCGÕévyðµÿéœÿ÷Èÿ?ákÿÓ9ÿï‘þ5‰ý’= Ù#ÐÑõz]ƒžFßü-úg?ýò?ÆøZÿôÎûäbdCGöHô4}^—`ç‘·ÿ _þ™Ïÿ|ñ£þ¿ý3ŸþùãXŸÙ#ÐÑý’= W¥Ø9ämÿÂ×ÿ¦sÿß#ühÿ…¯ÿLçÿ¾GøÖ'öHô4dCGÕévyðµÿéœÿ÷Èÿ?ákÿÓ9ÿï‘þ5‰ý’= Ù#ÐÑõz]ƒžFßü-úg?ýò?ÆøZÿôÎûäbdCGöHô4}^—`ç‘·ÿ _þ™Ïÿ|ñ£þ¿ý3ŸþùãXŸÙ#ÐÑý’= W¥Ø9ämÿÂ×ÿ¦sÿß#ühÿ…¯ÿLçÿ¾GøÖ'öHô4dCGÕévyðµÿéœÿ÷Èÿ?ákÿÓ9ÿï‘þ5‰ý’= Ù#ÐÑõz]ƒžFßü-úg?ýò?ÆøZÿôÎûäbdCGöHô4}^—`ç‘·ÿ _þ™Ïÿ|ñ£þ¿ý3ŸþùãXŸÙ#ÐÑý’= W¥Ø9ämÿÂ×ÿ¦sÿß#ükäø(ÿ‰¿á&ø³àgÚëåx7ÄËó ÌWÂÞõôçöHô5ò·ü&×ìß<ðw‰ôëájêÀÑ„qqîqæo ;ö??à¿ßòp ì›Çÿ§ínŠOø/ïüœÂ_û&ñÿéû[¢§üyú¿Ìà üz/ÈýÒaú|³ÿÔ6:ó/øy?ƳÓÄAÿ¹KHÿäZõ-"~Â:#Õ³ÿÔ6:ù»LðŽ¢ä +ýs‚ò¼.2úÕ8Ï–íÍí~kÚûl~aÄyŽ' ?öyÊ7œïfÕíËÛÔô$ÿ‚üp~šî”îRÒ?ù—þ9ñÇþƒºWþZGÿ"×=§x'R*€ø«ÿð†_"Û)=þZûwÃ92ÿ—4ÿðÿ‘ó+ˆ3G¯¶Ÿþ/ó/Iÿ#øÜuý$Ü¥¤ò-BÿðSqŸ›ÄZ8úøOHÿäZÁÕü)xGüzcØ-sÚ‡ƒ¯ØŸôGÁôCJ\-•Zñ¡MÿÛ‘ÿ!Ljó+ÚU§ÿKüÎðÿÁM~4vñ.‹ÿ„žÿÈ´ƒþ +kñ¨¶‰4RìSÑÿù¼ºjÉ[IüÓ¬þj%Á6²úýÓX«9}ÿÝ©ÿàÿ#oõ‡kýbø¿Ìõˆ?मzx—E÷)hÿü‹Z6_·÷Ç+ÃÇŠ4oÃÂ:?ÿ"×™iþ¾\n· zð®ƒIð4¨ß8dÛêøWL8c(JóÃÓÿÀ#þFâÑ»F¼ÿð)™è6Ÿ¶¿Ç{ÁòøŸFÿÂGGÿäZžOÛãÚ©aâmŒvð–ŽöÖ±t + ™•}rOøV×ü"êÑñs‘þÞ1úW5L“&‹²ÂÓÿÀùC8ÍZ¿Ö'ÿ?ó(]~Ûÿ­Ï>&ÒGýÉÚ9ÿÛZ©'íëñÚ6Çü$ú_þšGÿ#T×þ;Î.¢ ñĘÍx}²˜Üg8ªþÁÉm«SÿÀWù ûk6½¾±?ü ÿ™Y¿oo';|M¤qëàí í­'ü7íÇåñˆAõðŽ?öÒ¶!ð“Üû…o¤‚®Ûü4iüyÇ_0c,—$[á¡ÿ€Çüc›æïjóÿÀ¥þg;íÓûCgþCÚ{ é?ü‰W"ý¼þ>›©hoþï…4¾òV·[áCgÂSž„L8¤Ÿà쓯méÿvàT¬§"_óüäSÌó‡ÿ/çÿKüÌAÿøÓoþ¾ûIO +éü‹SÛÁH>*“ûÝKMO é_ü‹MÔþLU™tÍ`ýÙ³ý+ž¾øC-¤˜6^ Sê$ÈþU×K(ÉØz_ø?Èåži›'­zŸøÿÌí,¿à¢_¦ÆýcM\ÿÔ¯¥qÿ’Õ£íçñíÏéQ“Üø[I äµpZÃö@0¾"B8ÆÊ·ô‡ó°:Ñí@§?¥:™FK«SÿÀ#ÿÈ…<Ó6oýâ§þ/ó:{?Û#â¥ì‹·ÅÚ Rz é?ü[Ö_µÅk…|Oáù8ÉÏ…´±Ÿü—¬¯|8—†Þœ~Ùk®±ðe¼Q’'lúÀ£5äWÂe1vŽŸþ ‡ÿ"zT1Y›W–"§þ/ó+CûS|MŒâ]_FouðΘ?öÞ§“ö”ø—0uÝ:<úxgJãóµ5a|a#€Ð Ž;-lèþ°vÛäyš¸gC+Š¿Õ©ÿàÿ#²ŒÅéõ‰ÿàrÿ3–o®I1x¦Éoø¥tvÿÛJ|¾3\ÆšZ“Ù¼¤ý·ê:WÃûÇð–¶-¾XGÉÔGçÔ«–Å醧ÿ‚áþGd!˜=ñÿÀåþg“Zxëãdã'Ç>ìþÒ—?•½gj?¾7é®@ño…¥×ÂúZçÿ%«Ü[À°Æ„¢Êo˜Vuï€çœü‘HÃÝÅE:ù}õÃRÿÁpÿ"çKm1?ð9ÿ™à×´÷Æ­=þ}oÃrýÏ i|ÿäµYÓ?kO‹3¶Ù/´F>ÞÓ?ù½‚_„÷³ô²õ‘ªÓcøG¨Br4˜[þÿ]®¾PÕž—þò9}žfž˜ŠŸø¿ÌóX?iŠÊûžÿFt=‡‡4°GþKÕ=sö´øeÍö™?‰|7¥·èmÍzü? u4:dwÇ—Ïè* ß\¤Má¥p}Je +™O6¸ZOþ݇ù(æVÿx©ÿKüÏÓ¿lˆ³Ì¾%°E?õ*i'ù-]¿†hj›Kø«Glö ikü­ë¡—@ŠÄþó§ýñ¨†³¤Ø¯á¨â#®JºÔòê‹÷xH/HÓÿ"iTÇÁûø™üå?ó7´/‹¾'um_Ã×÷°Ê].™ñgU¹pŽ46õeÑlùÿÈUÀxx}ý¦}þ„V¾…¯èÈ V³DÞoþ*¼šÙf«ý^+þÝèztsEíí›ÿ·¥úž„¾#ÖïcÝ èËŸMÈŸýP\]x¹ù†}#Ÿú€Øý£SøVæÆ`¾[0³?zÏÃÿ xzñ“ûBDç¨Þ¸þy¯Ä¼>_cÿn/ò=¬;ÄWÑU’ÿ·™áz­×Ä{uÌ- ã±Yý¥\þ§â‹ÖÈZßþ9}ŸÃÖcÿiWÜv<q€ÑGA3ú­©|ð]Ø-2†ì. ÁKˆ°1vž?:q;jd¸¹+Ç/ü ŸžúïÆoŽ!8Ð|/tx´;Nò r·ÿµÿÆ*R²ø;F`:ŸøG혋úWß¾6ýž¼?m†Ô<¬9¼'ʼ—]øIc ¬$´˜(î _K€Î²Š«ÞÁÓöê_©àâò¼Î›Ó5ÿo6|«í¥ñ†wÇü!úHÓA´þ°×Cáïڛⶥ"ùÞÒ"¨Ú?{½·Â½.9FdçþzµzÂïÙçI×Iq=¡ä¸9ýV¶ÆæÙ5(s}Jšÿ·L°¹~kR|¿Z›ÿ·ü7ñoÇúÂþÿJРϦ‹gŸÈÃ]øƒÇ3Æ +/‡ÐŸïhüj¾¾Ó?g_ é1)”]9åç?Ð +¹7¿1Û$I1þ¹ý+äjñ\åû¼,mþ}-<——¿ˆ—þχµÏ|R±RÖ°øVofЭ?¤USFø£ñ& ÂêO†Xgªhö£ÿhŠû­gj#t1\m=6\±­r_¿g½Ãú[\XÍv²ÂI&à%­¨q[Qªo ¿î%ùUÉs/h±·ø™óîƒãÍ^òܽ7C‰‡]ºU§?ù +¯Μ5¦Œ?îkÿÆêÆ«¦,RÁ$qXÚŒ_a‰£y6Œà šô 7uJ+äŽ'‰ÄÃGR_{-Mã«•p’z6‘h?öE{ãíBÆDéúj,‡†]чþŠæ¼gâg5MCZŠÎÎÓP„3cÍX‰ ïšú#àgìû¬x£áͭƣ⻠lݲñÎàM8Éàsõ®œn_ƒÂQjÑŠO¥µü†‹ÄÕt©JNÞæÊÚn­w$(ÑiQ´øØÇE´*Ù÷òºUjº§‡µsg,lSžˆú #óнÄü¶Ò´]:+ÏÃ%¬ƒìÓ˜ãôßžGÖ¹Œ^øãJ±¹ñM¬«4dCª@bà1Sƒø×ÏáñX*•l¡kö{Û¿zûjµ \)ÝÎWÓíwÿ·Õ>5ê^4_ˆtÏíEA)‹ûÏæBÍþ§Ú±¬?hMWVñEönºlšŽž7M +èV'o`?Ô÷"ºo|·ñGÆÐƒÇvZ5ölɰÛDwkÇÊAã½sþø!§ë¼C;øêÇB–Ö5&é@‘uLpvöíž9æ¾®• «Ù¹:qºŠ[ÿ‡gåªê|åJù—:Šœ­Ío‹¥¿Å¿®¡©þÒ~3oO¥išž¡- âdЬ„q’>î|œëQÚþÐßooÚÝ|9§#Ú´K ª=IòkÑ>ü6MNË^¼oÃbÖìY3é.Ý2që\懦jú´Ò»^Ϊpoâ÷Àâº# µ¹F8zw·_¹# TÇ¥J¼õóé÷ÜÜÑ|SâélÔ\¶çXÅBû©«ÏâEiҹ캀ú&°µo4ó4'»08`KñoM{ƒ kÐÉ!ê‚L…sG,§SXчþ¿ÈèyHhêËÿæmëß|E¤‰{ßجc8}Á˜ÿäóŸþØZ•ŒÅ5ÿ[¼gŸØ3ÃÉÇó®ÖÒÇBñB¶8¸^¸VëùVŒ~xؼ“ildÇPMzL&[rÖæü¡ÕXœV>Qæ¥]¥ç)~Œó‹Û»]‚Ï`ñ>„ó±Àsá½4øyùUI¿nØYücáöy9-Þ\mq·V›o8WÀ?¨¬°yvQZ4¿ëÜ?ÈÓÄáàïV£õòævú×ímã26±£³(ûÒh:P'ðõç~"ý½~)Ãvëk­h1 <á½)þ“Wêúóý·lºEÙþ7É?­už±Óõè‘fÓ¯à~ÅJúº|9•Ñ=L59Û‘ÿ#ç'Ÿf5eË D×ý¿/ó;]öÁøç¯8û>¹¢0>¾Ò@ù+]®ƒñãæ²€¿‰¼5}|/¤Ÿýµ«?|/¡ØÅ{=Eˆë¼°Ízž‹ká¨QÐÙOûXþ¦¾w¶›j–Ÿþ ‰îàç˜M'S?üG ~5¤{¦ñ®ÿð–’öÚ¨êÿ>+éKx¿Lr=<%¤sÿ’Õëò^è  wÈÿæ¼W«øwÈo1;væÑú¤¥®Ÿþ ‡ùÕ^&1Ó?ü/ó1ÑÓÁú7ÿ"Õ†:l–êF•©+{ÄjÌŸ +´ò€ÿfê ÿÅ?õW+[Їþ¿È_ëcÒ´ÿð'þdËÿ(øæ½|]¤·ýÉú(ÿÛJéþ~Òþ8ý¡þ2jð™ê¶š¡Ñüö3‘e§ù~n­¢oÏÙ¡~|´ûÙÆ8ÆNxMCáæ›lm.“ýêéeý&×KøÏ® dtà«ÝÅ»ãVÑq^Nø6xŠ šqÕE'¬â·±èeî2¾.4kT“MKG&Ö‘okŸ#Á~Î~?ü$ÿ²oþŸµº)?à¿c¾Ù7ÿOÚÝøn/øóõ™úÞø0ô_‘ú1£Äì¡“ù –ú‡G^K¡ÝjƒªÚ;“^Å¡ÄüóCnä‚Yÿê|“c¬ßÇÿ/ò{f¿fðý)S¨¿»Oÿn?'â×j‰ÿ~§þÚ{Ýî #ÉKP}sR\j÷°!Ê[μ^ vü'ü…%ÞÿëÔw~#½TçT˜ÿÀ¿úõú Àuvþ¾gÉ,_Eý~ªÜk×Åñä[~äþ”‘k…†ë{b{œšñ™¼Gv[&þcõoþ½:Ýgþ?§À÷ÿëÓTa·õù‹ÚËëò=º»™FM­¹Ï\1Å8Ër bÎ/|^Cgâ«„ý6ä{äUÁ㙢?ñýwøOêSBúÏF™ê†æì-2zu5ÅÝÓ¿`sëÉÿ +óx>$Ës{|ÀwÈ­;?‹(„¸¾?ˆ¨xV¶³ûËUÓÞèènî¯b ”ƒ<}ãUÞ¥) YÉÿ}}ÅË2£{\¸ïœf´í¾.i…0àñýÑEªÇþ]Ü/Mï;åÚjŽç6÷=·šŸO“SÞ»lç qÉ­§øÇ¦‚q Ïä(,ŒAqÛ#ü*œ«5od$©'hièw:€ýF>ãšéìo¯ööê™®6ŽVÑD7@¼?–ïö’Kt!aºê?¼ú¸Zóÿ—ge¯^+§8ÊÒgª§-GP’âÞN-m_=?Ò£ÌÔº^½{Œiöl=MìU™¨è¶ë)ck¥g§Í*Ó¬mlâ`ÏAzhÿºyb㪿õês©IKúÿ#Ð4^¹³±Qÿ_±ÿ…n?. ƒ&ÚËú}ޏ½ûO@ò¼<¿ð5?ÈUË¿iÆA>U'ù-y50êRø?ó=*uÚÅý}ÅÍSâÍÝ«`[Ùí>š”B¥Ñþ&__0Ìq.zbõùWªx¦Í¦ýßö÷m¿öZ›Hñ|"@»ìPc¬vŽ1úWCÀÇ“H~f+.mgù¹¥ø®îá΋ÿmÁ­4Öî˜gí$}¼ÛOñ ÙQ걕þ•¡ý¡g/[û¤˜¯*¦]¿ц+Mÿ¶oÞ)À½`?ߦ\ë÷3EóÞÇw®6&ÒY{ÛÂ¥ÃU°<=äfK«æ=8¹ñ¨xh®î)W“ëøø³_1¡Ýx?íó^Eã¿È®Æ;ÖϱÿëW¥jú_…ï?‚úCØ›‡?û5sš·„<30;lælu-#Ÿë^ÎTéÚñrÿ3ËÆF¤ökïgÝ4ûLó®ïþµw^ñ[9Œ4ŽÇ¯Zn¯áo[·É`2:eøÖ4úT0¿ú$%ìôüëÜœéV”lyJR»w=ûÁ¾&!Sæ8ÿ{é¾ñpˆ.éSÜ0ÿ +ù +Îöò *ÇrÐÔ×zÆ ŠBÇy–ã½|ö'"WñX÷(gšØûoþkeŒ=Éÿy­éž7´3ô—ëкý–¿=u»Íbæ\$w™ÿy_ð–³<é˜nòOrÇúW$ø>š‡3ª¾ïø'DxžnvTÿø醉âDž,$Òa¸âAÿÄU»Ÿ*ípÅ›êÀÿì•ñƒ4}Oj #¸@}¥zV…á÷X”̳óÓ$×Ëâ¸z¥uSðÿ‚}:HëÇþôU¾‘ O‰ùöÒi9Åø ‘ü’¸O‚¿³æâÛ(no’åPòq0QŠö€>ÒlÂڵ͙òÕ.9?Ÿò˜úøzsöNM¿Oø'Ñ`èשh¢’õÿ€r'ñQ$¦0F%¿œf¼ëUñb=Þ<Ȉø¡ÜOþB¯^ñ7Á¤{¯|SªZ«ôÝ~ªÓŠãuo€ž¶œI?Œï”7<ê+Zà±8Dµ¿Ê,ÏCßO½øÆíª U xÈ‹ÿÈUè2ø¦úþĦ7)‡ˆÿ¢ë—ðŸÁï[m¼[{,Œp¸ÔBŸÊ»uøG¤fùi®ë +¤ŸÚ''úW6¶ÔºOç« K¡f×ÉŸ>üUOìNY§Ž5CÈ"-ƒù +ðün·Óï¾Ín<ÉQ—9ükìo‰ß²…§â??a_…þñEÄZ¬í€¼’ɪ” ô +I5õ¹&m—4•nfíÒ:ió>o6Ëq×nŸ*^oþç>¾›W&™J³òcÈסh€Çû¸'ûØ5ÏÀév²½ŸŠµ$EáâbÌçÙPŸ©"» ?„^Ò| ctšýêÉpÁ™f½Yî¥ã ç‹ WN3BVqæÕÛág>Z:JÚy£šÔïÌp‘[Éa‚ÊùÛøWüPñmÿÃ9MüKs©i.Û$Ø2aø¸ôú×Û«û=x'O¶ÓíOœ'»+òËrZIF2Aãëڸϋ| §ü@дY HtËðÆê;6îxÜXáTÿ‘^~]ÄUW•ÂMjÞ›¥óß±ÛŽÉqÔ’zuêþGÂðüjÓu™-^sæèúŽà³ùŠÒ!?9ã®1Wlt5ZHÀ†[[™<ä¶–‹¾r¼{óƒ^Ñû&ü)Ðk÷Ñ,#°%ŧ=¹¼ ¹çqÈäŒt­O†ß³WÂ|zÖô;÷±šßB ÖYÔ +Kn q‡È-ž½}+ëªç˜(Cž”f£È¥ðô{uß¿ôš§”bå>ZŽ-órïÕoÓc˜ð^­¥Ù]%¤÷ðÚÌß1W$•ÞßJîX›¡:ăqÈ9Û^—Ã=oÜO<°‹èÛ N‘ì;×ÉæµnªEu>—–Õö.gÀž2Óå´ÕäùXËeƒ‘øW£üÔŒ6`(ÇkÕ|sð£Â71'H"—<‘rTÿ:ãá'…ì¤Zj—–¸9o'Qe_ç^ü³Z8š5òÿ‚x±ËjЭΚ3×|7©$ð‚ ÜmÅmI,SAÉç+Ç|9ám>ÞbðøŸU`>êÿj3ùšïô*,w¶¡u1ÚpÙ¯—Åa¡tßÜ}¼¤¬×âgxææÚÚ-¼àr9¯š¾3xÞÃLY~YsþãqúWÕZφ´CLÌì»æ\òŸˆü¬ÓFáósŒ×±’ã(RšöŠ_#ÌÍpÕªG÷më¾;û}ãy0IÇ8â¶¼wqrá’W8ìd5ïþË_¤º.¯·žÚ‡ø×WáOÙ§Áv6»ã%Ž8Ìõöu8ƒ 5g÷Á>Z-yKu÷žnnD\Í(öó s^$Õ®-ܰšeÇ£šúÚO€ûí ·ýwÅs>&ý<,!™Tsþ—ç\Øn Âók÷Á7­’â9tkï>Poˆ>åϧßoñ xºêìœÝNÛ‡woñ¯¿ý™¼ $çh~?»zþubÏöbðLp—Ùs‘ЛŽ+ÑþÜÃ-\_ÝÿâþÈ®ôºûÏ£¹žáþûò{³t¾Ó®fùsþ5í³~ÎÞ +¶² ™U½MÆ1Tîþ ø^Ò Ö÷71ž¿%à¢yæjÑOîÿ‚(å5¢ï&¾ÿøcá«‹œn‡#ëÿ×®‹Bðä°¸.?RÕ¼ ¦Ù·îõMYAç‹îŸ­T³Ð ·#f·­(ÿ¯ÓúÖŸ´ZKð6„9«ñ;ë}&d•ÚîEQÕb)ɇŒÖ/‘Ä ×µaî×Dÿ:«wR'üŒƒy—ú×(»Þÿƒ:¥WK[ñFOŠ#K† ºŸb§Š‡à] ·øÓªaîðV¡Ó·üM´J³qá›Æf¯vÙë™f´>xnÏ@øÃtmfyüÿê[Ë>ìcVÐñüÍrñH¬®p¿XtþüM²Jmãã/)é,øOþ ú6þÐ ì›Çÿ§ínŠ_ø8cöøIÿdÞ?ý?ktWà§ûùÿ‰þgí_àÃÑ~Gé.ƒàžš!ÿª gÿ¨|uñÕŽ“ aûů²tÿwè‡ù –ú‡Ç_X<À6áøf¿dðòܳ¿òÓÿÛÉøºüêßÍSÿm7íô{s2¨ü*¾¡¦ZF1çO ©-.¬ÂŒÇ'>Ù¢ðÙÈ·™¿ WêM&º +›O[˜ÒØ[â_Ò¦´Òàl~÷õ«"àý’b©­-6ÞÌFžíì\V¤¯²5•GmÆÙxr)1‰€=~ð«xIBs: ÿ¶+sIºµˆÿÈ2ÛæUË~Ò@²°\ÿÓjÑÉ­"Rº»™ÉŸ +ƤǎüçúTðøR2Ã÷êGѿ¶ÅP)ÿW§¯ü“M4†'çìé8¢íl%Ü4ï«óæŒöZ´WÀ+äOÔõê;OˆP§C÷mÇ5b_ŠCq?rõ¬%*ý JR³x25cºâ!ô@­*xNÝM×àU[Ï‹œ±¹=:Yó|R»8üsMJ·Wý}ÁËO¢7n4+8£¹1çý__Ò°5˜"€6Ù¦`;ˆ¿úÕRûÇ—×Iƒû¾Ù‹¨ø‚ê`CNFkHÉÁ^L—-‘;Ü.Îyã+gHyخ߶\bj“4ÜÜ¿áZú~¡1#÷÷èMë)h‚tš;›y®!”º?Vâªê,à–O¹¬ËH¦½ŒáåüIªz•—Ùþô˜úšÕA's>vÑ©gx‘L q}Mw>×£r¸f#^UbФ£2)5Þø6þÍ6ƒ1ÈãŠÃ(\×'Øö j1ì_•Ûß?ýzê#{y£û÷ýk…ðÞ«fBs$ŸuVÞ#³Š<¾¾¬kä14¥Í¢gÓP𶬖âÒÑœfÒÁïÏõ­DÓæqþkϪdÖÏŒí “+ž¥ZÒ¼iÌË„Ú÷Wÿ­XN•^^¦°©O˜ômÃÖˆÛ;aôˆV«h”ùa‰~Š£úV†|L²¢ýò=È®…u•2¨OãÿÖ¯ +·:–§³IÁÇBî–Žˆ?à_à+ív¶Ð.sÃ1«ú½ÅÃ’#ϱ®~ä\³<}HÌšÞŒ[Z³ÒWÑ'˜ 3ŽøV?ÖªÍt¡OÌÄ{I•ăƒïÏôÙtÉqË`zãüH®”—s¶T¹Õ–Üd«¯¦úÕ‘yâ'’c‡eçÖ´¯ôs6N7z` ÿ#T%ðÛª“‰ÀÿsÏÕMSÝœóçèF<_ql’û¶Æ’_ˆ71¡Å•›ê“úÕ+ËqjäÙ±ÔnÏò©—⮓nTYD\p8?ʺ=”_à ˜ûF·•Š×µ&“÷Z]®Om±jÔð÷‹¼Gs Ù¥F§þ¸þf°o¾0Î$ýÜ6Ñdã‘“ý*;‹:•Ì„ £§îÐçZË 'á¥êÌ㈊—ÆÏ[Òµÿ¼`½­š.3óžGäj–¿ñ_WÑX«ZéÄŽû3üÍyü~1Ô¯£ù®nXÞRä*†³<óÄY™AÇ\n&¸¡—GŸ÷‰sÇK—Ülè5/ÚwWÓ¥9‡NAŸáŒf—Gý¨u}Fà/Úþêú«Ç¼Wi½Ýšp¥ze€¨¼# -r›¥’SžœŸóùW³ý‘„tù¹ý+ûOí-ÌÏ©3¶D2m?N•ëÐüSøy¨Ù¬~~Ðã~¯ƒÆæîNXP“]ÿ¤}Ž,ç…åY'ØøWâOu¨íd‘M+òŠñ Kŵö¤ÑÀ³ø~šxÏYøGv<ûÈtÙ›þ˜G‚,Wj~2ø3§ß™aѦ‘Aƣߓšör¾&ä…–Mú™åf4®ñ)/Så†/â2ñý®âþå‡_—bóõ¯eÑîõ=¨CL¡FAÁ8?ZöŸ +|Xø9Á¡Ó£ù&h|À¿‡5é6~\éñùo¤Çá#6êü1Åy™ŸU”ïõY/‘è`2Zq¾°ŸÌø»ÇúƵ2HZîã*0¥›Ÿ×ü+ä_ÚÄ0’GŠ+½Q9ãË Y‡¯¯ä~·üBñÂè-ÅäuÍÄ«À‚Òü–¾sø¹¯ü)‚aqöìÛ` +¼eÕ¥™½rz~¯o†ø–iýY¿‘åg¹4ZúÂ_3òêÛÅþ1¹½òEæ¸òG÷• †ð¯ ?e¯‰^%–ðÈoæHŽÄ,Ùõf5ïmñáN‹§Øáƒír4tÉþóc§á]‡~%ü8ƒÁ–Zu•ª^Ë)’O$ª_îŽçÜ××f9û«EÓú£×®Ÿyó8™Sª§õ…¡«áÍVþâÎ+ÇyP(ûù'ÐVGnµ) —"î`ì2‰,Þ€dWКÿÅ?‡š†‡á­2Úû%´‘Ë*B›V071®ã—ÅÞ|Oðø")t­5w\T*¸ê3Šüß ˜T•eû†¯~ùŸu_N4Ÿï“Ûïä|3ñ+×£Çë4»†§pˆ„¸m “ýÞœÔß§žëdz˜_$¦ $ó½|¿Ý"½“âíðãWý´ÒM¡4K}5áGT;‹r`xÏãPþÏÿ>ÁûOøå52é’L²[FXeHÜŽõ÷ˆú£”¨Jêš—ÞÒ±òKGë6e¬Úû•îkø52ùèÏŒ6É“ÐûñÍ]ñqk;ir¢¾s“òùW¡þÏþ5ð"jÚüZ¤QÉïKmÿ6$ìØ#Ÿj©âxVçỦM:ŒnZÒSË2ç¡÷?Zù9bçõ—N[¯¹ÿ—Sèㆇ°æS]ó>!øÉà¯ø›]šßP´³/1!ž7Ã+}Èü3ô¯×>jüe¯£É4ºQl«+ï{3ùŠÍý¦¼[yeãÛÔ¶¼¹U¶˜ìe†^}kÐe?ÚFÇÆÉ†|Yå¹›÷q]L~I}›=¿Z§a¡ñéªòòÿ#óy8ל—îÏÌú¯ödøákã¿ ÀY¤†á¬§;†½WXÖcû+1f*¡Åy7ÃP|>¾{)‹YÎC‡*µì#XÓáðÓE5ƒ}£´þ\zcùÎj¨z ¤Ð׽߶™žWÈ,¡¼×âׇ&·csgeþöþuÅ–VJwåoî:s +mÂÜÈùèx•"¾1ùŒàžœãùW øÅ6É cû™¦K/„c»óÁG=ÈÇç]·ƒÿá–Ä<ûz¾“‰‹§ð3ÂÂP’ŸÆˆäñŸ5© †:˜˜…q^3].â23·w÷ç^°óè‘X°(Ǩ šå|Wªx|DK(بôSŸÆ¼Ü-kOÝ‹;ñ4od +Õ´y§>MìÊ»¼E¾|±~êõÜáÝÒ½÷Vð»Ï¸éðçÜí5M¾ðÌvûþÆÊ=21_BñÓQø_Üa"åñ#ʵv(þW—ý—®wZ}b(ˆ‘nqî ¯~ŸÄ^·¶Ç•,•eê¾,ðÄvù2…í‡QÍiG2ÿ…øW¿ˆ|í^ß«¶ó2ýA¬Èu;Är<Ù+è=sÅþcœZËŸp?¥eE­ø^Y2Öp1ö*k¿ÛÎZò´q{GNdÏMBù×ä#Û4Ù.ïq‚×{šö³{á!ü{B¤ú üEAssár€¢Áž¸Ü3úÕ,KfDº)}¤xõ­ÅÓI†’l}Oõ¯Sý–7·Åý_vìÿÂ}÷ýE´Z”Þh1GÌG¡ºOƒ7v.Å’*ãÁZ‰|3WCÇOƼ*®ÞWR<¯Wý.'¯Ãô—×á+­¥ÿ¤³áø8 mý þú¦ñÿéû[¢ÿ¿´?ÂaÿTÚ/ý?kTWó¦/øóõ™û†ø0ô_‘ú]áèÿã]ÿªgÿ¨|uñ^Ÿl270QßšûsÃÐÿÆ·4&ÿªiÿ¨„uñv™¢K1ÆÖ¾p+ö_“q©þûqù7»MŠûi§e%Wt½½zRÞCS‰¸­] 2©'ó`•nfß• íšýFUa>4äõGÍîÆe Ôö¶[ԯϽu÷Þ û1' Ç<ñýj“:X?"Öˆ8½V¡.e£Ð̃Mû†’]3Ìé„}+Y|c M¨Ç/5"|Cx”z$`U9¾ÈJ {˜øjIËo3~¬C໩NEœÞ¼‚+]> ¼ _Ÿ¥*øþâWÄv…¾¬MCséU£ÖL‚ÏáýÙ6Àù`?­iCà)B|Én§ýàOò©l|[©Ì>K¤®qùÖöÞ±$DjŸ@+ Ôª´F°…?3ëÁnãËÏû#'ùUàוºÉÏû8­[ë½jäa¤lœð¨F*šèšœìr$bÜäö­c)[Þ’3”c}3î¼ +§«ôê ²5? ù\ ½=s]„ Ôf<¦©j°ß nîÏåóIÔ¥öÚ)B§ÙLòétfŠc‰môµôIq)A]¸øFáùx—¿Uû_‡Kf¹óè ¬ãRŒ]Ó)¬´hå†éíÓž‰­i% &oÒ»­_ÃÓC-ùüëŽÖ|:ò¹äç§Þ­ÔÔãÜÉÇ–]Ž~;5Šl™¾¼×EáËÛkg_2ë†k6¼Ï™Ïã]…ðá¤*ÅN>¸¬àœ7Ñ&¥kjvºŠtØÒ%síøÖÔß´ëxˆVœ9ùBÖV‰ðÎ,Ê9õoð­iþÁ4yØF{þ5çU–ËÞlí¤«¨èŽgZøÁm ‡jÈFx¥Ñ~7C £Hç?Ý&­ðŽ!{|Ü*]àôRÌÛžÕ³ú¯/‘šúÅôÜî<3ñüª(X +Ÿö°+¬·øûpÐä|¿î¡5ƒá/‚1Sör§±&»[?‚°4\ÆIö=JùìTð +[Ö8Î]ÎKZø÷4oóÍ>;…AYGö‡Š"=Ï=y ü«»Õ>[LŸêIúµs—À;[lŸ& G§zºrö¬Ñ5iãS½ÌñûF[¨â'9ëÍüÍSÔ?iùãìð”ÇBB¯ô5‘â‡k§†P#@8ϼ÷[ÑÄ ¢@ÅOE¯_ €ÁUÕ#ͯŒÅSѳ¾¸ý¤õ›æÂÈèIþ¸¢ŠºÖª k©yëŽ?¸¿xGRÔÝD67sÔ®Ñú×¥xgྩy +T‹>Û±Wˆ¥ƒ ¶HÎLU^­˜òk÷÷ûË—#Ý©ìÙÞÒ0>õéšìÿ ­¶æåËÈÆl?ÀÝ6Ìåâ’UÙ¶Šó%ša¢ùbzË«É]ž!wx« 6{ç5­áËKýB@-í¦|ñÀÀ¯TÐ4y?ÕÙ#'±Þi%ñ¶‘¥Må#oÇdà~”¥˜ó«SƒcŽ•Þ¤ì`ÛøT‚ËΕô8&¬Ãà+ÍR!ÉEõ‘°+aþ!Ûy_¹€nìrIιÍkÆÚËmBÑ©<`b¹#,DÞÉ2Tb·¹“⯇–z9ÍäåØÿ @3ÅEáuÓôÙ†Í3œn•÷Vͧ€µo€Û%‘ŸøˆÍuþý–oçÃܹ‰RÝëj¸êTéòÖ©©•<%IÎô¡¡{Áwñȱ“°EP1]rx¶[Wò„ŒŠ;ô¨m~Yx.Ï›å`8®Æ>0ƒK•s#âfÀJð!‰Ÿ¸®eÊT!ïèÎþ/‡œ)rx®—Gñ ·(ªôë_>éŸ`½¾UiP ô^?Zõßx–Í,‘ÕXàV8ì½Óލ×UæßŠ ÜÑ“²ºýx¯"ñµÆ©m©ó¤eÏ9rW¯jþ(2Ú·@Q‡ßa€?õÀjÔµÝTH…Þ6ç|ƒô²éªzÍ$èéÖ½—F-²ãvÒ8µq¾ønÚ"‡gÜz–aý;Wew¨Ç£Úœc +9Ïåæ5£V¥¡©è`©:tï= _5õÂ4hì?ºGjðß|ÔüS© î¯fg_¸±´Jë>0||Âëk˜ç€Ûº×‰êß´·æ ³1ÏÞþUïäØ bŠ$‘ãf˜Ì+—%K²æ­û,Í©Ün–yŽÓÆ“^ƒð‡öv}xç–G’eRXüƒÒ¼þ?ë2+!iÍÜ õ>õèÿ ~2êZ„ˆeF¢ òÞ§ó¯W ÅPjRV<ì°>Õ5sé/ xK{=ù,È2[=A\Ä¿†’k !gpåÈbÍtžñ-ÔöEäp8Ïzä¾'øÖóO¶šH”»d*ä×ÃaU¬hõ>»èûV‡Ë¿eË·ñ„—"âo1™Ü1É¿•7Á_³]æ­¥ïÚf<ˆÅ·rA-žTþ&üqÕ¡ñ%äq©Ã3mËtGøšç¡ý¡u2êPùaŸ›§'ükôúts QZ­ÏçS¯G¹öÃ?>›l€Èìç±<·¥u>&ð;ÜY°,À2`¶Zð¿ƒï5›x¼Ìc€H=»W»ÚkÓjúXRNqòœö¯Î³*š5ï6}Ƶ +´­ä/ÚöKRÕg¼ +¼„™r>µÀøöLû.°‚Ea‚Z3ϱ¯¨~7xWWÕlÛ줆OºsÈö¯7ð&‰¯i÷ánUˆðz}+ëðYYa¹œ•×Þ|Î/N5ùT]ŸÜ{çÁKÿè0Ú]3\G +…G',¡õ®·Äw `†AŽ@à× á=bòÆÍ7’ƒžÿ¯U|QñXòÔV>O4Ÿ3憧[àaŽQå³ì'¡|~L?­{ÇÃëH#´ +¡€ÇCþ5ð—ƒuÝkC¿ÄSÊ…N +±à×Ñÿ þ'ßËkwA£< Õ?áWœeµ%x²r¼t#>I#èMBÉ™ ƒÇL×üW³Q †Rúž+O_ñ¦£™hŠÈ¤z׈|Xø±©À®˜tã£ò¦¼¼§.ªê]3Ð̱ôÔ5E+ƒ– CUÜz7èŸZÚX”mF_Pqþ:ùc[ø—z×dºŽ½tÿ¾,Ü[\¢–dSÔçŠúšøeV<‘—¼|õ寢Ó!–Û Ç‚x5Éø·AM„Ç?QY ñMÆ» +옂Àzÿ*èo<¬jpoŠT•qÀ×Ϊn…KNV=·5V„ny¶¥áÈÌÜ«€¾ù©-4ôŒw5³â jú`&KGã©Q‘\?ˆo.cÝÆÆsE{tdꤔ&ªTÝÚ7.DK Ǩ9–kW´¶4{€üMs7^&½…Ο¯5“ªxæôFCËï^Œ0“½sŠxˆËK ñ&‘oæ6ÅÀ± þF°c³*ä5G±ÍQÖ1CÍN¥ãT¹_šâV?‰¬;ÝefbT»gÖ¨M)éS*²jÛ4’w$7ç9ÇãVm5hâ#$géT¦²zVjm;–â™ÔÙx† 0;t³§k0»}õyà%¬[josÈ­–#¤‘—°¶±=ƒDÕìó‡‘O®t–ú“ÆõÀÅx}¯Œ~Ê'#Ú­‰Ó¤{Sp¬jÓ§-T)ÎqÑ£Ú$º¶,0è§ÐAÔ­ <Íì+Ã.þ$ÞÍüOøš¡qã뎲}kc»5SŸcßßÅVvíÍÌX÷j®ß´ès›ˆ˜ý+çÉu›©Í;Ôå˜üòJŽJ]™jU;ŸC¿Å5âüU»ø¯hÃ÷w*àö +MxE­ìP°Ü‡êNkZÃÄ–ñpNÜ{V”¨Ño] êTª–‡£_x²mH“äUP&¸92GŸ÷IÅsV^5Tm9"®§ŽLÈB#gý£ŠïJ HXänOY%žŸrT2/<’1ý+oIŽXæ\ÝÀÓ&¼ÞóÇ2ƒ$j}ŽMT_<ï“4¬eÏçYN*Z6#&µH÷ýPŽ <Ëôö:èì59“ |2Gùô¯›4߬M½Ÿhÿmú*ètŠuúëÓž˜‰GyøŒ¹=TŽÚ8æ´q>†±ðþ™}†k½Äó€£ù×Q h:LELry¤u$×ÍÖ4»r»#¸˜ƒÕÛƒ]6•ûB<‘¨·Š8T{dו_*ÄI{­Ûäz4sz£éÝ"ÖÔ±bQôëZ‡P´µæ‘L +ùªÛã¼ÿgÜ×$c°âžÿå»…¶Í‚{“^<²íêÏN9Í´=÷Vñ¯–BÉïzãüCx5B\Ç÷>•åÑø²m^.fœƒÜqVÚÞî÷7Ká-¹oK,T·•LÃÚìûŸéÚ”…®5;yq÷¿JvàØÍ‘%»‘ݶ¨ý9®i¥Ò —q[‰cQüOå§åSÁã¿h¨Í%ݵ©=‘w°üy®ÇN³V‹“ùª¥$ï$¾óÓtm&΀­úˆsúšÓ¹ºµ´Œ/ÚÈè+Èeøãáˆa;Zîé‰êÙU?‡ÿZ£¹ø¿oªÚ³¶ÕWoþ•øÙñÓBðݳ¢ÞÀÎ8ÀmÇòòoÄoÚ ë‹­´ŒÀ÷ÎMy~­â ínbóK#=2Niöþ¼’4‰öxÛ¡qË~õø0ë–‚r}ÙóX¼T«¾j®Ë²;_ xêq¨¤ÒÌÜž„ä×Ñ_ |wý©K¸’xÎOå_'éx¶¸TY2Ù刯zødSÁTz‹™fv«2ñŸ@;×n2’«GÞ^÷C“ QÓ«î½®þéÑ^@xÃhç/Ú»H¯4«)6Æñ¾;“À¯n¾8kc $±¬œ$a0*¹ üN×µR;;c,“·û8 +=}«â±=ZmÎR²>®ŽwJ)B1»>½mvÊ(üfÔ&·±žcn¹\–™»óéY`xnu*i/ëúؼ^{CTzŸŒì"×õß[*ƒŽÄ'°õ5ÏKðô1ó#–pŠp}Mp4í_Ä +/.æ–†K‘Àöçô¯Oð7…õNó°’ÛM·â1Œ1ÜýkèjÓxUËδþ¬x´ª,CæäÜÅ? ÌsÍ9ù¾ï_¯Ö»o„¾6Ú‚ÌÓFÊ:|£¬}bø˜5”HÏ;rxè?Ïõ©|?âvÓÒ@ŠäBpûGÝÿç\µçZ¥&¯¹ÑF4éÔNÇѼ† 2¦@Uã©õ¬Ekui+yŠ)aõÇÿ^¼Å>0m=$ (‡?3`â²|Cñ>K¨—ÌY'ƒóW…G)¬ªóÅ\Ê›§Êp<ö­iåY,ìç=ÿ¹}Káè–3›%C}ßZíõKÃ}{l„9wËÇ'9ÿɽ·y¯Ä)ù‘ÆÈà ã _k‡­R1Qocå+Q¦äÚB|0Õ¤ðÅÛ[Ër¨!ëžã¯õ¯¦þüG´Õ4tÍÌlc;dzWÊ7þšöü`Ê»×ip?ê?*âWÇzçÂ-vE’i–ÙΜ…#†³µiºl§ÌÀñV‹û_>Ö÷‰pÅ¢9aÏ#¿äkص_Ú_Nø“à(õk;n­Çïc‚1_/[‡q4f’w‹ì},ïV.ëTzÿ‹>Éa¡¼öR BŒ²Žµó_ÅÏ6ù‘É\àžþàÖïÆÏíÏ ¶¥¢<“‹pEÜqï_,üjñIÖõYµ-?ÎÌÃÍŒñ†Ç?C^æO•{.i×W·ÞyžeíycEï÷ÍqNÖþ'^jk¶a+3t8äÒÁÂ…ΤßÈ12­Ur5ø’x’xžf*Jã±+7KñdšEÀ`w(5Ïkœ÷Ò»‡=0EbºÝÈͳyÇ^ÄVñíTæ‚6¥ƒN²gÓß ¿hË=-âŠæAS_Kü9ø×¢ëGåßÂY€8Îkó£¾XÃãè0kCEñ–¹áùÐÃ,Å{s\XŠô±?Æ‹Oºÿ#ª…*´?…$×gþgêÝ÷ìo-N^ Aõàךøìèš‹>ø‘œœqúWÅþý¦5í9V)eœ€9šß“ö‰ºÕ !åažEiƒÀPŒ¹¡Sô'Œ­%iÓ=SÅÖšM£>ÉŠž£?0¯7ñ&© [ö:°õËjßÚùKy„ƒé\–·â™dIÏJ÷'Ž…Y;žG^ƾk›KšðG½C.-¤ÏnÒüo¤]Dœ}ëF9í.×tSFÙô8¯œ$Òî!ùâ2¯æ*H5McMÁIgtç4¡Ä3ZT§÷y^´æ}4 Ž8ük×``á{øŒ@ðUßþtzø»Oø³¬é ,Œ\ï_TÁ,¼q/Ž~:ø¹dŒ#Zø&ã§}Ú®•ÿÄןæô+à'Ý;ÇÿJ‰Ù”e•¨âã9j­/ý%žÿ®ßÚOá@ÿªmþŸuª)ÿðq"ìý¦>O†Ðÿé÷Z¢¿Ä~¯ó?U¡ü(ú/ÈýPð½–à•ZâÀÚvÿ©I+óç`÷¯ÑÏ Xçþ ¡Ëù·ûSŸû”Ò¿9kõß %xVô§ÿ·˜q¤m8ŠûhÓ>´ž@õ4ú+õ+0Û©õ¦ý•}Z¥¢•\ˆÚ)îi>Äž­SQG*ÈMŠíMþÎOWüêÅr »+63Ý¿:Oì¸ý_ófŠ\‹°s2±Ò£=ßóßìx¿½'æ?­ÑG${3*cÅýé?1þ#üOùð«tRöqì>v~ºÿÄ +Dsÿ ÄÇ?íj6'ÿm+îúøËKø7£~Þÿ¾)x“âÝþ«©øá÷ˆnü=£ø^ éítû_± óo¥2¼³¶÷Ús³ T/òwúé§þó-níh“K·vèïõW*kø V’ÓvïçÙ3àßïƒQ®Ä{_ØÿòG/üíðjaƒâ‰ÿ†£b?öηÿcˆ_³/ÃÝOÆZŸÁëé¦èzÚ®µ¡,š™Ó’(™YïB^§ü|mU*ÿw½MröŸðT¿ZiÖ¾:Ôu?ÙðxfK‰¼+iâÓ7Œ­­\…Îy:%1ÜTÀ~FßëžxÚŠÄÏ^ö[¶—ßg¯ßc%¹M›ú¼~ZßDþýVžz +àÞo‚ç?ñT|Qÿ¨‡ÿ!Òø7“àÁÿ™¯â újvÿlëÖþ$~Ñ"¹¹Š S;I”t€—˜¸O“`@›±l¨¬ùà¡·þýׯ~#ÐôkoEâ|6Ÿý¤¶šQÕcâg72œGnRXœWqûÕúåZÿX—§_‹—ÿJ²ùšªùUô¡^Ÿ7þ“©æþ Úø(Ý|QñHÿÜJÃÿéðÿÁ»ÿálÿÂKñ=½Ž¥cÿÈußþÎ_·OŠ5ŸŽš‚üsâ/>*/YãÓ/>kÒ^5„ðÄҘ™öȶ:àŒƒ’ãþþÐh?\Ýi>ø_¤ø7Añmî¨Ý^5æ«gÙ‰¬1L‘£fm®åHUPsK‹ó§$–&Z«ýÍ-tî׿Kᜩ&Ýéú¦ôûŸÍ¯üÿðbÐ ºÿÄŽ=u /þD©ãÿ‚.| мEi£?‹<_¯} —Ö2êÖ"ææ8ʇtŒÛneRË’pÏQ\çíÿMñ·ìëñw[Ó¯kšv‘w,‰£iÃ[›WžÝeeÍqRZCwµv°s„nH÷ë1ø‹öýø9¨D®‘_ø+[¸E|nPïbÀw檗g“QåÄÊÎÿ„e%Óû¶&¯ +er¾7VÿÒ£ÿ¥:Á¾©ÿ×±½´ÿäj¿à‹ß +Ä[SYñÌ^ëwgŸÖØ××TT¾2ÎÞø™¸[)ÿŸ>?ÿ‡+|19ωþ#{hYãÿIiüWá\/Š># ÿfúÈí¥}ƒEë–wÿA2ü?È?Õl§þ|Gñÿ3âÍCþ_ð»UÈŸÆ?äSü?Úv@~BÒªø ‡Âÿ37ÄÂ=?´l¿ù¾Þ¢´\ož­*_‡ùøO({áâ|YüŸáªâ?üESëöë"[JÐÓà‰? t÷ ÚÏn˜t3ßÚ¿éölWØtTËsÙhñRûÂ<)”-°ñ>Zþ ð ê.Àãj¶ÿã—_ðHŸ†w1l][ƃ×Ë»¶þ?gÍ}MEaþ¶fûýb_y·ú¹–mìb|ŒÿðF?†/&Oˆ~ …þè¿´ÿä¶Z˜Á¾F»cñ'ÄSû±ÞÙ®²çõ¯¬è«|aœ½ñü?È…ÃRÚ„Oæÿ‚/ü2¸p_ÄßHþïö… ëþT5ø!ÿÂýb#x·âl©£d ÿä¥}—ERã,ím‰—áþB|-”½èGñ>¹ÿƒ{~ ]±2x¯â£g±Ôìqÿ¤u_ðoÁHß'Äßz6¥cý#¯¼¨¤øÇ:nï!®Ê’²¡ã_ ÿÁ ~ øaʺñŒî{»Gaÿ’Øý*Þ©ÿOøG¬fÔülXô"îÓåú£W×ôSÿ\³»ó}fWõú­”ÚÞÂ?qñ>Ÿÿø3a© “¬ü@¸*w忳(ÐZŠíü3áÙ’#âÖXø\Ý[qÿ1_RQSSŒ3©ëË^ŽŠ>_Oø$ÇÃd×¢Ô?µ|cæB›3ukåýqö|çñ§éßðI߆Ún§ytºŸ‹ä{Æ,Ê÷VÅS9ÎÜ[ç¿rkéÚ)¾*Í­oo.Â\;–ïìb|Ímÿ¥øom Ô|ZÁ‰9k›bGÓ÷ñ+þ½ð›â–жWú—-ÕzKmwj’ÄÛ‘úW×Q+Íâù–"WõùcVtb|kÿíüµ”x³â««vmNÀãÿ$ëG@ÿ‚ü#ðÊH–~0ø«J0Ëý§cƒÿ’u÷-¬xÇ:ŽØ™¾Êžô"|ƒð¿þ±ð»áEÍÜ–>!øƒv·ƒGy{fèµZÌÖ¿à„ÿµ»‹§mSÇp ³¹ÒÛ@ ûlq_hÑDxÇ:RsX™]ùƒá|©ÅEБñÿ‚|ûÀu߈ŒªrßYnüþÉMŸþ ðfâDs¯üF ƒ‹ûô’¾á¢´ÿ]³ßú —áþDªyGýÇñ>ø7÷à»Ü™á øŒ_Øàÿä¥D?àß?‚ÃvßcÏþJWÝTR|kž?ù‰—áþC\)”ψþ'ÂMÿõü1íÿ„‹âX_ûXÿòñ_ÁB>"ø–@è¡cÿÈ•÷m?ë–wÿA2ü?Èê¶Sÿ>#øŸ7üÅðMŸqñÄÒ{ÄÆÇü“¨ü¯ð@çþ*?‰Ù=ÿ´l3ÿ¤u÷µŸgO|D¿òጫþ|DøÿÁºŸJmÿ„—â~?ì#aÿÈt×ÿƒsþ>3â_ŠÔFÃÿëïª*Öìãþ‚%øÿÕœ¯þ|ÄøÿÁ¹ŸËdø—â‰=?ä%aÿÈtÁÿãüŸøIþ)äÿÔJÃÿëïê)­¹ÇýKðÿ!ÿ«ygüùGÀþ Äø˃âŠ_í+ ÿé1¿àÛï®>'ø©ÇýD¬?ù +¿@¨¥þ¶fÿô!ÿ«™güùGçÌŸðm·À²wÂOñTé©Xò@ßðm¯À§Îï|SlúêZÿ!WècýÃô¨)­9·üÿ—àWú½–ÿÏ”~zø6³àJ‚Š>+{iiøÿÒ*kÿÁµÜÈÏñT{KOÿä*ý ¢§ýgÍçü‡þ¯åßóéž2ÿÁ´?fûÞ&ø¨~ºŽŸÿÈUæÞ/ÿ‚_|?ÿ‚vþÐÚ@ð6§â½Gþ?k†ûûjæÞo/캯‡¼¿/É‚,gíÛº.1ÎUëä?ø(E·Úÿi_‡IŒçÀÞ)ÿÓ§…ë|&yŽÄW:õ\¢ú?-L1yFN4š?ÿàãh|Ú“áZú|5ƒÿOšÕoþT·û/íoð½1Œ|5·ÿÓÞ³Eu©'æÿ3:jЊò_‘úÕá àú$˜ÿ›~µ?ùj%~gWêƒ-ÿ‚,hÿVûmÿ¨²Wåå~·át¯ G¥?ý¸üÓŽ£iÒõŸþÚQE~°|QEQEQEQEQEQEý3«†é_6øïö`ø¡ð§ãˆ¼ið?ľµÆ“%ιá[\>–÷aHkèe·>jHÀ 1€²ÌXá}·â7Ä?øVš wÿØ~!×üÛ…ƒìú5ŸÚ§L«6ö\Œ Û‚}Y}k‰ÿ†´ÿªkñcÿ ÿþÙ_Æøl£ˆ¶£­¯t½V¯úÑî‘ýQ*ð¹'ýwþ¼ÖÍœ‡Ã_ÙkÇž<ñç‰òÉ´"©®Ý¬zó [þ ýyã€%𦳩hPê·^;½ñžrÖKªYÂÒ\4‘%żʫ(1»£¡ÊüÜÇ>‹ÿ iÿT×âÇþÿý²økOú¦¿?ðŸÿí•/‡±ûû?Æ?̥ߺL&’Òý»ô'þ’Ï+ýœÿd/ˆ>øË£k¾(ðìËá=7Din<ÏøUÓS½v‰âX¼éÐy ï/ÞLa~ë5{ì¥ðSTøðóYÒ5{‹ ‹GÄš®±YÈî‹ ÕÜ“F¤²©ÞÀ`çŽj—ü5§ýS_‹øOÿöÊ?á­?êšüXÿÂÿ¶U>Ç¿ùwÑ­ã³i÷òBúÅ.ýSû“_«< +ßöøíá^+øCá¯ü$±ð« ò[jòé—Û÷þ{Ût÷œ%¦Ü °÷…ýŸµ‘ûA|4ñgÚtÏìïø^÷D½Ì>Y¦û.ÖŒlÚPy/’̧‘ÁçÿÃZÕ5ø±ÿ„ÿÿl£þÓþ©¯Åü'ÿûeÈ3»û=}cÚQïÚLsÄÒ•îûþ.2üâ\¢¼„þÖMŸù&ß?ðžÿí”ÃY7ý‹øOöÊ_êþ?þ}þ1ÿ0úÍ>ç¯Q^Cÿ dßôMþ,á=ÿÛ(ÿ†²oú&ÿ?ðžÿ픫øÿù÷øÇüÃë4ûž½Eyü5“Ñ7ø±ÿ„÷ÿl£þÉ¿è›üXÿÂ{ÿ¶Qþ¯ãÿçßãó¬Óîzõä?ðÖMÿDßâÇþßý²øk&ÿ¢oñcÿ ïþÙGú¿ÿŸŒÌ>³O¹ëÔWÿÃY7ý‹øOöÊ?ᬛþ‰¿Åü'¿ûeêþ?þ}þ1ÿ0úÍ>ç¯Q^Cÿ dßôMþ,á=ÿÛ(ÿ†²oú&ÿ?ðžÿ픫øÿù÷øÇüÃë4ûž½Eyü5“Ñ7ø±ÿ„÷ÿl£þÉ¿è›üXÿÂ{ÿ¶Qþ¯ãÿçßãó¬Óîzõä?ðÖMÿDßâÇþßý²øk&ÿ¢oñcÿ ïþÙGú¿ÿŸŒÌ>³O¹ëÔWÿÃY7ý‹øOöÊ?ᬛþ‰¿Åü'¿ûeêþ?þ}þ1ÿ0úÍ>ç¯Q^Cÿ dßôMþ,á=ÿÛ(ÿ†²oú&ÿ?ðžÿ픫øÿù÷øÇüÃë4ûž½Eyü5“Ñ7ø±ÿ„÷ÿl£þÉ¿è›üXÿÂ{ÿ¶Qþ¯ãÿçßãó¬Óîzõä?ðÖMÿDßâÇþßý²øk&ÿ¢oñcÿ ïþÙGú¿ÿŸŒÌ>³O¹ëÔWÿÃY7ý‹øOöÊ?ᬛþ‰¿Åü'¿ûeêþ?þ}þ1ÿ0úÍ>ç¯Q^Cÿ dßôMþ,á=ÿÛ(ÿ†²oú&ÿ?ðžÿ픫øÿù÷øÇüÃë4ûž½Eyü5“Ñ7ø±ÿ„÷ÿl£þÉ¿è›üXÿÂ{ÿ¶Qþ¯ãÿçßãó¬Óîzõä?ðÖMÿDßâÇþßý²øk&ÿ¢oñcÿ ïþÙGú¿ÿŸŒÌ>³O¹ëÔWÿÃY7ý‹øOöÊ?ᬛþ‰¿Åü'¿ûeêþ?þ}þ1ÿ0úÍ>ç¯Q^Cÿ dßôMþ,á=ÿÛ(ÿ†²oú&ÿ?ðžÿ픫øÿù÷øÇüÃë4ûž½Eyü5“Ñ7ø±ÿ„÷ÿl£þÉ¿è›üXÿÂ{ÿ¶Qþ¯ãÿçßãó¬Óîzõä?ðÖMÿDßâÇþßý²øk&ÿ¢oñcÿ ïþÙGú¿ÿŸŒÌ>³O¹ëÔWÿÃY7ý‹øOöÊ?ᬛþ‰¿Åü'¿ûeêþ?þ}þ1ÿ0úÍ>ç¯Q^Cÿ dßôMþ,á=ÿÛ(ÿ†²oú&ÿ?ðžÿ픫øÿù÷øÇüÃë4ûž½Eyü5“Ñ7ø±ÿ„÷ÿl£þÉ¿è›üXÿÂ{ÿ¶Qþ¯ãÿçßãó¬Óîzõä?ðÖMÿDßâÇþßý²øk&ÿ¢oñcÿ ïþÙGú¿ÿŸŒÌ>³O¹ëÔWÿÃY7ý‹øOöÊ?ᬛþ‰¿Åü'¿ûeêþ?þ}þ1ÿ0úÍ>ç¯Q^Cÿ dßôMþ,á=ÿÛ(ÿ†²oú&ÿ?ðžÿ픫øÿù÷øÇüÃë4ûžºÿpý* +ò“ûX±òMþ,á=ÿÛ)¿ðÕ¿õM¾,á=ÿÛ(ÿWñÿóïñù‡Öi÷=bŠòøjßú¦ß?ðžÿí”ÃVÿÕ6ø±ÿ„÷ÿl£ý_ÇÿÏ¿Æ?æY§ÜõŠùKöã¶û_íSðá1Ÿø¡ÆÉFxy8ÿZŸ‚Ÿðs­¿Ùl߆iŒc᥷÷Öh«ðtŒ?gý·þ'§Ã;_ý=kW ÝÛ~oó<Ô¬’òGéÿƒ¾8øVø$~‰áfÕ ÷ü(X¾ÉÎýLjÀtÇÝ ×ÿýüeÿ¡›á—þ o¿ù¼;Ãç?4/OøRú…Å_¾Uôrαœ= +o%ûèFRºOUµ¾ö|Æ/Ãçµ+¬lƒ9F6vÓÏî?¿â¿Œ¿ô3|2ÿÁ÷ÿ"Qÿýüeÿ¡›á—þ o¿ù¿`h¨ÿˆ¡ž4ðz?ñòŽÒÿÀÇïø‡ïã/ý ß ¿ðc}ÿÈ”Ä?èføeÿƒïþD¯Ø(ÿˆ¡ž4ðñòŽÒÿÀÇïø‡ïã/ý ß ¿ðc}ÿÈ”Ä?èføeÿƒïþD¯Ø(ÿˆ¡ž4ðñòŽÒÿÀÇïø‡ïã/ý ß ¿ðc}ÿÈ”Ä?èføeÿƒïþD¯Ø(ÿˆ¡ž4ðñòŽÒÿÀÇïø‡ïã/ý ß ¿ðc}ÿÈ”Ä?èføeÿƒïþD¯Ø(ÿˆ¡ž4ðñòŽÒÿÀÇïø‡ïã/ý ß ¿ðc}ÿÈ”Ä?èføeÿƒïþD¯Ø(ÿˆ¡ž4ðñòŽÒÿÀÇïø‡ïã/ý ß ¿ðc}ÿÈ”Ä?èføeÿƒïþD¯Ø(ÿˆ¡ž4ðñòŽÒÿÀˆÄLäQäŸöjJå|Cñ6]#Åóh¶>×µÛ«[8og{'´HâIžd@LóÆI& :žkó³íŽ›È>¢“È>¢¾Iÿ‚š|}ø‹ðwLýŸÿà¬%ñÃo>‡¿> yðF‹âÿ­Ž»©_[Tд«Ö¼i£ÓfÓžÞ4Ôí¦¹š÷T¶¸En “ljýò¨£È>¢¾wÿ‚xü[ñ.½ÿëýžu}KIñwµ}sá†õ-GXkëY§¼º—L·ydšK›”–IY‰vrâù,Nqëßð²õ¯ú'¾0ÿÀ+ÿ“(ªò¨£È>¢¹_øYz×ýßàN•ÿÉ”ÂËÖ¿èžøÃÿt¯þL «È>¢ úŠåáeë_ôO|aÿ:Wÿ&Qÿ /Zÿ¢{ãü Ò¿ù2€:¯ úŠ<ƒê+•ÿ…—­Ñ=ñ‡þé_ü™Gü,½kþ‰ïŒ?ð'JÿäÊ꼃ê(ò¨®Wþ^µÿD÷Æø¥òeð²õ¯ú'¾0ÿÀ+ÿ“(ªò¨£È>¢¹_øYz×ýßàN•ÿÉ”ÂËÖ¿èžøÃÿt¯þL «È>¢ úŠåáeë_ôO|aÿ:Wÿ&Qÿ /Zÿ¢{ãü Ò¿ù2€:¯ úŠ<ƒê+•ÿ…—­Ñ=ñ‡þé_ü™Gü,½kþ‰ïŒ?ð'JÿäÊ꼃ê(ò¨®Wþ^µÿD÷Æø¥òeð²õ¯ú'¾0ÿÀ+ÿ“(ªò¨£È>¢¹_øYz×ýßàN•ÿÉ”ÂËÖ¿èžøÃÿt¯þL «È>¢ úŠåáeë_ôO|aÿ:Wÿ&Qÿ /Zÿ¢{ãü Ò¿ù2€:¯ úŠ<ƒê+•ÿ…—­Ñ=ñ‡þé_ü™Gü,½kþ‰ïŒ?ð'JÿäÊ꼃ê(ò¨®Wþ^µÿD÷Æø¥òeð²õ¯ú'¾0ÿÀ+ÿ“(ªò¨£È>¢¹_øYz×ýßàN•ÿÉ”ÂËÖ¿èžøÃÿt¯þL «È>¢ úŠåáeë_ôO|aÿ:Wÿ&Qÿ /Zÿ¢{ãü Ò¿ù2€:¯ úŠ<ƒê+•ÿ…—­Ñ=ñ‡þé_ü™Gü,½kþ‰ïŒ?ð'JÿäÊ꼃ê(ò¨®Wþ^µÿD÷Æø¥òeð²õ¯ú'¾0ÿÀ+ÿ“(ªò¨£È>¢¹_øYz×ýßàN•ÿÉ”ÂËÖ¿èžøÃÿt¯þL «È>¢ úŠåáeë_ôO|aÿ:Wÿ&Qÿ /Zÿ¢{ãü Ò¿ù2€:¯ úŠ<ƒê+•ÿ…—­Ñ=ñ‡þé_ü™Gü,½kþ‰ïŒ?ð'JÿäÊ꼃ê(ò¨®Wþ^µÿD÷Æø¥òeð²õ¯ú'¾0ÿÀ+ÿ“(ªò¨£È>¢¹_øYz×ýßàN•ÿÉ”ÂËÖ¿èžøÃÿt¯þL «È>¢ úŠåáeë_ôO|aÿ:Wÿ&Qÿ /Zÿ¢{ãü Ò¿ù2€:¯ úŠ<ƒê+•ÿ…—­Ñ=ñ‡þé_ü™Gü,½kþ‰ïŒ?ð'JÿäÊ꼃ê(ò¨®Wþ^µÿD÷Æø¥òeð²õ¯ú'¾0ÿÀ+ÿ“(ªò¨£È>¢¹_øYz×ýßàN•ÿÉ”ÂËÖ¿èžøÃÿt¯þL «È>¢ úŠåáeë_ôO|aÿ:Wÿ&Qÿ /Zÿ¢{ãü Ò¿ù2€:¯ úŠ<ƒê+•ÿ…—­Ñ=ñ‡þé_ü™Gü,½kþ‰ïŒ?ð'JÿäÊ꼃ê(ò¨®Wþ^µÿD÷Æø¥òeð²õ¯ú'¾0ÿÀ+ÿ“(ªò¨£È>¢¹_øYz×ýßàN•ÿÉ”ÂËÖ¿èžøÃÿt¯þL «È>¢¾Fÿ‚€üMо~Ó_u¿jéº\~ñLM<™ÚµO …Ô×ÕžñE¿ü!¥kV‰4vº½œ7°¤À $@ê@8aœ3Ü׿ÿüCþ§Áö*xƒÿO¯["ÃÆ¾>•m'o¼òóºîŽ¥hïsòOþZø“¢|Zý¯>k¾¾‹QÒ®¾Û¬SÇ®S[ÖUºÑW‰ÁS¿ä%ðKþÉãÿêG®Ñ^¾6‚£ˆ©F;FM}Íž^³­‡§V[Ê)ýé£~]¿4/‚6ú†E_¾ø'áô'à.€êˆØê~öV¼[ü<'ý{_¡æpWñq¿õö_¨QEñ§Ý…Q@Q@|‰ûCß?Æ¿ÛsÄ^ñg‰>#h_>|?´ñˆÒ<ªjÚ^©â[»««è$—ÌÒJj¥´vŠ«mnä<—`´r2Äëºó__²7?i-SFÔ¼O§ëë~¦›­h> Ô|;¬YÅ(XûOž ‘›P¼>g–ílÊJ)$ù“Þ×ßÎ-/[6ŸÊêÎÍ\Zå”_[j¼¤›ûÒqô}V‡ÈÚ§üGKøcà†ž +ø)âø’ÏųxŽçþ_øÅž<Õ4t»Øà¸±ŸLaÕæ‘.n’Ýe»‘<¤ˆï’V(­»àŸÛ‹ãÇÆï|ðf‹¥x7áÿˆ¼s ø¢ÿZÔ<]à­m<¶Ñõ +Xní´©î,®’Èî «ÄŠñ,ñ“$†"²ûõÏüçáDß tC¡k:nŸá‹ËGLÔ4Ïêº~»ksrÎ×SÿkAršƒIpÒ9™Úà™·0½lü6ýŽ>|&×¼/«hº5øÕ¼e©éúeýö·¨Ý¬Z•ÌwWÆin&‘îdšxcv–ròeNAÚ.<×Ú×Õû²KÒÒqº½¹Þ†oEh«~ŠûvÛËM•‘ò5ßü‹Ç—Þð†ãÓ¬4ïkº¯‹4íg^Òþkþ4Ó-ãðö¦4é&‡FÒå7 ]I$ <Ë‘¸f ,Ͱ?GàÛ‹ã¿Æß|ðf¤ø;À!ñÎ…â‹ýnÿÅÞ +Ö£1¶¨YZÃwm¥Oqeu7‘ÜV‰âYã&I Eeú[ý€¾k~ ·ÑAÕt¨,õÍCÄ–—º7ˆõ='U±¿Ô&–kÙ`¿µ¸Žîæ“|qʱ²¶Ý»@Q«ðÛö8øyð›^ð¾­¢è×ãVðu–§§é—÷ÚÝþ£v±jW1Ý_¥¸šG¹’iáÚYËÉ•8` Q’M:ž¯Íò»iÑ)5¢Ñ¥v¯¡U-wìö»µúG›Eæùz»´ö}Oš>;ÁH|Wð‡öÓ¬4?xOÇÞ—ÇzWƒ5 /MøSâDM1ï/`°•$ñLwSéêÚiü +1(`"9jôø$·ü›ŸŒìªxãÿRMBº}cþ §ðw]ñÓk÷ˆüïÃâ¥Òâñ޵ƒ«Ò^%êiIv,cs•`ݤgÜd}Þ¡ð—àφ¾øróIð®›ý—§ê­ö·qÚ%ŸÌ¼½¹’êæ]Ò3¾idm …]ØP+Oâ³_³iwÑÆ{ëªôEkK݆ÜɯDª/½óGm4>¢¹ þKç‰ì_Òô§S®¾¹ þKç‰ì_Òô§S©Æ_ t/ˆ#ðž­«Øý¯Pð6«&·¢KçIدÆîÁ¥Â°›[ë¨ö¸eýîìnUeãõOØ¿á~©§j¶cÂ}¦­áýÂí$¶ØØiÜÜiIf°: ),绚X&¶ò¦…ü¦GV†"ž¡Ex}Ïü¯áTþ²ÓcÓüaewewq{ÿ ŽuÛ?^<é s n+ÅÔ®£xílÑ£žåÐ¥…’íÛin#<ÿäø=ðóQð¬Ú/†5 >ÓÁÖše®Ÿ¤Çâ-Oûs¦Á ¾Ÿsw§›ƒi}ymµ Šîî)nÙZ(khL~áEsÿ þè_¾xkÁ^±þËðǃô«]H²ó¤Ÿì–vФ0EæHÍ#íw;3d’rk ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(®oã½wá_„^*Õ,%ò/´ÝîêÚ]ªÞ\‰ ²¶p@8 Šð?‚þøùñ{àï„üYÿ ÇCÓ¿á(Ѭõ²ÿÂßfûD /—¿í+»nünÚ3Œàt ¨(®KàΉâOxZ{x<]­[Ý0“QMNÔª2ªB…¶€9v$ää|7Æ·Ïм ñãý÷Ãßÿ›øªÇ§x³ÄÑø®f×màþÃÓµ‹‹ø´Ÿ°yRÛÛC©!‘VûÏhí§h¡š_*ÞP§è¯/ñGíuà…z‹—Ç~>ø_àûO ]ìio|]m [¬c<—©0ˆZH³ê¶‰åîl¼°¸k´‰O†Ÿµ•ãŠß¼)¨.Ÿ ]ø7Ʊx+L7Šyž$¸iúóceSæ,“æ%2–RK»•=BŠóÿþÖ? <_¬xNÒ~%ü?Õ5ê¶Ú½kiâ9æÑ5›£gmet‹!0\Kt Å WyAE¸®öýªáOþÏóxÇÁV>ñþ¡/ŠôŸÙZ6½öÔo|Am¡I÷pÃrbû5ÕÉBÃ#«[È…C€`¢¼áÇí½ý‡ñOSøñ¦ßáÿÂïAý†údv~3þÒÒµß홵+}>ÒÚæîÖÂY5›H¿ÕmÛä²I!y/OøqûBøãмO¡xCÇñV·à›¿°x‹OÑõ›kë­ã|©äÝųÛɾ—dNbc*pØQ^?àÚ§þïÙŸÆÿ¾ÃáÿÿÂ!ªø·JÛ®ëßaÒ‡ö­¨éßi»¾ò[ì¶òýƒÎ’O*O!$n%òòÙúüsà½çÃ=sÅÚïÄ?øDðçu‡Ú„þ(׬tŵÖt뻋ym]žm‹$‰l×1FÌ$ky"¢†À÷ +(¢€ +(¢€ +(¢€ ++ÉÿnoŠš×ÁÙ;Æž+ðíÊZkZ%¢\ZÊ𬪭çF¤`AI<×;ÿ +/ãçýÝÿ Üü—@õE`ü2³ÕtïØÛkš¹×µ{mðÝêeKQw"ÈÊ\DŸ,kÇ ’@À,Ç,~~øiû|ø«[¾¹ñ‹>øÃß +gø©|8Ó¼A§x®mOUMFOáûIotæ°`·º¾" ostñ=ݹtù÷àOÑ^_¥~×^³ž+øûá~­Þxü?gc‹­®êâMFþÊÆÜy‚'7“¾w¶T%n-/ F˜Û;“örý¨4¯š$­2éú¶|Aâ½ÓG}E&º¾·Ðuû{ØÐª;F^;w|)›È£,Ä«8¨Q^ð·ö±øYñÇG±Ô|ñ/áÿŒ4ýSU“B²ºÑ*øZøK<1ñU𕦑.ù,>Ñgâ [N°‚óGæ.ÈõŸÊtVm› Œ’ÊìWþÕß¶g…c[]3Wñ®£áý3Ã^B^Ü\kPÚßÙyúÆ“¥Gv-æ iðIª£ÝÝ4Éöeâ9Lãga£~оñÆ][áΟãßüBÐ-ÿSðž³m.³§[°ˆ¬ÓZ+™£Œ‰à!Ù"hùù× …Q@‡ì÷ÿ$Àÿö/Øé4uùýÿ ®õð@ÿ©OÄúxð½~€þÏò@üÿbý‡þ“G_ÿÁƒsxÔ§âý;ø^½îÿ‘­ñ#ÄâOùWÿ ? ?àªi·Tø$1ÿ4ñÿõ#×h©àªãn±ðLÕ<ýHõÚ+ÖͿ߫Ž_›<œ®_ìTÃɤ?³÷‡Ûþ¨‡þ¡±WêOü>/öqÿ¢‹ÿ” Sÿ‘«ò÷Ñû;x|ãþh‡þ¡±WÎu÷ùo `óÊtþ·)GÙÓ§nV—ÅÍ{Þ/²??§Äxœ¦­«F/ž¬ïÌ›ÚÛY®çîwü>/öqÿ¢‹ÿ” Sÿ‘¨ÿ‡ÅþÎ?ôQòªò5~Ñ^§üB\Ÿþ~UûãÿÈÿÄHÌÿ’ŸÝ/þHýÎÿ‡ÅþÎ?ôQòªò5ðø¿ÙÇþŠ/þP5OþF¯Ã(ÿˆK“ÿÏÊ¿|ùÿˆ‘™ÿ%?º_ü‘ûÿ‹ýœè¢ÿåTÿäj?áñ³ý_ü jŸü_†4Qÿ—'ÿŸ•~øÿòÿ#3þJt¿ù#÷;þû8ÿÑEÿÊ©ÿÈÔÃâÿgú(¿ù@Õ?ù¿ h£þ!.Oÿ?*ýñÿäþ"Fgü”þéòGîwü>/öqÿ¢‹ÿ” Sÿ‘¨ÿ‡ÅþÎ?ôQòªò5~ÑGüB\Ÿþ~UûãÿÈüDŒÏù)ýÒÿäÜïø|_ìãÿEÿ(§ÿ#Qÿ‹ýœè¢ÿåTÿäjü1¢ø„¹?üü«÷Çÿø‰ŸòSû¥ÿɹßðø¿ÙÇþŠ/þP5OþF£þû8ÿÑEÿÊ©ÿÈÕøcEñ rùùWïÿ ñ3?ä§÷Kÿ’?¦Šä4_ù/ž%ÿ±IÿÒNºúä4_ù/ž%ÿ±IÿÒN¿žÛ¾Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( oãƒw⯄^*Òì"óïµ-îÖÚ-ʾd ª®X€2H$ +ÆýŸ|-ª|(ø à j6ͨxk@°Ò®¤¶–6†I`·Ž'd,ÊJ–RA c t®öŠ£¢Ç/›{,°ÉŸ8uW*[4\ü¤Žª{×Éß¿c¿Š<[ûFxK_‡ö¿¿híTMªx|AxÞ$Ò4é¼3¥h·¶ðiŸ`û3\:éó®÷d&æ9^ ü–¶›ëú(åÿÁ?u]/þ +q­|oÖÓÁúžˆnõëý <Úž—q¢x+KŽhÃò)6xVÝ$Ï“y‚ÂYV??ÿ‚vÁ/ü}û>“â)uêÞ+†ÓÃÞÔ¬ÍÕÌúuÆmá éÏk, ,¯óE–åLIåßC´7JmgÓ~?,/ÿàšž(ý’g6ÔèZ‡Š|eðóÃúw…þ]iþ+ñwdñV·§ßéz¶˜×v7 iÞÒî/|=`.㌵º$éÔ,ÒÝ^ãë‰ðOOøLb+o„w7>ñ_ö¯Ä 7ÆÞ(þÙ±òô­gÌñ”$Ö KR'Ûo.ob‚ÞV—ÐÇ,ÏóÌ~Ÿ¢€<Sý„<+ðÿÅ¿?áTø?áÿï xâߌµ­3DÒaÒ!½ó¼3¬idq[D#{ƒ%õ¦KíýÔ-óˆÇþÅ_±—¾ x«áL>/â|økuð¿Ã·z>§s{uâûyßEÚWpKki²*hPŸ³G-è&öAçn«è ˆ~Çï´»Ÿ‡^1µø¥ü2³ø«©|M·Öôo^_뺾|_?‰ôë³–Â,±pöÂyEÅÖèíæ‰#V¸[›o¯è €þ %â©|%ûSyòü?›Äÿ¾øŸÁ¾ÔÙ¦i´¯íxÇW1Ï)·ó"·xõÝ#ÍoÝ-”Ÿ+ˆ¡wè4Ïø%·Š´ß„_|#oâOÛÁûEÿÂs¦x¦êušúm×VÔµÛÍ&òÁÙVFò#ÕDwc øá¯ÚWT¼ÓÿáþɼÖÝ%·Ò­lš+Ët‡U‡e°¼²Ýöc’ ÂUÐøÇûj¾ý€¼ ð‹ákéúßÂË¿¾„ŠøÃöƒý‘>4~Öþ8ðOŒ¼G¤ü/ðf·ðúÒåìô­7Å—ÚÕ®­q‰<¯ØÇ%Ôše«ÛÇ;øvîÚi M¸šQ.IxTøÿÛ×>~×x›P‡OÔü;¢x׾;Ó5›ˆ~$¼‘®5™uIÚ 3¦‘§É +êóÂoVK“*A#}ž9oZKo³è Š( Cö{ÿ’àûì?ôš:øþ +]ÓøþÅ?ÿéßÂõ÷×ì÷ÿ$Àÿö/Øé4uðGü»®¼ ?êSñþü/^÷ ÈÖ‡ø‘áñ/üŠëÿ„ü%ÿ‚° k¿?ìž7þ¤zíÿø+2íñÁQÿTñ¿õ#×h¯[6ÿ~­þ9~lò²·þÅGü1ü‘úYáhwþÍþoú¢6ú‡E_4WÓÞ\þÌÚÿª#aÿ¨tUó ~ÍÀßÿ¯t¿)ŸçÄŸý}«ÿ¶…Q_|xAEPEP§ëßô{/ØëÃ^*ŠÏn½¨x³QÓ..¼×>e¼V¶rF›7lid9 + ÝÉ u³ ž(øuàíoSñŸ¦xq<+yâ-Fâ %º°¶‹R’ÐF62µìòJP!•Ó`RꉚäüûH/†¾Ûx/Vð?ƒ¼]£Ùj“êöͪɩE4MQ¾ÒîT¬)Þy­8?lrÊM*Úß@ð´—¤Þh-¡ùWRXÞØ\ÝItöó¦!dpQÖU‘|´;÷Çç«SÌ>KU9;»5Êã+%{´îÕ´²óWOÙ¡<£*Ûr¤Ò½ïΛnÖMrß®öê“W>þÊúOǯMaàMÅ Òt½]gU?ð‹cX€G/•äAeÌ«q#—ˆ®'UÄ„±@¦º}cö‹ÂšÞ«.¿âøsÃú„¿á-GÕ<&öº»D·©g%´–/8ͽ˜§ï™ydº%<æÏö”mĦëHðW‚ômëK}QЭ㼒ÃW·yL­ç´·/p_xFWY•Å»hŸö–žÎÏ^´Ðü#àï iþ!Ї®mtèn™DFí.ŒÞd÷JÓE]Ò;€€(Qˆ«K5”ײ›QóP¿[Ý­/µ¬š¶úêiF¦\£ûØ&î¶rµ½Ý“×ù¯vžºyu3þÇštßÙúퟋ®€n¼3/ŠgÕo4…ƒP¶·ŠðÙ<"ÍguyÚãb „a"–tÃb¯ÂÿÙ_Iøõãé¬< ¯ø£ÄN—¢Ë¬ê§þlkåò¼ˆ,¢¹•n$rñÄ긖(ÖG†¿kxoHðþ™ýŸ ßhú‰uáÙ´û¨%h5{+‹—¹xîvÈ"W ¯FÊcBa“^Ïö”mĦëHðW‚ômëK}QЭ㼒ÃW·yL­ç´·/p_xFWY•Å»jÝ<Ñ)ÇŸ_{•û¶µånedù­m­ïÖòªeÿ/2÷¯´9¹u¶üûôµº[Òþ ßÄØ4ynüaç†ßÄ–¶’øJH¼Mr‰9·{dÒÚqºq /9_$yܯøÙðîÛáWÄ{í +ÚãZ¸K4„¸Ö4gÑïàw‰âšÙÝÌnŒÅN”ã EnºWöñœü.øpt¯ìïìñ¤yZŸç}£Ïû_Úüìü›¼üy&ݼVÆ‹ZÆcQ·±²òm-ôû[K$u·²¶·‰b†ÞÏ#Es»1êXšÛ ÁVO+ÆÏ¤V·ÑèÛ½´káëw²Ï< ¥%F6•Õµ“ÒÊû¤­{»½uµ­©ý×!¢ÿÉ|ñ/ý‹úOþ”êu××!¢ÿÉ|ñ/ý‹úOþ”êuü„J}xüçâö»ð;öD»×¼9âx[P“Å~Ò%Õt-=cU´³¿ñ&™cxm-$¶ºÜ[™Ö4ó1v]±³mïõÇüpø)¥|~ð]–…¬ÜjÖ– ÑDV7ç͸°Š ~Ëû©dûE¯Ú:þÞž/Ó>"ü ÐáM|@ð¦¡ãŸˆx_WÒ¼E›%Êé“hzÕòê—vz„º{ySi{¦‹írE'ú6ë‹3/A}ÿëð®·ÿ v‹ªx«â£ðËÆÛ’^ü=þÓ†ÓBIõ¯µRo:Úµ¼÷¾¿“ʸ¼–¤ºßQµ½©·¿¡þÄ‘GCÕüQñ;â‡|WáZkú>»­\éÐɦ ºµkx¬ììíôñöº†£o,†ÔÜ:^gÎmföÀÄÚ§Jømñ÷ÃdðïŒ5mKÄvŸo–÷M°I­t«ss¢M"™ââ?´M s=”7ÈO ·¦Ò ¢™þpý¡¿à«2꿳ý½ï€|%ñGÕþ `ÝøPž æñ®‡¨øƒEÒn5M!d»’+{ˆá×,¤‚=e-@–îÜˤwQÇôÅÙ[Jø¿ñ—ÁÞ1¿ñŒ,›Á÷q_ǤY_¢i×· Å¼Ä +Ó4ícJÕ¢ÒíZH帷’mJŽI/ÞêäÅhÎ$ÒHÏøþ +³g¤xKÅøûÂ^ µÕô­Wâè‘èðZÈž*³ð߉ Ñ-­ì£k¶–MBòmBÂÒF׋:¢"=¿›Ð|^ÿ‚³ü1øQðÛÄ-Œÿoø@ñ]„Æ¡‰ü9¤Øj²ÞhVšìVwš¦§ikqnÖ—°ãdÞk6ò‘4He®¾?ø'ï€SÅZ¦É¨O†|k©xãN²œ[Mƒ½ÝÝ¡g„Ë%›êÌš¸‰äcý­œˆé¥´1`iðL¿ xNÒŸáïŠ|að¿ÄZ5Þ°Ö¾ ðìCÞ¥†¥=´’iF+Ë‹Cgz~“kl>Ïç[ÚèöVñʱ#¬€Šà¶_ü3ðÛZñ—ÙüA/„­u]DÐõ›»+E°ñmæ©¡C⢵›R½¶Ko+L¸ŠiQ6jÌÂŒÓè>"ÁFìüAûøãÂ}3þKmwÅ~Ð ÒÖKY¦»k¯YèwöL·Ig%Â4·QÅ:Ý5›Ê‘ȳKnC¹ðÏþ MàŸ‚ÿt¿ +øOÅ¿4-Cú®•­è^$Ž}>ãUÐï,<1iád–$šÑí$ót«WŽE¸¶•wÝÏ"ØBaôÿ~ÊÚW?gˆþk>"ñ†¬ÐÝÛjñøŽöý'ÖSV¶¿R·Ôƒ.¸ŽËû_ÖôÑzoôècK–¿ŽH³50e¸´†ÝÍ„›%q%¹›€ý²?nýkÁ~ Âÿ¼3ã Ét?‰^ðŠ|]o•ý >¥­è†çNš;«•¼’I´ÍN%µ´™ßljRHå0÷þ ý„<=࿌¶^(‹ÄÞ0¼Ñ4?j~.Ð|#q%—ö6­êBô_ê0È–Ë$“iêdÅqw5ºù6D‚;q ŠÿðO}âÅ;ŸÅãψÒ5Ÿè~6×ü1¥-´¯ëDÚ|–—Wse5ä.“§DñÚÜÁ% ;É+ÈÇßÿÁ_ü x/Mñ.¯àߊo‡|Ui§jþ ½M&ÛR“Ç:M鉩XZY\Ov#I5­.F·º† ÆKÅ[K*KtÿðR?VÔSÃzOÂߊÏÅ(.ïmõO‡öí¢G¬è©g›q<ó\ͨ¦–ñˆu­À‚öW#RŒÝÊÁŸ ÿÁ)¼¥ZøjÊïÅ¿5#áÿöM§ôû¹ôô‡ÁZf¬iZ´Z]«Ci·òM¡éQÉ%ûÝ\˜­YÑäšI9ÿÚ—öñÝ·ÅÛ߈_®¿³<{âV÷QÖ5Û¿Ûè³i°O¦èZ|–°ÏáíbÚky×@Óæ‘¤‰'Š[QåÍåÏ$@ËüÿÞð7…t¯x£Åwz…Æ•ãX^øD¿Ô¼?áÛ«-_øWW˜Ks©_YÙ4‘Ü뀴k–áÙò–H`v‡éÿˆ¿·‡¼9ð“á7Œ¡3—y<וQÞFùÀy†¿à«> ñΧÂ_5¯x§û6ïÁ¾† >ÿéš•®£{aªYÉ5ÚZÁo=¦‘ªÎ#¿žÖåÁÖH#–[xæóÿÛ#þ +³.Ÿû|YÕ¾xKâ©ãßü?×5½N[h4uÿ…iylÚµ‚K¨‹Û´†çÉÔ´}N6[|­ý›+$rÛ´þ¢Á)¼àíÁÃþ-øáï|=ð§†|'áŸZϧÍ£E¡ZëV÷Kö’ZËq=¦»©A7‘™Z8¡–4güCÿ‚FøKÆ üAá+â'ÅÅãßÞøoÇWÚ<ºD·^9·¼»Ô¯nïí–[È÷zί6tøíBE +#ŠÝ!òÿÚûþ ‹ð÷DðwÇŸøÄ?Ùß|áOGáÝSíú5Þý{EÒïîf‡û3íRê0ùct|Ûë­%û/É,‹qmö§üûaYüBø§âÏ +hÞø{?„µXô‰oþÇkÌ«5¤w‡2\,–ßfŽö —‰o-å«}¢Â;èJ¹ä(Xü=øƒiâæð…†¡eo¦iwZê]Jö)×ísÉ$—÷Ó¬7·6±Ír-×ȶuþýlü)ñ³Ä~<°ñÇÄõ}šŠ[Ë[ˆtë8õ5ŠmÚYíæ™îVîK†±Šòæ-=¬VZö +(¢€ +(¢€ +(¢€ +(¢€ +(¢€1þ!x¯þ?ëšçÙþ×ý§Ï}äoòüï*6}›°q¸Î3Ð×…x/öÀø«ñÁÚN¿£þÏZåæ‘®YC¨XÏÿ ~“Ÿ¨$ö´—*Àá€#<€k׿hOù ~8ÿ±~ÿÿI¤®{öI½‡Ã²ŸÃ-;Q–+ BÃÂzUµÕ­Ë¦¶•,âWѰU• ƒ@7Áÿëþ:ð›^ø—ÂÏàÝUghŸK“QŠþHT*Ï$_»Ëœ+6 åW‰½ý»¾éßµ/‡W§ˆ ñªÚhW÷rxWV] +ÇQ»·¶¸µ²—W6ßÙÉq2^Yˆâk€ï%Ü(2Ȉ}?@ºŠöçR–#–6¹t`Êsê+á–:Ç£ý·¾éþø'Œ>=ê³iÞ¿oê‹á·‚ûÀÚ–oçÖ ¿ö|VöóAtÒ¯žg"ÖDЧha”îýÄÖÚZÁ ’è·kep×ÛG#˜"œ^DT¸dÈ —@âHË "‘?Á¿´/ˆ#ñf“¤_}¯Pð6«‰­ÅäÉدÆÒýbË(›[ëY7!eýîÜîVUøÂçàßÄ¿ŽŸðSh~%×þ8h_E߈.#M[Ô´M3REÑ> (ò’A¼:Ô±›9¡vš A7´o{ ¼üNŽ67ÿ……ñ{Hø€4ÿj¾»Õìí´‰ô›È¼Gyà/ +YOªj6qƦóOBòÑ£‰R>é%–x&XÅÎŽú?\ÇŽþýšþÝx¿Å÷Z…¦‰iwe`M†•wªÝMqyw ¬1ZÚE-ÄÒKqq j‘ÆÄ™ɯÌ…·?´Â?‚+øã¿ˆ¿$Ô¾øLñÇÅM2o +ø‹FµKÍ#YÒµ]ZÒÊÿTÕg²»’k=zÖ(¼=mo¤Ü ŒNð@lV¾ øãðS⇌?àÖZ±qã xƒã‰âHÞÉâÖ5Ÿ +i·?í5Kt%ÖæØÉ¥é²D®1=¤"Å´¶ñ†`£þþÓ¾ý¢¿µ#ðäÞ µÔ4O)¯´¿øoRðæ«oÛÄ7ËQ‚ Ÿ³ÊÑN‘Î#ò¤{yÑ]š}¾@ñÿì{®øö€ø/­¯Ž>0|AÕüCñÒx†kÈôÉŽ‡¥øÄ×zuâè¶ö6ßÙñê×Håfˆ‰å»H¦i“ɉyÿø'ü,/øZ~þÛÿ…Áý¯ÿ +þçþOü&Û?Ù_ð›yÚW‘ý“ý£þ‡ö}ßðÿÈýg‘»äû {†࢟ +¼Yñ +OZê0ŠX¼AsáVÕï| ®Ùxtê^É`öƒXšÍ4æÞÆÖ¨ÁÜŠ2ò:+z‡ÂŠZÇ…žñ¯…¯¿µ<1ã *×[Ò/|™ û]Ì)4ùr*È›£um®ªÃ8 ŠùCöDý‡u¯xgV¼ñßþ(Eᨾ0x³ÅVßolt«-¼6Ôµ-.ìH4ôÕ34v—è~ÚRRS!íßÉoŸÿdmKãGÁØ¿á×ÃKß |p‹Åˆ>_X-®—|¶¾ðÄ> ³ÖâàíŠÖ1wg¬Ãs§+ 'žym…«Ír?S诘?à›?ð•'ü,8¼Iÿ ‚_+U7>8ó£ûMÛy¯såÃ>ï*â=ÑA?ö\’hùϦù>}ݬOÐEPEP ûK|m‹öqøâ/ͧ>­‡ [‰-a L¦DB@ 6zsŒqœ×ŸÿÃH|gÿ£r×?ð³ÑÿøíOÿ+Ò®µßØoâµÅåíå”P[ÛÁ’Yäk˜•Qd³@ ’kÙá'Óè!cÿÓühŸÃ¯ê^+ð]†¡¬i@Õ.P›;íktlœ13*€¬Ã•Êç8fcç? ?nï†þ)Üø;FÕ<@5x5]KB†ãQð®­¦iZž£§Í<7¶VZÍ´vw·5­Ù1[M#”´¸p +C#/¨xfUŸKgFWG¸•”ä03>5ð‡ÃKcâŸÂkŸ‚–>ø§x·Ný 5/jºÏ„uM+B³Ñìþ%Ïâ!tš•źZÝ}¢Ò(RìäžG’òÈ¥Äð}ßáŸ[x³N’êÖ=B(¢»¹²e½°žÊBðO$BLˆíxؤ€• +I)h_<9s«xrûûGO´Õu-Y|™!Ùy§ßOay$U'˺¶ž=Àmm›”²•cùÁàºæ—ûNx¦]oö€¶ÕüáOk¿ t‹{ÍF=S^‡Åþ=—Lxàuÿ—cŒ‰bKÚ\ZÜÙ ­®lÌ]‡ÂŸ üyøMð§ãPÑtÏø¢ïâ”’ÖÜÛéÚ&­7ˆõíBØêv—Éi/JÚ\Zjwe¬Ì […³y¼Í`ô>¼ÿö„ý§|!û/èú ï‹fñüU¯ö&“i¢xoRñþ¡yö[‹³vº|ÎØ·´¹¶Íª±1$qŸ€>ø‹âwìá£é>>oü`øðïÃ?4gðý߆(~Ì_/> ~Å Ôüiã¼wàYÃâÿømbÕî­n ð>½ks~ÓjV—4wn±® %âýÙ]õ Cþ +sð‹DÖ-lu+¿ˆDòéPë·­©|7ñ%Œ>Ó¥º¼µŽ÷U–kK·2X^7›|Ð ŠÝæ$C‰§üwøïáŸÙ¯á׋ü_u¨Zh–—vVØiWz­Ô×—pÙÚí¤RÜM$·Æ©lIqŒšùÂëâ%çì³û}xÆMgÃÿ>!Oâ/…^ Ñ4mSJðUÖ£ÿ .§e¨ø ÏÅí¥´ZUÛËGv¹’ÎÙ>Ô˜a“?â·ìŸã/Á#> +ü·»ÔÆ^ »ø[¡^ê~·ÒX>›¯è+w¨[-Å»£G[Íq¾x +*DZXöZöÿ‡ß·wÃ?‰^#ÑôK=SÄWˆ5íUtkÄ>Õ¼?ªË;Xß_ÆæÒúÚÒÞK}3Q1ܺ${)ãIXÙ°Wç‡üCöø‰¥øGCÖ~x›â‡ÄÿõÞ±§[øªöK ?QÒÒøÖ 1.mcggzž®Û.üíAç @±Ÿ´GÆOürø…ñK_Ñ4Ú?Eøc‡üšTi¢xƒB^š+ß½øö!|Ae²fÚË=°½ÒÆâk[­(8¹ý¢¹ÿ„ÿÚ?ð«<5ý±ÿ ö¿öU¯Û¿·¾Ãý«çù)æ}¯ì?èhÝŸ3쿸߻Ëù6×A@‡ì÷ÿ$Àÿö/Øé4uðWüøf÷Àßö)ø‡ÿNþ¯½g¿ù ~ÿ±~ÃÿI£¯ƒà¿ »Pð7ýŠ^!ÿÓ¿…ëÞáùÐÿ<>&ÿ‘]ðŸ„ßðVÁüÿ²vßú‘k´S¿à®C)ø-ÿdí¿õ"×(¯[6ÿ~­þ9~lòò¯÷*?àäÓ?¦?f=Óþ‡þ¡ñWË•õ?„ÿÃ/h×à‡þ¡ñWËû/üÿ¯t¿öóòïø“ÿ¯µöТŠ+ïÏ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Šþš+Ñä¾x—þÅý'ÿJu:ëëÑä¾x—þÅý'ÿJu:þ'?«¾Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ЧâzÓºö©/‘c¦ÛÉus.Öo.4RÌØPIÀàkÄáèÿè¥è÷êþ7@õEs? >1øo㯃ÓÄÔÓXÑe•áŽî8dŽ9Yau]À g ÓPEP?ãÿ„þø¯ý‰ÿ O†|?â_øFµX5Ý#ûWN†óû+Qƒw‘{oæ+yWîm’¦w“]PEPEPEPEPEPEb|Fø¢ü$ðUÿˆ¼E~šf‹¦*½ÕÓ£:¬Á!A8ÜÜqÔñ^Aÿ@øÿE/Cÿ¿Sÿñº÷ª+#À^;Ò¾'x?O×ô;£}¤j± í.<§ˆO'€ÛN20Adk^€ +(¢€9ÿ|'ð¯‹üwáÏêÞðþ©âý§ûW»Ó¡žÿDûLb+Ÿ²ÎÊdƒÍŒ“Ë+½@ ‘ÅtQ@Q@Q@Q@‡ì÷ÿ$Àÿö/Øé4uðüÐgRð7ýŠ^!ÿÓ¿†+ïÙïþHÿì_°ÿÒhëáø/—ü„ü ÿbŸˆôïáŠ÷¸_þFÔ?Ä ‰¿äW_ü'á7üØcÅÿìŸýHµÊ)à¯ò6|ÿ²võ"×(¯_7ÿ~­þ9~ló2Ÿ÷?àäÓŸ +qû,xxÿÕ°ÿÔ>*ùR¾­ðºÆ*øtÿÕ°ùgÅ_)Wìœ ðKþ½ÒÿÛÏÈsÇûÉÿ×Ú¿ûhQE÷ç‚QE>™ +ÜjVñ¸Ê<ª¬=A" §Û\5¥Ìr¨£`ã=2i­õ&i¸´²ÿiÏÙwÃ~ +?ío~§ÃmÃ7Gàÿ}§RüC3\,bØ-åđ݅¥”µº¡O B’šøÓö5ð¿„~,x¿ÃCÇú•ſËk›ßêËCrEIf†ìµÄÒK4hVO!²DŽ 1ò?Šÿ5Œ?uŸjpÙA©ë—ͨOª2À’1É +™‚ýXŸzê[ö²ñÏÆxÒëMÐo_ÇqÜA®iC/öuô3fˆ…L€:#«$ªêȤ7¯Éá2ìÒ…/lܹ_7_zÐKYs>“wMFí]Xú\N;/«VOÙ%unžíäÞ‘åþí“»ß^ÛÉû"i÷‘k0ø¶føu'†¤ñIÖ›KUÔî>Æð}‹Ï+öµíˆ/Ÿ°†æ7­¿b +ê>‹Ä¶ÿ5¨ü,þŸÅ=Ï…Ñ/‚C©-ƒ[ˆñл1,¤Ê¡ŠYs>~Ó2ø³â9‡W»ð_ƒü$¾ŸÃÑh·v•Æ‚mKyÂÙÅ»Éz¥î?|gYA ¶ß–µ?hÚÎÂÓF²ðŸ‚íü/q£ÇàÖð½üúu¥ôV?½Ô û›1tâã +Â4ßp 1¸*j+O6ö°£ ;·ví({ßå·?Ã~WnÊÛÝe¾ÎUf••´»»w§~U{òÛŸV¯·U¦wìéûéÿ´Õü–¾¼ø7›©>m©Gà!s¤Aœy/{sël‚¥ÀI`ç.9«¾ý‡´?ø{ÂmñíÖ™â躞µkh¾óìíã°’åeÜ …pYmœ¦È[$à…á/ð»öÍÕ~é~ …ü'àïÞ|>¹{Ÿ^ê‰{æé¥çóÙDp\Å €ÊY·I?Í÷°ªމû]ø“A¼ðÄðØèlþѵ-Ð<2‘$7æäÌÒbA—_µI´Œ…Èl툥œJU)ÙkËðtKtë/fÝÒ¶©]jñÃTÊÔbëBïKü]en½#Ì£fï£vz.ÓðÍõí] ÄÚö¯áýwÃø–Ñm¼6²k÷b·´’Ú=.™e”:ï8¸Ç”º©Sä_>Û|*ø}¡[\kW f—ÆŒú=üñ#¼S[;¹Ñ˜©Ã²œd®‡Mý¦'ÿ„oÃú6µáx§JðÞ“.‘io©Ev§d—ve2Aq«(we7U(ÅY[9®sãÅ­GãGŒF±¨ÛØÙy6–ú}­¥’:ÛÙ[[ıC +og‘‚¢¹Ý˜õ,Mw`©æÄ¿¬Jð÷¿—ùŸ+Ó[òÚêÉ/7¡Éˆž ÐýÔm?wù·å2³ÒÜÜÍ;·­­mWô\†‹ÿ%óÄ¿ö/é?úS©×_\†‹ÿ%óÄ¿ö/é?úS©×ò ý.uôQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEr´'ü?Ø¿ÿ¤ÒVì_ÿ&wðŸþÄÝÿHa®ÿÄ: §Š´ í.þ/>ÇR·’Öæ-̾dn¥Yr¤HÈ ÕMÀš_†ôkM;N‚[ >¶µµ¶¸’(m¢E +‘¢+ªª +³¤ÿÇþ§ÿ_+ÿ¢b¯Îï? ü+£Gûx|`Ó<3áø~9ø/ÅqEðÿÅéÐÿÂIk¬xgû*ÂÎà//Ú/çŽb GvoÙâ™.^)?F,4è´Ôq“÷½‹ÈÒ3œ±' •pßðÉß ?á{ÂÒÿ…iðÿþoý ßðYÿnÿÇ¿Ùã÷Ëóÿãß÷?ý_É÷x ˜íCñOÄðPï|øi¤üð·Úu]fóRñ&­¡Þ]\ŸìíÀSEu=½½ÌÚý½%¡ 5¾È!´q!û!‚ëÿ‚`þÛÚ¯ÇÿÚź˜ÐôÿèŸ|A¤xÉ¥Õ&{ÕÔ..>øRèh:|Éå§Û!G7RIp¨d·µ³ÛܶM¦ýß§ü'ð®‘㻯ÚxgÃö¾'½ó¾Ñ«Å§B—÷tvqK¾p¾coO°FÉù–ÆØˆc ŸáÿÙëÀ>ð¨Ð´¯ø?LÑÞŸ~4ûMÚQq`–©a7”¨̶K%…ñ˜…¸B¢$Úð‡ÁÏø*ïÇo|:ð÷ë⬩r—6ZÁ¶yž9ÅÜûæ…âºS#4w31o`ñ7„ô¯iÑÙë:fŸ«ZCwm¶é|/ñ÷ìWñ¿À6þðoÀÿƒ'Æßé¾¼ðO„#¹Õô }?Fñ&±}«@cƒIHõKô·´²gkiQéöîæä†@ýŠ¿lß|mñW™¼^ž›DøùðÖë⇇m4}2æÊëÂð>гnç–êtÔ¤d×aiŽ+ ”‡È"à,Oë>Ò¼G¨é7š†™§ßÝèm¦Oqn’ɧ\4۴гcÁ<ñ\“H¹Úì?ðãözðÁÏxŸ]ð‡üá]oÆ×oñ¡£èÖÖ7ZýÆù_λ–$W¸“|Ó6ù Ë!ÎXäóÛÅš¯À…·ºOˆ5=CPðoÆïÚÖݼ%-ÅÃÝ6‘â _‹“5‘ök9´ý1/`ŒŸh‹W3KÏi½‡ísÿøí­|øÿ{eáøD¾+âG„ü7â8o4ý.ÿNÔt?\D¿³¾Ó_^Ü<ú4®-cÑí^•å2Gde¹ýÿ…Oá_øG?±ÿáðÿöGö¯öïØ³¡û7öÛ¿´~ÛåíÛö·¥y¸ßçþ÷;þjÏÑ¿g¯øsã.­ñOð?ƒì>!kö‹a©øžßF¶‹YÔmÔD®ÕÒFŒä ||‹€ƒÂvÚ­Ÿ…tÈuÛÝ?QÖâ´‰5 » '²µº¸²EË3Ã>â±´²îFã¡Yþðž•à/ +éš…¦iú.‰¢ÚEa§éöémkaoŠ¢@8ÑUQ@ ++B€ +(¢€ +(¢€<þ +ÿ&ñ/þÁ©ÿ£â¯z¬ø Gøá[­_Óíõ]"ø§Ú-'Å8GW +ãø—rŒ©àŽ ‘Vá·ÿž—ßø7ÿ@‡¿ãÂOúù¸ÿÑÏ_ß +>øWá_Âko‰Þ ðχô?¾)ý¥uÍëºV :é~%êj¶W‹æ_ÛÇ¢G}3Å7˜G`.€ì¢šÑ«+(ôûqA‚[æbÄ’I$’I9$× àÙ;ágŠzߎ¼-ðÓáÿ†¼mâ_?û_Ä:W‡¬ìõ]WÏ™gŸí1Æ²ËæL«#ïc¹Ô1ÉÐÄWüS⟅t¿º…¼+ðEðOÀ]+Äž>ÕícÓ/"¼ñÙ|_ãk9ì¢HæX¡¸¾‡@YäÔÉäÝI;›K±r¶‡ì×ûoj¿³¯ÀoÚþëCÓÓJøKwñgÇ6:MôÏ£ããkãrye²¸]ðÃglQmfÊMp&½…ä†Ö²I©}¾¿³×€SNñ%˜ð?ƒÅ§Œm&°×à5·—®[Í=ÝÄÐÝ.ÌO“ßßÊÉ&àÏ{rÄšBÚ ü+§fýŸÃ>ƒûU»×l<½:û£wöŸµ^Å…ù.&ûeç™*áßísî'Ì|€|aà_ø(·Æ…4Ò´ÿ^ðÃÿÚx‚Ãþ_kÙšz>}¥x žâÚ×_Õ’Æ3ªiVÑß]Ý$wO¨=´p,°‰?ö»·ñWíeû6þÄ:øMðÿÅ~6ñ¯Šìu_øÆÑÍ¥èK¨ÉàOÜÜÛ\$Ö·ÒÁöy·²G$ºÉjÅNd_£Ûþ ïðÓFÓ¼7¡øOEÓþxCñ>*¾ðw„4m7GѼGª[Oisewx"¶eµÅ¬¨mæ„HbTœOî«Ø5Ÿ é^#Ôt›ÍCLÓïîô ¶¿Ó'¸·IdÓ® mÚhY1È`žx‹® I¤\ívá ~Æ?¬ÿkÿˆKãÿ…Ÿü¤|6ø+àÍRÓa‚ÊÃá̲j¾2¹¿ºÒµ%†Ö[ “!›í°-¬¡¢I¿tê6è~Ôú7Œ¿h¿ø"ÂM?â6­ã +|BñÝß›êv4=GÕ.üGáõ»ž%¨³¼Šy$e0"‘GÈ6í¯«üû'|,ø¯ñODñ׊~|?ñ/¼5ädx‡Uðõæ«¥y4ð}žæHÚX¼¹™¤MŒ6»$šìÏñ +øÇûû_Ã>Õá+Ò—BÖþÙ§C?öΜ¿hÛes¹On>×uˆŸ(>Ó7¼lçøözðà +øoBð×üáíÁ—s_øOÓ4kkK] +âd¸IfµŠ4 Ž—wJÏRÂæ`I6@; +(¢€9ÙïþHÿì_°ÿÒhëàÿø/¡Æ¥à_ûüCÿ§ WÞ³ßü?ÿØ¿aÿ¤Ñ×Áð_Ù<«ÏŸú•¿ÿ õÞ¹¡ëZ=‡Ûôûkà¾Òd¼ÿQ%ë«%ÄXÏÚAû£šëè¯âsú°ä?±|}ÿC/ƒÿðš¹ÿäú?±|}ÿC/ƒÿðš¹ÿäúëè CûÇßô2ø?ÿ «ŸþO£ûÇßô2ø?ÿ «ŸþO®¾Šä?±|}ÿC/ƒÿðš¹ÿäú?±|}ÿC/ƒÿðš¹ÿäúëè CûÇßô2ø?ÿ «ŸþO£ûÇßô2ø?ÿ «ŸþO®¾Šä?±|}ÿC/ƒÿðš¹ÿäú?±|}ÿC/ƒÿðš¹ÿäúëè CûÇßô2ø?ÿ «ŸþO£ûÇßô2ø?ÿ «ŸþO®¾Šä?±|}ÿC/ƒÿðš¹ÿäú?±|}ÿC/ƒÿðš¹ÿäúëè CûÇßô2ø?ÿ «ŸþO£ûÇßô2ø?ÿ «ŸþO®¾Šä?±|}ÿC/ƒÿðš¹ÿäú?±|}ÿC/ƒÿðš¹ÿäúëè CûÇßô2ø?ÿ «ŸþO£ûÇßô2ø?ÿ «ŸþO®¾Šä?±|}ÿC/ƒÿðš¹ÿäú?±|}ÿC/ƒÿðš¹ÿäúëè CûÇßô2ø?ÿ «ŸþO£ûÇßô2ø?ÿ «ŸþO®¾Šä?±|}ÿC/ƒÿðš¹ÿäú?±|}ÿC/ƒÿðš¹ÿäúëè CûÇßô2ø?ÿ «ŸþO£ûÇßô2ø?ÿ «ŸþO®¾Šä?±|}ÿC/ƒÿðš¹ÿäú?±|}ÿC/ƒÿðš¹ÿäúëè CûÇßô2ø?ÿ «ŸþO£ûÇßô2ø?ÿ «ŸþO®¾Šä?±|}ÿC/ƒÿðš¹ÿäú?±|}ÿC/ƒÿðš¹ÿäúëè CûÇßô2ø?ÿ «ŸþO£ûÇßô2ø?ÿ «ŸþO®¾Šä?±|}ÿC/ƒÿðš¹ÿäú?±|}ÿC/ƒÿðš¹ÿäúëè CûÇßô2ø?ÿ «ŸþO£ûÇßô2ø?ÿ «ŸþO®¾Šä?±|}ÿC/ƒÿðš¹ÿäú?±|}ÿC/ƒÿðš¹ÿäúëè CûÇßô2ø?ÿ «ŸþO£ûÇßô2ø?ÿ «ŸþO®¾Šä?±|}ÿC/ƒÿðš¹ÿäú?±|}ÿC/ƒÿðš¹ÿäúëè CûÇßô2ø?ÿ «ŸþO£ûÇßô2ø?ÿ «ŸþO®¾Šä?±|}ÿC/ƒÿðš¹ÿäú?±|}ÿC/ƒÿðš¹ÿäúëè CûÇßô2ø?ÿ «ŸþO£ûÇßô2ø?ÿ «ŸþO®¾Šä?±|}ÿC/ƒÿðš¹ÿäú?±|}ÿC/ƒÿðš¹ÿäúëè CûÇßô2ø?ÿ «ŸþO£ûÇßô2ø?ÿ «ŸþO®¾Šä?±|}ÿC/ƒÿðš¹ÿäú?±|}ÿC/ƒÿðš¹ÿäúëè CûÇßô2ø?ÿ «ŸþO£ûÇßô2ø?ÿ «ŸþO®¾Šä?±|}ÿC/ƒÿðš¹ÿäú?±|}ÿC/ƒÿðš¹ÿäúëè CûÇßô2ø?ÿ «ŸþO£ûÇßô2ø?ÿ «ŸþO®¾ŠÇø{áOø@ü¡èhû_ö6ŸŸ³Ëó¼¨Õ7íÉÆvç8ÏS_¿ðptžSø‡ý +ºÿþü1_¥Uù£ÿ œ'ÿìU×ÿôïáŠ÷ø[þFØñ#ÂâoùWÿ ? ÿà¬rùÚÿÁFõøvßú‘k”T?ðUVÝ«|?õNÛÿR=vŠõ³÷úÿã—þ”Ï'*ÿr£þÿé(ýTð¬gþçþ¨…þ¢×Èuö„Óþ0ûíÿTFÇÿQ«ãêý‡/ú÷Kÿo?%Ï?‰?úûWÿm +(¢¿@<¢Š(¯záGÂÏ|3øewâ‹GâŸsuq©éÚ­¯Ù´’·³Ú£ 7µ/:)]—í1–ù€eàׂ׶iŸ´¯‚î¼à=?Ä?õ]{Vø{g=­ŒŸð’-¾™z^êk”76ÂÐÊȯ.Rá *ãrç5æfp­%OÙ)5Íïr´¹eÕµö¹t¿Ê×;°2¦Nv“å÷\“k›š;¤ŸÙæéøØÇÔf(|9ñcÄž×¼àÏ ê¾Õ[JÚqê,—̨’6¶´™U÷Œ„néÁÇMáïØëO·ø_ñ*ëž-Ò|#âoxŽÓAxîÍÔöaœ\‰7}–ÖvrÍ”8v2„Úøqûzßøj/ÜêöÞ)]{Ä:óë÷ZÇ…|IÿõåóºàÛ]H¶ó4¶ªyH‘£ +^NI ®n­û\hþ7×>*ÂKá-NïDø›®G¯›];\K;­2â)'ty-¦Ymë' +A^säTþØ’äi«(]§ Z”9¹SJÉ®Š÷²ÛgêÇû-IÍ5¼¬š–‘j¢3MÞÏÙíf•÷{rÞýœ×âG†.n´Oø6û[´ÓnuI<>F¡¡äÛ£K0%ªÚ³,HÏ´Nrã-ò×àï ßø÷źf‡¥À÷Z–±u•¬*2d–G«ø’+è_ ÁAãðØt;mÅV©†n|6úm‡‹>Çáɼëi`7§-¯ÏrL‚Ww™·È |¹Pž=û>üco€_¡ñ]¾žš†«¦ZÜ (¼Š#²¼xš8®YH"fÞ# e\œdG[ûç:{/q7_½¥Õ¬¾õWz¾œé`Ü)*s÷›÷šRÑZ:ë{´Ü¯mí¢ïé¿?cýüNð6‘ð×\ŸVÒ¼gªMᄽե\CªÛÝ y‹“ä…ÖH&A†`“s¸Šåì£*_ëEüsà…Ѽ0±Ç¬ë@êa¦ÝI#Æ–gm¡–i‰È6ñËÕ-¿h$uÿoÍSÃöº\:ÿ†|;«Å ø›OñNš46ÃÃÂÞæÙÏšZZªÊ&ˆì%†T¢0$§àoí©|»ñ„Ùé>2¹ŽöàøsÄ/¢j–ÒÄò4f;¥Ž@SÈ®+ +ʬ8)G8§NP—¼ã³¼}ëÉ_V´j-¥unewu¿mYes©Ï­¥Ÿ»e%Ñëv¢Þ»IÚÏnwRø…þ"_ø{Ä>5ð‡‡E­´7–º•È¿¹²Õ`š4– 6¶³Iµâtqæ" +ÖÆ…‡ÁoO êW}ì±ÁÜv2™m¯-ç‰&†hËm¯£Ê¬3‚ äW¯xöæMÇž+ÕÞÃÇ»üGkcm¯|Sd¶Ê/ö¤¶ÒÇ-$i `íŒ ª›[Îÿiߎ­ûG|[ŸÅ/ey`ÓXÙYîõÔ.$û=´Py’NÊ­#¿—¸’3–=z×f +¦bñUáhrêïŠÑÙ-WÚOV´ÒÚØšxJn”ï+è­-¯Ýékj´¿vDôQE!ŸÒEPEPEPEPEPEPEPEPEPEPEPEáþ9ÿ‚Š|*øqñ3ÄžÕõCw໸l¼E©Ãàmvç@ðóÉio{›Ý^+6ÓícK[¨'–I®!ŽMò2(${…W?ñ/â–…ðÖڷˆï¿³´û½WMÑ"—É’m÷š…ôqb5b<Ë«˜#ÜFÕ߹ЍfV}Ï‹4«?YhSjz|ZÞ£iqi§½Â-ÕÕ¼ +O4q½£îmÕÜÏ$\€hQ^?ñKöîøgðoÇwÞ×uO$ú/—ýµ¨ØøWVÔ´O ofÿ‰ž§mm%޲ #¸“ísÅå[Ëòl†DûW?¦üRеŠzÏ‚­ï¼ÏøJ°Öïì¼™Ùì尿†Ö_0¯–ÛäÓïj±eòrÁC!n‚€ +(¢€ ++å«¿‡úïÇïÛC⾈ÿ>$øKH𥎅5•§‡µH­â/uÇšYeŠAÖ#nÞK’k«ÿ†¿ÿ¢ëñïÿÖü‰@õEx/ü0Íÿý_ø>³ÿäJ?á†oÿèºü{ÿÁõŸÿ"P½Q^ ÿ 3ÿE×ãßþ¬ÿùøa›ÿú.¿ÿð}gÿÈ”ïTW‚ÿà ßÿÑuø÷ÿƒë?þD£þfÿþ‹¯Ç¿üYÿò%{Õà¿ðÃ7ÿô]~=ÿàúÏÿ‘(ÿ†¿ÿ¢ëñïÿÖü‰@õEx/ü0Íÿý_ø>³ÿäJ?á†oÿèºü{ÿÁõŸÿ"P½Q^ ÿ 3ÿE×ãßþ¬ÿùøa›ÿú.¿ÿð}gÿÈ”ïTW‚ÿà ßÿÑuø÷ÿƒë?þD£þfÿþ‹¯Ç¿üYÿò%{Õà¿ðÃ7ÿô]~=ÿàúÏÿ‘(ÿ†¿ÿ¢ëñïÿÖü‰@õEx/ü0Íÿý_ø>³ÿäJ?á†oÿèºü{ÿÁõŸÿ"P½Q^ ÿ 3ÿE×ãßþ¬ÿùøa›ÿú.¿ÿð}gÿÈ”ïTW‚ÿà ßÿÑuø÷ÿƒë?þD£þfÿþ‹¯Ç¿üYÿò%{Õà¿ðÃ7ÿô]~=ÿàúÏÿ‘(ÿ†¿ÿ¢ëñïÿÖü‰@õEx/ü0Íÿý_ø>³ÿäJ?á†oÿèºü{ÿÁõŸÿ"P½Q^ ÿ 3ÿE×ãßþ¬ÿùøa›ÿú.¿ÿð}gÿÈ”ïUù£ÿ ŒÅàŒuÿ„W_ÿÓ¿†+ô{Â1yÓ|Òl´‰wÍ+K#á,ìK1=ËIä’kóþOØ©¯ÿéßÃïð·ü¨‰ÿȪ¿øYøSÿPÿ§Á?û'ÿ©»E/üSþBß?ìž?þ¤zíìfëýº·øåù³Éʿܨÿ‚?úJ?Wü(™ýü:êˆXÿê#|s_fxI3ûxpÿÕ±ÿÔJ:øÎ¿aàO‚_õî—þÞ~Mžÿõö§þÚQE~€|øQEQEQEQEQEQEý4QEüNVQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@|a£þú×íñçö¦¶ñGþ(xg῎¼kme{á;+* ƺ[ø;ÃÖ—dÜÜiò_ùsl¸´y,îá(mÜFÑLŒõö}ùà<3â 4믊’~ÑïðßZñ¯ÄÛÝi|3âëf=Dx¡ ðÀ4wmNßKþĆøÅ4â 2:™¥·vóÿøOâ¿4ïÙüuÓ>8jßáñ¯Â«ý. +ß\ŸÂ)am?…®5¹¯—GÃâHµ8¼G+=ïï‘c…ˆÈÔú(óxÿãî¹ðëà…—Dý -®|ðª âÞ®özŒ?ÚšŒ:çƒ"×’Úp~Ó¨G¤Ç¯½½õw¸ûL§M¹¸¸YD^ÁðCálZ¿í“ð_ƺ5í'ßé^5Ñ4KßM¬ Ë{ËåðôÑÅqÛj¶žãOÖ™]R«u b2±¶íú(å ü]“öSý¤~>Úkž ø¡®j_|keâO Ãá¿ê:µ®µoÿÆ…¦*6£GN±‘¯t먈¿º¶„Y¥hàt™¼?âoü/ßøHüaÿ +ßþü4ö¯ŽþÛý£ý£ÿoöØuïøE>Åöïø¦þÑçÿÂ)Ÿ²¥çíjãûF¿Gè ÉˆÞñׯ_j¿&ý£ü5ðÓU´ðU‡‹üAâÿ|FÕµ–··5’Xl⸹´ñ ñ¥íƽ4«„‹–y·7ŠÿxÁ>4ÝcHøE¦Ûø·YøâG¥Gæßø‡FÕ4xn4£©j‡KÙkwut#¸[RO>wÕZ%³mKl숾ÿEQEx/À¿ù?¿ö ð·þˆ¾¯z¯øUá=SÂÿ¶/Æ_ßi·ðèºý¦m§]Òíí­î|à»A8_:1»$ *Àzïü$6ÿóÎûÿ¦ÿâhõGþùç}ÿ€Sñ4ÂCoÿ<ï¿ð +oþ&€/QTá!·ÿžwßø7ÿGü$6ÿóÎûÿ¦ÿâhõGþùç}ÿ€Sñ4ÂCoÿ<ï¿ð +oþ&€/QTá!·ÿžwßø7ÿGü$6ÿóÎûÿ¦ÿâhõGþùç}ÿ€Sñ4ÂCoÿ<ï¿ð +oþ&€/QTá!·ÿžwßø7ÿGü$6ÿóÎûÿ¦ÿâhõGþùç}ÿ€Sñ4ÂCoÿ<ï¿ð +oþ&€/QTá!·ÿžwßø7ÿGü$6ÿóÎûÿ¦ÿâhõGþùç}ÿ€Sñ4ÂCoÿ<ï¿ð +oþ&€/QTá!·ÿžwßø7ÿGü$6ÿóÎûÿ¦ÿâhõGþùç}ÿ€Sñ4ÂCoÿ<ï¿ð +oþ&€/QTá!·ÿžwßø7ÿGü$6ÿóÎûÿ¦ÿâhõGþùç}ÿ€Sñ4ÂCoÿ<ï¿ð +oþ&€/QTá!·ÿžwßø7ÿGü$6ÿóÎûÿ¦ÿâhðÇü‹Zwý{Gÿ  +üãÿƒ„FWÁ?ö*kÿúwðÅ~xv&ƒÃö(êÈéo²°ÁRd_œðpXÉðGýŠž ÿÓ¿†+ßáoùaÿĉÿäU_ü'áWüMâmðSþÉãÿêG®ÑNÿ‚«Œk?ìž?þ¤zíëfÿïõÿÇ/ý)žNSþãGüÿÒQúÍá(óûxtÿÕ±ÿÔJ:ø²¾Ýðd;¿aÿͱÿÔJ:øŠ¿aà7îKþ½ÒÿÛÏÊ3åûÉÿ×ÊŸûhQEúóÁEP^ûû&~ÊíðÇ——Z–§câÍ6{-?ÃÄñ‹KûÙ㺕mæ ¥³(¶òã*ˉ$\äð*ô†ÿ´ ïÃ…:߇ôÛyaÔu=oK×-uHî6>Ÿ-žS ´î%¦Ãn·{Ý;â§…®/.ãÔõO=׉c–x‘ìú’Ú§‘MȨa/œ†ÀžÛå.~(XkÓh>!¼þÎðôÚZ­ß‰Dþ+ŒÉ3Mö´ÕÛ :n1#ýŸ+ 2 Þ5…\Ù%ÍM½ýèoï[[u÷m¢K¯6¶Š”òÆß$ÒÕ[ImxßO%Íw{»{ª:_—ö;Ö¿á$µ†øVë÷Z ø›þh¦¹\:zHм®­¹V¡‡Ëò<Ær©±ûjðÜiÙø«ÂŸ‡u]ãÄO¯À×ÑØiöP\5¼’L²Û%À>rì»1e +kÒ4ÏÚ¼þÑ¿"Ò¯,^]!üsáCþßC¡«D/ö7¥Ì w+/•·ÌŒ¡ÀÈÛwâía§~Ξ ð^‰àÿ¶%–“àÙôi4O$÷–¦æþ[À¶úµ¬b#:%Ì‘FÑd´eXÉ,vl§\¾û¾—‹÷m;6÷溎©(k­›²éŽ-q•Noqrëï-wÌ•ÿÅ=nÉZömù ¿ì«]ë®±x›ÂRxj=øø™%»m7ìB³Ø-þ׸\þä§Ù÷†#gÏ^ñÁ°øÅiÖúî‰âKuŠ)£Ô4™%{YÖHÕÀjG"²îÚÊ謬¬â½’ëöѶ¿økâ ñvg±ÑÛNµÔâ\í¯ÛÊÓ™T½6Æ5ŒÆLFn›;²ÇÎ?hŸ ñ÷âψÚÂK-µ½®'ºû]ÝÀ†ˆMs>Ôó®&ç“bîbNÑ^¶y‹¬–&6ŸXï}/m[kv¹W÷QçbáT¥ìey][Ime}öW¾Žïmt×ú0¢Š+ùþ• ++Ǵχ“èi©´Ñ¯ˆ5H´‹gH÷ªÜHŽÑ†Ç 1M¹à²ç,.h~(·×õ=fÒ™dÐïÊràwkxgpNFÉÐsƒÜc€iQTà×­.5û-%Ý}go ÔÑma²9ZU³Œ˜d#o8ÈÍÊ(¬ßø¢ßÁÕu«´šK]"ÎkÙ’ Œ‘¡v + œ)ÆHî+J€ ++›Ò~(iúƉáø¡¼X|gåýˆ2(h·ÚKv<Ï›÷q0ùK|ÄœŽ’€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +üØÿƒ‚~ÿ‚?ìTñþü1_¤õùµÿÒx Ô©âý;øb½þÿ‘¶üHðx£þEUÿÂ~ÁVÆ5Ï‚¿öOÿR-rŠ_ø*èÛ®üõOÿR-rŠõ³÷úÿã—þ”Ï')ÿq£þÿé(ýzð5·ü`Ÿ‡\ÿѱÿÔN:øZ¾úðM°_ØÃoßþ…—þ¢‘×Àµú÷;Âà¥ÿ·Ÿ–ñm7ÿ_*í¡EWè§Ì…Q@Q@Q@Q@Q@Q@ÓEyö©áˆ¼oñ·Y´¾¾×£µ°ÐôÙ †ËY»±^K‹ðìV P1"(ÆNNW ×!¢ÿÉ|ñ/ý‹úOþ”êuüNVüwðšzÇÂÚ2Áy¨h¶º…ÏöˆºÔ%žo³M§ß@Û¥‘Ì­—Ta‹Ã Ç®|ñ^± ë°jâmF9üX/åKg$ÚΞštvГÊý™¤ó'‘dU@Ñ;FgÜh ³øªé62ÝŦMu{—c&š·7ÍsYj’ß­ƒº,qÂ&W·D*ÐÅä‘–X£2M¨| +ñ ¤²F×_ÛVÖë)ýÜPl«ÛKNßfü4ÙNûd"6þÒò²‘ÄsítPkß5]nÏ\’ÏÃ0éÖSèzì&–íl­¤Msk§ÁJ¨æ(Œ¯ãæ6+‰˜³+;-zÏÃÝïÂßÚ6Wqyì×ëûWr—Õ än”g+2T Á—±sIEyg<+®Ccð÷D»Ñ/,WÀ›>Õ¨K=»Zßyz|ö¸ #Jw<ÊãÌŽ?‘[;[ +y½Oà¶±á{‹Oì;ËK!¬%Õõ¥µÍÍΰ‚×­nq<±8¸¹Xç•"S"y°Æò{½âšÁ Û ;Y7:=åПÃöš}¨šò×í«¾½ž[U+vÅ%¸û9O²¶Ä„³Ä¥ë¶ðïÃ(µhÖº¬–=Œo‹]/Y»²Ž혂l‹|‰Ìq»"†nÖŠä?áGè¿óûãü+5_þH£þ~‹ÿ?¾0ÿ³UÿäŠëè Cþ~‹ÿ?¾0ÿ³UÿäŠ?áGè¿óûãü+5_þH®¾Šä?áGè¿óûãü+5_þH£þ~‹ÿ?¾0ÿ³UÿäŠëè Cþ~‹ÿ?¾0ÿ³UÿäŠ?áGè¿óûãü+5_þH®¾Šä?áGè¿óûãü+5_þH£þ~‹ÿ?¾0ÿ³UÿäŠëè Cþ~‹ÿ?¾0ÿ³UÿäŠ?áGè¿óûãü+5_þH®¾Šä?áGè¿óûãü+5_þH£þ~‹ÿ?¾0ÿ³UÿäŠëè Cþ~‹ÿ?¾0ÿ³UÿäŠ?áGè¿óûãü+5_þH®¾Šä?áGè¿óûãü+5_þH£þ~‹ÿ?¾0ÿ³UÿäŠëè Cþ~‹ÿ?¾0ÿ³UÿäŠ?áGè¿óûãü+5_þH®¾Šä?áGè¿óûãü+5_þH£þ~‹ÿ?¾0ÿ³UÿäŠëè Cþ~‹ÿ?¾0ÿ³UÿäŠ?áGè¿óûãü+5_þH®¾Šä?áGè¿óûãü+5_þH£þ~‹ÿ?¾0ÿ³UÿäŠëè Cþ~‹ÿ?¾0ÿ³UÿäŠ?áGè¿óûãü+5_þH®¾Šä?áGè¿óûãü+5_þH£þ~‹ÿ?¾0ÿ³UÿäŠëè Cþ~‹ÿ?¾0ÿ³UÿäŠ?áGè¿óûãü+5_þH®¾Šä?áGè¿óûãü+5_þH£þ~‹ÿ?¾0ÿ³UÿäŠëè Cþ~‹ÿ?¾0ÿ³UÿäŠ?áGè¿óûãü+5_þH®¾Šä?áGè¿óûãü+5_þH£þ~‹ÿ?¾0ÿ³UÿäŠëè Cþ~‹ÿ?¾0ÿ³UÿäŠ?áGè¿óûãü+5_þH®¾Šä?áGè¿óûãü+5_þH£þ~‹ÿ?¾0ÿ³UÿäŠëè Cþ~‹ÿ?¾0ÿ³UÿäŠ?áGè¿óûãü+5_þH®¾Šä?áGè¿óûãü+5_þH£þ~‹ÿ?¾0ÿ³UÿäŠëè Cþ~‹ÿ?¾0ÿ³UÿäŠ?áGè¿óûãü+5_þH®¾Šä?áGè¿óûãü+5_þH£þ~‹ÿ?¾0ÿ³UÿäŠëè Cþ~‹ÿ?¾0ÿ³UÿäŠ?áGè¿óûãü+5_þH®¾Šä?áGè¿óûãü+5_þH£þ~‹ÿ?¾0ÿ³UÿäŠëè Wàf£q«üðuÝÜó]]]hvSM4Î^I]­Ð³3I$’Iä“_ÁÀ#3ø#þÅOéßÃ÷§ì÷ÿ$Àÿö/Øé4uðgüðn¹ð?ýŠ~ ÿÓ¿†+ßáoùaÿÄŠ?äS_ü,ü*ÿ‚± xƒà·ý“ÆÿÔ‹\¢ÿfñÁoû'ÿ©¹EzÙÇûýñËÿJg“”ÿ¸Ñÿô”~ÀøBð¯ì á´ÿªeÿ¨¤uð]}Óá'öðßýûýD㯅«õþ_»—ø)íçå|C+Ô—ý|©ÿ¶…Q_¢6QEëÞ"ý“çÐfK/n+IŽåþ„-Jɧi÷3\AmvÒ–Ãy’Û‘°/Ê%ˆäïÀò1mŸR·[Çž+C"‰ÞH‰‘¸ª’¡˜ à=ÇZúgUýº|#⟉(ŽûáΓgá/h²x\^Ú=ìšÌlq*XŸ&KÓgæÄÐ[9 Ñ¶Ò Ý^Fk[OªÅ»;ÊÖÕ+{ºÛ⻳Z¦O,¥†œ¥õ™$­e{èßÚÓuí³ºÔâ>#~È—ÐøÎÓOð’ý¢Ê? +i Ô¯uRÓOµ²{Ëh\«\ÎЊe—lj͸ôˆ&°§ýüiâ½CHŸLÒ­¥Ò¬mµ;»Éµí>-2 {¦ÞF¾iůïw.Áæå³À85íÞñ´µß…üIá]+Ã_ït¸´ }¢çÃÚ4z¶£iu¦ÛC›!q›o!š_œH +¡+Éÿi¿‹^ ÓüS↚Ýljlôƒ£øfÜêZ}¬·ºuþ™cä½¼ÖÆx£~'•,ÃË–?ãÁ¯–mE…²rI6¬Û·¹y;K§4½Û]Ù[uQåØ9ÓöíµU­Ò\ö~î«­®å{+¿åg‡iŸ²Ä NÿÄÊÀxBæ ]b}KX²Óíl^uv„´óÌ‘!ØêÅraŽôÝÕxSö*Õ<wâhc6ž¸ðß„ì|Fkþžé©} À„í$Ë)Ýåü‘¹,êMŸŒµ~ƒñáŒ|7aa¬Aô¾´Ñ$¸Îlô«Yí·Ü°s¶iˆÛP2Œ°Ýò†møj¿xƒÅºÌZœ^$±Ð|EðçNðeÍÍ­Œ7v—6±Ù“2BÓÆ’Fdµ#Tm®m®‰âsiAË‘Eék&ßÃôæ³»rIZêÖ»z˜Ó¡–ƤT¤Ú{ê­ñµkÛ¤lù®¯½’Сâ/ØC\¼ðÃûÿ gê:·Š,îÍÕ¼Þ$ÓnîᾸ·iêÒ©»ù"Œâ1&EÁà<—„ÿbÿ‰8ð¶¬iš­Å®±m=å„-¬XÅy}é;Åló ÜFѾý¨J“€A=f—ûKøSÃ^?øuiˆo4¿„÷ßK5œ0\^Ä5Y®Õ£ŒLêÄê +³€#qqÖÒlo Xx§À÷Ïc¯¼5á¿è÷@Cé&ÔPhY?yÊ(»y8#k`6aâ³zp—³Š–³jñ{'QÅ|K{A-¬ž·eG–ÎiT“•4í%«|ŠOáû7›{Ý­,´<Ò_Ù#Çø¦$éºS=Æ–u¤¾M{Om+ìBFˆÜñ?ÙU<Õ1äÊ>|'Þ GâýWáoŠ$Ñõ˜­#½Ž(§Öö Ø%ŽXÖHÝ&Þ)‘”‚¬G5íþýª|9¥øCÁzTú—‰ô<=ák½öh<=§k¶—²M©½×—%•Ü«ðÜråY%E!X ×–þÑ>9ðïÄ_Š7:Ÿ…ô•Ò4·¶·„¨²†ÃísG +$·?f€˜mü×V*2Q7`^– Ž–%Ó¯¢¹µI­¤ÒwnÖ”u²»ôG#ƒT=¥)>owF×Xŵk^ê\ÊöJÉk}ôa\†‹ÿ%óÄ¿ö/é?úS©×_\†‹ÿ%óÄ¿ö/é?úS©×ò ý.uõ›ã[ø#®µv“Ik¤YÍ{2B‘’4.ÁA …8É=ÅiT:Žo«éóÚ]Á Õ­Ôm ÐÌã•a•”ðA‚øgGø“⯉Wž Ö¼IñwÅÞñWŽ­ãÕ¼?¦øzÒ$ÐtËiÜÉaì¥îY‹“ °°U?Ú従ÀºJê—©©jÚ¤7·‰n-ÖîáÉeXÁ!Y‚äà+“ðOìÕ¡ü<ðþ¥é¬òÚøjƒO–ùEÕÝ¢7±JßêÔ¯Ê@UPT"ªÿO±L±ŠÞ<ì‰v‚z·©>äòO© 2Ѿ=ê–—­,ÖVvÚŽ•âˆ4¨×,ésa6®lãü®|»…ÚXüðï +ªÖ÷>;hÞѵé¡i¯.´[;»„F‚hm¯e·‰ä{xîJžAå¸dFf_.L¯îÜ +z·À}_HÒ¡mJhn´I¯ÇqAL©&¢×¯hã91’P Ñò¬ÛÙkK½Õµ£/ö:Yë?Ú ÷hЮ°Zõe†½bÙAçÉ´,hÀ,JY•\HÚéßômNê#¹™n./OH¦µšÃZ}°FÊê +Ÿ³çp?)Ã|µOLøÓá½f}=mo¦š=J8$†ál§û2Ñ^’mž\R:¼ec‘•Ï› —\äk_Ó^Ô5MJkècÖ/ìá0ÜÃlâ;=A ,o6îìì…‰P-1“æI¸µøš<ëa¦ßCgᆼ°¿’Å­ž[•–É-–ŽàÉ…vûƒÆìyóÀ Þøç§x£Å ›:=öŸ§\énÖsÅsy%Ìרq(r›-„€ì y Ø7¾}zÒß_¶ÒÞ]·×–ó]CÖ;㉢Y8ÀÁš1‚rwqœpžýŸ¿áþκµÕök?‡ôíÊôZãoÙ|íÅ×Ï Þjï‡#Z²¸uGNÆ^»×µý;TÓuOì«ë+{‹”Û-Çú<í HPÌ ”vƒæÝä`;ãg…µ4‚HõxVÞâÍo’æhÞqCö€­+¨E“È>i‰˜H#ùÊ…æ‹_Œþ»žÒ6¥ Õíäv0ÚÜiWp\´’$ŽŒaxÄ‹X¥>iQî¤ù¾FÇ9§~·`Ñ®µù¤Òdž×÷g´H..#þF å—Ë4¨¬"I#â_-Þ&›Áß³ü^Ö´Ý@7†ì¦°ÔãC¢hé¶óªÚÝ[¨`ܾn™‹3²á*).Ì×øSǺOþÑý™wö³ífÌO™gdɸ2ÚÛ%LÆû[k§/Ç kÚI¾‚öò;sn—P›6êÙ¯cfUV·Y#V¸ËIrZX—¬ˆ ¿‡¾»ð_öˆ¹Õ?´öà̈–ËnˆNwHÊ t„–Æ#Ÿ,±#4…üûÂß³ž§âO…Þ°ñeæš×ZF‡m§ÚÙǧfr¯i;Gt η#̳…[aˆ2ù cz”ôâ·®êÖÓÞíGÏÙm&ŸqÐù+Iç+ 0`KhMÂXÊçzä—â·‹'Ñ^{ﶏŽÒiO¸‘M"#Ç\ìòC°–0ª_%¤Esr>ü‹Àšý–£š< oo{ –º^‘hZá¬ÎäEf#Ñs½¤fi̪ª‚œ_ õ½gÇ>${ËË;O^ø‚ËV޵/wtÖÖö,Œ³ vÆž}°VFˆ±T|½Y@6 øïá‹&Âý/o ž£n/oìÛ °[–`·þïýÚåd›b2£0%T‘›ãÚJð§ˆ4ët–f²[˨õKÆÓ®^Úmì®§—ËSÊyà +Ȭì6È»w)ÛOþîâßÂú-¶· +ZÝxn×Âú»É`^K«hT„O7.%\˜þ_”ïÐe1à5쬿¹È +€–Áb×ø‡â^á}BkK»™¾ÛpÊm µšâyDÆaŽ8ÕšB~Ï3@J¬LĪ~ø±câÿ\èöQÍ$pépjIsåH—žâ†@PyRFð`£ù.6ƒã +o‚ÚÝç‹Äw>%³›_ì­j²JØÛ4){H›Ìdhï¤83n ÛŠô~ð=Þ‹â‰5{­SûBòûOŽÎû6Ë»E4ÒÄb +v‹ö‰—kyŒTE—Ü®Òt”QEQEQEW+ñ“Â㿦˜¶pêͪi²Ü[ÌÇ-¼wÖòL7 <¤rTõq^}ÂsA·¸fg +_[ë—ñ¨·?kµmJgÆ>\Žšx-ÖPb‹*Ž )öº†Æåîág’ÞkV:”¡f +åCü¬FÜá†Bœ¨ùòÏàŸ‰‡oí-tJÎÊ)/Œ6ײiñÉ{§Éob%Ò„v¬-í…ÜÉ+yñÑKºV'J/€z^^è6sÍ6¡n-f”Àî-Ä…ÅâI*’XÜ.ôãÌI +ÇrлÑ^«ü0ñf“àÿiö:ÛßÄš=æ§Æ/a†->ï56[-ò¡¶»aD Mä¨Ü kà¢Úv±=¦ƒfš¥Ý¿‰o# 3ê2_yšUÆüƒç$O/—!9„; ¡b»Ñ\W>[øûâvq©é°êZ%Ž—¨C4Ó¼!g¥Þé3_ßj:§‡õFúmB& dÓc¹F%‹É8{Iàld93â2î5›àï[øßÂVµh“Gk«ÙÃ{ +L‘RD¡€$†Á#=Íx×þê>Ñtm ÙØ_iš†Îø ð]¥ÑþÖue<<–Â5•Áýò*®_¬ßü Ö×á¾§iþ›Â3ÙèvöZâBÖ+'ˆfYìžB¢7’)•âµRnö°)$»@>‰¢¼ƒá/Á» x×C¿›J¼ƒNÓ­õF¶MA¬LÚl“=$V¨°Á¼EtqàC³3•\ñ/ýFÿâ]ÕÚè¿h¾¸Ö,otÿoƒþ%V1 o´Yïg æyWCdhÑ·ÚþfäÚè>ñE¿|5g«Z$Ëe¨ÇçÛ4 +M s¸à:mp Ê­•Uå–_ .áý™|)áUÓþÇygýŠoííg[v‰¢»¶–íÖHØaÆÙ\º6âÙ*KžoÆÿïî5«˜"Ò/$ð…¦¡;Xèú\:dˆ‚K[ ’¥½è6è‹,wÙ ,ç%AY$$ÚôÍzÓX½Ômí¥ó&Ò®­ÒíaåHbŽ`¹#÷rÆr2>lu •â‘üñŒ³ÜÙ|ž ]BÂê-U¥Šöié_ÙnÒK ¥{fyî°Ñ…”«†•Ädß5&õŒÚoöþ¥\ZéÑèø€ÿjiEzÖé¶W¿“%ô)¶fÿgù¹guZõŸx¢ßÂdWw)3Ç5å­X=ÅÄp!äŽȤ÷À8ðt«Â"ø®\-ì¿`û ÄßÙ)§M۵Ɠk½sxöé»r/ÙíšØl¢&Tó +ï/<¨jÿI`9]¤&7,Ͼ|ð·Á/ø(Ÿ‡4o Ø_[YKà­CR¶ê·Zƒ™þÕo`g‘‚mBê +q+‚H ±ëæV ÿ>ðÙ(?5ЧÛ×ÓÔÈ~Ïò@üÿbý‡þ“G_Á~o<ÿbŸˆ?ôïáŠûÇö{ÿ’àûì?ôš:øGþ à¥ïüý +~ ÿÓ¿†+ßáoùaÿÄŠ?äS_ü,ü(ÿ‚µ.ßüÿ²xßú‘k”Sÿà®+³Å?ÇýSÆÿÔ‹\¢½lãýþ¿øåÿ¥3ÊÊ?Ühÿ‚?úJ?\¼Ïì!áÏû!ö?ú‰Ç_ WÝ~ OøÀßú¡ö?ú‰Ç_ +Wìü9‚—þÞ~SŸÿõò§þÚQE~†|èQEQEQEQEQEQEý4W!¢ÿÉ|ñ/ý‹úOþ”êu××!¢ÿÉ|ñ/ý‹úOþ”êuüNV}Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@GÇ‚vÿ­<1 ÍüÖ áŸÙxŽ3aÌòÚ1’8ÎO +dÚ[¹P@Á!‡Sö}Kþ~ìðÿøå^¢€(ýŸRÿŸ»üþ9GÙõ/ùû±ÿÀGÿã•zŠ£ö}Kþ~ìðÿøågÔ¿çîÇÿÿŽUê(Ùõ/ùû±ÿÀGÿã”}ŸRÿŸ»üþ9W¨  +?gÔ¿çîÇÿÿŽQö}Kþ~ìðÿøå^¢€(ýŸRÿŸ»üþ9GÙõ/ùû±ÿÀGÿã•zŠóOŽ5¶ºt1ü@ñ?ƒ–Á¤f>XmÞïvÜ U•ˆ]¹J‚X’…Ûç_ðïÝ_þ‹¿Æ_ü´ÿãô…á¿bH¾|c‡Æ×ž>ñ¯Œuk}2m&1®Ko*ǯŒÇ6wF¤d‘Ëq“š÷*( Cö{ÿ’àûì?ôš:ø[þ Ì3ªx?ô)ø‡ÿNÞ¯ºg¿ù ~ÿ±~ÃÿI£¯…à½êžÿ±KÄúwðÅ{ü-ÿ#l?ø‘àqGüŠkÿ…Ÿ…_ðWž<_ðgþÉáÿÔ‹\¢ø+ÇüÿìžýHµÊ+×ÎúýñËÿJg•”¸Ðÿô”~ºx,ÆxwþÈ}—þ¢q×Â5÷ƒü`G‡ì‡Ùê'|!_¯pðåþ +_ûyùO_õò§þÚÝþÍÿ-¾;üT‡Ãך´ú%¡±½Ô'¼†È^IZÚËrÁb2F˜DTeÔdõ®½?ö=øÏ§|øëcâ]VmjÖÒ ûO´i,—¶²\YÍrÆ­$@”y¿Ö)ùx9¯¸Ì%Z8J²Ãüj2åÿ¿. SxŠj·ÁÍoðÝ_ð¹[þ‡þ"kú~‹ðÓWñOŠuëÓ+}WÑ,ômê‘—Ä,/çód;H€Žîbµþ~ÇzÿÅïhúEíÕ‡†Ó^Ñ/õÛo/-VIa¶ŠV¢’hÚ5‘ãÚöü›¤‘×G¯|еïxkQñÅ_Ž,<=vÚŠYk6¢Õ–x×tK¿Úw-"€è¹e @t~מÖÿiý/ân«mâ½×t‹­;Å–°Ä’¥´ÓYIdf±2M–M޲dØ©Eb»Jø•qY—²”h«¾IYµ¯=¥ÊµPZ»jãek>nuËëÓÃà}¢•gd¥¤ôq¼y¶rz+í+»Ý[‘óyÝïì™ã]?Â7þ ’ `éÓËi&¤ž)ÒžÒYã…&h!•n +O/—"‘E™°ÁA(ÀRÕÿf¿iºñ:Å jZ=„qMxúWˆ´íNkå!Qç‚Úy%…KRdE˜)Á V×Äo‰þo€?<=?ˆu4ÒüŽ^"Ö¡{ùtí;ÃZ-ο©Kofon¾ËÝâ –LºðΊfgP¤Óõ…zеMøo­ø‡Æ:¶µq%«i·Úé—p0ØQ€K‹ˆž6 ÿ7˜ +ùLYBáO'Ñ|ã7Ôum{ƾ¹¶·fÓ5 ¬o{as¹Fâ,%ÆdS¶hØ$­îGö÷±Ð§³uwedVêiæµ·[™Ð+¸ ¬L­È³…Éâ»~ÇZ·‹¼Uà¿Ý­ŽœÞ*ñ1Ðá!µñ›ªi™ò ¤i˜i#YƒçåÖ5Ôç¶øuûS|7ø3àxGoëQi7!¹¹¼¼ÒílÚvÔt¡gH’ê]¡FìÈ~PXrv/áí=¥ü0ð/Ã;3a¨]êñäž+¹Pa¸·)fhÛ·y™·~ªÊòyjbó:²—²…£önšz¹ë«[%f¾ÑÃ`©Ò‹©;Íó^Í4¬•º=ÛkGÓC’ø•û4ø›á¥ž³}0ѵ=#C»ŠÎê÷JÖìu$·iL¢0[M!Œ¿“' ŒÁ#<ÏŽ~k ¯ì­u»?°Ý_Ø[êPÂeG"tD̉BÈU‚¶ ¤€¯¢¿eýgÁ—í%â«HÄž#ø]â] P½ñZjvésÙÛÂZí]|»‰Ô˜åН¹K´…vÃ>ñ‹âu÷ÆŠZ÷е-‹w®^=ÓFƒ “òF£²¢P=WVŠ©_ØUJÊ*MÙ§®‰Y½ÔÛén[nN? ……9V¢ßÄâ•ï¶·½¶åqVÞí¶ô³þëÑä¾x—þÅý'ÿJu:ëëÑä¾x—þÅý'ÿJu:þC?¤Î¾±þ!x¯þ?ëšçÙþ×ý§Ï}äoòüï*6}›°q¸Î3ÐÖÅñ¯ÁßÙ¢ËãïÂïü@ñ§‰îÛNÖ?²ï~ŷ숬g»Ž‚ ÌóK°¹·˜eÀW+sRø-¥ëÚRÝOy-ö©§Åe%èXRâ)í‘•Œ¹% bêÍ¥¾yK¾ iqêË%´÷–:Y¸¶¼—H¶XRÊií–%‚Oõ~jlöøHäDýÊåH/¸ÀßÇŒ¡$Wº•ìš„ˆÎ÷seT@ˆ¹o*€)–Mó8T#„M¼‡gQ¦xE±×uKSÔô.ÚÊÚUhV=)ãkyso¶ÞÖÐ0óÄ„ˆT†pÀ^ý ôo‰¶Ÿe¥[Þ\M{ö¿9£šÚh¬>ΰ3y’G3#îPcÉi9“ ´«…ÍoŒ£ÃßöØO©ïµKYÌ—l‚[Aj#Ü`~Çâ噋9Ý’0/í¥ÙøN}zóNÖ,4SoÕõÂB¶úœr:$LŽ$"æX°.|“‡$à$…&Ð~=h~#øc­øª×ΖËÃÑÎ÷ÐÃ,!Š!3"¼R<.Ll¤m€[i*Á‚–ìí4?ììkÒéö‘×nÓD#ÑÄ2G$& ±0ÆðÂU®<ãˆðI }¯†ñjžÖ4 GUÖ5%×mæ¶»¼¸–?´–?(ì +‹xL0¹ˆ,ÌÌ…âÚGCðžŸ4º®¥¦Ü,­½­ï‘i%Üs š)CK*Çe·œíãв+2+Sðÿí#gâyä¶µšçA–ÏMh® ò¢ººÔg°h„¥\ #h·!ÊÁØ÷t~'øMgâ_>´·Ú–Ÿ«í’ÞêÙ¢-haûR‡E‘ d¼z°Ã° Q^üÓõ+ÈæÔ5‰.5 $|TÓþkzwÛα"ÜÛ»,í–u“7vVÁŠæ³«Ý&Õ9V“åf*ŸŒ¾(M7ÁŸêš|7š>µáÍ>ï|IÍcr–¾|{¶4‘?Èñ8Ú̸p!”køÓá~Ÿã­oL¿»šò9´­¾H…Ô+bîÒïæÊ’ygà•œu ƒVø_§ë'‹¬%šñañŸ™öÒ®¡¢ßi¡òþ\Ýħæ ózpˆÞ=ÓþŦ^jww–voq7˜ðIJ!H¬înÍØaåüåÕ*Xü|±ðF€×ºö¬hS5ÄvÐ[_IiÚYÕÜm¸óþÊ>X¥$<ÊÃ`fHÃÍ©|‡Åimâ^ñ¬rHâ±k +âK[‹Y6ðÄØhî_<äB䦸H׶ѽ׉|Iwª[\-ͦ¥#[ ¬™c’?Ýİ‹~Ri”–‰˜‰99HÊcÚ~Óú¥d÷VvzÅí¶žº¥íͼQÉoal%¸ŠYA&ÇòžÚLˆ‹´ƒ •CØ—ã>Ÿký£u>Ÿ¬C¡iŸjYuŸ!d´/kæy뵦]†)WsĨ͘¼{ËŸƒ}þ“¯ZÜêÅÓxG5íÄÓ«Ìц¹c"¸W&î^òÔUEUÛD¿4û¯íYõ bm SûSK£yë {¯3ÏmÈ«3o2ÊÛ^VEi2ª¥#Ø|)øÙ£|_ûzi­²ãMòÚx~Õmuµ$ݱ¼Ëie‹“»÷¹*)nn×ö±ðï¿øƒÅ¿Ù²x“O[ÉñuiÀ#<‹Üy²!R!,›HC§»ð§…fðçÚëZÖ5Ë‹ªf¾h—ËEÎc†8â³Û7¶@f!P/-«þκuÿ†ŸI´Öuí&Ê}/ûámZÝÚâÅ|Ñ »a|’iYvÈCeÙØÃ_‹7ZãXk:”mu®jšu†¢ëoökÃÕÖÈTFæE+ óIƒä·ÌK.ïA®CÃßm´}/VÖ/­íµ ½RÎÆãÈöW7-1’D)ÊÜ\N Hî HxÈR:ú(¢Š(¢Š(¢Š(¢Šä?g¿ù ~ÿ±~ÃÿI£¯…¿à¼£:·¿ìRñþü1_tþÏò@üÿbý‡þ“G_ ÁxFuØ¥âý;xb¾ƒ…äo‡ÿ<(ÿ‘Mð³ð£þ +ö6øÃàÏý“Ãÿ©¹E;þ +þ6øËàÈÿªvõ"×(¯c8_íõÿÇ/ý)žVQþãGüÿÒQúéàÅÏì áÏû!Ö?ú‰Ç_WÞž +ñ€¾ÿ²eÿ¨œuð]~¹À?×ø)íçå\CüI×ÊŸûhQEú!óEPEPEPEPEPEPôÑ\†‹ÿ%óÄ¿ö/é?úS©×_\¯ˆ~K«ø¾mjÇÄšö…uug ”éd–© ÌèHž  Ï'BqÅŸÕ‡UErð­5¯ú(^0ÿÀm+ÿèÿ…i­ÑBñ‡þi_ü‡@}È´ֿè¡xÃÿ´¯þC£þ¦µÿE Æø ¥òuôW!ÿ +ÓZÿ¢…ãüÒ¿ùøVš×ý/à6•ÿÈt×Ñ\‡ü+MkþŠŒ?ðJÿä:?áZk_ôP¼aÿ€ÚWÿ!Ð_Erð­5¯ú(^0ÿÀm+ÿèÿ…i­ÑBñ‡þi_ü‡@}È´ֿè¡xÃÿ´¯þC£þ¦µÿE Æø ¥òuôW!ÿ +ÓZÿ¢…ãüÒ¿ùøVš×ý/à6•ÿÈt×Ñ\‡ü+MkþŠŒ?ðJÿä:?áZk_ôP¼aÿ€ÚWÿ!Ð_Erð­5¯ú(^0ÿÀm+ÿèÿ…i­ÑBñ‡þi_ü‡@}È´ֿè¡xÃÿ´¯þC£þ¦µÿE Æø ¥òuôW!ÿ +ÓZÿ¢…ãüÒ¿ùøVš×ý/à6•ÿÈt×Ñ\‡ü+MkþŠŒ?ðJÿä:?áZk_ôP¼aÿ€ÚWÿ!Ð_Erð­5¯ú(^0ÿÀm+ÿèÿ…i­ÑBñ‡þi_ü‡@}È´ֿè¡xÃÿ´¯þC£þ¦µÿE Æø ¥òuôW!ÿ +ÓZÿ¢…ãüÒ¿ùøVš×ý/à6•ÿÈt×Ñ\‡ü+MkþŠŒ?ðJÿä:?áZk_ôP¼aÿ€ÚWÿ!Ð_Erð­5¯ú(^0ÿÀm+ÿèÿ…i­ÑBñ‡þi_ü‡@}È´ֿè¡xÃÿ´¯þC£þ¦µÿE Æø ¥òuôW!ÿ +ÓZÿ¢…ãüÒ¿ùøVš×ý/à6•ÿÈt×Ñ\‡ü+MkþŠŒ?ðJÿä:?áZk_ôP¼aÿ€ÚWÿ!Ð_Erð­5¯ú(^0ÿÀm+ÿèÿ…i­ÑBñ‡þi_ü‡@}È´ֿè¡xÃÿ´¯þC£þ¦µÿE Æø ¥òuôW!ÿ +ÓZÿ¢…ãüÒ¿ùøVš×ý/à6•ÿÈt×Ñ\‡ü+MkþŠŒ?ðJÿä:?áZk_ôP¼aÿ€ÚWÿ!Ð_Erð­5¯ú(^0ÿÀm+ÿèÿ…i­ÑBñ‡þi_ü‡@}È´ֿè¡xÃÿ´¯þC£þ¦µÿE Æø ¥òuôW!ÿ +ÓZÿ¢…ãüÒ¿ùøVš×ý/à6•ÿÈt×Ñ\‡ü+MkþŠŒ?ðJÿä:?áZk_ôP¼aÿ€ÚWÿ!Ð_Erð­5¯ú(^0ÿÀm+ÿèÿ…i­ÑBñ‡þi_ü‡@}È´ֿè¡xÃÿ´¯þC£þ¦µÿE Æø ¥òuôW!ÿ +ÓZÿ¢…ãüÒ¿ùøVš×ý/à6•ÿÈt×Ñ\‡ü+MkþŠŒ?ðJÿä:?áZk_ôP¼aÿ€ÚWÿ!Ðû=ÿÉð?ý‹öúM|5ÿÝÖ|ÿb—ˆôíáŠýðw…íüá +E´y¤µÒ,á²…æ ÈÉRÄ ÂŒàžÂ¿?¿à»c:Ïǯ„¼Cÿ§o WÐp¯üðÿâGÅò)¯þ~Á`†²ÿ…ƒuâxîoôëó¿i41GU‚ÞGBb“ 0qrpÃæÇ”ó\l±q¦ãÓ„®áfí»³—»µæÙÛÑþÎÂÆŒÓ¨œ“Ñ©G[*—JýŒ=禪˿Ͽ~7Á/ŽÞ#ð@¿›øR}8]´GžU¶î)¹¶ý7z×iñ;ö&ÕþÇâø­¼[àÏêÞeþßÒ´©/–ïOŒÈ"2ÿ¤ÛB’¢Èñ«y.äãnHÇý¬>!èß¿kOø›C¼7Ú«®Kyirax¼Ø‹ä6LJˆ»ïÚ—öÃÓü]ñ{â +x#GðÖ™¡øÇTû^³‚÷ûG\³IDª’}ªW«:£²Ã%ŒjÀÛZÓ­˜ÎD“æ”/;¤’»º—mì•×dÈ«K +¸—§,eh$Û¼}ÿ†Ûí]Öºî$½ýœ>!éš¶—§ÜøÆv÷úä³A§[I¢\¤Ú„ÿ­HP¦ddÁܽñZ¿ ?dïüOø¿uàK}SÓ2ÖïôÍÁ~,Õu-.ãìw¶–zEÄóÚO‡>Tˆ¨YHv°÷oÇÊqƒâo ê~ ×®´­gN¾ÒuKò®lï`x.-ßû®Ž)ö"¾øãûLx_Å¿ ~#hZVµus{ªKá{n^ÞXŸÄ‰¦ÚM Åãü (iNR„À…óÚÃâñ7Çš þ‹yöè­|+¢é×R˜ž2.mì!†U;ÔU®îAÇŒWf‹«VÕ©òÅù?儯wÒòqµ®œuÖésb°xjtÛ§Ròµ÷_Îã˦îÉJéÙ­•¬ÏèfŠ(¯ä#úX(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š+ó·þ ²3­øþÅ/ÿéÛÃú%_¿ð]ùxþÅ/ÿéÛÃô+ÿ#|?ø‘àqGüŠkÿ…Ÿ…ðXoùþ Ù;?úë”S¿à±8ø5ÿdìÿêC®Q^Îqþÿ_ürÿÒ™äåî?Áý%¯ +ÿ”xsþÈ}—þ¢‘×ÀÕ÷¿‚ükÿÞÿì¿õ޾¯Ö¸{“ÿ/ý¼ü·ˆ¿‰/úùSÿm +(¢¿E>h(¢Š(¢Š(¢Š(¢Š(¢Š(¢Šþš(¢Šþ'?«Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ¾Nÿ‚ÁÁý¯û>øOHš{¸ôÝkŰÛ_Á Ë·‘%…üë›Ü¢Xb}§Ñ©ê}c_%ÿÁ`%0üð dxÎ>¿ö Ô«êøÿÛ¸koͧ­ŸÈñ8ÿÂekö?3õ Ï ÙÏ"/‡4`ˆÅA6à÷ã¿›w¯hJNßh¹SÈ[qÏçX7w†Fr‹g<~\Uzþ×§—SKÞ»ù³ù¾UßDmɯéD¾ÑÀ'ŒÚ­'öþ–Iχôl{Z®kŠßêT{~,ÏÛH×:îœÙÿ‰Š3éf¼R gN8ÿ‰&Ž=þȵ“E?©ÒìÚFƒj–LüIôŒõÿ8úþU?ˆ4Y¼5w§‡ ÓgšîcŽçM<‘H¡Ò@ «© Ad»ðƒÀmñ7ân‹¡ît†úä ™T¨·P^iO²D®çÙM}9¨è>ý¨të¿hn³ãýOÃpÞÙÅ ê6/a%ì“\}¢Ò–·RK"E —¥Dr£°³ €χšæ”0¡ ÂñkÞkìßHÝ»E)4ÕäÒóÜôð˜¨Ë•¤öŠïüÞo•jÒMöGÉú®›ý‡r°ÞèvÖS4I8Ž{š9:>ÎÖFV¡i-õ‹IÒIÆrÖˆr*úÇâ'Âï xÓâF·/ˆ¼;o£]ü=Ó4}oXÓ–úâ?´iË£À¯`7ÈYJܬÉ‹¦ÜÇ`"ÏÁÙ?Â~.ð‡î5ŸL~Ô4{çÕ¬,54ë´»¿¶‰­¾Ý%óÇ$¢)Ù]#¶Œ££'Èwy’âì0ñ«^œ“|›Y«Í]Yók£OÑ£µpþ"U\)I?‹{¯…¤î­¦èù +mBÒAÆ“¤ŽçÎ>GåL3Ù“ÿ Í0ÛªWÑ> +øiáO‰~µñ—à+)µ¸Ž­k§xbÒöþTñ–ß`)¿3™ÞTŠêâV[w0ªÕü6ý|ªé—Ó뿵Øõ·Ô"¶Õt-3ÌÔ[ÂÖíkž{ÈÚ…·ØDŒóoLâ$¬œ£nè¯ÄØ +n¥9.]÷o{Ûn}¯ö¾—æÐΞGˆ©%Ê.ý}ëm}ù ü­©òž›f·ñ]Oo¡ÚÝC§Æ&¹xôñ"[¡u@î@©wUÉã,$ŠÝð§€u¿éw÷º'Ö¬ô”ó/ç°Ñæ+%Ã02²!0¬rØáO¥{µÿÃ+OþÍÞ5¹Ñ¼óÂ:lÑøÉå¹gÕndÔ,žkõ¦Ôyr #1Æ›×ÈË1ÜsÊè~ ñoĆ çø{o©\Gáv¸mN[*º&¤oO¶\°l@­n-±;”R°»÷MµÿmQ­NU)¥§ÉÍ&¬½ÎkÊÏK¿vͦ›WW÷\K,';ɸ¹Y-^©Z7ZïvÒjÉÛ¹áÏui#s¥é\ÿÓ¢qù +FšÌóý›¦®?éÕô¯°|ð»Á:Χuâ‹[ÉàÍRÓY×dñišú;k{˜u ß²[³-º,ÞU¼^Q_1–pP£`ÕÏŒ? m¼Qã¿\]x.çT×#ñˆ®´Ÿ A!ÖÝF™²EˆL%%¡š[“ä24¡ËUQÉO‹ðnqƒ£%~kÝÇGø´×~n^Ug+'sª|;Y)5Q;4–U%{íé·5Ûi]­~/7–nÉ/M8 çìËëôÅH׌Ù:f˜Oµ¢é_S]|ø{áßxGGoX]Oãÿc_,ú¥ë6ºÓMy­¡òæ\Ë÷S 3y„lÚáØdrÿþi–?³¯…õ –ºÆ¡>Ÿmä;ÜkRÏ ›ÖÛd³[]©¶!Ðñ9bú—à*JšTå{Y¾^­«üODâïø^ç,òLD9í$ùSo~–þï[éøÙž·V‹ÁÓ4³¸Ϫ~œR™ìñìÍ0ç¿ÙS"¬Ÿë dnŽ•©‹al׆SjþXfò]ØÆÁ7îËtòç¦U,5&ïbUF´E—ºµfÏö^•ÿ€¨?¥5§³1ÓtÑŽßeOð¨)®§<ÓT)övIqse(ñ+Óp1“öp3íYº¬6ÚÈ£M±˜bÁ^C×?[x¡ ㊣sµÇFòsÓùV°£Mj‘¥6Û?f?àÚõ÷ˆÿà§Ô/.ïç…µK4’âf•Ò5K¸aŒ$íŽ(ÑtUE^ ÿ×ÿï¿ìRñþ¼1^ãÿg]¿ðN?K½kÿOWÕá¿ð]ùøþÅ/ÿéÛÃüSd¸Æ¢_óþú\ßsÿÓôê?’? +¿à±_ò<üÿ²wÿ»¹EðX¯ù~ Ù;ÿ݇\¢²Î?ßëÿŽ_úS2ÉÿÜ(‚?úJ?]|?ã|9ÿd:ËÿQHëàšûßÁ?ò`ÿ²cÿ¨¤uðE~·À?ßø)íçå|CüI×ÊŸûhQEú!óEPEPEPEPEPEPôÑEåÿkÏü!ý¨>ü#×gÔ-¼WñŽÓZ¸ðË%©’Öåô¨­ç¹‚GRLr'iP²ì"ÞP]\Æ’ŸÕ‡¨Q\ÀÿzWÇïÞëº5¾¡miaâ oÃr%ê"Hn4­VïK¸p˜ym=œ¬‡9(ÈYU‰Q¡àߊZÄø³IÒ/¾×¨xUDÖâòdìWci~±e”Í­õ¬›²þ÷nw+*€tQ^?ñ»öÖð¯ÀÏêúæŸâ cWÑt­/Q¸ƒM‚™õ}Sû'E°VšXÔÜjÉqM‘?f‘F‰äö +(¢€ +(¢€ +(¢€ +(¢€ +(®?Çô¯‡< áVßPŠ_ˆwwzf‘|ˆj×ðZIz,äÃy«$––׳#ùfXʯ"Hð$À…Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@|wÿ´¿þË~ÖZ ·°Ñ|[oq}<6Ï2YÄöWÐ,’ljf‰7 Ò ÎXö%ëä9¯önaKËÍÈïkÚþW³·­Ÿ¡Ã™`–/ <3væV¾ö?œ“ñ#B''V²$ÿÓQIÿ Bãþ&¶_÷ôWôoE~éÿþ_ô¿ðgÿs?7ÿˆ]Oþ‚_þÿÛÎGü,} ?ò²ÿ¿¢øXúñ5²ÿ¿¢¿£z)Ä—ý/üÿÜÃþ!u?ú øÿl9ð±ôú XÿßÁGü,} ?ò±ÇýuýÑIøý'ÿ0+ÿ÷0ÿˆ]Oþ‚_þÿÛÎGü,}þ‚Ö?÷ðSOÄÍjÚßUýÑKþ#ä¿èÿ*÷1ÿÄ/§ÿAÿÿíçüMÐK5K>}_Òž¿ô"9ÕlGýµýÑGüGÙÐþUÿîaÿ¾Ÿý?üÿ¶?œ†ø“  ÉÕl¿ 3M?t ÈVÓþú¯èæŠ?â>Ëþ€ò§ÿsø…ôÿè!ÿà?ý±üâ§Ä½ÿæ)bq̘âŸÿ Aÿ µýüýÑGüGÙÐþTÿîbÿˆ_Oþ‚þÿÛÎÆ»ñâÃÄ:~•g{®ÙÍo¡Ú›+%WɈË$År ýä²¶OÍŒà3ÄÝ pT³9î_¯èꊘxõÈ­Kþ¾wÕÿ˾¯R¥áŒ%ñb[éðöÑ}®ˆþq‡Ä:¥ˆÿ¶ š?áfèô´ÿ¾«ú9¢©øû/úÿÊŸýÌ_ñ éÿÐCÿÀûcùÅtóªÙøÿZ”üMÐ1Æ«iÿ}WôsEñeÿ@?ùSÿ¹‡üBúôÿðþØþqcø•¢0RuK_Þ +ü,}þ‚Ö?÷ðWôoEÇÙÐþTÿîbÿˆ_Oþ‚þÿÛÎ1ø™ í[Oûê“þn„[T³>æLWôuEñeÿ@?ùSÿ¹þ!}?úøÿl8ÍñDeÿ­€?õÔqT¯~!h¡$+©Û;í |îü?Úþ‘¨ª^?IÌþUÿîc†Ó¿ÖþÿÛ3ÿÁt‹Ýþ Ïðñ/ìîìe¹:ìqÜBлÁ>©w42…`É"’9ã ®¤pEx7ü[þC¾ÿ±KÄ?úvðÅ~ˆ×çwü[wÀßö)x‡ÿNÞ¯É2œsÆñ$qŽ<¾Ò£•··3n×ò¹õ¹öØdU('~XZþ‰#ð§þ ÿ#ÏÁ¯û'û°ë”QÿŠÿ‘çà×ý“¿ýØuÊ+«8ÿ¯þ9éLáÉÿÜ(‚?úJ?]ü„þÀöøcÿ¨¤uð=}õà—þ ÿáÏû!ö_úŠG_×ë|ðOü¿öóòÞ"_¼—ý|©ÿ¶…Q_¢4QEQEQEQEQEQEMó‡íYû!ÜþÓ?µwÃëûø5 _ +h^ +ñ»ëvPGu¢kÛžÕ4‰âŽ@âI#ŸG’áDËnM I‘ÒO.O£ë矎(ø“â¯ÚÿJøà¯Xø.ÆoMâæ¸Ð"Õ|É"½ŽßhVxÊäLwû±òòMŸÕ‡Ìß¿c_‰–þMñëà‡þ8ÿfê¿o|[ðÿBm'QÒŸZÖ¼Uý§§kv–úÕÔ­o Ô#å›í°¦¬±ù¼ºòøýkþ YñVÇàµþ‘âý7PñÞ½ªøƒÁúï5 Ë¡jÚŸÄ{-?Àñh/§°ñfÖúKmrØêe5H„"•¸‚C|(¾Õÿ…ñóþ‹î‡ÿ†îþK£þ_ÇÏú/ºþ¸?ù.€>zøSû ø¿á÷ŒgÉá߈5”ðž±j~!ñf›=σ,$Õ.¯>ÎMŒvƒH¸ŠÕí-ãƒBŠæÂî>‘x†ÊÞÇQCöØøsûBþן<7‡´ÿÚxËÃÿ¯²uUƒì¾ Òô_jWšðT¸";˜ílî­Úâ1¸{l…K\D¯î¿ð¢þ>Ñ}ÐÿðÝÁÿÉt‹øùÿE÷CÿÃwÿ%ÐÇ_µ7üßâgį|VÒ<;ð¯oÄÝoþ-Ƨñ'íÚL?ð±t]_Kñ '†þ×öŸí~Ìú–‚žEü0ÙAý‰û¹JÛZ>ý½®t¯°~Îö^²ðyñ—‚¼kjþøn/SG_[ɧ]xzâ;e†)e‚ÏM´ÖþßÑ}ÐÿðÝÁÿÉtò×ÀÏø$¶»û7ø:ù´ý#þø7âÃkO ø±®£¶¹>Ò´¿éšååœMpãNûU®Ÿ«Ãul³]ÁC!¸mÔúü—ö}ø±âÿøhˆþxþÉþ;|ƒáîšë®Yé–Ú%åŸü$o+^5É?µZˆ#™^x].Ê.kÙáEü|ÿ¢û¡ÿểÿ’èÿ…ñóþ‹î‡ÿ†îþK š¾>~Â>!øƒãô^ð>¡áÁãK» ËÝvÛÄŒl“[²º»ÓmÍÁhµHçÒmg·ŽÛÄ6ÑæÍwqa÷ZEã}“Ÿðì¼ß|#ðSÀ÷ßüa®é·ÿ¼Iâ”øm¯7…çÔ°WÀzΛu Ót¨­´+ 9¯îàˆÆ’=³M¬A%ÅÂO$1ýkÿ +/ãçýÝÿ Üü—Gü(¿Ÿô_t?ü7pò]{Õà¿ð¢þ>Ñ}ÐÿðÝÁÿÉt‹øùÿE÷CÿÃwÿ%нQ^ ÿ +/ãçýÝÿ Üü—Gü(¿Ÿô_t?ü7pò]{Õà¿ð¢þ>Ñ}ÐÿðÝÁÿÉt‹øùÿE÷CÿÃwÿ%нQ^ ÿ +/ãçýÝÿ Üü—Gü(¿Ÿô_t?ü7pò]{Õà¿ð¢þ>Ñ}ÐÿðÝÁÿÉt‹øùÿE÷CÿÃwÿ%нQ^ ÿ +/ãçýÝÿ Üü—Gü(¿Ÿô_t?ü7pò]{Õà¿ð¢þ>Ñ}ÐÿðÝÁÿÉt‹øùÿE÷CÿÃwÿ%нQ^ ÿ +/ãçýÝÿ Üü—Gü(¿Ÿô_t?ü7pò]{Õà¿ð¢þ>Ñ}ÐÿðÝÁÿÉt‹øùÿE÷CÿÃwÿ%нQ^ ÿ +/ãçýÝÿ Üü—Gü(¿Ÿô_t?ü7pò]{Õà¿ð¢þ>Ñ}ÐÿðÝÁÿÉt‹øùÿE÷CÿÃwÿ%нQ^ ÿ +/ãçýÝÿ Üü—Gü(¿Ÿô_t?ü7pò]{Õà¿ð¢þ>Ñ}ÐÿðÝÁÿÉt‹øùÿE÷CÿÃwÿ%нQ^ ÿ +/ãçýÝÿ Üü—Gü(¿Ÿô_t?ü7pò]{Õà¿ð¢þ>Ñ}ÐÿðÝÁÿÉt‹øùÿE÷CÿÃwÿ%нQ^ ÿ +/ãçýÝÿ Üü—Gü(¿Ÿô_t?ü7pò]{Õà¿ð¢þ>Ñ}ÐÿðÝÁÿÉt‹øùÿE÷CÿÃwÿ%нQ^ ÿ +/ãçýÝÿ Üü—Gü(¿Ÿô_t?ü7pò]{Õà¿ð¢þ>Ñ}ÐÿðÝÁÿÉt‹øùÿE÷CÿÃwÿ%нQ^ ÿ +/ãçýÝÿ Üü—Gü(¿Ÿô_t?ü7pò]{Õà¿ð¢þ>Ñ}ÐÿðÝÁÿÉt‹øùÿE÷CÿÃwÿ%нQ^ ÿ +/ãçýÝÿ Üü—Gü(¿Ÿô_t?ü7pò]{Õà¿ð¢þ>Ñ}ÐÿðÝÁÿÉt‹øùÿE÷CÿÃwÿ%нQ^ ÿ +/ãçýÝÿ Üü—Gü(¿Ÿô_t?ü7pò]{Õà¿ð¢þ>Ñ}ÐÿðÝÁÿÉt‹øùÿE÷CÿÃwÿ%нWçwü[þC¾ÿ±KÄ?úvðÅ~xY¦ éÍq<—S›XŒ“H^fØ2Ä( + < xq_Ÿ¿ð]oùøþÅ/ÿéÛÃô+ÿ#|?ø‘àqOüŠqágáOü+þGŸƒ_öNÿ÷a×(£þ ÿ#ÏÁ¯û'û°ë”W³œ¿×ÿ¿ô¦y9?û…ðGÿIGë·‚›þ0 ßöCì¿õ޾¯½|ÿ&áÏû!Ö_úŠG_Wë|ü9ÿ‚—þÞ~WÄ?Ä—ý|©ÿ¶…Q_¢8QEQEQEQEQEQEMà·ÿò” 'þÉmïþ­+Þ«Áoÿå(Oý’Ûßý;ZWñ9ýX{ÕQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@|1ÿ"Öÿ^Ñÿè¿??àºçï¿ìRñþ¼1_ ~ÿ‘kNÿ¯hÿô_ŸŸð]Q{Àßö)x‡ÿNÞ¯ á_ùáÿÄŠäS_ü,ü)ÿ‚ÅÈóðkþÉßþì:å¿ðX¾ÿàºçn½àSÿR—ˆôíáŠýðÇü‹Zwý{Gÿ  +üûÿ‚ìÈwÀ¿ö)x‡ÿNÞ¯ áOùáÿÄŠäS_ü,ü+ÿ‚Åœøëà×ý“¿ýØuÊ)?à±?ò<üÿ²võ!×(¯g8ÿ¯þ9éLòr÷ +àþ’Öï6?`ŸÙ±ÿÔN:øB¾ìðiÿŒ ðçýû/ýD㯄ëõÞø%ÿ^éíçå9ó½Iÿ×ÚŸûhQEúóÁEPEPEPEPEPEPôÑ^ ÿ)@Òì–ÞÿéÚÒ½ê¼ÿþR¤ÿÙ-½ÿÓµ¥ŸÕ‡½QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEGÃò-ißõíþ€+óïþ ±ÿ!ßÿØ¥âý;xb¿A<1ÿ"Öÿ^Ñÿè¿>ÿà»òð/ýŠ^!ÿÓ·†+èxSþFøñ#çø«þE8ð³ð«þ ÿ#ÏÁ¯û'gÿRrŠ?à±_ò<üÿ²wÿ»¹E{9ÇûýñËÿJg•“ÿ¸Pÿô”~´ø0ÿÆøwþÈ}—þ¢q×µ÷?ƒ_°—‡ì‡Ùê'|1_®ððåÿ^éíçäùïñ'ÿ_jÿí¡EWè'€QEQEQEQEQEQEMà·ÿò” 'þÉmïþ­+Þ«Íu‚úŒŸµ…¿ÄhnlžÖÓÂRxmlœ²É#Ëx— )`¤¢$P0Ko»´nþ'?«J¢¨ý£RÿŸKü þ7GÚ5/ùô±ÿÀ·ÿãtzŠ£öKþ},ð-ÿøÝhÔ¿çÒÇÿßÿÐê*Ú5/ùô±ÿÀ·ÿãt}£RÿŸKü þ7@¨ª?hÔ¿çÒÇÿßÿÑöKþ},ð-ÿøÝ^¢¨ý£RÿŸKü þ7GÚ5/ùô±ÿÀ·ÿãtzŠ£öKþ},ð-ÿøÝhÔ¿çÒÇÿßÿÐê*Ú5/ùô±ÿÀ·ÿãt}£RÿŸKü þ7@¨ª?hÔ¿çÒÇÿßÿÑöKþ},ð-ÿøÝ^¢¨ý£RÿŸKü þ7GÚ5/ùô±ÿÀ·ÿãtzŠ£öKþ},ð-ÿøÝhÔ¿çÒÇÿßÿÐê*Ú5/ùô±ÿÀ·ÿãt}£RÿŸKü þ7@¨ª?hÔ¿çÒÇÿßÿÑöKþ},ð-ÿøÝ^¢¨ý£RÿŸKü þ7GÚ5/ùô±ÿÀ·ÿãtzŠ£öKþ},ð-ÿøÝhÔ¿çÒÇÿßÿÐê*Ú5/ùô±ÿÀ·ÿãt}£RÿŸKü þ7@¨ª?hÔ¿çÒÇÿßÿÑöKþ},ð-ÿøÝ^¢¨ý£RÿŸKü þ7GÚ5/ùô±ÿÀ·ÿãtzŠ£öKþ},ð-ÿøÝhÔ¿çÒÇÿßÿÐê*Ú5/ùô±ÿÀ·ÿãt}£RÿŸKü þ7@¨ª?hÔ¿çÒÇÿßÿÑöKþ},ð-ÿøÝ^¢¨ý£RÿŸKü þ7GÚ5/ùô±ÿÀ·ÿãtzŠ£öKþ},ð-ÿøÝhÔ¿çÒÇÿßÿÐê*Ú5/ùô±ÿÀ·ÿãt}£RÿŸKü þ7@¨ª?hÔ¿çÒÇÿßÿÑöKþ},ð-ÿøÝ^¢¨ý£RÿŸKü þ7GÚ5/ùô±ÿÀ·ÿãtzŠ£öKþ},ð-ÿøÝhÔ¿çÒÇÿßÿÐê*Ú5/ùô±ÿÀ·ÿãt}£RÿŸKü þ7@¨ª?hÔ¿çÒÇÿßÿÑöKþ},ð-ÿøÝ^¢¨ý£RÿŸKü þ7GÚ5/ùô±ÿÀ·ÿãtzŠ£öKþ},ð-ÿøÝhÔ¿çÒÇÿßÿÐê*Ú5/ùô±ÿÀ·ÿãt}£RÿŸKü þ7@¨ª?hÔ¿çÒÇÿßÿÑöKþ},ð-ÿøÝÿ‘kNÿ¯hÿô_Ÿð]ùøþÅ/ÿéÛÃú£Ù¶Ÿ¤ZÛ¹RðB‘±^„…â¿=à»'çìRñþ¼1_CŸò7Ãÿ‰ÿȧþ~ÿÁb¿äyø5ÿdìÿêC®QGü çÇ¿ìŸýHuÊ+ÙÎ?ßëÿŽ_úS<œŸý‡ø#ÿ¤£õÁÍÿ+áßû"?ú‰Ç_ ×Ü> 9ý†<:=>Øÿê%|=_¯p'ðåÿ^éíçäÙçñ'ÿ_jÿí¡EWè‚QEQEQEQEQEQEMQEŸÕEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_ð]ÃoÀ¿ö)ø‡ÿNÞ¯ÑJüëÿ‚îÿÈkÀ¿ö)ø‡ÿNÞ¯¡áOùáÿÄŸâ¯ùb?ÂÏ¿ø,7>7ø5ÿdïÿvrŠOø,/üŽßìŸýHuÊ+ÙÎ?ßëÿŽ_úS<¬Ÿý‡ø#ÿ¤£õ{Á-ŸØwÃã?óD,õ޾"¯¶üáb]wÿ…!cÿ¨”Uñ%~»À÷rÿ¯t¿öóò|ñZ¤ÿëíOý´(¢ŠýðŠ( Š( Š( Š( Š( Š( 颊(¯âsú°(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Šü©ý¶þ,|\øÿMÕ~øOâo‰¼#¦j7zu’Zj3Û[Ù™4ûy± V9vryä·¥wÚßü×ö¸ø{§I¨øköÔ¼GÞ,¯uËßß`p©çù‘–>µ}MyïÅ¿ùXBÓþÃZWþš-«õj¿UÏsª¹^O N³£ I8Eݵ­ô¾¾§ç™FUO0¯‹ž"s¼jÍ&§%e~šÛð?=`Ÿø*ŸŒµŽËðƒã•Œv>'šëû6ÓR6Ëi0¼ÎÞâ5ÂfC€’£6áéÿðP¿ø'·ÿkÏ^ñ'†¼xžÓü4‚)íä’T’ÉÄ­'Úí¼°A™U!Š€#_›¨¯’à¹Qø#öìðf¹¡¢Å¯\è–WÎ#ᥞ+¹’}ÄF«ŸHÇ¥kÿÁfå%ß ?ì ¤ÿéÖò½*L*ãp™–Yj½9É®U(§“´[VNúzm¹Á[1•<.'˜^²¥R >gÔÕÚ½Ú¶§êÕùÿ\IiqðfX£–&Ö]N +tò«ÿü¯â—í·ðÚˆ^?ø­*x¿_µ¦Ÿ¡5£É¦ébE߸>hò†ÖìC´“þ°ä·ÆáxW +ð|Ç‹T¡W™k&œdÖ–z§k¶ím·>£ÄX…Œ­ÂáISåI¦¯­Ö[%­üÒšüÐý‹>i_ ®üA¦þÕzMÿÅk;7¹Šøø¾À[ÝÜ*—/ï<õ à€æRFàÛOC×~Î~9Öÿà©_ðM?ˆ~ñ4Í­øóÀÍÆ™|à5ÅÛ„ym žò?—<ñʶN[q;ÖàúQ¤±4± ÓŒ£·NQqRvRI¿z7óOÈÆ—Tu +”R›‹”Rš’—*»‹ihþMyŸ¥tWçßüã¯ü$|UðþöoôŸ +_ FÍ]¹· ïU‰23yÅyGì3¡Û›þ +Ó㉷Jnü?ákÙµkyæFÚ~ͧ¦{Š$³úTUàÙQÄcib*òÇ órßšÿµÕ¹½]žš•OŠ#VŽ¥w•wk_á·Äïmy}ÏÔ?ˆ^8°øeà-oÄz¤žV› ØÏ¨]?÷bŠ6vǾ×áô?¶Çm7SÓ¾,MãŸKáÛ¯̃OþÞº:yž ÓÚKù~IŽeP˜#h#ŸÑø-ÏÇ#ð§ö0¹Ñ-¦òõ_E¥.Ó†[uýôíô!3ÿ]¿ùïÇÿ³ÿ…áÿ‚%èúLZÞ€þ,Ò„^6kxï¢óÞiX™#eÝ»rZM´®3º 1_IÀô°ø<qXªjXª©««Ú);ËÉs;?CÃâÊ•±8©aðóqö4Üݯ+«/=שúkàïYxïÂ:V¹¦ÈfÓµ›8o­d#â•¡üU…h×ÉðEŸŽ¿ð¸?b3J¹›ÍÔü u&‹0f˘F$·lvQˆÇýq5ó_í¿ñ¯âíáûzÿƒðF»sáÿ éwO§]¦x£¹’$2]Oq³Ö=¬©;IAп+‡á*µsJø MByœ¤öQ]mÖêÍ#è«q:y}dbç*¶QŠë'ÓÊÌû›þ +âOÁ_±_ÄmWFÔo´RÇIy-¯,® ‹wÞ¿2:Ê}Á¯ÿ‚|Pñ7ÅŸÙ?Ä:мE®ø›PƒÅ·6ÑÝj×òÞÍBÎÉ„aäf`¡ŽÐq–'¹¯ž¿j¯ø%ˆÿbïÙÅ"ð7ÄÍgRÓVÌCâMæ¾£jì¨Îª—r1 @É +áºÏø$ׯø?fïø%¯Å\@.‡‡|I{q³Ìl´ôŠ2G@Ò2{M}Ê0«‡*CQVr­Ÿ+Œ®ì¹lõ_}µ<5™âw c é(Ó“k›™Y]Þëºú¤uù¡ÿÖøñ㟄_< má?ø¯Ã÷šLòO“«ÜY$î&3C8ɯ8ý“¿c/ÿÁYî5߈ÿ> jÖš4ïij¨¦gy‡d‚6a ‘@ÚIa€A5äÿðSŸÙãÆ?²ïÄøGÄ>0½ñ¯‡í´÷ŸÃ—·™óííÚL=»d±xŠárTz|+Ã,w =LLjUŠ|ÐåvøzIé&¯ª²ü!ÏñX¬¦U¡BP§&¹g̯¿TµIú¿Äýίοø.ïü†¼ ÿbŸˆôíáŠý¯Î¯ø.ñƳà_ûüCÿ§o Wçœ)ÿ#Œ?ø‘õüUÿ"ŒGøYøWÿ…ÿ‘ÛàÏý“³ÿ©¹E'ü Ÿüÿ²võ!×(¯g8ÿ¯þ9éLòr÷ +àþ’Ôß]ûøy3ÿ4FÇÿQ«ãJúÿÂOÙã×à•‡þ¢1×Èú÷_õî—þÞ~M»Ô©ÿ_jÿí¡EWè„QEQEQEQEQEQEMQEŸÕEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPäwí+ã­#á—ü†M{^¿ƒKÑô½WJšêêlùp'öM°Üqž2E}±ñ3þ +õðáÆ‡5Ô~4Ä7j›¢±Ò-e¸šsýÐÅDjßu®·ã7ü§àÏíã{ÿx»Á6ú¶»©˜ÍÕàÔ.íä›ËbLùR áFíÏ5Ÿàïø%×ÀÝG5—Ã-wˆåF¡$úŠªÜI ?ˆ5ú3;ÈqÔ0˼ôiÆ"‹å]Ûo-‹ÂåYÆ­ªÊŸ-YÊw|Í«¾É%·žçÁ?³—€|aÿ\ý¿Sâ–¿¤O¦øA¼†åË‚Öé ³‚Â7 yŽÍÌ„c¤o—*§cþ 3ÿ).øYÿ`]'ÿN·•ú££èÖ~Òà±Óí-¬l­PG ½¼KP¨èªªØ +óŒß±ÂÿÚâf•ãøcû_Äz$0ÛÙ]ÿhÝÛù1Å+ÍÙª‰$s–RNpr®Ž(¬Îš´Ü(Ó¦áFͤյm«ù³,G Ôx P§QJ¬æ§)KK´ü“·‘ñü]ÿ4wþã_û¯ÐòF¼%ÿ`[?ý•Ì~ÑŸ±×ÃÚÏûþ‡?·ÿ°<ÿ°§ÝZyw—樑7gÊïgxÆN}DÑ­¼;£Ziöqù6v¥¼î-²4Pª2I'IÍ|öcœÐÄdøL¾ óÑs»v³æ•Õµ¿­Ò=¼WVŽi‰ÆÉ®ZŠÞþê³¾–ôÕŸ•ÿðFoùIwÅ?ûêßúu³¯9ø_û3h?µ§ü»âW„|K5ìZ<ž%ñÜÂÑÄrÈcº›h AÇÌAè~î;×êOÁŸØ‡áìùñ3Uñ‡„<1ý‘â=n­ïnÿ´nî<èå•&l–VEÌ‘¡Ê¨#Š<ûü/øeñ¿Sø¡øcì>3Ö&º¸¼Ô´nåó¤¹ró)å1 ÌIÀ@lWÖUã¼2Åbq8u8Ê¥(Â.ÊêK«÷´]š»ò>nŸWxz+¸µ +ŽRWvq}›úÙyŸ¿±WÇMsþ [ûak¿~!\”ð^±|ªnß+»¾¾ ™é‰µdç€yŒŠë¿à½¿/¢ø‘à‰­¦Ï«xf Eѵ5ÙR"“¼È®Ë÷«,ŠwN¹Û_s~Ðÿ±'ÂïÚ³TÓ¯¼}áH5ÛÝ&&‚Öqysi"FÇqBÐH…—<€Ù–Æ7öº/¿è m|šlW~´³]=,5{øÚÝFљ˴Šç'€qKŒðÑÌ(g©µZܵVŠ2ÒÜÑiÝ?—nÚõ.®ðu²ÉÍ{+Þ›ÕÊ:ÞÍ5f¾}ûéùÉðûá×ìãß +ÚêM¨K¢M:-ާ«j÷6®@%n*ÄtÊ3)ìM}mÿõøOðCÁž ×|Að<Éq£k÷Ii}tÓÝH&–Û~Õãæ|æäìò1Uõ?ø$—ìñ«k }/Ãk$ŸyXu;è!Îsþ©'¶Ü{W¥XøsÀ?±oÁ bëHÑ-<3á= µ[Ø´ÛBÌB ó%` ´µ98Q“ÇužPÆÐú¾¶"nm{µ$œwÚɶÝíc«*Ê+ajû|M*QOÞ‚j[oªI+^çå¯í6­ÿÔý¼þ ÝøvƒFøáëÿ±ÆÕ‰/£líì<›ÄÜeEõÅ}—ÿNýžÁŸØþßÄ–þN¯ñãûYË.Z()l§ºWt£¯þòwŽüY«ÿÁl?m¿éÚ.‹{£ü;𚸺™G™4²ÊË•Y¦Ú¨‘‚Ø «õ§DÑm<9£ZiÖñZXØB–ÖðF»RÑBª(ì¥{œg™Ô¡•áòêêØ‰Æ.®·v…Ô¼Ýîý'…ð«˜VÇQw£%Oµånf¼–ËÔü®ÿ‚´ëW_µ‡ü[ÀŸtÉä6úIµÓ%Ùó}žâõÒIåôÂÁäéå·Ò½Í¿àß¿ƒ{NlÈÉ#žSÊ»aAù@Àǭ׋ŒãJôp¸lQ9S…8Z[.i·y=Òûz½W ÂԪׯ‰ÌáÊrºÝÚ+DºkßÑ“¿ðFÞþη¾k’ŸX@kûŒzÚ¾²¼yâÙàœðXmgž$±¼“Ã>#Ô/534Qîi¬õ îÒGœn1LÄ9ýÓÔWèΡûü(Ô¾>/Äù<*WÇ+yøÔâÔï"ýò(@Æ$”Drª0Üî'=_ÆßÙãÁ?´w†£Ò7ÿ‚†ÁN¾|Sý•)²hR ; ˆÖÎÝ{4ò™p©np2A ($ywìðgPý ?à?<)¤Ä×¥÷‰..- O½q-½¾™r‘¯ûNÐ…ì+î_‡ðO?ƒ? |=­éžð™coâ+ ô½BFžyîf¶ rÄ'’F••ˆ;A]oìýû5ø+öZðmχü¢ÿai—¯¨MoöÉî·ÎÉlû¦wa•‰ÇËÓ$çýfË0y{Áåpšj¤*'>Ww=lÕ¶VI>·gJÈqøœbÅfƒNƒQº²}¯¾îíÛÐüóÿ‚BÿÁF¼û=|ÔþüDÔ¤ðÌö”·¶rÚK$3$wÂÞZ³$ŠêÇæØÎF‹ÿÁ_k/~ÖßôKÁé{wá}Ê]2 Z[g‚-FçzË0Œ8 µH~ð/œ`©?¨¿à~;xÊ_xŸÀ:eö³pþl÷P\\Y5ËÿzAˆ$cܸ$÷§|Eÿ‚wüø«áhÏ4æÑü+çÿeÚYÜÜXGlgòüÓþ"ogò£$¾ã•ëÉÏ©„â슆j³…Fª©+ó+ÅÅ6µqÙ»¾í+6í²<üO çrïìÇVŸ$mÊí$ÚOE-Ò²ìžÉwg´×çWüƒþCÿ±OÄ?úvðÅ~Š×çWüƒþCÿ±OÄ?úvðÅ|_ ÿÈãþ$}'È£þ~Á`¿ätø3ÿdìÿêC®QGü þGOƒ?öNÏþ¤:åìç?ò0¯þ9éLòr÷ +àþ’Ó߃w¶:ý™< „QÚjß ,<MÔrÆà †‰ÇjÍ_Ù+ÀÒÖoü/æÿær¾1ñíâߨs]’ÏÃphÚ®ä¸oë°É5„ȼ°´2Eq %A)Ë1,ÈÌIª+ÿÔñÒôøUðlÛ-sÿ–uè`8¦©EBSƒIEò´“åÛó>Md8ºÎUèªrŒÛšçNéÊ×Z//™÷$?±¿‚g-¤‡þêßüÎSÏì_àÑÿ.ráÀ›ÿ™Êø~/ø/¡/ÂσCþØëŸü³©?áýÿ±ÿ$·àÏýø×?ùg]ßë“ÿŸÕ¾ô/õoÿ>è}Òÿ#í¿øc/gc“ÿßüÍÐc/ùsü8ó7_ø/oÄä–üÿ¿çÿ,éþ Ýñù%¿ïƹÿË:ë“ÿŸÕ¾ôêæ?þ}Ðû¥þGÛðÆž ÿŸ'ÿÃ7ÿ3tÃø3þ|ßÿßüÍ×Ä_ðÿˆ_ôK> ÿà>¹ÿË:?áþ¿è–|ÿÀ}sÿ–tÿ×ú}[ïB\9ÿŸt>é‘öïü1§ƒ?çÊOü8ó7M?±·ƒÿ'ÿÃ7ÿ3uñÿ‚÷|A?óK> ÿà>¹ÿË:?áýßè–|ÿ¿çÿ,é®1_óú·ßÿW1ÿóî‡Ý/ò>Ýÿ†5ðf?ãÍ¿ðàÍÿÌÝ'ü1¿ƒ?çÉÿðàÍÿÌÝ|GÿîøƒÿD³àÏýø×?ùgHà½üÒσ?÷ã\ÿåRãÿ?«}ñú¹ÿŸt>é‘öáýŽ|ÿ>oÿ‡oþfé§ö<ðXÿ—'ÿÃ7ÿ3uñ/ü?¯âÿšYðgþükŸü³¤ÿ‡ôøüÿÍ+ø3ÿ~5ÏþYÓÿ\#ÿ?«}ñÿ1«˜ÿù÷Cî—ùmØÿÁCþ\ßÿ ßüÍÓOì‡à¡ÿ.Oÿ‡oþfëâFÿ‚õxüŸù%ïÆ¹ÿË:iÿ‚òøøÿÍ+ø3ÿ~5ÏþZSÿ\!ÿ?«}ñÿ0ÿW3ä¡÷KüÜÿ‚¨xµ:ø7á¯þ§ÿ)©‡þ +­âÁÿ2oÃoü+õOþSWáóÁwüxÃáWÁŸûó®ÿòÒ›ÿÙñÑÿšSðgþüë¿ü´¯˜Txù*}ëüÏ}â8Ÿþ~RûŸù¸ÿ^ñRÌðÛÿ +ýWÿ”ÕÁZõþbúÇÏÊ_sÿ#÷¿à®&SøC¾ÿá_ªÿòššஞ%ó'|7ÿ»Uÿå5~·üÆlyøMðkþýë¿ü´¦Ÿø.ŒüÒoƒ_÷ï^ÿå¥W°áïä©÷¯ó'ëQÿ?)}Òÿ#÷ÿÁ^.”’ßþ œÿÓ={ÿ–”ßø}—‹?è‘|ÿ¾5ÿþZV‹Ã]iÕû×ùñWÿ?(ýÒÿäOÜOø|ˆèNøoÿ…~­ÿÊZoü>KÄÇü!¿ ÿð¯Õ¿ùK_‡‡þ aâ³ÿ4‹à×ýñ¯ÿòÖ›ÿ¬ñ^ä‘|ÿ¾uÿþZSú¿ Ϻ¿zÿ0úÏÿÏÊ?t¿ù÷þ#âÿÈ›ðÛÿ +ý[ÿ”´ø,ˆ@ÿ‘7á·þú·ÿ)kðëþYâ¿ú$_¿ïÿ–”Óÿ¯ñX?òH¾ ßÿÿ-hú¿ Ϻ¿zÿ0úÏÿÏÊ?t¿ù÷ÿÁe<@?æMømÿ…~­ÿÊZdŸðYÍz.¾ øoÿ…~­ÿÊZü;?ðZïŸù¤_ïÿ–´×ÿ‚Ôx¢Aσ'þ¯ÿòÖ«ð×üû«÷¯ó¬ñWüü£÷Kÿ‘?pþ Q­©ÿ‘;áÇþÚ·ÿ)i­ÿ­Ö“¯ƒ¾á]«ò–¿þ 9âVëðà×å¯ÿòÖšßðY·üÑÿƒ_—ˆ?ùkGÕøkþ}Õû×ùb8«þ~Qû¥ÿÈŸ¸gþ c¬ù“¾á]«ò–šà¶ÚÀÿ™;áÇþÚ·ÿ)kððÿÁdüDzüø5ùxƒÿ–µÁd¼BIÿ‹=ðkòñÿ-i}_†ÿçÝ_½˜Ö#Šçå/º_ä~ãÃîuúþá]«ò–‘¿à·š²ÿÌŸðãÿ +í[ÿ”µøqÿñýïƒ_ùpòÖ‘¿à±šûuø;ðkÿ.þZÑõ~ÿŸu~õþcúÇÿÏÊ_t¿ù÷þ«Пðãÿ +í[ÿ”µ$ð[Mfá€_|8$ÿÔÝ«ò–¿ Ïü'^?óG~ åÁÿËZ|_ðYÀÙ_ƒßÁö0òÖ…C†¿çÝ_½˜Ö#Š?çå/º_ä~êGÿ™ñ ¿wÁ¿ ð°Õ¿ùKJಾ"ó&|5ÿÂÃVÿå-~EÿªñL?wáÁ¯ûç_ÿå­?þaâ¿ú$?ïÿ–´{ÿŸu~õþbúÇÏÊ_t¿ù÷ ÿÁeüD?æLøkÿ…†­ÿÊZiÿ‚Ìø‹þ„φ¿øXjßü¤¯Ãfÿ‚Ùx¯?òH~ ÿßÿÿ-i?áö+ÿ¢Cðgþù×ÿùkUõ~ÿŸu~õþcXŽ(ÿŸ”¾é‘û“ÿœñÿ™3á¯þ·ÿ))¯ÿ¡ñuðgÃ_ü,uoþRWá¿ü>»ÅGþiÁŸûç_ÿå­!ÿ‚Õx¥ºü ø3ÿ|ëÿüµ£êü5ÿ>êýëüÃëQÿ?)}ÏüÜø}.¿ÿBgÃ_ü,5oþRRø->¾?æLømÿ…†­ÿÊJü7ÿ‡ÓxŸþˆÿÁŸûç_ÿå­5ÿà´¾'Çü‘ÿƒ?—ˆ?ùkG°áŸù÷Wï_æXâùùKîä~ãKÿ°×bø3á·þ¿ÿ)*¤ßð\½Zßïx7áÀÿ¹»Wÿå%~ 7ü‡Ä¯×à÷Á“øxƒÿ–µZø,V½q÷þ|?øPòÖŸ°áŸù÷Wï_æ/¬qGüü¥÷?ò?pücR_ù“¾á]«ÿò’“þµ©ù“¾á]«ÿò’¿þ +÷¬·_ƒ_¿?ÿòÖ›ÿxÖ?è|üüCÿËZWáù÷Wï_æYâùùKî—ù¹?ðý­HÌðãÿ +í_ÿ””‡þ ·©ÿ"wÃü+µþRWá¿ü=ãXÿ¢5ðkóñÿ-h?ðWm`ÿÍø7ÿ}x‡ÿ–Ôþ¯Ãóî¯ßó¬ñGüü¥÷Kü܃ÿÝÔ±ŸøC¾á]«ÿò’Áwõ"äNøqÿ…v¯ÿÊJü7oø+¾°þHÏÁ¯ûëÄ?ü¶¤_ø+¾°Oü‘Ÿƒ_÷׈ùmGÕø_þ}Õûãþaõž(ÿŸ”¾é‘û’?໺‘8ÿ„;áÇþÚ¿ÿ))[þ ¹©¨ÿ‘7áÇþú¿ÿ)+ðÐÁ^uÿ4gà×ýõâþ[RŸø+Ö°æŒüÿ¾¼CÿËjj‡ Ϻ¿|Ì>³Åóò—Ý/ò?rüRó&ü7ÿ¿Wÿå%ðþKþ„߆ÿøWêÿü¤¯ÃcÿxÖüÑŸƒ_÷׈ùmIÿvÕÿèŒüÿ¾¼CÿËjVáoù÷Wïù‡Öx£þ~Rû¥þGîOü?‡Rÿ¡;á¿þú¿ÿ)*—‰?à¸x·Ã·úN§à_†wšv©o%¥Õ¼ž.Ö +OŠQÐÿÄ“¡RAú×âü=×Wÿ¢3ðkþúñÿ-¨?ðW]\ÿÍø5ÿ}x‡ÿ–ÔãC†"î©Õ¿ªÿ䉖#гzKüÚ_…ßðXm#àŸ…£Ñ<%ð¿á‡´¨ÛÙì|O«D®Ø»cCË1e˜’qÖº/ø6£ÿBwÃü+õþQ×á¿ü=ÓVÿ¢1ðkþúñÿ-©?áî:©ÿš1ðkþúñÿ-ªêSáš’s© +ͽÛi¿ý(Têñ4"¡ÑItIÿò'îAÿ‚ôjþdï†ÿøWëü££þÓ¨Ððßÿ +ícÿ”uøjÿðWWòF> ß^"ÿåµ7þãªÿÑø5ÿ}x‹ÿ–ÕŸ°áoù÷Wïÿ$_Öx£þ~Rû¥þGîYÿ‚õjþdï†ÿøWëü£¦·ü¾ý:ø;á¿þúÇÿ(ëðÔÿÁ[õCÿ4_à×ýõâ/þ[Rø+n¨æ‹üÿ¾¼EÿËjÿŸu~øÿ˜Ö#Š?çå/º_ä~åÃü¯¿èNøoÿ…v±ÿÊ:Aÿó¾càï†ÿøWëü£¯Ã_ø{V¤æ‹|ÿ¾üEÿËjü£R?𥾠ß~"ÿåµVáù÷Wïù‡ÖxŸþ~Rû¥þGîzÁyõ' ømÿ…~±ÿÊ:wü?‡T#|6ÿÂÃXÿå~¯üËUNŸ> ß^"ÿåµ<Á^u€1ÿ +gà×ýõâþ[QõnÿŸu~øÿ™_XâùùKîä~æÃ÷õ_úþÿáa¬ò޾{ýºoøl¨4ë½BÃÃ:-Æ…¤^éV¶ºF©}©5Û]Þéw î׫ƺq匿÷ŸËvÿ‚¾ë*?äŒüüüCÿËj­©ÿÁ\ÝüëÝÀQZê¨;í%—WÕ/#G‹[][Ê=Vd=è®>âêçâ^£wâÝÜë:Þ³1º¼¼º`ÒLäl*€ª¨ +ª¡T¢½)ðÔ±s–*S³›r·k»Ûñ<Ê|L°Ž0º‚Q¿{+\ÿÙ +endstream +endobj +861 0 obj +96859 +endobj +862 0 obj +<< +/Type /XObject +/Subtype /Image +/BitsPerComponent 8 +/Width 336 +/Height 400 +/ColorSpace /DeviceRGB /Filter /DCTDecode +/Length 863 0 R +>> +stream +ÿØÿàJFIF``ÿÛC  + + + +    ÿÛC  ÿÀP"ÿÄ + ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ +%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ + ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ +$4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?ú³ö,ý޼1ñ›áG‡¾*|ZÐtïx›Çi®XiÚÚ.¡¤hÚ}Êy–iœ›­Þf¶xä’YQäY%tFTP+Ö%ýœg&’7ø[ð$…Ú9¼¢FRU”#‚ ŽÄ‡ö8ñu½—ìaðR&u ¿|4Oã¤Zðo†¿õÏ‹þ>Km7HÔïôȵ8-/f´p³…¤Û÷°Bâ5b20ôÀ®üß0ú…:*%';ïåoó=ŽázÛÅTÅb(ÑåÚÚóswkù~mŸ@Cû7þÎ7Å|-ýŸÞY¤X£Aá ³»ª y’Hu$×Cì9ðN_ù¢?ðƒÒù¾^ø•ðk\ø=ñ í5='TÓôéµí¬¥»oÛ Y +dÀ¡Ç7¡¯²~0|vÒ>|ñ7Œu òYøoMšý≠’ÎQ X‘G,îÛUTrY€jrœßëQ«*´T}¶Wo~–òùŒxJŽP°ÒÂb]HÖæÕÙZܽS·Ú×µŽx~ÂÈÿ’!ðcÿ='ÿ‘èÿ†ø)ÿD?àÏþzOÿ#×ð'ö¿ñÁ¿€ºÖŸñŽî|Qð~¹m¡ÜA éÛÜxŠãQM§Çitˆ.¿™#¤a­&wtTv\Ÿ„_ðQM^_üLOø7Ç×šÒøþ xSÀÑÚéi­ÅÊöxŒ¢ålŠ.n® Ò]”(B¬„˜ã>Ê6ÚI;+íÝÁ[×ßÖêêöº¿ÄÂ’rRzwºÓ]uèìÚot¶g©·ìðW·ÁƒøAé?üTî¿aOƒI÷~ ü÷!i?üU?bÏÚ7Ä?g_x›_þдÕ,üWâ{ [[ûX ºÓmí5+¨míåH³x£°/¸®w¾w/ƒ´Õ߈cOٳŞ/ñ.¿¿ãû=MFïL´°TÕ.îtƸ•n–HŠÅlì®Ìm„r)TUw¡R”©{f’_»íÿ/oËùkòµÇV”á)C™¾^}¯ÿ.þ/¿¥íçcqÿa߃Áˆ> ÿá¤ò=4~Äyÿ‹)ðgÿ-#ÿ‘ë›ñüÁ~ø%uñ'Zð¿‹´\›QáÍwU¹Ò,­|aö§Ûnm<ÛõxEÄïÖÕV6 Å@8Äð‡üÛÀ¿´? Kàßø÷ÆúÇŠ¥Õ­íô¶‘¨Io&šÖßiYnã¿6|»¨¤Ié£`voó™"cÚÒ»\ªñÝ[UÞëuk«öº½¹•ÏcW™Fîîýw²oNú'¯“ìÎü~Ä?èŠüÿ HÿäjFýˆ¾ù¢¿ð‚Ò?ù©øþ + áß‹·¾OxGÆÞ3µ×t?\¿¼±ŠÆÒßÃ6—Àµ»Þ›Ë¨ r«+4VÂyQb%o‹Ìçfoø+?ÂoÚËãlÞð¥ÛM~ö·wÚuØÕ4«¸uH-¥Häq ­ä×VÙó•o`·vRp¤«|ÔùýŸ*¾ºYtßúëÐÏ’§'?3²·~»i¿¯n¶:Óûüÿ¢+ðkŸú´þF¦·ìEðxù"¿¿ð‚Ò?ù¸_Þ|Hø§ñóâì~øÃ®ø2¶œº.4m&óE¸w°ŽåþÚ%µ7²FîHa Ü,Œ‡ \¦“ÿÃøIm€¬õÖû·âÍEÔõ(cÖ4¨—A}N(¤… ›È¯.F%V&ÒÞ}¨ÊÍ·8¨£ˆ£Q_‘-RÕ-ß5¿ô—úî9Ó©ÍÌì•Þ¯ËüÏboØ—àøÿš-ðgÿ-#ÿ‘éû| þH·ÁŸü ´þG¯:ðïüÒçÿ +>!x»ÇŸµ­Kðg‹®|?Ók^Ó!»‰n>uÞ¬‰ª 7Éf•<¥›n/?à¡Äß…)ã?‡~!ñNžúdž´mbÎÆêËM“O¶†ã[[9\°Y$k¬ bm²½¾À­Xï$q˜wN5U¤“Z+ëuÿ’¯—RjR© J2›¼[[öšƒÿÉŸôô=Rïö8øAÿ’/ðgÿ#ÿ‘«*ïöTøCÿ’1ðgÿÿ‘«£ð7í9iñ_âŠô; xšÎ×o§Ï­ß(m.n!hR´Ô;dWVšÚ4’2²FÏ‘»ß×üCn a—5ìáèRšMÓZù/ëú¹çשRœœ\×›8 fo„(OüYŸƒ<Ôƒ£ÿò5Dÿ³_Â8ø5ðgÿÿ‘«jóÅy„nRO¿Ä+ÒŽ_GùÜŽª¾ÛûÙ–ÿ³Â1Óà×ÁŸü tþF¡?fÿ„g¯Á¯ƒ?ø@èÿüVåñœ+Ÿ˜TcÇ–êyqǽiý›Gþ}¯¹õê¿Îþö$³WÂëðkàÏþ:?ÿ#TÑþÌßÉçàÏÁü tþF¦¯ÄKUêëùÔ±üJ³d_Ρ崿çÚû‘KSùßÞÉ#ý˜>gà¿ÁƒÿrÿÈÕ2~Ë_Éø3ÿ„ÿÈÔ|K³ÿž«ùÕˈ¶nx‘:ÊYu/ùö¾äh±Õ?ýä)û+|aÿ$_àÏþZGÿ#Ô±þʉÿ’-ðgÿ-#ÿ‘êý¿Ž-䦾S‹f°¸5Vš³¿Cï|:ÁG0Í~¯Y¦¹[÷µ_©ô >IŒü ø îžèŸü‹QjžøCi¨èö_¾ jÚž½~še…¤>ðݹ¸ÕŠ'™sQ)m…T3‚ÎÈŠTüw¥üZø†HΠð/þ&´Œ|UãI­ôok‘iº« ·¿½›Gkä´„‚Yü˜ci$n0ªËË ËËðùõiâaI¹Y´··ãsúÀ¸}\LU4ã×»Ìî¼”nÏ«5¯|>ðî‰â½Jûö^ð•€äþ$šóá߆,ãÒ'còAº`‹s+«Fȶ¦bëqnWwŸý ¾üŒqðà†ìžèŸü^wûVþÖš_íð¯JÒtÏøöÓSøW2ÿÂ?'ˆ-.5¼p‚Ýak«±1†ôÇ$긒vyòy¨|Zø‚ˆq~ßø ÿ^Žuš}Rp ÊIßU+ìöß§õªgÎpo SÍ0õªciS§(¸û®Ÿ.^÷jÎýº[Í`é_ ¾^k¶víð{àƒ$Ó¤d¾ÑA`1ÿÕæ_c?x'þ ñá/Œ? 4« xãÂÿôê‘i²]?ÄV±iO}ö‹u>WŸä‰fYÑVW’5WfV"¼ÀŸ> Ïñ@I/ØÆú•º°û4|5sü>•ö¥®®nàŠ_½mÓ¿ììÌç’|$I¯¢á\[Ū¾ÒîѾ§Äx•’ÒÊåAPå\Ï^_×Dp³ÏŠ®m?eÿƒÑ«0Uøoá\®‡dk'MÒuM+ƶÚÕ¥–Kèï¢Yp¹d”8F¨ÁÁÁÆA#êü +‚ÓFý‘~jÚŒ­o¦é +¼=©^J±™8-ü=k4¥TrÌ6Àîp2:×±Åû7|ECÿ$‹âgþxkÿ—5ö™ÎSƒÇQ ±yV›kt»ú ÁüaŽÈªâ¾«AUUZN÷Ó—›·~fx]χusÆ÷:ÔúsG-ö ÷²@8i%.UyÈä€ 8 G¸|[øg ~ÒÞ‹ÂÞ-ŽKÿ¾¡g¨^iÌ#{}P[N— opެ$¤7§ÀÚN B×öø‹ñhþ%ŒÓφ¿ùsZvŸþ#ÚŽ>üKÿÀŸ òâ¹òœ¯.À)òVææiëý×uø›qgfYó£í0ꚤ¤—-þÕº·ÒÚXó;ø'gÂ]>ÿT¼ðn”~Üj±éÎá ·´Òb·¼°¹{›;ô…`1ˆÚYP—FI#¤ˆë€¥~Áúk{wmñâ€ñ•ߊOŒŲjSj¶ÚƒX%„»í ¡†Ku(`{v‰7þíc OU ¾%ªñðâ_þøoÿ—ôøsñ-NáQüKÏý|øoÿ—诩+Ú¢×Í÷OóKå­¢’ùOö½oïkü•—ܯoWÝß;ö~ø%£þÏ? ¯#Öm5 ýCS¹¾Öoêþyïn$¸š@Š畱‘1œ×ð£ö%±økàøbóâGÄOøsáôÖøNÖSGXôä³·–Þ(·ÚØA$¨b— 滱ؤ0;·zŒ_þ$)çá'Ä¿ü +ðßÿ.*uð/Älcþ'įü +ðçÿ-é?¨ÙGYréÓÜøtÛÝéØÖÝï­ïÝó|ZùõîxÕì+¦h? "ðm·ÄŸ‰±xwC¸µºð¸¹Ó¼ß=´¥à3ýΑ“²ñîTÃû¶IÏO |Iñ·…|K®xמ1ñ„lu=:ÚÿU]>¸†ýížA*ZZÁ)öHÂEà¶íä‚;ÉþüF•p>|IöóáÏþ[Öe×Â_‰SôøSñÛLJ?ùoNø'w*‰ß{¶îö¿«Z7½’W²C\½ÔüÞš½6»ovxïÃïØïFø)uáÇðo޼{ᨴM"ÇCÔ-íæÓî ñ5­™o!oâÒ@®äC%·‘#+à·Éͯ€ösXé?¼q©xFÒ)mô¿ êgM—NÑ¢i7¤pJ–‰xR%Ìq¬·L.Õ#»—àÄÉ?æ–|Eöñáßþ\T|ø˜çþIÄ_ûÿáßþ[Ö´§ŽÕ_ÇÕù6Ú3©õٶܾ¯Ôòÿˆÿ³%¯Ä?ø£W>#h:Wþ̾ Ðt‹› k-U!‰aòÌæÑ¯¡D»Ás`¥IÍJ¿³Ý‡„þ)?‰¼ãoü?·¼ƒO·Ô´ 4ÖÒ5E²O*ñ]YÌÑ7kw‰š8¢Ê)‹'ìùñ9ÿæ˜|Dößÿü·¨&ýœ¾(J?ä™|Cÿ¿þÿå½U?ìè|5ÖÿžþZ»-•Ý–¬‰}y«r=­ÓËü–»è!ñGì½¥j~ ½Ôì|sãmðø†Oi-f4ÉG‡/æ†Xn¤µr†óÒyw‹;fïÝy]+?±§ƒ<-ðþ×Ãÿðx¾þ+]"×Gk»ËØ$º¸Ž Iµ–F€eiØîm èù«Ø.?fŠr—á§Ä0ë·‡ùqT§ý•¾-6vü6ø‡ÿ¼;ÿËŠÒ1Ê­êGM’ååÓ·»¦†Ž`Û~Í뿞ªZÿÛÊþ¾§¤ü%Ó|/ñïWø“yâ=wÄ>%Ô,J·{ØtøM±i¼ï²£ZÛC$Ñ«…Ùö§“ µ”É!}MÇí#®y÷­«¿ÙâõÉÿ’mñ õÛßü¹ªƒö-ø²í—økñþþøsÿ—5ëa±¹e(¨ªªË׫¿æÛ8q\«rtÞ§*ž#–æ\î5n#=ØùI9÷®ºÃö5ø¡þ|@?ö×ÿü¸®‹Gý–þ#XãÈ úmáïþ[×cÎòåµTr,§÷¦Ï4>¼¹\Ç5NïÁ×àq¼W¾iÿü{j 7Âߟûoáÿþ[UÆø)ã‡? +¼~íãÃÿüµ¬ÿÖ +ÿ—ˆ¯ì\cû ùsTðΧ$ÏjZ­»šAŠúæóö~ñ­ÒŸøµ~?ÿ¦þÿå­aê_²ŸŽ/ Ûð¿ÇãþÛxÿ–Õ¬8‡Ö¢"Y&7¤ò²\êÊß~JÛÑU•ÆYëßì{ã½ùÿ…cãÿûýáïþ[V–“û*øæÅo…ÿôÛÃßü¶§. ËŸü¼A—Ö ò¯iÚ”¡s¾» ;A¾dî¯PÒ¾xÇO@Ÿˆúxðÿÿ-kE~øÖ/»ð£âþøÿ–µçÔÎðOi£²N-oyXðýè©ðéW±6rÜW«EðëÆÊ~o„ÿð'Ãÿüµ©OÃÏ”ÿ’Mñ?õóáÿþZ×;Î0ŸÎÖWŠþFyæ™5Än-ZðêN e«jóáoŽ\üŸ +>"~>ÿåµS…;|'øŒíçÿü·¨yž ý´RËñKì2”ºëFylS­µÆœà74—¾"ÎxøOñ#õóáÏþ[Õá?Ä 'ÌŸ ~$ççßü·¤ó¿ˆ†°8«ü ¿be˜÷5æŸ?d¨þ&xºïÄ:n·c¢_ꢨÛê: jöw2ÃvñÜ"Çwk,Sy1E~õ‘–¾E`ÌþËcáZÆü*/ˆÄúzð÷ÿ-i÷:ŽdL„?¿ð+ÿü¶¯7S/ÅÃÙWi£Õ˧˜àjû|-ã.çÌ ûjšgÅÞlz|?¾ÿåõ1¿f-E8>*ð_þ¿ü½¯¢ïü ãË£‘ð‡âGþxsÿ–õ›/ód| ø“ÿ^ÿå½xï‡øzZÊ+ïgЮ2âˆü5¥÷/ò<eýMúx«Áø@Þÿòö£›öSÔæ8>+ðPϯ€/ù{_@ÁðÓÇË×áÄŸü ðçÿ-êføqã²?ä‘|HÿÀŸòÞ’áî[A}ìoŒø¡ïZ_rÿ#ç­+ö2¼{Õiük¡ZDOÍ6‘à‰­oãÌ3\j×1G'£´8;N1]Çí/§Yø_öø­£i–ÑØiZ7½N±µŒ’–ÖðhW1E$’B¢(É$œs^˜~øùåøEñ'ÿ¼9ÿËzñ¯Ú_Åöž'ýо)jz|­>­ü*ñ¥g#¡ž ô ©£,§î¶Ç\ŽÇ#šôðx¾…*‹–Î狘æùž2¥7˜M»=.y·…u$ðNm3Ô|³ÿÔF3_°uøŸáíY“öÑ¢Ïð¡lÿõŒ×í…rç‘´(‡ü‡”;Ê·ø‚Šä5ïkÿðŸ]èz‹£ßýƒO¶¾ž{íZK?õò\"¢ª[Ëœ}‰$¼8¯#ýª§Ô.>:~É/ª[YÙß7Å]C͆Öå®bOø¢|Y²4q–ÈÁ9A‚Hç?>{GÑtWÈ´íCâ¯ÁAÂÿi?ôøóJð®›eâíWC›PšÏ͇Ç:”‹w76ò^[LJÞ8!YàòeÔî&/ Ì/çÿà£ÿ¼ãKDðw„~øÿþ_…‰üu¬èךxе jšÕƒ@÷z޵§ÿ`íþÁ¹3¹M_ìrM4n²}ˆ=èßôWÀà©?þ|,×þ)x§ÃõŸÛx¯â7„ôJkË]Vëþ˜|O}ýÅì$QyÐøu­Õ-¤ùæbäl°ý¢ÿjÿ?³d'¡“áÅOŠ^6ñŽ›£Ÿ h†ÆëK·›NÖ¯Þ[ÿZ‰$Œ¦ƒp‘Nu‹q)–|GºÇ˼û>Šøƒöñ–£ûXÁ1<,ÿ<'áøu g⯃¼9âm¦±Õ,.¾ÍñLÓ®#ž(./-“ÎXXËeö›Ÿ³´’[<³4NíŸãÿ‹?ðOÿ|pѾ ø;O›Á¾´ð‘áÏ +höÐG£hž,×õ»½:òx ÖöñH¶÷:ôšrÜZE!¸IšKgÔe¼p»è¯Ï‡ÿ·'Å ?ö ðæ«ñ–ïOøo¢|+ðWÄ=OÇö) W ©ØXEàûèo$ÓtÝ[RM:òÔÛbIq{3Û¬®‘Ä5ø‡íÿûqüXñ/ìÛñOáoÆ?†~Ó¼M…5›Ë]OQÐ,ì.m,õxöD–ÊÞ×ZÕã‚á$ðüЛ“yºH/î"6Ñ&˜õúŠùëà—í5㈴¿<-¨Mðæ}&Ò=B_ ÚXÝN·QØÝ%”²%èi¡¿äÉ ìk ¤úEÌQÁ$7‘Ý[^ÉêßÛ^>ÿ¡kÁÿøRÜÿòuôW!ýµãïú¼ÿ…-Ïÿ Qýµãïú¼ÿ…-Ïÿ P_ErÛ^>ÿ¡kÁÿøRÜÿòÛ^>ÿ¡kÁÿøRÜÿòuôW!ýµãïú¼ÿ…-Ïÿ Qýµãïú¼ÿ…-Ïÿ P_ErÛ^>ÿ¡kÁÿøRÜÿòÛ^>ÿ¡kÁÿøRÜÿòuôW!ýµãïú¼ÿ…-Ïÿ Qýµãïú¼ÿ…-Ïÿ P_ErÛ^>ÿ¡kÁÿøRÜÿòÛ^>ÿ¡kÁÿøRÜÿòuôW!ýµãïú¼ÿ…-Ïÿ Qýµãïú¼ÿ…-Ïÿ P_ErÛ^>ÿ¡kÁÿøRÜÿòÛ^>ÿ¡kÁÿøRÜÿòuôW!ýµãïú¼ÿ…-Ïÿ Qýµãïú¼ÿ…-Ïÿ P_ErÛ^>ÿ¡kÁÿøRÜÿòÛ^>ÿ¡kÁÿøRÜÿòuôW!ýµãïú¼ÿ…-Ïÿ Qýµãïú¼ÿ…-Ïÿ P_ErÛ^>ÿ¡kÁÿøRÜÿòÛ^>ÿ¡kÁÿøRÜÿòuôW!ýµãïú¼ÿ…-Ïÿ Q øã_ÿ„úÓC×4]Ãíú}ÍôØêÒ^¨’Ý^Þ,gí +AýÓÅuõùâëå»ÿ‚jk«žGÀkÏýD¤¯×*üdÖ/¤‹þ ï®FÙÚ~Þê!¯{$W…oðÿ™âæß/ñ‘ËhÓ…ýˆ4QÆOÀ[/ýCc¯ÜJü6Ò~_Ø‹E=¿áBÙü³#¯Üš¼õû”?ÃþBÉ׿[ü_ær/ü—ÏÿØ¿¤ÿéN§Iñ¯özðí)á[} â7üãýÒíoàÓüI£[j¶°Ü*:,Ëèè²’E@‘†pÆ—Eÿ’ùâ_ûôŸý)Ô믯ž=³Ëí¿b/‚ö ï|Â…ñx7Q´·°»ÐS¶+¦][Áw5ìÉl"òš8îîn. +³O,€vc¡­þÉß jßtÿ„? ì>ë÷k©øbß¶1hÚ˜ŠÍ5¢Ä!’@`€‡d$cçä\z…Çø›özð> GðçYð?ƒõo‡°Ú[XGá‹ÝÚ}-íŒfÞhèaÄbˆ¢lÂÓhF þÏ^ð_Á©>èÞð~“ðökK› <1e£[A£=½ÉÜBm&9L²—M˜s#îqÏaEqþýž¼ðþм5àø{DðeÜ×þÓôÍÚÒ×B¸™.Y­bA#¥Ýҳư¹˜Dž?Â?ðOo€_ô}GNÐ~üÑ4ýc?oµ°ðnm îmn¬Ïš‰›[ëØàuypŸvW ìP?áß„þð‡ŽüGâ'Ã>ÒüOã³ojöšt0_ëfŒÅmö©ÕD“ùQ’‘ù…¶)!p8®‚Š(¢Š(¢Šù§Ã¾:|[ñ¿mü£ü'þÅðo‰î¼:²kWº…½ÔÍE(b±G"ãdÈ3‘’åôµà¿oý¨?èðÿÚ·ÿ#ÑöÿÚƒþ??ðm«ò={Õà¿oý¨?èðÿÚ·ÿ#ÑöÿÚƒþ??ðm«ò={Õà¿oý¨?èðÿÚ·ÿ#ÑöÿÚƒþ??ðm«ò={Õà¿oý¨?èðÿÚ·ÿ#ÑöÿÚƒþ??ðm«ò={Õà¿oý¨?èðÿÚ·ÿ#ÑöÿÚƒþ??ðm«ò={Õà¿oý¨?èðÿÚ·ÿ#ÑöÿÚƒþ??ðm«ò={Õà¿oý¨?èðÿÚ·ÿ#ÑöÿÚƒþ??ðm«ò={Õà¿oý¨?èðÿÚ·ÿ#ÑöÿÚƒþ??ðm«ò={Õà¿oý¨?èðÿÚ·ÿ#ÑöÿÚƒþ??ðm«ò={Õà¿oý¨?èðÿÚ·ÿ#Ó ÕÿiKY’]GOøŸº–ÚÿTžhâ»$m +`¹!K¨'²õñ\†µÿ%óÃ_ö/êßúS¦W_\†µÿ%óÃ_ö/êßúS¦P__¾#Hæÿ‚xkl¸Ü>Þê!%~ÉWâÆ­,‹ÿüÖiø yÿ¨t•ïdŸoðÿ™âæß/ñZ]·ü`®ŒÿõA,ÿõ Ž¿q+ñWEÒÄŸðO­R9ÿ…gÿ¨tb¿j©çðÿòŸŠ¯ø¿Ìä4_ù/ž%ÿ±IÿÒN¼ûö¯ñf«áÏ?³%žŸ©êšÿÄ«Ë N {‡Š=FÝ|â[…†eR‘‰à‚PÛ‘HôþKç‰ì_Òô§S¬ïÚöbð‡íA£è6^-‡ÄñKê¿ÛzMÞ‰âMKÃ÷ú}çÙn- ±ÝióÁ:æÞîæ2»ö²ÊÀƒÆ<Ù<ƒãí•yð«öÉ»øoáÂEãßé^µÑ­âÛ­;B¹–é|[zÉ:,"Ëʵðõëˆ-¦–æIí!$p¬±ñÿÿàªÞ-øñ Nð„ßüa®ø¯Kðý¿‰<]¥èPjúü–ÖóÞßÚBšTš^—w Ì“2îHF§&’$´Þл]%Ÿ¯ÜÁ:þ^iÏÆŸã ½HÚYYG¯\xç]›ÄV©g>¥5¹‡V{à ‹ý±©ÄdŽuv·¼’Ý™ Ä@ÖàœŸµÝ;I³›Ã„Všm£X]Akâ-NÖ?Û´òÜI¶±\(Öã’{›¹dMOí"W¿½g ×w@ ñüÒçៅuïxÓáf¡£ü4Ò|Aão Zjvôú¾¯{á”×n§š+q¥œÖzàY%¹I–ïý­öß?Añïöûø—û,ü=ÓŸÇ?´óã/ø‚ßAðͯ…¼A©x›FÔÞK+ûéD²Zhí«G$0i—,ë“:f{B%(×OgëúŸì_ð¿^ð®¡j>ÓõMLñµâˆtûù%»µ’ÿXMM57–)’hîYÔ•¡”4 ]¨¡#ÛÏÛÁ:þAá[Ý6M?Æ·w·v÷¿ð_xç]¼ñE›À“G¶Öå¼mJÖ4Žêñ8.Q_ޮݷw@ ý®þ;øûö…ÿ‚^é>%ð}׌>|Bño|' ZÞÞéW1Þø~â_éºd—Òò+i®,ääHî¡·7V³ š¼×‰sþ~ßWš·ÆÏÞ"×?âŸÕüð«Á#Tð©¬]K†¼[s¨xž94œAo,¯qs0Ó¡Šk[Id¿‰ì%¶Šå&¶}?ì¹àK„ZGBφ4MVÇ]··kÛ†šMFÏR‹UŠö{ƒ'qp×ð¥Ì²Ìî÷™c)’MÙþ'ý‹þø¿Å^>×oÓJµñ6¡i$¶wZ‘ÒÞWÓn|Ø]^+ËW”´7q¸ŒÅnVPmàòÀ>P·ÿ‚ÛëèúÃü û4þÒ¼QâˆP_jú¦‘6•§h6ºõÃi–ú†‘mw{q-Ÿˆmš8¯`Ó‘¥†U˜Z;—è>)ÿÁ\¼KðÇÄcÀmð“ûWâîªê6Ε¤Ýëºæ…kމ|óAw¥èwš„»¡ñ”—L‚! »F”yvæëØ4_ø%ÿÁ]GñU”žñ±ÿ Æ•¬èšõÞ·ãkX¿Õ,õ{]2ÓPŠK«»¹g>e¾¦Æ8h–ÕDf=Ï»âì#ðÏâWˆõnóKñ•â {UmfûYð÷еoê²ÎÖ66 »±¹†t·’ßLÓ„–Èâ Ê 6–5pØ| øªü^ø{aâ}CÇ„-5ûK=KLÓ5Rñk6ÖóÙ[ÌÑj6­‹;ȧ’x^’`*Þfçhãì+Ÿøuð·BøI£¾™á»ì#÷ o¦Ã4Ÿ`Ó"†Ö X­ìíË­-Òx€‚Ýcˆ6÷Ù¾Iº +(¢Š+ó—Æ¿ð•7Æß '‚¿áOÍûSëÙM­ùÍag¿ÀÒÉq$pâIü¨ËÊ-ÕâóÚ5ˆÏn$3Çú5^û3ü+ñGÄ]GÅ^&áþ&j^$ðÝÅÖö‰-Õìc±û\ µŒNѵÜ[†Öh¥qÊIó|¹âïø*ïÇk»ín×Áß ¼?¯ÿ¢ҵ KÇZ†tû=+Uûˆ¼C¢³}§QÖì°íåÿ„jæãÎ)«ù y‡Gû kÏ?ýþ1x«áßí›ãß x*_éþ'ø©â»ï YjúÞŸ6§a¢ù^7øÅ«É<–pÏm%Îøô·€"Üñ®VRÎ"1Iú#â/Ù¿á'‹õj:·Ãꚇƒõ[wAº»ðŒSÍ¢j77BòæöÕÚ`¸–è ä–2®ò€ìKsGˆÿfÿ„ž1ðæ¿£êÿ <ªé+Ûý·cyá§¶Övß\j+ö˜Ú³búîêèoÜÍ/ß‘˜€7ö=ø×ªü|ø 5­vßO‡[Ò¼A¯x[P’Á+[ëY½Òe»Š'gxc¸{&ai%0‰„fYŠy¯êƒá;MÀ^Ó4- H]DÑm"°Óôû )í­l-â@‘CH#UU ´?á!·ÿžwßø7ÿ@¨ª?ðÛÿÏ;ïü›ÿ‰£þùç}ÿ€Sñ4zŠ£ÿ ¿üó¾ÿÀ)¿øš?á!·ÿžwßø7ÿ@¨ª?ðÛÿÏ;ïü›ÿ‰£þùç}ÿ€Sñ4zŠ£ÿ ¿üó¾ÿÀ)¿øš?á!·ÿžwßø7ÿ@¨ª?ðÛÿÏ;ïü›ÿ‰£þùç}ÿ€Sñ4zŠ£ÿ ¿üó¾ÿÀ)¿øš?á!·ÿžwßø7ÿ@¨ª?ðÛÿÏ;ïü›ÿ‰£þùç}ÿ€Sñ4z¨øŸþE­Gþ½¤ÿÐ ðÛÿÏ;ïü›ÿ‰ªºî±æ‰y Q_4’Àèƒìs ’¤÷hb¹ kþK熿ì_Õ¿ô§L®¾¹ kþK熿ì_Õ¿ô§L ¾¿üS $_ðMín`9o?õWì~TxÏB)ÿ¸×gÇO€·ƒÿ-I{™4­ßáÿ3ÈÍ#yRÿùG‡¬Çü;_D“þ¨¡ÿËB:ýŽ¯ÈŸøvy?à–š-ÀF*~Zsú”PWëµNm>hRôÿ!å‘´ªzÿ™Èh¿ò_*~¿äz?ÃÏ[OÿrðäÌ«–øh¤ã·ü#(¿Ê¿Aëà?;EÿVðô€œ€–­ÿ–ÒWߕɊ›”cs§W#Ñä¾x—þÅý'ÿJu:Îý¡?iß~Ëú>ƒ{âÙ¼AÿF«ý‰¤ÚhžÔ¼A¨^}–âìÅ®Ÿó¶-í.d-³j¬LIgGEÿ’ùâ_ûôŸý)Ôëçÿø*ž™ª»üÕôýGâ†iΈRßêzï€<&þ'Öt;wð¿ˆmVe³[ ðѼ÷[³µ¬EÈ9FÚëÆuGü-ø—§|`ð%ˆô›oZiú™åE­èWÚúl‘£>eì0ÜÅ–BG™îR¬¹VV=|!ûiøËâ_~ x RøG{ñÃS‰¼â;_^øRÐ5›ý§Ã¨Ïed¶¶$xÑôq-´6ÌR`‚6޼¿[ðçíOÿ Ûâî¡á|@ÿ…›ÿ¿ö6ÿn¯ý…ö³êkáøšjZ§ü"ݰ¤ÿ‰}‡Û¼ÏÝÝ|¿Ú³PéýsúïÅ- ÃúÅÆ™%÷Úµ{?ìö¹Ól!’þþÒ+û§µµ¸–Þyc·y¢˜ÝDH¶÷î© ¬Ÿhþ&_‡šßü[ðæ?Ú¾ãá?…øááÏx¿ÄÓ4Ø.no¤ž×F´øÏ¬\jVw«i4¶¢84=GM¼Žñµ„—d’KU» õ>Šü°°Ñ¾:xÀ>Óü;«~ÑúŽ/í<1oñ«S¸Ma×NñKø·ÂËq>ŒºœréæÍ-OŠšQ£Ç&”mÕ|ôk²©ôŠþø—ðç[×|/¦ÉûGÞøSÁÿ…—‚×J¿Ôµ ­BÚ}B¸BÚ¬¯5ÌòE©]êòÛɬ›µÍŽ¢Öéö)m?Cè®á§öwü#—?Ùð}›ûWRßý³öï´ùÿnŸÏÙöÏÞýŸÎó<¿¸ò<Ÿ³ÿ£ùUÐPEPEP_%ü"øE¯þÑÞ>øµ}}ñkâLJ¡ð÷Žï´[X†XmÒi”– Ó¸á€(b¾´¯[À*ø¥ñ(h·ñÃú§ûHë1ø¾óÂw“YLtqàÛöhnn#Áo-д‹Í$ŽY`x%†å`•>€ÿ†¿ÿ¢ëñïÿÖü‰\þé>!h^Ô¾?þÑGÄ^%´šÿN±²¹ÒOo îŸe4ÇÈÓÜ$qOªXïw*%yXˆ¡™ãù«Æ¿ð»-ü%ã+SþøŸDÒµíà3iÛí šõŸ‰¼Mk`úÔ¶¿¹¸·k|$Ësâ6{KˆŒ³%_ÈÞáÿðŸ¯?kϺï‚4ÏKh,5=CC·¹eµ·ŸÇß^ꥄ|±É§ÛjM"1­àº, i&=Wþfÿþ‹¯Ç¿üYÿò%sÿ¿f»Šú;Þè´Ç»Ÿ³y {i6±ok¥K5¬qÛÞZÍd“Ú\}žæÞC蒪̅nò×ìÑðÓãgÿ‡_ õInh ižøA¬Þ¦½®ëú¦ýc[×ÇÆ‰wÜÒ$ÞV™ %´êÑ雚âí%•å`ÿ‚'|-ñ·Ãÿx·Vø™cñÓǾ9Ò¼­ßKâ9µ >Ú©à­Âid1…5©Xê‘Ý) yû«v¸[Z3{/ü0Íÿý_ø>³ÿäJ?á†oÿèºü{ÿÁõŸÿ"W½Q@ ÿ 3ÿE×ãßþ¬ÿùøa›ÿú.¿ÿð}gÿÈ•ïTP‚ÿà ßÿÑuø÷ÿƒë?þD£þfÿþ‹¯Ç¿üYÿò%{Õà¿ðÃ7ÿô]~=ÿàúÏÿ‘(ÿ†¿ÿ¢ëñïÿÖü‰^õEx/ü0Íÿý_ø>³ÿäJ?á†oÿèºü{ÿÁõŸÿ"W½Q@ ÿ 3ÿE×ãßþ¬ÿùøa›ÿú.¿ÿð}gÿÈ•ïTP‚ÿà ßÿÑuø÷ÿƒë?þDªš×ìI©ÙXï‡ã·Çq#K`¾¹hÊ7H«œ Až¾µô-QñüxGÿ_6ÿú9(æïødM_þ‹çÇOüZñšàþ=ü4ñÀ[ jV¿>1k­«ø³IÑ¥µ¿ÕáŽÝ¡¸ºE—qŠ%æ=Ê6²XñƒÍÿÁV~ ~×^6Óü3­þÊ_ì<©Ãu›­øoYÒ4¹ôû›yg +u(în-&š9 ZX²ÂHcÌJ&O.ç¤øóà|7ýœ¾èž0ñ­ÿÄoéþ9ðújž$¼Ó­tÙ5kƒy¹äÖ¨Ã'jF •E@Ï#†‘€>Û®CZÿ’ùá¯ûõoý)Ó+¯®CZÿ’ùá¯ûõoý)Ó(¯¯‚~!x" _ø#ˆ¦7/À{´éÿRÓ­}í_|NŒø"o‰ýP«¿ýG^»0²j2±É‰åáÇØåÿ‚*ørÝ® óÛà5ªy{ÆìÿÂ6«îÊü¾ø~óø&߆@ÎÏøR6_ú‹Ç_¨5јáUÓiß™\Ï]ÔsºÙØä4_ù/ž%ÿ±IÿÒNºúä4_ù/ž%ÿ±IÿÒNºúòÎð¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¯1øðgVø1ãéÞ}?Pÿ„ÓÅ·ž$EY/²$±ÃD~C¸í€1<\¨È]ÍéÔP´j_óécÿoÿÆèûF¥ÿ>–?øÿün¯Q@~ѩϥþ¿ÿ£í—üúXÿà[ÿñº½EQûF¥ÿ>–?øÿün´j_óécÿoÿÆêõGí—üúXÿà[ÿñº>ѩϥþ¿ÿ«ÔP´j_óécÿoÿÆèûF¥ÿ>–?øÿün¯Q@~ѩϥþ¿ÿ£í—üúXÿà[ÿñº½EQûF¥ÿ>–?øÿün´j_óécÿoÿÆêõGí—üúXÿà[ÿñº>ѩϥþ¿ÿ«ÔP´j_óécÿoÿÆëânâÏxúÇÃ׺6­M°Úê71½üvŒ²+n0þïyÀ8Ë€ †©ë( š?á›?hú-~ÿÂ%?øýexö)ø·ñPÐÅ_ü9¬iz·e­ý– +ý‘å’Úe•TH³¹Á\ÀnÎ ¾¬¢€ +ä5¯ù/žÿ±VÿÒ2ºúä5¯ù/žÿ±VÿÒ2€:úø³ân£nßðDßÄ&‹Íÿ…wòn¿ä]~Õö~kxþ[øu¿‰TçËÿ…{ÿ¨Ä•êe¸eZ5.íÊ®yøêþÎPÓwa¿d„ÿÁ2¼0 ¿áHÙê3~•×äç5«…ý€<5? ø#cßþ¥XÍ~±ÖÙ»¼hÿ…ejÒ«þ&r/ü—ÏÿØ¿¤ÿéN§]}r/ü—ÏÿØ¿¤ÿéN§^ÿ:ø×®ü±ø/i¤xËâ´ÿü@}[Ô|áXüM®½šøw[¾X­ì›OÔ æêÊÔ»%«²Æ²¢îaâž¹ôýó‡ŠÿlŸ~ÆŸ¼ |g¬|PñÔ¾#ðþ£¬èÚ¾¹¡ÙišÏ‰¯c0Mkáõ´Xlk—iwåÙéËmÓ €àI–ãï¿à¸¿´OŽÞ.ð>©âìïøC?·#½Õ>ß§]ïŸE·º¹Õ!þ̶º—X‡ÈŠÆüù·A/Ùu,Ÿhµû@×ôW‡ø_öÛŽëÆžð׊þüPøuâ/øƒûM²×­´é£bt­OS[ƒwcyshјô‹ÈÌqÌ÷¿d†8§ŠWòÿ‚ GãOÚÅÞƒHñ†“à ÝøcL‹\ÓmtãzšÍÏÄ-[ÂWw q<¬î§Ó•áƒÌKQzæHnÕÙôWÊÿðWÿè Ó|K«ø7↛áßZiÚ¿ƒoSI¶Ô¤ñΓ{ªézbjV–W݈ÒMkK‘­î¡‚ñ’ñDVÒÊ’ÄÄÏÚ§Äßd‰¾'ø}áßxâ_Â;µ¸Õ¼{ai¬Ý\XÅg¬>„ ¬—vÍ&§¦Ë )=¬—©£7´*ô}óÅ?ø*…|!ÿ Cþ”ðÿŽá ø§øÃÃÙž#†OøOµÏ;ÊÑl¼´“uÃyÚß+Îwÿ„›LÄ_éþyâ_ø(†¿c¯Š ~ |Uñ?ü$^=ñ>•£ØM⯶hZwöÞ§u1Óã›ûo†¦¿j½­­”ÖÐùùiR8gx€>Ÿ¢¾@ð×ücÁ>"ð&ŸâFøoñ‚ÇH—áþ›ñ[U¸›LÓä‡Ã~½“Q ª^KëÄ6C§=Á´…å½’)Óɶ™âºŽÜÓ¿à¬Þ ð…÷´É´?Œ'ƒáïö¾¿ârMO~Ñm|E¯éwWrË‘FÖörhw"8#Y5 ‹QÇ ÜÉvbúþŠùÃSÿ‚ééñ3NÐt…¿¡l²Ü[ÅnÓB—Ét™¾ ¾yƒöÇñ犼gâí7µ_ØøC\ŸA¸Ô!ñ6Ÿf’O£œ$ìŽ>Ic=ù±“ƒ_CW‚þÃ?òøëÿeKRÿÒ; +?á¤>3ÿѹkŸøYèÿüvøiŒÿônZçþz?ÿ¯z¢€<þCã?ý–¹ÿ…žÿÇhÿ†øÏÿFå®ág£ÿñÚ÷ª(Áá¤>3ÿѹkŸøYèÿüvøiŒÿônZçþz?ÿ¯z¢€<þCã?ý–¹ÿ…žÿÇhÿ†øÏÿFå®ág£ÿñÚ÷ª(Áá¤>3ÿѹkŸøYèÿüvøiŒÿônZçþz?ÿ¯z¢€<þCã?ý–¹ÿ…žÿÇhÿ†øÏÿFå®ág£ÿñÚ÷ª(Áá¤>3ÿѹkŸøYèÿüvøiŒÿônZçþz?ÿ¯z¢€<þCã?ý–¹ÿ…žÿÇhÿ†øÏÿFå®ág£ÿñÚ÷ª(Áá¤>3ÿѹkŸøYèÿüvøiŒÿônZçþz?ÿ¯z¢€<þCã?ý–¹ÿ…žÿÇjK?Ú7âü—q-×ìýªiÖ¬àMw?Œt¶ŠÕ3óHâ7g*£$„Vlœ +÷j£âùµúö“ÿ@4z¹ kþK熿ì_Õ¿ô§L®¾¹ kþK熿ì_Õ¿ô§L ¾¿:¾"¼?ðꯀFÿøQ÷ŸúI_¢µùcãnéÿàœ>$€“å½ÿÔZCüëÚÊ£[ü,òs5ïRÿ<ÓÂþ=k_ØÇÃV ‚6?úˆÆÕû3_Žþ ð,7_±/‡/IÿáHØÿê'×ìENjŸ-+ÿ*[nj¶þfr/ü—ÏÿØ¿¤ÿéN§\÷í;û1GûJA๡ñ§Œ<­øÄÄš>±áµÓ¤º†á´ëí9Ñ’þÒêÝãk}BàbÈ%H`VºþKç‰ì_Òô§S®¾¼sÕ<â¿üßGøÿàMHñÿ> xÇPðÞ•«YéºÝéÒíïìuÙ!{}z¶²ŠÚßXÓ––7CÛ¬óðí+1/¿à~Öÿá.ÑuO|@Ô~xÏûrK߇¿ÚpÚhI>µö£ªMç[C£7ž÷×òyW’Á—[âŠ6·µ6þÿEx¡ûËâ-Ö}sã/Æ {ÆÚ6«¯ xÂîmoü7,v·–xµ±‹OM$ï¶Ôu¤y¬%–E»¤&ÚÐÛóþ +ÿ‚Lü8øw¥Ãe¤ëŸ#ƒûVËW½{Íeu^[ËâÛsqu³Iö{û«èÃïÍüÂy'™`ž§è ˜4ø%7‚t«_ Y]ø·â±¤|?þÉ´ð>Ÿw>žø+LÓµ+V‹Kµhm#–âÞI´=*9$¿{«“  :<“I'·ü4ø)¥|+ñ§Ä-wO¸Ô&»ø•â¼I©¥Ã£GÄzVŸ¥ªBT¬~F›ÅŽ÷îÚUW°¢€<ÁÿðM…žÿ„;ìNÏøB|W{â«<ÚÙ´ùùû>›6Øí>ÇÊÒ~ÉÛöøGtL1ûX>+ÿÁ=ôŠ?î|C> xgHÖ|W¡øÛ_ðÆ”t¶Ò¼G¬iiòZ]\=͔בüºNÇksl–€ì$¯'¿Ñ@8h¿ðKÿè_¼Mðæ_Æ ¢x«àþ“ðRîwº¶7QèÚm¶§oÄl /5[‚îPÆJEˆ” Cÿ¿ð  ø×¡ _ÆÓ㿇õ? ëîn­¼Ë;{ýWÄ:¤Ïj|Œ$‹?‰oÕL‚@+`U™di>¢€> ÓàŸ?5¿ÚÆÏU>,ÿ…qð§Â~+ñŒ|?¦èž$³×æMOU³Õíd½ŽÞïÃðËkpókWwäO¨jÑJZÝmž­þߢŠ+Àÿc_k_ŸP"Åu‰zÍ©¸>P¹ˆ[ÙÆdMØÜ¾dr&FFäaÔ^ùEQÿ„ŸMÿ …ýÿOñ£þ}7þ‚?÷ý?ƯQ@á'Óè!cÿÓühÿ„ŸMÿ …ýÿOñ«ÔPøIôßúXÿßôÿ?á'Óè!cÿÓüjõGþ}7þ‚?÷ý?ÆøIôßúXÿßôÿ½EQÿ„ŸMÿ …ýÿOñ£þ}7þ‚?÷ý?ƯQ@á'Óè!cÿÓühÿ„ŸMÿ …ýÿOñ«ÔPøIôßúXÿßôÿ?á'Óè!cÿÓüjõGþ}7þ‚?÷ý?ÆøIôßúXÿßôÿ½EQÿ„ŸMÿ …ýÿOñ£þ}7þ‚?÷ý?ƯQ@á'Óè!cÿÓüjŸˆ¼E§ÏáûäKë7w·‘UVe%‰S€kjŠ+Ö¿ä¾xkþÅý[ÿJtÊëëÖ¿ä¾xkþÅý[ÿJtÊëëòïÇÑ ÿ‚lø”Ïü(ûÞîW’¿Q+óÇöl?àš¾$~qÿ +>÷ÿQy+ÚÉ×»[ü,ò3GïRÿ<À>'¸ö:Ð-ùò—à‡þ¢1ý›¯Éï|0YÿàŸÔöòß,yÿ¹V5¯ÖY´Zÿ*XÓ•[39 þKç‰ì_Òô§S®;ö¶ý¡|Uð:ëᮑ௠xÆ'ø™â·ðÅ•¾·â)´+ O/GÔõY'’â;É?Õ鎖•rÊ®ÇEÿ’ùâ_ûôŸý)ÔëÇÿà¤?²n«ûWøálz‚>üJ´ð/O‰5? xþñítmjÜèš¶ž¨Ì¶7ÃÌŽ{ø'PÖì3ù•‚šñXôý ãWü!ž·¸ø±yðÿÀ'‹JÔ5ÝJÂ×Å_n°³Ó¬¤Aqz·W6ör=¼1ÍjÓJÐFµÂ« +»óú×íÍð²÷þ‘áoŠ?õÏ|;ÒµKWÑ.|mgmý‹ö,¤í©4~t¶6ñMµ'™áo'qÊ1Oˆ~Óß°¿i߃_4«]áà ¿‡ÞÕ’ÛÃú±sq£^\!´KðÝÜ£O·7>¼‚þÓ°ð™ µŠG¹aÜ|Ä_°ÆÛ ö_ñ×ÃûÍÁþÑ4ïü\Õ|1©êzÅójz寵/‹ô«Eº°:z%›&¼n–ê+›£$0BV.7B÷}¯ícð²÷þ'â_Ãù¿áþÔþÝÙâ6þÅþÌò?´¾Ó‰?sö?´Û}£ÌÛäý¢/3nõÏûG~ÑÞ>ðÇßü9øsà_øÃ[ñ‡‡õÏO?‰<_sáë[ }2çI·dVƒN¾yd‘õhÈ(…¾bHóÅOØkÄ>+ñƒð¢)u©xÒïâvŸãM^ÛB½¸Ñ´ŸøÃ[¿Õ.ÞúHáµà–×GµŽ/6v€ÝÜNÖwP }!ûKü/ø§ÿ OðçâgÃ=áÿŠ?áð§ˆü1©i¾'ñMç‡ÿä%y¡\Å<2Ûé×ÛödȬŒ‰þµc‚(~ÏöïøY§| Ó~!ø¿ÆøeáûíVïò·Œµk=ì:Å¥ÅÍ­æšòÉ/÷ÜYÝÆ|™dþÌïËÙ¿·ÂÍ;ÄtíÆðwü) WNÒ¼WuâZÏO¶±û}åÉw—ä·›í‹rJ#ß<¢†Ù“äÿa?ˆ^øEáÂZÿü%Zj¾ ×üQ£¯ŽuŸ†ëƳ©>©&¡¥¤%ÍôVöÓÜjE¦¹’7Šþ7šy&³‰äñÿ‡ŸðG߈_ ÿfßøaõOëš¿‚µ_ ø±`Ó|i¬øGûKQ²ð$^¾°]VÂyin‹oôWQ#=Ç™%¤¶Ð 3È÷ÿ‚¾,xWâW“ÿ牼?¯ý§J²×bþÍÔaºótëÏ7ìw«å±Í¼þDþT£ä“É“i;xÿì[ðGXý›þYø:÷Hðþ§Ûý§Xßaâ-SZ˜ê:†¥}{ ³ê;în|¶ž"o¤›}ܲÜ9µ²P‘` Š( Š( Š+ã¿€¿²G€ÿhŸˆ_u麮¥}§üEÔ4ûv‡^Ô,’(½¬¡pN‰÷味ŒÝzPØ”W‚ÿòþ й®áY¬òUyÿÄÙ?àg>6xWÀü>ñÞ¹âéWÚݰ°ñeòÃoge¨iWRÊóê1cËþ؆r¨š+{¥E(×TW‚ÿòþ й®áY¬òUqÿco€ŸàÖ¡´ð§ŠôÍo·vÚgˆ´{ÿê¢ë@¿›N³Ô~Ç+Å{%¼²%½ý±g·–hrä,ŒTàêª+ÁáÙ?è\×?ð¬Ö?ù*øv_Áú5Ïü+5þJ z¢¼þ—ðcþ…Ísÿ +Ícÿ’¨ÿ‡eüÿ¡s\ÿ³Xÿäª÷ª+ÁáÙ?è\×?ð¬Ö?ù*øv_Áú5Ïü+5þJ z¢¼þ—ðcþ…Ísÿ +Ícÿ’¨ÿ‡eüÿ¡s\ÿ³Xÿäª÷ª+ÁáÙ?è\×?ð¬Ö?ù*øv_Áú5Ïü+5þJ z¢¼þ—ðcþ…Ísÿ +Ícÿ’¨ÿ‡eüÿ¡s\ÿ³Xÿäª÷ª+ÁáÙ?è\×?ð¬Ö?ù*©kßðMƒ°iàÅ k±;Í{×Åz¹*ESŒÝОÔô=òÏü;¯áý¼Uÿ…v¥ÿÇkÍ?iŸÙ?á÷Á-/ÁZ—‡tb+ÝCƺ.›+^ø‚úö#·iæ)ŠILm¹T¡¬6³qœ÷r×ü—Ï Ø¿«éN™]}r×ü—Ï Ø¿«éN™@}~f|E“ðLŸú¡÷¿úŒI_¦uù©ñN?ðì/ÉÿTB÷ÿQ™+Üɾßág›?z—ø‘£ðÖÿ·ðÁÇ_‚_úG_£UùÑðÓŸø%Ÿ†ìˆYê5~‹Õg ð¢rŠ·ø™Èh¿ò_ñ^Р²Ò®õ//ä‚{€…m¢ÅÁkq+Í.ØbH]ÑFit_ù/ž%ÿ±IÿÒN¼¿öÈÿ“Šý“¿ìªßêâºðOlõýKâ–…¤|SѼq}åøŸÄUþ·aeäÈ~Ñgc5”7Rù|µÙ&¡f»Yƒ7• Êóþ&ý¨ü àï|R×õ-wìÚGÁo?þ)þÅpÿØÞN—o«Iò¬e¦Åݼ¿¹Ÿ3`Ë« üÐÒü'ñóǵÛ}3ö—â–ðÖkÚ…ý¿ŠšÖÖâx-üC…,ãìK$–6Þ hSÃdFlÁd´Ç¨~Ìÿ çø§â߈ *ÖuéÞ"ŽïWðö—០E6›$úâµÜßoÕvZ4ˆÐÜé–ÚÌHËåÄ(ô~ŠüÀø‹ðÓãf…á/ˆ^#Ñ.hñ;i_üe¦Äºî¿qööâaƒ!‚ͦhE¼–7-5#û&£ÆÒÛ܈"hψ¿ >6h^ø…â=çö€¶•ñÆZlK®ë÷ÿohþ&ø2,Úf„[ÉaspbÓR?²j1,m-½È‚&ŒôRø¥¡iôo\_y~'ñ•­ØYy2´YØÍe Ô¾`_-vI¨Y®Ö`ÍçeCr½|AûJÿÂUï´f¥ÿ †?á[j¶?ØÖ-çYj6þ ð¾¹o¨ëþLm÷n5¿°j*6J¶×ö1h"o+lŒ¼~‡ |yðÿí¡ø+V×;øgÆŸ|_ðþÂëP>+ð-¦«Ú\iWv±¥½øœÚM òİÝFæÖå Û¼ ʺ•ž¾&|eøsàO†ÿ5ýSâ‰|1ðŸUð¿Â?è°ø‰f¿ø‹â:OxKS¾³IîRÞ[{½XÑœM¨Ëk4«¤<ÒÆ† _7èØ#À*øQûSë>ñÖ·ÿ /¼5û?ü/Ò¼C«ý²kÏí]F ÏEssçÌY|É•ßÌmÙ` "€>¿¢Š(¢Š(¯[ö\ÿ†ªø”4íCBÿ„ƒÁþý¤ugÅV­{öx[N> ¿³ : ÜÛËuwk¶Øtš)äIcxa_}Wð“à{|»ñ|Ú~¨.[Æ^#ºñиµÈ†Y–8ÄiµÇʱÃç$¶ãÀ!TóûÆ¿ðO‰“øKÆZ%ß¿øJu GJ×¼3ðoU[í&H~]xš]/X®.Rm2ÝtÛÿ ˜›HI®¡‹DŽ3mik}ÿý—/øðëá{i ¼?áoø7Ÿ\i¦Û\éšäãÜE,N +Ü]iÚÃ{:6u"Ž÷cÜ?àŒÿ±‰¿cO…ú½Ÿ¼!§èÞ+ñ‡ü×Z¥¼–—8Ó¼#¤èÒiSM™KKÍ:úPë}š”m ®ò\$_`ýŸRÿŸ»üþ9GÙõ/ùû±ÿÀGÿã”zŠ£ö}Kþ~ìðÿøågÔ¿çîÇÿÿŽPê*Ùõ/ùû±ÿÀGÿã”}ŸRÿŸ»üþ9@¨ª?gÔ¿çîÇÿÿŽQö}Kþ~ìðÿøå^¢¨ýŸRÿŸ»üþ9GÙõ/ùû±ÿÀGÿã”zŠ£ö}Kþ~ìðÿøågÔ¿çîÇÿÿŽPê*Ùõ/ùû±ÿÀGÿã”}ŸRÿŸ»üþ9@ªˆãÂ?úù·ÿÑÉGÙõ/ùû±ÿÀGÿ㕇ñ'Àz·ÄOßhÑx–ïï|ª£QÒmÑ/m°êÙ¥2"“·ØH•*À0ø«þ +³ÿàøûoiþÕ>~Ðþx¿Gº‚Îù´oê6ú>«¦4àÎd³·ž5û\(òI‹´ÊG“+hå·é><ü!·ø û9|ð}®»âßG øçÃöí«ø£YŸXÖ57ûfçžææbYäwfl ¨€„5D_Kÿ‡~êÿô]þ2ÿà}§ÿ¨eÿ‚qWUÒ.5‹Ÿ¼C‹©ÚêÐÙêW³[¼öò¬±–ØÜ¸;H8$df€>–®CZÿ’ùá¯ûõoý)Ó+¯®CZÿ’ùá¯ûõoý)Ó(¯¯ÎˆÑøu—‰ýQ ßýF¤¯ÑzüèøŠßñ«Oú¢¿úI^îKðÖÿ ëözð ö£ã[Éüàù®þ%ZGaâéßF¶iðþ—â}›û{W´Ó¡‚ÿ[û4f+oµNª$ŸÊŒ”Ì-±I ÅtPEPEPEó̶?3ÿѹkŸøYèÿüv€=êŠð_øiŒÿônZçþz?ÿ£þCã?ý–¹ÿ…žÿÇhÞ¨¯ÿ†øÏÿFå®ág£ÿñÚ?á¤>3ÿѹkŸøYèÿüv€=êŠð_øiŒÿônZçþz?ÿ£þCã?ý–¹ÿ…žÿÇhÞ¨¯ÿ†øÏÿFå®ág£ÿñÚ?á¤>3ÿѹkŸøYèÿüv€=êŠð_øiŒÿônZçþz?ÿ£þCã?ý–¹ÿ…žÿÇhÞ¨¯ÿ†øÏÿFå®ág£ÿñÚ?á¤>3ÿѹkŸøYèÿüv€=êŠð_øiŒÿônZçþz?ÿ¨oiߌZ}¹–_ÙÏ]_—Æ:CI„œ’(è ++çøk‹ÿômÞ*ÿ›Mÿâë7Ä?·7Ä>–þ"ø¬xvËVÔí4ˆ¯/|ObbYîfXccß#|Ì ØŒB†8À4ôÕr×ü—Ï Ø¿«éN™]}r×ü—Ï Ø¿«éN™@}~qüD|Á.¼N?êˆÞÿê5%~ŽWæÿÄFÿ`øœÕ½ÿÔfJ÷r_†·øYâæÿñ"×Ã?ùEŸ†ìˆYê5~‹WçGÃ3ÿ´ðÏý‘ /ýF£¯Ñz¬ïá¡þ?Å[üLä4_ù/ž%ÿ±IÿÒN¾ÿ‚©ükñ÷ÀWø®ü>·Ô5k¸~%K6· Ù%Ì÷&Ñ­¼/âÛû- e7W«5¤.|¶½ŽÌ¾K 4_ù/ž%ÿ±IÿÒN¯øËán…ñÄ~Õµ{µêÕdÖôI|é#ûãØÝØ4¸Vók}u× ¿½Ýʬ¾í|ý¼¼C¯þÒ¿´ßŽõÝ<ü7Ò¼á[Ÿ†mÍÝìVúÒI©x›OŠçl uæI«ê‹öItø'{Ë)´ƒ3LË-ÿàµÒXü=Kícán¡¥øŠãÄ¿ìtÛ‹­GOVñ¼–Zmþƒ Â5 6Òö(õ+kù ¾½²µ‚Ùì¤ æE,Ëôþ©ûü/Õ4íVÌxCO±´Õ¼?£ø] Ó¤–Â; "{›),ÖAe%œ÷sKÖÞTп”ÈêÐÄSÑà—ÿt}ÅVRxwÄÇü'V³¢k×zߌu­bÿT³ÕítËMB).®îåœù–ú>›`á¢[U˜÷>àö¨øwÇÛëႵ|@Òü1qðÿÆZÝÅ—†Ûþ +â߆²®|tÝ?âOÄ!ã_øJ; bÕ×QÕôÝ ]Ô4–ÕžßBÑõ)Œ˜¶°7”6‹5ðÛù[¿¿ü|ý|ûJx«ÃÚï‰GŒ-5¿ Z^Øiº‡†üg¬øfê{ǵ{˜Z]6êÝåŽG²µb’À¤sGÄØÛáßÄÏ +øcF›GÔ<7ià«OìíOk—þºÒ,ŠDcÆ—5´Éf }ÖÁü–6¶ìP´1ñ„ÿðV»?Ž:†µ |9ñ©§øÃÅv¾Ò-?´­`Õnâ¹øxž5‚O.B¶ÉpÊëcä½ÊÄù¦à.V½öKý¡|UûHxLñ¥á/è:|ßm·½šÇÄS_ º†H8 Žk;k‘±šòÞê;è,®­/,%€ÛJ¤N9€ðMü(ñWˆu wLð‰­.¼eð§AÓ?á"×GðU“Ý5¶‘3]Ïw5Ü’ ¦[©ZDŠè[ZæÚ6‰™ý?àïìÅá€ÞSxnE8ûS]\j$ÔµKZ[³¸¾–êyd¾¸Hìí¡Š{––X ˆCÇ 1@¢Š(¢Š(¢Š(¯‘~|4ÿ…£àŸÚÍî~ 5µ‡Å-WQ›Iðn»ýƒªøÊÓmLv |³[Ëo¾o)ÃEwk¹âD–o³¼ñÉõÕ|©ðsà_…þ1iÿ´¿[_Ú@ßµ_G¾´Õ®ô=JÑÖÒÚÜÝXßZË Ì TÝ[´J¥ã’â%D %Ü|_ñ·Š¿gÿÚÄ~=ø¯û9|*Õ,üSÒ| àÝbV»ÕNxf6šM»ßÞÜbdùc† ]Éú` –!A äø)·üÁŸðJ_øGo>"|;øµ­xoÄÙ†ÓÄ>Ól.ô¸®Æòl¥yo"x® hdUd "n(Îb”G«ñçâ•ÇÆßÙËàï‹n¼#âßI¯øçÃ÷‹¡x¢Þ mcOF¼ùÌ0Ë*Å#&×òËï@ádT:.÷ˆÿlo +xÇOŽÓWøWñ[U´†êÞú8o<q&èkðÄ:—Ù­î¾Í£ë^EµìþUˈì7iھ¦Kì?²+"ÞHHûKøWþ?†zv‘wÿ Wü-:çDºÐ¥†úÛû:+¼mVGWÿüzÁö”ž~¥bœ}¡Mz|ð ö:øð;þY4i¼?>¡ð§Â—ß~E®£.•i¦OåßÂ×fÚF¹{udÑt™ûîJx]®‘Ãj2­|ßû'Á5üaá_Ú«Á“?¯h|5ã]Å‹¤øÎÏÀ¶1ÙjVºŒíçÔàÓü4VËÌ[›ÏpÑ}­ž(Žã¢@?OüM¬Üè:tsÚé:†µ+ÝÛ[µ½“À’F’ÏO93Iyp£´Î)ˆÒI +FÚùðïþ q㿃¿ÿeÝ/ÂþþÌÕô¯ +xGþ»®µo%Íþ±¥x«À÷Ñý²wš÷ì66> []­,vÐ+ÛÛìIb‰ùýoöÔcسàÍî¡¥øÀº6‰ð«I²øß.µâ«H|W}i­x:OìMBòîäC{çX[ø‡K´K™¾ÃW¦ÌIok8Rú¿E|!ÿl²ð7ˆõ¿Šþ0ø}ð_OðüEã[ë _é–þm3N²…-nൟJ»žÞHîïì§v6/4&m2e¸x®"XÝôQEWÁ–ü;ã]cã‰õ/…>.kV¿/´xtï xš-.{;_²A?šVëS°¶1¬ŽÀív”´Ëò• Sï:ø×BðÏŒ¼sð[öðï$Ô-5¿|\m +æÿN¿Ž¥Þ>‘kªjs—_*ò×O–îæùˆšˆŽSû§Ðý—?dÿŸµWÀ ÇÚwÃïøoOñÚÖËYñeñ¹h¢¸–¸I-uí¦·cÁ<IÐM ¨ì® zü;/àÇý šçþšÇÿ%WµxOÂzW€¼+¦hZ™§èº&‹i†Ÿ§Ø[¥µ­…¼H(b‰HãDUUE(­ +ð_øv_Áú5Ïü+5þJ£þ—ðcþ…Ísÿ +Ícÿ’«Þ¨ ÿ‡eüÿ¡s\ÿ³Xÿäª?áÙ?è\×?ð¬Ö?ù*½êŠð_øv_Áú5Ïü+5þJ£þ—ðcþ…Ísÿ +Ícÿ’«Þ¨ ÿ‡eüÿ¡s\ÿ³Xÿäª?áÙ?è\×?ð¬Ö?ù*½êŠð_øv_Áú5Ïü+5þJ£þ—ðcþ…Ísÿ +Ícÿ’«Þ¨ ÿ‡eüÿ¡s\ÿ³Xÿäª?áÙ?è\×?ð¬Ö?ù*½êŠð_øv_Áú5Ïü+5þJ£þ—ðcþ…Ísÿ +Ícÿ’«Þ¨ ÿ‡eüÿ¡s\ÿ³Xÿäª?áÙ?è\×?ð¬Ö?ù*½êŠð_øv_Áú5Ïü+5þJ¦\Á9¾xjÔ­|7ª­=MÌ>‰uKˆ· Ü»ã’å‘× e]J°à‚ ïµGÄÿò-j?õí'þ€hõr×ü—Ï Ø¿«éN™]}r×ü—Ï Ø¿«éN™@}~nüEÿ”bx›þÈïþ£2Wé~nüEÿ”bx›þÈïþ£2W½’ü5¿ÂÏ8ø¨ÿ‰~Ê-¼1ÿdBËÿQ¨ëôf¿9¾øÕ·†?ìˆYê5~ŒÓÎþàA“üU¿ÄÎCEÿ’ùâ_ûôŸý)Ô믮CEÿ’ùâ_ûôŸý)Ô믯öŠ( Š( Š( Š( Š( Š( ¸„ŸÛàíß‹æÓõArÞ2ñ׈î…Å®D2̱Æ#M®>UŽÇ9%· +½õGìú—üýØÿà#ÿñÊ>Ï©ÏÝþ?ÿ«ÔP³ê_ó÷cÿ€ÿÇ(û>¥ÿ?v?øÿür¯Q@~Ï©ÏÝþ?ÿ£ìú—üýØÿà#ÿñʽEQû>¥ÿ?v?øÿür³ê_ó÷cÿ€ÿÇ*õGìú—üýØÿà#ÿñÊ>Ï©ÏÝþ?ÿ«ÔP³ê_ó÷cÿ€ÿÇ(û>¥ÿ?v?øÿür¯Q@~Ï©ÏÝþ?ÿ£ìú—üýØÿà#ÿñʽEQû>¥ÿ?v?øÿür³ê_ó÷cÿ€ÿÇ*õGìú—üýØÿà#ÿñÊ>Ï©ÏÝþ?ÿ«ÔP³ê_ó÷cÿ€ÿÇ*+ý/PÔ,f·{Ë0“ÆÑ±[FÈ`ã÷•§EÈk_ò_<5ÿbþ­ÿ¥:euõÈk_ò_<5ÿbþ­ÿ¥:euõù»ñþQ‰âoû"7¿úŒÉ_¤Uù»ñþQ‡â_û"7¿úŒÉ^öKðÖÿ 'ÿÁ@§ýˆu ü2ð§Áߌ5ŸG𥗌|Aauâ/ø“NµÔn¯DvQ]ZZëÝjK+ä ¨ZZåmÒ+·‡Ì{nöýÿ‚ºk¬~/økÃ7•ö? +x¦ßÁ¾:Ò­õKûh|C¥øwPÔäŠá®t”ÑÏÙåÓoaxàÔo&YíÄr[..E°ßôWÎ~Þ¯‡¼+ãIµßiöÚß>%xCᮡia¯½Õ¬·âxhËsïk´vÏâ +­™…˜'É3m‹Ãíà¶%ºð'Ã]NÛàOˆ5í_Å¿ô‰ºÞáíßM§é:´—`·²–ÃD–)õ†ÊrÑ_¶›n%hÑ.¥O:x@>ÿ¢¼?ÀŸ´÷Œ¼ñ÷Ç> ƒá柧/„®íSê%Ý=“ÜÇÞ\[ v)ÄjšÁí^îƒasou6›s°GîQEQEQEWÍ>øåñÓâßü{oà½á?ö/ƒ|OuáÕ“Z½Ô-î¦h’)CŠ9&AœŒß(¯¥«ó—ö»øi§|Jÿ‚gþÞ?Ú7> ¶þÀÔ¼g¬Úÿek·ÚO›<>M‰qöY£ûM¹ÜwÛO¾ 8ßmúƒíÿµý~àÛVÿäz>ßûPÐ'à'þ µoþG®+þ +ðÁ¿´ÿŠŸÁšg‡´ýoã~§áó‡â[¥7MðvÖGcñ-»9#O¼YÃ5·Ù|«­BâÂó n¬<ÿö‹µðoìåûU|?ø·àÏiúÌZ—ˆÊÖá÷"ÃçþÁ:õ-*ëöUÓì4o x?Ážñˆ¼-&—á]-4­®4½vÿN¸»¶³L‹hî§µ–ëÉß!ŒÜife2¸_·þÔô ø ÿƒm[ÿ‘èûíAÿ@Ÿ€Ÿø6Õ¿ù½êŠð_·þÔô ø ÿƒm[ÿ‘èûíAÿ@Ÿ€Ÿø6Õ¿ù½êŠð_·þÔô ø ÿƒm[ÿ‘èûíAÿ@Ÿ€Ÿø6Õ¿ù½êŠð_·þÔô ø ÿƒm[ÿ‘èûíAÿ@Ÿ€Ÿø6Õ¿ù½êŠð_·þÔô ø ÿƒm[ÿ‘èûíAÿ@Ÿ€Ÿø6Õ¿ù½êŠð_·þÔô ø ÿƒm[ÿ‘èûíAÿ@Ÿ€Ÿø6Õ¿ù½êŠð_·þÔô ø ÿƒm[ÿ‘èûíAÿ@Ÿ€Ÿø6Õ¿ù½êŠð_·þÔô ø ÿƒm[ÿ‘éÐjÿ´¥¬É.£§üƒOƒÝKmªO4q]’6…°\¥Ô€Yzxª>'ÿ‘kQÿ¯i?ô@«Ö¿ä¾xkþÅý[ÿJtÊëëÖ¿ä¾xkþÅý[ÿJtÊëëówâ/ü£ÄßöDoõ’¿H«ówâ/ü£ÄßöDoõ’½ì—á­þx™ÇÅGüHÐøh?ãU~?õD,¿õŽ¿D«ó¿á—ü¢§Ã?öD,ÿõŽ¿D)g_ 𢲊·ø™Èh¿ò_(Õ|1¨jr›½Büè—~"Ôæð¹¸¿´º³¿›û ®—æ\Ã}z&³fW¼¸‘ËI+»{…áúÿü“à÷‹!kö‹a©øžßÃ)³¨Û¨ˆ,3]¬Bi#Fr†>>EÇ}Ep>9ø7ðçâ…|I¡x—À~ñ‰ã;¸oüA§ê~K»]vâ·H¦ºŠHŠO"%¥ª«È¨¶„kŽƒÂvš€¼+¦hZº.‰¢ÚEa§éöSÛZØ[Ä"†(‘G"ªª(@oQ@á!·ÿžwßø7ÿGü$6ÿóÎûÿ¦ÿâjõGþùç}ÿ€Sñ4ÂCoÿ<ï¿ð +oþ&¯Q@á!·ÿžwßø7ÿGü$6ÿóÎûÿ¦ÿâjõGþùç}ÿ€Sñ4ÂCoÿ<ï¿ð +oþ&¯Q@á!·ÿžwßø7ÿGü$6ÿóÎûÿ¦ÿâjõGþùç}ÿ€Sñ4ÂCoÿ<ï¿ð +oþ&¯Q@á!·ÿžwßø7ÿGü$6ÿóÎûÿ¦ÿâjõGþùç}ÿ€Sñ5W]Ö#¼Ñ/!Š+æ’X}Ža’T€>ílQ@r×ü—Ï Ø¿«éN™]}r×ü—Ï Ø¿«éN™@}~nüEÿ”bx›þÈïþ£2Wé~nüEÿ”bx›þÈïþ£2W½’ü5¿ÂÏ8ø¨ÿ‰_ ¿å>ÿ²!gÿ¨Ôuú!_ÿ ¿å>ÿ²!gÿ¨Ôuú!K:øhÿ…”|U¿ÄÎCEÿ’ùâ_ûôŸý)Ô믮CEÿ’ùâ_ûôŸý)ÔêßĉVŸo|6—«ûŸkèË.[÷2I­ÀR[t‘ªvÌÜH +kÂ=“¤¢¹[‹ZeïŽüU¢´°ÛÇàû;K­Bîi<¸á3¬ÒmÀ(ш#`à©­+OˆZþ’—ðkš<Ö2[Ív—1ÞFÑ40°Y¥  +FH ÙÂ’#4±EcüBñ_ü ~×5ϳý¯ûOžûÈßåùÞTlû7`ã;qœg¡¬ßüS·ñF³ [ÛZÌ‘ëš]Þ¢LÌk'·–Ú'·’1œH¯pÊãvQ¢e ž€UʷƯ JšD–šÎ›¨ÚëZ Ñẳ»Šh#¹0É2Æî°@  ±icæÍlCã"âäUÓ^9£·™nP«¥Ã”Ï"WPôr02hJŠÁ“â—†"‡T‘üG ¬z‹¢çPˆ.žìåÌw~ì—@lAhðW-ü]jÅ„6—FóP¶ŽØÌIRÒíížP0 T' +dPIà ê+×~+bøoǺØ<ßøB<ßÝùû~۲¾»~LùÛ:7ÝÏ|þ?ûû'íÖÚŸgû_ØüåûG“»g›³;¶nùwcã9  ”VñKþŸݧˆô«[«ÅÓášB'Ž[–Xƒ`ÈA ùˆ=*åŒtNvŽÛUÓn$[ÇÓÊErŽÂå»Á€Ö*+1O¼’FiW+¨üsðN‘¨Oiwã +ÚÝZÈÐÍ ÚµºI©Ã+)|‚ ƒÈ"ºªù[öXýŸ|ñ_Æßuø#Â%Ô!ø—¨ÛGuªèÖ÷“Gµ²ayˆPÌÇã,Os@õÿ àú<ÿƒ›oþ.øhOÿÐñàÿüÛñu‡ÿ _ðwþ‰?ÃOü&,øÕðÅÿè“ü4ÿÂbÇÿPçü4'€èxðþm¿øº?á¡<ÿCǃÿðsmÿÅÖü1Áßú$ÿ ?ð˜±ÿãTÃüÿ¢OðÓÿ ‹þ5@ŸðОÿ¡ãÁÿø9¶ÿâèÿ†„ðýÿÁÍ·ÿXðÅÿè“ü4ÿÂbÇÿQÿ _ðwþ‰?ÃOü&,øÕnÃBxþ‡ÿàæÛÿ‹£þÀ?ô%Úåa—Lµ¼õ^GFžÞ[ »VE+ÎI¸^뀃‹Eÿ’ùâ_ûôŸý)Ô믯ö2Óþ +êþµÕņ© ºÔt»%¹ öÒ_\¥ÝåÍë¹6âàÝ0- ‘Š(Ø€ókû9x‚þÏR2¾›e$÷—”1bïRk‡û-”1YÝ\M’k)Z ñ’§ ǸÑ@ßÄO j;øWâ]VÎÖûWÓïlmÉ™ž!æ$‘ÄìÛY€S´’lyo|¸ñ/‹õ‰m5(l4MoÃzž’ö¾Qsiyxð™.dF  (7©~ZY½6ŠòÏ üÔ¬Íâ{Q³™í-ÙÂw~SUǬÑ@Akð/_›Nð½•Äš?ðüVöð–5c©<³I,Ä–$’I5Øí~Ð?Å_øUj_ü~¬hßðLŸ„º·a¨ÛéÞ#7ZeÔ7¶æoßΉ4R,‘±G”«muS†qÒ€>€®CZÿ’ùá¯ûõoý)Ó+¯®CZÿ’ùá¯ûõoý)Ó(¯¯Í߈¿òŒOÙ½ÿÔfJý"¯Í߈¿òŒOÙ½ÿÔfJ÷²_†·øYâgñ#Cá™Çü³Ã?öD,¿õŽ¿D«ó·áŸü¢³Ã?öD,¿õŽ¿D©g_ 𢲊·ø™çÄ-À5ïíÍsGѾ×áý/ÈûuävþvÛKvÝäg—8é‘ë[ðОÿ¡ãÁÿø9¶ÿâ믢¼#Ù9øhOÿÐñàÿüÛñtÃBxþ‡ÿàæÛÿ‹®¾Šä?á¡<ÿCǃÿðsmÿÅÑÿ àú<ÿƒ›oþ.ºú(ÿ†„ðýÿÁÍ·ÿGü4'€èxðþm¿øºëè CþÀ?ôñ @ñçÇÍû\ÑõŸ²xTóþÃyÇ“ºçMÛ»a8ÎÖÆzàúW£Ñ@~nüEÿ”bx›þÈïþ£2Wé~nüEÿ”bx›þÈïþ£2W½’ü5¿ÂÏ8ø¨ÿ‰ ÿåžÿ²!eÿ¨Ôuú%_Ÿ Ïüj³Ã?öD,¿õŽ¿Dég_ 𢲊·ø˜QEáÈQEQEÄ|hý¢üû>ÛiÏâNâÒMYÝ,í¬ôûFîà GX-£’_-7 i6ìS$jX@xOøxßÂúxËÿM{ÿëÆ¿à©Z¡Ò~<|*7xoÄ«‘ÿ_Zþ•óߊV”¸=‰Î+õ®ðÿ™å´ñµg4å}š¶’k¬_nç玺‡ŒGýÈš÷ÿ!Ôgþ +OðITñx#þ¤]{ÿëóËPñkÉ+yO SØVLºýËJÄHÀß­}e?²ù+º³_8ÿò'ÎËÄÜZvTâþÿþHý#ÿ‡”ü"ÿ §‹ÿð…׿ù“þUð‹v?µ<_“ÿR.½ÿÈuð–‹ðŸXÖtË&Ö‰m¬j°?EšYEõô|•+ˆÌJ_bI";àmS½7C¢|/×u›k ³}§Yé×Zdš´×× ‚ÂÝ&’ ÊU ni#Úª‹P$Èü.Éšn¼ö÷5½šV½ÚijuGóGkPŽºõòþöŸߣOf}éÿ)øEÿAOÿá ¯òðòŸ„_ôñþº÷ÿ!׿Ókw!ˆósŽ2;Ñý»sÿ= wÿÄË¿çôþøÿò''üDìgüúãþgé/ü<§áý<_ÿ„.½ÿÈuoÁŸðPÿ„ž<ñž™ YxƒV¶Ôµ‹…µ´þÓðΫ¦[É3ñf{›hâWv!YÁwtEË2©üÏþܹÿž†¡Ð¯Þëã_ÂÀíœ|@ðÆ?ðyc\øÏ²ê8jµ•YÞ1”–±Ý&ÿ”éÀø‹¯‰§EÓŠR’]z´»Ÿ´TQE>Ÿ°Q@pŸÿi~ͺvŸsã=q4•Õeh­"KYîî. +]–䨹PÏ·j—@H. ÷uùÿÿ½ÖdÑþÕ¿ù¿-|_ðfûÁú5ßÛ¼[á%×´Ûtº¼Ð äÉl­´íÜñ-³Ê©1G3È9rŽÍÚòF$–9>æ³Âx+‘b#ÏN½V½c÷«ÓÕ5³Z>ŒÒ·ˆ™¥&”éÁ_Ê_¿£îž«©û&ŸðTï’)+âýE€ôðƬöÚ‘¿àª|c¨; êßü_Ðj²ˆŠƒ€O­k|?ðµ÷Ähþ°–Þ+Ýnö+á™bW‘Â)b!rFp ö­çàvIN2JõRZï —ý¸es)5Ó…ß”¿ù#õ÷þ™ð7h?ð—jDã÷ÿ"Ó?áê¿èq¿ÿÂgVÿäjür¸¾™I‰›ýYÛÁôâ ’úDzûÕÇÀ¬™êëUûáÿȼJÌ“·³‡Ý/þHý¥ðü¯àŸÄÏéžÒ|jXÖg¶q]éö1Ï+}ÈüÙàHùª–Ù•W,Àu¯À¯ÙÚòIj_„êÎÄÂwáþ3ÿQ[Zýõ¯È*?âE߆OŸø%‡†‡§Á /ýF£¯ÑZüãøa!ðK¿ ¯ýQ/ýF£¯ÑÊY×ÃCü(yGÅ[üL(¢Šðh(¢Š(¢ŠøSþ +÷#GñáIS‚tŒÿÛÖ‡_%M+;`¹#Ó5÷÷ü‡ö6ñÇí;sàÍcÀ:‡…aÖ<3¡§Ïg¯Íqmm=½ãZHÒ¬ÐÇ+ ì£ xa+ÊPùy¿à•¿´™9üþÆ Sÿ•õýáÿäØLŽŽ‰Œ'k¦¥uy6¶‹èî~1Æ\7™ã3I×ÃQr‹Q³ºè’êÏ1°<úÓZöQÿ­ý¥qÍÇÁì?©ÿò¾˜à”ß´‘ëqðK×þFSÿ•õöËŽx{®6ù7ÿ"|¢àÌï®ýñÿ14OxnïÆ^ñÍÞ»¥ç†­¬–ãE6× uu5”ibU1yrã%žDd̘FÚ»íZülѼMð×Cð>¯ukk£]i’›Ë´²&]3Q—2Á+0C$‘ªI´ª–g€\b«éi/ùøø%ÿ…©ÿÊú?áÔ¿´‘?ññðKÿ +Sÿ•õâO:áYÛ›½ÛrïîòórÛÜû<Í«Ýè¯tzô²^!§~L5®¬õ^ò÷o{ªVv¶÷ÓÇB9ƒq‘œ~i+Ø¿áÔß´—üü|ÿ‡Tÿå}ðêoÚKþ~> áCªò¾½Ïõç‡è6ù7ÿ"y?ênuÿ@ïïÿ$xí3ÂÌã‡Âÿoˆ>ÿÓÝ•{/ü:›ö’ÿŸ‚_øPêŸü¯­ŸƒŸðI/V¿ü«øÃWøacáïøƒO×nŸGÔ¯¯oìW1ݤI¶¡óŒ±lWfÊ„n,ϸzxðŽ2.NI%-[‹²øNܳ„³ŠXÊU'‡i)E·xè“Mõ?Kh¢ŠþI?¡Š( ¿:¿à½/³XøIêmõ¼ßzm~Š×ÉÿðTØGÅÿ¶~૟êÞ±Ôü-%ìS[ëO4\Cr %ÖX£•ƒ£[ Øcà ޻·ðã2ÂåüE†ÅãgÉN<×nú^Kkõi;Åx:جª­ Õ©ƒ2È ¦ùQHÊífç)?àˆ_Ôs«|!o®³¨ÿò #ÿÁ¾>œãWø<ÿ¨Æ¥Ÿý"¯–¯žðiÑ•lÙRøSµ¬´³\š¯]|ÏjŽUŸÒöŽTœ÷}o{ßâÑÝôV슷´^™®ŸEø—'õi%Óï?8ÇöÇÁõç¶±¨çÿH«ž®gÁu"©¼u’¶Ö¾ŠÚ¾K¿+·Ë´l´4¥—ñ%Íõ{»5¯›¾ÜÖõÓ^·>V»q-ܬ§*ÎHúf¢  úÇþ‡ñì.­ðƒ>§YÔOþØÓþñõÛ'YøB:.±¨ý±5õëÄŽZ}r?ù¸C9“rt¾Ÿæ|ñû9 ~Õ_ +úÈõáüàÖÖ¿}«òûö}ÿ‚-|[ðwÇÿx‡ÄúÿÛmÃZí–µtt»ÛÛ˹~É:\¤i–Ñ'Îñ*.6+³åB7ê ?øÅÄvk˜P©—UUafÕô|Ϻ?Rà<¯‚ÂT†.­ÊëîAEWãçÝQ@Q@~müD8ÿ‚cø›þÈïþ£2Wé%~m|Eÿ”cø›þÈ•ïþ£2W½’ü5¿ÂÏ8ø¨ÿ‰øføÿ‚bøhzü²ÿÔf:ý"¯ÉOØÓöÏð¯Ã¿†º/Âï‰ÚîàÏx6ÀhÓëÏŽ‘­é–ñù6®—RâÛÙV8¤ŠVWwŽFUe`kÓí¾$~ËÃïø“öYÿÁ·†øºëÄaéã)Ò”jÆ<±KW©ÍB½L%J‘•6ù¥}ú9E~vˆÿ²·þËø6ð×ÿKÿ öVÿ¡›öXÿÁ¯†¿øºãþÅüþÞuÿkËþ|Ëî?D¨¯Îåø‘û*÷ñ/ì±ÿƒ_ ñt¿ð²?eOúeüøkÿ‹¥ýùý¼?µåÿ>e÷¢Wçü,ÙSþ†_Ùcÿ¾ÿâéñöVç&ý–?ðká¯þ.Ÿö,çô~ðþ×—üù—Ü~‰Ñ_ñöYíâoÙgÿÞÿâé¿ð±e¿ú¿eŸüxkÿ‹§ý‰ùÿ¼_ÛÿŸ2ûÑš+ó›þ/ì·ÿC7ì³ÿƒo ñt«ñöZŸþË?ø6ð×ÿOû?óþxlKþ|Ëî?F(¯ÎŸøXÿ²Ïý ß²Çþ ¼5ÿÅÑÿ öYÿ¡›öXÿÁ·†¿øº_Ø‘ÿŸñûÃûb_óæ_qú-E~sˆ¿²Öäfý–ðmá¯þ. Ÿâ'ìÁŸ“Äß²×þ ¼3ÿÅÒþÅüþÞÛÿŸ2ûÒ ++ó]þ"~̧§‰¿e¿üxgÿ‹¨Ûâ'ìÑÎe÷¤ÔWçd_?el|Þ%ý–?ðmá¯þ.Ÿÿ #öTÿ¡—öXÿÁ¯†¿øº_ØÑÿŸÑûÃû^_óæ_qú!E~wÿÂÈý•?èeý–?ðká¯þ.ƒñ#öTÇ%ý–?ðká¯þ.ìhÿÏèýáý¯/ùó/¸ý¢¿;ád~Êßô2þËø5ð×ÿGü,Ù[þ†oÙcÿ¾ÿâéÿbÇþGïíyÏ™}Çè•ùÛÿ öUÿ¡›öXÿÁ·†¿øºCñöVÇüŒß²Çþ ¼5ÿÅÑý‹ùý¼?µåÿ>e÷¢tWç%×ÄOÙm—äñ?ì´¶­á¯þ.³'ø‡û4ÿ‰ÿeÏüxgÿ‹£û?óú?xkËþ|Ëî?K¨¯ÌÁñömþFoÙwÿþÿâéÃâ'ì×ÿC7ì¹ÿƒ ÿñtbÇþGïö¼¿ç̾ãôÆŠüÏÿ…‡û6ÐÍû.àßÃ?ü]9~"~ÍXñ7ì¹ÿƒ ÿñtbÇþÇïí‰Ï™}Çéuù§ÿ öhÿ¡›ö[ÿÁ¿†øºUø‰û3çŸ~Ëø7ðÏÿGö,çô~ðþ×—üù—Ü~•׿×Ä_ùF?‰¿ì‰^ÿê3%1~"þ̸çÄ¿²ßþ ¼3ÿÅו~Ýß·Ÿƒõÿ„ÿÃ/†~ ÑžYJ¬exµ£9qêbêSŒiÉZIêÿÙ +endstream +endobj +863 0 obj +36642 +endobj +864 0 obj +<< +/Type /XObject +/Subtype /Image +/BitsPerComponent 8 +/Width 695 +/Height 540 +/ColorSpace /DeviceRGB /Filter /DCTDecode +/Length 865 0 R +>> +stream +ÿØÿàJFIF``ÿÛC  !"$"$ÿÛCÿÀ·"ÿÄ + ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ +%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ + ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ +$4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?ÎøyàÝ"×Ãúv³«éVz–©n—é±-Ä0Å*îV'Êå²±fRÁ˜€@Õ¦¢0|áf£ÃÖüj¡ øOÃöÓôŽÙÒ4kÝ[T[ZÏ, p‘ÊÑŒùj[{på^Ž;è(>^g.ääù\1¾Óš|±…¶1¿±41ËxCª:sáë1ÿ´ªÄ^Ðßþe/ +á?gÿÆ«CWÑïtXÃsk<0´î‘4ƒbÇãÇó«úõ¾¡^j· +Z;XZBª2[…¹'õ¨Âce'(%ból®8/féÔrR¿àc +hdgþ/ +ÿà‚ÏÿRÿÂ)¢Ð¥á_ü'ìÿøÕIá½~÷JðåÌ*wÔu»¤¶t´Q®žm­røöî$‘‰ j ÆW&ëY[ý#U’äk c§éB8ÈÿEŽV]ÛÄx¼}Í&1À=usò<• ¾£¿áÑ?èRð§þöüjøWDÿ¡KŸøOÙÿñªÔð©{¬ø_PÔoD±Í¡}$±ª¼IΨŒŒ¨P;çOZæ¾ëÒÞx[EÔµ/ø¢îêý¬VQ>“¼"YT’±³[ x‰ÎYˆpÃ9)N 'eÓñ BQ»¾ß¡£ÿ®‰ÿB—…ðŸ³ÿãu"xWB=|%á_üYÿñºÉ_Š6ƒ¡ØÂEpn/æŠk‰¶Mm H–gEm²H›þéc ÇoNFzÏtlôHôRmÛoÿ@ á;cÿÆi ìôð·þ¶?üfªR5?«RþU÷ ë5™–Íì=´ á;cÿÆi¿n‡þ€>ÿÂvÇÿŒÕZLSúµå_p¾±WùŸÞ[ût9ÿ…¿ð±ÿã4¿m‹þ€>ÿÂvÇÿŒÕLf–«QþU÷ ë5™–¾Ûý|-ÿ„íÿ£í±ÐÂßøNØÿñš«F)ýZò¯¸_Y­üÏï-}¶/úø[ÿ Ûþ3GÛaÿ …¿ð±ÿã5WGÕ©*¬Öþg÷–¾Ûý|-ÿ„íÿ£í±ÐÂßøNØÿñš­Š1GÕé*ûƒë™ý埶Åÿ@ á;cÿÆhûl?ôð·þ¶?üfªâŒQõz?ʾàúÅ_æygíÐÿÐÂßøNØÿñš>Ýý|-ÿ„íÿª¸£}^ò¯¸>±WùŸÞY7±vÐ|/ÿ„íÿ£íÑÐ ÂßøNØÿñš«ŠJ>­KùPþ³WùŸÞ[ÑÐÂßøNØÿñšrßCßAð·þ¶?üf©bphúµ/å_p}f·ó3Mo-ÏüËþÿÂvÇÿŒÓ¾Ómÿ@ á;cÿƪ„f¦Z_W¥ü«î¬ÕþfZûM·ý þÿÂvÇÿP.m¿è_ð·þ¶?üj«â—¾­KùWÜ?¬Õþg÷“›‹oúü-ÿ„íÿ¥6ßô/ø[ÿ Ûþ5UñF(úµ/å_pÖ"¯ó?¼².mè^ð¯þ¶?üj´Zÿпáoü'løÍW¢«RþU÷ë™ýåqkÿBÿ…ð±ÿãT¿hµÿ¡{ÂßøNØÿñª¬)—Õé*ûƒë™ýäÂâ×þ…ÿ +ÿá;cÿƨûE·ý ÞÿÂvÇÿT8¤¥õz_ʾàúÅ_æy?Ú-è^ð·þ¶?üj´[пá_ü'løÍCŠB(ú½/å_pþ±WùŸÞN.mè^ð¯þ¶?üj´Zÿнá_ü'løÕWÅþ¯KùWÜ5ˆ«üÏï,}¢×þ…ï +ÿá;cÿÆ©~ÑiÿB÷…ð±ÿãUZŠ>­KùP}b¯ó?¼³ö‹Oú¼+ÿ„íÿ¤ûE§ý ÞÿÂvÇÿUcIKêô¿•}ÃúÅOæykí6Ÿô/xWÿ Ûþ5J.lÿè]ð¯þ¶?üj©Iº“ÃRþU÷ b*3ûÍqdæ]ð¯þ¶?üjž'±ïáÏ +ÿá;cÿÆ«3}8IPðÔÿ•±;³Qf°?ó.xWÿ ëþ5R¤šqÿ™o¿øOYñªÉY}êd—Þ¡áéÿ*û‹XŠÙ­Ó_ øWÿ ë/þ5VàMºø_‡þåë/þ5X‘ËÏZ·ÜÔ<=>ȵ^}Ù¹¦†ÃþE_ +á?eÿƪQc¡ž¾ðŸþöüj¨ÚÏ9«ÑÉžõ›£Ñ*³î;ìý +žÿÂ~ÏÿQö þ…O +á?gÿÆ©á©Ù©ö0ìŠö³îBtýþ…O +á?gÿÆ©>Á¢ЩáOü'¬ÿøÕNM%/cÃUeÜ€ØèŸô*øSÿ ë/þ5Vô=/@¸Ö¬`›Â^h¥¹á³äÿË*†¯øoþF-7þ¾âÿÐÅDéAEè\*IÉ]‡†´ÿ/†´'„<%#>ÙäЭؘ”’ÌÑä’{šÔM;Á‡¯ƒ<ÿ„ýŸÿ¯ ±Õ5ôÓtÕŠàˆÿ³­qûµÿžûV„¯ˆ[ƒÿ~×ü+â+c%ísõ.QJ¤v=JÛGðÍíÜöºgÃo ê3[Ûý¦T·Ðtýâ<‘•FPÏÈè*:²å¥øZ+}>êçádž-¬õ-ßbž]O_=Td²¦ß3n1ó ó/?2ç’ð6®ö¾$¶ÕõíZêÖ=0ý¢ímØÏpüþíYW +¤pÛˆ½É[Ÿ}>]Rùlnn亹·U–vw‚Z6eÚGÊQ•‡\ä7„1ÿ¡s\ÿÉþL¥ÿ…Cãú5¿üÿäº_Úæ¨â?”óšB+Ñ¿áPøÇþ…Íoÿ$?ù2øT>1ÿ¡s[ÿÉþL£ûCüÃúŽ#ùO7"ŠôsðƒÆ?ô.kŸù!ÿÉ”Ÿð¨xTrq"úe׌|Ug©ÞI4º4Ö6·¦h𥌩-ä÷kg›˜¤óˆß)ò™%$DG™óå=6Šùçß~"éþðÄvzt:ü¶ ÓµÍ^ú)tfØ’Íq{Á-›}Æ'ÜYœÆB>ÿ¼_â©þxË^‡UÑ´Û³kÚ}…ºyjÏf—h&ŠãÌ"W-jÒyke‹oo+÷€ÏEy,Þ:ñÔ>;—J]ÊïGÒµ+ #S¾ ¼SOBýŸÈÛ³Êòñ·fß—n1Ž* h"¶ñƇ¦M­ZÄa·Ô^Ñæ;²©)•~wàâoSZ”P%ß„ü+yscqwá­âm>æK»)%±šÚy$ód–2W(í Þ̸%¹<ÔöþÐ-üEsâ+}L‡ZºˆCq¨¥¢-ÌÈ6á^P72ü‰Á?¾‚µ(  H|'áh5M?T‡ÃZ,wúe°´°º[ÄÖeDûrˆ0Ú¸cëK¥xOÂÚN·w®é~Ѭ5kÍÿj¾¶±Š;‰÷°wß"¨fÜÀ1ÉäŒÖÕQEqóøþÂ=BöÎ Äw¯epÖóIi¦´Ñ‡^£rñЃøŠì(®;þûúÿt¿õýwÿ¥W=ñ§þDOû‹i_úp·«§ñ¢gð³É¾œøÏ¿öÿÜ^¥E3á±ÏŒü-ÿaÿýÅêTWF3ø¬Ç ü$s–ÿòLm?ìJ‹ÿMk_YŠù>Üůµ?õ%Eÿ¦µ¯¬^7hz`wŸ©™oÿ#Mÿýy[èsÖ_ŒµKý?Ä~ +´´ŸÊ‡RÖäµ»]€ù‘ :ò`¹#ÞCd`ü¸èH:–ÿò4ßÿו·þ‡=&³¢Ú꺎‹}q$ë.z×¶á­æ·!²WdîxÇ!yÆAá=†µøË¢\è6:Ä^ñ2ǪÛ[\é0Ko Rê+4ööçË( ²[¸Œ¥ƒïŒÈŸ5oøsÇš~±âðëišž«ˆ®^æÒéb-j`û#vŽGBÌ—Ö‚U”­`x§áL7^ðÆ‘ ê÷¶w>¶²Óì®dxË-´W¶É!ÌL­0[Û•ØX˃ƚ|4ÓÄ¢øøƒÄÛË+_j©jÎîá)bŽ3࿉üQ¯Zø6üëþ,×eÔ¬bŸ^UðúÙÙZ£Ú´†[i–Ö#}£ÉE $¹I¶°×Ѽà­+Á:ö~qzÖÆÚÒIÝ_{ÛÛ¥ºÌHPw´QB¬÷JUT—-5‡„4ko‡Px +tšóE‹H]!Öi’kq’C2mùŠu+·“Æ(†Ò>4é¾#Õô+ Ù}ªk­n+ FÙo,îžym/&I–[{‡„a­X²—.äËGº|bµá¿†µOiþ 7·ºE„ÿhp'Ry$µ·žXaŒïÚ“ÝEQw‡ +ʸ5ÓX|7·‹ÄKâ-KÅ Ö5ˆå´{{»±j†oö•« ¡WKË”mÊÇeJ²«*7à ´ï +X›½OÊ𽽕‘ócÝ"Cqep¦O“–/a;vðÏÀ$‡[ø©£è¾›WÕ4»Û­u%Ó/,.ï¬-¥¶¡ª´“\¤˜š7Är¹ÃŽ2®O‹šN£s³Cðïˆ5x'–4û›u¶Ž;ù¥³ŽõbŒM2:°¶ÊL«þí—q}ªÚzÃÛ9µûïéšöµ¢ë—/3ÞYýÙെHUfŠDØÂÊݲT¸d8`¬TÃá?†† Ò`°»Ôä]*öØ Ò!,ñicLPØA•òT1Æ>~s·å  Èþ8xéš®¡çÿhýb¸ó v‘½ºýžIå·¬ÐüÉ "ùŸ3.É6z-ŒÒ\ØÁq5¤ÖrK»ÛÎPÉ #%£2îÖaÇŽkŒð¿ÃM;ÃKam£øƒÄÚu´v‹=ŠOÇ{%´A²¸ŒJdHÝ#o/ „4»;d¶±··šîkÉ"‰Qî'$˜‚ìUC§j¨ç€bŠ( ¼ÓÃþ!‡Ãíâ?ô ÝJöÿÅ“ÚØØÚyb[™~̲²«Jéâ8¥|»¨Â2ÅTú]y§‡ü=ˆÄy¿½ÓolhË*Åy©ˆž[Ž/2=%–¡-õ¼1Ÿ,Jó‚v‰WiˆiñC@¹…³ÔÒ[y, ¸£0Íw¨K§ˆŽ£¸‚PåI\ ÈÒ+™¾ø¡=6öö~ Òü3ªYyö·B;6Ÿ›¨é[K.ò$En˜8‘cp“z›:OÈàñÒêW0Â4›9.®`Oµ¼’jlY.cˆÖgŸÈV3cÎóG\±Â=&;½-¤ñˆ'±Ñㆠ&ÂF¶ØÃÕ¥ÊDŒ°‰CY@™‘ݶ†ù·Ô?ƒûØ.ƒ¨¸_³Q— Ç™´RmrK"ð³dø_ ¾áí3íšš¯‡t…Ó4é„‘ù‰²KIb¾M­*Ic ‡æ Œ§Ãj¿ß_Õ|;/ƒõ/"Îk•µÔ`Ýms¶_í]"¾lM,m›{é9ŽFÍç˜OEð‡4ÿ_ZÛÁ¦jv1j-¨é7K—©Z)Œâ #2/ïà;fXß÷£åÈp´îþi×÷zuö¯âjwÖ2 EÍÄñfR.¬®@(±¬h¡´ølj€ƒ! »—©¼9ðúÏB¸´–Ï]Ö]4ëe±Òb—ìåtë/2'{Xñ.޶ð¡iL’O•Õ‹1Æ“ãgƒÿá'Ô¼;kî¡eö¸â‚ÊKy®/.-RG–Þ;e—íÿs(V’4F(6¹ßsÄ?|¤[Çp·n‚ææXlgŽúÎ{äŠ8ZY ¸¸ž8dDiÒ"ïÞ²¤FälÉðþø™ÁkâŸiö¿l’+++¨áKK‹¯0Ëq‹š_|ÒÈGtWpʃd{!_†zEŒÂo jºŸ†%ŠYM§öZ[¬á™ [à °¼I½´s6w˜]ƒìY¡j–æ‰a­éSý¢ÃP¶ŽêÖ]Œ¾dR(dm¬R¯U{ hì¬`³…§xàbFšg–B`w%½Y‰'©$ÕŠ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š*ÿÙ?ëš6©ªÿÙ?ëš6 ý¤¦ò/¼<ø0]ÿ}A^9&¥1?(½cö¥‘RëÃ[˜.c»ÇçyGh¨Õ- ë¸ 0@îtcÀïž kôÎ?ìúnK]6|vmÍõ©[Ëò=öo•¤ø£pIÿ˜=ÇþŽ·¯¤=+æÏÙ¥•¾'\m`âO?CÿM­ëé/Jù%·ö„­åùîQþê¾fo†¿ä/ý]ÿéD•Ï|jÿ‘þâÚ_þœ-ë¡ð×üƒ¥ÿ¯ë¿ý(’¹ï?ò"Ü[KÿÓ…½x”þ4z3øYä? ¿äuð·ý‡ÿ÷©ÑKðÌcƾÿ°ÿþâõ:+£üVsá?†Œ;eÿ‹[jêJ‹ÿMk_Vö¯•­—þ-E¡ÿ©*/ý5­}SÚ¯´= ð[ÏÔÌ·ÿ‘¦ÿþ¼­¿ô9ëN³-ÿäi¿ÿ¯+oýzÓ®¼(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š*ºÚZ.vÚÂ2ÅŽ#’rOÔžjÅÙm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàQö[où÷‡þø5Ùm¿çÞûàS£Š8ó寉ž»F3RQ@5JÖ­–×XÓ,µ÷¬WP,ªÀŒàž}ÍdÿÂàoú<;ÿ‚Èøšé1JjãRqÑ6ˆp‹Õ£/DÐ4-ÎþÅÑ´í7ÎÛæý’Õ!ó1œnÚq“×ÔÖ¥%-K““»)$•‘™á¯ùKÿ_×úQ%sß?äEÿ¸¶•ÿ§ zè|5ÿ éëúïÿJ$®ã?üˆß÷Ò¿ôáoUOãDÏág‘ü8ñ§…¿ì?ÿ¸½JŠ“áêãÆžÿ°ÿþâõ*+£üVc„þ1­“þ-£Ô•þ›¾¤ô¯˜íS?­þ¤˜¿ôصôåV-éCÅ?S2ßþF›ÿúò¶ÿÐç¤ñ½¦xzÅ.õ9gU’Q 1[ÛIq<îAm‘ô’0Uf!TáU˜üªH[ùoÿëÊÛÿCž¹ï‰«5½ÿ„5ϱÞÜÙhúÛÝ_}ŽÖK™c‰ì/ VX¢V‘ÿylè®ß8¶¹¶XöÌŽÂ˾€>™ªö÷v·3\Ãos ²ZÊ"¸D1…Ê+…p>ëltļ¡ä>¿ñâxõD²ñÿ„Ûí4‹Y⺚îW‘4æ„L—¾LÍ¢k­¨ŠytãÍÏÙ¿KÖôý+R»ñ4ÌZƧm¤]L×ï1óÒ­af`çh›Ï†ádKò¡”ÆHYá_ˆ¾ñ4ÖQéW˜]B/2ÆkÍîΰSxÉxKX¾ºñ½¬hž†çLðíùµ³ŽÞôX˜„A–‘X,’Cûæp»É`YCOÂ:o‰nüe¤ÇwsâmWúF·§êæm/X±x¦’ÛRñöÙ¥¹‘7µˆ+˜‚9,оs0¿hZ¥†¹¢XkzTÿh°Ô-£ºµ—c/™ŠkFTƒ‚«Õóž“áïh¾ø}¥iþ3µ›PÑ4Á«È»Ùì%ŠûIEEÇoåÛÉx¬›‘#v˜JUš¶|Y‰,ãÔü6$ñ5®i­±°Õ6júÂÆ,­aÿCž;¹‘æžðù¯#F†,Œ˜Â{à Ós»œÕÚ+Í´ #Pñ«âIçñoˆì’ÓYšÖm.•cT +Œ8dcÕÏJôšñ»¿¶y:¾?¶¿±¿á5Ÿûsû#íkû/ØŽÍŸfÿHÿ³gÊù¶çwɾ€:mgÃPhöqÝê?¼c2\Áj­ö¤lË<É KòÄ~ô’"ç ÎNM]ÿ„ú¼cÿ±ñª­¦èºgˆü%y¢ÜIâÈEÕŠ¬SêFE¹·ˆM1µš6pU.#Àuvh]°4ÿ¼¸mA—­è~øuâi Ö®uVÓlôïCtóOy2Ü„c$›Érð\¾ï¶Ã —{W+€ðskÚç€|&Úßî!Ô4Ý$øšæêëSW’âKí;/o,ì!€êÞÕ‚lÁs,Ð°ßøE,,n/¯¾"xªÖÒÚ&šyæÔ!HâEff1áTI'¥Oÿ4ÿô=xÇÿbÿãUæ7Òüa®iþ"Ñ4øi.Ù·ÚÃý®6ºWsywwžK(Vkψ~*¶‰¥Ž%yuP$pˆ ˜þó;*Ü&§ÿ„ú¼cÿ±ñªó 4½KXð v—Ðxþ}r?컯¬¯x¶ââ ëI®Zй ½DwMÓþBOÙÅ-Í·Å?øIüKq¥ë:ÏöÿüMþÉeý•söO'dãOÿHžãû?þ|Û÷0ù»¾Y8ûCPiw§éV¾'·ðÌÿ|bš­Ç•å[ùêwy‰s"|£+gry?òÏý¥ÍÝ?ÃPjš•¥§ÄË6™r¶·‹ö¤\¦æ “?»š6ÈÈù±Ô8­ Ã1k$ñeç„!ñ5¼ðiºMÆ}âUÔÐF ¯ßËó/A›Ée‘#•bëò(Áv©´ëM~ëQ×|qakâÍ6âûÅ:$ÖzlñÉKYíô¸®ÚXå‘„Fds'˜±§–Êì@:ýgÃPhöqÝê?¼c2\Áj­ö¤lË<É KòÄ~ô’"ç ÎNM† ×4K oJø…ã‹ BÚ;«Y~Ô‰æE"†FÚÑ2¤ y_‡tψvƒ[Ô5ýJ÷íÚ4ÚÝ›è×Ñà âjÖ2HÉ-ÅÄ‘º¢­ÉÍ”iÐÌÛTB*çÛOØh>±ºµñe¯ˆ-¢Ð!Ó`Ý¥ŒZbÛY åGú*ÊÔ'ýð;6säЪÿ ?ý^1ÿÀØ¿øÕðƒOÿC׌ð6/þ5\ŃãWÅ6wš¯â +N—H·—E[]þyùžS ‘"žâ`¿dùuaä‚ óKÄ+ñ!ç×’ÂoA§´·cI—ʸ–d¶þÔ·þÐk¤VVfùŸb[vYM¶ð„I´Ð¤ÿ ?ý^1ÿÀØ¿øÕðƒOÿC׌ð6/þ5U~ +Á«Áák¤Õ5=OQ„ß1±–ÿO¹´Cå¦T%ÜÒÝó<ßšv ’B(FOw@wü ÓÿÐõãü ‹ÿQÿ4ÿô=xÇÿbÿãUØÑ@wü ÓÿÐõãü ‹ÿQÿ4ÿô=xÇÿbÿãUØÑ@wü ÓÿÐõãü ‹ÿQÿ4ÿô=xÇÿbÿãUØÑ@wü ÓÿÐõãü ‹ÿQÿ4ÿô=xÇÿbÿãUØÑ@wü ÓÿÐõãü ‹ÿQÿ4ÿô=xÇÿbÿãUØÑ@wü ÓÿÐõãü ‹ÿQÿ4ÿô=xÇÿbÿãUØÑ@wü ÓÿÐõãü ‹ÿQÿ4ÿô=xÇÿbÿãUØÑ@wü ÓÿÐõãü ‹ÿQÿ4ÿô=xÇÿbÿãUØÑ@wü ÓÿÐõãü ‹ÿQÿ4ÿô=xÇÿbÿãUØÑ@wü ÓÿÐõãü ‹ÿQÿ4ÿô=xÇÿbÿãUØÑ@wü ÓÿÐõãü ‹ÿQÿ4ÿô=xÇÿbÿãUØÑ@wü ÓÿÐõãü ‹ÿQÿ4ÿô=xÇÿbÿãUØÑ@wü ÓÿÐõãü ‹ÿQÿ4ÿô=xÇÿbÿãUØÑ@wü ÓÿÐõãü ‹ÿQÿ4ÿô=xÇÿbÿãUØÑ@wü ÓÿÐõãü ‹ÿQÿ4ÿô=xÇÿbÿãUØÑ@wü ÓÿÐõãü ‹ÿQÿ4ÿô=xÇÿbÿãUØÑ@wü ÓÿÐõãü ‹ÿQÿ4ÿô=xÇÿbÿãUØÑ@wü ÓÿÐõãü ‹ÿQÿ4ÿô=xÇÿbÿãUØÑ@wü ÓÿÐõãü ‹ÿQÿ4ÿô=xÇÿbÿãUØÑ@wü ÓÿÐõãü ‹ÿQÿ4ÿô=xÇÿbÿãUØÑ@wü ÓÿÐõãü ‹ÿQÿ4ÿô=xÇÿbÿãUØÑ@wü ÓÿÐõãü ‹ÿV¿†´‡ÑÍÅ»êú®¨_k‰/ç2õ +ãÓ<õ骅ãöOúæŸÍ¨ξ6x§Yðóé6úMð±ûJÏ$’ˆ‘Üùf0o|ÂOàr9Ï™Éñ;Åêxñ=ÁúZ[ñºê?j)uáÌwŽì~°W‹WèYY†¯…JM»ô]Ùòy¦.­sÿP{ýo_IWËñ +t1Ò…5e¦Þ‡·•Ô•L2”Þ¦o†¿ä/ý]ÿéD•Ïüfÿ‘Ø_JÿÓ…½tÿt¿õýwÿ¥VÆN|¿öÒ¿ôáo^E?ÓøYå~\xÏŸöÿÜ^¥EMàÅÛã/ ÿØÀôשQ[âõªÌpŸÃFU¢Å’´?õ$Åÿ¦Ñ_JŠùÎÉ?âÄZ7ýIÿé´WÑ‚ž%ÝGÐϬåêf[ÿÈÓÿ^Vßúõ§Y–ÿò4ßÿו·þ‡=i×!Ú^òÒÖú%†òÚˆ–XæT•€ñ¸t`ñ+ª°=Š‚9bŠ(¢Š(¢Š(¢Š(¢Š(¢Š+Ÿð¾w¢Ë¬;<3hêrÞ€¯–UBôäáüqÛ' ¢€"Ýsÿ,ü>:‡N1ë ¦\X´›\Û‰‘Ñöîw)ÎQpsëÁÈ#‹o‚û3;|E³3¹'Nl–qµÏúþ¬8>¢½¸ÒסC6Åáéªtçd¼—_TrUÁP«.yGSÍ>|,ÿ„+^¸Önuã©Ï%±¶‰RÐ@ˆ¬ÊÌOÌÅŽQqÈÇ=r1éTf\¸œM\MGR«¼™µ*0£X+#7Ã_ò—þ¿nÿô¢JÁøÇÿ"RÿØcJÿÓ…½oxkþAÒÿ×õßþ”IX_9ðbúŒi_úp·¬éüH©ü,ó_ +©_x@úëçÿMz•gBMž1ðw¿ˆÿMz¾+ZŒÇ¥4fاücõ£Ôþ›E}^ `Ÿñ޶­ù‘ãÿÓp¯y¥]ÝDXeg#2ßþF›ÿúò¶ÿÐç­:Ì·ÿ‘¦ÿþ¼­¿ô9éu™gW±µ‚w·7w&•K »ü»ÊÈ<õçQ¥Ed^ßÀKr÷`˱Þ[gæ,È„ðzcŒppMeǯ<ÚÉÛw+XÈëäùq®Ho±ìûÃ8ÌÍžøcÜ utV%·ˆì浊ãìב¬ñ,–ÂDϹ‘p¼ðwH‹–À;² _š‹íZWðþ³s ÙÝXÅ(Û0BUÄBE?)e# ´·EsPêsÚHeó5]B×j£ý¢Ñ`q+H‰¦åŒw6zãhäw½.½i HóÅÇÿdI·g8þËS×ë_UŽ•¦*”©¨ßª1ÁÖW;tv3-ÿäi¿ÿ¯+oýz±¨Y­âEûé`–<È¥näm¥ISò³AëëƒUíÿäi¿ÿ¯+oýzÓ®C¸Ëm ·—(Ôï–í7´æ2å[nWiR€|‰ÑGÝÏvÍko ØAäìšäù^^ܲó³ÈÇðÿÓ²~míÚ(ïCŒiö°Úî’[+q¿™6ÁÃDÁ‹o˜”Ž0zƒE†‘9Òu]Nåå“QfóYYIPcXø`Š Âçñ“·EW¾µŽò†Vu ,råzå\~QY×Z$À´³ÄÞkÇi$bH1Ü«¼g{÷ n8 lÑ@þ•£^hÿhê·M,èÈbQ"¸VUå„iÇ‡'8¯‡mĽ¼x­•RÞ)¶%Y#p …ÜFbAóqžsÍmÑ@°é0ÃUx  ú<×iEyÊxêÅwìðç‰×{o|i Í€2}N…YøDe”ø’òK;»T»Õšx–ê‰ÊÓ­îü+½¢€<ãâýå¾™©è÷÷² {_³Ý@f~HÏnʹé’ÈìŸJâÛÅ~Üâ{ ltéü?ÅÜþ^õïtPŽ|$¾‡Vø„÷v-͵¾—4rI*ŒòÀUXö$#c×iô¯c¢ŠÌð×üƒ¥ÿ¯ë¿ý(’±~,ÿÈ¥ý†´Ÿý8ÛV׆¿ä/ý]ÿéD•Ï|i‘¡ð™5m-—ê5 zºjòDMÚ,çî×o‹ü ÿc ÿé¯Q¢¼ïá_Šõx×Ã+ªL’ }xö¦ÜnÒõ<ÿ!Eo‹¥*u\Y†¬jSæG+mÿ"}§ý‰ðÿé­kì_ Zø£­?ìO‡ÿMk__ŠéÌv§èpå[Õÿ›oÿ#Mÿýy[èsÖf[ÿÈÓÿ^VßúõˆußìcÚÙ|ïí­Iì7ù›|¶—ñƒ»þ=ö㿜ñƒæÁµEbj¾#ÒôkAõ½[FÓ,,­­ç–{Ach¼Ù$@eVF„ TrÇ{o\ Ÿ2Üø³ÂÖßÙiñ.öÖßì¯2ú5û~í»|Œ·ïs½1·9Þ¾¢€6¨¬»/躳izæ™s¨¬RLÖ‘]ÆóŽS ¶ÀwmYU£'2•<ŒU+ø2çÃ×>#·ñ‡æÑme\j)©BÖйۄiCmVùÓ‚‰}Et4U7VÒµ ŸÙÚ•æûh®×ì󬛠—w•(Ú~ãì}­Ñ¶¶:½@Q@Q@Q@fË®hÊðͬiÑÉtk”HêÏZÒ¯'Ó¡ðµ±ñF­âÏRgñtzz;ÙÇ4Šn$¶‚>_øCÌ ç¸€OÑá!Ð?è9¦àZðèôÓ?ð-?ƪÂàïúôüEÿÄ×1§Ÿ‡WÞ;»ðt^ Ó–þÓÏó$m.ßÊ>LV2¶_»¨BUúawv_ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâhÿ„/Áßô)è?ø.‹ÿ‰  ðèôÓ?ð-?ÆøHtúiŸøŸãU?á ðwý +zþ ¢ÿâk>ãÁ¾HáÑÏøòŒ6¯ ÷  ¿øHtúiŸøŸãVlu òÿa¾¶ºÙþLªûsÓ8éÐ×/ÿƒÿèSÑ?ð j§Â8`·¹ñe½­¼6ÐE­:G1„DQ`ÞÑEQE—á¯ùËÿ_·úQ%sŸ?äžIÿaM3ÿKíë£ð×üƒeÿ¯Û¿ý(’¹ÏŽ?òO%ÿ°ž™ÿ¥öõ¥/Ž>¦u>xÀùtû'þšõ:)¿³ógÆúý‡SÿMzÝš¼¿‘Å–ÿ»¯™¨ÿŠ6ÓþÄøôÖµõðé_!ÚÈ›iÿb|?úkZúðt§˜ü4ý 2êÿˆÌ·ÿ‘¦ÿþ¼­¿ô9ëâ.“¯ßÜxgRðå¾™uw¢êízö÷÷’[G*5͹DŠR…o»ÎÓÈ­»ùoÿëÊÛÿCž´ëÌ=ƒÊõ/øÒÿÆ–¾:{OŪYGfbÓ§3A+ĺ¬.­qöpʾ^¢ŽÊl´l˜‡¬ß|,Ö5½B{Ùìôcý³¦‹ NÒÓYÔ4ëK\Ü]Lîb¶+ý¡»íŒH`ÞѳžÂ?f¢€<^øEuªø9ü?Ι§É{¯ëºýÔQ,—ðj0DøÂù’¢]Û‚ˆÈ …\Ýñwƒ|WâŵÕõ=/Ãö¦Ÿ} ðÚéºÕÜ]"AuÙ5¢ŽhÔ}±™QbllpX‰Ï—êtP/ðçD¼ðÞƒ5¥”§™s˜/®.[Ïžy¥•çËÉ‚ëûælÈÌçˈak¨¢Š(¢Š(¢Š(¢Š+Èot¯øgÅšE¤SHÒxæÎi|›“o"ÃÝŒ³2Ȭ¬¬±£°*Cqòüد^¬½/EµÓõìäž6½º{¹É!·HØò8UöõÉ ñÂýRm^æÚ öOÚêW §èšD\ˆ‚KM?dÉm~ ²"ËþH (yÉPVY …þxÚ=fâi¬f¿·(¹iõ(î$Ô¢Xü<'öy­:i÷Ñ"F¯ÿ-6,•ô•'üýMù/ÿG•'üýMù/ÿ@ÂçGÓõŒèði·z—Ú4½÷Cû>³ÁG²h“tÑÏ.ØÙów30¥CåIÿ?S~KÿÄÑåIÿ?S~KÿÄÐÔT>TŸóõ7ä¿üMTŸóõ7ä¿üMMECåIÿ?S~KÿÄÑåIÿ?S~KÿÄÐÔT>TŸóõ7ä¿üMTŸóõ7ä¿üMMECåIÿ?S~KÿÄÑåIÿ?S~KÿÄÐÔT>TŸóõ7ä¿üMTŸóõ7ä¿üMMECåIÿ?S~KÿÄÑåIÿ?S~KÿÄÐÔT>TŸóõ7ä¿üMTŸóõ7ä¿üMMECåIÿ?S~KÿÄÑåIÿ?S~KÿÄÐÔT>TŸóõ7ä¿üMTŸóõ7ä¿üMMECåIÿ?S~KÿÄÑåIÿ?S~KÿÄÐÔT>TŸóõ7ä¿üMTŸóõ7ä¿üMMECåIÿ?S~KÿÄÑåIÿ?S~KÿÄÐÔT>TŸóõ7ä¿üMTŸóõ7ä¿üMMECåIÿ?S~KÿÄÑåIÿ?S~KÿÄÐÔT>TŸóõ7ä¿üMTŸóõ7ä¿üMMECåIÿ?S~KÿÄÑåIÿ?S~KÿÄÐÔT>TŸóõ7ä¿üMTŸóõ7ä¿üMMECåIÿ?S~KÿÄÑåIÿ?S~KÿÄÐÔT>TŸóõ7ä¿üMTŸóõ7ä¿üMMECåIÿ?S~KÿÄÑåIÿ?S~KÿÄÐÔT>TŸóõ7ä¿üMTŸóõ7ä¿üMMECåIÿ?S~KÿÄÑåIÿ?S~KÿÄÐÔT>TŸóõ7ä¿üMTŸóõ7ä¿üMMECåIÿ?S~KÿÄÑåIÿ?S~KÿÄÐÔT>TŸóõ7ä¿üMTŸóõ7ä¿üMMECåIÿ?S~KÿÄÑåIÿ?S~KÿÄÐÔT>TŸóõ7ä¿üMTŸóõ7ä¿üMMXú½­­õ½Ýí´7V·âšý5­}v: +yÃOÐÇ)Þ¯øŒÛùoÿëÊÛÿCž´ë2ßþF›ÿúò¶ÿÐç­:ó`(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢¼óIkú¦¼Ö^+·Ó­¬5Yl≴´˜íUFvåþþ:vë@‡Eqߨ^>ÿ¡úÓÿIÿÇ(þÂñ÷ýÖŸø"Oþ9@Çaxûþ‡ëOü'ÿ£û Çßô?Zà‰?øåv4Wý…ãïú­?ðDŸürì/Ðýiÿ‚$ÿã”ØÑ\wö¿è~´ÿÁñÊ?°¼}ÿCõ§þ“ÿŽPcEqߨ^>ÿ¡úÓÿIÿÇ(þÂñ÷ýÖŸø"Oþ9@Çaxûþ‡ëOü'ÿ£û Çßô?Zà‰?øåv4Wý…ãïú­?ðDŸürì/Ðýiÿ‚$ÿã”ØÑ\wö¿è~´ÿÁñÊ?°¼}ÿCõ§þ“ÿŽPcEqߨ^>ÿ¡úÓÿIÿÇ(þÂñ÷ýÖŸø"Oþ9@Çaxûþ‡ëOü'ÿ¨®4Äo,‰cŽtEpOüôö ڊ࿳~ Ðù§à”ñUSíž/Ò¼Yáý?RñL„ËÆñæ¬$*FÏ÷‰=HОEzEQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@žÿtßõûwÿ¥W5ñËþIÜßöÓô¾Þº_ È:oúý»ÿÒ‰+šøåÿ$îoû é¿ú_oZQøãêgWàgÎß³:Ñ?ì:ŸúlÕ(¥ýœÆûXÓî-^Öî{»+­à¹µžËVÝnðÜ–Ȱs!]·gîþX{[W¾Šùíak¸bxbœ 2"9Rê­Ô+Бßbú +ÌÒ<'ámLm+HðÖ‹§Ø”»6¶¶1Å%تz´qÝAEôäþø¯ã»Ý"ËSÔ|7eamâk9ôW¸òWÈûUÝ¥º‰w$·h‚õŸe¯úµRÌ<³âOˆ¼S¦ÝÞǨj^Õÿ²|%â;JÊ;iZÎÿʆÂH£žØÊ|—xYåÝ1|ìGë6Þðµ·ö¿Ù¼5£Cýµ»ûW˱~ß»vï? ûÜï|îÎw·©¤Â~DƒBÃ:2i6þo“b¶1‹x¼Åt“l{v®å–UlDŽÞ4æ~1ø›â­Ãz—Š¡‹F–Áîu½>ÂÅíeó`ŸO†ùÄÒÍæí•´öýÚÇQ0ùÎÌ¿sá o_ŸÅ:¿‡øã¹¼7ã)áÒ?³t?³kÚu…úK Ã=œ7`Mßj2ÊåíXùkm@Å·°‹tžâºN–º]¶”ºe’ØZy?gµ/•’ÊÑlLm]…®>éUÆ0*hþ"¹ñ¾‡¦C­]D!¸ÔRÑædp¯(™~DàŸá_A@Y¤k)ð_}3h×VźMøH%I®§º²Òí‹Ä7•·HÚE“ f. LÇ·{,?¼U‘áÛû˜tY?á0Óm¯´¤ŽÖDþËóîì-Õ'&Sö­¿Ú(į‘»Èa…óÔ­X¾🅼;·þÿ hÚFß3oØlbƒg—æ}Å{Ê‹w¯–™û£TW“¾Ÿý©áoØ}¶Ê×Îñb —’ùp^bKSö9Ÿ’ãgo•ò&#cýÆõŠäü9 ÉooâkMgN†òÏXÔî&08I#’ lŠÜÁNW‘ƒÏq@q7muámÃ>Ѽ;ªéž7’Òk(®d›L¶–Mæo22PE2HbT„<¾`Êï3ÿ⿎Þ[¸´ Ù^ÿ`[O>³?îc·ŸÊ½½µ'Ìžî±£}‚Gß‹‚NAòó/¬éš&‰¥ØØXé¾²±´Ó¤i¬`·µ†8í]ƒ†hÕxF"I#ÞßÞ5 ߆<3yqcswá .â}>æK»)%²šÚy$ód–2~ã´ƒ{0Á-Éæ€<çà'ü”ÿÛ_ý?ëõìÕ™§éÚvŸq=͆‡¤÷󤆑¤Ì’JwyýäÒ¿?Å#ž¬swÍ“þ}fü×ÿŠ  ¨¨|Ù?çÖoÍøª<Ù?çÖoÍøªšŠ‡Í“þ}fü×ÿŠ£Í“þ}fü×ÿŠ  ¨¨|Ù?çÖoÍøª<Ù?çÖoÍøªšŠ‡Í“þ}fü×ÿŠ£Í“þ}fü×ÿŠ  ¨¨|Ù?çÖoÍøª<Ù?çÖoÍøªšŠ‡Í“þ}fü×ÿŠ£Í“þ}fü×ÿŠ  ¨¨|Ù?çÖoÍøª<Ù?çÖoÍøªš«_ôýæÿПæÉÿ>³~kÿÅV_‰_]{þÁ°µ’ìIÿ/³lŒ.'å Iç§^0@<ŸâγñÓIñ–•iðÿCð®±¢j’,>u䬚{…Ë4ì³c³UÿcnížgS­­ÒxËÀI}43]-Äây!ˆÇ¿ÙÛs*bªNp¥›§­YÙñ?þžÿÀ¹¿øš†ßDñ¶¡âÍ SÖítXm´Ùäý’æFsº6NŒ¾¤wõ F¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(3Ã_ò›þ¿nÿô¢Jæ¾8ÿÉ;›þÂzgþ—Û×Ká¯ùMÿ_·úQ%s?äžKÿa=3ÿKà­(üqõ3«ð3çÙÔÅs¡ÿØu?ôÙ©ÑNýøñ·ÿaÔÿÓf©Ewf¿ï/åù9oûºù“Ùø¢¬ýJÿé­këNß…|›f?∲?õ'Ãÿ¦Å¯¬»~f? ?C,«z¿â3mÿäi¿ÿ¯+oýzÓ¬ËùoÿëÊÛÿCž´ëÍ=p¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(3Ã_ò›þ¿nÿô¢Jæþ8É<—þÂzgþ—Û×Iá¯ùMÿ_·úQ%sÿäžKÿa=3ÿKíëJ?}Lêü ùóözñÖ…ÿaÔÿÓf§E;ö}ñÎ…ÿaÔÿÓf§Ewæ¿ï/äpå¿îëæX²ñCYØŸþ›¾¯«å+ÿ%‘ÿ©>ý6-}Z;TæSô2Êþ*¿â3mÿäi¿ÿ¯+oýz»wq¥¬×S¾ÈaF’FÁ;T “ǵR·ÿ‘¦ÿþ¼­¿ô9èñ_üŠÚ¿ýxÍÿ 5yÇ®ImªÚÜΰÇðfèd±š5õå™@pþÖ5—ñä¶šî¿©ØÝÉ}w z=Α·N–ÝZCnmnüµßpФS2ùÒàyãÊM¿¹ôzæ#ð|?ð“Á­]kšÍì6—2^Xé×2Æöö—#£H³Î?,Ó(G‘‘D„*¨XÂpÞ øÉ§[ü/Ðõ¿G©ÚÝM Zß}²ê­ãÔä?gŠf‹,¢%0¦é„1Ÿ4:±ˆš¯Å÷×õ_ËàýKȳšåmu7[\í—ûWFˆ¯›KfÞúNc‘€óy湓á~‚ú7‡´Ï¶jj¾ÒLÓ¦Gæ&É-%Švù6´©%Œ 26˜22œQwðÓN¿»Ó¯µxƒS¾±J.n'‹2‘uerEcE §À»cT ܽfx‹â/ü"ßµ-'ÄyO Á|·{w}žéMü²&ÄS#o·´•ó«öm n¢|eCð•©xúßìÚþ§©jÑ;íöPý-¯¥‰£óç’Êømï÷‚°Ë躄4}G]¼Ö/’i庋NFˆÉ¶5672ÜÛºíÃnÊIÉ íQŒnÝ™'Ãë8’ÞM#^Ö´{û{Bhïí~Îò„¾ºûMÄ;f‰ãØevo5¹mÀcüY¿¿×¬¦Ò,oot9ɦÃolÖ·¾VçúA’&”îy™Ë’?‘WnÖËžšßáõ¿‰ìuxuíelì5+RÛH͹´Žêá'Y¤Ýåyçq¹ö™J†~Pªü=³Ö/5cý½¬Øéºçü†´»o³˜5 İ>öxšTÝ qÆ|©#À\®Ö%ˆqñÎßÄ÷ÚDÚ²¶v•¶—s«âÜÚGup41íó|ó¸ÜÀ›„EC?$(fÏ‚~+>¥¡è—𖓬Ëâ cDÓ.¢Ñ­RØG4· y&è¥ÂîŽÒišPi‘™Í¿ÃÛ›xƒWÕµë×Ò¯õ»]R "$@ïomh±É+¼àë5°}©(B2]IÂÓì²iº¾³au§ÛZÚéw1<,ö[}­bXÃÆÊø†öhs*ÈJm'÷ƒÌ Ëñ@FºFñ®cöýZD¶C› +OsÁ•÷í- –’†H˳ãtBU W¤Ñü[g©ëº¶—›«F4ÇxÞåí³® ˆ’èÀIU•PÊ®/1>zÈá~‚š7ˆt϶jl¾"ÒLÔf2Gæ>ù.å–uù6¬¯%ôìp6”**ŒVΑá[]7Å7þ!]GS¹žò/%a¸˜4p&ö¢¡Ýw»2‰Yü ì±yh̤÷öå—üñÔÿðYqÿÄQý¹eÿüЊ*kˆ®c2@û‘]ã'|ÊÅXsèA©¨¢«ÜÝGo=¬N¬ZæSÐŒüûaéEõÔvp¬Ò«°ic‹ ×.êƒðË +±EWŽê6Ô&² +þdQ$¬{åÀü~Cùб@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@UoVÒô=.mS[ÔìôË6ù·Ws¬1G¹‚®çbÉ sÜŠ½EQÑ5m/\ÒáÕ4MNÏS°Ÿw•ui:Í›X«mu$GÁ«ÔQUìîío¡i¬îa¹‰e’xœ8”u$º²‘Ø‚"¬PEPEW¼»µ±…f¼¹†Ú&–8Uåp€¼ŽüLìªr@šÍñ7‹<+ásoÿ 7‰tmí;¾Ïý£}¿›·¶ïa»—8é‘ë@TU{{»[™®a·¹†Y-e\"HÂå¸u¶:6fSЊ±@]îíRú+º…næ‰æŠàHè…C²¯Rªd@Omëê*ÅQEWs7‹5kºN•âH4«]:+WU}9g,eV'ËŒ÷ëW?°¼}ÿCõ§þ“ÿŽPcEqߨ^>ÿ¡úÓÿIÿÇ(þÂñ÷ýÖŸø"Oþ9@Çaxûþ‡ëOü'ÿ£û Çßô?Zà‰?øåv4Wý…ãïú­?ðDŸürì/Ðýiÿ‚$ÿã”ØÑ\wö¿è~´ÿÁñÊ?°¼}ÿCõ§þ“ÿŽPcEqߨ^>ÿ¡úÓÿIÿÇ(þÂñ÷ýÖŸø"Oþ9@Çaxûþ‡ëOü'ÿ£û Çßô?Zà‰?øåv4Wý…ãïú­?ðDŸürì/Ðýiÿ‚$ÿã”ØÑ\wö¿è~´ÿÁñÊ?°¼}ÿCõ§þ“ÿŽPcEqߨ^>ÿ¡úÓÿIÿÇ(þÂñ÷ýÖŸø"Oþ9@ÅO¢øþ8÷Y“¸(CAÔãþzUì߈ô>ißø%üUw´W˜k÷>7Ð’Æ{¯[]Çs¨Ahc‹JXÛ8Rw8ÀÏcÎ+Óè3Ä¿ò‹þ¿­?ô¢:Ó¬ÏÿÈ:/úþ´ÿÒˆëN€3<5ÿ é¿ëöïÿJ$®sãwü“éì'¦é}½t~ÿtßõûwÿ¥W9ñ·þIôŸöÓ?ô¾Þ´£ñÇÔηðÙà_?äyÐ?ì:ŸúkÔè¥ø ÿ#ƃÿaäÿÓf§Ewæ¿ï/åùgûºù—,ü[Û#ÿR|?úmZú—Ò¾\ÓÇü[»/ûáÿÓj×Ô~•ý©ú–oSüFm¿ü7ÿõåmÿ¡ÏGŠÿäVÕÿëÆoý¨·ÿ‘¦ÿþ¼­¿ô9èñ_üŠÚ¿ýxÍÿ 5yç¬i×-ñZÂóTø}«iú}»Ü]\D©iÕ‰uÿ9í]M‘µÿç”ß÷í¿Â¯éà­ª†VS–àŒ¼jʼn µÊkjðYÏkší;ý§t¡ ÷SwÊåŠ1;ÿ1Ï͇¡ê+ ÙYA`Þm¥™Ž¶[}ÉqÈg-'*¬B2²a¹bØ8®ÞŠçtÍ!íõKkÉ,âÊÏ|ÌÃnåie ’ß ·?{æÎ"Ö´ûû~¸íefŽx<©áXXC);7ïsþ³„ùH*;µtôP%þs>¯u{T™-á6r;|¾r™Á :íÛ&ã‘‘‹6%®›Ñ]3C§A^ôy”ÌYÃê¿4Yo“Ùkµ¢€9VÐgi<¿)Q&¸ºK¦P¸’¤YKuÉ%PEê7dp£(ºMà\êv?ÚÊòIç[í‹æp±F“mv ÊÄÍ×+æíõ5ÕÑ@|¦1+íº7Q™¯²Î«eåî'!ˆó ¡¾bA^µµ{o<Ú1Ed°I°¸·F\b)U¶¡à`„ùs·¨ÎÞq­EsóÚÝ_Fæ]>x–{x`<±‰cHÌx,„ü+16æ³/´;éÍ»=¬êº¤)lðâÚMîKf@Æ!†Oõ[ŠíÀݵ3ÙÑ@º›YÚN¯ +Å$·—61— +cާnßÐv­*( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ¼ûö¹ûÃcyý¡e§yÞ'Û/Wu½¾ÝRÔù’ É”^­ó/üËÖ½ŠðÈ|Mqcà¿ë6šõ‘›Xñ$H¾(³¸†ÏIm¶6ÀÜ,³GtCˆ>Ë–ó÷\ ¡p"¥áoˆÚ¾±ak6»ãë?ùVÒ .{8་Ä1ßÞÛ2(1¼ù-­[e ÜÜ¡<È•>€¢€<3ÂÞ$ñ‡áßIo颹ñ4¾±[s4z­âj7²²; ?œ¦<, ·tfG )ܶÐè¾0¿½ø©¦øsÃß§ñN‹-öžg»‹û6r [jóKn^…o±[gൗvkÜoí£½±žÎf#ž6‰Úž)a‚UІFôe Ž ƒYžðÆ‘áÓpÚr^É5ÎÑ5Íõü÷³º®v'›;»ìRÎU7mÜ€ 1 5§|Bñ3Xiw±x«ûBi­¬¯¼Wla¶+á‰>ß`·Î0Öè šÿp¹/"­©mêc‘ŽžâïxÛâ¥ö‡ xÊk™oÚ+›m>•â†ÛFhÌ4ev™.ça#,ŠñÈvä¤Om¢€>lºñÅï‹toÝøÅèºÞ¯ák‹Cöx£ÔâšM6âK…IU®Vin4rgÁ¬…½3QñƒáOŒÝ÷Š5Í3B´¿ðþ™œú•ÜvÑܼW•cg ; –"Àgo˜™ÆáŸG¢€<3Eº¿Ðõk~½þÎÐãñn‡ao¢1mÑ¢º´Òm›ÍWQ$~\R©Ž4t;üÀv./…¾!|AºÒ.¯µ/hÅå¶µ“W·¶¹[™ü8ÒÝÛG9t‘­Ÿ“ ·LRîIØ|Ë å¾¢€<ûZÔçñŽuá¿Íâ»TÒuˆ›[¶²Ž[”µóô“,,H ¼–2X+²iah¦ömÿOÔÖêóLסÕíä–7S ÑI¸h"uE1ºÈË(ÜXŸ7 í*¥QE暦»ÿ¾·ñCÄßeû_öN‹o}äyž_›åA;ì݃·;qœg¡ªG޼uaö‡ñ†‹eem§\ÚK¨ÊÉ 3%ÇŸ—ÈŠòäF‘Kr<òHªb\Å–ít.úÏÆþ"Ö%‡uµüv‘Á±ÆâbGÜHÏ/ô>Ù—JðdžtëBÒü!¥Øi7›þÕcmepO½B>ø× +ÙPär(̵¯‰a}ö‡m¦šõôW ;Yçºû<qwÙ%Xm‡› […Wg; OªüMñV›¤j:„ÐèÏæÿÂGo£§ÙdO:úÊímì,³æŸ:iöÎÛk>Ü"Œ[Ó5DÖ/¬/µ Øê7zlžu„÷V°Ë%«åN虲Q²Šr¸û«éTäðÅ“ø‹OÕDw‘Á§K-Í®Á²]Ëæ‰.¾U4¬·)Ë”;ËmßóP'Æí6ÞëEÐõd½Y¬¼I£yKäÑÄÛõKEo2%`’ñÓz¶ÓÊàó\Ÿ‰m-dñŠ|G%´/­i¾;Ðtû E£æÒÖ_ìŸ6¥ûÉý¢ãr) +Þt™;gØ/"‚ö†óL1¬‘Ì©*FàI‡FŸ¼®ªÀö ȪW‰qâ+oÜxjÊmjÖ3 ¾¢ö°µÌ(weRSó*üïÀ?ÄÞ¦€8ÏøÇÅZW.ôÝ&],-m´u+uc,²¼ú•ôöhûÖd"dŽB›I]éËÌØüDñU÷í´}/JðÌzµåÌzEÖ¡=¼£“&»Ë…mÅ´á*@[:HüÁ»Í_`¹Ó´ë«‰.nt8'žO#|’C3yaÉ'Ÿ.Fg_î±$`Ôhz$Ë}†lb»Y Ë:[B$LİaÎânn鼿ßl€yœÿõK? +øóS¿MÞ h’K ’H®o£½Ô¬ùøId±ˆ¬A‹)Mîpj•—Œ¾ ÚÁ¡[n_ê:߈î!•­Váílí5?!aešòÜ?3 ®².ÄTArãÔï¼3á›ï+í¾Ò´ù~u”³í;¾ÓŒôów7™ýýÇvsF·á ë–ó[ë~Òõ8&¹[¹c¼²‚e’uŒD%`ÙˈÀMÇ ”ÌxOÇ:εâ]%.Ãöšv£e  ¼ûS‹‡µ/ÝFÆ6•”ˆ +/™ }¢9X+ÄžYŸÙÚwöçöïöÚßfû'Û¼˜¾Ñänßåy™Ý³wÍ·8Ï5wÍ“þ}fü×ÿŠ  ¨¨|Ù?çÖoÍøª<Ù?çÖoÍøªšŠ‡Í“þ}fü×ÿŠ£Í“þ}fü×ÿŠ  ¨¨|Ù?çÖoÍøª<Ù?çÖoÍøªšŠ‡Í“þ}fü×ÿŠ£Í“þ}fü×ÿŠ »ÿT¿õÑ?ô!^=ñÏXøÁ EaðËCÐuûydK{«+¨$71;¶Õ•YfE1òd ˜ÜI]Å=O[“T:d¿ÙV1Éz +˜VæP‘ä0?1]ÇAÏN:×%³âý<-ÿsñ4‘â•×WÂ'›M›Yþز7§DñÛ2çlaÙ›h鸟›Âçhõzó[Cø­>Ÿ¥g CmmÓµ½Ô…ÿvሗŒúW§Pg‰äýZéDu§Yž%ÿt_õýiÿ¥ÖfxkþAÓ×íßþ”I\çÆßù'ÒØOLÿÒûzèü5ÿ é¿ëöïÿJ$®sãoü“é?ì'¦é}½iGø‘õ3­ü6x'ÀqÿÆÿaÕÿÓf§E/À¡hö_ý6jtW~kþòþ_‘Á–»¯™OñnlOýIðÿéµkê_1iÃþ-­ý‰ðÿéµkéÑQŽÚŸ¡9nõ?ÄfÛÿÈÓÿ^Vßúôx¯þEm_þ¼fÿЋùoÿëÊÛÿCžÿÈ­«ÿ׌ßúWžz¦Wñ™>kŽŒÊË•`pAÞ´ØQ_0øßÆŸ á†çþðþ£â/É«Ýh–zÔ.”Çq•yæ>nܼ6á¹r2›d1ý!¡ÙÛiÚ\V6qyVðH×$à=Ï$ûžM^¢¼—G×`ýåÌ-Ï’øsòå(­Q^qsñƒÃV:uÝþ¯e©é0Á­»òn$Šâ;YâW”FŠæháf”Ç[z»DA‹ñŸÃÚ÷Øàðþ¬ëZ…×Ú‚ÙéÍkq±íþÎdV'6Ã争Ãy»:¡a.# ›Eq ¼kÿ ÿˆ¤´·ß£ÙÜÚeߪl[¨'°¶¹VmáÁŸ'(ƒkÆX>1®þ6xBÓXÕô›˜ïZ÷K¹H 9-凜5äV…Ö+id‘6ÉÎ%vM‡h2FgSø—§éö:Ö«'‡üA.‹¤Ç|ϪCOòY‰<ø•Džb2´3 iR8Ù“Îø÷€wTW âßÉ¥|AÐ<%§é“^\^_[%ñÚ˜[{‹}AÕã-"üÈöŸ ü™Úˆ—…~(i7úV<6ž ½Ó§‹O‚çY¹ŽÙV ›¸ x"ÕŒ¯ö›|˜bh”Ì>e +û=ŠâüñJñösZiZΫ¦ÿi鯨۬_k|¡+*‡f_-¦‰Ip¡÷†ŒÈŸ=v”QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE™â_ùEÿ_ÖŸúQiÖg‰äýZéDu§@žÿtßõûwÿ¥W9ñ³þIüŸöÓ?ô¾Þº? È:oúý»ÿÒ‰+œøÙÿ$þOû éŸú_oZQþ$}Lë žð3þG}þëÿ¦ÍNŠ>ÿÈñáÿû/þšõ:+¿5ÿy/ÈàË?Ý×ÌÒÓÇü[K/ûáÿÓj×Óƒ¥|˧ÿÉ1±ÿ±>ý6­}4:Vxí¡è,·â©êf[ÿÈÓÿ^Vßúôx¯þEm_þ¼fÿЋùoÿëÊÛÿCžÿÈ­«ÿ׌ßúWêu‘âí/øvïDžw‚+µT‘Ðe‚îãßÿ]kÑ@ý§„ô[Oßx¾ÛJÓa×ïí£µº¿[lK,H~U'wû¹=X$`ä"mÜ qí,–$1Ôæ¤¢€8½áõžŸ¨I,úö³©i¿ÚSêi7gû$RÜ=ǘ6D²>Ù$fE•ÝU¶°‘I>éSÿiÙ]jºÌú£öÆ›CûBÇhïÌûCnVvÞf™¶¼¬ŠÒeUJG³´¢€9+/*jZn¥ªøŸÄÝî›}öËy¯d@?gžž\1G]·2¶à¡ØìŲ̈ª)Y|5Ó­ôë])üAâ .Â[6Òìdž! Œv·ÏH52.mâMÓ$ ++©w-ÝQ@-ßÂýäDZóSIm俞ÞE’<Ã5Þ¡ eLŽâŠp6ºÈ ­=ÁñiúÝž¹u®k:¾§mmuln/¥Œù‹pÖÌÙHÑQ6‹H‚ˆÕ—f ìÌzz(˜ð‚´¯éÿÙú5Åë[kH]'u}ïon–ë1!AÞÑE +°OÝ)UR\·?Â=&;½-¤ñˆ'±Ñㆠ&ÂF¶ØÃÕ¥ÊDŒ°‰CY@™‘ݶ†ù·ÕèôP/©ø+JÔ4éS\^¬-ó>ÞÈê=öqZ+åã÷p©ù·|ÄöàBÞ žïF¼Ò5ïxƒ^´»–‘/ÍÈäð‘¼aâ”.DpÛ²»Žzê(…ƒá¦fËý“âi14FÚâ;9âA= žibµ c-Pý¢Xãò NˆTnÊ!Y¤øw¥Oý§euªë3èÛmí  {¿3í º5YÛyšfÚò²+I•U)ÎÒŠá,>éöþ!$»ñˆ5=lKi(¾»ž"ÀÛ‹”cXÖ$VŠîx™UÃoe̦-áN‹£ÛéÖz¾³ý“gö%Óá1^\YÇ +[ÜJÞWšEµ±Û¢ÊÎÐ( cÞ +Ò´ᯱÏzÿðŽh¢Yù®§| öl´˜Q—ÿE‘´rÜr1ÓÑEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEfx—þAÑ×õ§þ”GZu™â_ùEÿ_ÖŸúQiÐ_†¿ä7ý]ÿéD•Îümÿ’~ÿöÓ?ô¾Þº/ È:oúþ»ÿÒ‰+øÛÿ$ýÿì'¦é}½iGø‘õ3«ð3ÁþÈñáÿû/þšõ:(øÿ#¾ÿaåÿÓf§Ewæ¿ï/åùgû²ùþf¶œ?âØXŸú“áÿÓj×Ó¥|Ó§É-±ÿ±>ý6­},:Vxí¡è,»â©êf[ÿÈÓÿ^Vßúôx¯þEm_þ¼fÿЋùoÿëÊÛÿCžÿÈ­«ÿ׌ßúWêu›â]f×@Ñ.µ‹å”Û[(i<µË`8iWñ¯þIf½ÿ^ãÿCZ?á?·ÿ¡SÆ?ø%–ºm*ôj|7¢ÚæØJ»„W ²EÿysÁöê;àׂx³DøÝãÿêß 5¹!Ðüo¦»»ñ‰{ý.Y ‚Â>0²€9>ê®íÀÿ¤}iþ©¿ë£ÿèF€0ìüoàËߟYø¿Ã÷ÒË$M§E©B÷!ãݽ| Û·.ÖÈÇNzWC^?ðSÄÖ£[Õü;qã I+xƒ]ú(]R7þÒ¹³1¸;ÆÀï´B¿+)ΖÆÐüoã ?Á~Õ5ÏOªOâO¶©,±Û[ÚǦÌÂ$™[ËaJ/ZYä•eUò‹¬h€Ä@=ÅîíRú+º…næ‰æŠàHè…C²¯Rªd@Omëê(·»µ¹šæ{˜e’ÖQÂ$Œ.Q\+÷[c£`öe=¯™ô?_Æšd¾(ø«¦hqé‘ë}¾¿aªéóÇx +èÓùfym’ 38ù!Œ(J»:ÛøÓÆÐÉwss¨iž—V¾ŽóXº¿½KŽÞðhÚ1[A%͵ʫ7›9ò™7Ÿ à#†ú+Äž!Ð<5b—Þ#×4ÍÕå¤÷÷io9… äØV8ö>•vÂîÖþÆÞþÆê«K˜–h'…ÃÇ*0ʲ°á”‚#­y§Œuøì,>x‡Æ:Ž™¥1ÕÖ]BâRö–ÑJú=ðl ¯—l“ 2¸¬ÍG^¹Ñü)â_H¿þËÒuÏ+èš³]CicmZÀÒÜ4³C4pÃ5ÄW!d0°–K„eÿ^²Ð³U{û»[ ‹ûë¨mm-¢i§žg H£,ÌÇ…P$ž•óß‚üe¬\{Æ:Ž­ºæo ŧ[\X\@mnM¾¯¨Z›ÿ= *Rx%–dŒD‰9‘¡Á”^)ÔüOû9üWž±¦km¥XêVPêÑÞGp‡MŽ|™¢†݃NËòĘÚ†`]€=NÃâ€u yî,U£ll2~ô€{ãö>$žç]ðÎáÏŠsx£N¼ñpÝÞÅmg+m[éÞÛíÄ *ÆÞQPL‰/‰cÛÌŸø©í<1'ˆdÑD©$jËsv†9ÜÊ~Ïòº²;¡¨®GáÕö§-ω´]OR›Tm W[(on#'ÎÚç2•#Üá”mEùUr e]@Q@u½RÇEÓ&Ôµ)ü›h¶‚B3³30TDUÙŠª¢‚ÌÌA$ +‡Ãšö™â»Ó%–9L3Eqm%¼ð8¶I ª²FÅYXQ•eaò°&—Ä+K[Ï ]Gym©ÏRÁr§MŒIsÅ2J“Ƈ>cDè²ìÚûü½¡$'cyoˆuJM+Ñø‹PñœºÞ-{h. µ¼²Õu 1¥\KûØ,ãŠa¶é]p"L¤(Ä0ýã{W¿¹ŽÊÆ{É–wŽÚWXayd!FHT@YÛÑTzM|÷¬[|J¸–Ïþ'>&Óm–Ú_øG|½*þòáßí·~GŸå\BˆâÛû??Ú[’ÛðEÆv|Oÿ ö>Ïÿ þO³k~WØþÕö³m¸û•Ÿômû>É·ì¿éf7Ëzö]/T°Õ~Ôtùüõ´¹{Y]U¶y©ê¬FkŒT®®‡ Œ:Ö»¦iÃä³›‰âšX­í­¤¸™Ò$Ý#âVm£å\ãïi[Äï4Ïi:CÙéë6w¾(Ô¼Y¤ÚÃöÙbòo®®åšÒ÷k°Ã“Iº?›÷›£GiXž›ã¦—­ÝêgTÐàÖM퇂|F,¦Óšde¼‘lÖýѰåç,›”n@TÓ4mRÃX´’ïNŸÏ†;™íY¶2âX&xe_˜òÉ®zdd`Õêù³PÒþ C¨\Ekâ ßíÚ¤Ú2Zh××F[É5‹÷, ˆaU1µ›)¾ÝÈÂùÙõ?j‰~#[¯øIšÜîm÷»–Õ~p"EVÌG Fö¤e­Ò ‘^@@ª:¦©c¥ý”^ÏåµåÊZÛF¨ÎóJÙª¨$áC3aQÛ +¬G†øßþoìÿcÿÂgÿ güO~Ùäý³ìŸ`û=ïöÙåÛÎÝý³þÿvíÜùÕèÞ8ÐZ}WáÍ¥´ZœÖšf¾%–T¹ä#ÓoUY·oe.cV.Çy}­»y¦Ð5Ý3][£¦Ë;5¤±ÃsÖÒA$.ðE:«$ЬËš2AnÚpÀrâîÖÚkhn.aŠK©LVèò38Fr¨ÞmˆíÙXô¾aд߈#C³}^ëÄÚEÏÙçÔ]]Oz4mºØÍ Ñù’ùYËã+þ^=_Òu›Ý7áÆ²5;»­/W¶¹Õç<™Ä†Æâ1ÒÙØ7ÆQž0¬û‰ˆ3P£Ñ_6G{®µ§„eñ>«âÓ£Å}má­Cû6öõîoï4û]Y.î#lgh¤¸X~cµßÈÜ說LúÅ·Ä«‰lÿâsâm6Ùm¥ÿ„wËÒ¯ï.þÛwäyþUÄ(Ž-¿³óý¥¹ -¿\dèÊʃ_ѧխô«}Fîîcº–%ˆï[JÎ7”2I*!Rs’F>VÇ)à¯íQñ/Äkuÿ 3[;÷rÚ¯ÎHªÙˆáhÞÔŒ£•ºA2+ÉÆxoÀ÷—<µ´¿&Óí–çÅ7ò[]Ü@’}§R³žÚ4¸S˜Ñâ).Ø2ñȭȹÕ{ »[û{û¨n­.bY ž¨Ã*ÊÆR ޵à)ªüFº¾ðF©~ž °Ö„ZWvé¤ê2Ç{¦{4¦'[f_6é&„ȾNà˺"g‡t½o@ý›¼=ac³« [iòßÚ+Ì÷r›9â’òÚ,’dÞ"š(ÕO”êèª|¦S@¥{s¤K,«;+K@E ÊÙwT + –nŠ2ÌB‚Fãß êÔ¼Uiªùš>™l·W—?g”yqXîÃm+¸þâhßócï™Ýiÿ­u[{ûÛÙ¾Åscqu&-ËCqöíVÂY£RGÌ–þF¤›Oú»YmÁݺLfxÃÚý·ìÍãí"ãCÔáÔn¼?6ök"Í3XÂUÌÞj,¸Š×Å:lauv¢kÛy´˜mcŠ8í¦ï·Þn¡XËFçq1 ¬oGâ;-v}çVñn«ãM'WÑlžxî5´³l¶:i¿.Ïþ‰¹‘¯÷ JYÕ”ohè߬.íoìmïìn¡º´¹‰f‚x\†¢©h?gþİûÛ~ÍöhüŸ¶ùßhÙ´mó<ïÞïÇÞó>|çw9«´QEQEQEQEQEQE™â_ùEÿ_ÖŸúQiÖg‰äýZéDu§@~ÿtßõýwÿ¥W;ñ·þIûÿØOLÿÒûzè¼5ÿ é¿ëúïÿJ$®wãoü“÷ÿ°ž™ÿ¥öõ¥âGÔίÀÏøÿ#¾ÿaÕÿÓf§Eäwðÿý‡WÿMšßšÿ¼¿—äpeŸîËçù›Zhÿ‹WbêO‡ÿMË_IÕ󖘹øObêO‹ÿMË_GzVXÝ¡èrÖ§©™oÿ#Mÿýy[èsÑâ¿ùµúñ›ÿ@j-ÿäi¿ÿ¯+oýzÐ[WšÂ÷PÿI¶µŠÚÏËóe–yã‚5_1Ñ^Uå˜3SøoS½Õl^âûÃÚž…*ÊP[ßÉnò0À;Á‚Yo$rÀü§Œ` J(¢€)dé_ÛÛ¿Ù–_Úßfû'Û¼…ûG‘»•æcvÍß6Üã<ÕÚ£®ê–‰­ê³ýžÃO¶’êê]ŒÞ\Q©gmª 8PN&¯PEe\ëv°xªÃÃÆîúÆæú' +<°I8cœî&å1Çfäqœ 'Ç7z½ÅèÓ| âk›+[›ÛQ|%°X¦–ÖIbeEk‘'Í$LŠYd©m«–¥•á­n×_Ó¥¿³ŽxâŽúîÉ–Uﶸ’ÝÏü¥âb=ˆÈŠÕ «ßÚZߨÜX_ÚÃuisC< xåFee<2H õ«Pt*}>Ú2Î(tÌ}‚4BÚâ6ˆyC&#fO—+ÐÕê( Š( Š( Š( Š( Š( Š( Š( Š(  +7zN•yªXê—ze•ÅþŸæ}ŠêXå¶ólž[‘”Ü01‘Ö¦·´µ¶–æk{Xb’êQ-äaLÎP3‘÷›b"äöU«PEPEPEr>ñ¤úþ­-µŸƒüAõÝ“jÒ½˜¶ßm,‘9Ú. ÛL‘2Ý÷€9®º€ +(ª:î©a¡è—úÞ«?Ùì4ûi.®¥ØÍåÅ–vÚ “…àhõ^Þi%–åÒhB#ÈP¬ãb¶õÚÄ…Ëù‚œ£q·k5Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠÌñ/üƒ¢ÿ¯ëOý(Ž´ë3Ä¿ò‹þ¿­?ô¢:Ó  ¿ È:oúþ»ÿÒ‰+øÛÿ$ýÿì'¦é}½t^ÿtßõýwÿ¥W;ñ·þIûÿØOLÿÒûzÒñ#êgWàg„| ÿ‘ßÃÿö_ý6jtQð7þGÿØyôÙ©Ñ^†mþôþ_‘Á•ÿ»/™ÒéCþ-‰ÿ©>/ý7-}+ç},ÿÅ¡±õ'Åÿ¦õ¯¢cÚ…`7©êf[ÿÈÓÿ^Vßúôx¯þEm_þ¼fÿЋùoÿëÊÛÿCžÿÈ­«ÿ׌ßúW èštQEQEQEQEQEQEQEQEQEQEQEQEq4‹ýsÀ2XiÚ}î£0Ô´Û–¶³º[k‰"†ú eòåi#Øþ\nTïS0AÅs÷Þ“Äúoƒtë¿ +x‚ÏJÓA%c Їš¤ß­5äÐõ›VçOŸKû3iq[èöPÃÉdòì’ê?š;€aµ&mÞ¢IXzö¿è~´ÿÁñÊ?°¼}ÿCõ§þ“ÿŽPðŸÁºŽ‰ã} +öïÁÙw¶ºÓõÝ{6‡ûnùä²>~èäiåÞ`žMó"·ÏÈ ÄTÓ|;ÔSágÄ x-õ7ñ¹ˆ¢¶³“X•íœ]\ܽ¾ÈZSo:¼GpU#sn –®¿û Çßô?Zà‰?øåØ^>ÿ¡úÓÿIÿÇ(É5ß…¾(¿ÕfšöÃY•%¹Ô•ý>š?³f—U¾œ]4·QÉ%¶ø§´a- i‡”w.èãé~ ðýþñ/Äz¤¾û{˜ßµâÈ×LÎ6Tï™(À¸Ekf2E I /Cû Çßô?Zà‰?øåØ^>ÿ¡úÓÿIÿÇ(±¢¸ïì/Ðýiÿ‚$ÿã”axûþ‡ëOü'ÿ ÆŠã¿°¼}ÿCõ§þ“ÿŽQý…ãïú­?ðDŸür€;+ŽþÂñ÷ýÖŸø"Oþ9Gö¿è~´ÿÁñÊìh®;û Çßô?Zà‰?øålxj×Z³ëZÚêÒ¬Ž–‹n¨¼ñ´“Ç\úp;€lÑEy·ƒÇŽüG E¬'ŒímifE„èé!P’º}íëœíÏAÖ€=&Šã¿°¼}ÿCõ§þ“ÿŽQý…ãïú­?ðDŸür€;+ŽþÂñ÷ýÖŸø"Oþ9Gö¿è~´ÿÁñÊìh®;û Çßô?Zà‰?øåØ^>ÿ¡úÓÿIÿÇ(±¢¸ïì/Ðýiÿ‚$ÿã”axûþ‡ëOü'ÿ ÆŠã¿°¼}ÿCõ§þ“ÿŽQý…ãïú­?ðDŸür€;+ŽþÂñ÷ýÖŸø"Oþ9Gö¿è~´ÿÁñÊìh®;û Çßô?Zà‰?øåØ^>ÿ¡úÓÿIÿÇ(±¢©hÉw™ w×l¹L¬³ùb?1ƒ£…ÜýOZÁø•¨êºv—¦ñ,îo5[k?5¡…Y[i;O\g=GN´Ëü,Ò5=ÄÚœWÞñd2Þjú¬§Q}j9t¿&kÙ®"e¶ûYØÌ†1•€6ælðX×%£ü=ñ5žŸd5Ï +ÿni±}‚It_:Ùñ§%½ìpèÛ$Esö)¦Š_´JËæîÝËD€úö¿è~´ÿÁñÊ?°¼}ÿCõ§þ“ÿŽP˜xÇ᮵¬j|ðøZ±²]5-ô{>ûN“û +´\9‘¦ºŽG´ù$¶¬˜¼‚©½a€¶e·ï|[£xŠÓÞ‡EÔnõÛßxŽaozœSI©[ÇnÏ5êÍ-»’0£ìù•Œ7ªê6þ/Óï4ÛK¿ˆ¶‘M©Üµ­šÿÂ>™(†IŠñ'»†FÉÀùqÔ€nÿaxûþ‡ëOü'ÿ =]¯ˆ¯5=Ká§öÇ…å¹f·ðÎ,ÉfÓ´¨¡—É–Qn<Ÿ²ÝÁ•}Ëæ|‘Ù¨ðÏÃ?éº|Ú–«oý£âèu½¢ÕMé•ÚÞ}2ùbw`Éæ,7k!¼ȡX0Ø+п°¼}ÿCõ§þ“ÿŽV^°Þ%Ò!»’ÿâvZE³BºÉ0»$@F²f‘Õ‘A.Ãj†n(OƒÞ¿Ð?¶ÖóÃÿÙ =ʲ–¼Yžåþc$ŒP‘7ÌØ[©w A:nˆ<žƒ\wö¿è~´ÿÁñÊ?°¼}ÿCõ§þ“ÿŽPcEqߨ^>ÿ¡úÓÿIÿÇ(þÂñ÷ýÖŸø"Oþ9@Çaxûþ‡ëOü'ÿ£û Çßô?Zà‰?øåv4Wý…ãïú­?ðDŸürì/Ðýiÿ‚$ÿã”ØÑ\wö¿è~´ÿÁñÊ?°¼}ÿCõ§þ“ÿŽPcEsZ.â›=J)uÅ©[6åò#Ó[‚[sqÐc·=K@ž%ÿt_õýiÿ¥Öfx—þAÑ×õ§þ”GZt™á¯ùMÿ_×úQ%sŸ?ä@“þšgþ—Û×Gá¯ùMÿ_×úQ%sŸ?ä@“þšgþ—ÛÖ”‰Tg[à~‡„üÿ‘Û@ÿ°êÿé³S¢ßò;øþÃËÿ¦ÍNŠô3o÷—òü?+ÿv_3£Ó?䑨ÿØŸþ›–¾‰+çm/þIý‰ñé¹kè‘Ò±ÆíB²ýêz™–ÿò4ßÿו·þ‡=+ÿ‘[Wÿ¯¿ô¢ßþF›ÿúò¶ÿÐç£Åò+jÿõã7þ€ÕÂzFQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@t¿òZí¿ì\—ÿJc¬ÿiká¿…ž+Ѽ³§q¢jV?f{™äûH€.ä”–Û3ÈÊøÜII>g25hKÿ%®ÛþÅÉô¦:ìhÄ¿á ¸¶ø¥oþ‡â·ÿ„ÊÓPIþ×w$d‹ÃòÁ.ò7ˆž976÷Ìb]ÊñîöÚ( Š( Š( Š( Š( Š( Š( ¡_øý“þ¹§ójš¡_øý“þ¹§ójš¸ïƒòNìëâïÿJ¥®Æ¹ïhמðͶ‘#Ápñ<®Î¬TfIL;nÆ{ã1{ß\Yßø‚ÎÆoÛEq*GtMM*2¦Þ Yc›i½p­™XÞadGã™þ!ZxOû-牿´ôí6æëI½‹EÕ&—PœË)† -íîXC²8í°Ú‡œd~ñC¬ê~Œ¢€>lø¡iâ;“q5µ¯Žfñ¥­ö¿2=²j-g ±Óõ4°h +¢,»ÍA‹÷»Ø†ùÌ•Ðkúoô{­a</‰¥¼‡RºÓ4ŸµÞOuµ:ÜÄÌnY£oø˜¢y2Àâû—^çEygÁ_íK ¯â¾ÕüA©é÷RÙ½Ðõ+eŠp“<¼ßÏ5ÀR‹ÌÛ b¡iA^kàÝvçÃúë~,ž÷Rðÿ„¢¹–KËÖŸÍWêVߺ)cóÑ•œ«"ùžQUI6ý'EQEQEQEQEQEC?úÛúèô©ªÿÖÛÿ×Cÿ µM@ž%ÿt_õýiÿ¥Öfx—þAÑ×õ§þ”GZt™á¯ùMÿ_×úQ%sŸ?ä@“þšgþ—Û×Gá¯ùMÿ_×úQ%sŸ?ä@“þšgþ—ÛÖ”‰Tg[à~‡„üÿ‘ßÃÿö_ý6jtQð?þGÿØyôÙ©Ñ^†mþôþ_‘çåîËætzgü’+ûâÿÓp¯¢{Wκgü’;ûâÿÓp¯¢»V8Ý¡èV_½OS2ßþF›ÿúò¶ÿÐç£Åò+jÿõã7þ€Ô[ÿÈÓÿ^Vßúôx¯þEm_þ¼fÿиOHÓ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(Ž—þK]·ý‹’ÿéLuØ×/ü–»oû%ÿҘ뱠Š( Š( Š( Š( Š( Š( Š( ¡_øý“þ¹§ójš¡_øý“þ¹§ój— &¼Ð|dÐö†þÃ×€#<Å?‘–½-ºøãU¹—í³(nÓë_Aåt³ MT¾–ýO#4ÆÔÂòòu¹ïGã>€:èÚØÿ€ÁÿÇi­ñ¯Ã«×HÖ¿ï˜?øíx½½íͼ÷Æí ¸ 43Ó'¦OaÔö¦Íkx–Q^Ë %¼ÌV'n7ã®ÞäÆGâ¾ýWÀÞÎNþ§‘ý³‰jÿ¡ïãã_‡ÏöFµ÷`ÿã´‹ñ³Ã¬p4kþùƒÿŽ×ˆÍ£K†aÕÖãsI Œå‹„r{äÆããÖ¥¹ð¾¹ogbϧjòòYcŽÌÚ8¬aà:wßÃY<ƒ,Z9½Úß¶æŸÚ˜ÇÓÏcÚOÆÏ ƒ¤ëGþÿ­Ÿ|HÑü[­I¤ØXjVóGn×®0…U•H]¹ËÞµó‡ˆôÙ´mDØÎ_ÍE#«Ç±¼jåH=Æì~Ý~Í$ÿ»ÏýäÿѱW>? ÁÑÁKI·¥Ñ¶3ÄTÄ*s>Œƒã_ZxWLŠþòÒòé%œBÕ˜¬Ù;˜>S߸­êóÚÌ~‰Áûl|ÿÀZ¾OF5ñ§-›=ÌUIR£)ÇtF~2èC®‰®ªAÿÇi§ãG‡Ç]Zð?øí|öóÍ#}ãÉé[Zׇ¯¬õK}>ÈÍ©Ë)ÿǯ‡ìc°ÿѵð8ÊJŽ"tã²m}ÌúŠs¥=ÚGeEW9°QEQEQEQEQEQEQE ÿëmÿë¡ÿÐZ¦¨gÿ[oÿ]þ‚Õ5fx—þAÑ×õ§þ”GZu™â_ùEÿ_ÖŸúQiÐg†¿ä7ý]ÿéD•Îükÿ‘Oû +iŸú_o]†¿ä7ý]ÿéD•Îükÿ‘Oû +iŸú_oZQþ$}Q_á¿CÂ>Èïáÿû/þ›5:(øÿ#¿‡ÿì<¿úlÔè¯C6ÿz/Èóò¿÷eó:-3þIý‰ñé¹kè®Õó®™ÿ$’ÇþÄø¿ôܵôWjÇ´= +Ë÷©êf[ÿÈÓÿ^Vßúôx¯þEm_þ¼fÿЋùoÿëÊÛÿCžÿÈ­«ÿ׌ßúW étQEQEQEQEQEQEQEQEQEQEQEQEqÒÿÉk¶ÿ±r_ý)Ž»ã¥ÿ’×mÿbä¿úSv4QEQEQEQEQEQEQET+ÿ²×4þmST+ÿ²×4þm@·C_^×sõvþuö‰äcÖ¼ üÔ Þ8‰ä“¤uÿÈÕôü5™a°2¨ëÊ×µ´o¿cÆÍðuq*Í^×<ÐêpÜh°é÷qÌÓsZ¼o”É9!ãnxù†Ó뻌&½¨Á«:Þ¼sÇ|ØY³)xØ€Ww̼ mËL +ôÏøgûÿúâÿÁIÿãÔ§à¡ÛÆðû„öêú5žeJ\Êoî—]úGö^2Ö·âŽOMñ½¦¦"6‚]"£Hcû,K9h¶²qóºäÄ Ç¯‡_Ð#ÓJŠ}bH.>Òf¹’§˜Ñ0Âù˜oõXl°Ècô®°|Ôâ·‡ÿýºðP?ð›ÂîÿÛ«’Y†LÝÔÚù=ûí¿ôÍ£‚Ç%k~?æž*¾µÔuƒqeöƒn°C +Ô;#TÉ‘ÎßZí¿f¯ù(WŸö “ÿFÅZ‡öÔ_Åÿ‚þÝ]_Âß…·> +ñÚ¼Þ#MHKhÖâ%±òq—FÝ»{gîcõ9Žs€©€–ŒÛv²Ñÿ‘xL» J©5§©é¢¼Ïö8ð<õ¿Œã^™\—Å/OãOÁ¥A« 1£ºY̆ßÎ ºíÆåÇÞ9í_—U…U:“vI«žö.œªP”#»GÌz Å­¦±kwx’I/æE±^Ts؜ힽ+£´ñm½îuc®‰YC¤w6p¡Dr¬ùUØ–~¡›ž™ëÿáŸïÿèv‹ÿ'ÿQÿ ÿ~?æv‹ÿýº¾ïœå8‡yMߦOM™§—ciü1üNq|U >¥c,­«Gq ðl… ϲã"A¼9‚ ሮCK¸´·½7w1ÜHc!áH¤òòùãsuP:ñÉèê=HüÔüÎðÿà£ÿ·P~j'þgxGýÂ?ûugC6ÊhÅÆ5ž›?ò*y~6v¼WÞyÜZâD÷·âQ¼óþr°¢7_—9ŸöÉ|ÁÉȸkØGìÿ¨ãxðQÿÛ©?៵sãx‰?õÿíÕÓK?Êé_–o_'þFrʱ’Þ?Š;ÿ€ßòJ´¬ÿú>J±ñOþ=|;ÿc‡þ­‡¾ +xBËA’ø_5±“3ˆ|­û¤gû¹8ÆìuíYßÿã×ÿö1ØèÚüóR5q5*CfÛ_6}^£ºHì¨¢Šæ6 +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€!Ÿým¿ýt?ú TÕ ÿëmÿë¡ÿÐZ¦  ÏÿÈ:/úþ´ÿÒˆëN³/ý7 +ú.¾tÓ?ä’ØÿØŸþ›…}éXãv‡¡Y~õ=LËùoÿëÊÛÿCžÿÈ­«ÿ׌ßúQoÿ#Mÿýy[èsÑâ¿ùµúñ›ÿ@já=#OŠJ+Ÿøƒ­ÜøwÂ7ºµ•¼SÜÆcŽ$•ˆMòH±‚Øç¶HqŒŽµT麒PŽïBg%¹>‡CEx,Ÿü\„†þÁã¯ú$¿üv£oŒ>*^¿Ø_ø/ÿ¯epö9ýŸÄóµðÝÙïÜÑÍ|ÿÿ —Å?ÝÐÿð_þ;Mÿ…Íâ¯îhŸø/ÿªÿWqÿËø‹û_ ÝýÇÐTb¾|?üT?åž‹ÿ€rÿñêaøÕâÌñ‹øÙËÿǨÿVñïìþ!ý±…îÏ¡±F+ç¤øÓâÂy‡Eöé/ÿ¡¾5x¬t‹E?öç/ÿ£ý[Çÿ/âÛ8^ïî>…ůžáux³þxh¿ø /ÿ§>+Û“Š§ØåÿãÔ«xÿåüCûg ÝýÇИ£óÉøÕâÌñ‹ÿ€rÿñêCñ¯Å£Ÿ#EÿÀIøí?õoü¿ˆ¿¶p½ßÜ}Š1_<Ÿ~,ýF‹úó—ÿQÿ «ÅŸóÃEÿÀ9øíêÞ?ùþÙÂ÷gÐØ£óÊüjñY<âÿ^’ÿñÚs|iñXÿ–Z)ÿ·9øõ/õoü¿ˆÿ¶p½ßÜ} Š1_<ÂëñoüðÑ?ð_þ;H߇£µx§Ão‹Zþ½ã?AÕ,´Æ‚øHªöÈñ´l±´™;™ƒ !ã¨9ãÚëËÆ`«`ê{:ÊÎ×;ðøˆb#Ï …¢Š+”Üã¥ÿ’×mÿbä¿úSv5ÇKÿ%®ÛþÅÉô¦:ìh¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¨Wþ?dÿ®iüÚ¦¨Wþ?dÿ®iüÚ€&¤üh$w®.OŠY^1­4»©x¬ç‘ k*ÃÜ+JT*Õþ[·es:•aOãiz­ÅÂÒð?ýn?ð]sÿÆèÿ…¥àú +ÜÿàºçÿÖßPÅϹ}ÌÏët?}èíy£ŸJâ¿áiøþ‚·ø.¹ÿãt‡â¯‡]ZàÜ:çÿÓþÏÅϹ}Ì>·Cù×ÞŽÛð£ð®$|Uð1àjóŸû‡ÜÿñºÅ_º´ãþá÷?ün¨b¿çܾæ/­Ðþu÷£¶ü(ü+‰| x´çþá÷ünƒñWÀî¯p?îqÿÆèú†+þ}Ëîaõºξôvß……qâ¿ÉÖ&÷¸ÿãtÂÖð.qý¯>ìsÿÆèþÏÅÿÏ©}Ì>·Cù×ÞŽßð£ð®#þ·è/?þ îøÝ;þ§ñŸíkü\ñº?³ñ_óî_s­Ðþu÷£µæŽkˆÿ…­à_ú Ïÿ‚ûþ7Mo‹>_½¬Ì?îqÿÆèþÏÅÿÏ©}Ì>·Cù×Þw®;âŸüzøwþÆ;ý[ž×ôiƒRÑo’òÛy™T«+ªÊÀ2žAÁ‚B+âŸüzøsþÆ;ý\ÒŒ Üd¬Ñ¼d¤®ŽÊŠ(©((¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š†õ¶ÿõÐÿè-ST3ÿ­·ÿ®‡ÿAjš€3¨Î¯ðß¡áäwðÿý‡WÿMšŸäxðÿý‡—ÿMšèfÿïRù~GŸ•ÿ»/™Ñécþ-‰ÿ©>/ý7-}_:i§þ-%ˆÿ©>/ý7-}Xãv‡¡Y~õ=LËùoÿëÊÛÿCžÿÈ­«ÿ׌ßúQoÿ#Mÿýy[èsÑâ¿ùµúñ›ÿ@já=#O½qÎ>_úx´ÿÒ˜«´ï\OÇÛðÏQoI­OþLÅ]X qTÿÄ¿3 WðgèÏ™'•‹Éäõ¨ 'š23œŽi2=Gç_²(ÙŸ·v-uº&nÞ‚õt­îâK¹£wÔ5o…UŒ¨QçFÞlõí\ŽG¨üë^Ç[Ž .=:çHÓïâŽg–3;LY‚†ÿW"ñò/ZãÇS«8/g½ÿ®«ó6 ã{ß×àËÓxNùÉ÷:|×MS}Šrè’” Ë ½]F7gðæ›…ÄÂw‹Ä,[!iæIˆðÊ¿wfóËŒ<óÅBMD¶º–ö.¦¸tÙb­ÈÝr£‚NpËÆCbìþ,³y."kV¾¶].+ t¹MžfÇ‹ÈÁÚz1<($óYψ.u[?³\ÛZª¤ÞlLŠÀÄ»<µçquñ×­MŽH¹ü7×m­÷úŽj‚‹åÜÕ²´ÒY|;§M¤ÂϪE‰nÄ’ùÈÍ3ÆFýœax*sƒõ©<;àKCì—SÞ"ØI:$ΰΥA'Êí–Í“Žþ@ã&ßIJÛZYFºu¹²ŒÇmvÂC,`³6@ß³ ±Á+ÇÔU«^Ú¤oŸ§µÊG _iq)vH™û?A‚G¿5Z8åÍ쯫ï~¯¾ÊÖû¶'AÛŸ·ùÚxRòûM¼¿±º†x-|ÂÅ`ŸF2NóÁÇ ž™â¥ð®ŸÎ…¨Þ6¦^ÜCqh/¯Mº*²È[ÍŒò¯=ø¨¢ñL±Ûy+¥iÙX§† šZåݹW÷˜?}°XÏSXñßÉ—>œySMÌpw@àcÛç?¥oìñ•a8ÉÛUoKë³]æ£)/?ø|¾ –þÚÑ4ÛDŠâS$Ó2¼³*Gå@êU,y—cÏ%±šÏ¼ðF¯em{qy5­ºZœfQ" >@àS +Ha&ÒIÚr*âûö†;y­l¦¶X¼©!e}³&È“ †% ƒ‘éÅ2ÛÅ3Û­ÏÙt½.™Z4x¡dh‘“aPC|àŽy¿žz’k +tó+_Oø=ßõo3G,4·_ÕŽÙ¥-X[¨.tûfÁŒZL£æ{øºŸüwm@NI8ž•íÆMî¬p5m„¦@ɧZF9Õ¡WÁLÿÂÞðßýv¸ÿÒY«ëÒ¾Oø)ÇÅï úkqÿ¤³WÖ¿7âß÷åþù³ì2O÷o˜QEó°qÒÿÉk¶ÿ±r_ý)Ž»ã¥ÿ’×mÿbä¿úSv4QEQEQEQEQEQEQET+ÿ²×4þmST+ÿ²×4þm@·C_ý±âµµE$oþ€µö1û¿…|TìLpŒð ‹ÿ@Zû.Š”êßËõ>{?vPù“½í×5§e¦½Æ—¡s­XXÅ,Ï k8˜³2…-÷#lœu5‡]&â§xvÂÖ¬®%ŽúY¦†æÎ9F±mÁu;sµ‡ÊAãé__‹E¨­oýtgÏÑqæ÷ŒN+» BâÆà5¼­àänSƒUw·\×£Oâm=:âÖÎúÙ -sæ­Â]<—,ìÅheŽFé>`S#8ÍGÆV÷s]Ç.«4¶ÒϨ,‡ÚÑ<@@¸ÇMÙÂö<œu® +y†#gAþ+eéÔé–•ïí?¯¼óÅ•À&ƒ#œ×{¨øªÖˆnaÔü_nImí¼¶Qgk±–H>`È`¸Lƒ³9éRØøŸI²»¼±Ó¯bŠ"† >îãí1©I2¨"E.í»ÐíÁíZ<º2¢ÿ¯—õ­¶!aé·g?ëï8m"ÖãQÔΕ¤‘ˆTURÌÍì'ŒŸJv«j,åŒ%ý¥òH›Ö[gb:‘‚SÇBcЊ½ì2x¾}BßPM04ÒI ÄvÌO8ÊÅTô#æÀ= ugˆ´k™-îtȵ‚!%üpÜ[ÛÈUܲªÀEÊ´Â1œŽ„¼N*µ))F «--úÛþ—eN”%x¹|ÎþÖ{K{9¤d+w š=¤’;'>ùSúT +ÎXÔö¯JƒÅºB¼†ÒæÎÖé¢Â\)ÿǯ‡?ìc°ÿѵÉþËÿ„/YÇý_ÿIளâŸüzøsþÆ;ý_æÿïÕÄϼÀÿ»ÃÐìh¢Šóް¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(ÿÖÛÿ×Cÿ µMPÏþ¶ßþºýªjÌñ/üƒ¢ÿ¯ëOý(Ž´ë3Ä¿ò‹þ¿­?ô¢:Ó  Ï È:oúþ»ÿÒ‰+øÙÿ"ŸöÓ?ô¾ +è¼5ÿ é¿ëúïÿJ$®sãgüˆØSLÿÒûzÒñ#êŒêÿ úð7þG}þëÿ¦ÍNŠ>Èíáÿû¯þ›5:+ÐÍÿÞ¥òü?*ÿv_3Lÿ’Mcÿb|_únôhí_9iŸòIììO‡ÿMË_FŽÕŽ7hz]ñTõ3mÿäi¿ÿ¯+oýzÿ…/ðãþ€3àÊëÿŽQÿ +_áÇýfÿÁ•×ÿ¯BÍ®¿í _üý—ÞÿÌÇê´‘}Çžÿ—øqÿ@¿ðeuÿÇ)áKü8ÿ  ßø2ºÿã•è9£4hbÿçì¾÷þaõZ?ȾãÏáKü8ÿ  ßø2ºÿã”–ømÿBü¿ø1¹ÿã•èY£4hbÿçì¾÷þbú­ä_qç£à¿ÃqÓ@›ÿW?ürƒð_á¹ë Mÿƒ+Ÿþ9^…š3Gö†/þ~Ëïæ?ªÑþE÷{ÿ +[á·ý òÿàÆçÿŽQÿ +_áÇýfÿÁ•×ÿ¯BÍ£ûCÿ?e÷¿óªÑþE÷{ÿ +[á·ý òÿàÆçÿŽP> |74 ¿ðesÿÇ+гFhþÐÅÿÏÙ}ïüÃêÔ‘}Çžÿ–ømÿBü¿ø1¹ÿã”–ømÿBü¿ø1¹ÿã•èY£4hbÿçì¾÷þaõj?ȾãÏGÁ†ã¦0ÿ¸•Ïÿ üønx: ßø2ºÿã•èY£4hbÿçì¾÷þaõZ?ȾãÏáK|6ÿ¡~_üÜÿñÊ?áKü8ÿ  ßø2ºÿã•èY£4hbÿçì¾÷þbú­ä_qÈx_ᯂ¼5«.«£h‹ê#"K%ij ×o˜Ì‘ÆG8$t&ºê)kž­YÕ—5FÛów5„#h«QPY.†­âÕñÜ‘2X%ˆ¦Wi;1ç®UqøõÏ›nç´_÷èÿñU-ÛŸùíýú?üUnç´_÷èÿñU-ÛŸùíýú?üUnç´_÷èÿñU-ÛŸùíýú?üUnç´_÷èÿñU-ÛŸùíýú?üUnç´_÷èÿñU-ÛŸùíýú?üUnç´_÷èÿñU-ÛŸùíýú?üUnç´_÷èÿñU-ÛŸùíýú?üUnç´_÷èÿñU-ÛŸùíýú?üU$QȲ3ÈêÅ”/ʸÆ3î}jj(àŠùÂãà‡ŽgŽßPðôÐ!Ù4ѳ áK(‚œc#'ë_GÑ]øÏmÑv¾ÿ#—„¥‰·´[6ÿ‘ñÿüýxoÿæÿã4‘ñ÷üýxoÿæÿã5ôŸ4W£þ³æ?Ïø#“û Ûñ>l||?åëÃø7ÿ¤?|ÚëÃ_ø7ÿ¯¤è¥þ³f̾ä?ì|/cæÅø!ãáÖëÃgþÞæÿãT‚>?íuá¯ü +›ÿWÒ˜£¬Ù‡ó/¹ û Ûñ>k_‚>&ëÃgþÞæÿã4‚>?íuá¯ü +›ÿWÒ˜£¬Ù‡ó/¹ö>·â|×ÿ +CÇÝîü7ÿsÿñšOøR>??ò÷á¯ü +ŸÿWÒ¸£¬Ù‡ó/¹ö>·â|Ö~|@=n¼5ÿSñª_øR>>ÿŸŸ ÿà\ßüf¾“Ŭهó/¹ö>·â|Ô~øüÿË߆¿ð*þ3J~xôøúðßþÏÿÆké:Z?Ö|Ãù—܇ý…ìp¿ü௠ÜXj—V×wW¯u ·ÝåÇ•D + `·ƒœI²z/è‘ëi`’NЋ+ø¯TªçsFw*Ÿlã>ßlJñ+Öjޤ÷g£NœiÅF;"=·?óÚ/ûôøª6ÜÿÏh¿ïÑÿâªZ+2ȶÜÿÏh¿ïÑÿâ¨Ûsÿ=¢ÿ¿GÿŠ©h ¶ÜÿÏh¿ïÑÿâ¨Ûsÿ=¢ÿ¿GÿŠ©h ¶ÜÿÏh¿ïÑÿâ¨Ûsÿ=¢ÿ¿GÿŠ©h ¶ÜÿÏh¿ïÑÿâ¨Ûsÿ=¢ÿ¿GÿŠ©h ¶ÜÿÏh¿ïÑÿâ¨Ûsÿ=¢ÿ¿GÿŠ©h ¶ÜÿÏh¿ïÑÿâ¨Ûsÿ=¢ÿ¿GÿŠ©h ¶ÜÿÏh¿ïÑÿâ¨Ûsÿ=¢ÿ¿GÿŠ©h <¹šHÚI#!8Gb=}êz(  ÏÿÈ:/úþ´ÿÒˆëN³¨Î¯ðß¡àß¿ävÐ?ì:¿úlÔè£àOüý‡WÿMšèfÿïRù~GŸ•»/™¹¦ÿÉ)²ÿ±>/ý7-}&:WÍšiÿ‹Wcÿb|?únZúLt¬±ÛCÐYoÅSÔ(¢Šà=P¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(™øªHøaâ¢:ÿc]ãþü½y ÷ÒeŽB zq^¿ñWþI‡Šì wÿ¢^¼æGóŸ5}_ ÒSŒïä|æ{77Œª>YÜ÷T—Rº$bg?ð#TŽãÞšsÞ¾²4 º:êÍõ4ì$Ôï¤d·bv.çg”" õ,ÄÎ'©%Âk¼ñÊ®¦IJ~ð°;‡#=i4‚—Eöš%†å’)c2È#W ¼ÜxæÏ$=q[V:¦˜…YÞKg¦¬e]÷G$Ÿhm}ý ö$¢¸+Ö9µ§ªÒÞšþ‡U(©Fò×oÔÁ¾“R²‘#ºgŽFE}¾fXÈÜùN;ƒûFëþ{?ýôjo¤?Úosmsöˆn¿~ŒÏ¹×wU~ûÈç¯^õ]´#ÓRkSž¬¥4™oûFëþ{?ýôj9ï®Z3™_§÷ª +d¿sð­•(_b9åÜöÿ€,[ám‹1,Måÿ'þ¿f®ð÷®ö~ÿ’S§ÿ×Ý÷þ–M]ñï_–ãÞj‰þgßῃEù(x¶óÉñF¶WRóœÓÄ•ˆúŒÇ¦Ò­øÔÿÅe¯ ÿÌVïÿG½c×êø +ú¼]ðØ‰¿k/SONþÑÔ®…µ¢©cóUP2Y˜à(©$NÕ ÔôæíX 2–ŠH¦Icqœ®„©ÁààñRø]á#R±yâ·’òÌà ’¾ÄicÂä)\œyâ¶¼-§[éÒ\˽êäªb×íVŒ,Ùc,Èñä>TÉ;‡LXbkû ËE§N¯ÎýȺpçõù¸”~tö»¿å£ßUÝkWjm§ZE£gµ­ë<‰LåÃÎbÄTàG·dÔb–#£®·»_¾ç Ú!9Ëó +‚@ÎÍæpyíŒÖÚJ×tüÿ¯?.Ú–ðÚÛ˜âb[Óg%ò‡0E"Æï¸p̨Ç^Šß•B×31æFüë±ñuΚÞžx¬m®š{f’+{¨eÝ?Íû¤Hò\ìr2sšáë·Wës”mÿ ŒkÃÙ´“¸÷¸—Þßz÷ì®ìÚŸŠwùceüî+ÇX ŠöÙSþB>(ÿ®6_úÅy¼K²éÛºüÑÛ“¿ö¥óüx¢Š+òóìŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ¸Ÿ¿òOåÿ°ž™ÿ¥ðWm\OÆïù'ÒÿØOMÿÒø+J?Ī2«ü9z ð$çÆúý‡WÿMš߀Ç>6Ð?ì:¿úlÔè¯G7ÿz/ÈóòŸ÷eó7ôÑÿ®ÄÿÔŸþ›–¾’«æí5€øWb?êO‹ÿMË_HŽÕ†5éAåªÒ©ê-Q\'¨QEQEQEQEQEQEQEQEQEQEQEQEQEQEcx×L¸Öü­hö¯\_éóÛDÒYãeàŒŸC^/„¾#»³Âv2sÿ!Oþ;_JPkÒÀf•°)ªi;÷ÿ‡G/On{è|Óÿ‡ÄúîÿðciÿÇiƒþ$ù‘.ÿðaiÿÇkéŠ+ÑÿYñ˹ÿ™Çý…†îÏ™ÿáø‘ÿB-ßþ -?øí'ü!ß?èE»ÿÁ…§ÿ¯¦ +OÂõŸü±ûŸù‡ö»>hÿ„?âGý—ø0´ÿã´Âñ#þ„[¿üZñÚúbŠ?ÖŒ_òÇîæØX~ïúù3Âñþ„K¿üÚñÚd¾ øãÀ×cþâŸüv¾œ£ñ¡qF/ùc÷?óì<7vr?tMGÿ´í/U"½<ÒÆ®ËógyB8$ã# à‘Íu½¨WÏÕ¨êMÍîÝÏ^PŠŠè|ÑãO†Þ=›ÅúÅ͇‡¾Ûkq}5Ä3Åy +†Y¸áÝX»Ž ã#äÿ²ø“ÿBŒ¿ømÿÇ+êÞ´WÐÒâœm*jQ²Ógþg—<›99;ê|¥ÿ +ËâOý +2ÿàu·ÿ¥ÿ…gñþ… ¿ð>×ÿŽWÕ¼ÑÍ[âÜsé¹ÿ™?Øx~ìùDü3ø’zxBQÿoößür”ü3øÛÂà}¯ÿ¯«h£ýlÆöÜÿÌ?°ðýßÞ|¢>|HÏ>—õÿkÿÇ(? þ#öð|ßø0µÿã•õu­¸îÑûŸù‡öÏï>P ¾$¾—ÿ­øåz¯ìõàÿxdë—zý‚Ø5ç‘0™’GÄ~a,v0|À9ùOŒúÎ(®Lwâ±´]‰Yö_ðMðÙ]=Nx^âÑEážQEQEQEQEQEQEQEQEQEQEQEQEQEQEWñ»þIì¿öÓô¾ +íëˆøÝÿ$ö_û é¿ú_iGø‘õFU‡/CÀ~œøÛAÿ°êé³S¢›ðÿÅo¡Øu?ôÙ©Ñ^–oþõ/—äyùOû²ù›¾ ž×Wø{¤F¯ ‚M4É™@Ü’GoöixõVVúŒõߟx¤ùèÿø%“ÿ’é4¯‚º™}-îâOé¯;nš(¥·’ÜÑK !l7‘޵²>?ýÚÿþi_ü‡YÊ¥)E)GTaN•h·*r²z˜gÇþ)óÑÿðK'ÿ%Òx£þ‚:?þ dÿäºÛÿ…eŸùuïüÒ¿ùøV_õ:ëßø¥òsÞ•ö6åÅ:1‡ùÞ˜ßùø¾ã˜ÿ…«âoùýÒðI'ÿ%ÒŠÞ&òù¤ÿà’OþK®£þ=·ý Ú×þ ´ŸþB¤ÿ…OmÿCv·ÿ‚í'ÿ¨çÂ#gÿŸ‹î9sñcÄ¿óù¤ÿà’OþK¤üKÿ?šOþ $ÿäºêáSZÿÐÛ­à»Iÿä*?áSZÿÐÛ­à»Iÿä*9ðŸÈÓÿ?Üs+ñWÄÇþ_tüIÿÉtïøZ>'?òý¤à’OþK®“þ5·ý Úßþ ´ŸþB¥ÿ…Qýßþ ´ŸþB£Ÿ üŒ91¿óñ}Ç7ÿ CÅóý£ÿà’OþK¤ÿ…¡âùþÒ?ðI'ÿ&WMÿ +¦ú5Ïüi?ü…Gü*˜?èp×?ð]¤ÿòøOäxù1¿óñ}Ç5ÿ CÄÿóÿ¤àŽOþL£þ‡‰ÿçÿHÿÁŸü™]'ü*˜?èp×?ð]¤ÿò/ü*˜?èp×?ð]¤ÿòø_äxrcçâûŽdüQñ@ÿ—í#ÿròe4üSñ@ÿ—Ý#ÿ’òetÿðª ÿ¡Ã\ÿÁv“ÿÈT§·ÿ¡¿[ÿÁv“ÿÈTsá?‘ýáÉÿŸ‹î9Fø±âqÿ/šOþ $ÿäÊoü-¯Ïæ“ÿ‚I?ù2º³ð–Ôõñvµÿ‚í'ÿ¨ÿ…IiÿCnµÿ‚í'ÿª”ðóíýäûþ}¿¼91ßóñ}Çßþ}¿¼=ž7þ~/¸ãƯÏΕÿ‚9?ù2“þ_‰?ççJÿÁŸü™]§ü)Í;þ†cÿšOÿ!R›ÓèhÕÿðY¤ÿòø?ùöÓÿ?ÜqŸð»þ}¿¼91¿óñ}Çÿ “Äÿó÷¤àŠOþL£þ/‰ÿçïHÿÁŸü™]ü)ëúõŸüi?ü…Gü)ëúõŸüiü…OÚ`¿çÛûÅÉÿŸ‹î8ïø\¾'ÿŸ½#ÿRòe1þ3øF~Õ¤ÿàŠOþM®Óþõ‡ý zÏþ 4ŸþB¤ÿ…;aÿC^³ÿ‚Í#ÿ¨ö˜/ùöþñòcçâûŽþ7ø•zÜé?ø#“ÿ“i‡ãŸ‰?çãJÿÁŸü›]Ñø3¦ž¾(ÕÏýÃ4þB¤ÿ…/¥ÿÐÏ«à¯Hÿä*=¦ þ}¿¼91¿óñ}Ç ÿ ÓÄŸóñ¥àŽOþL£þ§‰?çãJÿÁŸü™]Ïü)m+þ†m[ÿzGÿ!Qÿ +[Jÿ¡›VÿÁ^‘ÿÈT{LüûxrcçâûŽþ§‰çãJÿÁŸü›Gü/OÏÆ•ÿ‚)?ù6»ŸøRÚWý Ú·þ +ôþB£þ¶•ÿC6­ÿ‚½#ÿ¨ö˜/ùöþðäÆÿÏÅ÷/ü/_ÏÆ“ÿ‚)?ù6ø^Þ$ÿŸ+ÿròmw_𥴯úµoüéü…Gü)m'þ†m[ÿzGÿ!Sö˜/ùöþðäÆÿÏÅ÷/ü/oÏÆ•ÿ‚)?ù6“þ·‰?çãJÿÁŸü›]ßü)m+þ†m[ÿzGÿ!Qÿ +WIÿ¡›VÿÁ^‘ÿÈT{LüûxrcçâûŽþ·‰?çãJÿÁŸü›Gü/Ï}+ÿRòmw_ð¥tŸúµoüéü…Gü)]'þ†][ÿzGÿ!Qí0_óíýáÉÿŸ‹î8CñãÄŸóßJÿÁŸü›Gü/ÏÆ•ÿ‚)?ù6»¿øRºOý º¯þ +ôþB£þ®“ÿC.«ÿ‚½#ÿ¨ö˜/ùöþðäÆÿÏÅ÷øñâOùøÒ¿ðE'ÿ&ÒÂùñ'üüi_ø"“ÿ“k¼?túu_üéü…Kÿ +SHÿ¡—VÿÁV‘ÿÈT{LüûxrcçâûŽ þω?çãJÿÁŸü›Gü/¯Ï}+ÿRòmw¿ð¤ôúµoüéü…Gü)=#þ†][ÿZGÿ!Qí0_óíýáìñ¿óñ}Çÿ ëÄŸóßJÿÁŸü›Aø÷âOùï¥àŠOþM®÷þž‘ÿC.«ÿ‚­#ÿ¨?ôúu_üiü…G´ÁÏ·÷‡³ÆÿÏÅ÷ ø÷âAÿ-ô¯üIÿɵ™âOŒZ§ˆ4ÏìÝN[6µ3Á;-¾Ñ;¥ITk§EÏÊxÏÖ½Gþ–ÿC.«ÿ‚­#ÿ¨ÿ…#£Ÿù™5_üiü…N5pQiªoï§Œj΢ûø> +stream +ÿØÿàJFIF``ÿÛC  + + + +    ÿÛC  ÿÀL¤"ÿÄ + ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ +%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ + ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ +$4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?çÿbïØÏÂ>øAáoøÏÂÚ‹¼câí2t zÒ=SOÓl¯#ZC¤Á­Ù´ÈòIȲJꬪ£>ãÁo\¦øþüt$Ëð×B#ƒƒÿ.ž Ó~¦g„œÍ7ð§þ˜lk¶økð_\ø¿ãä¶ÓtNÿL‹S‚ÒökH÷ 8ZM¿{.#V##/L +úÎ#Ïe… +žÅU[¶å½ô}Ÿ•ŽnàºÛŪؗBž•.[Yß™ui}ŸVÙÉ¿‘A“áÁHÁ!rß ´%'ǧsÅjØ~Í>½¾ +sÿTßBÿäJØø•ðk\ø=ñ í5='TÓôéµí¬¥»oÛ Y +dÀ¡Ç7¡«¿´î·ªøöwÖujshz¿ŸcmüC4¶¢kÈ!gU™$Œ°Iц{äÉx‚Êu§[û;l–·¿{v:xç‚©äŸU–*±¯Í«Òܼ½›þm{XÌ_Ù+ÀRG‘ð‹à¨?öM´/þD¨_öJð*Ÿù$ðÛè_ü‰U> üAñ쯮k^ñGÄ/ø«EÔü#¨x¢ÏZKÒÄZXÏg ñ Kx¬¦ÅäF?2Û(Ë fpè#îfý²ôþ-OávðŽ>ÃcâH¼%yâ7³µ]"ÛQšæ‚2ÆàNË'›ŽUw +å2 {нãf¯-´_ÍÉÿ¥Y.í¤·>t«E6ê;-w{[šÿußÉœs~ɾíð“à¯þm ÿ‘)­û'xÍ$ø+ÿ†×BÿäJËø9ÿ ðÞŸû=j~%ñeÕÖìx^¶K84ë ¿·¼ºkÊÒE»‘L_"±)Fá#?Uðþ +ðëö†Ô,-´¨¯m^ûT¹ÑZW½Ó/í-¯"³[Õ…®lnî s-±•ÐÅ#¨û<ªæ7[Xì-H©FÕ)j–Ïgýzì_Õ±<¼ÜÒûßEw×·ùnb?ì£àÓá/ÁlÿÙ6Ðù˜eOÿ$—à¯þmÿ‘*§ÅïÚÇV×gðGˆ¼)Ò|)£é‘xçÆpêV‘æÐfœ[§–òwÄnïU”ïÆž‚ùŒÿÛö¾Ÿáß…|a§ø/Ãþ*Ôõ }† CÄšu­”ú^ƒsrñ2C2Í0šF0˱† R5ž6vQ’ºøG©hg‹¼eá j>'Ÿìº=¦±«ÛÙO«M¹Ë·I]ZWÝ$cjrê;Šç­Œ¤èûZp¯e¢×HÊëÉ©+>»­,ÞÔ°Õ½¯²œå{_w¦­?šqwí×[ÛæyÿaÿÄä’üÿÃm¡ò%4~Å~UçáÁlú¦Úÿ"W·þÕ¿5Ÿÿþiš7‡ïD±™PËmy{ ÷2ƒá °Žê`a#f^!'6„åÉìã{Ûe«µô;jeu­ÍËkîûÛóÑwèqw¿±÷ƒ-—'áÁaú¦Úÿ"V]Ïì·à¸Ž?áS|÷M´þD®ËYý£u/|Vžoø†ÞÛÁZoŒ|ÿÃk ÿòYñ×íiwâOŒ_4 è)²ðÖ³ã‰ü?wâ+‹K3¥ëioc¨à‡2µÊm¹·HÐįä6Çt9jÑÿÁI¾I¬xûNŸLÖãÔ>Z=î¡kgw¥jóO\‹g–³²H²2æÄRÜ!!€ìŽ?fÜ"­²¶ŒTÛÛnWDÞÚ™VÂâ “u%²zIéy8¥ëuÒý:èdê¿|/d§ > tÿ‹k òr:çÃï ée‡ü+‚ãõMëº~àx_ÆÖZž‰e5¥ìK^ÚÙêwbïa-w%«–+4HؤÁ|Ø–=Í]o‰ì +h6¦án¾Ñä'›ö¯+ÏÝ´gÌò¿w¿=v|¹Î8Å{8…¬ßîc¦Ÿ +ß¶Ý:ö½·<¼Â8ºMÕ–·ûO¥¼úÞëº×kAwaáˆð¬þ û¦~ÿä:£r<4ŠJü6ø.1ÿTÏÃÿü‡Z,A䎙®nâ~ }<«Õý”ðþGÍTÍqiÛÚËÿæWÕõ Ü“ïƒú¦^ÿä*À»ñN™à|>ø2ý“ÿòhê#ÍF®gRˆ£JèŽS‚ÿŸ1ÿÀWù¼Ûÿ?¥ÿ?ó-Éâý8ÌðdÝ0ðïÿ!S?á1±aÇ€> ýáXxwÿ«ÎÊaf'­WöN þ|Çÿ_äCͱŸóú_øÿ3m¼cb¿ó üÿÃaáßþB¤2²'þDƒXÿ²aáßþB¬rõ¦2äõÅRʰ_óæø +ÿ"?µ±¿óú_øÿ3i¼ceÛÀ_¿ðØxsÿ¨ÿ„ÊÈ̃ðkÿ ‡‡ù +±ÑAJ]‚šÊp_óæø +ÿ!kcçôÿð'þfÊøÆÄ¯üˆ?¿ðØxwÿ¨ÿ„¾Èÿ̃ðkÿ ‡‡ù +±ÕvÒ“Oû'ÿ>aÿ€¯òͱ¿óúøÿ3[þû,ÿÈ…ðgÿ ‡‡ù +”x¾Ë?ò!|ÿÃaáßþB¬¯/4›0xÿ²p?óæø +ÿ!<Ûÿ?§ÿ?ó5Ç‹ìüÈ?¿ðØøwÿ¨>/²ó üÿÃaáßþB¬r0ivUdàçÌ?ðþDÿkc¿çôÿð'þf©ñ…—ý_ðØxwÿ¨>0³ó!|ÿÃaáßþB¬‚¹¤)Oû#ÿ>aÿ€¯òílwüþŸþÿÌ×0²'þDƒ?øl<;ÿÈT7Œ,‡üÈ?ðØxsÿ«a ¡ÅÙ8ùóükãçôÿð'þf«xÆÏ·€¾ ÿá°ðçÿ Ó-üÈ_ðØxsÿ«/hÏJd‘ŒúfìŒüù‡þ¿Èk7ÇÏéÿàOüÍoøMìÁÿ‘ àÏþòXƒÆV×À?Iÿ²aáÏþB®a¥‰všìœüù‡þ¿Èk7ÆÿÏéÿàOüζ鎹?¾ û¦>ÿä*—þ/þ‰÷Áü6>ÿä*ç-dØØõ­!×µ/ìœüù‡þ¿È¯íloüþ—þÿÌÕþÞÓO‡ßýÓÿòÿä*Í+ǵ*¨æ§û+ÿ>cÿ€¯òÍq¿óú_øÿ3CûKÿ¢{ðcÿ ‡ù +œ5Í+¿Ãσøl|;ÿÈUšTŠïéÚì¬üùþ¿È¿íLgüþ—þÿÌÒþÜÒèž|ÿÃcáßþB£ûsIÿ¢yð_ÿ ‡ù +³ÌyçšCÙX/ùóüÖkÿŸÒÿÀŸùšŸÛ:Gýσøl|;ÿÈTliôO> á±ðïÿ!VbœqKQý“‚ÿŸ1ÿÀWùûWÿ?eÿ?ó4†³¤ù§Ÿ?ðØøwÿ©F·¤gþIßÁü6ÿä*Ì¥àÔÿe`ÿçÌðþCY¦3þKÿæjgGÿ¢uð_ÿ ‡ù +­hÝ?á]|Ïý“ÿòeí uâ‘Î8§ý—‚ÿŸ1ÿÀWù f˜Ïùû/ü ÿ™¨u­Í;ø/ÿ†Çÿü…GöæŸù'?ðØøwÿ« ŸN½ª7}½GÔžSƒÿŸ1ÿÀWù³\güý—þÿÌÜ:æŠ?æ|ÿÃcáßþB¤~|?÷L|;ÿÈU‚&ÏJî<Ô<§ÿ>£ÿ€¯ò4Y®/þ~Ëÿæt«®hYÿ’sð[öL|;ÿÈU<¾€øÏ¿øl|=ÿÈUÈ›²;ÓâÔÌl9Åc,§ ÿ>£ÿ€¯ò7ŽiŠÿŸ²ûßù¬‡‡KsðÛà©õÿ‹eáïþB­ I|1#|ß > +Ÿû¦^ÿä:á Õçñ«öš±sœW<ò¬/üúÜ¿Èè†i‰ÿŸ’ûÙé:=‡ƒ®H|.ø(Oý“?ÿòtÞðDÉŸøUÏýÓMÿëÍt]wkœ~5ÛhÚÐ’5ù«žYfþ}ÇîGDs,Güü—ÞÎËÂßþø¦Xa¾øQðdĚ߇ò¾h6Éù¢¿ðÜh_ü‹_1øcS–- Q–Û4Wþt=pÃÄÚ9¹ Wö€ø‡™rðjnÓ¤LcÒ"w`ãœó_3ŽËa*òäŠI%ÐúLa5F<Òm¶úúfÃ7üÿ¢)ðÿ ƇÿÈ´Óû7üÏ>á¸Ð¿ù¹áã?Ù¿ò[>7à‚?þR×|Yø×¦|Q×-¼â{\ðlÂ4»ícOŠË…6ð´»×ìÐô˜Ê£÷kÂŽ¿xøØj­>HÁ¯Uc×ÄT©FîIú3èíödø ÿ‰¤‚ßXm¬q‰>è®±§öV™&ÔØ„]ò»ap2ìz“ZÚgì¯ðg]6Ÿû?ü¾Š <§’?‡~Uµ[< +z0íŽkå=kã7Œì¼=4°êf¸Ö‰”ýž3¸EÇðñÔÖï…>1ßxƒáƒéº×Š•}ýªoC(\ïQŒpo¯åÓ½[Ëš¦¤’ß±šÇ^|®û‘ô~¥û+üм–Ôgÿ‚61\Iå$’|;ðë)}¬Øù cÑOlq\ŸÅÙÛàfŸ†n­~ |‰ãÕæ"ø}¢¢È£IÔ¤ +ê-°ë¾4m¬ÜŠq•¼oÅï¼?ðÅ4ÍÅU¿þÕ¥†•ö`Ša1ž6ú~};× âoŒ^6Õ|3l%Ô ËíÓEþ 4dáõ¼üÏ +é`jW¶ßæg‡êGšQÃ=¥ßm™îvÞø7'_ƒ_?ðÚhü‰W¡økð]Ç?>ÿá´Ðù¾Òþ,|ElgPoü‹ÿ‰®‚ÏâÄ3ÿOcÿnÑñ5ù'ˆ«Aï/¿þ ýI€ð÷Qk_rÿäO¯ô_ƒ~ñ‡á-NÃöXøeaãéM¿†ç²øiá[ÈõiÔüðî…[Hв3­Ñ„¢ÛÜÛä˱‘|7øA±¬išÀošV« ß>i/Ãß \›yÑTºy–ðËݵ‚¹*êèÁYYFì‡û^蟳oÂ-CFÕCnð­Ô¢_6÷/’HU¸„c‘Ÿóf³âx#T»Ò<7âµM“ɰ¾‡Ik%»‹«ù3F¯`ᔂÃ8Ão5Ì>¯†Uiɶں置¶ß_éì|G äPÌ3)áq¡%':N*vvºmièý7>­¸øsðb1ÇÁ€ƒþé¦ÿÈ•Ä|Eýžþ |E×ÖO„ãµ>ÕÞHôÏiúS3.¥ "¸’Î(¥If•VDu‘²eÞÙù¯Rø­ñæÚ ?íÖ/þ&½3öNñw‰‡‚øÏ0È+ã>¥‡U£U¥+ßNW+lúó3Ìo ½Ö_ ZC,-:e¤„͸…<¨dbnHë¯h“öjøºç…_Gý·ðÇÿ.êý˜>/·O…?ð#Ãü»¬¡ ¶1PU*¶4i¯Ë¦¶Ñ3xË1‹º¦ï¯â­ø}Tõ8þÆŸ¾$øŸ_Ö<]௠øÊû\ŠX¤×4«KÆÑ­b·XRÚÍš-ðD0Ò`1>d®Ùè)­þÂ~Õ4™ôÄø…ñ6ËFÔíôäÖ´û}NÑb×î,aŽ.î­Œ¢S Š)|•ße·zëþË?ÿÉ,ø—ÿü3ÿ˺‚_ÙCã™ÇÂï‰CþÛøgÿ—u¢þÎWµH뿞û÷Õ·ë®ú˜µ˜8ò:NÖ¶Ý4ÑvÙmØàn¿dŸ ê“UOxöÏE‹ÅøÊ? [_Û&¨%Yžl}œÜ:I wh^fˆ<®êˆáY~Èøqâ˜n-‡§zùÎ×öKøÅáÉ8ÿ®þÿåÝz—ÿ„_¼5l‹sð¿â)eÆsqáß髚áÇK *‰¥Ñz%ù$—d’ZxhãeWÚU¦îúüÛüÛmõm·«;ßøHñOÅ ø¶âæõ5/ A}ogr ‚E»X–C *X"]¸aŒœç·œx'öÒ~ßè×Þø™ñ+Àwz~“‰|ú\šMÊkÖÐÏ,Ð ¨ïl.#O2‰ Xœ¬¥X¶oau࿈³I•øañúùðÿÿ-ªþ•áψvjü0øƒÿ:ÿ-kÈÁÇ ¤§&“G­R5ÜyTtðæ‰¿a‡¾-¾Ô.µ‡Ö5[mWTÖuKÛ ‹ˆþÍtu[%²º…‚ƯåyKò€ÁƒKð¯~ÇÚ.ÍΩñGâ—Šõm?M‹GÒuMRþÆ+ÝÍ'†i!†KKH7™Í¼ ,“‰euŒ ã-»êItÿ}£áÄOý<èü´¯øÁû>üVñ¼²›?†>q‰ü:ž°+ÙÀG/¦ÒçIY/’*û£î¯&×W/ bƒTé·våóníüÝ›ïe}‘óBþ˾Ó> i²øÇÇ/¤xw]»ñ•áÆÔ-ÿ²¬n®’án +â;£©˜,“?–[ùk•>mñ?ö7°Ñ¾köñW5ÛøFSÂz“y{aom¢Ø}ª |»wŠdÞ¢%Y¥’Bnfnkè[¯ØCãUÃ’>üFþºøkÿ—uYÿ`/ÿ4óâ/ýüð×ÿ.ëØöY;¦éªÉ]5¥ï¬y/ëË¢}ˆñ'ý¯-tíÑóéZúêyv»ðÃ÷›ëž-ñgеRÿK½ŸXÔ¥³[¿/M¹[›[U[Å +²‡'ïo:B\’¥[ãßAp_kø×¤ÝÁ<>5Ý)áçÄL×O òî²n¿à˜Ÿ//ðóâý÷á¯þ]×±„Ì2š:*Ñü¯^ûžn/›×ÑÑ󟈵?¶ÜsÍaÌO98¯§›þ [ñyºü:ø‡ÿ}xkÿ—tÇÿ‚S|]où§_ÿï¯ òî½xñ&WeY~?äx’áÌÕ»ûø™òÕÂä3Xº½žâHõáÿ‚Pü]?óN¾!ß^ÿåÝAsÿ•ø»:‘ÿ +óâÏû^ÿåÝh¸›+ÿŸËñÿ"Õ¬Óþ|¿ÃüÏ‹.­ü·éúÔ%3ÓŠûãþéñ‚g$xâ_ òò ÿ‡5üaøÿóðßÿ/)ÿ¬ÙWüÿ_ˆ¿Õ¬×þ|Ëðÿ3ä%LŒp‹ŠúïþÛñ‹?ò øûóð×ÿ/)ßðæÿŒ8ÿ‘ÇÿŸ†¿ùyOýgÊ¿çòüDøg5ÿŸ/ð>DUÛÒ—¾ºÿ‡7|aÿ¡ÇÿŸ†ÿùyHàß{xÇÿŸ†¿ùyOýgÊ¿çúüÈŸõc5ÿŸ/ðÿ3ä`™ì(1ûW×Cþßñˆù|Ÿ¯†¿ùyKÿqøÃÿBÿ? òòšâŒ«þ¯ÇüƒýXÍçÃü?Ìùу_]ÿÜ~0ÿЃãÿÏÃ_ü¼£þãñ‡þ„þ~ÿååëFUÿ?×õòõc5ÿŸðÿ3äJP¹õ×ü9Çãý>?üü5ÿËÊOøsÆú<Ï¿†¿ùyUþ´å_óý~?äKá|Ûþ|?ÃüÏ‘Hìi6 ××ðçŒ_ô xÿóð×ÿ/(ÿ‡8|aÿ¡Çÿùmòòõ§*ÿŸëñÿ!ªù¯üø‡ùŸ"l›}và߉ÿ‘ÇÿùmòòøswÆ/ú~ åµÿËÊ?ÖŒ«þ¯ÇüƒýWÍ¿çÃü?Ìù Ç“Ó4Ó;b¾¾ÿ‡7|bÿ¡âþ[_ü¼¦Ÿø#oÆ"ä@ñùü|5ÿËÊ?ÖŒ«þ¯ÇüƒýWÍçÃü?Ìøý“?Z@˜=këóÿjøÄOüˆ?üü5ÿËÊCÿhøÅÿBÄü¶¿ùyIñ>Sÿ?×ãþEÿ«¯üø‡ùŸ%@r­_µpÈ+êxÿàÐÿȃãóøøkÿ—•b/ø#¿Æ(Éÿ‹ñŸ òò“â|«þ¯ÇüŠ\1šÿχø™ò¾Ò¦¤ã5õXÿ‚B|aþIïÄøøkÿ—”åÿ‚CüaQÿ$óâýõá¯þ^RÿZ2¯ùþ¿òú³šÏ—ø™òª®ïƆL{WÕðèŒ#þiçÄ/ûëÃ_ü¼§âþ0cþIßÄ/ûëÃ_ü¼¥þ³å_óù~?äZá¬Óþ|¿ÃüÏ”¨+†¯«?áÑ_0âÝüBÿ¾¼5ÿËÊ?áÑqÿ$ïâýõá¯þ^RÿY²¿ùþ¿òá¼Óþ|¿ÀùYFA5õWü:3ã?äüBÿ¾¼5ÿËÊ?áÑŸ?èž|Bÿ¾¼3ÿËÊŸõ›+ÿŸËñÿ ÿV³OùòÿåB˜S1àúR"¾­ÿ‡Gü`ÿ¢uñ þúðÏÿ/)ü7ãÿšuñ þúðÏÿ/(ÿY²¿ùü¿òõo3ÿŸ/ð>SŠ]Á‡_à|‘ ÁÈÈ5®TsùúWÖïÿ}øÂßóO>!~~ÿååFßðGŒdÉ=ø…ùøgÿ—”¬¹_üþ_‰k‡s?ùòÿäG—œƒQ½Ïs_\IÿløÇ!ÿ’ñ~>ÿååDßðFoŒÄñàˆ?ùlÿòò¥ñUÿ?—ãþE.Ì×ü¹‡ùŸ'E·ð«Pj›OZú”Á~3ÿ"Äü¶ùyN_ø#?Æeÿšñóð×ÿ/+9qVÿåòüMcf_óåþÍšnµå¸æ» ø‹¿Zöˆ¿àŽ?ã#þ-ÿÄÏÃ?ü¼­=;þ #ñšÄ‚~|Clz7†Gþç+ gÙcÿ—ÈÞ&b·¤ÎÃ>&Ž+k«[ƒr,õ(’ÞÖ_*æ’Ç4rÄä²Ç4QH„‚»£\©ª[Ó¦Û»WÑf| ÒOàIüÉvo+\Ž<žû#EôQÒ»[ø&7Æ+D¾|FlÓO òò´aÿ‚oü^ŒóðÃâAÿ¶¾ÿååy˜Œ~UV\þÙ'äÚ=,> 3¥EIµæ“8µ >AƧáßü!/?ù ©å†ä'áÏü!/?ù^‰ü·âêÍ.ø“ÿ|1ÿËÊ™àžßÇ_…Ÿýµð¿ÿ/+ârßùÿÿ“3²43ùóø#Î`Ô­71Í­h—)syöЯàK!o³[[m\k íÙiù‰;‹à€—Zc G@?÷#]ÿòþ½Á>¾-ù¥ÿïï…ÿùyKÿüø´ü’¿‰÷ûÂÿü¼¬}¾Z´U¿òfl©f/z_‚<äO¦š‡ÿð†»ÿåõVÕm-u?±uíÐYÜÉsµ<rË9{K›R¯tœywR´ƒ¸/$¨ø'ÿÅ sÿ +«â_ýþð¿ÿ/*Eý~,¯üÒŸ‰÷ûÂÿü¼®|CË+AÓ©Vñ{®ftajf˜jªµv’ÙÙK§xÈ·^ðà?ö ]òþ¶­|N5ß ãþįþ_W¤Û~¿mÏü’‰§þÛx_ÿ—•~Ø·â¼CþIÄãÿmü/ÿËÊñeÃü7-ÒûÙô°ã>,ÃRKä¿ÈòÃàèè=áÏü ®¿ù}Cx6þÞðßþW_ü¾¯Yÿ†5ø«ÿD‹âþx[ÿ—”ÃüUÿ¢Cñ?ÿ<-ÿËÊÏý[áŸåÞÍ×n-ÿŸ²û—ù9uðÚ ¡Î¿á‘ÿrßÿ/«K@ðõƒÖy`¼MJþîͬXô‘¦[YÛ´ÑM"C ¸¸´’A;É3dAª _Ô¿áŽ>*ÿÑ!øŸŸúøð·ÿ/+—ñ÷Âo|.Ô`°ñ?†QŽ3ï_“:Dñ‚:!ÿª gÿ¨luú}ñgÑô}nöÓK¿Öî­ažxtë&…noÝU™aˆÍ$q €ªd‘,7:Œ°èÎióЦ–þÏO[Ù#j¥ñŸ%þÇŸðU­gãoÀK/x“ã_Àk«ëÄÑ öƒá¯ ]\Þø^{ëØmþÉx©¬Ï)yO!¢„G#yެ¨Ñ×§øþ +££é^Ôµ/ È5ãèZu‡†ü;¨ëwZ^¥=¨¸kkD¸ŸjF™¦Ú"W•AÙ½ùoÁ?ÙÿÄÿ?d¯|Ö¼ñ#áý·íô•ñOˆ#Ð&¶ÔŸJÔl®D o§ê÷R¤“ß" Ĺ!Qãø¥ÿƒ°ñüº> u?‡úö­¢ø‡ÄÚ¼vþ8ð ~&Ñ%·ÖïþÚðµ“]Bë<±*\$ë%2$Âù“¥&©ÆëÞ_/rÏ]™jô_Ò¹Si¶õæ¿ý»Ë/–ü½;i»>ØÒ~6[kÚUµõ“›»;Ø’x'ˆ‡ŽhØWR ‚ê Iwñ…,m%žTc… ¹Ùœ2{×+à¯Â)àÝ'KòôØ¿³l¡µÙ¦Ù}ŠÍ<´UÄ0n*!–=íµp7fâØ¥Ò<)©ÝÁ¤^ëÓÚÚK4ze›@·‹* ŒÏ$p‡r6©–DL°Üê2F•ðôýåKÎ×ü.rÒœíi¾—ýOŸ<5ûü\_‡þøÃ­Zø/…>/Ô´ô‡ÃpéwQkúV™¨\Eoi}.¢÷~D²:¥¶qìYghƒKè°ÁX>ßxºûB´ÖõËíOO½Ôt¹ÛÃ:œÐÉ`&7:|s$)oU`•ÖÕ¦‘tGVV?%øcá¿Æ-Kð÷‚/>|jºø7á JÛQÒ'h峂EŒŽÒ)Z8!G™ñ)›¿ý”ÿd?øÄWZ‡Šõßì¯xwâ§Š¼Q¦ønOKi©ÝO&¥¨Ço;ÞµÆÙ,Ú;=mƒ3ÛÎhþCÍ**IÂ’¶«î—¸•ÞÍë'k;½.£ko7h:ÝÞÚlô›ÓªÖ1^Iìå{úwìõÿ`ðÿÇo‡~ñ¦¡z¾Óø‹¤k^'¸“ÃÐ[^é}.ÊÚËIÕbÔ¼³l÷“»Ï<ˆÊòùÁy{"]®$ߨÁÍ$­¾IÊ^nö\º_K»JVQ J)&ÝßÝxÛðæ~©]+»zu¿üOá烶 ¼ñ…ÀËø}´¸|¬É®Ç~–âåàm-mò‘’в¶vO°Ù|b[û8gŽÅIÐH¢HLN•°Ê}AŽ„WÉÿàú¿Ä›ŸˆWZ'м+¦j>;ñ%¿ˆ ½Õ¼1u}wá·‡HƒMa=®£g5½Øò ‹r’)Q#& côo†ü&Þðí…„—wzŒ–VÑÛµÕӞ䢅2H@»c$€9&Št âÜÕŸ»ÿ¤ûßt´^]÷2œšk•Ý;ßË]Ý׺é±ÓOñhŰŠ|ª’>Qþ5ñ'†?à»^ñ_ì…ðó]²ñï ߌ>*¹ðíž¡áKmn &‚kÝFÒÞö(ìÅѹWŠ)¦`¬IB€°`?Xøµ'Ñ|)©ÞZiwúÝÕ¥¤³C§Y4+s~ꄬ1¤Ž!#L’"e†çQ–Ùø ÇÖŸ±/þÿ‡øäÇÁ§@?Úûü>Ùý—}kwþ£þ?“Íû6Ïõ³~~l`ÌhÁT¼–—‡ÝÌù¿ _¿CHOÝ×sè?Úþ +§áŸ|6ø¥ÿ•ÅÖ£ãxwYÔlÍö¨ òûO¶’I-VûbZÜI¦Ù`‚àÊž\ …1¾Ýˆ¿àªŸ ´ÏÃáM[]¼ƒÄð\éúv§:ô–ZUåì0KkÅÒÄÖöâ´F±4ÒªÈ䢳::Ÿþñae¬|T].ïáe­ÄË¢ë £›ÆZTšÄS @Öò?:åžB±½¸sØŒœ¦xGö1ñÏÄß´«¿ü6½ñ‡‡¯nígðÔ¦óÄ‘Øi;†²¾ûB$P¼öÆ)¿s>DnŠÑ8-SBŠn*qÞ1oÉóZJý4ke-´N̪­kÈôNvó^ç%ÿòm4ókCî¯øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èko«ÒìaÏ#oþ¿ý3ŸþùãGü-úg?ýò?Ʊ?²G¡£û$z>¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èhú½.ÁÏ#oþ¿ý3ŸþùãGü-úg?ýò?Ʊ?²G¡£û$z>¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èhú½.ÁÏ#oþ¿ý3ŸþùãGü-úg?ýò?Ʊ?²G¡£û$z>¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èhú½.ÁÏ#oþ¿ý3ŸþùãGü-úg?ýò?Ʊ?²G¡£û$z>¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èhú½.ÁÏ#oþ¿ý3ŸþùãGü-úg?ýò?Ʊ?²G¡£û$z>¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èhú½.ÁÏ#oþ¿ý3ŸþùãGü-úg?ýò?Ʊ?²G¡£û$z>¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èhú½.ÁÏ#oþ¿ý3ŸþùãGü-úg?ýò?Ʊ?²G¡£û$z>¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èhú½.ÁÏ#oþ¿ý3ŸþùãGü-úg?ýò?Ʊ?²G¡£û$z>¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èhú½.ÁÏ#oþ¿ý3Ÿþùã_$ÁG¼Mÿ /ůIµ×Êðo‰—æëªø[Þ¾œþɆ¾Wÿ‚ƒZý›â§‚G¯ƒ¼Kÿ§_ WVŒ#ˆƒŠêqæVûŠŸðp Ïíð—þɼú~Öè¤ÿ‚ÿÿÉÀü%ÿ²oþŸµº*qÇŸ«üÌ0ßÁ‡¢üÑ=<þÀúÇüÐK?ýC£¯&ÿ‡“ük=&ÒGýÉÚ9ÿÛZ©'íëñÚ6Çü$ú_þšGÿ#T×þ;Î.¢ ñĘÍx}²˜Üg8ªþÁÉm«SÿÀWù ûk6½¾±?ü ÿ™Y¿oo';|M¤qëàí í­'ü7íÇåñˆAõðŽ?öÒ¶!ð“Üû…o¤‚®Ûü4iüyÇ_0c,—$[á¡ÿ€Çüc›æïjóÿÀ¥þg;íÓûCgþCÚ{ é?ü‰W"ý¼þ>›©hoþï…4¾òV·[áCgÂSž„L8¤Ÿà쓯méÿvàT¬§"_óüäSÌó‡ÿ/çÿKüÌAÿøÓoþ¾ûIO +éü‹SÛÁH>*“ûÝKMO é_ü‹MÔþLU™tÍ`ýÙ³ý+ž¾øC-¤˜6^ Sê$ÈþU×K(ÉØz_ø?Èåži›'­zŸøÿÌí,¿à¢_¦ÆýcM\ÿÔ¯¥qÿ’Õ£íçñíÏéQ“Üø[I äµpZÃö@0¾"B8ÆÊ·ô‡ó°:Ñí@§?¥:™FK«SÿÀ#ÿÈ…<Ó6oýâ§þ/ó:{?Û#â¥ì‹·ÅÚ Rz é?ü[Ö_µÅk…|Oáù8ÉÏ…´±Ÿü—¬¯|8—†Þœ~Ùk®±ðe¼Q’'lúÀ£5äWÂe1vŽŸþ ‡ÿ"zT1Y›W–"§þ/ó+CûS|MŒâ]_FouðΘ?öÞ§“ö”ø—0uÝ:<úxgJãóµ5a|a#€Ð Ž;-lèþ°vÛäyš¸gC+Š¿Õ©ÿàÿ#²ŒÅéõ‰ÿàrÿ3–o®I1x¦Éoø¥tvÿÛJ|¾3\ÆšZ“Ù¼¤ý·ê:WÃûÇð–¶-¾XGÉÔGçÔ«–Å醧ÿ‚áþGd!˜=ñÿÀåþg“Zxëãdã'Ç>ìþÒ—?•½gj?¾7é®@ño…¥×ÂúZçÿ%«Ü[À°Æ„¢Êo˜Vuï€çœü‘HÃÝÅE:ù}õÃRÿÁpÿ"çKm1?ð9ÿ™à×´÷Æ­=þ}oÃrýÏ i|ÿäµYÓ?kO‹3¶Ù/´F>ÞÓ?ù½‚_„÷³ô²õ‘ªÓcøG¨Br4˜[þÿ]®¾PÕž—þò9}žfž˜ŠŸø¿ÌóX?iŠÊûžÿFt=‡‡4°GþKÕ=sö´øeÍö™?‰|7¥·èmÍzü? u4:dwÇ—Ïè* ß\¤Má¥p}Je +™O6¸ZOþ݇ù(æVÿx©ÿKüÏÓ¿lˆ³Ì¾%°E?õ*i'ù-]¿†hj›Kø«Glö ikü­ë¡—@ŠÄþó§ýñ¨†³¤Ø¯á¨â#®JºÔòê‹÷xH/HÓÿ"iTÇÁûø™üå?ó7´/‹¾'um_Ã×÷°Ê].™ñgU¹pŽ46õeÑlùÿÈUÀxx}ý¦}þ„V¾…¯èÈ V³DÞoþ*¼šÙf«ý^+þÝèztsEíí›ÿ·¥úž„¾#ÖïcÝ èËŸMÈŸýP\]x¹ù†}#Ÿú€Øý£SøVæÆ`¾[0³?zÏÃÿ xzñ“ûBDç¨Þ¸þy¯Ä¼>_cÿn/ò=¬;ÄWÑU’ÿ·™áz­×Ä{uÌ- ã±Yý¥\þ§â‹ÖÈZßþ9}ŸÃÖcÿiWÜv<q€ÑGA3ú­©|ð]Ø-2†ì. ÁKˆ°1vž?:q;jd¸¹+Ç/ü ŸžúïÆoŽ!8Ð|/tx´;Nò r·ÿµÿÆ*R²ø;F`:ŸøG혋úWß¾6ýž¼?m†Ô<¬9¼'ʼ—]øIc ¬$´˜(î _K€Î²Š«ÞÁÓöê_©àâò¼Î›Ó5ÿo6|«í¥ñ†wÇü!úHÓA´þ°×Cáïڛⶥ"ùÞÒ"¨Ú?{½·Â½.9FdçþzµzÂïÙçI×Iq=¡ä¸9ýV¶ÆæÙ5(s}Jšÿ·L°¹~kR|¿Z›ÿ·ü7ñoÇúÂþÿJРϦ‹gŸÈÃ]øƒÇ3Æ +/‡ÐŸïhüj¾¾Ó?g_ é1)”]9åç?Ð +¹7¿1Û$I1þ¹ý+äjñ\åû¼,mþ}-<——¿ˆ—þχµÏ|R±RÖ°øVofЭ?¤USFø£ñ& ÂêO†Xgªhö£ÿhŠû­gj#t1\m=6\±­r_¿g½Ãú[\XÍv²ÂI&à%­¨q[Qªo ¿î%ùUÉs/h±·ø™óîƒãÍ^òܽ7C‰‡]ºU§?ù +¯Μ5¦Œ?îkÿÆêÆ«¦,RÁ$qXÚŒ_a‰£y6Œà šô 7uJ+äŽ'‰ÄÃGR_{-Mã«•p’z6‘h?öE{ãíBÆDéúj,‡†]чþŠæ¼gâg5MCZŠÎÎÓP„3cÍX‰ ïšú#àgìû¬x£áͭƣ⻠lݲñÎàM8Éàsõ®œn_ƒÂQjÑŠO¥µü†‹ÄÕt©JNÞæÊÚn­w$(ÑiQ´øØÇE´*Ù÷òºUjº§‡µsg,lSžˆú #óнÄü¶Ò´]:+ÏÃ%¬ƒìÓ˜ãôßžGÖ¹Œ^øãJ±¹ñM¬«4dCª@bà1Sƒø×ÏáñX*•l¡kö{Û¿zûjµ \)ÝÎWÓíwÿ·Õ>5ê^4_ˆtÏíEA)‹ûÏæBÍþ§Ú±¬?hMWVñEönºlšŽž7M +èV'o`?Ô÷"ºo|·ñGÆÐƒÇvZ5ölɰÛDwkÇÊAã½sþø!§ë¼C;øêÇB–Ö5&é@‘uLpvöíž9æ¾®• «Ù¹:qºŠ[ÿ‡gåªê|åJù—:Šœ­Ío‹¥¿Å¿®¡©þÒ~3oO¥išž¡- âdЬ„q’>î|œëQÚþÐßooÚÝ|9§#Ú´K ª=IòkÑ>ü6MNË^¼oÃbÖìY3é.Ý2që\懦jú´Ò»^Ϊpoâ÷Àâº# µ¹F8zw·_¹# TÇ¥J¼õóé÷ÜÜÑ|SâélÔ\¶çXÅBû©«ÏâEiҹ캀ú&°µo4ó4'»08`KñoM{ƒ kÐÉ!ê‚L…sG,§SXчþ¿ÈèyHhêËÿæmëß|E¤‰{ßجc8}Á˜ÿäóŸþØZ•ŒÅ5ÿ[¼gŸØ3ÃÉÇó®ÖÒÇBñB¶8¸^¸VëùVŒ~xؼ“ildÇPMzL&[rÖæü¡ÕXœV>Qæ¥]¥ç)~Œó‹Û»]‚Ï`ñ>„ó±Àsá½4øyùUI¿nØYücáöy9-Þ\mq·V›o8WÀ?¨¬°yvQZ4¿ëÜ?ÈÓÄáàïV£õòævú×ímã26±£³(ûÒh:P'ðõç~"ý½~)Ãvëk­h1 <á½)þ“Wêúóý·lºEÙþ7É?­už±Óõè‘fÓ¯à~ÅJúº|9•Ñ=L59Û‘ÿ#ç'Ÿf5eË D×ý¿/ó;]öÁøç¯8û>¹¢0>¾Ò@ù+]®ƒñãæ²€¿‰¼5}|/¤Ÿýµ«?|/¡ØÅ{=Eˆë¼°Ízž‹ká¨QÐÙOûXþ¦¾w¶›j–Ÿþ ‰îàç˜M'S?üG ~5¤{¦ñ®ÿð–’öÚ¨êÿ>+éKx¿Lr=<%¤sÿ’Õëò^è  wÈÿæ¼W«øwÈo1;væÑú¤¥®Ÿþ ‡ùÕ^&1Ó?ü/ó1ÑÓÁú7ÿ"Õ†:l–êF•©+{ÄjÌŸ +´ò€ÿfê ÿÅ?õW+[Їþ¿È_ëcÒ´ÿð'þdËÿ(øæ½|]¤·ýÉú(ÿÛJê>þÓ8ý¡¾2êŸð™ê¶º§ö?‚µ±˜t‹-?Ëóum~~Í {óå§ÞÎ1Æ2sÁê4Û`sitŸïWOû.i6º_Æp[#¦ÿÞîÝß¶ŠòsþÀá°ÄP¥ÓŽª)=g½C(Ïq˜Œ\hÖ©&š–ŽM¯…½®|‹ÿþ9ý >ÿÙ7ÿOÚÝŸð_Ñÿ ?ì›Çÿ§ínŠü?¿?ñ?Ìýo üz/Èý Ðø'æˆ{ÿ„³ÿÔ::ñÍëTVÐÜšö}1ÿ÷ÑýPK?ýC㯑,u›øÿåþ@l×ìž.juþZûqù?»TOûõ?öÓÞìïuJZƒëš’ãW½RØþuâðk·á?ä)(þ÷ÿ^£»ñê§:¤ÇþÿׯÐ^«·õó>Ibú/ëð=Vã^¾/"Ûð''ô¤‹X¼,7[ÛÜä׌Íâ;²Ù7ó«õéÐx–ë?ñý>¿ÿ^š£ ¿¯Ì^Ö[ÿ_‘íÐÝÜÊ2mmÎzáŽ)Æ[•q{àšò?\ é·#ß"®Íÿë¿ÀŠTêšÖz4ÏT77`qi“Ó©¨®.î˜íûŸ^OøW›Áñ&X››Ûæ¾EiÙüYD =ÅñüECµµŸÞZ®ž÷GCwu{`,¤ãï¨.õ)IÎOûèÓì~.Y•ÚåÇ|ã5§mñsL)€·îŠ-V?òîázoyØç.ÓTw9·¸Áí¼Ôú|šžõÛg9ŽMm?Æ=4ˆn!@øÑ`¤b ŒÙáTåY«{!%I;ûCOC¹Ôèr1÷×Oc}°°TÍq°|r¶ˆ‚!ºýáþ·´’[¡ Ð?QþçÕÂןü»;)â(Å|g¢Yê—†ëücâº}TÊ‚m@õø×ƒ/íBÉ!Ä7$tûËþ«gûI}¼`Ct3ÇÞ_ð®:¹]ym÷PÌ(Çy~¾iÆéƒm=vŸãYz»Z²Ö0¹?ôÍ?øªòø\×7h ‘ßïYšÇÅ{¼‘º|úy¦°¥“V¹¬óJV=ŠÐÚ3cû:÷SÿŠ­Í7MŠä¶°&G/øõ|åkñJõ¥99êd5ÚxCÇšØ@½:üÎj±9Uh+ÜT3 +rv±íÉáâS;`Àí…ÿ⪵þ—$*HŽé½þÍ\þ¯ÞßÂyz}ãZ2@.cÃÇhùõzñ]9ÆV“=U8ÉhŠ:„—òqkjùéþ•þf¥ÒõëØcO³aêob¬ÍGE·YK]+=>iVckgöz#ûÓGþÓËUÿ¯SJJ_×ù øªðÍŠúýü+qüiq6Ö\ÓìuÅè×Ú| +•áåÿ©þB®]øƒL†2 ðøú©?ÉkÉ©‡R—Ãùÿ™éS®Ô~/ëî.jŸní[ÞÏiôÔ¢.ñ2úù†c‰sÓ¨ßʸSÅ6m7îÿ°0?»líÿ²ÔÚG‹áßbƒc´qÒº<šCó1X¹sk?ÈõÍ/Åww>t_ûn i¦·tÃ?i#èõæÚˆà˜€nÊUŒ¯ô­í 9zßÜ€}$ÅyU0zíøŒ1Zoø³x–ñNëþý2ç_¹š/žðž;½q±6’Ì ÞÞ}.­áï#2]_1éÅËÿCÃEtqJ¼Ÿ_ćŚùëÀ ÿošò/øŽEv1Þ¶}ÿZ½+WÒü/yüÒÄÜ9ÿÙ«œÕ¼!á™Ûg3c©iÿZöp§N׋û—ùž^25'³_{<€øÖé§Úg˜¨=wõ«ºð/ŠÙÌa¤v=zÓu xzݾK‘Ó,Ʊ§Ò¡…ÿÑ!(G`ǧç^äçJ´l£cÈ„jR•Û¹ïÞ ñ1 +Ÿ1ÇûدMð¿‹„AwHBžá‡øWÈVw·aV;~†¦»Ö5R;Ì·ëç±9j¿ŠÇ¹C8tÖÇÛð›[,`yîOûËþoLñ½¡œ¤¿^…Ôìµùë­Þk2á#¼ÏûÌjÿ„ìµ™çLÃw’{–?Ò¹'ÁôÔ9U÷Á:#Äós²§øÿÀ?L4O$ña&“ Çþ"­ÜùWk†,ßVÿd¯ˆ|£ê{PIÂìxý+Ò´/ºÄ¦eŸž™&¾_ÃÐ¥+ªŸ‡üèpùÔêGX~?ð¢­ôˆZ|„OËÿ°®“HœéÈ6+ÿÀ\ä•Â|ýŸ4ïÙCs|—*‡“‰‚ŒW°ÛüðÖ“fÕ®lÈÿ–©qÉüø¯”Ç×ÃÓŸ²rmúÁ>‹F½HûE—¯üñ?Šˆ€™%1€:1-üã5çZ¯‹îñæD@?Åâòz÷‰¾ øu#Ý{âRÕ_¦ëõP~œW«|ð´âIüg|¡¹çQZ׉Â%­þQfxº–ú}è‡À7h%Q¨cÆDXÏþB¯A—Å7×ö%1¹Hä<@ý\¿„þx܃mâÛÙdc…Æ¢þUÛ¯Â=#û7ËMwXPÝ$þÑ9?Ò¸ñµ°®¥Ò8XJX… 6¾Lù÷âªdjrÍÊ€œýIØYü"ðž“à[¤×ïVK† Ë5êÏu('X—8üXbºq˜ú³6®ß 9ð¸:ÑÒVÓÍÖ§~c€¤ŠÞK WÎß¼‡â‡‹oþÊoâ[KIvÙ&Á“?Åǧ־Ý_ÙëÁ:}¶Ÿj|á=Ù_–[’ÒJ1’Ï^ÕÆ|Xøà]?â…¢ÍC¦_†7PÙ·sÆâÇ +§üŠóòî ª¼®kVôÝ/žýŽÜvKˆtӯWò>‡ãV›¬ÉjóŸ7GÔwŸÌV‘8ùÈçqŠ»c¡¬zÒF2ÚÜÉç%°$´]ó•àßœö‹ÿÙ7áNƒû_¾‰a€Ñ.-<éíÍàHÕÈ';ŽG$c¥j|6ýš¾ø»ãÖ·¡ß½ŒÖúf²Î R[p[Œ>Alõëé_]W<ÁBô£5E/‡£Û®ýÿ¤|Õ<£)òÔqo›—~«~›Ç‚õm.Êé-'¿†Öfùй$¨ööúWqâ?h>Ò +ÿkÛ(Ç.XªŸ©Ç5Ù|øàMsPñ,WâÄÓ¥dµ‘î¿x©Ï8'éíY_þøRø-ªêKsíõ»M*© *yÎ+æêæZ˜• sî–Ë®ßÓ=Úx,D(9Ç—g×±à¾/ø‘¦ø€K¦±§Ü†ùqÈ&¾mø¯ð—PÓuïí8šáIݼÿã^añãÅ÷¾ø‘rt°Ög”…ÃpÃ?•{‡ìÍûAÃñVÁl53ºQƒ ½~£G<ºš­‡|ѵÚ{ÙŸžÕÅÃ?eYr»èÍ¿€~"½y£Ç†€ÿ…z‹íg¿Ñd +Ûþ\Ÿ—¶¼ðšÄÝ Ö$ŽAÎÚô¸þè3x&âyå„_FØXšp¤aÞ¾O0ͨûuR+©ô¸¶¯±p“>ñ–Ÿ-¦¯'ÈÒÆ[,ä½ত` ³F8Ø3^«ãŸ…¹ˆÉ:A¹ä‹’§ù×ÿ Ô?ƺ¿ +~Í> ±µß,qÆg¯³©ÄhÁ«?»þ òÐÉkÊ[¯¼ðÃsr"æiG·˜kšñ&­qnå„Ó.=×ÖÒ|ðØwm¿ë¾+™ñ7ìéà©a Ê óŸô¼:æÃq›X¿»þ ½l—Ë£_yòƒ|@¼ð/.}>ûÅ×WdæêvÜ;»{ýÿìÍàY';CñýÛÐG󫳂c„¾ËœŽ„Üq^öæjâþïø'öEw¥×Þ|íÌ÷÷ߓݛük¥ðÎs4€€wËŸñ¯m›övðUµlÊ­ên1Чwð_Âön·¹¹Œõù/Ï0óVŠwüG)­y5÷ÿÀ8» \\ãt9_þ½tZ‡%…À1qüê–­àM6Í¿wªjÊ<_týj¥ž…¹5½iGý~œÖ°œý¢Ò_´!Èõ_‰ß[é3$|®Ðr*Ž«HŽHô3ò—þ’Ï„¿ààÚá/ý“xÿôý­ÑKÿ ~Ð_ ì›Çÿ§ínŠþ~Åÿâ™ûFøô_‘úM )ðOMÓþ%Ÿþ¡ñ×Ç6:L%‡ï¾ËÐ#ÏüÃC<ɳÿÔ>:øºÁàF·Ã5û7‡–åÿ–ŸþÜ~MÅ×çVþzŸûi¿o£Û˜ù•GáUõ 2Ò18}Iiuff99ö͆ȮE¼Íøb¿Ri5ÐødÚzÜÆ–ÂØ?þ•5¦—c÷¸­XÙì“=Mii¶ö`4÷obâ°%}‘¬ª;n6ËÑIŒLë÷…X“ÂJ™Ðgý±[šMÕ¬GþAß4‚®\ëö‚•‚çþ›VŽMh£ù•ÕÛüÎLøV0Ãý&þ°þ*Oú½=àDšhñ¤1??`HÉÅkd .á§x_Ÿ4`ÿ²Õ¢¾X—"x€£ÿ¯QÚ|B…:p?»n9«üPŠøˆéû?­a)WèZTz•›Á‘«×¢ýiSÂvèrn¿‚ªÞ|\à…ÉéÐ +Ï›â•Ü€ˆáÇãšjUº¿ëîZ}»q¡YÅÅÌ?êúþ•¬Á¶Í3ÜEÿÖª—Þ<¾ºLÝöȬ]GÄSr3ZFN +òd¸©l‰Þà‰psÏA[:CÎÅvý°šãT™¦æåÿ +×Óõ ‰¿¸?Bh§YKD¤ÑÜÛÍp± ¥Ñú·WP¹g°*}ÍfZE5ìg/âMSÔ¬¾Ï÷¤ÇÔÖª ;™ó¶K;ÄŠ`KŒƒêk¹ð–½•Ã1àò«…%‘I®÷Á·öi´ŽG V¨)Bæ¸y8ÎǰøkQbü®Þùÿë×QÛÍÌÇß¿ë\/†õ[2™$ükª¶ñœPåõõ`3_!‰¥.m>š„Õµd·–Œã6¶~­hèš&Ÿ3ô ^}S&°.|gm™X#üóý*Ö•ãHîf\&Ð?º¿ýjÂtªòõ5…J|Ç£hÞ´@6ÙÛ¤Bµ[D„§Ë KôUÒ°<3âe•ï‘îEt+¨4©•BþµxU¹Ôµ=šN:ot´„tAÿÿX÷kµ°®sž_Õî.±}s÷"嘩ãê@þdÖôbÚÕ˜Ö’¾ˆ±<Àdyœw±þµVk¥ +~f#Ø +H¬®$~ ¦Ë¦KŽ[×âEt¤»œí²¥Î¬¶ã%]}3ÿÖ¬‹Ï<“;/>µ¥£™²q»Ógù¡/†ÝTœNû˜þx®ªjžìçŸ?B1âû‹`@D—ݳþ4’üA¹,¬ØPÄŸÖ©^[‹W ÆÍŽ£v•L¿ít›r¢Ê"〠ÁþUÑì¢þ\ÇÚ5¼¬V¸ø©4ŸºÒírxm‹V§‡¼]â;™Í*5?õÀ'ó5ƒ}ñ†q'îá¶‹'ŒŸéQÛüYÔ®d \m?v€:ÖXY8ÿ /VgDT¾6zÞ•¯ø•ãílÑqŸœò?#TµÿŠú¾ŠÅZ×N$wÙŸækÏãñŽ¥}ÍsrÀžò?!T5™çž"ÌÊ:ãq5Å º<ÿ¼Hëž:\¾ãgA©~Óº¾)Ì:r ÿ c4º?íC«ê7~Ј÷SÿÕ^=â»MîìÓ…+Ó,Eáak”Ý,’œôäÿŸÊ½ŸìŒ#§Íȯèy_ÚxŸinf}IáÿŒW·áKÜÊÇÇú×e¥ü@¹¿URÌØ÷¯øwl„Ä:|ƽÃÂ-¡D-áÔöñ¹•4ž‘>£V­E«54ïÞË€²ºMƶâ×õ%¶Ý!¹xÏ®q^£ðj_‡þ´Ž}`Xñ²!“iút¯^‡âŸÃÍFÍcóô†‡ШðÅ|77têr„šïý#ìp™gÇ¿|k­Gk ´Ši\”Wˆj^(ø…¨ß´m ¶ˆž˜ÃükôÓÆzÏÂ;±çÞC¦ÌßôÂ<ùb¼ëSñ—Á>üË4Š0Eüœ×³•ñ7$,°’oÓüÏ+0È9¥w‰IzŸ(ü1—íw÷,:ü»Ÿ­{.w©íBe +2 Áú×´øSâÇÁÈ& ßÉ3Cæü9¯I°ø«ðòçOË}&8 ·PGáŽ+ÌÌø‚¬§ªÉ|C’ÓŒmõ„þgÅÞ?Ö5©’B×wQ…,Üþ¿á_"þÐ ñ„’Ç kû‘£ –O÷›? +ëü;ñ/áÄ ²Ó¬l­RöYL’y%P2ÿtw>æ¾»1ÏÝZ.ŸÕ½tûÏ™ÀäÊU?¬- _j·÷q^;ÊGßÉ8>‚²<{u©Hd¹saÌIfô"¾„×þ)ü<Ô4? i–ЧÙ-¤ŽYRÚ±€!¸ùsÿ¾+øóâ‡ÁK¥i«ºàB¡UÇP qœWæøl¤«/Ü5{ôè¿Ìûªø*q¤ÿ|žß{ÿ#៉^½?Y¥Ü5;„D %ÃmŸîôæ¦ø}<÷^8½œÀ‚ù%0I œmèåþéìŸ?h‡¿í¦’m ¢[é¨Ï +:¡Ü[;ƇöøÑðÎÚÇ)¨!—L’e’Ú2Àã*@>äw¯¸xüGÕ¥BWTÔ¾ö•’X:?Y´k-f×ܯs_Àq©—ÏFxäa¶Lž‡ßŽjï‹‹YÛHû•󜟟ʽöñ¯V×âÕ"ŽHßz[où°¹$fÁûUOx£Â·?5Ý2h ÔcrÖ’žY—=¸ú×ÉË?¬¸ºrÝ}ÏüºŸG4=‡2šëø™ñÆOxGÄÚìÖú…¥™y‰ ñ¾[èG៥x>¹ð“Pøã(u}I¥Ò‹eY_xÜŸÌVoí5âÛË/Þ¥µåÊ­´Çc,„2óë^ƒû)þÒ6>6Hü3âÏ-Ìß»ŠêcòKìÙèÕúÕ8Ë ¿MW——ù›ÉƼä¾t~~gÕ³'Ç _øfÍ$7 e8éØô5êºÆ³ÙY‹1P=+ɾüƒáõóÜéLZÎrÄ9U¯aÆŸ†š)¬í¤òãÓ¯ÎsUAâð鸷·cî2çYPQ¬õGŒ|NñŒ;LªQ¿é™9ü«Á|_¯hð]Rñg$¤ƒúf¾œñ¯‰tT²"æÑA«ã^kâMgÁºª$óXž3€Ùð!ȯ¢Êq‰^ù3Ą̈s¿|Ï3ðwŒ,#ºXV`Tö!¿­{‡ÃífÎ[UèWýFk•ðøðÙk…Ó¢Æqæ ¬?ï¡Ïç^‘àË?˧††@za†Ú¬× /‚Kî]BQbëZµœ6§22¯û§¨¯ø§­Y¬d$ñóÐm þ†½îý´È´ò¾A`=5æ¿.¼95»›8‹/÷°§ó®,²²S¿+qÓ˜SnæGÏCÄ©ñÌgôçʽÀž)¶H0ÙÜÍ2Y|#ß˜Ö +9îF?:í¼ÿĶ!à·ØІô˜ÌL]?ž„”þ4G'ˆtù­H`Œ1ÔÄÃü+Šñšéw‘»¿¸ä:õ‡ŸDŠÀ…F=@\×+â½SÃâ ÒYFÅG¢œþ5æákZ~ìY߉£xë$xV­ ÛÍ9òofSýÝàŠ-ô å‹÷W®àî•躷…Þ}ÇO‡>çi«úm÷†c·ßö6Q鑊úŽšÂþäx‹ /‰U¨Øë±Gò¼ì¿ì½sºÓëDD‹spM{ôþ"ðÕ½¶<©cü«/Uñg†#·É”/l:ŽkJ9”ïü/Àš¸µüCæjöý]·™—ê fC©Þ#‘æÉ_Aëž/ðÛâÖ\ûý+*-oÂòÉ–³±S]þÞrו£‹ØÂ:s&xújθ!Ù¦Éw{Œ¸ãÜ×µ›ß ÿãÚ'ÕÇâ* ›Ÿ ” õÆáŸÖ©b[û2%ÑKí#Ç­n.šL4“cê­z§ì­¹¾0jû·gþ«ï½ƒÿ1]¤7š DóèA®àÝÝ…×ÆK¿±"®ßj%ðÎu]?ðxª»y]Hò½\?ô¸ž¿Ò__„®¶—þ’φ¿ààaÚá(ÿªoþŸµº)ßðpBgö‡øMÿdÞ/ý?kTWó¦-~þ~¯ó?o¿ÜÃÑ~Géw‡Ó?ðN] ÿÕ³ÿÔB:ø«O¶˜(ïÍ}»áèã[Úÿªiÿ¨„uñn™¢K1ÆÖ¾p+ö_•ãSü4ÿöãò~/vš¿óOÿm4ì „ªî—·¯J[Èc +q#ã·«£øA¦U$þlò­ÁàLÛò¡€³_¨Ê¬#£gÃÆœž¨ó¹£]ØÌ¤žÖËzƒµù÷®¾ûÁ¿f$á8çž?­RgKä@úѪÔ%Ì´zi£pÒK¦y#¥k/Œc´)µï忤Oˆ`/ÏDŒ +§7Ù Aos I1ùmæoÀÕˆ|u)ȳ›×Ek§Ä+óô¥_ÜJøŽÐ·Õ‰¨n}"Š´zÉYü?»#&Øß,õ­(|(O™-Ôÿ¼ þU-‹u9‡ÉcƒÔ•Î?:ÑþÛÖ$ˆ€-Sèa:•S¶ˆÖ§æaÝx-Âyyÿddÿ* |ò·Y9ÿg«}w­\Œ4“žÅS]SŽDŒ[œžÕ¬e+{ÒFrŒo¢f}×Tõ~A VF§á?+·§®k°ƒÁºŒÇ”Àõ-VáÝÀùü¾i:”¾ÛE(Tû)ž].ŒÑLq" ¾€V¾‘¢É#.%#è+·Ü?/÷àŠ¿kðél×>`b=5œjQ‹ºe8U–¡ÐÝ"ÀºsÁâ±5­$¡$ÍúWu«øzhc`¥¿ ?qÚχ^W<œôûÕºšœ{™8ò˱ÏÇf±M“7ךè¼9{mlëæ]cðÍfÁà—™ó³9ük Ð¾4…X©Çל†ú"äÔ­mN×@ñN›¯úD®}£ÿÚ›â6o +Ó’?(ZÊÑ>Å€G>­þ­?¸&;Ï`?Ƽê²Ã9{Í´•uÌë_-¡íYϺ/Æèa”b çû¢¤Õ¾Â$ !Ïo›åK£|ŠY€»sÚ¶Uåò3_X¾›Ç†~?•E SþÖu–ÿn—ýÔ&°|%ðF ª~ÎTö$×kgðV‹˜É>ǯé_=ŠžKcÚÃG˹Ék_æþy§Çp¨+(þÐñD@g¹ç¯!•wz§À+i“ýI?V®cRøkm“äÄôïWB®^Õš&­ZÕ52§„©9Þ”4/x.þ92vèª+®OËjþP‘‘G~• ¯Ã‹/Ùór ìÃøÇÆir³®daüLØé^„13÷Ñì¹J„=ýßÅãó€e.OÒèþ!–å^kçÝ3âL·Ê­*ž‹Çë^»àÙ¥’3º°#« +Ç—ºqÕàñª£ÜÛñA»š2c–W_¯ä^6¸Õ-µ ÞtŒ¹ç.BŠõí_Å[B¶è +0ûì0áÞ¸ CÁ–»ª‰»ÆÜïp>‚–]5OY¤‡Ž‹ž»-|37N²És$ˆz§Ýý:ײèÅ¢¶\nÚGv®7À ÛDPìûRÌ?§jì®õô{SŒaG9⼼ƴjÔ´5= 'Nç¡‹ãf¾¸F‡÷Hí^ãïÚŸŠu!=ÕìÌë÷¶6é]gÆáØ]mcóðwZñ=[öƒÖüÂÄf9ûßʽü›ŒQS¤’$¼Ž58fm¹n€(ÿ\ô?´.±¦]@J,8Sótäÿ~ŸNŽa*+U±ùüê`£Uè÷>Ñøgà'Ómœà'–ô®§ÄÞ{‹6˜LÏë^ðcã½æ³o™Œp ·j÷{Mzm_K +IÎ>SžÕùÖeCF½æÏ¸ÀÖ¡V• |…ûC~ÉqêZ¬÷‘¡W“ ÎGÖ¸þÉŸeÖH¬0C+Fyö5õÆï +êú­›}”É÷NyÕæþÑ5í>ü-ʱžO¥}~ 1«,73’ºûÏ™ÅàiÆ¿*‹³û|ø)cáÝK¦kˆáP¨äå€ô>µÖøŽøA`ìÈ1Èá|'¬^XÙ¦òC0sÃõꯊ>'4²ÝŠx)ïî+ãªágV»’Wô>¢xS¢¢ÙÉ|]¼{M6YþÍ#Û¿Þqõ«ÁµMrÂGdâW<)—?^Õì^*ø· "‡YQ‡ r¯ ø·àk}vÚKí:cms˃`?Ò¾Û&§ËZŠÇÉæ“æ|ÐÔë| 1Ê<¶}„ô/ɇõ¯xø}ivT0èƾðn»­hwøŠyP©ÁV<ú?á?ÄûùmcŽè4g¸r§ü*󌶤¡ÏNWŽ„gÉ$} ¨Y ³!0xéšñÿŠöj!pÊBŸSÅiëþ4Ôc³-YZñ‹58Óœt~T×—”åÕ]K¦z–>š†¨¥pb²ÔbÊ»Fâ½áë[K¨Ëê?Ïç_,kïZì—Q×±®Ÿá×Å›‹k”RÌŠzœñ_S_ ªÇ’2÷ž£]Ò—<£¡õôZd2ÛaxãO¹?è)°ƒçê+#Á~)¸×a]“X_å] çƒuN ñJ’®8šùÕMЩiÊǶæªÂðÏ6Ô¼9›•pß5%¦ž!‘Žæ¶|Aá-_LÉhüu*2+‡ñ åÌ{¸ØÃ®r¯nŒT’‘äÕJ›»Fåȉc!£8õ#òÍbjö–Ó£p‰®fëÄ×°¹Ã“õæ²uOÞˆÈb}ëцq÷®qOia¾$Ò-üÆØ¸ö$ÈÖ ve\æ¨ö9ª:ÇŒIv.ÇáTí2kg‘Ÿ ½Ýžßñ5ѫ渶ßÙU,úÃÿK‰îpïüŒ!§Ié,ùCþ +ý¢>Ù6‹ÿOÚÕŸðpOüœ?Âoû&ÑéûZ¢¿œq?ÆŸ«üÏÜpÿÁ‡¢üÓß ÅŸø&–†qÿ4ÓÿQëâ[O›v¯¹|3láØºöÿ…iÿ¨ŠWÁ=+ö/&Ô*ÛùiÿíÇå\cçÿ4ÿöÓª²ñ䉶ïW[â[ +nxö®ŠiOJý1ÍuHøÅ6u:—Rå~k‰Xþ&°ïu•™‰RíŸZ E4§¥LªÉ«l8ÒIÜßœçY´Õ£ˆŒ‘Ÿ¥P"šÉéY©´î[ŠgSeâ€ÀíÐVάÂí÷Ô~5瀔¸Ò[êvO +×áö¾1û(œj´~'N‘íM±«NœµR4§9ÇFh’êØ°Ã¢ŸBR¶€ó4j°¯ »ø“{7ñ?âj…ÇŒo®:Èqõ¬}ŒìÕN}YÛ·71cݪ»|JÓ¡În"cô¯Ÿ%Ön¦?4ïP–cóÉ)üj9)ve©Tî}ÿtÔ\ˆðVïâ½£ÝÜ«ƒØ)5á·±BÃr©9­k[ÅÁ;qíZR£E½t3©RªZ}âɵ"LD{‘U@šàäÉÝ'ÍYxÖQ´äŠºž93!ŸöŽ+½(-!c‘¹=dt–z}ÉPDȼòHÇô­½&9c™swLšó{ÏÊ ‘©ö95Q|\ó¾LÒ°”c?e8©hÚ4ŒšÕ#ßôMB8€ó/ÐsØü룰ÔlæL5ðÉçÒ¾lÓ|V±6ö}£ý·éü«¡Ò>(iÖ?ë¯Nzb%~5çâ2äõR;hãšÑÄúÇÃúeö®÷Îç]F é11Éæ‘Ô“_7X|tÒíÊìŽâbWn tÚWíòF¢Þ(áQí“^U|«%î·o‘èÑÌhEê§t‹[PʼnGÓ­jBÒÖ?šDR=0+æ«oŽóýŸs\‘ŽÃŠ{üg–îÛ6 îMxòÈk·«=8ç4RÐ÷Ý[ÄV¾Y ${½ëñ àÔ skÜúW—Gâɵx¹šrqÅXKk{¸CÜÝ,j?„¶æ5½,±RÝþU3k²7î|§jR¸ÔíäÇÞý)Úw€ÌÚ?U]¿øñ®7–W“¼“ù£¥fb¬š=Tñ|–r~çjGÜí \׈|Wý§ ¿q÷Pî5ÊϬÙj¶ ¼ò¾î¬qøž+KH²Ñm ÌÒõú“ùŸè+¢8HÓWißÐÆX™MÙ==L+ýõf,ׂq—ò+cÃßc»¯ß®>U?nÚÚxymÃ.ì“ò> +IºÐáTmÌ?…O'úÕVÆÔQ´.¾DÓÂAÊò³ù‹áÿƒVj«\³/û=3]Žð[G…•¦q´r9&«Yø›FÓÈgž+qýÜüƬ¯Å­M É(™ýIÎ?Ãñ¯½\\þžÍ*xh/zÇs èVZM°[XÑèJäÒëZ­”%®/qÔ¯ñ÷ío¡hr!¿Lp‘|Ä}OA_6ücý¯n|S [i†XPä3d–oÆž‡ñ¥ÏUò®ìXŒê…8òÓ\ÏÈúWãgÇM Ãv΋{8ã·ÈWÉ¿¿h3¬j.¶Ò3ß95åú·ˆ/µ¹‹Í,ŒXôÉ9§Ûø:òHÒ'Ùãn…Ç-øW×àppîZ É÷gÍbñR®ùª».Èí|%ã©Æ¢“K3rz“_E|-ñßö¤Q.âIào9?•|Ÿ¤iâÚáQdËg–"½ëá‘OiQê.e™Ø¬ËÆ}ï]¸ÊJ­y{ÝL-GN¯ºô>»ø{§Ey=ã £œ¿jí"¼Ò¬¤ÛÆøîO¾Aºøá¬Œ4’Ʋp‘„Áüªæƒñ;^ÖuHì팲Nßìà(õö¯ŠÄpõi·9JÈúº9Ý(¥ÆìúõµÛ(ñ‰#.z-s4×­ÖNˆáÉükÅfñ¾£¤E%­ŒæïPQþ•vëû«QÜ/bÉô¯$ø£ñ›PxšÞÆyºäMprZfïÏ¥eá¹Ô©¤¿¯ëbñyì! Qê~3°‹_ÔC}lª;žÃÔ×=/ÃÐÇÌŽXdqÂ(Áõ5Áü<Óµ(¼»šXlb.GØ{ŸÒ½?ÀÞÔ4ÛæDg%s‚{ûƒZw¿?·<&Ú–ˆòN-Ápuǽ|³ñ«Å'[ÕfÔ´ÿ8G363Æý {™>Uì¹§]^ßyäfy—µå¿Ü{4ñEâO +µÿ‡õF–x†d·fË'¨Ç¥yn©ñZöÚâKk´te8en>Õæº'Šõ¯ ê1ßYKjr_3ô÷ÅÖW–!­çVpà׎|_×a–'R½Gq^¤ü\Õ´ø@g¸PN2 Å;[øy©®Ù„¬ÍÐã“K +:“ ÄʵUÈ×âIâIây˜©+ŽÄt¬Ý/Å’iÜ ×=¬jsßH@îôÁŠëw#6Íç{XWǵSšÚ– 8rÉŸO|&ý£,ô·Š+™X=M}/ðçã^‹¬A— fã89¯ÌVŽùc  Á­ ÆZç‡çC ³íÍqb+ÒÄÿ->ëüŽªªÐþ“]ŸùŸ«wÞ7±¼µ9x%׃^kã³¢j,ûâDnrqÇé_økö˜×´åX¥–räk~OÚ&ëV€‡•†x8¦B2æ…OМV2´•§LõOZi6Œû&*zŒü¼ßÄš¤1oØêÃÔW-«|Ckå-æ¥rZߊeu'=+Üž:adîxñÂN¬®Õ¯ëq;€#éŠÃ‡ÆºuœÄHÛ0{ñ\~¹®_I)®Þج ÇŸPb²Dù{ù¬Fm.kÁõ º<¶“=»Kñ¾‘up ÷­ç´»]ÑMgÐâ¾p“K¸‡çˆÊ¿˜© Õ57%œӜ҇ÍiRŸÜ9äqzÓ™ôLЂ8|ãñ¯Uý…ÔŸ¾$œx.ïÿNº=|m§üYÖtÐF.÷¯©à—>6—ÇŸ<^’F­¼qÓ¾íWIÿâkÎÏózð„nãÿ¥DìÊ2ÊÔqqœ¬Õ¥ÿ¤³ÂÿààÅÛûDü&ÿ²mþŸµª*oø8f/'ö‘øN§·Ãh¿ôû­Q_‰b_ï§êÿ3õZ¢üÕ_ Zÿ¬Ðäïÿ +Ðÿ夕ùñ°{×è焬sÿÑ$ÇüÐ ^îSJüå¯×ü4•á[ÒŸþÜ~_Æ‘´áþ)ÿí£L@úÒyÔÓè¯Ô¬|@Ãn§Ö›öUõj–ŠVAr#h§¹¤ûzµME¨w!6({µ7û9=_ó«QÊ‚ì®tØÏvüé?²ãõÌUš)r.ÁÌÊÇJŒ÷ÌS±âþôŸ˜ÿ +·E‘ìÌ©ý÷¤üÇøPtxñ?æ?­ÑKÙǰùÙúëÿðüÿ¡Ÿâþ ¬?ù¤‹þ èø)Ïü$_ÿµ¨ØŸý´¯»ëâÍ ö#øaûVþØÿïü}áíë½'VÓ-íûFî×ÊFÓaf†T$u šþO\eóò¬D¶o~Í.Þgôká|§–î‚Þß›ïäf¯üýðj5ÂøâRkûþC¨åÿƒ}¾ L0|Qñ?ðÔlGþÙ×¢þÍ:f­û.þÔ¾ ø1ˆu-ÁOáXüQá¥Ö. ÅLJÑ&û+Ùù½M¸Â”îªàd†cãz7ü‹ÆøÙ¤øÄ~%øã [VÛL¹²ð`Öší„îˆ%†êXšÍÄ{ðó>m¬ †é¤xÓ;©(©{ÛmÝÆß&­Û­ìg.Ê`¥)aãîï÷)~Nÿ®àÞo‚ç?ñT|Qÿ¨‡ÿ!Òø7“àÁÿ™¯â újvÿlë{Vÿ…ãÿ,ñ÷ü!ðª6ÿÂ;¥ïþÚþÐÏöoÚ.<¼y_òó¿ÎÝü|¼sš‡öÓÿ‚„xÛögøÓ¨höž5ýŸ,ô¥Úöºv©·{­DQ³-ÊÙ$‘ÂÌÌJoÛ•*yÁ¬cƙ˄$ñ2\×ü]¿§uÐ×ýUÊùåB>í¿Ÿë÷Yõ0ÏüµðQºø£â‘ÿ¸•‡ÿ!Óáÿƒwþ ÂÙÿ„—â{{JÇÿëìÙãâô~øWƑؾ˜¾%Óa¿6/šm‹®JoÀÜÈ#œ•ã·g…í¿i¿ˆ¾ø$Ó-†¾×#ñÅ^>Ò2°‚Gi.ä‹ÿË#N¯ç”åÉíäå{Zë¦ý:$ßÈš|3”N<þÆ6µö/½Ùz³Í-àßÿƒ€m×þ$që¨Yò%kØÿÁ >XZñùÇ÷¯­þÛWWð³öœ×<+ÿâ×üFñÚÜxßáN™}£jp^«ÚâïÃ…:ßÅ/‰þø}¢xÓAKÛ-KÔn.5϶ÈФ1Í;l#‘¹PJ@KmbvŸgIÊ1ÅK•$ïÝ;¸ôê–ˆˆpžTùo‡3m[Í4šù6s©ÿNøN§þC^<>ÆöÓÿ‘ªvÿ‚/|+mMgÇ1{­Ýž[cXß ÿà¢^1Óþ#øaÊøxŸAÿ'øEj¸Ä?TúýºÈŸÖÒ´4ßø"OÂ]=Ã6³ãÛ¦ ÷ö¯ú}›ö2ã\öZ1Λ»ÄÈk…ò¤¬¨Dø×ÃðC‚þEò®¼c;§GžîÑØä¶?J·ªÁþ뙵?=»´ù~ŸèÕõýÿ×,îüßY•ýEþ«e6·°Ü|O§ÿÁþ ØjBäë?. +Â9oìÊô¢»AÿŒø_ödˆßøµ–>7VÜä WÔ”TÔã êzÏ'ó8c*‡ÃB'Ë-ÿˆø^÷K3_ø¸È¼n­¿øÅjiðK_‡:2-­÷Šbyxy;öü|å_IQYKŠsi+K/¼Ö<=–ÅÝQ‰óv¡ÿ¸øw¥5˜Ô|W÷„W6ê[ëûŠæ¯¿àŒŸ ïí’'Ô¼f¨‡ -å¯?_ôzúÚŠª|W›ÃàÄI|Å>Ë'ñQ‹>gŸþ OðÚ[KU¿ñ\6¶x) w6Á[ÞýÆMt ÿñð‡ÈÇé_KÑUþ³æ¿óþ_ðÄÿ«ùwüùGÌ·¿ðJo‡ÚZqÕ<^E· ·VÁÛ§Èþ”š÷ü‹áLj>Éæê¾/ˆYŒ ŠêÔãæÜþ•ôÝKŠsdî«ËþO‡²×£¢—Óþ 1ðÙ5èµí_ù¦ÅŒÝZù\}Ÿ9üiúwüwá¶›©Þ].§âùñ‹2½Õ±TÎs·ùïÜšúvŠoгk[Û˰—å»ûŸ3[Á)~Û@È5°bNZæØ‘ôýÅ`|Jÿ‚/|&ø¥¢­•þ¥ãKu^’Û]Ú¤ƒñ6ä~•õÅGŠóx¾eˆ•ýAðîXÕŸÚÿÁ»­ce,øªêÝ›S°8ÿÉ:ÑÐ?à€¿ü2’%ŸŒ>*Æ’Œ2ÿiØàÿä}ËEk1Σ¶&Fo…ò§½Ÿ ü/ÿ‚,|.øQsw%ˆ~ Ý­àÄ‘Þ^ÙºÁmV³5¯ø!?Á­nâéÛTñÜìît†öÐ(>ÀÛWÚ4Q1ΔœÖ&W~`ø_*qQt#d|@?à_~İwâ#*œ†7Ö[¿?²Sgÿ‚|¸‘ëÿƒ À"þÄý$¯¸h­?×l÷þ‚eø‘êžQÿ@ñüO†Ÿþ ýø.÷&_øH>$#ö8?ù)Qø7Ïà°ÝüIú·Øóÿ’•÷UŸçþbeø× +eóâ?‰ð“Á½L{á"ø–þÂ?ü‡GüC×ðP€ˆ¾%:¨Xÿò%}ÛEOúåÿÐL¿òú­”ÿψþ'ÁÍÿñ|gÜ|Gñ4žßñ1±ãÿ$ê#ÿëü9ÿŠâvOí ÿé}íE'ÆÓß/Ãü†¸c*ÿŸ>?ðn§Á›á%øŸûØò5ÿàÜÿ‚Œø—â‡õ°ÿä:ûꊟõ»8ÿ ‰~ä?õg+ÿŸ1>?ðngÀòÙ>%ø¢OOù Xò0Á¸ÿÁ'þŠy?õ°ÿä:ûúŠ_ënqÿAü?ÈêÞYÿ>Qðÿƒq>2àøŸâŸ×ûJÃ?úGLoø6ûàk€‰þ*qÿQ+þB¯Ð*)­™¿ýHêæYÿ>Qùó'ümð,ßð“üUzjVü…P7ükð)ó»ÄßÛ>º–ŸÿÈUúÿpý* +_ëNmÿ?åøþ¯e¿ó垣þ ¬ø âŠÀßÚZ~?ôŠšÿðmGÀwò3üUãRÓÿù +¿C(©ÿYó_ùÿ!ÿ«ùwüúG猿ðmÀY¾÷‰¾*®£§ÿòy¿‹¿à—¿ÿàß´&’< ©ø¯Qÿ„ÏÁá¾þÚ¹·›Ëû.«áï/Ëò ‹ûCçvsŸÕjùþ + kö¿ÚWáÒc?ñCx¤ÿåSÂõ¾<Çâ+Æz®Q}? ^Qƒ£FS¥M&ÁOø8Ò³~Ô_ +ÓÓá¬?ú|Ö¨«¿ðr­¿Ùk…éŒcá­¿þžõš)Õ³©'æÿ3:jЊò_‘úÍàû<ÿÁtI1ÿ6ýkÏýʉ_š5úàËOøÒþˆÿõo¶ßú‹%~_×ë^JðÄzCÿn?4ã¥iÒõŸþÚQE~°|QEQEQEQEQEQEý3«†é_.x‡à·í ðëö…ø‰â_†—eÐ|syiyåø™õ&»…¡´Ž bÝBJ±êݹ+ß¾#|Cÿ…i Çý‡â͸X>Ï£YýªtʳoeÈ ¸'Õ—Ö¸ŸøkOú¦¿?ðŸÿí•üo…Ê1Xˆûj1ºÕn—Tú¿$TJ¼#îÈä¾~ĺ¹Ð<}«üEñ„ž#ø‹ñ3EmPÔìmަ‰hÑ2‹[(ÿ¸ŽìÛØ!UfPʼnó›_Øïãþ§ðƒÃÿ¯õ߃ZWƒ|#¨i“Ú®‹§^Ey¬Ãit’pXàw æ“Ò»•Y˜ûŸü5§ýS_‹øOÿöÊ?á­?êšüXÿÂÿ¶WTr |d¤©ím/{­µ×£mù¶Û»3xŠn6o¾½uI?Á%ä’µŽ[ãÀß‹Z?íIÿ án£ðý¡ÖôK}[±ñJÝá ÞD–ÜÛŒ–++Œ9cø³òó0~Ë?~|MñüüAðºË¿õkb÷WÖ4»™üC¦É:R5Œ¬3¤LIˆJØØŽ§ÿÃZÕ5ø±ÿ„ÿÿl£þÓþ©¯Åü'ÿûeGú¹Žåäözj·ŽÒ|Íoµõ+ëtù¹¯ÙíÕ+'ëm ¿ÙOáF¥ð3öqðo„5y쮵?i‘Y\ËhÌÐHê9(YUˆú¨úW•xßþ ËáoÚGã§‹üañwH±ñ$w-mcá«[]VöìÛc9ó<¶‹÷’Jò98QŒ7&»¯økOú¦¿?ðŸÿí”ÃZÕ5ø±ÿ„ÿÿl«žAœÝIS×^±ë×—£dÃN1ä‹ÓæyDðNëï†>øÓà‡Í¡é^ø¡$z=æ¡u$šV§ä´2—.’1†EØÅ·³¸ ŒcÚþ,þÏ6¿?fKχZÅÂÛ¥þ• “\Å™`š ¡ád[kcp8ÍeÿÃZÕ5ø±ÿ„ÿÿl£þÓþ©¯Åü'ÿûeL¸{ÓR†öûJú^Ýz_òÄÓRROkÛNö¿ßdýoÜðÿ‡°ÇÄ#↺¯…em3BÑõ.$×4?•×EpV7A2Ìd?ºóÇÊ­t0~Ë?~|MñüüAðºË¿õkb÷WÖ4»™üC¦É:R5Œ¬3¤LIˆJØØŽ¦ŸÚɳÿ$ÛâÇþßý²øk&ÿ¢oñcÿ ïþÙD¸{%gOºzÇTí~¾Kkmëqbi§tû?K^ߛ߹»û)ü(Ô¾~Î> ð†¯=•Ö§áí2++™mš G% *±UJôòøk&ÿ¢oñcÿ ïþÙGü5“Ñ7ø±ÿ„÷ÿl«žE˜NNNž¯Î?æLkÒŠQOoSר¯!ÿ†²oú&ÿ?ðžÿí”ÃY7ý‹øOöÊŸõÿ>ÿÿ™_Y§Üõê+Èᬛþ‰¿Åü'¿ûeðÖMÿDßâÇþßý²õÿ>ÿÿ˜}fŸsר¯!ÿ†²oú&ÿ?ðžÿí”ÃY7ý‹øOöÊ?Õüüûücþaõš}Ï^¢¼‡þÉ¿è›üXÿÂ{ÿ¶Qÿ dßôMþ,á=ÿÛ(ÿWñÿóïñù‡Öi÷=zŠòøk&ÿ¢oñcÿ ïþÙGü5“Ñ7ø±ÿ„÷ÿl£ý_ÇÿÏ¿Æ?æY§Üõê+Èᬛþ‰¿Åü'¿ûeðÖMÿDßâÇþßý²õÿ>ÿÿ˜}fŸsר¯!ÿ†²oú&ÿ?ðžÿí”ÃY7ý‹øOöÊ?Õüüûücþaõš}Ï^¢¼‡þÉ¿è›üXÿÂ{ÿ¶Qÿ dßôMþ,á=ÿÛ(ÿWñÿóïñù‡Öi÷=zŠòøk&ÿ¢oñcÿ ïþÙGü5“Ñ7ø±ÿ„÷ÿl£ý_ÇÿÏ¿Æ?æY§Üõê+Èᬛþ‰¿Åü'¿ûeðÖMÿDßâÇþßý²õÿ>ÿÿ˜}fŸsר¯!ÿ†²oú&ÿ?ðžÿí”ÃY7ý‹øOöÊ?Õüüûücþaõš}Ï^¢¼‡þÉ¿è›üXÿÂ{ÿ¶Qÿ dßôMþ,á=ÿÛ(ÿWñÿóïñù‡Öi÷=zŠòøk&ÿ¢oñcÿ ïþÙGü5“Ñ7ø±ÿ„÷ÿl£ý_ÇÿÏ¿Æ?æY§Üõê+Èᬛþ‰¿Åü'¿ûeðÖMÿDßâÇþßý²õÿ>ÿÿ˜}fŸsר¯!ÿ†²oú&ÿ?ðžÿí”ÃY7ý‹øOöÊ?Õüüûücþaõš}Ï^¢¼‡þÉ¿è›üXÿÂ{ÿ¶Qÿ dßôMþ,á=ÿÛ(ÿWñÿóïñù‡Öi÷=zŠòøk&ÿ¢oñcÿ ïþÙGü5“Ñ7ø±ÿ„÷ÿl£ý_ÇÿÏ¿Æ?æY§Üõê+Èᬛþ‰¿Åü'¿ûeðÖMÿDßâÇþßý²õÿ>ÿÿ˜}fŸsר¯!ÿ†²oú&ÿ?ðžÿí”ÃY7ý‹øOöÊ?Õüüûücþaõš}Ï^¢¼‡þÉ¿è›üXÿÂ{ÿ¶Qÿ dßôMþ,á=ÿÛ(ÿWñÿóïñù‡Öi÷=zŠòøk&ÿ¢oñcÿ ïþÙGü5“Ñ7ø±ÿ„÷ÿl£ý_ÇÿÏ¿Æ?æY§Üõê+Èᬛþ‰¿Åü'¿ûeðÖMÿDßâÇþßý²õÿ>ÿÿ˜}fŸsר¯!ÿ†²oú&ÿ?ðžÿí”ÃY7ý‹øOöÊ?Õüüûücþaõš}Ï^¢¼‡þÉ¿è›üXÿÂ{ÿ¶Qÿ dßôMþ,á=ÿÛ(ÿWñÿóïñù‡Öi÷=uþáúTå'ö±b?ä›üXÿÂ{ÿ¶Sá«ê›|XÿÂ{ÿ¶Qþ¯ãÿçßãó¬ÓîzÅäÿðÕ¿õM¾,á=ÿÛ(ÿ†­ÿªmñcÿ ïþÙGú¿ÿŸŒÌ>³O¹ëò§í¿mö¯Ú«áœøÅGÿ*ž¯tøkñ³þF»-ü">7Ð<¨ ÿhÖt¿²Àøe]ŠÛŽ\îÈè­é^1û`ÁöŸÚïáºÿÔ‡â¿ý:x^²¡†«†ÅÆegÿö0ÆJ3ÃÉÇúÔüÿƒž-þËûgü3@1†–ßúzÖh«ðt¤?gý¸~'§Ã;_ý<ëW ÝÛ~oó<Ô¬’ò_‘úw᎞ƒþ +¡øQõkq¯Ÿ€6‘}“û…€éºsÖ¿8ëÝ4(¿âÆhþ¨‡þ¡qW…×í¾`a‡„ÜùáNOÕóŸŽñ>cêˆØê|÷_¸ðKýßýÃ¥ÿ·Ÿ‹g?Å©ÿ_jÿí¡EWÝ(QEQEW¼|)°áÿìÑcâ}Gð¶§â¿ø®_‹ÿÙÙ^YhðEªì½ mLò’f•~T°Ê àõ×|3øçâ_„–Z¦wdÚv®íš~¥¦Zê–,‡)#[]G$FEÉÚû7(f€ÄÃRµ.JvÝ;=šOgk»~{=:°U¡J¯<ö³ÛtÚi5æž¾[­R=ÞÛöT½ñž·âßüCÒ|1¢ÜhvÚDi¤è$Ñ<7e«½ä,Ñ\¥ä%„jÐÀÒ”…öaµnaâٯៀ<9ñÄW·úÿ‰ôŸ Þh±iÖºˆtç-öø'’Kyï"Šâ’Ý£Ød‰ +¹¾E +yr~Õ>8ÿ„ÃRÖåÕ,nî5{Xlní.´{+2h + ‹ì2DÖ¡"Ø»ˆ#+ƒT<[ûBx·Æú^µc¨j6ÆÃÄÙM{km§[Z@ÆÎ&ŠØF‘F« +G²„Œ*œò ÅxÐ˳>kJ¤T}Ý"䬓‡2^M)Ùé/z×µ­ëK€µÔ$åïk$ÛRå“ôn7Z§kÙ»ßÝWöðÅ®©â=i¯.î|3a¦hWÚv™yâ3A»™õKSr±I¨^ ·ýʤ¿v-Òápˆ7Êñì×ðÏÀøƒâ+ÛýÄúO†o4X´ë]Ä:s–û}¼òIo=äQ\BÒ[´{ ‘!W1·È¡ÁO+°ý¨¼oa¬½ñÕlïm.×FšÚûJ³½²¹µµT[xå¶š&†CEÚî…ÎI5OÅ¿´'‹|o¥ëV:†£ll]HÙ ¾ñ÷Œ>|=°ðýž¡¢ëúW‚Gˆô CTûMçöŠx–o²Nl4»X"Òä2›,4wwÄ^$ÉiõE†žšz8S#¼­¾GvÜÎØ>ƒ€8°äß´¿ì{gûOý®ËSñÇÄ Ã ÒŸ@ñW†ô«ËS¥x·L0Iip—6óIk¾9î#yô÷´¹t˜™ŒÆâ_üÏàÿŸÛ&Ûà–«©ìñ;êºnw?ö®•Øu=E`k+O°Kxš­Ïš.ìÿie=²}§2L‚ £‡ìéûwÜø¿þ £ðÃ㟼3¨iߎ…§GI©jš¤–Ö¶pYƒs$QÇywun 77#K˜ËÀVo/¯½ýlÿá{j^3Òüqñúˆµ[MÄ^Ò¯-mô¯êv¶öÖÐÝÜMös¨&!±°à·»†Úd´ ,2,×+9ìSá[?Ù;Hø9o¨x‚ßÃûü#WK<&ÿßٷ‘^hþC´F9³ä¶³}ª9üÕ´Œ]}¨¼ÆPø'ÿ!ñ^­ñ[â·†õ…¿5ŸAãY­ü9ðþݼ9³¢è–~ðÅÅäó\E4çŒ^ëQ8m–àJ0©²)VÃáÿü›áÇÅ_¨ðî‡ñSðz꺑qãOìe·Ð­¥×ìt»½îšD¹—ím¬YÁ²$–ÚFÝw´òÿ‚bÁá_ê~+°øÑñ‚‰ºÎ«w¨ÞxãÊðëj³Awc¤Y\X}´£§ wMI}ÂÌNÓ‰‚É*¿AàÏø&ÇÆÿ 5xxøƒHðÅߊü+âË{(ïVoìé|9…k’£Èmü¿X¬žkI+T²”ñÿ‹ŸðU™|Y¥øÓÁ¾øá8>#ê¾Öü)âÍV ]+ÅÞ¸ñ†tËÉmâK¹îàûEž½ E»µ·™RàœE4{WÐ?bŸø+ŸÁÿÛÛâž¡á/êhÔ"Ò¤×ôÇþÕÒ¯¿¶4Èæ†'»òl¯..l0×VŸ¸Ôá³¹?hÀ„´7 þÏÿðJêŸ|-uñ;^þÀðÂÍ*ÏIð'„4O[øŽ ]w@Ö-mã»}M¹KxÖ6ä]=ü÷JÇíII?Óÿ³Gì{gû0}’ËLñÇÄ sÃÒ“@ð¯†õ[ËQ¥xKLO,Gin–ÖðÉu²8-ãIõ»¹D„…™L÷&`0ñ—íß­xÓöªø3áxgÆ~×>%k~Ö|]q•ý¯¾›¡xˆÝiÐÆ×-©G$:¦™ƒ+ZBŽl$Ù+Å"¸ÿ‡ðZ_ ~Ñ¿~è? 4_íC]øiáiQëzµs¦é—z½}¡Þ™ª\ië¶mF’&¸{•‚Ú|[šÐËè?à”Þ ø¥â6ƒ]ñoÄ ï‡/ªëúÙøyçéñhFó]±Õ,õY~ЖƒUýøÖµ9vý¿lr\þì$qÅhxGþ ½§éSâ/‰>)|PñïŽìîô[7ZÖ—D·“KM0jñ¬Cc§[[¼sÛëÚµ¼¦h¤}—{¢xeŠ)cÐøÿ"ø{ûBþÔþ5ø9¦Iö?x+íÒKký·£jŸm‚Êò;;©¶i××RÙìškqåjÚNÞ~&1\xÿÚþ ð£öaøßãøª=A5¿ø~ÿ_ò¬5úëVz4šÔÖñiñj ¨ÛÉö(gu’úÖÚÝŒADÙšßÎì?g¯ø'¾û9üSð߈tÿ|@ÖôxRóÁ>ðƪt³¥xSG¹›NÚÛ¼Q^O宕eIysq&ÈÉgwvsÇülÿ‚FøK㤮‘¨üDø¡§øQ»ñ&§ƒì%ÒLÓ¯õý;V±Ôï"žK¿2Iý·©\*Ku$)4à,b(ã…@ þ ð£Áµ‡ð‹Ä1êñ–£w¤iþ±¡­Ö«jq[Éi¦Ëbšƒ_ÝH~Ùfq§Û]Ù¡œ–¹ ËÃØ|ÿ‚‘|=ý¡jüÓ$û¼öé%µþÛѵO¶ÁeyÔÛ4ëë©löM5¸òµí'o? ®;÷¿±íŸü/mKÆz_Ž> xwOñ«i¯ø‹ÂúUå­¾•â=NÖÞÚÚ»‰¾ÎuÄ66¼÷pÛL–e†EšågÀýž¿àžú?ìçñOÃ~!Óüyñ[Ò< áKÏø?éÒΕáMæm:CknðYEy?–ºU”I%åÍÄ›#%ÝÙÈ¿o¿kú Òþ(h1xkƺ…[\²ÒlžßP½¹Öô«´"f‘íc/©Ù‡ÛMset÷Zq¸Œ%Êñÿ?à²^ø+£øž_ˆ~ |:Ô<7ªéšYø‡Vðż:ž£}kuz¶I¨¦®úeµÄVVu$W·vÎ"žÏhv»¶I}Å?ðN¿ +ø×âNµâmSÅ_/gÕ5]U·µ—S…áÓ?²õØuø­‘Ì>uÅ»_Â̱ÞKqö8®na±6PÍ$mÏü>ÿ‚bÁð÷áfá˜þ4|`Ôî|%ª®»áMvú/¶«áEᾂòõ4¤ŠöâöJõneÔ¢»yáæn@ÄOÛ¦Ïã/ìáÿŠ õŸ³[xïÅ~ð|š­­äÚ;j(³ðýü2´ösÜZ´÷^Tªnlä–ä_µ[°ó3üeûwë^4ýª¾ ø_Ážñ…Ÿ5ωZß„uŸ\G¥ckï¦è^"7Zt1µËjQÉ©¦`ÊÖ£› 6JñH†nÿãì­ªø·öU²ð^‰â-C]ñâ ÅÖúНÞY5ëý3]´ÖÌW3ÇÑÝOjbͼD˜y¾T1ÛW!ñþ MàŸŠ^#h5ßü@¾ørú®¿­Ÿ‡ž~Ÿ„o5ÛRÏU—í h5_ßkS—oÛöÇ%ÏîÂGQ Ÿü;ÿ‚Òøköø‹ð×Aøi¢ÿlêïÄ O ø£J[е«7L»Ðõëè5®ôÍRãO]³hÒ4‘5ÃܬÓâØ´Ö†_`øÿ"ø{ûBþÔþ5ø9¦Iö?x+íÒKký·£jŸm‚Êò;;©¶i××RÙìškqåjÚNÞ~&1\sü#ÿÞÓô¿Œ©ñÄŸ¾(x÷Çvwz-Æ›­kK¢[É¥¦˜5xÖ¡±Ó­­Þ9íõíZÞS4R>˽Ñ<2űè~Ï_ðO}ösø§á¿éþ<ø­éð¥ç‚|áTégJð¦s6!µ·x,¢¼ŸË]*Ê$’òæâM‘’ÎîìäÏôïø+7‚|!}ãm2mã‰àø{ý¯¯ø§\“FÓÅŸ†´[_kú]ÕܲÅ$Qµ½œšÈŽÖMBâÔ@ñÃw2]˜¹ÿÁIåÕþ8xË®> Ià¿êº ¤>$†ËG¾­}ñ'Yð´š\èÏå¶žòiñG ‘[…±†êIg[Æ€·¨Cÿ¿ð  ø×¡ _ÆÓ㿇õ? ëîn­¼Ë;{ýWÄ:¤Ïj|Œ$‹?‰oÕL‚@+`U™di oø%ÿ€týZöòÓWñ…¬º·ˆ-üIªº¶eÔî-|e7Œ,’MБÛjwñ ‹Ë/o}*ÊÒɼЀyÆOø+Ÿ†¼Iãýoá—‚u?ì?ˆÞøá"ê?í] ZþÐÓƺ6‰ªŸ.ÆòòK,Ǩ,[5í.Ò³~dy‡Áïø*o€o>èÚΥŠ|/§|5Ó|{¬xË[Ðí™­m'Ò$ÔÒKë{Þ¬’Z[]Hnmíš×Oi ÁºO²Jÿ‚FøJÇÄ’çâ'Å Kÿ m,tÏønâ]!tï +ØYkz±og ‘Ø%Üñ¬žÓ`/wq<Æ“2y®f­Á&~iÐ<-©kŸ'×|WcávÒ´­oÚ×öjÝØêwÑêz~©qb¶ë©3Ä—x¿fèÄM—?ã§ü=söGø…âÿé0ðv«§|5Õ~-|<Õ5«]:m;â“¥EovÓÅSÏ46s >9b¼ŽÊóÉÔÿr"š9ß×ü/ûGkãOø—ž(|Eñ‚¼Aý¿¦Þë×:t1©V§¦-¹´±³¶´XÄz½ä†HáK‰ÈM$PEy‡Äø%5›þÎ>/ð7†|[â SûSáþ¡ðŸÁÐø’{QaðÛÚšÛ[^Cf--#ž÷Ê·µ³t[ùgšVÓaŒÝÁçÜ\0×ôQEQEQEQEà¿ðL¿ù3/ØK[ÿÓÅí{Õx/ü/þLËßöÖÿôñ{@õEPEPEPEPEPEPEPTtŸøÿÔÿëåôLUz¨é?ñÿ©ÿ×Êÿ蘨€ñ¯Ä-_À¿¼O{¬:†ƒ¢ønÇR¿ŠMAá’Ù]A¤x"òÙ$‘’ZCm®Ë¬ýRÕ\ë¾5¼Ó­|/¬]ØÁqygÌOºI­ŒŠášHRÕQžEarÇsÄS/åõ?|]qã -õÍœ6R2°Üâb¼HäR­”t–8Ý$ŽE+€¡„ž›V¹»—OûGÚ¼Òö³Ï,ÖA¥VY]m™Œ(ò3ªo6\“æ>í/ øNÇÁÚ{ÛØÇ0Yd3K,÷\Ï;t’ÈÍ#ªª 1!QT`(JŠ( ¿7?à¿£7¾ÿ±OÄ?úwð½~‘׿ÿüÝw_øÔ§âý;ø^½îÿ‘­ñ#Ãâ_ù×ÿ ? à­£%ø-ÿdí¿õ"×h¥ÿ‚¸.ß|õNÛÿR-rŠõ³o÷êßã—æÏ/*ìTÁÉ¥þ1«ÃÇþ¨‡þ¡ÑWÍô÷†“³‡ÏýQýC¢¯˜kö~þÿ¯t¿öóñüé~ö§ý}«ÿ¶…Q_zxaEPEP§ëßô{/ØëÃ^*ŠÏn½¨x³QÓ..¼×>e¼V¶rF›7lid9 + ÝÉ u³ ž(øuàíoSñŸ¦xq<+yâ-Fâ %º°¶‹R’ÐF62µìòJP!•Ó`RꉚäüûH/†¾Ûx/Vð?ƒ¼]£Ùj“êöͪɩE4MQ¾ÒîT¬)Þy­8?lrÊM*Úß@ð´—¤Þh-¡ùWRXÞØ\ÝItöó¦!dpQÖU‘|´;÷Çç«SÌ>KU9;»5Êã+%{´îÕ´²óWOÙ¡<£*Ûr¤Ò½ïΛnÖMrß®öê“W>þÊúOǯMaàMÅ Òt½]gU?ð‹cX€G/•äAeÌ«q#—ˆ®'UÄ„±@¦º}cö‹ÂšÞ«.¿âøsÃú„¿á-GÕ<&öº»D·©g%´–/8ͽ˜§ï™ydº%<æÏö”mĦëHðW‚ômëK}QЭ㼒ÃW·yL­ç´·/p_xFWY•Å»hŸö–žÎÏ^´Ðü#àï iþ!Ї®mtèn™DFí.ŒÞd÷JÓE]Ò;€€(Qˆ«K5”ײ›QóP¿[Ý­/µ¬š¶úêiF¦\£ûØ&î¶rµ½Ý“×ù¯vžºyu3þÇštßÙúퟋ®€n¼3/ŠgÕo4…ƒP¶·ŠðÙ<"ÍguyÚãb „a"–tÃb¯ÂÿÙ_Iøõãé¬< ¯ø£ÄN—¢Ë¬ê§þlkåò¼ˆ,¢¹•n$rñÄ긖(ÖG†¿kxoHðþ™ýŸ ßhú‰uáÙ´û¨%h5{+‹—¹xîvÈ"W ¯FÊcBa“^Ïö”mĦëHðW‚ômëK}QЭ㼒ÃW·yL­ç´·/p_xFWY•Å»jÝ<Ñ)ÇŸ_{•û¶µånedù­m­ïÖòªeÿ/2÷¯´9¹u¶üûôµº[Òþ ßÄØ4ynüaç†ßÄ–¶’øJH¼Mr‰9·{dÒÚqºq /9_$yܯøÙðîÛáWÄ{í +ÚãZ¸K4„¸Ö4gÑïàw‰âšÙÝÌnŒÅN”ã EnºWöñœü.øpt¯ìïìñ¤yZŸç}£Ïû_Úüìü›¼üy&ݼVÆ‹ZÆcQ·±²òm-ôû[K$u·²¶·‰b†ÞÏ#Es»1êXšÛ ÁVO+ÆÏ¤V·ÑèÛ½´káëw²Ï< ¥%F6•Õµ“ÒÊû¤­{»½uµ­©ýÑEü„J…WÅÿ¶—üJ‚zÓ¼Sâe¼ñ(Ñ®•ýΡ´:Z5¼°ÝÞ1Ò¯³Ôö0©6ÀÜm’G€Ü(®?Yý¡|áÏŒºOÃCǰø…¯Ú5þ™á‹fÚ-gQ·Q)i¡´gINKª2sò69ÿ€?¶€h¿ÙÃßôm{O°ø{¯ø|x’MCQ½¶Š=Ýb/p—’¤ 2[–9ǘDO ªÍòõ ++熟ðU‚þ8ðÿÄ/j~è|ãX¼¦x¾ãÆv?ØÞ$¸}OÕÃr̰ùŠo'„IJHse#d|Èž¿sûBøÏâe—‚¦ñǃâñ–£wqai ¾³lºÕÄÞÏ vÅüÖ’;K›{‡@¤¬3Å!X€vW€|Wÿ‚’|,ðuõΉáoü?ñï´¯è~Õü/¥xªÎMWFþÐñŸ¡Ï=Ä™%ì³_©tt\ºˆË!pÃÓþ~оøÇâ¯è^ñǃüU­ø&ïì"Óô}fÚúë@¸ß*y7qDìöòo†eÙ S˜¤ÊœvW‡üKý¾<àÚ«áïÁ­?Äž×þ!xËÄèúŸ‡íüEmý³á»tе ]of²]Óyl,àŒnŒ^ÆûÊ®Mÿø/y€/4/ˆ~ñ~‰ñÆ£áöŸ­hõŽ¡¦Zë-§\ßÅk<é6Å’D¶X’5Ý#Mul¡1&àîWðãö…ðÆ?xŸBð‡Ž<â­oÁ7`ñŸ£ë6××ZÆùSÉ»Š'g·“|3.ɜŠÆTã?Sý¬~hž;ñO…¯~%ü?´ñ?´§×|I¤Mâ8ïü?§$qÊ÷·<Ë{uŽhœË T *pÀ@¢¼ÿLý¬~k~;ð·…¬¾%ü?»ñ?Žt¤×|7¤Câ9/üA§™á [Yk7Öú®·m¥µì6ͺic€M<Çlxqi"îL3¯ |Gý¡|ðsÅ^м_ãøW[ñµßØ<;§ë͵ֿq¾$òm"•Õî$ß4+²0Ç2Æ1–ì(¯?Ôÿk…š'ŽüSák߉í‡dúV—fɶ¶¹–8гvÀnY™™,ÌÄ’I5ÐÑ@á·ÿž—ßø7ÿGü#ÖÿóÒûÿfÿâªõGþëùé}ÿ³ñTÂ=oÿ=/¿ð6oþ*¯Q@á·ÿž—ßø7ÿGü#ÖÿóÒûÿfÿâªõGþëùé}ÿ³ñTÂ=oÿ=/¿ð6oþ*¯Q@á·ÿž—ßø7ÿGü#ÖÿóÒûÿfÿâªõGþëùé}ÿ³ñTÂ=oÿ=/¿ð6oþ*¯Q@á·ÿž—ßø7ÿGü#ÖÿóÒûÿfÿâªõGþëùé}ÿ³ñU=†šŽ"~ñ·±yFc€3–$ôò©è Š( Š( Š( ¿8?à¾c:—ìSñþü1_£õùÃÿñÿ—¿ìSñþ¼1^÷ ÿÈÚ‡ø‘áñ7üŠëÿ„ü&ÿ‚ºŒx¯à¿ý“³ÿ©¹E/üãþFÏ‚ÿöNÏþ¤ZåëæÿïÕ¿Ç/Íž^SþãGüü‘úaá•ÿŒ^ð÷¿ÁýC⯗kê ÅŸÙgçþ¨…‡þ¡ñWÊõû/ ÿ׺_ûyùwüJŸõö¯þÚQE}ñáQ@Q@Q@Q@Q@Q@ÓEQ_Äçõ`WÎÿà˜ß ¿iŸxïÂ<5aãŸxëÄxžM +úImF™©GF×–×p°ºŠi•cˆ¾[4`*¼¢_£(  _xOøyáË-'JÓ´ÍJÓ- Óôý;M¶[k=2Ò ´1  +±Æ¼(UPÏ_ðP¿ÙÅ_µ‡Ù´Ý#¿õ=ÚUņ‰ã-xMm⯄úŒùV×4yÚãí ‹Y£‰%Óž9´ä?j9Z×éú(ãÁ6õÏ~ÛZÿ :~±áOx×AñÝÕÍïÄ?iñè—U¶• vÃÃvnšn¥!“F†T½¹ Or›íîÉ#¸ì4¿Ø§ÅZ/ücá×ÁÈõÏâ„¿ðŠÿeÝ4ó%‡ˆ?áÕ,/,¼÷òŒ–nL„K²;±µÔ>Ø!S7ÓôPÄ¿dß¾ý¦¼q ¤·ñE+,s\DfúCþ µÿÛ×?cxqµètû¨¾ø)¼ £ëOñÄž&º×-Ùì7Üǧ_ºXhÉý›½•¢Ý ¼Q¥ÄQÚâçìú(âþÃ?[Ä~ðÏ…µŸ‡þðÏ„þ xÓâ‘ãßí ïuÛ;Í~ÇÄÂþÃ’Çìö;Ï//¨ž;Å#3£çþÿÁ4þ'xKö±°ø««[xEþÁÕ|9ui¢Ý|Yñ濊ÖÏÅzu󶥫Ú$öÛmüN'†Þ4’)%±dcÚZxþÿ¢€>0ý‘?aÏŠÿ m 'âµ-?\‹DðV·á«í}þ#kší׋oﯴkíô[Ët°Ð#“û6yÏO™áŒÜEîŽaåÿ¶ïüËãgíUâßD5¯ê0^ÿÂ`Ö>"Õþ$ëé A«xg^Ò4ëá…µ“J³ûÕm {Ø$iæŠÆYÙL×rÇ_£ôPÆ>ÿ‚mëž&ý¶µÿtýcž0ñ®ƒã»«›ßˆ~$ÓãÑ.4«m*퇆ìÝ4ÝJC& ©{s:žå7ÛÜ%’Gp~ÈŸ°çÅ…¿¶†“ñ ÇÚ–Ÿ®E¢x+[ðÕö¾ÿµÍvëÅ·÷×Ú5ÇöŒz-åºXhÉý›ŠøÃÇßðOßxÏ↿u|/Ó|:¾5Ð|Q¤ɸa‹´­{SxchXéROš‰s 3ÜÛêw°Á|SM•®–ãñìñ³ãƒ´Íâ>‹ðüüVÐ#ð†ð¿ÅZ'Åi~ñŸn.E®‹ocs«ÉöŸ°Åo*jñÌšÔË%”“Ø‚->Ñ‹‚ð}E|ûIÁ2>)ünø'âß…vWì¼1oªüBñg†üC6¯xoõ]GʼnmÒÂòÀYùvvöÒxš\ÝGurò.ž„[!¹+oê2ÿ‚~ê¶¿¶×ƒ¾%ø=<£xSÀž°Ò<9{ÖßN¶ñ†›w +,P˜íã†ÏÅMnˆ¬${ t\'ÕôP懀àˆšå—Ÿ ø#ÄZwƒõ½+ÀÖžðÌwº÷¼Iâ¸üY£XøÃúŽ¡+PΟ¢Gsk¡tûhî£wš…Ì0Ûqô‡ÃïØ§Å^ÿ‚‡x›ã7ö‡‡î´꺼?Ùþ|Éso§_è>¶ûF|¢­q÷…v}Ÿ„h/üï=^³Ëôýóü1OŠ¿á«á:þÐðÿöGü.¯øXþOŸ7Ú³¿á]Â/åmò¶ý£íß¼Û»g‘óoßûªñýþ ‘ñOQð—Á?j×ì4ÿÙÓJðç„ôëM^òêoiÖ&ðž§su YÆ4Û²øXíc’ñ[ò­r‹™/ßôP̳‡ìS⯃ÿ¼-âOPðüú~‰ÿ KÏŽÖyšgÿ„ŸÆ6:å†ÐÑ(>]­´‰6HÛ)Pžj’ãËüYÿ¿ñö»âO^C«ø=bð¯|KâK°÷W!¤·Ô¾*xÆ$x€æEÓô«ˆœpñ(fŒ´Ë÷}ñüÿþ ÉãØ·XðIJé¾ÖgøyáH<¥j×ÿüO­Í­iÒ]i¢îö+Õk÷rÎ4ûHîRY~Ï»µ†ÜÉ7ÛôQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@~pÁ}ÝCÀßö)ø‡ÿNþ¯ÑúüÛÿ‚ÿËäÝø¿êTñþü1^÷ ÿÈÛþ$x\Mÿ"ºÿá? ¿à¯ÿÂYð_þÉÙÿÔ‹\¢ø+ƒùž(ø,êŸýHµÊ+×Íÿß«Ž_›<¼©ÿ±Qÿ$~øY?ã¼=ÿdFÃÿPø«åúÏÂéÿáÓÿTFÃÿQ«äÊý“¿†ÿëÝ/ý¼ü‹;þ$ÿëí_ý´(¢ŠûóÁ +(¢€ +ŸL…n5+xÜeUV ‘PSí®Òæ9TѰqž™4Öú“4ÜZGÙ´çì»á¿Šö·¿ Óá¶á›ˆ£ðˆ¾Ó©Fþ!™®1lòâHîƒÂÒÊZÝP§ !IÍ|iûø_Â?<_á¡ãýJâßáŵÍï‰õáÅ!Ž9"Š$³CvZâi%š4+'ŠÙ"GPùŋƋ:ÏŒµ8l ÔõËæÔ'ŠÕ`Iä… ÌÁ~¬O½u-ûYx‚çãG‹¼iu¦è7¯ã¸î ×4‰¡—û:úгDBÈ&@Õ’UudR×äð™viBŒ¶n\¯›¯½h%¬¹ŸI»¦£v®¬}.'—Õ«'ì’:·OvòoHòÿvÉÝï¯mäý‘4û‹Èµ˜|[3|:“ÃRx¤ëM¥ªê wcx>Åç•ûGÚöÄÏØCóÈÖß±G…u Eâ[ˆÔ~ OâÆžçÂè—Á!Ô–Á­Ä xè]˜–Re +NÐÅ,¹Ÿ ?i™|YñÃ«Ýø/Áþ_ Oáè´[» JãA6¥¼álâÝä½R÷¾3¬ [oËZŸ´ígai£YxOÁvþ¸Ñãðkx^þ}:Òú+Þêý͘ºqq…ao¸˜‰Ü5§›{XQ„Û»v”=ï‰òÛŸá¿+·emî„2ßg*³JÊÚ]ݻӿ*½ùmÏ«WÛªÓ;ötýtÿÚjþK_Þ|N›ÍÔŸN¶Ô£ð¹Ò Î<—½¹Šõ¶ARà$‚0s—ÕßþÃÚ‹|=á?¶øöëLñ‹ô]OZµ´_ùövñØIr²‰n¸,¶ÎSd-’pBðÇ—ø]ûfê¿ ô¿Âþðwˆo>\½Ï‡¯uD½ótÒóùì¢8.b†@e,Û¤ŸæûØU GDý®üI Þxbxlt6 èÚ–‡hH’órfi1 ˯ڤÚFÂä6vÄRÎ%*Š”ìµåø:F¥ºu—³né[T®µxáªej1u¡w¥þ.²7^‘æQ³wÑ»=iá¿ØfÇÆúö‹.…âm{Wðþ»á‰üKh¶ÞY5û± ÛÚImž—L²Êwœ\cÊ ÝT©ò/Ÿí¾|G¾Ð­®5«„³HKcF}þx‘Þ)­ÜÆèÌTáÙN2 WC¦þÓÿÂ7áýZð‡ƒ¼S¥xoI—H´·Ô¢»S²KÆ»2™ ¸ŠU”;²ƒª”b¬­œ×9ñƒâÖ£ñ£Æ#XÔmìl¼›K}>ÖÒÉmì­­âX¡…7³ÈÁQ@ÜîÌz–&»°Tóâ_Ö%x{ßËüÏ•é­ùmud—›ÐäÄOè~ê6Ÿ»üÛòÇ™YénnfÛÖÖ¶«ú?¢Š+ùþ— +(¢€ +(¢€>KOٻ´wíßñžXê:Œ:ŸáײŽßX½°XZk{‘)ż±†,!–Î6 cšµûBþÆß?f¿€^8ø®øSÅwz'€›²“ûMôk?µésÿÂ3k'öbÏiö{IåƒMûuÄçìºkMk'ؾÓq$Ws˜¨_øv_Áú5Ïü+5þJ£þ—ðcþ…Ísÿ +Ícÿ’«ä¯ðM#ð­Ç…4¿éúå§À߆¿ü3ðc]šîÁn´ëÛ¤ðÝׄä²2ÉçY^Xnôد^O8íRM]®yÿŽß²ÎûHøËà·‚ ð‡­>'Úx«À>ð}…ÔðxÁ^"ðLJÞûÅQiÖ¡ÚÞÎ kÃú” lÑ[Ewª×04ÂI@>•øïû'ü øuàû)>xïĺ¿Žõ[­EÓô_ ®¯ Ñõ[Ê-s¨Ãyé“FŒîÍ’ 弉¡­~Æß4/¾øs7…,Øø«MѾo|T½Õ~$_\|XûG‡ÓûIÖ<;â»MIûd׋ª·5]ÇÊžÝ-áûÌE#}!á¯Ø¿Äß e_ë>ð†Ÿeñ‹Ã<_ñs@´·’Ò»«`š}þ@“SðýÑÓEÅÎóf—‘ÈPIi ªÿòþ й®áY¬òUð쿃ô.kŸøVkü•_5||ý„þ"|CñÇè¼=à}CÃƗv—ºí·ˆ,.5Ù&·euw¦Û›‚Ñj‘ϤÚÏo·ˆm£‡Mšîâ Æû'?ðßþ ó©ü5ð¯…[Ä¿üañsá=߈?…$ÜÝh÷·i¡­–¤ºL`ðå”pÿgë@-œÓL´ÓdÉ}{¸Ö¿ð쿃ô.kŸøVkü•Gü;/àÇý šçþšÇÿ%WÏ^$ý˜~2øsûgÂoÃík/|Uøsñÿ\ÿ„Ýu=NÑÿá¶¾´ûUñMGQÔ#}âmóAOjþi¸7gìOá÷?ðH[|ø OàïYËáƒþðÖcàËŸZÇàÆnæÖ5YïuK[«6Iî.¬ä:—‡ÒkÇ{ft–Hl÷€}ëÿËø1ÿBæ¹ÿ…f±ÿÉUÇ迱·ÀMwãÃáO®·á_é>$»üSª‹Y-õ+NÞ…és"¾•p\‹ İ[ÿl¿…Ÿ¶GÁ?ü-ø!ûEü»ø»ãŸ +kW„¿±<}g%ý®¢ú|þMÌc’K•òXyÆHQž5‰œ–¾_×a½o[Ö>-Âû(ÿ¢øWã+ÁÚV»áMÀRjþ þκñ%Ô÷:u“ÜÝèmp—7zù5=¹¶ŠëÊ|Vä}K¦þß³Þ¯ñOYðU¾•®IâéVÝý—ü$Úàû=ô×°ÚËæ-·É§Þ.ÕbËä傆BÇÅŸØsö{øð³ÄÞ5ñN•®i~ð~•u­ê÷¿ð“k“ý’ÎÚšy|¸îGÛ3mEf8ÀàWË_³§ìñwáßÃßj´õß|?“ÀšbøŽ? ßëz/†àñž½uq£yQ±Òc¸ºðþ­`¶V±+é q¥¤7Iom1ÉØ~Î_±Ä•ÿ‚~Ò¿‡„øÓÃ÷þÑ|wamkánëáüšL-–k)&1Ço§†›H¶YmÔFu÷áXþ‡ü'Ó,ôO…ž²Ó¼-ÿ6Ÿi¥ZÃká¿*ÖøGâXP%ŽËW’Ù|•=°;Ä6a—€y/ü;/àÇý šçþšÇÿ%QÿËø1ÿBæ¹ÿ…f±ÿÉUïTP‚ÿòþ й®áY¬òUð쿃ô.kŸøVkü•^õEx/ü;/àÇý šçþšÇÿ%QÿËø1ÿBæ¹ÿ…f±ÿÉUïTP‚ÿòþ й®áY¬òUð쿃ô.kŸøVkü•^õEx/ü;/àÇý šçþšÇÿ%QÿËø1ÿBæ¹ÿ…f±ÿÉUïTP‚ÿòþ й®áY¬òUð쿃ô.kŸøVkü•^õEx/ü;/àÇý šçþšÇÿ%QÿËø1ÿBæ¹ÿ…f±ÿÉUïTP‚ÿòþ й®áY¬òUð쿃ô.kŸøVkü•^õEx/ü;/àÇý šçþšÇÿ%QÿËø1ÿBæ¹ÿ…f±ÿÉUïTP‚ÿòþ й®áY¬òUð쿃ô.kŸøVkü•^õEx/ü;/àÇý šçþšÇÿ%QÿËø1ÿBæ¹ÿ…f±ÿÉUïTP‚ÿòþ й®áY¬òUð쿃ô.kŸøVkü•^õEx/ü;/àÇý šçþšÇÿ%QÿËø1ÿBæ¹ÿ…f±ÿÉUïTP‚ÿòþ й®áY¬òUð쿃ô.kŸøVkü•^õEx/ü;/àÇý šçþšÇÿ%QÿËø1ÿBæ¹ÿ…f±ÿÉUïTP‚ÿòþ й®áY¬òUð쿃ô.kŸøVkü•^õEx/ü;/àÇý šçþšÇÿ%QÿËø1ÿBæ¹ÿ…f±ÿÉUïTP‚ÿòþ й®áY¬òUð쿃ô.kŸøVkü•^õEx/ü;/àÇý šçþšÇÿ%W¬ü*ðn›ðóÀvZl,ô½)¥¶¶‡{HQW.ij±êY‰f$’I$×CT|=ÿ×ÍÇþŽzù¯þ +¥cˆ~|7ÐhšïD:¥—˜Ë£ :>©v‘L€$b{h$ØÙRÑ) â¾:›À÷~ðY§üImŽ?ñÊûþ +šÅ~m§Á×ÇVÛT~ÁõËßÁ<< -õÝÕì–×ZÍŒ/q3JÑ[Ûë°A,I 1Ç/EDU +úf¾[ÿ‚0àœ¾ +'’u?ü¯jõ%"ñBK9Å¥ÿ?jélþ’Éòú ÿ$ô”ù©ÿ 6ÏøAÏýJºÿþü1_¥uù£ÿ 6ؼÿb®¿ÿ§ Up·ü°ÿâG'Ȫ¿øYøcÿ_“Í×> ·¯Ã¶ÿÔ‹\¢¢ÿ‚©¶íWà™ÿªvßú‘ë´W­›ÿ¿×ÿ¿ô¦y9Wû•ðGòGê—…cÏìáÖôø#aÿ¨„UâðÅ?è’|MÿÂ^ûÿW¹xN?øÄŸO‚6?úˆÅ_µ5ôÔø¾¶GN—²¦§í)ÃvÕ¹oÛÔù\¿†ifõ1Òn<•g·[Ûüç“þ§ã/ýO‰¿øKßñª?áŠ~2ÿÑ$ø›ÿ„½÷ÿ¯ènŠÓþ"ö3þã÷³Òÿˆi†ÿŸÒû‘üòÃüeÿ¢Iñ7ÿ {ïþ5Gü1OÆ_ú$Ÿð—¾ÿãUý ÑGüEìgýÇïaÿÓ ÿ?¥÷#ùäÿ†)øËÿD“âoþ÷ßüjøbŸŒ¿ôI>&ÿá/}ÿÆ«ú¢ø‹ØÏúÞÃþ!¦þKîGóÉÿ Sñ—þ‰'Äßü%ï¿øÕðÅ?è’|MÿÂ^ûÿWô7Eñ±Ÿô½‡üCL7üþ—Üç“þ§ã/ýO‰¿øKßñª?áŠ~2ÿÑ$ø›ÿ„½÷ÿ¯ènŠ?â/c?è?{ø†˜oùý/¹Ï'ü1OÆ_ú$Ÿð—¾ÿãTÃüeÿ¢Iñ7ÿ {ïþ5_ÐÝÄ^ÆÐ<~öñ 0ßóú_r?žOøbŸŒ¿ôI>&ÿá/}ÿƨÿ†)øËÿD“âoþ÷ßüj¿¡º(ÿˆ½Œÿ xýì?âa¿çô¾äQE~@~–QEQEy'ß…úçƒjoо0¹²é.¶Ñmtÿ&h̬làœJ쥆Õ-8Uç$£ä´·¦ÿk\Ð2ûþû‡ÿŽW;ñö…ðÁÏxcBñŽ<á]oÆ×`ðk6Ö7ZýÆø“É´ŠWW¸“|ЮÈÃËÆXg Ñ¼Y¥xQÕ¬ôýOO¿»Ð.ÖÃS‚Þá%“N¸h"¸XfU$Ç!‚x%Ø%&±µÔk\Ð2ûþû‡ÿŽQý­qÿ@Ëïûîþ9W¨  +?Ú×ô ¾ÿ¾áÿã”k\Ð2ûþû‡ÿŽS|3âÍ+Æšt—š6§§êÖÝÜØI=•ÂO\[O%½Ä%$Šx¥‰Óª-oQ´¸¿´ÓÞáêêÞ…'š8‰ÞÑÆ÷6êî +gˆ ®|ÿà§í»ð_ö”ñUÆ…ðçâ÷Âÿëv–>Ÿá¿Xê·PÛ«¢4Í»¬aäK‘€dQœ° BþÖ¸ÿ e÷ý÷ÿ£ûZãþ—ß÷Ü?ür›áŸi^4Ó¤¼Ñµ=?V´†îæÂIì®xÒâÚy-î!,„$SÅ,NQãu`HGûZãþ—ß÷Ü?ür Ã$yÆÑ;Í,›‚T4ŒÃ8$t#½\¢€>[ÿ‚°øOÄšïÁOê¾ðÖ»â¦ð¯ŠÓR¿²Ñ­MåòÛI¦ê~dp/ï%Ä·pîXÃ0RͪÄ~xÏiñ ¥;~ üg+Û>ÕÁÿÒjý²¢¿Gá_ñ&êtððš»w“•õôkÌøìûƒ0ù®#ëjJ.Ö²·ê™ø,þ# |øÈîEÕÿù³uÿ‚Oü-ñÁ¯ØÀºŠ4›Í ZI5;é,/-żWZÝÔ"E”s Ñ–FÃ!%X¢¨¢¿Ì1’Åâªâæ¬êJRilœ›v_yú>¨Q…»¨¤¾å`¯Íø8awEàûuÿý;øb¿K«óOþ£ðOýŠºÿþü1^Ÿ ÈÛþ$yÜ(¢Š+ãé?hOÚâOÆßŽÐxÿàððÿÁŸZéVžÖ¼9¨hx•c¨JªÇ¨ˆ­þÔñ¤Ÿ`™Sj³#ò+ìùS\ý…¾+iÿ>.ê^ øÏá¿øWã6³mªêÐIyâ ,&Ÿia*Øê¨‹häh­w#Ía0äÉG +ÍóÞ\š>WÊÞÊW›ZÝ[›£^[Óp·¿µÕý5½¿«Ôêm¿oK¯~Ͼø•à߃_>"xoÆþ‹Ä›ô ´(¥Òb’%”C4wú•¬.ñÊÓÎH†ñ§ü¿[ºý¢~é_¾x—âg€~/øÿÆpÝiCO³ÔJ$šÙÝF£¨Z,q¬we¦GC!2Ãå䬡rþ?Áô‰WÞ²Ð.¾Mà¿øNßÂø‡àCãm7F‚m·šlO{o­ó£–âT¸i0 Œ²tÿ‚tx£á?†?gÆðÄmMñWÀ¯Éàf¿×<%.§a¯ØK ŠJÆÖûg·—}„.Œ'uPÎ¥_ Ž¤éº®[G™Ùuª‰_É?fôÕ+êÞØ$Ôw|º¿?qéçñ.ÍôJÇ{ñGöÚ—à§Ä½?IñW‰úG…5MvËöÞ6Ý£]hu{*Akº(5Ô$¸’8wµ˜ +î mL½z§Å‰:?Á¿†¾ ñoˆ.â°Ð¼1§Oªj20U‚ci$bO¢©¯Œ<{ÿ`“âÇÃã-CÅ59cñ펭õí[á¸Ô|wÙµ(/†˜ºì—øŽÉDMmqZÇå@cOŸk™>™ý²fHÿl?÷oõ™´kš…“x I<ýSMŠá&¸±Ic–7·3¬b#2’ÊŽûFâyš”°É'jÛÑ57ÑÙ¹^ËT´Ž×Õ8*ÚëøÙ½»]Z×êõk[x_ìëÿ$ñV•û>|\ñ/Ç +Zø{Äß +4;Þi>Ù§Ðo4ó{l#þòæ6ŠòÒBY¦´r+= +ãþ +ZW‡£áʼnüYã9.&ðß„€ÑcÖ5½:¡’]PyšŠÛÚÚ¨ž%+y=¼áÝP‚Ÿ:øÏÿoðÿ‹äñLžñ÷Ž|=7Ž<¬|?×[ÄÞ Ö|jní/i#mKPw­f ác`²,Ò© +X:õÿ¶_üSAý¬“áö§qoðïSñ/ë;6Å|yàˆ¼_ ]Û\$q.žóÀÂ]ÖмsEF›ÿφo—F:®¿äIj·dÚÛ}¦Îâ;H¿°¿{ {±/ÛôP³7Ž|Mû>ÿÁ>êúO‰5v|àhu^ÛZ4žѯæÓaÔ/Æ![dKÓnn&I®b’8ÒÅ%ºûB¬ÆOŸô_Úå¼¥|d‹À´fŸ¨Úx£ã^Eñ‹^ñ¯…ü? j‰iàß +Äúlº¨Ð¯ôÖ¼y.?qm„o$zMã™Õ­åYÿ[è Ê¶G‹×ömø«ñ;Tñoü+ß|uÕ|âE¹“RÓ|9áŸÅ{àMy5©oµ ;Q6š}åÕ…þ•÷ÞE%ݬ±g3Î=CXøÝâoÛþñàÍYñ^žÓã=+Ÿ²ÎÊdƒÍŒ“Ë+½@ ‘Å}?E|Áâ_„þð‡ü#áïŠtŸ øKñ7Œ>xÏû{W´Ó¡‚ÿ[û6§àØ­¾Õ:¨’*2R?0¶Å$.Ð~ÊŸñ~>6|FøÇ}óÁoªê<#k//¤éÚ>¡5ž§)C¸Cq{«ÛÝ6Og§è¦DI p=þŠü ømñãâ‡|9ñ Âþ0Âkñw^øñzÆO†~g‡î¿áe¾ñeæ«yBÝ.í¼ÍV "/7S¸–Ìÿkì(<ësAãïÚwâ?ÄOÚhMâ gÂÍðÿâ%÷Á+K¯ µ´>=Sáÿ]Øé-k,ßÉö­FÃ\½†%0Þ\E§4°»ÙŸôâ—ÃM;ã/¼9«\ø‚ÓOÔ|¿6]]¾ÐïÓd‹ òï,¦†æ,²|¹r–Vʳ)ÐðŸ„ô¯xWLд-3OÑtMÒ+ ?O°·Kk[ x$PÅ‘ƈªªŠP@š ý·¾&Y~Î><ÕµÚ#áþ¹áUÑÄ~4ð·‰´ŸMmæ-óßiÃÄ/áý7Ã6 –ö^DwöÒf[‘o=Å©Õtë‹Ñÿ„úíçŠ>xkSÔn>רj:U­ÕÔÿØ—Z+ÂŒïö ¦k›<±'ìó³Kv9,¤×AEQEQEQEù«ÿ ¯‚ìT×ÿôïáŠý*¯Íø8,n>õ*xƒÿNþ¯…¿ämCüHðxŸþEUÿÂ~ÿÁU†5‚ŸöOÿR=vŠ“þ +°˜Ö~ +ÿDñÿõ#×h¯c7íÕ¿Ç/ý)žVUþãGüÿÒQúËáÿã +|:êˆXÿê%~¥Ãk|ÿ¢·ðËÿ +‹þ;_—~@bOͱÿÔJ:ø¢¾Ç.á +9ì!íª8{:pµ’wæ¿Cã)ñ-\¢¥g.z³ßÊßæCðÚß¿è­ü2ÿ¢ÇÿŽÑÿ ­ðkþŠßÃ/ü*,øí<”W¥ÿ‡ÿAû‘¯üD¼OüùÞÏèoþ[à×ý¿†_øTXÿñÚ?áµ¾ Ñ[øeÿ…Eÿ¯ç’Š?âàÿè"_rø‰xŸùó½ŸÐßü6·Á¯ú+ ¿ð¨±ÿã´Ãk|ÿ¢·ðËÿ +‹þ;_Ï%Ä!ÁÿÐD¾äññ?óæ?{?¡¿ømoƒ_ôVþáQcÿÇhÿ†Öø5ÿEoá—þ?üv¿žJ(ÿˆCƒÿ ‰}È?â%âçÌ~öCðÚß¿è­ü2ÿ¢ÇÿŽÑÿ ­ðkþŠßÃ/ü*,øí<”Qÿ‡ÿAûÄKÄÿϘýìþ†ÿáµ¾ Ñ[øeÿ…Eÿ£þ[à×ý¿†_øTXÿñÚþy(£þ!þ‚%÷ ÿˆ—‰ÿŸ1ûÙý ÿÃk|ÿ¢·ðËÿ +‹þ;Gü6·Á¯ú+ ¿ð¨±ÿãµüòQGüBýKîAÿ/ÿ>c÷³úh¢Š+ðSö¢Šüaý ~)|XÑ?àž?µ‡Â­6ûþ%þ=Õ~.øËF×¼›?ø§ü9§kÞ MMû3.n7]C§A绬Ãþ-ð«.•&@?g¨¯Œ<}ûy|a±ý¶µÿ ø{áöŸuðŸÀ¾5Ð| ®êײi–±Ïq©ÛiWäj:ͼÐIÖmÕ,¢Òo ÓÀ‘%ÂÉw‹_?ýž?à¥ÿŠüðÔÿà¥ÿ"øSð›]¾¥ßí!áýÅ>GðåóÇà[}CÄ~Òä´¿QW‘`ñJ2Í Ó†ý=‰ˆ­ÀX}Ãöjýµ¼UñŸöo‡×ú‡ãŸÃÿðœÂYkiÂÿÃañ­Ÿ†>Ô+oí="K‹ØüåkXLÖûaVôýñ‡ˆÿà¦ú¯„ü+ðþk럅úv·âï‰_ü1-¦¹«>j4o 'ŠJ_4å¥{xÑô,]ݘ¦Ž!w!ñ*ñþ#ÿ‚ƒ~ÐWŸð†ø žðÿ‰þ*j_Û×zóiÞ‡í:Z_ö2Ëg{¢_ø‚Æ;Kƒ&¹%‡Y½Šh ·º€O¢j÷ýùÁñsö§øûg|"ѼEøàÿø_â¯ÂK kÃÐÄÞ%¿Ô¯/µ/ë~už¹my˜·µˆa-.e³yRP.Q`ì?k/‹>>ýœ¿mÚ#â„5ÿb|0øáø‹BÖ4;›Ë¯[Ù_xÎëì–—‘^B–:C4~t–÷aL±¿”De$û¾Šùƒöjýµ¼UñŸöo‡×ú‡ãŸÃÿðœÂYkiÂÿÃañ­Ÿ†>Ô+oí="K‹ØüåkXLÖûaVòÿì©ûPø«ÁŸ¼Ið¿ÁZOÃýÄþ<ø®é¶^.Õt9µ ¬üßüVÔ¤[¸¡¹·’òÞ8ü>ñÁ +Ï“.§q1yapÓú+à?ðQÿŽÞñŽ¥¢x;Â?üÿ +¯ÂƒÄþ:ÖtkÍÄôøƒÿIø§ð#áf¿ñKÅ>ø¬ø&Ûż'¤h:S^Zê·_ðŒÃâ{è/î/di"‹Î‡Ã­hö©m'Ï0» `€Ñ_~ѵǟٲ ÀÐÉð¿â§Å/x‚ÇMÑÏ…´Ccu¥ÛͧkWï-·­D’FSA¸H§:Ÿ”Ë>#ÝcåÞtÇí;âoþ ñŒüàñâ¹þ%xkÂÚ¶zÖš­•µÀñÍ–Œ÷a-nîa·¼Œµ$+upln‘#yg{vgú¾Šü°ø½ûfühý¢ÿc?ƒºoŒÓá~—wûMxÂ'±·ÒtËë­;G·“Å~ Óïlu(åºCªYê0x‡2Ú/ÙDP¬öo-êËöªõÚKþ +oñOàÁ?üT²´ø{á‹Wâ„ü7áé´‹Á¥j>ÓüKp—÷—âó˼·¹“Ã2æÖ;[guåͱk€¿è¯ˆ/k/¯ûEj^·ñÁø¼ßˆŸ ,/äð6£'Ùµð=·ŠîµicÂù¶òm¼´ŽÉZ7‹Ï‚Vº›Èx§çôOø+WŽþ&¢ñß„|öÿ†^'ÿ„#Iñµ¯öu»ÿÂ+¬x›û1â·þÖ—T‚wò-õÝ.lA¢ÜÇ.ï,ÜBÒJlÀ>ÿ¢¿0?b_ÛâŸü!ß|ö¯‡úÄߊÿ +¾ÿÅÃÖ>þÉß ?hø(ç‚ ‹á§Ã÷ño‚~Ãñ7ƾ.ÿ„zÌk²y%¯‡l~Ûå­Ðó®ì§¹ó`™¶Gá߲φýCtðN_†šwÁÿ‰ÿµ‡4›Ÿ]éúwÅ[_*]o]¾×/߃<-!ó//fšæ\3<Éj…Uª¨ú~ŠüÐðí1ñ£öGýžŸ-žS ´î%¦Ãn·{Ý;â§…®/.ãÔõO=׉c–x‘ìú’Ú§‘MȨa/œ†ÀžÛå.~(XkÓh>!¼þÎðôÚZ­ß‰Dþ+ŒÉ3Mö´ÕÛ :n1#ýŸ+ 2 Þ5…\Ù%ÍM½ýèoï[[u÷m¢K¯6¶Š”òÆß$ÒÕ[ImxßO%Íw{»{ª:_—ö;Ö¿á$µ†øVë÷Z ø›þh¦¹\:zHм®­¹V¡‡Ëò<Ær©±ûjðÜiÙø«ÂŸ‡u]ãÄO¯À×ÑØiöP\5¼’L²Û%À>rì»1e +kÒ4ÏÚ¼þÑ¿"Ò¯,^]!üsáCþßC¡«D/ö7¥Ì w+/•·ÌŒ¡ÀÈÛwâía§~Ξ ð^‰àÿ¶%–“àÙôi4O$÷–¦æþ[À¶úµ¬b#:%Ì‘FÑd´eXÉ,vl§\¾û¾—‹÷m;6÷溎©(k­›²éŽ-q•Noqrëï-wÌ•ÿÅ=nÉZömù ¿ì«]ë®±x›ÂRxj=øø™%»m7ìB³Ø-þ׸\þä§Ù÷†#gÏ^ñÁ°øÅiÖúî‰âKuŠ)£Ô4™%{YÖHÕÀjG"²îÚÊ謬¬â½’ëöѶ¿økâ ñvg±ÑÛNµÔâ\í¯ÛÊÓ™T½6Æ5ŒÆLFn›;²ÇÎ?hŸ ñ÷âψÚÂK-µ½®'ºû]ÝÀ†ˆMs>Ôó®&ç“bîbNÑ^¶y‹¬–&6ŸXï}/m[kv¹W÷QçbáT¥ìey][Ime}öW¾Žïmt×ú0¢Š+ùþ• +ççøOá[Ÿjþ“Ã>“à ûwö¦Út&ÃRût’Ë{çÁ·Ë—íO3˼5¦¾âÌOAEqúÏìõàüeÒ~#jð}ÿÄ-Ѭ4ÏÜhÖÒë:u» CC Û!š8ÈžpQ\&“²iÿ³×€t:ÒÎ×Àþ¶´°´Ò¬- ‹F¶Hííô©ÍÆ— +(L,vS³Knƒˆ‹FŽk°¢€<ÿÿ²wÂÏk#ÔtŸ†Ÿô½CÆ­¶»¯]ZxzÎ µ½FÚèÞ[^Ý:Æ ÷]ð|^2ÔníïîõäÑ­—Sº¸‚Òk(&’ä'šÒGisqnŽX•†yc#²žYýˆ¾ øàÖ“ðçPøCð¾ÿáîv×úg†.<+c.§\1”´ÐÚ4Fä&yÉu@IšN~vϨQ@ãÿÙ;ágÅŠz'޼SðÓáÿ‰|má¯#û#Ä:¯‡¬ï5]+È™§ƒì÷2FÒÅåÌÍ"laµØ°Á$ÑãÿÙ;ágÅŠz'޼SðÓáÿ‰|má¯#û#Ä:¯‡¬ï5]+È™§ƒì÷2FÒÅåÌÍ"laµØ°Á$× Q@û=þÏv³þ¯¯xƒÅ¾ ñn«ý·âkfÕoõ»Ákoe²Gi½¬{-,í )[uf +I#ž#ý“¾xÇÚþ«ü4øªé+Ûý·cyáë9íµ·×Šý¦6Œ¬Ø¾»ººÁÄ÷3K÷äf>Eyþ·û'|,ñ7ü ¿Ú_ >êð«ü¯øC~Óáë9áò¼Ÿ/û;tgì›>Ïo·ÉÙ·È‹ظè,þøWNþÍû?†|?ö6«w®Øyzt+öFïí?j½‹ ò\MöËÏ2UÿÚçÜO˜ùè( /Ñ¿b/‚þø5«|9Óþü/°ø{¯Ý­þ§á‹ +ØÅ£j7 +b+4Ö‹†I‚aŸ‘qØAðŸÂ¶ÞÒ<-†|?†ðy´ðu¤6F¶òô;xg´¸†UÙˆ#Ž{ U#Úì­˜ÐÆW?Sý“¾k~;ñOŠo~|?»ñ?Žt§Ð¼I«Íáë9/üA§*ð–»yð‡á}Þ·à K; jxVÆK¯[Ù¹{Hl¥1o¶Ž%¢HŠˆÉÊ€kÔ( ?ñìð³Æ>×ô}_á§ÃýWHñ^ßí»ÏYÏm¬í¾¸ÔWí1´efÅõÝÕÐÞ'¹š_¿#1жýž¼gá[Ý +ø>-Qðý¿„îôôÑ­–ÖëF&H4É" ±¬ãK›…Kr j'”Û=…ŸáŸ é^ Ó¤³Ñ´Í?I´šîæþH,­ÒÞâæy..&*€$³Ë,®ý]ävbY‰:Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@öÞÒ¬üU{®Ã¦iñkz¥½…Þ –è·WVð<Ï2JöŽ7¹¸dBHS<¤]²hÞÒ¼9¨êך~™§Ø]ë÷k©Ïon‘I¨Ü,[¬Ó2€dAlƹڊ…ãúŸì9ð÷HÖËÿQXëóþ¿^à‚à¥ÿ·Ÿ—q"J£·üü©ÿ¶…Q_¢Ÿ0QEQEQEQEQEQEMQEŸÕ_˜ü'ÿ åû?þÒÿ´U—ÀÙüø›áÖ«ñ{Äþø…1û_‹5-FÏÄðH/!|2EncI`/¤îÐÆˆD„Eú\üÿ ü+sàM_ÂÒxgÃòxcÄnþÔÒN„Øj_n’Yo|ø6ùrý¢Iæywƒæ´ÒÜY‰ùRýº¾;h¿µç…cð_‡õÏxÅ~ð‹|B¶ú~‘a¨ê:•ž‘<×°\ÞkËse±µ˜|­=4íAçhc….Ì—Y¶Ðÿ‚m~Þ_jÿxrûâÃí?Â^ øŸà¦ñß„åy4Ë;«k}ö ¶Ñ¤ZÍõÖ©•©D^õì´ÁŠ öáï(>ŸÖg¯øã.“ñPð?ƒïþ!ha¦xžãF¶—YÓ­ØJnÙ ÑÆDó‚Šà4œ|í“áÇìõàƒž*ñ>»áø?º߮þßâ-CGÑ­¬nµûò¿w,H¯q&ù¦mò9–Cœ±ÈÄ5ÿ‚—ühð&‰ãÌß ïtOZ|Nñ}¦šž¾†é´okÿÙSé’\EÞj)=¼‰|!Xí ƒgv&SÆø*ïÇohÿ|meðÛÃöÿ|7ÿ öá»Í\éöðɨøj×Zd˜\ lßj^|ú»ìcÒm(§•ÅÓÇfe¹û¿Pýž¼«i×vw^ð}Í¥ý¦«asº5³ÇqoªÎ.5H]Ja£½V[„…âM^oYÉâ 9ãŽ'²¼œÇæ\[´pĆ) !X…|ñþ +oñOöHǺ‡m>øóOøoªë½¶Ñ4‹ÏM«ê6~ŸÆÑßÇ,×—¢ÞÝ­cM8Ú´s?›ºì\…"Èv¯íwñ£áÇí…àoÚî­ð¿\Öõïhw:‡‰,<'}§Ú¶}¦x¶ò[(¬_SÒñ_ÂŒ«v×/5›R`ÌßWÿ§ð¯ü$ÛðŒøû_ûWûwíßÙÐý§ûGì?Ùßmó6îûGØÑ|Üïò?uŸ-qþý~|0ø{'‡¾x+Áÿ "ŠîçUÓ.¼+á½6ÊM TžÊKÕ-£kw·[Áo#Eæüiöš5´6¢âÁ-RÂo)P'™l–6K ã1 ;p…DI´äø,7ÅŸxÓàíCðçƒü;¢xàUߊ|E>±¡Üê÷Zý¾§m¯Ûý’Ñ¢¼µK"McçH—aÍäºQgþÒ_ðSŠ~ ø·â¥•§Ãûß \j¿¼'á¿M¤^ ý+Qð¾Ÿâ[„¿¼¿ž]å½Ìž—6±ÚÛ)½øiðþïÄþ9ÒŸBñ&¯7‡¬ä¿ñœñÇÙ^Ncó.-Ú8bC…¬H€>pñGí›ñ£Âß´>ŸðKPO…ö¼gw£\éšõ¾™}£xbßP°ñMóYMj×PMªIð¤ð‹µšÀLuåû,ghgù¿Ã?··Æ]3öñdúO‡ø†_ˆÞñÇÄÏü0ñMÔO„|?ª5ï…mí(¬ôëû)o4»ÓLK˜mb +nîK$—S OüYá=+ǾÔô-wLÓõ­Z´–ÃPÓïíÒæÖþÞT),2Äऑº3+# ×?ñ¯özðí)á[} â7üãýÒíoàÓüI£[j¶°Ü*:,Ëèè²’E@‘†pÆ€> ñÌ þ*ü3øñÏá΃§Ë.©â‡°ßøßX×¥Ö>"ø&ÞþïÃßÙú*šyV;ëMB8¯â:„`Õ.îü»ù.åK`ýŒ¾ø6?¯ñ;á'‡´ÿ|4“Ã÷š4º¥²“uñ†ö{›9“Äs’f¾ŽØ[\%¶£xóM|u[ùЭ»Ås¨{þ³û=xÄtŸˆÚ‡üñ @´k 3Ä÷5´ºÎnÂPÐÃvÈfŽ2'œW‰¤ãçlóÿ?b/‚ÿ³_Š®5߇?~ø[»´k õ øVÇJºšÝ¡i`‰£/lPœœeE|AàÿÚcãGìû~EǨPEPEPEP_œ_ð_1ºóÁþ¥?éßÃú;_œŸð^á›ÿÿاâý;øb½þÿ‘¶üHð8£þE5ÿÂÏÂø+Zíñ7ÁqÿTñ¿õ"×(§Á\†ËÿQHëàºû·ÁÍŸØ3Ãþ¨uþ¢q×ÂUúÿÿ_à¥ÿ·Ÿ•ñ ½I×ÊŸûhQEú!óaEP^½â/Ù>}öd²ñøÖâ¸Ôœ[Þ_èBÔ¬švŸs5Ä×m)l7™-¹ü¢XŽNü(ÓÙõ+u¼yâ´2(áA$ˆ™Š©*€Î Üu¯¦u_Û§Â>)ø‘âˆï¾é6~ñ‹'…Åí£ÞɬÁ¦Ç¥‰òd½6~lM³±¨Ým Õäfµ±päú¬[³¼­mR·»­¾+»5ªhôòÊXiÊ_Y’JÖW¾ý­7QÞÛ;­N#â7ì‰}Œí4ÿ /Ú,£ð¦‘â J÷YÕ-4û['¼¶…ʵÌí (¦YvƬÛA¸‚k +ØÿÇöž+Ô4‰ôÍ*Ú]*ÆÛS»¼›^ÓâÓ ·¹ +mäkæœZþ÷rìn[<ƒ^ÝáÿAû]ø_ÄžÒ¼5ñ÷K‹@ðÇÚ.|=£G«j6—Zm±´9²ù¶ò¥ùμœ;ö›øµà?Å>(øi­Üx–ÏH:?†mÎ¥§ÚÁ{{§_é–>KÛÍlgŠ7âyQÂÌ<¹cþ<ñifØøÔX['$“jÍ»{—“´ºsKݵݕ·Wõ]ƒ?nÛQåZÝ%ÏgîêºÚîW²»þVxv™û!|@ÔïüIÑ쬄.`µÖ'Ôµ‹->ÖÅçWhKO<ÉIެQ÷&ïMÝW…?b­SÇ÷~&†3iá; øNÇÄi±¯éîš—Ú XNÒA1H²™mÞ_É’Î¤ÙøÁûWè?>øÇÃvÄ_KáëMK€ŒæÏJµžÛ}Ë;fHµ(Ë ß(fÐÿ†«ð‡ˆ<[¬Å©ÅâKÄ_tï\ÜÚØÁswisk™3$-×4p¢Ksöh †ßÍugò£%v5é`±Xéb]:ñJ+›TšÚM'víiG[+¿Dpâ0ø5CÚR“æ÷tmuŒ[Vµî¥Ì¯d¬–·ÑÿFQE ŸÒáEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_œ¿ð^¡KÀãþ¥?éßÃú5_ð^4ó5oú”üCÿ§o W¿Âßò6Ãÿ‰Ȧ¿øYøOÿv]¾-ø0?êžýHµÊ)ÿðWÕÛãƒÑ;?úë”W±›Çý¾¿øåÿ¥3ÉÊ?Ühÿ‚?’?\<¹ýƒ<:yÿ’eÿ¨œuð}ßàµÇìáÓÿT:ËÿQ8ëá +ýw€‡/ðRÿÛÏʸƒø’ÿ¯•?öТŠ+ôCçBŠ( Š( Š( Š( Š( Š( 颊(¯âsú°(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š+ó«þ ¾q«øþÅ/ÿéÛÃú+__ð]ñcÀÿö)x‡ÿNÞ¯…äo‡ÿ<(ÿ‘Mð³ð£þ +ýÿ#ÁŸû'gÿRrŠ_ø,ÇŒþ ÿÙ;?úë”Wµœ¿×ÿ¿ô¦y9GûðGòGë§‚Çü`G‡?ì‡Xÿê'|_yx-sûxpÿÕ±ÿÔN:ø6¿[àáÏü¿öóò¾!þ$¿ëåOý´+»ý›þ[|wø©‡¯5iôKCc{¨Oy ¼’4µµ–å‚ÄdŒ30ˆ¨Ë¨Éë\%zì{ñŸNøñÖÇĺ¬ÚÕ­¤öŸhÒ"Y/md¸³šåZH(ò+¬Sòðs_q˜J´p•e‡øÔeËþ+;~6"Xxzíµ²ÖmE«,ñ®è–)´î [ÝU^EÑrÊ€*èý¯<7­þÓú_ÄÝVÛÄ {®éZw‹-a‰%Ki¦²’ÈÍbd›,›dɰ!RŠÅv•ñ*â³/e(ÑW|’³k^{K•j µvÕÆÊÖ|Üë—×§‡ÀûE*ÎÉJ7IèãxóläôWÚWwº·#æó»ßÙ3ƺ„oüA$>þÁÓ§–ÒMIþÌÞ8ø¹a¦\øwB}NfêîÊÈ­ÔÓÍkn·3 WpAX™[g “Åvý޵ox«Á~»[9¼Uâc ÿÂCkâ=7TÓ3åA!HÒ 0ÒF³'Ï!ˬj©Ïmðëö¦øoðgÀþðþŽÞ7Ö¢Òn`¶šC&N ‚FyŸü<Ö>_ÙZëvaº¿°·Ô¡„ÊŽþDè$‰˜+…«l6I_E~ËúÏ‚5/ÚKÅV?‰·2¼WS2M¨ÉäÍ?Ùí•U¼É¼›yßiÀÄgœWÒ¿ ÿiïüøwðÒÆ /Äž!Ö¼?©?Šõ#ZM*|ïå-¤É=ŒÍ:¥´H GT?h•A9&¾Ë5­Š§FØ8óTn˲ÝÝÝ¥m-¾íF]N„«_í®û¾‰-·k¦×}øeðoÅuIm<+áŸø’[P­rºV›5ë[#q£9äã¥v>6ý|Y¦þÐ,ð…´xÞoßµ•ÕΕ£M3*†Ú%x£Þcç«vë^ƒâ|3ñ?‚5OøÇ–>Ðt¿Oâ;95 ?PhukíâXbyí»$„Cç1Y$Ö÷ǯŒþý ¯ü]§YxîÇÃ_ð°n¼OÍþ~`×í&†(ã*°[ÈâhLRaf®.N|Øòžk–"4Ü`Óºp“µÜ,Ý·vr÷c¶¼Û;z?ÙØXÑšu’z5(ëeRé_£q‡¼ôÕYwù÷ãÏÁæø%ñÛÄ~ãSêO§ ¶ƒÈóʶÝÅ76ߦãZí>'~ÄڿØü_·‹|â}[ÀL¿ÛúV•%òÝéñ™F_ô›hRTY5o%܃"œmÉÿµ‡Ä=âWíiã?hw†ûBÕuÉo-.L/›|†Øà0ã±×}ûRþØz‹¾/|AOhþÓ4?ê€ßkÖp^ÿhë–i(•ROµJâgTvXb„±AkZu³Ã’|Ò…çt’O÷wRí£’³ºì™i`aWô匭›w¿ðÛ}£«º×]Ñä—¿³‡Ä=3VÒôûŸøÎÞÿ\–h4ëi4K”›P’õ© +ÌŒ˜;‚‚W¾+Wá§ì㿉ÿî¼ o jzgŠ,¬n/î,5ˆg"€Í†ŒFdVqµPÃ4‘ŒÀ׬ø§öŠð¯j¯Ž7Íâi¬´‰zmÞ“¤øŠ[k‡ŽÑZX$Í@†á`xà06ÈÙ•d!Šw„¾=ø3Áÿ>i³øŠ=SKð§„5/ j(K;Ÿ"I/"½”¢[–··7IÍrʦ6îÆYždð÷T­7+rËI89/-$”9~&ß5’ÐÖ8 +­gSÝS³wZÅJ)µ×X¹Jêé(Úî÷^#¦~͵¿j:—€ý¾#|Fð7‰õÍÂÚÝñ𖥓¨iÐé·R߬î$,¢$ŒãÊòÿx©O18ù«þGˆüAãm Ã>ñ®¹ªM¦A©5—ö©y±ãFiÚFh2ãd¼R­µwb½Á¾'ðÆ©ð¿â¯‚5/ˆ0\kZÞ©i¾ ÕlïÚßW[StŽXE Ó£¸]|ÄìC5Úxóã—‚>*x#^ð„>0¶ðókðœK«ÝØÞeÓm W6S`’p<É«,L…  Õœó|+Mr7ÆÞä´MBﻳr|ªÏÝiù\089A^Vv•ýè½T¥eåx¨ûÚ­omó÷†þøçÆZÝþ™£ø/Åš®¥¥Ü}ŽöÒÏH¸ž{IðçÊ‘ #â)ÖþíøùN0|Má}OÁzõÖ•¬é×ÚN©bþUÍìÅ»ÿuÑÀe>ÄWÑÿi ø·á/Äm JÖ®®ouI|/a ËÛËø‘4ÛI¡¸¼” ‰ÂÊC‘°‘¸¾cûX|CÑþ&øóA¿Ño>ݯ…t]:êSÆEͽ„0ʧz‚J²ÝÈ8à‘ŠìÀã±ujÚµ>X¿'ü°•îú^N6µÓŽºÝ.lV N›tê^V¾ëùÜytÝÙ)];5²µ™ý ÑEü„KQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@~wÁu¿ä;àoû¼Cÿ§o Wè~wÁu¿ä;àoû¼Cÿ§o WÐp¯üðÿâGÅ?ò)Ä…Ÿ…?ðX¯ù~ Ù;ÿ݇\¢ø,Wü?¿ìÿîîQ^Îqþÿ_ürÿÒ™ääÿî?Áý%¯> sÿÿðèíÿ +>ÇÿQHëàZûãÁ?ò`>ÿ²eÿ¨¤uð=~·ÀÿÁKÿo?-â/âKþ¾TÿÛBŠ(¯Ñš +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€?¦Š(¢¿‰ÏêÀ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¯Îÿø.§ü‡ü ÿb—ˆôíáŠý¯Îÿø.§ü‡ü ÿb—ˆôíáŠúÿ‘¾üHð8§þE8ð³ð§þ ÿ#ßÁ¯û'û°ë”Qÿÿ‘ïà×ý“¿ýØuÊ+ÙÎ?ßëÿŽ_úS<œŸý‡ø#ÿ¤£õÛÁ?ò`ÿ²cÿ¨¤uð=}ñà‘ÿáßû!ö?úŠG_×ë|ü9ÿ‚—þÞ~YÄ?Ä—ý|©ÿ¶…Q_¢6QEQEQEQEQEQEMQEŸÕEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_ÿð]OùøþÅ/ÿéÛÃú!_ÿð]OùøþÅ/ÿéÛÃô+ÿ#|?ø‘àqOüŠqágáOü7þG¿ƒ_öNÿ÷a×(£þ ÿ#ßÁ¯û'û°ë”W³œ¿×ÿ¿ô¦y9?û…ðGÿIGëß‚ø'ï‡?ì‡Øÿê)|_}x)ÿã_þõCì¿õ޾¯Öøøsÿ/ý¼ü·ˆ¿‰/úùSÿm +(¢¿D>h(¢Š(¢Š(¢Š(¢Š(¢Š(¢Šþš(¢Šþ'?«Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ¿;ÿຟòð/ýŠ^!ÿÓ·†+ôB¿;¿àºŸòð/ýŠ^!ÿÓ·†+è8WþFøñ#ÀâŸùâ?Âϯø,oü¿ìÿîîQGü7þG¿ƒ_öNÿ÷a×(¯g8ÿ¯þ9éLòr÷ +àþ’×_·ü`‡=þØÿê)|_zø ÿÆxsþÈ}þ¢‘×ÁUúçüÿ/ý¼ü¯ˆ‰/úùSÿm +(¢¿C>p(¢Š(¢Š(¢Š(¢Š(¢Š(¢Šþš(¢Šþ'?«Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ¿;àºç÷ìRñþ¼1_¢UùÛÿ×ÿï¿ìRñþ¼1_AŸò7Ãÿ‰ÿȧþ~ÿÁcyñßÁ¯û'û°ë”QÿŠÿ‘çà×ý“¿ýØuÊ+ÙÎ?ßëÿŽ_úS<œŸý‡ø#ÿ¤£õÇÁ°7‡?ì‡Øÿê'|_yø+þLÿöCìõ޾ ¯×8 ørÿ/ý¼ü«ˆ?‰/úùSÿm +(¢¿C>t(¢Š(¢Š(¢Š(¢Š(¢Š(¢Šþš(¢Šþ'?«Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ¿;à»òð/ýŠ^!ÿÓ·†+ôJ¿;à»òð/ýŠ^!ÿÓ·†+èxSþFøñ#ÀâŸùâ?Âϯø,Wü?¿ìÿîîQGü+þGŸƒ_öNÿ÷a×(¯g8ÿ¯þ9éLòr÷ +àþ’Öï¹ÿ† ðàÿªcÿ¨œuð…}ÙàÆÿŒ ðïýûýD㯄ëõ¾ø%ÿ^éíçåó½Iÿ×ÚŸûhQEúóáEPEPEPEPEPEPôÑEWñ9ýXQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEùÛÿØÿç¿ìSñþ¼1_¢UùÙÿÚÿß¿ìRñþ¼1_CŸò7Ãÿ‰ÿȧþ~ÿÁb¿äyø5ÿdïÿvrŠ?à±'>8ø3ÿdïÿvrŠös÷úÿã—þ”Ï''ÿp¡þÿé(ýhðcÆøtÕ±ÿÔN:øZ¾æðcÆ +xwÛà}þ¢q×Ã5úïÿ_õî—þÞ~Ožõö¯þÚQE~‚xEPEPEPEPEPEPôÑEWñ9ýXQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEùÙÿÚÿß¿ìRñþ¼1_¢uùÙÿÚÿß¿ìRñþ¼1_CŸò7Ãÿ‰ÿȧþ~Áb?äwø3ÿdìÿêC®QGü#þGƒ?öNÏþ¤:åìçïõÿÇ/ý)žNOþáCüÿÒQú¿à¹sûè ÿTBÇÿQ(ëâ +ûSÁ3gö,Ðþ¨…þ¢QWÅuú÷_õî—þÞ~Mžõö¯þÚQE~€x!EPEPEPEPEPEPôÑEWñ9ýXQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEù×ÿÜ8Ö| }<%âý;xb¿E+ó¯þ ½ÿ!اâý;xb¾‡…?äo‡ÿ>Š¿äQˆÿ ? +ÿà°Ç>6ø3ÿdìÿêC®QIÿ…ÿ‘Ûà×ý“³ÿ©¹E{9ÏûýñËÿJg•“ÿ¸Pÿô”~§ø%ã<=ÏüÑýDb¯Œkì¿Ümý<:¹ÇüY+ýDc¯+õÞø%ÿ^éíçäùêýäÿëíOý´(¢ŠýðŠ( Š( Š( Š( Š( Š( 颊(¯âsú°(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Šü©ý¶þ,|\øÿMÕ~øOâo‰¼#¦j7zu’Zj3Û[Ù™4ûy± V9vryä·¥wÚßü×ö¸ø{§I¨øköÔ¼GÞ,¯uËßß`p©çù‘–>µ}MyïÅ¿ùXBÓþÃZWþš-«õj¿UÏsª¹^O N³£ I8Eݵ­ô¾¾§ç™FUO0¯‹ž"s¼jÍ&§%e~šÛð?=`Ÿø*ŸŒµŽËðƒã•Œv>'šëû6ÓR6Ëi0¼ÎÞâ5ÂfC€’£6áéÿðP¿ø'·ÿkÏ^ñ'†¼xžÓü4‚)íä’T’ÉÄ­'Úí¼°A™U!Š€#_›¨¯’à¹Qø#öìðf¹¡¢Å¯\è–WÎ#ᥞ+¹’}ÄF«ŸHÇ¥kÿÁfå%ß ?ì ¤ÿéÖò½*L*ãp™–Yj½9É®U(§“´[VNúzm¹Á[1•<.'˜^²¥R >gÔÕÚ½Ú¶§êÕùÿ\IiqðfX£–&Ö]N +tò«ÿü¯â—í·ðÚˆ^?ø­*x¿_µ¦Ÿ¡5£É¦ébE߸>hò†ÖìC´“þ°ä·ÆáxW +ð|Ç‹T¡W™k&œdÖ–z§k¶ím·>£ÄX…Œ­ÂáISåI¦¯­Ö[%­üÒšüÐý‹>i_ ®üA¦þÕzMÿÅk;7¹Šøø¾À[ÝÜ*—/ï<õ à€æRFàÛOC×~Î~9Öÿà©_ðM?ˆ~ñ4Í­øóÀÍÆ™|à5ÅÛ„ym žò?—<ñʶN[q;ÖàúQ¤±4± ÓŒ£·NQqRvRI¿z7óOÈÆ—Tu +”R›‹”Rš’—*»‹ihþMyŸ¥tWçßüã¯ü$|UðþöoôŸ +_ FÍ]¹· ïU‰23yÅyGì3¡Û›þ +Ó㉷Jnü?ákÙµkyæFÚ~ͧ¦{Š$³úTUàÙQÄcib*òÇ órßšÿµÕ¹½]žš•OŠ#VŽ¥w•wk_á·Äïmy}ÏÔ?ˆ^8°øeà-oÄz¤žV› ØÏ¨]?÷bŠ6vǾ×áô?¶Çm7SÓ¾,MãŸKáÛ¯̃OþÞº:yž ÓÚKù~IŽeP˜#h#ŸÑø-ÏÇ#ð§ö0¹Ñ-¦òõ_E¥.Ó†[uýôíô!3ÿ]¿ùïÇÿ³ÿ…áÿ‚%èúLZÞ€þ,Ò„^6kxï¢óÞiX™#eÝ»rZM´®3º 1_IÀô°ø<qXªjXª©««Ú);ËÉs;?CÃâÊ•±8©aðóqö4Üݯ+«/=שúkàïYxïÂ:V¹¦ÈfÓµ›8o­d#â•¡üU…h×ÉðEŸŽ¿ð¸?b3J¹›ÍÔü u&‹0f˘F$·lvQˆÇýq5ó_í¿ñ¯âíáûzÿƒðF»sáÿ éwO§]¦x£¹’$2]Oq³Ö=¬©;IAп+‡á*µsJø MByœ¤öQ]mÖêÍ#è«q:y}dbç*¶QŠë'ÓÊÌû›þ +âOÁ_±_ÄmWFÔo´RÇIy-¯,® ‹wÞ¿2:Ê}Á¯ÿ‚|Pñ7ÅŸÙ?Ä:мE®ø›PƒÅ·6ÑÝj×òÞÍBÎÉ„aäf`¡ŽÐq–'¹¯ž¿j¯ø%ˆÿbïÙÅ"ð7ÄÍgRÓVÌCâMæ¾£jì¨Îª—r1 @É +áºÏø$ׯø?fïø%¯Å\@.‡‡|I{q³Ìl´ôŠ2G@Ò2{M}Ê0«‡*CQVr­Ÿ+Œ®ì¹lõ_}µ<5™âw c é(Ó“k›™Y]Þëºú¤uù¡ÿÖøñ㟄_< má?ø¯Ã÷šLòO“«ÜY$î&3C8ɯ8ý“¿c/ÿÁYî5߈ÿ> jÖš4ïij¨¦gy‡d‚6a ‘@ÚIa€A5äÿðSŸÙãÆ?²ïÄøGÄ>0½ñ¯‡í´÷ŸÃ—·™óííÚL=»d±xŠárTz|+Ã,w =LLjUŠ|ÐåvøzIé&¯ª²ü!ÏñX¬¦U¡BP§&¹g̯¿TµIú¿Äýίοø.ïü†| ÿbŸˆôíáŠý¯Î¯ø.ÿü†< ÿb—ˆôíáŠüó„ÿäq‡ÿ>¿Š¿äQˆÿ ? +ÿà°Ÿò;|ÿ²võ!×(¤ÿ‚ÁÈéðgþÉÙÿÔ‡\¢½œçþFÿÇ/ý)žNOþáCüÿÒQú…á7?ðȾõD¬õо?¯¯¼)Çì“áÏû"VúˆÇ_ ×ëÜ ðKþ½ÒÿÛÏɳ¿âÔÿ¯µöТŠ+ô +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€?¦Š(¢¿‰ÏêÀ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(ò;ö•ñÖ‘ðËþ Ã&½¯_Á¥èú^«¥Muu6|¸û&Øn8Ï"¾Øø™ÿzø ðãCšê?GâµMÑXé²ÜM9þèb¢5?ïº×[ñ›þ Óðgö‚ñ½ÿ‰<]à›}[]ÔÌfêðjvòM寱&|©Ppˆ£vçšÏðwüëàn£šËá–ƒ;Är£P’}EÕn$Äý ä8êeŒ^z4ã G‘Eò®í·¿–ÇÅár¬ã V¿ÕeO–¬å;¾fÕßd’ÛÏsàŸÙËÀ>0ÿ‚®~ß©ñK_Ò'Ó| ÞCråÁkt†ÙƒAa<ÇfæB1€Ò7Ë•S±ÿ™ÿ”—|,ÿ°.“ÿ§[ÊýQÑôk?ipXéö–Ö6V¨#†ÞÞ%Š(TtUUìyÆo؇áíñ3Jñ‡‹ü1ý¯â=mì®ÿ´níü˜â•æŒlŠUFÄ’9Ë)'89 +× ÇVg MZniÓp„#fÒjÚ¶ÕüÙ–#„ê<¨S¨¥VsS”¥¥Ú~IÛÈø‹þ.ÿš;ÿq¯ýÇ×èwÁOù#^ÿ°-ŸþˆJæ?hÏØëáÇígýÿ ßÛÿØØ?Óî­<;Ëó?ÔH›³åG÷³¼c'>‡¢hÖÞÑ­4û8ü›;RÞ÷Ù(U$“€$æ¾{1Îhb2|&_ùè¹Ý»YóJêÚßÖéÞ +«G4Äãd×-E ouYßKzjÏÊÿø#7ü¤»âŸýuoý:Ùלü/ý™´ÚÓþ +Ýñ+Â>%šö-OøŠîahâ9d1ÝM´ ãæ ô?wëõ'àÏìCð¿ö|ø™ªøÃÂþÈñ· Ö÷·Ú7wtrÊ“H6K+"æHÐåTŒ Eýˆ~ü2øß©üGÐü1öë]\^j?Ú7rùÒ\¹y”ò˜†æ$à ¶+ë*ñÞb±8œ:œeR”aeu%ÕûÚ.Í]ù7O„+¼= +ÜZ…G)+»8¾‹Mýl¼ÏÎߨ«ã¦¹ÿ­ý°µß„?®Jx/X¾U7o•‚ÝßßPLôŽDÚ²sÀ<ÆEußð^߃Ñ|HðÄÖÓgÕ¼3¢èÚšÆì©IÞdWeû‚U–E ;§\í¯¹¿hØ“áwíYªi×Þ>ð¤íî“Ak8¼¹´‘#c¸¡h$BËž@l€KcŽ{]á_‡ô?†¶¾M6+¿ ZY®ž–ƒ½ümn£hÌåÚEó“À¸¥Æxhæ3ŠTÚ­nZ«Einh´îŸË·mz— Wx:Ùd潕ïMêåofš³_>ýôüäø}ðëöñï…mu&Ô%Ñ&–ÇSÕµ {›W Œ7b:e”ö&¾¶ÿ‚zü'ø!àÏë¾ ød¸Ñµû¤´¾ºiî¤Km¿jqó ¾srvyªúŸüKöxÕµ†¾—áµ’Nϼ¬:ôç9ÿT“„Ûn=«Ò¬|9àØ·à†±u¤h–žðžÚ­ìZm¡f!Py’°PZGÚŠ œ(ÉÀã:Ï(ch}_[76½Ú’N;ídÛnö±Õ•e°µ}¾&•¨§ïA5-·Õ$•¯sò×ö¿›Vÿ‚j~Þnü;A£|GðõÿØ„cjėѶvöMân²¢úâ¾Ëÿ‚'~ÏàÏìoâ Ë'Wøqý¬å—-¶SÇÝ+ºQ׉ÿ +ù;Ç~,Õÿබ߇ôíE½ÑþøM +Ü]L£Î‚ÌÈYeeʬÓmTHÁlHÕúÓ¢h¶žÑ­4ë x­,l!Kkx#]© h¡UvÒ½Î3ÌêPÊðùuulDãW[»Bê +^n÷~‡“ÂøUÌ+c¨»Ñ‹’§Úò·3^Keê~WÁZu«¯ÚÃþ +-àO„:dò}$Úé’ìù¾Ïqzé$òúa`ò ôòÛé^æßðoßÁ½§&ø˜lê?ü‰_FøöøWá²üP³ð¹OMs=ãj’jw“6dd‘„O)ˆe]€0 ü `cÖëÅÆq¥z8\6(œ©Âœ--—4Û¼žé}½^‡«†ájUk×ÄæpŒå9]ní¢]5ïèÉßø#ïgÛƒÆß 5ÉO¬ ‹‡ 5ýƒÈF=‹íß Y^<ñl¿ðNø,6³âßXÞIáŸêš™š(÷4Öz†÷i#Î7¦bþé€ê+ôgPýƒ~j_â|ž+㕼Žüjqjw‘~ù cJ"9U˜nw“ž¯ãoìñàŸÚ;ÃQé7ðÞâ+É +Ü©[±-ŠC¡#‚U†kҭƸ™„ñS¥' +ô”*­½­Íw}4W±ÃK…qpÁG‰N•G:oV­½¥§ßkŸÿÁC?à§_ >)þÊž&ð‡€u‰üeâÙ4)…Äkgn¿½šyLˆ¸TŠ78 Œ<»öø3¨~ÐðFŸŒžÒbkRûÄ—'Þ¸–ÞßL¹H×ý§hBv÷/Ãø'ŸÁŸ„¾ÖôÏøL±·ñ„ú^¡#O<÷3[N†9bÉ#JŠÊÄŽ¿ ®·ö~ýšüû-x6çÃþѰ´‹Ë×Ô&·ûd÷[çdŽ6}Ó;°Êăãåé’sÇþ³e˜<½àò¸M5RŸ+»ž¶jÛ+$Ÿ[³¥d8üN1b³ A§ A¨ÝY>×ßwvíè~yÿÁ!à£^ýž¾j~"jRxf{ J[Û ¹m%’’@»áo-Y’Eucólg#Åÿ௿µ—‡¿koŒz¥àô½»ð¾ƒe.™­-³Á£s½e˜FÚ‹$?x—Î0TŸÔ?‹ßðN‚¿¼e/ˆ2ø3ÿdìÿêC®Q^Îsÿ# +ÿã—þ”Ï''ÿp¡þÿé(ý>ø7{cãÏÙÀ°Avš¯Âû}¯c:[Ü®„šlဓu±¸!¢qÚ²ì¡à1ÿ.“ÿá}7ÿ3•ñ÷Ž¿l_þÂzü–~ƒG×¼5}w%Ãx^†Iì!ž@Åæ…¡x®!$¨b‘̱³̌ĚÉø.‡ŽOü*¯ƒ÷ç\ÿåzX\÷ê‹Ùª“„’Q|¶³åÛV|”r|N#›AS”&Ü—:wN[­_æ}°Ÿ²ñi7þÓó7SCûø"qòÚKÿ…üßüÍ×ÃëÿÓñÊœ…_ÿïÖ»ÿËJ–/ø/a?/¿ƒCþØëŸü³®Ïõº_óþ·ßóú¹ÿŸt>é‘÷ýŒü?åÊOü8ó7Gü1§ƒ?çÊOü8ó7_ÿÃû¾!mÇü*߃?÷ã\ÿå'ü?·âý߃?÷ã\ÿåWúÝ/ùÿ[ïù‹ý]ÇÿϺt¿Èûkþ×ÁŸóæÿøpfÿænøcoùsü8ó7_Ãû~ ÿÑ-ø3ÿ€úçÿ,éÿîøƒ“ÿ³àÏýø×?ùgGúÞÿçýo¾?æ/õwÿ>è}Òÿ#íÏøcOcþ<Ÿÿ ßüÍÒØÛÁ€ÿÇ“ÿáÁ›ÿ™ºøÁ{þ!ù¥ŸïƹÿË:Cÿîø‚Oü’σ?÷ã\ÿåë{ÿŸõ¾øÿ˜ÿÕÌüû¡÷Kü·ìoàÁÿ.Oÿ‡oþfé?áŽ|ÿ>oÿ‡oþfëâCÿíø‚æ–|ÿ¿çÿ,é?áý?è–|ÿ¿çÿ,éÿ­ÏþÖûãþbÿWqÿóî‡Ý/ò>Û?±ß‚Àÿ7ÿÃ7ÿ3tŸðǾ ÿŸ'ÿÃ7ÿ3uñ/ü?¯âýσ?÷ã\ÿå'ü?§ÇÿôJþ ÿßsÿ–tÿÖçÿ?ë}ñÿ1ÿ«¸ïù÷Cî—ùmØÿÁCþ\Ÿÿ ßüÍÒÙÁCþ\¤ÿÃ7ÿ3uñÁz|Ÿù%ïÆ¹ÿËJCÿçññ?òJþ ÿßsÿ–t­ÿôþ·ßóõsÿ>è}Òÿ#÷ ÿÁR|^?æMøkÿ…†©ÿÊj¿àª>-^¾ ømÿ…†©ÿÊjü>?ð^_ù¥ïιÿËJiÿ‚ïøíºü)ø3ÿ~ußþZWÌ*9òTû×ùžÿÖ8›þ~RûŸù¸-ÿWñ`ò&ü6ÿ¿Tÿå5FßðUï'_ü6ÿ¿Tÿå5~Ÿø.ÇŽ›¯ÂŸƒ?÷ç]ÿå¥5¿àº~8aσ?÷ç]ÿå¥W±È’§Þ¿ÌŸ¬q?üü¥÷?ò?o_þ +Óâ„ëà߆ÿøWê¿ü¦¦7üÇÄÊ9ðwÃü+õ_þSWâ Ÿð\Ÿ°9øOðhÿÛ-wÿ–•Áq±ÅóòÝ/þDýÅÿ‡Éøƒþ„߆ÿøWêßü¥£þ'âú~á_«ò–¿¿áõž*ÿ¢Eðkþù×ÿùiHßðZßÿ$‹à×ýñ¯ÿòÒ«ð×üû«÷¯ó¬q_üü£÷Kÿ‘?q¿áò~!ÿ¡7á·þú·ÿ)iüSÄþd߆߸Wêßü¥¯Ãø}Šÿè‘|ÿ¾5ÿþZÐàµÞ+?óH¾ ÿßÿÿ-iý_†¿çÝ_½˜þ±ÅóòÝ/þDýÄ—þ 7¯Å×Á¿?ð¯Õ¿ùKPŸø-F¸?æNøqÿ…v­ÿÊZü?“þ Sâ™ÂƒGþ¯ÿòÖ¡oø,߉X`üø5϶¿ÿËZ_Wá¯ù÷Wï_æ?¬qWüü£÷Kÿ‘?qþ ]­/_|8ÿ»Vÿå-1¿à¶zÊÿÌðãÿ +í[ÿ”µøxಾ#?óGþ ~Zÿÿ-i§þ #âëð{à×åâþZÑõ~ÿŸu~õþ`±ÃÅôH~ ÿß:ÿÿ-hX~ÿŸu~õþaõŽ(ÿŸ”¾çþGîQÿ‚ÍøˆÌ™ð×ÿ [ÿ””‡þ ;â?äLøkÿ…†­ÿÊJü6?ðZÿŸù¤?ïÿ–´‡þ [â£ÿ4‡àÏýó¯ÿòÖaÃ_óî¯Þ¿Ì>±Åóò—ÜÿÈýÇ?ðZ//_|5ÿÂÃVÿå%'ü>—_ÿ¡3á¯þ·ÿ)+ðÜÿÁj|Pzü ø3ÿ|ëÿüµ¤ÿ‡ÓxŸþˆÿÁŸûç_ÿå­?aÃ_óî¯Þ¿Ì>±Åóò—ÜÿÈýÇoø-F¾¿ó&|5ÿÂÃVÿå%2Oø-†»$ø3á¶ýN¿ÿ)+ðáÿà´Þ'$ÿÅŸø3ÿ|øƒÿ–´Çÿ‚Ðx–Aƒð{àÉÛÄüµ¦°ü3ÿ>êýëüÃëQÿ?)}ÏüÛù¿à¹:´†ðoÃú›õþRT-ÿÙÔ”ÿÈðãÿ +í_ÿ”•ø{7ü+^œå¾ ü'þæþZÔ ÿyÖXäüø5ùø‡ÿ–´þ¯Ãóî¯Þ¿Ì_XâùùKî—ù¹þ ·©ù“¾á]«ÿò’ƒÿÛÔ€ÿ‘;áÇþÚ¿ÿ)+ðÛþñ¬Ñø7ÿ}x‡ÿ–´ÃÝõ‚?ä|ÿ¾¼CÿËjWáù÷Wï_æYâùùKî—ù¸ÿðýíKþ„ï‡øWjÿü¤£þ½©Ððãÿ +í_ÿ”•øoÿuÕÿèŒüÿ¾¼CÿËjüÛWŸøS?¿ï¯ÿòÚ«ð¿üû«÷ÇüÃë³Åóò—Ý/ò?rüƒRþD߆ÿøWêÿü¤£þéЛðßÿ +ý_ÿ”•øjà®ú¹?òF~ ß^!ÿåµð÷m_þˆÏÁ¯ûëÄ?ü¶ªú· Ϻ¿|Ì>³Åóò—Ý/ò?rOü‡Qó'|7ÿ¿Wÿå%Rñü +OøzÿIÔ¼ ðÎóNÕ-ä´º·“ÅÚÆÉâ‘J:ø’t*H?ZüC?ðW]\ÿÍø5ÿ}x‡ÿ–ÔŸð÷M[þˆÇÁ¯ûëÄ?ü¶§1uN­ýWÿ$'ˆâ†¬êRûŸù´ÿ ÿà°ºGÁ/ Ç¢xKáÂ?iq¶ÿ³ØøŸV‰]°vƇ–bË1$ã“]ÿ‚òj#þdï†ÿøWëü£¯ÃcÿtÕ‰ÿ’1ðkþúñÿ-¨?ðW=XÿÍø5ÿ}x‡ÿ–ÕU)ðÍI9Ô…fÞí´ÛÿɈ§W‰áNŠK¢Oÿ‘?r?áüúý ¿ ÿð¯Ö?ùGHà½:€?ò'|7ÿ¿Xÿå~ÿÃÜu_ú#¿ï¯òÚ˜ÿðWWqÿ‹1ðkþúñÿ-«7‡áoù÷Wïÿ$iõž(ÿŸ”¾é‘û•ÿéÔ?èNøoÿ…~±ÿÊ:CÿìÔÿ‘;á¿þúÇÿ(ëð×þãªÿÑø5ÿ}x‹ÿ–Ô‡þ +᪟ù¢ÿ¿ï¯òÚaÂßóî¯ßþH>³Åóò—Ý/ò?r›þ ß~½|ðßÿ +ícÿ”tÓÿó¾ó'|8ÿ»Xÿå~ø+f¦Ý~ üÿ¾üEÿËjiÿ‚´jGþh·Á¯ûïÄ_ü¶§õnÿŸu~øÿ˜þ³Åóò—Ý/ò?r‡üÒøÿÌ›ðßÿ +ýcÿ”u"Ázµ ømÿ…~±ÿÊ:ü1ðVHÍø5ÿ}ø‹ÿ–Ôôÿ‚·ê©ÓàÇÁ¡ÿñÿ-©}[…ÿçÝ_¾?æ5‰âùùKîä~çø/¨zx3á¯þÇÿ(ëçÏÛ»öñÿ†Ê´Óîõ  h·‘{¥ÚÚé¥ö¤×mw{¥Ü4Ž×6«ƺq匿÷ŸËsÿyÕÐ|ø3ÿ}x‡ÿ–Õ_Sÿ‚·ø—T±{}?áÂMöl,:…­¾¯u5£d|ëÞ¡5»‘é,N§ºšêÁTáÌ%xbhS«Íuw_ï9ñ”ø‹BXzÕ)rÉYÙJöûƒþ +Ý©CªüIø_§Û¿{ ø ++]B}¤²êú¥äHã±kk«yGªÌ‡½É\]ÜüJÔnüCâ »g[Öf7W——LIœí…PUUUT*€W¥S†¥‹œ±RœÛ•»]ÞÛyžm>&ŽÂÆPJ7ïekîÿÙ +endstream +endobj +867 0 obj +84625 +endobj +868 0 obj +<< +/Type /XObject +/Subtype /Image +/BitsPerComponent 8 +/Width 339 +/Height 191 +/ColorSpace /DeviceRGB /Filter /DCTDecode +/Length 869 0 R +>> +stream +ÿØÿàJFIFHHÿÛC  !"$"$ÿÛCÿÀ¿S"ÿÄ + ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ +%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ + ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ +$4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?öŸxÅ6>6×£ÄwXAÍl’‡>bù{çhÎâÙ»–š'‹Ÿq«\Áa¶“R7s,e¼É +0ìY6“÷wÛ#¤º¶×S£Aâ)CâMOrýå i‘õGcÈ×J‚¾$Õ³é²ÓÿŒWŸi^ ñ^•§·övµ=­à¶KPÆý¤ª³0åO͹ã+œíÁ^¯Âºv¹¦j“¶£«Ýj–E*$WW>cææ.ª1û²A'$ž¹Å6¬ßºLe~¦”i­Õ«ÐǪÿß6¿üb³>Ï?÷<[ÏýãGÕiv¶ŸsH\êßô1ê¿÷ͯÿ¥ûF«ÿC&­ÿ|ÚñŠÎóúŸÎ—ìóÿxþt}V½µNæ‡Ú5_úõoûæÓÿŒQöWþ†M[þù´ÿãŸöyÿ¼:>Í?÷çGÕiv·©ÜÐûF«ÿC&­ÿ|ÚñŠ Æ«ÿC&«ÿ|ÚñŠÏû4ÿÞ?/‘?©üèú­ öõ;—MέÿC«ÿ|ÚÿñŠAu«gŸê¸ÿv×ÿŒUþ§ó¦˜'ÏçRð´ÊöóîlÂú”ƒþFm\À-?øÅHRÿ¡›Wÿ¾-?øÅd[$Êq¸þu ‘Ë€r:—…¦5Z}ËB=HÿÌͬߟüb¥ÿC6±ÿ|ZñЉa—xþtõŽQÜÖo ý¬»òuúõûâÓÿŒS¼Gþ†}cþø´ÿãѾ´á¾µ.„íd(·ÔègÖ?ï‹Oþ1GÙõúõûâÓÿŒRˆåÇZ_.AÞ—°€ý¬†ýŸRÿ¡ŸXÿ¾-?øÅgÔ³ÿ#>±ÿ|ZñŠvÉ}h1Ê{Òö´‘ÆëÞ'Ô´}~ïOŸÅ:†ÈÖ&zÚ)ù—'þXsÍSoêMqmomâÙ帓Ë@d´@[*äÀycÀè3‘š«ñáÝEý­A8’Ñ•çòÊq• ‚1ô9¬[†ÝÊ]Z[ÁÄ`„•oP²ä`•ÊB9«Éª± +µ¢½Óè¨}Aá/)~ò߉Ñj)=Ä^!½‚Xc%£€Øù—"ªx8È“г¤ø\×/n,ôßÞG"YÉ*±†ÖEî!ÇÌsÏzäµ/†:ÕõËÝ]ÛÁ=Ęß#^ g c'2}Iä÷­Ï‡¹ðÅýåôëF[s +Æ’ù„å•‹€ÜsUB5å^Ò^é–5àaƒnœ¿ycÕü>«àíTºeiï4ø.%ež5b@íÉ¢©|-ÿ’eá_ûYÿ蔢·{žd]ÒgœxÂØÝxóY‹p_3T‚ Ägnû{5Î;ãvk£ÿ…`?è<ÿø¿üUbø€ãâ©ÿa«Aÿ¬kÔõg•"…a•¢2NˆY@$yÆAèUÄÕ¥ +jkC† +u'7%}Nü6KgÄ{v ¶mWå§æö¥†Áq¿Äl¹!FmTdžß{­lx§Â÷Z¦¥c$7¹}›Tóf{`þh`¹v`Œm•ýóÌÛhŸÛV»¹¸Ô­Ì ?›k·Ä¤Bã…-°`™;†{\ÿ\¯üìßê””¿ÃÅ·”Iÿ )Èkdã=3óWEƒ¨Å‰uµùG{%ÿóH|ñ*ãíÆîñ ÷>HÜÝ«#ŌȲF æ@JàžŽõÖø?Gñå­îšuÍb{ÈSÏûIiÐc!vü¡N<Ž:ž"¬þ)áð£ þÁÔÈÿèǧØ×üi‡µ#ÿ1Ñÿ€kþ5¯ö;ú +Ýßñ¿c¸ÿ ¥×ýñÿQí%ܾHö1‡uÿ1ßü”_ñ¤ÿ„oQηòQƶ¾ÇqÿAK¯ûâ/þ"±ÜÐRëþø‹ÿˆ£ÚK¸½œ{@ÔÀÀ×F?ëÍÆìO¾º?ð ƵþÇqÿAK¯ûâ/þ"±ÜÐRëþø‹ÿˆ£ÚK¸{8ö2‡õ/ú¯þ¯øÒÂ?©Ðtàÿl}Žãþ‚—_÷Ä_üEc¸ÿ ¥×ýñÿGµŸpöqìcÂ=©Ðtàÿ#xoPnºà?öæ¿ã[_c¸ÿ ¥×ýñÿGØî?è)uÿ|EÿÄSö³îÊŒøE.ÿè7ÿ’‹þ4Â+x?æ7ÿ’‹þ5¿öKú +]ßñ_QŽîÖÔΚ•ÕtùY#Á€#…÷£Úϸ½”;#·½¶ÿòQÆ—þkßú ÿä¢ÿu#¥{Y÷eÇ-ÿ½÷ýÿòQÆ—þ{ïú ÿä¢ÿuQígÜ=”;¿ü#ßôÿÉEÿ?á¾ÿ ßþJ/ø×QEÖ}ÃÙC±Ë ^ùÿä¢ÿE>ƒ, Íâ8¢i[daíÑK· Ër}…t:»Ì‰Ã3BÒNˆY@$œã Šã|yáKV¾‰­mà¿c-—›pêjï"0œ R>\5Ö}ÃÙC±ª|3yžuÏü”_ñ£þ‹Æÿ˜ßþJ/ø×o¤üP½hç‹U½Ó 7ò<‘OdÑ•mÝ3ûò0ÔÑígÜ=”;hðÅà9áÿÀEÿ<=©Ƽ1ÿ^kþ5ÊÚhŸV7’MVa͸‚¿Rˇ&bͰç'z)ÛŽ>…öYÙ™—P¹Œ$*¤xšÒö³î?gÆOö§ÿAÅÿÀ5ÿQ¡j€Èuð Ƶ¾ÇqÿAK¯ûâ/þ"±ÜÐRëþø‹ÿˆ£ÚO¸{8ö2¿°õ_ú¯þ/øÑý‰ªÿÐuð Ƶ~ÇqÿAK¯ûâ/þ"±ÜÐRëþø‹ÿˆ£ÚK¸{8ö2ÿ±5_ú¯þ/øÑý‹«ùާþ/øÖ§Øî?è)uÿ|EÿÄQö;ú +]ßñs˸{8ö3?±µoú§þ/øÑý«Ðu?ð Æ´þÇqÿAK¯ûâ/þ"±ÜÐRëþø‹ÿˆ¥Ï.ãäc3ûUÿ âàÿ!Ñ5Oú'þ/øÖ§Øî?è)uÿ|EÿÄQö;ú +]ßñùåÜ^Î=Œ“¡êõÔÿÀ%ÿÌÔ£¾Óµíf¼[µšÞIòeJ²Äç;Ïå].mõ;XšöYã•_rº è1µEdø§þCÖƒòã?þ‡iFrsWfU¡NV] ~œü2ð©ÿ¨5Ÿþ‰J(øYÿ$Ç¿ö³ÿÑ)Ec-Íiü(àüB¹ñöªÞšÝŸþ‹±¯PÕúZÿ×Ôμ÷Z·VñVµ1<®»gÿ¢¬kÐõŽ–Ÿõõó®ŒC¼aèeAZSõ(xãYŸBÐ íµ¼SÌÓG +,¬Uv'àg ®üFÖ—þ]´£“ÿM?ƺ?Œ-·ÁÁ½/-ÿô1^5¦jÁyÜ&øT Î8àõæ½¼£/¥‰¡)Î7ižNi«B´cY3»ºø­À¹û”HíûÏñ®×Ὲ¦ñW†#Õî-£¶—Ï–HØ•Ê9\ŒóÎ+Àõ›˜¦¼¸š!²v1©ãjö¯^ýž˜7Äo[û¯ýÕ®u–ÐÃa#RœlÛ_“'+ÇVÄW”'+¤‰¾'xæïº•¥­­¬âhWyäa›Ö¹øÏª*ï:V›·;wy’c>*¯í3&ÍJ_[FÿÐëÍôýFÎîÂâ#,’HÏ1+ ”Úâr„xëŠô2Ì› [N´©ó7¾ýÌ1¸úÐÄÊœgd½Fºøëª@CbiòF0X œ3Èu¯v„å½@5ñ%àýÑÇ¥}·ú„ÿt*ó¸›/Ãà¥MQ¯{þnO‹«ˆRuìy·þ"ßxsijivöRGhÞdÒ0f,3À ®qþ5jJptÍ0ý%“ü+›øÿ)ngþ=á9ÿ€×.¬ÿ°þËåm¹Üw7’­¿AÞ~eÀÈÀà×±—äxJ˜JU%NîI_¿sÎÅæ5ሜ#+%éþG­èßõïéÚdº5“ww¹xæ}˽‚îã5í@apHϵ|yàßù|?ÿaKoýµö^à(`«ÂcdÕÿÔÊ151ܪ;êy‡¾%ßøÄ·z\:}‹ÇÀi_s’‰ÀæÇáXGãN¨0Ò´Ò©Ì$“=;W!ñÊOø¹:œ~†?ý•ÍFÌxa´èâd¸vBäD¸m¬Çq|îè@ÛŒ W»‚Ȱ³ÂR¨éÝÉ+ïשåâ3ñ¯8©Ù/CÖ|3ñ‡PÕ¼]¦èÓèö+ íÀƒÌŠgܹ`ô¯Z×?ä'ûÉÿ¡­|£ðÛþJ_†Éÿ Œxüš¾­Öÿä'ûÉÿ¡­xK£ƒÄÂcdãÅ÷=l£R½*Žîæ…Q_$×í¿ëÆý*Ö¼ÿ½‡û²ÿ!YÚÚîñ¾{XOÿ¡ÅZRÒhÊ¿ðåè3áoü“/ +ÿØÏÿD¥|-ÿ’eá_ûYÿ蔢¢[•OáG/«ÆN¹¯ÉØköcÿ!XWy¬}ÛOúúùל뚙‹ÅÚΖ-Ëyúí›ù›¾î"±ã…z6±÷m?ëê?ç[VŒ’…ûI¦åná¯èún»¥I¦jÖÂæÒ\BÅNAÈ ‚ Œäå?áRü?ï¢?þ\ñu©ñ7Y¾Ð¼!>¡§-ø¡N¥nIíö5ÿôòÜ;MË 6•ûµùxÌVŒùk+¿Kžœ~|=< ¿ð6þ.ºŸèšf¥Å¥èö‹igfXÁ-ËI$’I$õ&¼Œ.æ+û]Ùïf¿ã^ÁðƒÄ:Š<m«j†#tÓM4i´6Ç*; +y–_ÃÑSÄÊñ¿võ + Zn4cgécGÅ~ ð׊f‚mwL[¹-Ô¬Oæ:2ƒÔeHãŽõ‰ÿ +áæ?ä^ø7ÿY¿'ø÷]Ð<[>Ÿcuo¼qFUM¸vbÃ$’OÐcÚ¹ø½â€xÔ-Î8ÿ5ÿíÂeyZQ•)µ´÷™Í_‚…GÇUäzÆð»Àš~£o¨Yè)Í´‚X§•ö°èpÌFAç¥vAxë_=xâÇ‹nüW¤ØÍsg-µÕì0HŸe +v»…8 ðFs_Br¯?3Âb°Õ#L®ÚÓ[x:ôkEº*Èå¼AðïÁÚö©&©«hëqy(Pò‰¤MØ +Àtã>ÕCþÃÏú‡þÏÿÅ×+ñâˆ4?_iÖ—–ð[ÂQQM¸rrŠÄ’O«~•ÍÜ|Xñl+=í¸YWz±¯Ì¹#=}Aü«ÐÃe™¥JQ•9û¯oy£Ž®7Ê2Ž«}WÒ>x#IÕ-õM?CHníŸ|24Ò¾ÆÆ21ä×G® i’¼Ÿúׇx?⯊µ/é]ÍŤ֗—K ‹ö`‡iAê1^ã®È2O÷“ÿCZó³<&+ QGï+w¾‡nµÐr¤¬®_¢Š+Î:Š( Š(  +:¿[?úúOëNÖt»bÁ¬u|è†+¸©‚ ƒî 7Wëgÿ_Iýj¯‹nn-´ø½ÃÛ´·1ÄÒ ‚“Î2Î:Pgü+¿÷Ó%>æöþ.ƒðëÁçþaràdÿü]Uyõšº–£³j¶|ÈÏ p8ÙT/µ=R(TÔµ¨@$´xÉí÷(·Ñt«Â; 6·¶Œ’¨ <“’I'$’s“Tõÿ hºìñÏ©Ú4ÒF»–gŒíÎpv‘‘õª5ÝWÃIu}1šQq4[Ȳ¬…W8ã8”Ï^Ý&º¶©}qo¶W Ð]ÙØd–€õ4ÏøW~ÿ \Ÿø?ÿGü+¯îé,Ø áî¦`~ ¾ö5UçÔ€ÈÔ¯ÀËe¨ëüâ{[Ò즸¶Õ®Y£®Z7BTòÈ3î=èÔÔc¾k Yð‡µ‹ã{¨X´³²…fYäv:d+OlÖäyÛÍr:µýà×/!û}ÔiÇQBPQX“•$’[ô/ü+¿Ð.Oü Ÿÿ‹©lüáK;Øo-ôÂ'Ä‘³ÜJáXt8f#ƒÍg½Æ ík°ÎLÑã®1sX³kúŶ¹§Àš•Ó¬º„PH’ìe*· +ByÍz~>\f¹›¯xRæâK‰´Ç2JåÛmÔª2NN`$žtØãÄZ^ê7QާzdwrËFªƒ{(N0äòhïü+¿Ð.Oü Ÿÿ‹«ºƒü=¢_í2Ãɸ(SÌiÈRA ncŒàV,·Z‚¡oí{ 9c4x8ÇÜëȪÞÖuyÿÉ2ð·ý¬ÿôJQJ[•…ˆgEø“©BGÌÚͦ?ïÕ•zž¯÷mëê?ç^5â™1ñŠò,õÕ­ÿ¿vUìºÇÝ´ÿ¯¨ÿvbãhRÿêÎl+¼ªzÿ‘É|zEðÖòBÁ@šIÿ¦‹_7èz²iš¢_mŽRªË´°ÈÈ## €Fr85ö.¡ik}g%¥å´0H0ñMta<'ù4?ü‹ÿ‰¯W*Îé`°Ò¡RŸ73ïn‹ÈãÇe²ÄÕU#+[Èù#T½Žòòâë)šC&ÐFO¶}û8ß ­JGÚîyþšµu_ðˆxOþ…}ÿññ5«cekcmµ´¶ñŒ$PÆè«7ÏaÃÆŒ!Ëfž÷Ù-–«©)^þG†þÓs,Zþ…ÕKZ9Á=pÿýzò˜õ!•q`$'•$oŸ”0Æ;ýïÒ¾ÁÕôm'V1OL±¾ò³³í6é.ÜõÆàqÒ©Â!á?úôOü‹ÿ‰®Œ¿ˆéa0°ÃÊ•ùzßÎýŒqYDëÖ•E;_ÈøêòHü¦>btþõ}»ú„ÿt*ÈO xU]<3¢«) ¬,"Ж¶•qé\æqÍÁƼ·ëÜê˰¤œ¯sæ¯Ú +t_‰1—P~Ï ‘Ÿ»\¬ZÍ‚øJ]1¥“íÿ*©aøçp£âf©uyYúÄ•ËÍ­™tdÒÉR"*fNÌXS»…}c¨xsAÔ. Σ¢i·“• æÏj’9 ÉÅCÿ‡„ÿèWÑ?ð/þ&½l/P¥B)RmÂÚß·ÈóëdÕ*U”Ôí#åÿ†¯ø™á±½I:Œxû5}]®È2O÷“ÿCZ¯gáŸÙ]%ÝŽƒ¥ZÜ'Ü–8Ñ—· Ž X×þÌ“ýäÿÐÖ¼|ç4ŽeZ5#[+Ž_ƒxJn ßSBŠ(¯ ï +(¢€ +(¢€(êýlÿëé?­d|Fž+]+™cŠ;¸‹»*Œã$öëZú¿[?úúOëVåE‘ +:«)êdñäñ•ŠF":‹Fªoš:` ûU}GÅšdöÛ¬É$r&èp1œwë^Æ,l±Í¥¿ýúáGØl¿çÒûô?€9oƒn%ðDr®6½ÝË)2¶¬ÿˆº­¶•â8¤¸¸†{5òšV ’óŒõ#p®þ4XÀTPªS'‚ñæÃ˜é½7có !>3±?{R±?!SûÁÉ㟯ΰ¼W¯é׺t°Z\[1`ÛcŽ]ijqÜö¯xû —üúAÿ~‡øR‹;5!–ÖÀäàþT:ôJòÿjözwНV{¸-åG"‰G–£ £ Šõ¨e¶·•·Mr€ºGç@>Þ/ÓÀ+¥g<³t9ž¾ÀcÒ³áÕ¬ï¼Q£Gkq ®ú­»lÃ`yªM{wØl¿çÒûô?œ––Ѹx­áFŒ?Jž¼sþk 9Þݯ­"‘%u•dHß)ã×ò¯bíéP5«±y-¡f<’cŸÒ€<}ü[¦ía¥i lŸ’~rH$õögáÞ£o©|JŽ[i" ;†-·ËGùW«}†Ëþ} ÿ¿Cü)ñ[Á  1Çž» þTZóþBöîËü…fëÿò·ÿ¯ ÿô8«JóþBöI¬ÝþC¶ÿõã?þ‡iKãF8áKÐoÂïù&^ÿ°5Ÿþ‰J(ø]ÿ$ËÂßö³ÿÑ)EL¾&]?…aâ›]ÿ®®7}ÝZÔcþÙY×±ë-ëê?ç^-âÁuÿ ²à¢“ö¥®ãÛýU{N¯Ò×þ¾£þuÙŒ¿%/ðþ¬æÂüu=DSñ­Ýíž„$Óî>Íq%Õ¼]ö %D'‚pÇ­AýâOún?ðð§xûþ@PØFËÿJc®‚¸NÃþÆñ'ý7øøQýâOún?ð𮊊ç±¼IÿCÇþAþcx“þ‡üƒü+¢¢€9ßìoÐãqÿ€…ØÞ$ÿ¡Æãÿ ÿ +訠wûÄô8ÜàáGö7‰?èq¸ÿÀ?º*(þÆñý7øøQýâ?ún?ð𮊊ç±¼GÿCÇþAþcx“þ‡üƒü+¢¢€0¬ôírÚî)n¼M=Ü!°Ð›8>}ÀÈ«úïü‚äÿy?ô5«Sô_÷Çóªº÷ü‚äÿy?ô5  uK¡c¦]^”.-áyJƒ‚ÛA8ý+ž“ÄZ”Qæ[]9\WíNp}?ÕÖÇŠ¿äWÕyÇúßú¯—>$éß.|i©MáÍjUÑä5¬PÞÇpÒ¬¹ÎAç¾jg'{\èÃPUåÊæ£æïú'ùChž0–÷Ä6úEÅ”Hn#‘ÒHf, ‚ +ŽÆºñ_:~ϰø¾ÛÅ6Vþ4»7ÀÜ´,dYGå¯ Ê<çôXéN.êæU ¡7Ó·U°QEÈ!»¶‚ê!é½CAEWþɲþäß÷þOñ«ÔPì›îMÿäÿ?²l¹7ýÿ“üjõGû&Çû“ßù?Æì›îMÿäÿ½EQþɱþäß÷þOñ£û&Çû“ßù?ƯQ@²l¹7ýÿ“ühþɱþäß÷þOñ«ÔPì›îMÿäÿ?²l¹7ýÿ“üjõGû&Çû“ßù?Æì›îMÿäÿ½EQþɱþäß÷þOñ£û&Çû“ßù?ƯQ@-ôë8'Yã¼Å+4ŒØ¯SY!ã]¶ÿ¯ÿô8«¢®sÄgþ'Ößõã?þ‡iGøˆÇü)zÂïù&^ÿ°5Ÿþ‰J(ø_ÿ$ÏÂßö´ÿÑ)ED·eÓøÌê‘Ú·‹5gp¾pÖ-vúÿª³®ëWékÿ_Qÿ:óz;“ñ&ýÓ>Oöµ¶ïûõg^¬}ÛOúúùÖµÔ} ¦µ—©ãïùAÿa/ý)Žº +çü}ÿ (?ì#eÿ¥1×AXš…Q@Q@Q@Q@Q@Q@ÏÑßΪëßò “ýäÿÐÖ­OÑßΪëßò “ýäÿÐÖ€,^ÛÅwg5¤é¾£hä\õR0Gäk‘ÿ…máæ?4Ú±÷:„‡ú×S¬]=Ž‘y{+½¼*«t%Tå\«ñ3ÄV>»ñ‚ëÐÉ,6ëfOʃ,Ì|Ï•x8Ï\t ‡ÃþÐôMPjv‰t÷*ŒˆÓÜ´›Aë€{œWN+„ð狵ßÚisµ¤ð\Å+oŽ"…J¼Aô®î€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +æüIÆ»mÿ^3ÿèq×I\׉ä;mÿ^3ÿèqV´ˆŒq?— ï…ÿòLü-ÿ`kOý”Qð¿þIŸ…¿ì iÿ¢RЉn˧ð#ñ¿·Äëí¨/6­lÀÿÛ+:õ-_îÚÿ×Ôμ;Ŷáþ<Í?tÔíGþB³¯qÖ:Zÿ×Ôλ1ŒaI®±ÿ3› 9JU/Ò_¢3¼}ÿ (?ì#eÿ¥1×ATµ>NÍm§g +³G0(pw#‡_Ã**ÎÉ?ç³ß"¸NÂJ*=’Ïfÿ¾E$ÿžÍÿ|Š’ŠdŸóÙ¿ï‘FÉ?ç³ß"€$¢£Ù'üöoûäQ²Oùìß÷È  (¨öIÿ=›þùl“þ{7ýò(J*=’Ïfÿ¾E$ÿžÍÿ|Š’ŠdŸóÙ¿ï‘FÉ?ç³ß"€ ú/ûãùÕ]{þAr¼ŸúÕ“’7JÄ0*¶½ÿ ¹?ÞOý P^+ x_U' ²›?÷Á¯•¾"ü):ßî5«mL‹ @É-òK¶Y¢™Pùf=ùÌd€6ÿn×RÆ’ÄñJŠñ¸*ÊÃ!ê®wþ?ÿй§ÿߪ‰ÓEi+¢*S…EË5t|éû -ÌZòCsÐ4åct(¼„žŸ09Çq_WŠÈÒ<1áí"ìÝéº=­ÁRždq€Ø=F +×¢œ9"£ØT©û8(ß`¢Š*ÍŠ( Š( Š( Š( Š( Š( Š( Š( ¹¯ÿÈvÛþ¼gÿÐâ®–¹¯ÿÈvÛþ¼gÿÐâ­hÿâ…/Aß ÿ䙸[þÀÖŸú%(£áü“? ØÓÿD¥ø™tþx÷Œ'døÿ$C£jv¿ú*νïPµ7Q*,Í $‹"°àƒèkÀÉÿAFÿ¿ V­®`º‚;‹iVhdPé"ÊÊzGQRƒ‘š¡öKÿú +7ýøJ>ÉÿAFÿ¿ Wé7 ã“@~ÉÿAFÿ¿ GÙ/ÿè(ß÷á*îñŒàŸÂ”0$ŽhÙ/ÿè(ß÷á(û%ÿýþü%_¢€(}’ÿþ‚ÿ~²_ÿÐQ¿ïÂUú(‡Ù/ÿè(ß÷á(û%ÿýþü%_¢€(}’ÿþ‚ÿ~™6u:ysjNÑ–”D£8 ã?…iQ@Q@Q@Q@Q@Q@Q@Q@Q@R6r1@ Eq‰â}JXÌÑ›гmF‰˜¨ G'xÉãÐTÅÚ®âY¾N-œãÿ êŠàá1Õÿ—üþ.øLõ?Kûðÿü]wÕÍx—þC¶ßõã?þ‡fèþ,¿¼×ìtùãµhî™Ótq²2ŒùåŽ~î1ïZ^$Ïöå®zý†ý*ÖñŽ'øRôð¿þIŸ…¿ì iÿ¢RŠ>ÿÉ3ð·ý­?ôJQQ/‰—OàG“ø¶H‡ÇæRÛ÷êνƒÆš]浡K¥ÙÝGkö‡EšGî·ë·¾à6àñ‚kÄügÿ'ßöµÿÑVuô8ï]øåhQÿêÎL¼êÿ‹ôGŒj^ñ¥­Ü0éÚ‹Ü ZRæ M°³HvÌÀ0ÞÁ7 Œ¸ê}t.>xŠò0—Zêùe»}—íWG¶2Ìë’A>cìrHÊœ£>¯EyÇqåVÿ 5Ëuµ‚?J¶YÅ”.îï²¾sŒ7FUÚðöšôoÛ]Ùè––×ò,·qÆÒ+³ ø›'žO8íœUú(®_Ç£®- ±Ô¥±û7œÿ$ÒG¾F‰–"vU\«àñòŠê( /À^*f‘äñ<±Ê°ºÂñÝNCÜ—B.I%C,e:šê>h:§‡´™í5mV}Ji'2 e¥8Úäªã$ÚˆÉë]EQEQEQEQEQEQEQEQEQEQEQEQEPh¤#4ã¨òye¾d?ë£U‹I–8Š4ÒÂÞ`pÑ®IÀ#}ë·¹ð/….n$¸›H¥•‹¹:‚IÉ8 Qÿ¾ðý“þÿIÿÅP2÷zL“{^¬K–L–$÷ÿ•ñ9ž5b’>×RC)GPkëx[ B¼ª{h§koó<,ê­JjüŽÏþ?Œ1ÿ#ÿæ¿üMZƒÆ?ç·Iá×/ +9TÉb Ý´ŒíÜqž™® íÏQZÖ^#ŠÒ8CÜC…e2·ïÛ·zŒú•õUòì4#zT¢ß¢<:xšíûÒv:+ïxòÑ‘'ׯcw]áK!`3ŽF8Î;öæ«·Äovñïþ;þÎkZÊj—l¸1‹–\M 92œðÇÐãߨý¢ùêµ­,»à¹éE?DLñ5ùŸ,ÝKø{ãï^ø÷D±»×.®-®n„RÅ RJ· ö¯¤WîŽs_#|+a7Ä߈råoC œ­’}½ëë•û¢¾#Š(Q£ŠŒiE%ËÓÕŸI“Tœè76Þ½E¢Š+æ\(¢Š(¢Š(¢Š(¢Š+Íþ;ø‡TÐ4­1´Ûé¬ÍÅì7&@ÉŠôŠñßÚŒ”дI!ã†l ¡ÆMzY=8TÆÓŒÕÓg>RŽn;žrßü]Ÿ—_Ô1îËÿÄÕ‹xö+t™µÛÌ8"É8d d9äWöˆ1̃»§øšÎÖú=Cì(÷‰ÆÒùår\9ïŒWè•òü4téEü‘òTñ5Þ’“_y¬¿üpN?·u‘‘ò¯>ÿvž¾?ñÑ·k“¯_y*Ê¥¾QËGnzk2µÃ\y‘ü“8`#¸dh€ +«v_—‘ß?C¯ø·ûbÉme޲¶U¸AQ…ç89úÖQÁÒrIáâ»íþFžÚ¥´©/ÄÓoˆÞ5ÿ¡ŠûÿÿâkÙ~kúLj|1}q¬_Iy,Ír8Ûå£`à òƾj7tó¾‚ý—³ÿn¤ø;Rb¤ƒ†ÄQ‚G¯ùíýô)›­;áÏÔs^Oÿ‹|ÍÿÙ>úhÉÿȵjÛÁÞ,„’t IŸïj2qÿ’´{:o/äg§o¶þô?˜£u·÷¡üÅy¼^ñJH\øo žÇQ“úKV‡¼UÿB·ƒGýÄ$ÿäZ^Ê?΃ÛËùßn¶þô?˜£}·÷¡üÅpðx«þ…ÿàÂOþE£þïЯàßüIÿÈ´{(ÿ2·—üûg~¯nCÂÔSÄðÿÏXÿï¡^{ÿ÷Š¿èWðoþ $ÿäZ‡|RF?áðwþ $ÿäZ=Œ?™ëÿŸlô/>ùëýô(óáÿž±ÿßB¼èøoÅô-x?ÿò-'ü#>+ÿ¡oÂø0“ÿ‘hö1þtXŸò3Ѽøç¬÷УχþzÇÿ} +ósáлáü“ÿ‘i?áñoý ¾ÿÁ„Ÿü‹OØÃùÐ}bÈÏIóáÿž±ÿßB>ùëýô+Í—Âþ,?ðxCÿò-N<=â9ð·ƒOý¿ÉÿÈ´½ŒÖ'üŒô/>ùëýô(óáÿž±ÿßB¼ûþïЫàßü“ÿ‘hÿ„{Å?ô*ø7ÿäÿäZ=”™ëþFzŸüõþúyðÿÏXÿï¡^}ÿÿŠèVðoþ $ÿäZ?áñOý +Þ ÿÁ„Ÿü‹G²ó!}b_ÈÏAóáÿž±ÿßB‘¥† ‘èXWžÉáÏ:àxcÁËôÔ$ÿäZˆx_ÅŸô.øCÿäÿäZ=ŒÖ%üŒôMÖßÞƒó»­¿½æ+ÎdžOþE£þŸÿзàÿüIÿÈ´ý” ÛËþ}¿ÀôMÖßÞ‡ónµþô?˜¯=ÿ„kÅô-x?ÿò-ðx¯þ…¯ÿàÂOþE£ÙGùÐ{yÏ·øƒºÛ<4?˜§¬°/HÀöa^wÿߊ¿èZðþ $ÿäZ?áñWý >ÿÀù?ù—±‡ó¡ªòÿŸoð=Ï‹þzÇÿ} +<ø¿çªßB¼ëþ¿гàïü“ÿ‘hÿ„oÅ_ô,ø;ÿäÿäZ=ŒÖ'üŒô_>ùëýô(óáÿž±ÿßB¼ëþ¿еàïüIÿÈ´Â7â¿ú¼ÿƒ ?ùcçAõ‰ÿ#=χþzÇÿ} +<øç¬÷Я8>ñYÿ™oÂø0“ÿ‘h_ x°ÿÂ9àóíöù?ùŸ±‡ó úÄÿ‘žçÃÿ=cÿ¾…s~#‘]¶ØÊرŸ¡ÏñÅXCÃÞ)Ç>ðiÿ·ù?ù›>‰ã¤´4½Â7¡A0¿”…÷*-—v=3NŒ$¥Ì´"­IÔƒŠƒÔé>ÿÉ2ð·ý¬ÿôJQWü!¦Ë£xOGÑç‘$–ÆÂ gtû¬É©#§W<Ýθ«$ÿÙ +endstream +endobj +869 0 obj +14044 +endobj +870 0 obj +<< +/Type /XObject +/Subtype /Image +/BitsPerComponent 8 +/Width 676 +/Height 588 +/ColorSpace /DeviceRGB /Filter /DCTDecode +/Length 871 0 R +>> +stream +ÿØÿàJFIF``ÿÛC  + + + +    ÿÛC  ÿÀL¤"ÿÄ + ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ +%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ + ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ +$4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?æÿbïØÓÂ>øGáoxËÂÚ‹¼eâí2wý¤z®Ÿ¦Ù^F&´†+Iƒ[³i!‘ä’7I+ª²ªŒûå—ìùàÝFÝfƒà·Â á|íxþ茭ƒƒ‚,ýAª_—þ1ëáÿªoá?ý0Ø×Ó? >Çñ³à_äðÖ£ê~5ð׉å2ØÝÛÇ#ÞØTŽÝ\áâcìØÉ÷q_x²¶S4¨áã^¥xÎO™ëî(É¥£mûÏNËKìpð7áów‰Uñ2¡N„©År¥eÎåÞ©$¹V½Þ­n|ó/ìëàËXL—¾A “áŽ†Š 8›>äøÕÍ?ökð æ1ð‹à§?õM´/þD®ŸÄ~ð÷„5ÿE¢ï.ÿ¶¦±:Ýù°Z»lV²ÆÁ½qæ.vÈ7€Ri¿´Ö»ªøöxÖ5êshš¸žÆÚ ø †imD×°Bì«2Im’67£ ãƒ^WñÒÏ)⥈‡/Âù¯Ì›ê£µ­ëèz|}À‹‡å…ú¶*u~o‰rµÊâº9hïC:/Ù3ÀR&áQ|ÿÃm¡ò% û$xòH¾ +ÿá¶Ð¿ù³~!|C×ÿewZðߊ~!x»Å:.§áÿÙëQizBx‹Ckìá%¼VSFâò#™o”e38t÷ûfø~?‹ø]¼#ã±Xø’/ ^x­-WH¶Ôf‚9¡˜Î'e“ÍÇ *»…r™¾ñW ÜcìÕå¶‹ù¹?ô«%ݵmÏϧJ´Sn£²×wµ¹¿+¿“8çý“<  > +ÿá¶Ð¿ù£oÙCÀãþi/Á_ü6Úÿ"VwÁÿø(o†¬g­Kľ,»½Öcð‚]ë¶Éiav/Þ ]5åi"Œ]Ȧ/‘FØ”£Nð‰Ÿ¨ø ÿ øuûBêºTW¶¯}ª\è­+Þé·ö¶×‘Y­êÂ×67w1–ÛÍt1Hê>Ï*¹ÀVÆ–; R*JÕ)j–Ïoëç±¢Ââyy¹¥÷¾Šýû–æ#þÊ^ íð—à¯þmÿ‘)‡öSðHÿšMðWÿ ¶ƒÿÈ•å_ÿl_x¯ã-ËøGž3ðÌ:†<7©ø+@—Ãv’iZíö£{C©Þ=¤ßdŽå`¶TêÝñ#l@P{F¥ÿø]¦~Ó1ü,k¥›[:ªhRÜÇ©éž\íñµk±~Ü•O5-Z Í‚ãk•ÑâpêJ2§Û¶Ëum=uJÏ[¸«]¤ÔèWÛ¨ôI½^Í_ò¿Üû3 þʾ Ïü’‚ßøm´þD¨ßöZð` ¾ áµÐù—Â_ðR xûLÑî4¯†®›ÅTÚχ`E¢¾»o"Ý4ln¼¸×-vÐ$™_%¦ßý­Köððƒé“kZ7†¼_âi–Zžµâm2 ?ìí ¨åušæ;‡)m$sÈ-ᘤr)#'m\kÐ’º„~å¦ë]4Ö/~ÅO ŠŒ¹%)_µßKm®»­¿FsÍû-x@Ÿ—áGÁoü6ºÿ!Óì·á$ëðŸà¹ÿºk ÿò%;Lÿ‚†éŸn>+_|DðÕχ4øÂ èWr_iv©­<¶V·ÃæÍ~"IXK$Þd­+G¹„‹"/г·ÇþÒß®>#iöz†ôé.âÔ§½Ô,ä‡LkR|ã%Í´óZ²*þds<{H;ºã æhýˆì›ÑhšO];5~×]ÕÚÁb[Qç–®ËW«×nû;w³ìíàP~ËÞ aó|%ø-Ÿû&ºÿ"S¤ý—| ¾ û¦ºÿ"WКŸˆ|7ñö{ñŒþøŸÃ¾'Óí4ËÙ¬õmú JÐÏ N~Y#/uäsÈÁç~*׬4ŸÙÞîk²ÑøæÑç×BÛE›íºל|£aóP7É·¦:qE<ÓÜÓ§È¢Þ‹ió[ÿHwùZæpؘ¸ÇÚJò涯ìò߯÷—âyÄÿ³'ƒÓ§Â‚ßømtþCª“~Í~Sǯ‚ãþ鮃ÿÈuŽ¿à¢–·ÿ³Æ¿âß |<ñ­–¤Þ—Ç>‡Ä¶PÅ­Ù*Æp‰y¼GM •\ÆìŽ "PÊM?¶&±ðëIÕ¯ô¿ xÊóÄÖ°øUï<5~šAµÒ¡ÔõíK¤‘Ý+<î!t ÜI»Ûùå}o‡Qrt•—÷WwÝiökR#ƒÅÏ—–«×oyÿwÏûêÝú.?g? ¯O…ŸÇýÓMÿë3Sø á»D$|.ø0?î™èü‡N׿n½#àn©ãë¼Öë‹­´MGšëL°žÜ6‹e{,s=Ä6ƒcI;–çˆÎZ59¿?o½Æ_5=oáÞ‰â] Ük“ÜiQXܧ†—uÄÉpZãdØžÖàmµûIanì)Bõaÿ€¯òíloüþ—þÿÌÙ>3²ÿ¡ à×þò'ü&Vyÿ‘ àÏþòey|Ò³GöNþ|Ãÿ_ä/íloüþŸþÿÌÖ>1³ÿ¡ àÏþò*øÂÈù~ ÿá°ðçÿ!V?•ŽÂœ©e8ùóü‘/6ÇÏéÿàOüÍøL,¿è@ø3ÿ†Ãßü…M>1²Ïüˆ_GýÓòel†?ÆŸöFþ|Ãÿ_ä/ílwüþŸþÿÌÖÿ„ÆÏþ„/ƒ?øl<9ÿÈTŸð˜ÙÿÐ…ðgÿ ‡‡?ù² + ô¤)Í?ìŒüù‡þ¿È?µ±ßóúøÿ3`øÊÏþ„ƒ?øl<9ÿÈTÓãK0?äBø5ÿ†ÃßüƒY[8Å5“ñ£û#ÿ>aÿ€¯òílwüþŸþÿÌÕ>7³ÿ¡ àÏþò !ñ½ ?ò!|ÿÃ_áÏþB¬w‡¾ 0ÇRòœüù‡þ¿È¯íloüþŸþÿÌè`ñ¥‹ýïüÿÃaáÏþB«öÞ)Ó%ü?ø3Ÿû&>ÿä*ä¡&6«örŒŒ÷©þÉÀÿϘà+ü†³loüþŸþÿÌé?á!Óÿ’}ðdû&>ÿä*_øHt¿ú'ßðØøwÿ«&1¹iê9Ádà¿çÌ?ðþE,Ûÿ?¥ÿ?ó5F¿¥‘ÇÃïƒøl|;ÿÈTÂA¦Ñ=ø1ÿ†Çÿü…Yˆ yLÔ¼«ÿ>aÿ€¯ò)f¸ßùý/ü ÿ™¢ÿä*ÈÁÚ•_ÔÒþÌÁϘÿà+ü†³Lgüý—þÿÌÙ¾‹Î~|ÿÃcáßþB¥:¾ˆü“¯‚ßøl|;ÿÈUŒÍÏÉZ_Ù8?ùóü‘k5ÆÏÙàOü͵Ö4<óðçà·þò?û[BÇü“‚ÿøl|=ÿÈUÏ™<Ð.°$‡”àÿçÔðþF‘Íqóö_øÿ3¢þÔÐ1ŸøWýÓòHš‡ˆÿ’mð[ÿ ‡¿ù +¹–»*)WPÇzÊYNþ}Gÿ_äo×ÿ?e÷¿ó:ø/<6㟆¿ðÙx{ÿªÔMá–çþ§ÁSÿtËÃßü…\l:‘SÖ¯[ê|uýkžyVþ}GîGDsLOüü—ÞÿÌìm ð«°ÝðÇà©þ©—‡¿ù·tÁ—'ð·à£Ý4ðÿÿ!×iªã=+sGÖ¶° óõ®ie˜où÷¹1Ìqóò_{=OÂ? >ø±¡ŠÿáGÁ“k~Êøy¢@Å$ñ•ªY-T•xe•IÃ+° ƒ_O/ìÝð ÿÍø ÿ†ãCÿäZù_ÀÚÔƒ@Ôd…±<7þt8ÎxŸG ×;©|ø…•tðjngH˜Æ¬Dîãœó_5ŽËa*òäŠI%Ðú,a5F<Òm¶úŸeÿÃ6|ÿ¢)ðÿ ƇÿÈ´Ù³à8ø)ðÿ ƇÿȵÍþÎ8ÿ’Ùñ»ÿò–¼â¯Æ«ý;â~»mà?kÚ߃ –!¥ßktPÞ\)·…¥Þ¿fƒ¤æe»^uûÇÆÃP…iò(5ê¬{Š•(ÃÍ?F} ~Ì_à¿ñ4ðWàkíµŽ1'ÃÝÖ4þÊÓ$Ú€Û«¾Wl.]RkWLý•~ kÂfÓ¿gÿ‚7ÑA'”òGðïê¡¶«cçOF±Í|µ¬üdñ•Ÿ‡§–@¬×É2Ÿ³Æw¢è¸þ:šÚð·Æ+ï|2}7Zñ@Ò¯¿µMîæÒþÐD"1ò…Ûëÿ|ôïVòæ©©$·ìguæâï·ùEjŸ²·Á­BÚìÿðFÆ+‰<¤’O‡~e-µ›$ z)íŽ+Žø¯û<ü Ó£ðÝÕ·ÁŸÑ¼Z¼ÛÄtTYi:”]E¶wFµ‘N2 $ñoÆ+ïü/M3Eñ@ÕoÿµEî᥋`Ša1žvú~};מøŸãµO @%Ô ÉíÓEþà Y#ø}@¯?3ºX•íðÿš=®©FiG ö—}¶{žëgàOƒscwÁ¯€Ÿøm4þD­~üqÏÁ€¿øm4þD¯†´Ÿ‹IÔúu‹ÿˆ®–Çâ—Ä'Œ··þEÿÄ×ä8ž"­¼¾ÿø'õÃì MãKî_ü‰õþ‹ðkÀž"Ðü%©X~Ë µ Jmü7=—ÃO +ÞG«N§ç‡t(âÚDU‘nŒ%Þà¶ß&]Œ‹á¿Âu_LÔ~| Òµ]ùôëûI~øbäÛΊ¥ÓÌ·†X˜®í¬ÉWWF +ÊÊ0ÿd?Ú÷Dý›~j6©â¿ßêŸfaâ 4 iì!ð:5»Â·Pn‰|ÛܼfI!VâþD~ͺωüQàNïGðçˆbÖ46C …ô:CY-ÜX_Éš5tnpÊAƒaœa·šæWÃ*´äÛm]sÞ×[o¯ôö>#…ò(f”ð˜ŠPŒ“Œ';;^íièý7>¬¸øsðb1ÇÁ€ƒþé¦ÿÈ•ÄüDýž~ |E×ÖO„ãµo ë $zg„4ý)™—RÐ\Ig2¤Š³J«":º d +Ã{gæ½Kâ·ÄA¸ A‡ýºÅÿÄצ~Éž.ñ'‰¯ücÇÂ3ÿTߟúb±¯§¿c¯Œ¾ +ø âoxŸU³ñ-þ·­]Ê`ûå¤vÑÚ±ÜH¥¸Œ´Ëd²6‚„ƒ“ó7Âymtßهᖡ9µÓ´¯…>Ô¯&™+{ZO+*ŽY„q¶Œœ Œæ½þÇ¿‰ÿ’Iñ7þÿøcÿ—uáq`s5‚¯‰®éΊn:'ñ(¦ìÓÚÚv=ŽâlvV±¸l5VÚRÕ¯…É¥tÖŽú÷6¾:|lÓ>+øºMZÓÀš^ƒs&¡ÅΧ¯’ßE¡ã/meî q¹²ÛIaÈ|Gðnñ¿á†¡á{íKSÒ ÔL./4óº¶x¦I‘ÓÍŽHò5áÑî+]?dOŠ‘ôøKñ7ÿ<1ÿ˺µoû,üX·û¿ þ&ÿàG†?ùw\|9ÃY^Rñú×´u­Íuí}¹#ùÞþg_ñ>gœÇMá=”h^Ör•ù¹wç”¶åVKEØä!ý“ü;â øºxÃÆ~3Ö¼e¦bÜ뺬öi{ccßfµŽÞÚ+XP¸ÞÅ`Ý#]Ÿbè¯>xZõ50÷ú¸¯Œ-/IÓáWÄÁÿoÿåÝee±Š‚¨¹U´é£M~]5¶‰£hK1‹º¦ï¯â­øGÕ=L|ðWеOÜ]µð‹Ç^±ðÍí¬3$PÚ[YµÛ@öûP4r©»s»qÁŽ2¡J’s| ðB/†ž<¸Ö4Ÿ‰^=†ÃRºú¦‡)Ó%Óµ;£ +Å,ï¾ÈÏJPHëo,Hd,ÁsgªÙgã >|KößÃü»¨eý”>1Iÿ4»âXÿ¶þÿåÝk)eòŸ´•U{[~½;­•öVË“ËËì¿à%÷ÙY=Òõg/à/ÙûÂ? -|Ž¥­J¾ðÅß…4ó<ñ1šÖàÚ—yvÆ7J>É +í_™²§#ì?àïøR/ é~4ñæ•á;­#NÑuÝ «iâˆlíÒÕZ轫J’KopÊÖ²A½G^·'ì‰ñ•³†‡ý·ðÏÿ.ê¬ß±¯Æyz|3ø?í·†ùwZƦ^—/µVÓð»×º¼žMK•L;gNWÿ‚Ÿæ‘Ždÿ xçÅõõ§‹|cáË­s]±ñE´šLöHÚ«kVÂòÕ¥¶‘·Im +Á$S`xÙ×ËØŸ¬¾é·>ð¶ªx¯]ñä,ìú¶³”Ws†bB²ÙÛÛÁ…hÛ8$œ“àžý”þ/è:‚KqðÓâ1U뙼7ý5£^æü=øk¦›áÄ-ã¿Ú¹û>øPÔ®u{oøÇJñLúÔzòëÖsY-ä7+§Å§È5³[´rà +—áeÞw(]©· âïìë¤|DŠækψ_ ¿Ö4Eðþ¿yescm7‰-Q¥h…ÆËP‘´fy€kU€‘+,0ª·üçãkù'Ÿï熿ùyP\ÿÁ;>6\©áçÄN駆¿ùy]äÒMN´Z{­m·.ßáÑ®«sÌqÎ4jŒ®½:4×ÜÒk³ÕkâÙèÚ¶Ÿo+É ” or E + Æp=+ÉüS«}¶á°x5ôußüã5çÞøyñþûð×ÿ/*›ÿÁ)¾/Èrßþ!Ÿø†¿ùw_AC=Ê¡«®¯óÿ#À­‘æ“ÑPvù™òýWºMÀ×ÕðêO‹›qÿ +ëâý÷á¯þ]Ó$ÿ‚P|]pâÝ|Bÿ¾¼5ÿËÊê\M•ÿÏåøÿ‘Éþ­fŸóåþæ|ƒ«Ù Ås÷pln8¯µnà’?®ð¯> ø†¿ùyY—?ðG‹óçø€3ïá¯þ]Õ®&Ê¿çúüÈ?Õ¬Óþ|¿ÃüÏöšr'>õõ÷ü9Ÿãÿ™ ÇÿŸ†¿ùyJ?àèAñÿçá¿þ^Qþ³åóù~"ÿVsOùòÿó>BØsŠTL0àW×Ãþ×ñ‡þ„~~ÿååðæÏŒ?ô øûÿ-¯þ^P¸Ÿ*ÿŸëñ%ðÎiÿ>áþgÈ› zW×ðæßŒ_ô øÿóðßÿ/)Gü»ãäAñÿçá¿þ^SÿYò¯ùþ¿òáŒ×þ|?ÃüÏöJpQé_]ø#wÆÿȃñóð×ÿ/(?ðFïŒ_ô ü@üü5ÿËÊ?ÖŒ«þ¯Çü…þ¬f¿óáþæ|ŠTI³ŠúëþÝñ‹þ„ÿåµÿËÊ?áÍß¿èAñÿçá¯þ^S\Q•Ïõøÿ«¯üø‡ùŸ"„õ §¥}t?àß³ÿ"ÿ? òò”ÿÁ¾0ÿЃñóð×ÿ/*¿Öœ«þ¯Çü‰ÿUó_ùðÿó>C*E4¦y¯¯áÍß¿è@ñÿçá¯þ^QÿoøÇÿBÄÏÃ_ü¼£ýiÊ¿çúüÈ?Õ|Ûþ|?Ãü϶ +Bž•õ÷ü9¿ã?ä@ñÿçá¯þ^Rø#oÆ#ÿ2ÿ? òòõ§*ÿŸëñÿ \/šÿχø™ò!#¦4uöü9¯ãý?? òòšßðFŸŒDÿȃãÿü¶¿ùyGúÑ•Ïõøÿ× f¿óáþæ|}°V ?/ò¯®?áÌÿ¿èAñÿþ[_ü¼§'ü«ãtðÿòÚÿååOúÏ•Ïõøÿ‘_êÆkÿ>áþgÊÖr`sŠú¢ø#·Æ8ü“ÿˆñð×ÿ/*qÿ‚øÂÃ߈'ñð×ÿ/)­Wüÿ_ùþ¬æŸóåþæ|¨§¥8.êú©àWþiïÄ/ûëÃ_ü¼§/üã +ÿÍ<ø…ÿ}xkÿ—”¿Ö|«þ/Çü‡þ¬æŸóåþæ|§´ƒÅ.ú×Õ‡þ ñ€ÿÍ;øƒÿ}xkÿ—”ŸðèŒ?ôO> ÿß^ÿåå'ÄÙWüÿ_ù¸k4ÿŸ/ðÿ3å=˜>´å\šú¯þñ„ù'Ÿ¿ï¯ òò…ÿ‚E|`_ù§¿ï¯ ÿòò—úÍ•ÿÏåø•þ­æóåþæ|ªSñ¤)Žq_Vÿã>0ÿÑ;ø‡ÿ}xgÿ—”‡þ ñ„ÿÍ;ø…ÿ}xgÿ—”—eóù~?ä †óOùòÿå@„ÐTŠú­à‘ŸþißÄ?ûëÃ?ü¼¥?ðHߌþi×Ä?ûëÃ?ü¼¤ø—+ÿŸÈêÞgÿ>_à|¦ »ƒu¯ªáÑ?è|Cÿ¾¼3ÿËÊCÿŠøÃŸù'ÿï¯ ÿòòõ“+ÿŸËúùáÌÏþ|¿ÃüÏ–6Ônv““_Vø$_Æÿ4ïâýõáŸþ^PßðH¯Œ-ÿ4ëâýõáŸþ^Qþ²åóù~?ä?õs3ÿŸ/ðÿ3äé0rzŠI +ç<ŠúÉ¿àŸI8øwñ óðÏÿ/*7ÿ‚?übnŸ~!ÇÃ?ü¼£ýeÊÿçòüȥùŸüùòkË»¡¨Þãg^Õõ‹ÿÁ~1¶âÞüBÏ×Ã?ü¼¨Ûþçñ‘¿æŸ|Büü3ÿËÊ—Ä™_üþ_ù¸{2ÿŸ/ð>Qdt=jx5>qž•õ!ÿ‚7üe?óO¾ þ~ÿåå ÿ‚7|f?ð¯þ þ~ÿååfø‡+òù~&±È3%ÿ.YóU¾«ïZºn³±ÇÍÖ¾…þïñ™ü“ïˆ?Ÿ†ùyVaÿ‚Büfˆ‚~üB$µáŸþ^V2ϲÇÿ/‘¼rLÉoIž[àOGkÕ¥Ë\‹-J$‚vµ—ʹ‡dÑͱ9,±ÍR! ®è×*à ú%¶»§\*“«è³>i'ð$þd‡»7•®GO}‘¢ú(é]Ÿÿ¦øËbÀŸ‡?áŸþ^×A§ÿÁ6¾0Z»á—ĆǤžÿååy˜Œ~UV\þÙ'äÚ=,> 3¥EIµæ“8¸¯ì¦©áÏü!/?ù ©–{#ÿ1O þ>¼ÿåýwðÿÁ<þ.F?ä–üIÿ¿¾ÿååXöø¶˜ÿ‹Wñ+þÿxcÿ—•Ç,N[Ò¿þLÎÈÐÌçÏà=†òÝ-î’moB¸K›Ï¶…Ü }šÚÛjí×AÛ²Ö3ów9Á!›NÇü„|?ÿ„5ßÿ/«Òì ñgòJ¾%ÿßï ÿòòø`o‹'þiOÄÏûýáþ^V>ß-Z*ßù35öY‹ÕÒüæÂ]8ù x{ö#]ÿòú©ë6vº—ØŒZö‰h,î$¹Úž¸uœ½¥Í¡WÝ®ç.¤#ip^HU°7ÅxøSñ3þÿx_ÿ—”§öø°æ”|Lÿ¿Þÿåås×yeh:u*Þ/§3:pµ3L=UZ;Ilì´ð•„1®x?ö ]òþ¶¬,ù¥ý¶ð¿ÿ/*Å·ì/ñfØø´ÿOý¶ð¿ÿ/+ÄŸðÜ·IüÙô°ã>,ŽÕ$¾Kü8OÂãþCÞ÷!]òúœÞ …Æ?·¼7ÏýHW_ü¾¯U‡ö0ø­ÁøGñ8ÿÛ ÿòò¤ÿ†5ø«ÿD‡âþx[ÿ—•êç ÿ,~ökþ»qoZ²û—ù9uðÖ ®ºÿ†GýÈü¾­-Ãö>Yå‚ñ5-BîͬXô‘¦[YÛ´ÑM"C ¸¸´’A;É3dAª _Ô‡ìsñTuøCñCÿ<-ÿËÊåüð›Ä µ, ÅáåK98=ôGåŸü ÿ' ð—þɼú~Öè¤ÿƒ€¿äà¾ÿÙ7ÿOÚÝÉŠþ4ý_æNø0ô_‘ú¤&`mã§ÀK?ýCc¯Ö-W⩳žäæ&&`>QŽ3ï_”:2göÑOýP;?ýC£¯Óoˆ+>£ëw¶š]þ·uk óçY4+s~ê¬Ë Fi#ˆHäS$ˆ™a¹Ôe†ùÅ>zÒß“O[dͪ•¿Æ|—ûÁVµŸ¿,¼iâO®¯¯D7Ú†¼-us{áyï¯a·û%⦳<¥äi<„vŠæ:²£G^Ÿàø*Ž¥xRÔ¼|/ ÔGŒ @šÛR}+Q²¹-¾Ÿ«ÝJ’L ` |ˆ7ä…Gâ—üÃÇòèúÔþëÚ¶‹âjñÛøãÀ1ø›D–ß[¿ûkÂÖMu ¬ð:Ä©p“®@”È“ æÎ”Tš§¯y|½Ë=uþe«Ñ~?FåM¦Ûךÿöï,¾[òôí¦ìûcIøÙm¯iV×ÖNnìïbIàž"9£`]H8 ‚#¨5%߯±´–yRuŽ.çfpÉï\¯‚¼ÿ§ƒt/ËÓbþͲ†×f›eö+4òÑWÁ¹ü¨†>X÷¶ÕÀÜqšw‹b—Hð¦§w‘{¯Oki,Ñé–mÜj,¨H‚3<‘ÂÈÚ¦Y2Ãs¨ÉWÃÓ÷•/;_ð¹ËJs´}¦ú_õ>|ð×íÿñq~øcãµkàh¾ø¿RÓÒ Ã¥ÝE¯éZf¡q½¥ôº‹ÝùÊ<èf–ØYDZdtY¢ /¢Áÿ`øO}âëí +Ó[×/µ=>÷QÒäKo êsC%ý€˜ÜéñÌ¥½U‚W[TfšDÑYXü—á†ÿ´}/ÃÞ¼øMñªëàß„5+mGHðü6~ƒYhí'[‹; ­Hø£–Î 0;H¥hà…gĦnÿöSýüsâ?]j+ײ¼áߊž*ñF›á¹<9-¦§u<š–£¼ïz×d³hî<ôE¶ Ìco9£ù4¨©' +JÚ6¯º^âW{7¬¬îôº­¼Ý ê7w{i³ÒoN«XÅy'³•ïéß³×üƒÃÿ¾øÆš…êø Lñ?…u_èÚæ…±%¢Ú<÷j‹x~Ën·#t†YüÅhÝDNMgÿføG?µ¯]kÚÖ‹¦øxØõÖü3©épÇ}:ÛÚN-® Žw·–Vس¢‰WùþFÇhðJ‰oþøcÁ>*ñÔZ®á_ëÿ­ßKÐŽs.©%ŒqÈï%Ìëö˜VÌ呤ˌ.ÖÜÕÿàŸž+ø¤_Üxûâ.‘­xžâOAm{¤xUô»+k-'U‹RòͳÞNï<ò#+ËçQåì‰v¸“c4’´zù')y»Ùré}.í)YD%(¤šwwuãoÙú¥t®íéÖÿðU?†7ž þÚ‚óÆk/áöÒáð^³&»ú[‹—´µ¶7ÊDJK@FÊÙÚA>Ãeñ‰oìáž8o'A"‰!18dnVÃ)õ:_'üqÿ‚wêÿn~!]hž*𮙨øïÄ–þ ‚÷VðÅÕõ߆Þ" 4=„öºœÖ÷cÈ2-ÊH¥DŒ›%Ѿð›xö]Ýê2Y[Gn×WL{’ŠÉ!팒äš)Ѓ‹sV~ïþ“ï}ÒÑywÜÊri®Wtï-t_w^ë¦ÇM?Å£Â)òªHùGø×Äžÿ‚íxOŲÃÍvËÇ¿/~0øªçöz‡…-µ¸$š ¯uK{Ø£³Få^(¦™‚±% +Á€ ýcâÔŸEð¦§yi¥ßëwV–’ÍdЭÍûª°Äf’8„Ž@U2H‰–FX|Kgà/Z~ľø;ÿ +ã“ÿkïðhûgö]õ­ßúøHþO7ìÛ?Ö6Íùù±ƒ1£RòZ^w3æü-~ý !?w]Ï ÿhø*Ÿ†| ðÛâ—ü"WZŒ| áÝgQ³7Ú 4;Ëí>ÚI$µ[í‰kq$n›e‚ ƒ*yr‚Æûv"ÿ‚ª|2Ó¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èhú½.ÁÏ#oþ¿ý3ŸþùãGü-úg?ýò?Ʊ?²G¡£û$z>¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èhú½.ÁÏ#oþ¿ý3ŸþùãGü-úg?ýò?Ʊ?²G¡£û$z>¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èhú½.ÁÏ#oþ¿ý3ŸþùãGü-úg?ýò?Ʊ?²G¡£û$z>¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èhú½.ÁÏ#oþ¿ý3ŸþùãGü-úg?ýò?Ʊ?²G¡£û$z>¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èhú½.ÁÏ#oþ¿ý3ŸþùãGü-úg?ýò?Ʊ?²G¡£û$z>¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èhú½.ÁÏ#oþ¿ý3ŸþùãGü-úg?ýò?Ʊ?²G¡£û$z>¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûäðµÿéœÿ÷ÈÿÄþɆì‘èhú½.ÁÏ#oþ¿ý3ŸþùãGü-úg?ýò?Ʊ?²G¡£û$z>¯K°sÈÛÿ…¯ÿLçÿ¾GøÑÿ _þ™Ïÿ|ñ¬Oì‘èhþɆ«Òìò6ÿákÿÓ9ÿï‘þ4Â×ÿ¦sÿß#ükû$z?²G¡£êô»<¿øZÿôÎûä|“ÿñ7ü$¿¼ &×_+Á¾&_˜cþb¾÷¯¦ÿ²G¡¯–?à Ö¿fø©à‘Ó>ñ/þ|/]X0Ž"+©Ç˜É¼4ïØüSÿƒ€Nh/„¿öMãÿÓö·E'üüçöøKÿdÞ?ý?ktTâÿ?Wù˜a¿ƒEù¢ú(ÏüÿEÿ² gÿ¨tuä_ðòg§ˆ4ƒÿr–‘ÿȵëúÿÆ¿toû vú‡G_0éžÔ\‚"Ïá_¬ðNW…ÆB_Y§Ú4íÍí~kÚû^Çæ\K˜âp³ÿgœ£yNöm^ܽ½OBOø(ÿÇé®éGþå-#ÿ‘iáãŸè;¥á%¤ò-sÚw‚u" ÿ€Š¿ÿeò!Ͳ“ß寺|3“/ùsOÿù.¸ƒ4zûiÿàRÿ2ôŸðR?É×_ÒGýÊZGÿ"Ô/ÿ0ø×ù¼E£¯„ôþE¬_—„Ǧ=‚×=¨x:ý‰ÿD|D4¥ÂÙU¯ßý¹òx2½¥Zø¿Ìïü×ãGoè¿øIèÿü‹H?ি‹`x“E'þÅ=ÿ‘k˧ð \•´ÀM:Ïáö¢\k/¯Ý5‡ú³—ßýÚŸþò6ÿXqÖ¿Ö'ÿËüÏXƒþ +Añºç§‰tQÿr–ÿȵ£eû|r¼¢Lå]t²Œ‘퇥ÿ€CüŽY晲zשÿÏüÎÒËþ +%ñ*loÖ4ÕÏýJúWù-Z1þÞîÐlñ•=Ï…´’þKW§ü?d â$#Œ`ü«Gø;s­þÔ +súS©”d±Wúµ?ü?üˆSÍ3fÿÞ*àrÿ3§³ý²>*^È»|]¢'¡ðž“ÿÈÕ½eûPüV¸PWÄþ“Œœø[KÿÉzÊð÷Éxi éÇ÷í–ºë[ÅY"vϬ +3^E|&Shá©ÿà¸ò'¥C™µyb*àrÿ2´?µ7ÄØÎ%Õôf÷_ éƒÿmêy?iO‰s·]ӣϧ†t®?;SVÁö8 Èã²ÖÎàk` ¾A癫†t2¸«ýZŸþò;!ˆÌ^ŸXŸþ/ó9føññj䓊lvÿŠWGoý´§Çñkã5Áý©¾+jR/á½" z‡ðý ñW»Û|+Òã”afNç«W¨ü.ýžtp$—Ü*@KƒŸÕklnm“R‡7Ô©¯ûtË —æµ'Ëõ©¿ûxùßÃü¬/ïô­ + úh¶yüŒ5Ñ/ˆè><Õï-Á»Ót8˜uÛ¥Zsÿªññ¼éÃZhÃþàö¿ün¬jºbÅ!\AǨÅö™Ú7“hÎɯAap³wT¢¾HâxœL4u%÷²ÔÞ:¹WaÑ '£iƒÿiÔW¾>Ô,dA.Ÿ¦¢ÈxeÑ­è®kÆ~&xÓTÔ5¨¬ìí5C6<Õˆ¾ù¯¢>~ϺNJ>ÚÜj>+°–ÍÛ/îÐsŒž?ZéÆåø<%Ö­¤ú[_ÁaqؼMWJ”¤íçþl­¦ê×wòB•OŒt[B­Ÿ+¥Wñ6«ªx{W6rÁ¦Å9è¡Ú?8«ÜOÁ+m+EÓ¢¼ñ|2YÚÈ>Í9Ž0ñMùä}køÅàwñŽ4«ŸÚʳFD:¡D!Î8?|þ‚©Vʶ¿g·ý»÷¯¸ö«PÅÂÜå}>×ûxðSã^¡eãEðø‡LþÔT˜¿°ìþd üßê}«Ãö„Õuo_höë¦É¨éãtЮ…bvöýOr+¦ñ'À‹|mµ¯í ñöý­×Úr1m¡›D² +£ÔŸ&½áÃdÔìµëÆñ,6-nÅ“1î’çýÑÓ'µÎhzf¡o«M+µìê§æþ/|+¢0Ë[”c‡§xÛxõû’0•LzQ”«Ï_>Ÿ}ÍÍÅ>.–ÍEËhþqå‰ÐlT/·úš¼þ ñQñ6+žË Xÿ¢k VñaÓAß3B{³ùÖ¿ô׸0¶½ ’¨$ÇøW4rÊu5à üއ˜Ô†Ž¬¿ð'þfÞ½ñGÄZH‘§½ðýŠÆ3‡Ñ,þA¯9ñí…©ÙXÌS_ðõ»Æp ðíƒ1ü<œ:ím,t/!ûc‹…ë…n¿•`øÇá—€‹É6–ÆLuäס„Âe±—-l:oÊýQʼnÅcåjUÚ^r—èÏ8¸ý»µØ,öèO;>Ó@‡•T›öèñ=€UŸÆ>g“SÂúbªþpéY3ðßÂ=0´Ú_,¬pBãò¬+? |.ׂÃA×f-üksøšúºyFRã̰šyÓ‡ù;<Ï3RåxÇ?ó;(ÿn^Ì`‹ÅÞW=$ÿ„gKÇþ“ÖÞûDüBÖâWô‡fèSÂZV?ôš©ü=ý—ü©D¬¾ÕG9 30?νsÃßt/ Ù·Ò<¢2Ùþ¦¼¼bÉi{´ðÑ¿:äwáe›T÷§^VòœÿÌä´üRÖÔ©ñ¾›Ä<¤Ÿý·«º—¾"h0—Æö·,¼‘ÿ¦ŒƒÿIj÷‹ôi4«söX¤ˆîÒ¼3âÝåÆ×ui¶ó…|úŠË—a15¨ÓKþ½Ãü18üNõj7ÿ_'þgo­~ÖÞ8Ѓ#k;2½&ƒ¥o^wâ/Û×âœ7n¶ºÖƒÀ>Ò˜ÿé5xÞ¯¯?Ûvˤ]‘Ÿã|“ú×Yà‹?^‰m:þìQAô¯«§Ã™]óÔÃS—ý¹ò>ryöcV\°ÄMÛòÿ3µÑ¿lŽzó³ëš#ëám$ÿ’µÚè?þ>k( ø›ÃPg×ÂúIÿÛZ³ðçÂúŒQ—³ÔXŽ»Ë ×©è¶¾…ý ”ÿµêkçqÑËi¶©`éÿพîy„Òu1SÿÀäpx×ãZGºoèð i'ÿmªŽ¯ñ£â¾„·‹ôÇ#ÓÂZG?ù-^¿%áa +|ñ®kÅz¿‡|†ó·a^mªJZá)ÿฑÝUâc13ÿÁ’ÿ3ļEûZü^Ò ìñ>’6ÿº@ÿÛjàµßø(OÆM)˜ÂS¢qéáMÿí­z‡Žoü+r˜¥,=ÿ­^1ãÛ/ \3l³½,º¦¾¯ ”euãi`àŸý{ù9‰ÌóR¼qSkürÿ3/Sÿ‚£üg±b?á'Ñøÿ©KGÿäZ¥üOãeËáÑÿù¹MgÃÌä.Ÿ©ÿr“Mð‘#/JÔ¿–Má< –”)Ûü ü‚®¼ÿåÙÙOF+ã=ÏT¸,7X·ãÓèú¦Tj¨(?ƼjI!¹#§Þ_ð­[?ÚKí㡞>òÿ…qÕÊëËh¯¼ê†aF;Ëð=óûN7Lhùëû´ÿËÕÚՔÉÿ¦iÿÅWÿÂæ¹»@\Žÿ| +ÌÖ>+ÝäÓçÓÍ5…,šµÍgšR±ìV†Ñ›ÙÐðºŸüUniºlW µ28áxÿÇ«ç+_ŠW­(áÉÏS!®ÓÂ<ÔnÂé׿sU‰Ê«A^⡘S“µnO™Ûl/ÿU¯ô¹!RDpMè?öjçôm~öþÈ+ÓïÑ’s;Gϫ׊éÎ2´™ê©ÆKDQÔ$¸·“‹[WÏOô¨Çó5.—¯^Àã}›S{fj:-ºÊXÚéYéóJ´ë[8˜³ÐAÞš?ð®žX¸ê¯ýzœêRRþ¿Èô ÅW€.lìT×ìá[ãKˆ ɶ²ãþŸc®/F¾ÓàP<¯/ü OòrïÄd1O‡ÇÕIþK^ML:”¾ÏüÏJv£ñ_qsTø³wjØö{O¦¥©t‰—×Ì3Kž˜½FþUÄjž)³i¿wýýÛgoý–¦Ò<_.û료~•Ðð1äÒ™ŠÅË›YþG®i~+»¸Aó¢ÿÛpkM5»¦ûIG¯6ÓüGÄvTz¬e¥hhYËÖþäé&+Ê©ƒ×oÀôaŠÓÄí›Ä·Šp/X÷é—:ýÌÑ|÷„ñÝ뉴–`^öðƒépÕly’êùN._üj+£ûŠUäúþ$>,×Ìhw^Oû|בxïÄr+±Žõ³ìúÕéZ¾—á{Ïà¾ö&áÏþÍ\æ­á ÌÛ9›KHçú׳€•:v¼_Ü¿Ìòñ‘©=šûÙ䯷M>Ó<ÅAë»ÿ­]×|VÎc #±ëÖ›«ø[ÃÖíòX Ž™cþ5>• /þ‰ B;=?:÷':U£eD#R”®ÝÏ~ðo‰ˆTùŽ?ÞÅzo…ü\" ºB÷ ?¾B³½¼ƒ +±Üƒô55Þ±¨"±Þe¸ï_=‰È£UüV=Êæ¶>Ûÿ„ÚÙcÏrÞ_ð«zgí ãý%úô.£ÿe¯Ï]nóX¹— æÞcWü'e¬Ï:f¼“ܱþ•É>¦¡Ì꯻þ Ñ'›•?Çþúa¢x‘'‹ 4˜n8ñnçÊ»\1fú°?û%|CàÍSÚ‚HîcÇé^•¡x}Ö%3,üôÉ5òø®…)]Tü?àŸC‡Î§R:Ãñÿ€}o¤BÓä"~_ý…tšDçNA±_þä$®à¯ìù§x¶Ê›ä¹T<œLb½†ßà†´›0¶­sfGüµKŽOçÅ|¦>¾œý““oÓþ ôX:5êGÚ(¤½à‡‰üTDÉ)Œщoç¯:Õ|Xw2"þ(wÿ«×¼Mð_éëßê–ªý7_ªƒôâ¸Ý[à'€-§Oã;å Ï:ŠÖ¸,N-oò‹3ÅÐÄ·ÓïD>ñ»A*ˆC2"Æòz ¾)¾¿±)ÊG!âèºåü'ð{ÀäoÞË#.5§ò®Ý~éÙ¾ZkºÂ†é'ö‰Éþ•Ç­…u.“ùÄêÂRÄ(YµògÏ¿Sû#S–iãPò‹`þB¼#Ç?­ôûï³[2cÀTeÎûâwìŸáOÚ#êZ^[Ð7©ÅxÄØWá†|Qgq«;G /$²j¥ý’M}nI›eÍ%[™»tŽš|ϛͲÜuÛ§Ê—›ÿ€yÏ„/¦ÕãI¦R¬ü€Øãò5èZ 1À>î þö Esð#À:]¬¯gâ­Ix_ø˜³9öTçêH®ÂÏá„ôŸØÝ&¿z²\0fY¯V{©A8ÂĹÇâÃÓŒÇЕœyµvøYÏ…ÁÖŽ’¶žhæµ;ó$VòX`²¾vþä?<[ðÎSÜêZK¶É6 ˜Aþ.=>µöêþÏ^ Óí´ûSç îÊü²Ü–’QŒFxúö®3âÇÀŸéÿ4-h2ü1º€ÎÍ»ž78U?äWŸ—qUåp“Z·¦é|÷ìvã²\C§u$žz¿‘ð¼?´ÝfKWœùº>£¸,þb´ˆAÀÎG8ëŒUÛ cÖ’0!–ÖæO9-%¢ïœ¯üà×´_þÉ¿ +tÚýôKì‰qiçOnoF®A9Ür9#+Sá·ìÕð‡Åßµ½ýìf·Ðƒ5–u’Û‚Üaò g¯_Júê¹æ +票ò)|=Ýwïý#æ©å¹O–£‹|Ü»õ[ôØæ<«ivWIi=ü6³7ÌUÉ%G··Ò»ø»AðæWû^ÙF9rÅTýN9®ËàwÀkš‡‰b¿Þ&+%¬uûÅNyÁ?OjÊø‡ðÀº—ÁmWR[˜/o­Øˆ¢iUH\€SÎq_7W0ÂÔĨKŸt¶]vþ™îÓÁb!AÎ<»>½ñÄ7ÄX-5>ä7ˈîA5óoÅ„º†›¯hÙÄ× +Níàÿó/½ðÄ‹“¥†°û<¤.†ü«Ü?foÚж a©˜ ÒŒ…ëõ8åÔÕl;æ®ÓÞÌüö®.éû*Ë•ßFmüñìƒÈ¸< 4ü+Óü_k=þ‹ Vßòäü¸5µàÏ„Ö&èN± Ürv×¥ÇðÏA›Á7Ï,"ú6ÂÄÓ…${õòy†mGÛª‘]O¥Àåµ}‹„™ð'Œ´ùm5y>F–2Ù`Ç$~èÿ5#M˜ +1ÆÁšõ_ü(ðÌFIÒ¥Ï$\•?Î¸ÇøIá{)Öš¥å®[ÉÔYWù׿,ÖŽ&‡#M|¿àž,rÚ´+s¦ŸÌõß êI< ‚Cwq[RKÐryÇJñßx[O·˜¼>'ÕXº¿ÚŒÀ~f»ýJ†Kí¨]LGvœ6kåñXhEÝ7÷A‡¯)+5ø™Þ9¹¶¶Ëo8Žk毌Þ7°Ó_–\ÿ¸Ü~•õV³á­'PÓ3;nù—¼§âÀÿk#tѸ|Ä\ã5ìd¸Ê¦½¢—Èó3\5j‘ýÛGÄúïŽþßxÁLqÎ8­¯]Ü\¸d•Î; {Ä¿²×Ãé.‹«íçö¡þ5ÕøSöið]®øÉcŽ3=}N ÃF YýßðO–†K^RÝ}熛‘3J=¼Ã\׉5k‹w,&™qèæ¾¶“à„~ûh-ÿ]ñ\ω¿gOKfUœÿ¥ãù×6ˆ0¼ÚÅýßðMëd¸Ž]ûÏ”âäysé÷Ûüh.º»'7S¶áÝÛükßïÿfoÉ9ÚîÞ‚?X³ý˜¼%ö\ät&ãŠô·0ËW÷Á8¿²+½.¾óçhîg¸¾üžìßã]/†t뙤þ\ÿ{lß³·‚­¬ƒfUoSqŒU;¿‚þ´ƒu½ÍÌg¯Éx(žy‡š´Sû¿àŠ9Mh»É¯¿þÅØøjâç¡Èúÿõë¢Ð¼9,.‹çTµoi¶mû½SVPyâû§ëU,ô(-ÈÙ­ëJ?ëôà~µ„çí’ü ¡GªüNúßI™#åv€;‘TuXŠDrG¡ã5‹ä$quíX{µÑ?ΪÝljÿ# ÃÞeþµÇ +.÷¿àΩUÒÖüQ“âˆÒáˆ.§Ø©â£øj-¾4ê¤26ï_ôíÿm§¸ðÍã3W»lõÌŠ3Z ü9gáÿŒFÖwŸÏð^¥¼³îÆ5]Ì×/ÔŠË' õ‡OïÄÛ$¦Þ>2ò—þ’Ï…?ààù8„ŸöMãÿÓö·EðpüœÂOû&Ñÿéû[¢¿Ÿ±ÇŸøŸæ~Ñ…þ =ä~‘h ÿöÑýPK?ýCã¯lt˜KÞ-} .?àžz!ÿª gÿ¨|uñ•ƒÀŒn†köomË;ÿ-?ý¸ü›‹¯Î­üõ?öÓ~ßG·1ó*«êe¤cp$ú +’ÒêÌ(Ìrsíš/ ‘\‹y›ðÅ~¤Òk¡ðÉ´õ¹-…°~%ý*kM.Çïp?Z°!².Ù& zšÒÓmìÀiîÞÅÅaJû#YTvÜm—‡"“˜×ï +±'„”'3 Ïûb·4›«Xüƒ ¾i\¹×í! +Ïý6­šÑGò%+«·ùœ™ð¬a‡úLxïÎ¥O…#,?~¤}ü+aüUŸõzzÿÀ‰4ÑãHb~~À>‘“Š.ÖÈ]ÃNð*¿>hÁÿe«E|±.Dñ=Gÿ^£´ø… +t0àvÜsV%ø¡1ð7Ó÷ ZÂR¯Ð´¨õ+7ƒ#V;®"DúÒ§„íÐäÝ~U¼ø¹Á “Ó Ÿ7Å+¹ÃÇ4Ô«u×Ü´ú#vãB³Š1‹™Õõý+Y‚(mšf¸‹ÿ­U/¼y}t˜?»í‘Xºˆ.¦4äf´ŒœäÉqRÙ½Áà<çž0‚¶t‡Šíûa5Æ&©3MÍËþ¯§ê?p~„ÑN²–ˆ'I£¹·šábK£õn*®¡rÎ `TûšÌ´ŠkØÎ_Äš§©Y}ŸïI©­Tw3çm–w‰À—Ô×sá-z7+†b0À5åV- +J3"“]ïƒoìÓh3Ž8¬1PR…ÍpòqaðÖ£Åù]½óÿ×®¢7·š1˜¿Ö¸_ ê¶d'2Iø×Umâ;8 ËëêÀf¾CJ\Ú&}5 «jÉn--Æm!lüÿZÑÑ4M>gè¼ú¦M`\øÎÚ 2°GùçúU­+Æ‘Ü̸M uúÕ„éUåêk +”ùFѼ=h€m³¶H…j¶‰ O–—èª?¥`xgÄË*/ß#ÜŠèWPiS*„þ?ýjð«s©j{4œt(Þéièƒþþ±î×ka]ç<3¿«Ü\9!b<ûçîEË1SÇÔüÉ­èŵ«1­%}by€Èó8ï…cýj¬×JüÌG°‘Y\H0>üÿAM—L—¶®?ÄŠéIw9ÛeKYmÆJºúgÿ­Yž"y&8v^}kJÿG3dãw¦Ïò5B_ º©8œ÷1üñ]TÕ=ÙÏ>~„cÅ÷À€‰/»güi%øƒsYY°¡‰?­R¼·®A›Fìÿ*™~!Úé6åE”Eǃü«£ÙEü0¹´kyX­qñRi?u¥Úäð6Û­Ox»Äw2 šTjë€Oækûã âOÝÃmN9?Ò£·ø³©\È@¸Ú:~íþu¬°²qþ^¬Î8ˆ©|lõ½+_ñ+Æ ÚÙ¢ã?9ä~F©kÿõ}е®œHï³?ÌןÇãJú?šæå=å ~B¨k3ÏÒÜÌú“Ãÿ¯o—¹•Ž3Žõ®ËKøs~ª¥™±ï^3ðîÙ ˆ tù{‡„4[BˆZ=éì+ãs*4i="}F­Z‹VjiÞ'½—eu›můêKmºCrñŸ\â½GàÔ¿ü?iúÀ°3ã;dC&Óôé^½Å?‡ššÇçé 0¡PáŠøQøbþ#/Úî/îXuùv(ÿ?Zö]ïSÚ„4Êdƒõ¯ið§ÅƒL:1¿’f‡Ì øs^“añWáåΟ–úLq3n ÃW™™ñYNÿU’ù†%§Ûë üÏ‹¼¬kS$…®î2£ +Y¹ý¾Eý è°:}Ž>×÷#GA,Ÿï6:~×øwâ_È<e§XÙZ¥ì²™$òJ eþèî}Í}vcŸº´]?ª=zé÷Ÿ3É•:ªXZ¾Õoî,â¼w•¿’p}dxöëRÉr.æÃ!˜’ÍèE} ¯üSøy¨h~Ó-¡O²[I²¤)µcCqóçþ9|Wð=çÄÿ‚"—JÓWuÀ…B«Ž¡@ã8¯ÍðÙ…IV_¸j÷éÑ™÷UðTãIþù=¾÷þGÃ?¼9z<~³K¸jwˆK†Ú ?ÝéÍMðúyî¼q{9òJ`’@ÿ8ÛÐ7ËýÒ+Ù> ~Ð5ÛM$ÚD·ÓQžuC¸· vŒþ5ìÿñ£áœ´ÿŽSPC.™$Ë%´eÆT€}Èï_pñøª9J„®©©}í+$°t~³hÖZͯ¹^æ¿€ãS/žŒñÈÃl™=¿Õß³¶‘÷*+ç9?!?•zìÿã_&­¯ÅªE‘¾ô¶ßóarHÍ‚9öªž ñG…n~kºdШÆå­%<³.zp3õ¯“–.YqtåºûŸùu>Ž8h{e5×ðÿ3⌞ +ð‰µÙ­õ K2óã|2·Ð Ã?Jð}sá&¡ðÆPêú<“K¥ʲ¾ð¹?˜¬ßÚkÅ·–^=½KkË•[iŽÆYeçÖ½öSý¤l|l‘øgÅž[™¿wÔÇä—ٳѫõªq–š¯//ò?7“yÉ|:èüüϪÿfO޾;ðÌšHn@*ÊqÓ±èkÕuf?²³b zW“|1ø5Ãëç¹Ò˜µœä1ˆr«^Â5> 4SX7Ú;HåǦ1_œæªƒÄ9áÓqonÇÜeβ £Yêøâ  v™T£Ó2sùW‚ø¿^Ñàº*¥âÎHIôÍ}9ã_è©dEÍ¢‚VƼ×ĚσuTI汋|g²?àC‘_E”â9¼%òg‰™PçùžgàïXGt°¬À©ìCZ÷‡ÚÍœ¶ªЯû Œ×+áñá²× §EŒãÌXßCŸÎ½#Á–~—O *€ôà µY®"_—Ü,º„¢þ$ÅÖµk8mNde_÷N?Q^;ñOZ³XÈIãç ÚAý {Ýûi‘iå|‚ÀzkÍ~ ]xrkv76q_ïaOç\Yed§~Vþã§0¦Ü-Ìž‡‰R+ã˜Î éÎ?•z‰ Œz€¹®WÅz§‡ÄA¤²ŠE9ükÍÂÖ´ýس¿FñÖHð­[A·šsäÞ̧û»Á[èËî¯]ÀþÝ+Ð/uo ¼ûŽŸ}ÎÓWôÛï Ço¿ìl£Ó#ô/5…ýÈñ._<«Q±×båyÙÙzçu§Ö"ˆ‰çàš÷éüEá«{lyRÇùV^«âÏ Go“(^ØuÖ”s)ßø_5p1kø‡Ì:Õíú»o3/Ô̇S¼G#Í’¾ƒ×<_á¶9Ŭ¹÷úVTZß…å“-gb¦»ý¼å¯+G±„tæLñôÔ/pB=³M’î÷-qǹ¯k7¾ÿÇ´*OªÄT7>( +,ëÃ?­RÄ·ödK¢—ÚGZÜ]4˜i&ÇÔÿZõÙ›þÞ¯»vá ¾ûÇþ¢Ú-X7š DóèA­¿…·¶7o>Š»|¨À9Õ´!ÿ‚ÿ®ïÚá'?óMãÿÓö·E'üá·||øHê›Çÿ§ínŠþvÅ/ßÏüOó?nÃ7ìaè¿#ô·@‹?ðN½ óÏÀK?ýC㯋ôûa‘¹‚Žü×Úþ‹þ5Ç¡¶?æÙÿê!|g¦h’Ìqµ€ïœ +ý“Ã¥xÔÿ ?ý¸üŸ‹Ý¦¯üóÿÛM;(!*»¥íëÒ–òœHøíÅjèþi•I?›ü«px6ü¨`l×ê«èÙñ§'ª<îh×v3)§µ²Þ í~}믾ðoÙ‰8N9çëT™ÒÁù¾´AÅêµ s-†dhÇÜ4’éžgHä#éZËãí +mF;ùy©â Ä sÑ#©ÍöBP[ÜćÃRL~[y›ð5bÝJr,æõäZéñ…àJüý)WÇ÷¾#´-õbjŸH¢­²dîÈɶwËýkJJæKu?ï•KcâÝNaòXÀ õ%sδ¶õ‰" TúXN¥Tí¢5„)ù˜w^ p‡^Ù?ʨ¼­ÖNÙÅjß]ëW# #dç…B1T×DÔçc‘#ç'µkJÞô‘œ£號uàU=_§PH‘©øOÊàméëšì ðn£1å0=KU†øcwp>/šN¥/¶ÑJ>Êg—K£4SHƒo ¯¤h²HˉHú +íÇÂ7ËĽø"¯Úü:[5Ϙ@Mg”bî™Ne£G(t7H°'nœðx¬MkI(I3~•ÝjþšØ)oÈç\v³áוÏ'=>õn¦§æN<²ìsñÙ¬SdÍõæº/^Û[:ù—Xü3Y°x%æ|ìÎè4/‡ !V*qõÅgᾈ¹5+[SµÐåÌHz–ï[UÇR§O–µML©á*Nw¥ Þ ¿ŽEŒ€ú*Šë“Ųڿ”$dQߥCkðâËÁv|܇(;Åpþ1ñ„\¬ë™6úW€¡ LýÅt{.R¡Fwñxä<àK“Åtº?ˆe¹@D…W§Zù÷Lø“íò«J€g¢ñú×®ø#ĶidŒî¬êDZÇeîœuF¸û øw®PðF¥®ê¢D.ñ·;ä ¥—MSÖi!ã¢ç¤.Ë_ ÍÅÓ¬²\É"©÷@?Nµìº1h­—¶‘À«ðÃvÑ;>ãÔ³éÚ»+½F=ÔãQÎx¯/1­µ- OCIÓ§yèbøÙ¯®£GaýÒ;W†øûàv§âHOu{3:ýÀ­£úWYñƒããøv[XüÇ<ÝÖ¼OVý õ¿0±™Ž~÷ò¯&ÀcTé$4Æa\¹*]—5oÙfmNãt³Ìvž0üšô„?³³è³Ç<²<“(Â’Çä•äïñÿX‰‘Y L~lná©÷¯GøKñ—RÔ$C*0g–õ?z¸øf*ƒR’±ç`¥ö©¨»ŸIxcÀ’[ÙïÉfA’Ùè: +ä~%ü4“XY ;‡(FCFk¤ð‡‰n§²/ #Æ{×%ñ?Æ·š}´ÒD¥Û!W&¾ +«ýcG©õ؇GØê´>]ø‹û.]¿Œ$¹yŒìÎáŽHíü©¾ +ýšï4ím/~Ó0™äF-»’ lóø +§ñ7㎭‰/#N›n[  +?Ä×=í ¬i—P‡ËüÝ9?ã_§Ó£˜JŠÕl~:˜(Õz=Ï´~ø ôÛdGg8‰å½+©ñ7ÞâÍf“³ú×…üøïy¬ÛÅæcAíÚ½ÞÓ^›WÒÂ’s”çµ~u™PÄѯy³î05¨U¥h!~Ðß²\z–«=ähUä$È3‘õ®À¿²gÙu„+ ÊÑž}}Cñ»Âº¾«fße$2}ÓžGµy¿4M{O¿ r¬@çƒÓé__‚ÌjË Ì䮾óæqxq¯Ê¢ìþãß> +XßøwA†Òéšâ8T*99`=­u¾#¾X;2 r¸_ ë–6i¼À ðßýz«â‰ãM,·d"žŠ{ûŠøê¸YÕ®ä•ý¨§^訶r_oÓM–³Höï÷‡\}GjðmS\°‘Ùø•Ï +_åÏ×µ{о$-ÂH¡ÖTaÈ‚+Ã~-øß]¶’ûN˜Û\òÆ Øô¯¶É©òÇ–¢±òy¤ùŸ45:ßC r-Ÿa= ãòaýkÞ>ZA U :ñ¯„¼®ëZþ"žT*pU¾øOñ>þ[X㺠àn©ÿ +¼ã-©(sÅ“•ã¡òIBjH,ÈL:f¼⽚ˆ\2§ÔñZzÿ5ìËDVE#Ö¼CâÇÅNtç•5åå9uWR鞆e¦¡ª)\¬µ²®ãѸ¯DøzÖÒÄ£j2úƒóù×ËßĻֻ%Ôuìk§øuñfâÚå³"ž§¢þ¦´în­m# ö„rAƒú +ò~8øbNÖ»ºbz¶UOáÿÖ¨î~/Û궃ìÁ­£õUÛÿãyey;É?š:VaF*É£Ñ5OÉg'îv¤}ÎеÍx‡ÅÚp°{ð‡uã\¬úÍ–«j Ï+îêÀç‰â´´‹-Ò Í/_©?™þ‚º#„5vý e‰”Ý“ÓÔ¿ÐVbÍxø'wÿ"¶<=ð†;¸ÑšýðzãåSøÖí­§‡–Ü2îÉ9ß!Çóçò·ô›­@fÜÃøTò­UlmEBëäM<$¯+?˜¾ø5a檵Ë2ÿ³×ó5Øèÿ´xYZgG ’jµŸ‰´m<†yâ·ÝÏÌjÊüZÐ4ÐÌ’‰ŸÔœãü?ð+ÕÅÏá¹ìÒ§†‚÷¬w:…e¤ÛµŽ„®M.µ¨ÚÙBZâñAjñ~Öúg"ðdÇ ÌGÔôóoÆ?ÚöçÅ0µ¶˜e…C6IfüiáxZ\õ_*îňΨS-5Ìü¥~6|tм7lè·°3Ž0qü…|›ñöƒ:Æ¢ëm#0=ó“^_«x‚û[˜¼ÒÈÅL“š}¿ƒ¯$€M"}ž6è\rß…}~ :å œŸv|Ö/*ïš«²ìŽ×Â^:œj)4³7'¡95ôWÂßÿjEî$žó“ùWÉúFž-®L¶yb+Þ¾ðF•¢æY€*̼gÐõÛŒ¤ªÑ÷—½ÐäÂÔtêû¯C뿇ºtW#Þ0Ú9Ëö®Ò+Í*ÊM±¼oŽäð+䯎ÁXÃI,k' LÊ®h?µígTŽÎØË$íþÎ_jø¬GV›s”¬«£ÒŠPŒnϯ[]²’2ç¢×1ãMzÝaq$莟ƼVoê:DRZØÎnõéWn¿ºµÂö'üŸJòOŠ?µ‰­ìg˜Û®D×%¦nüúVXJšKúþ¶/žÂÕ§ã;µýAä7ÖÊ ã± ì=MsÒü= |Èå†G"œS\ÃÍ;Wñ‹Ë¹¥†Æ!’äp=‡¹ý+Óü á}CÄÓ¼ì$¶ÓmøŒcLw?Zú´Þró­?«-*‹ù¹71OÂóÜóFÎ~o»×ëõ®Ûá/„ ¶ ³4Ñ²ŽŸ(ÆkXŸþ& e3ÎÜž:óýj_ø´ô"¹œ>Ñ÷F?Ãù×-yÖ©I«îtQ:u±ôG‡/!‚Ì©EÀ8ê}kÇÑZÝZJÞb€ŠX}qÿׯ1OŒÛOIJ!ÏÌØ8¬ŸüO’ê%óDIÁÁ üÕáQÊk*¼Ç±W2¦éòœÄOý«ZyVd ;0éÏð®_Røz%ŒÇæÆ PßwÖ»}Rðß^Û!]òÁqÉÎƲomÞkñ +Fþdq²88ÃWÚáëTŒT[ØùJÔi¹6Ÿ 5i<1vÖòܪzç¸ëýk鿆?í5M3sÎÆÁ•òÿ†&½¿2®õÚ\Ãúʸ•ñÞ¹ð‹]‘dše¶s…'!HÏÍÊiã“jV‘¾ 2ž¤ãt~ŽAy§kë±eGŽ@ÆO¡¬íCÃÚn›)óGÆp|U¢þ×Ϥ5½â\1hŽXsÈïùö-Wö—Ó¾$ø +=ZÎä«qûØÁ ŒWËÖáÜM¤âûAK;ÃÕ‹ºÕ¿âϲXho=”‚P£,£­|×ñsãM¾dFrW8'¿¸5§{ñ³ûsÂm©h$âÜw\{×Ë?¼Ru½VmKOó„s0óc˜¬8|k§YÌD³¿Çëšåô’ŠííŠÀ¼yõ+$O‘×±¯šÄfÒæ¼ïPË£Ëi3Û´¿éQ'ŸzÑŽ{KµÝѶ}+ç 4»ˆ~xŒ«ùŠ’ SXÓpRYÀ9Í(q Ö•)ýÞG­9ŸDÍ#‡Î?õ_Ø^2ÿ´ž@õ4ú+õ0Û©õ¦ý•}Z¥¢•\ˆÚ)îi>Äž­SQG*ÈMŠíMþÎOWüêÅr »+63Ý¿:Oì¸ý_ófŠ\‹°s2±Ò£=ßóßìx¿½'æ?­ÑG${3*cÅýé?1þ#üOùð«tRöqì>v~ºÿÄ +Dsÿ ÄÇ?íj6'ÿm+îúø³Býˆþ~Õ¿¶?Ç{ÿxcûzïIÕ´Ë{GþÑ»µò‘´ØY†!•ÉH&¿“×g|ü«-›ß³K·™ýø_)å» ··æûù«ÿÿ|p¾#ø”ƒÚþÇÿê9àßoƒS |Oü5ÿ¶uÚüÖ§ýˆ>=øÏá­ïˆµ{á¾‘à¿øM´Q©Ln¯Å¾ÊSþmß§ÃÍÿ¤ëò<¤ÿÁ»_¯Š>)û‰XòRð·ü/öñU¤·ZGþ jÖÐO%¬’ÚkZtñ¤Ñ±I#b–„VYO ‚ {wÃoŸ<-ûJx?Àß,þµ¯‹,µ+Øî|,u‘ªBB‘p@_šC’7n\e¸…´Ô²§ìuâ]|ÚÙ^êZÄkHÓ ½¾KG¹›RŸkM;ü±Dª®ìDz‘œqŽs÷™lÚÛu8Âß{ú¯•µüïo—+•þägZÿÁ¿ÿ-Û¯üHã×P²ÿäJ×±ÿ‚| °&µãóï_Zý¶­ŸÙËöéñF³ñÓCð_Ž|Eð'ÅCÅëÙ6Ç\Ñr\céOŠ ´?Œ¿u_ x’ÇûKCÖ!ò/-¼é!ó“!±¾6WЊҧçѧu‰–Ýÿà[™Ç…rw;:û¿àÿOCåäÿ‚'|'Sÿ!¯c{iÿÈÕ;Á¾ˆ¶¦³ã˜½ÖîÏ?­±®Gö?²ÒÿcÏø%ÿ‰¾%x3F²Ä³[^ßÝÉn'‚öKk»ˆaž`Ú8ù +ç©Éæ½Ã?´ÇÆÏ |Uø~ß¼)ðûJðWÄ›±¥ÙÛè÷÷Z¾töí4BáØdÆê|¥ÀÎw|¿8øÃ:säX™tûÞËæÕ—éq¾Ê£gB?kîŽïîÔóÏÿÁ.þø?Æ6Ö>)x‹K×õ`ŸbÒï# ÿfúÈí¥pÿ <ã _ÚËãÄOxwভ¡x7Ä w­j—WZæ¶›ÖÿÙÏ )Øü’Ù ïó1ÀLvóþØ<ð÷Nøµâ¯|=‡á=ù·»¸Ò´ûû©Fø#Ó'Ä?Bÿt_Úò[?­L?àŽ_ £]±ø“â )ýØïl×?Ùsú×ÖtU¾0Î^ø‰~äBጩmB'ÈsÁþ\8/âoˆ¤wûBÐõÿFªÇüÿá~±¼[ñ6T‡Q²PòR¾Ë¢©q–v¶ÄËðÿ!>Ê^ô#øŸÜÿÁ½¿®Ø™ßÛ$O©xÍQ@[Ë^~¿èõõµTø¯7‡Áˆ’ùŠ|9–Oâ£|Ï?üŸá´¶6–«â¸mlðRîm‚¶?½ûŒšèþ ãàx¬–Þ;ïÅŒa'€gÿ ×¼QXω39üUäÍ#‘eñøi#æëø%ÏÃÛ Bêèj~-’{¿¼ÏulvûÜqPÙÁ+~Øé—6«ªø½…Ñ,ò5Õ¶þ}‘Ò¾—¢«ýgÍçü¿á‰ÿWòïùò™oà”ß/´´ãªx½ ‹nn­ƒ¶=O‘ý)5ïø%Ã}“ÍÕ|_³AÕ¨ Æ9͹ý+éº*—æÉÝW—ü8Ÿe¯GE/§ücá²kÑjÚ¾1ó!M‹ºµòþ¸û>søÓôïø$ïÃm7S¼º]OÅò=ãe{«b©œçn-óß¹5ôíßfÖ··—a.Ëwö1>f¶ÿ‚Rü7¶j>-`ÄœµÍ±#éûŠÀø•ÿ^øMñKE[+ýKÆ–ê½%¶»µIâmÈý+ëŠ(æñ|Ë+úƒáܱ«:1> µÿƒvþ ZÆÊAø_ÿXø]ð¢æîKüA»[Á‰#¼½³t?‚Ú­fk_ðBƒZÝÅÓ¶©ã¸ÙÜé í P}¶8¯´h¢5ÏüÄËðÿ!®Ê?çÄá&ÿƒzþ +˜öÿÂEñ,/ý„,ùø‡¯à¡|K tP±ÿäJû¶ŠŸõË;ÿ ™~ä?õ[)ÿŸüOƒ›þ âø&ϸøâi=¿âccÇþIÔGþ ×ø sÿÄìžÿÚ6ÿÒ:ûÚŠOŒ3§¾"_‡ù pÆUÿ>"|àÝO‚%6ÿÂKñ?ö°ÿä:kÿÁ¹ÿñ/Å?ê#aÿÈu÷Õ?ëvqÿAü?ÈêÎWÿ>b|àÜÏå²|KñDžŸò°ÿä:`ÿƒqþ‚Oü$ÿòê%aÿÈu÷õ¿ÖÜãþ‚%øÿÕ¼³þ|£àÿâ|eÁñ?Å?¯ö•†ôŽ˜ßðm÷À×üTãþ¢Vü…_ TRÿ[3úÿÕ̳þ|£óæOø6ÛàY;¿á'øªôÔ¬?ù + oø6×àSçw‰¾)¶}u-?ÿ«ô1þáúT¿ÖœÛþËð+ý^ËçÊ?=GüYð%AÅ€=¿´´üé5ÿàÚ€î?ägøª=Æ¥§ÿò~†QSþ³æ¿óþCÿWòïùôÏàÚ€³}ï|T?]GOÿä*óŸÿÁ/~ÿÁ;¿h}$xSñ^£ÿ Ÿ‚5Ã}ýµso?—ö]WÃÞ_—åA3ö‡ÎíÝÁÏê¥|ÿµûgí/ðé1œøÅ'ÿ*ž­ð™æ;^4ëÕr‹èþó ^Qƒ£FS£M&ÁOø8â³þÔß vøkþŸ5ª*ïü±oö_ÚëáztÇÃ[ý=ë4UUwœŸ›üÌé«B+É~Gê÷„lAÿ‚=è²wÿ†~µÿÔQ+ób¿O<iŸø#‰'ý[í·þ¢©_˜uú×…Ò¼1”ÿöãóN:§KÖûhQEú¹ð!EPEPEPEPEPEPôή¥|¹â‚ß´/ïÚâ'‰~\|—AñÍå¥ç—âgÔšî†Ò81‹u*Ç«vät¯~øñþ¦ƒÿöˆuÿ6á`û>gö©Ó*ͽ—#6àŸV_Zâá­?êšüXÿÂÿ¶Wñ¾(Åb#í¨ÆëUº]Sêü‘ýQ*ð»#›ø)û_YÛx×]ø£âAãO|GÒ¿±õ{›X~Íe¦Ø˜Ê›4ê#Rìw° ä+ »wÝ~Ç_|sðÿLøMâ¯ü?“á6žmín5M:Âæ?jÖì­¼ˆÙ·pDFe$€ ùeohÿ†´ÿªkñcÿ ÿþÙGü5§ýS_‹øOÿöÊêY=;ªzi¥ãm.Ö—èÛ~ww½ÈúÍ;|Z÷ÖúÚúôÙmµ•­d\ðGÁ-Oõ_¼q,úyѼG¢izm¤1»›ˆÞÕ§.]J… +D«· IÁÈükâì›}àÙÏ_¸Õ0ø[ã |3á½V[„ø|f»Ò´¨¦hc¥º‘˜´ò¸#Êà*§øëÑoàŸ×ž2ý™õ_ëZ–…°ÇY%OdÖñë.~ý_w„±P»mîï×ùyßßó<¯ösý¾ øOã.®ø£Â?³/„ôÝ¥¸ó< áWMNõÚ'‰bó§Aä /¼¼gy1…û¬ÕôÅ!â†øªÿ`ÿÂRaÿ‰wö×›ýŸæd®ò¿y·û¼çÁÃZÕ5ø±ÿ„ÿÿl£þÓþ©¯Åü'ÿûeáü|£Èéþ1ÿ0Ž&’—5Ï"øgûü[³ý„¯ñëá3ØÜé±ø’×XÔ<ùLÐÅm4L±a_tŠ@m£ò:Tgö²lÿÉ6ø±ÿ„÷ÿl£þÉ¿è›üXÿÂ{ÿ¶U<‡0æçözÞ/xïu×¾âxŠmr·üßù6ÿðø/öp–ÿŒ¶Þ ’ÎçFøŸ©´ÑÇm#RÕôè-dÜ +æ7#ia‚¼ç xµ×ìuñçÇ?ôÏ„Þ*ñÏÃù>iæÞÖãTÓ¬.cñ&­anÊÑÛÈ›x÷DfRH + ß–Vöoøk&ÿ¢oñcÿ ïþÙGü5“Ñ7ø±ÿ„÷ÿl©‡ãâթ좷ÙV^Ÿõ¹RÅSw׫ø»·kþŠÇ®Ç‰TaT`AK^Cÿ dßôMþ,á=ÿÛ(ÿ†²oú&ÿ?ðžÿ픫ù‡üûücþd¬E$¬™ëÔWÿÃY7ý‹øOöÊ?ᬛþ‰¿Åü'¿ûeêþ?þ}þ1ÿ1ýfŸsר¯!ÿ†²oú&ÿ?ðžÿí”ÃY7ý‹øOöÊ?Õüüûücþaõš}Ï^¢¼‡þÉ¿è›üXÿÂ{ÿ¶Qÿ dßôMþ,á=ÿÛ(ÿWñÿóïñù‡Öi÷=zŠòøk&ÿ¢oñcÿ ïþÙGü5“Ñ7ø±ÿ„÷ÿl£ý_ÇÿÏ¿Æ?æY§Üõê+Èᬛþ‰¿Åü'¿ûeðÖMÿDßâÇþßý²õÿ>ÿÿ˜}fŸsר¯!ÿ†²oú&ÿ?ðžÿí”ÃY7ý‹øOöÊ?Õüüûücþaõš}Ï^¢¼‡þÉ¿è›üXÿÂ{ÿ¶Qÿ dßôMþ,á=ÿÛ(ÿWñÿóïñù‡Öi÷=zŠòøk&ÿ¢oñcÿ ïþÙGü5“Ñ7ø±ÿ„÷ÿl£ý_ÇÿÏ¿Æ?æY§Üõê+Èᬛþ‰¿Åü'¿ûeðÖMÿDßâÇþßý²õÿ>ÿÿ˜}fŸsר¯!ÿ†²oú&ÿ?ðžÿí”ÃY7ý‹øOöÊ?Õüüûücþaõš}Ï^¢¼‡þÉ¿è›üXÿÂ{ÿ¶Qÿ dßôMþ,á=ÿÛ(ÿWñÿóïñù‡Öi÷=zŠòøk&ÿ¢oñcÿ ïþÙGü5“Ñ7ø±ÿ„÷ÿl£ý_ÇÿÏ¿Æ?æY§Üõê+Èᬛþ‰¿Åü'¿ûeðÖMÿDßâÇþßý²õÿ>ÿÿ˜}fŸsר¯!ÿ†²oú&ÿ?ðžÿí”ÃY7ý‹øOöÊ?Õüüûücþaõš}Ï^¢¼‡þÉ¿è›üXÿÂ{ÿ¶Qÿ dßôMþ,á=ÿÛ(ÿWñÿóïñù‡Öi÷=zŠòøk&ÿ¢oñcÿ ïþÙGü5“Ñ7ø±ÿ„÷ÿl£ý_ÇÿÏ¿Æ?æY§Üõê+Èᬛþ‰¿Åü'¿ûeðÖMÿDßâÇþßý²õÿ>ÿÿ˜}fŸsר¯!ÿ†²oú&ÿ?ðžÿí”ÃY7ý‹øOöÊ?Õüüûücþaõš}Ï^¢¼‡þÉ¿è›üXÿÂ{ÿ¶Qÿ dßôMþ,á=ÿÛ(ÿWñÿóïñù‡Öi÷=zŠòøk&ÿ¢oñcÿ ïþÙGü5“Ñ7ø±ÿ„÷ÿl£ý_ÇÿÏ¿Æ?æY§Üõê+Èᬛþ‰¿Åü'¿ûeðÖMÿDßâÇþßý²õÿ>ÿÿ˜}fŸsר¯!ÿ†²oú&ÿ?ðžÿí”ÃY7ý‹øOöÊ?Õüüûücþaõš}Ï^¢¼‡þÉ¿è›üXÿÂ{ÿ¶Qÿ dßôMþ,á=ÿÛ(ÿWñÿóïñù‡Öi÷=uþáúTå'ö±b?ä›üXÿÂ{ÿ¶Sá«ê›|XÿÂ{ÿ¶Qþ¯ãÿçßãó¬ÓîzÅäÿðÕ¿õM¾,á=ÿÛ(ÿ†­ÿªmñcÿ ïþÙGú¿ÿŸŒÌ>³O¹ëò·í·mö¿Ú³áÂzøÅGÿ*ž¯røkñ³þF»-ü">7Ð<¨ ÿhÖt¿²Àøe]ŠÛŽ\îÈè­é^5û^ÁöÚóáºÿÔ‡â¿ý9ø^²¡†«‡ÅÆegÿö0ÆJ3ÃÉÇúÔüÿƒŸ-þËûhü3Lc -¿ôõ¬ÑW?àéx~Ïûq|7_O†v¿úyÖ(¯A»¶üßæy©Y%ä¿#ôÛÂ?|'ü_Cð£êð€6°ý“~ãáD`:cîz×ÿýüeÿ¡›á—þ o¿ù¼E_ø²Z¿ÁýBâ¯ßºúIçX¾…'—É~ú”®¯ªÚß{>c€Ãçµ+¬tƒ9F6vÓÏî?¿â¿Œ¿ô3|2ÿÁ÷ÿ"Qÿýüeÿ¡›á—þ o¿ù¿`h¬ÿâ(gŸÍüüCü£´¿ð#ñûþ!ûøËÿC7Ã/üßò%ñ߯_ú¾àÆûÿ‘+öŠ?â(gŸÍüüCü£´¿ð#ñûþ!ûøËÿC7Ã/üßò%ñ߯_ú¾àÆûÿ‘+öŠ?â(gŸÍüüCü£´¿ð#ñûþ!ûøËÿC7Ã/üßò%ñ߯_ú¾àÆûÿ‘+öŠ?â(gŸÍüüCü£´¿ð#ñûþ!ûøËÿC7Ã/üßò%ñ߯_ú¾àÆûÿ‘+öŠ?â(gŸÍüüCü£´¿ð#ñûþ!ûøËÿC7Ã/üßò%ñ߯_ú¾àÆûÿ‘+öŠ?â(gŸÍüüCü£´¿ð#ñûþ!ûøËÿC7Ã/üßò%ñ߯_ú¾àÆûÿ‘+öŠ?â(gŸÍüüCü£´¿ð"1yy'ýš’Šüìûb? úŠO úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢ úŠ–Š‹È>¢¾Ký½~$hŸ¿iï‡:ψ¯áÓ´Èü â˜Úy3µYµO …æ¾¹¯ÍŸø8 n¹ð8ÿ©KÄ?úwð½zÙ5ñô¨Ëi;}ç•×t05kGx«Ÿ‘¿ðsÄMâ·íƒðÇ[Ð/bÔt»¯†¶ëñçk•Öõ•n t Š+ƿଣoˆ~ +ÿÙ;oýHµÚ+ׯÐEJ1Ú2kîlòpx‡[N¬·”SûÒ?BôXsð'ÃíéðFÃÿPÈ«÷Ê¿tÏÀ ÿÕ°ÿÔ2*ýê­x·øxOúö¿CÎàŸâãëì¿P¢Š+ãO¼ +(¢€?1tË=sŸ°ÇƯÚ&ËâGÅX>$ü7ñ—u4^øëV¿Ð¯aÓµ›è`ÒåÒ..^ÀÛÉ knp,‰•h$Uaì?o/‹Ÿ|iák?‡Úg‚?ghmŸÄ·aus¬ø¡×K·Õ¯RÞí.¡‹OÛor‘De·¹ß*1`ƒŠõ þ ‡ðc@ñÏöôz‰.Øx‚.‘¨xÓ[¿ðòj³N÷x4‰îßO‰äi‘…¿îåæÖUa·ñ[öøSñ¯â\Þ,ñ‡oî5[ÿ²jCi¯ê6oˆ«n·•¼ñÚê">Š.â— +ýÐÒ‹è’òM$®¿™;?uÙ]óorêÊ2«)Úé¹>ͧ&Ôzòò­¤®õjÖHù»â×íõñº×Iý¥Øø#öy–;¨ô½[Ã÷÷š¯‰í¿°ìµY`71ßÅ”Ÿ¿‘a Â똇”L׿i_ÛÇãx öñ¯Âû¯†žðçìû¥ n¬|Sá»ÍjûÄ—£H‡V‘RKmJÑlá\ÛĬÉ;3‰[ +)úw_ý‘>x£Ãô‹ïyúwÆbíã¾ßr¿Û¬¢±o˜HÛC~ä§ÝÝ÷‰cò÷íÙÿÏñGíEã?èú†¼¤xSǧ‡ï¼EÄé°À±´Ëw ÚÄtíbh¢b {©±«±­T¡­¢—”­ï6ú«­²ÖúZΩ8)FU5I¾o8Þ6I-¹¯mvZî¼ÚÇö×Ö?f¯‰ÿî´m5î|Oñ?âþ¡Ú\Eá­KÄé Þ Ó¯gºm3NÍíàH­¥YI,¥¤œ}{ûþÑ1ý¡<âY×dÓ-ui|¬ø6ßͦgŽî7VêÜ)™­Ø4’©’ÙÙ_k…]­_öø]®h>&Óî<90_j¶zî£u­{mzº…¥´¶×–×1J³YÏ6ЪÉlñ0ÚNrÌOKð/öyðÇìåáíCMðÊëîšµéÔo®µ¿êýýäæ(á%ÝüóÜ>#†4U2U@µRŽªÚ(Æ+Ë–0_¤­ß›]£ËÍï8Âûý¯6Üÿé¶—[»üeûHüO×?f/Û ö¨øƒ¡ë>(Ôî¾|°ñŽ k*Õîü7¢ï«¬ý›ö¡nªëal®×e*Ò;7¤è´ÆßülÒ<âícá}ÝßÄŸ‡ºÏ‹<=y¢xfúÙ|-ydÖJ ºjhÅþž§ÌìL~Î~Eówé¾8ÿ‚v|'ø“ñÇž+×têZ¿Äͼ-âE—Æ:רµ 1‘“ìÂÐ]‹hUD’•1FŒ4¬¥ZGfîõÙ÷Â·ÄøªãHó5ï hמÒî¾Õ8û-Ù·7ì±·›X>fRÃge³Í(7GÙõå’òWU-oIJ›¾ö‹·gÕ)ÅÕçKK§ëeI~<µ.¶|ÚÝíù×ÿÁÔ¾ |4ýŸþøGÀÉðGFø…ñóÂW5ßOàk¯2{k8¬•ÿ´bMM'Õõ9®uÍt×0*©”ù'_v~Äÿ´§ûIü +]k]±ÓìÿÑKÐÿïÔÿün€=êŠð_øzÀ?ú)zýúŸÿÑÿ@øÿE/Cÿ¿Sÿñº÷ª+Ááèÿè¥è÷êþ7Gü=àý½þýOÿÆèÞ¨¯ÿ‡ |ÿ¢—¡ÿß©ÿøÝðô€ôRô?ûõ?ÿ z¢¼þðþŠ^‡ÿ~§ÿãtÃÐ>ÿÑKÐÿïÔÿün€=êŠð_øzÀ?ú)zýúŸÿÑÿ@øÿE/Cÿ¿Sÿñº÷ª+Ááèÿè¥è÷êþ7Gü=àý½þýOÿÆèÞ¨¯ÿ‡ |ÿ¢—¡ÿß©ÿøÝðô€ôRô?ûõ?ÿ z¢¼þðþŠ^‡ÿ~§ÿãtÃÐ>ÿÑKÐÿïÔÿün€=êŠð_øzÀ?ú)zýúŸÿÑÿ@øÿE/Cÿ¿Sÿñº÷ª+Ááèÿè¥è÷êþ7Gü=àý½þýOÿÆèÞ¨¯ÿ‡ |ÿ¢—¡ÿß©ÿøÝðô€ôRô?ûõ?ÿ z¢¼þðþŠ^‡ÿ~§ÿãtÃÐ>ÿÑKÐÿïÔÿün€=êŠð_øzÀ?ú)zýúŸÿÑÿ@øÿE/Cÿ¿Sÿñº÷ª+Ááèÿè¥è÷êþ7Gü=àý½þýOÿÆèÞ¨¯ÿ‡ |ÿ¢—¡ÿß©ÿøÝz§ÂOŒ~øëàôñ„õ4Ö4Yexc»Ž#ŽVC†Ø]Wp‚FFAÈ tÔQEQEù·ÿ ÞxþÅ/ÿéßÂõúI_›ßð_•Ý}àoû¼Cÿ§ ×½Ãò5¡þ$x|Kÿ"ºÿágá'ü¨cÄì·þ¤Zíÿø+xljþ Ù;oýHµÊ+ÖͿ߫Ž_›<¼¯ýÊøcù#ô[@L~Ïž8ëðFÃÿPØ«õ'þû8ÿÑEÿÊ©ÿÈÕù{áèÿã<>êˆXê|ç_ eÜ%ƒÏ)Óúܤ½:våi|\×½âû#óê\I‰Êjâ>­¾zµ/Ì›ÚÖµšî~çÃâÿgú(¿ù@Õ?ùø|_ìãÿEÿ(§ÿ#WáéÿÄ%Éÿçå_¾?ü¯üDŒÏù)ýÒÿäÜïø|_ìãÿEÿ(§ÿ#Qÿ‹ýœè¢ÿåTÿäjü1¢ø„¹?üü«÷Çÿø‰ŸòSû¥ÿɹßðø¿ÙÇþŠ/þP5OþF£þû8ÿÑEÿÊ©ÿÈÕøcEñ rùùWïÿ ñ3?ä§÷Kÿ’?s¿áñ³ý_ü jŸüGü>/öqÿ¢‹ÿ” Sÿ‘«ðÆŠ?âäÿóò¯ßþ@?â$fÉOî—ÿ$~çÃâÿgú(¿ù@Õ?ùø|_ìãÿEÿ(§ÿ#WáÄ%Éÿçå_¾?ü€ÄHÌÿ’ŸÝ/þHýÎÿ‡ÅþÎ?ôQòªò5ðø¿ÙÇþŠ/þP5OþF¯Ã(ÿˆK“ÿÏÊ¿|ùÿˆ‘™ÿ%?º_ü‘ûÿ‹ýœè¢ÿåTÿäj?áñ³ý_ü jŸü_†4Qÿ—'ÿŸ•~øÿòÿ#3þJt¿ù#úh¢Š+ùàý°(¢Š+Ãþ,þÙ÷Þøû¨ü9ð×Áÿе½Ãúw‰5)ü7q [ZØ[ßÜêöÈÍ©jvnÒ3é—DˆÑ€¹`X +÷ +ùƒÇÿ°¼_o¯ø×ÄïñKðÅÇÃÿ èšEï†> ëû]å¶£â9¯"š=.öÞI|¸ï,™Zue{ˆÎ|Ñ@ÿðŸâ–…ñÇág†¼kákïíO xÃJµÖô‹ß&H>×gs +M¾\в&èÝ[kª°Î"³ÿh_zWì×ð ǵÛ}BïDð‡ïüI¨A`‰%ÔÖövÒ\J‘+²#HR6 +ÔFXkãÁ<%ð¿þ!ê¶_Ûx–7wíUHLZØÝI¹Ê¯î¶çs*·ÀÿcÿÚ Æ^±øe௠Â7>…ñâO‹m>"·Š!²¶µ—Äz_Œ›HžÍ /|>Í>»kÔ2Á:!·Žò÷öìW§ø‹ÆŸ 5ï þËzÁïø âV—â{ÿÜ\è‘I¨Í•­iãV‡KÓî'Òa’Ò}SN¹7BáofM>Aå—±ÓÒàèÿŒ_µ´¿þ)Ë௠|5øñSÄú~•k­êö^—G¶þų»šæ9f“T¿²üù,oUV•“ì®d‡ˆÉêñ5·<+¦k6qêÚjÖ‘^Áý„öH’ uÛΉ4FèåEt9VU`@ð‰xßà?í¡â¯ˆÚ/Âï|RÑŠúvƒWXîZÇ]EŠÖËì×\cÚo _ë_ô­ ãï†~Ío¨6·â¯êÞ$´ ¬vúmΙo:Hщõ[r€!$¹e!Cvù!¨Á2¾$ëš'‡´­'àÆ¡àh dðßÄïˆøcí_/Æ¿á;½Eâ‘î&—Q“Q´ÒµÍ§]·ŠøKÅD¸GØðMÙy¿fŸ +­ßÃÿh«uwªÞhsø‘¼..¼#e*i1ͦ­¶…Ztw·6¯v-´õ¸†Sl×73Çs8@>¯¢Š(¢Š(¢Š(¢Š(¢Š(à_Ù‡â‡Å?øF> +ü4øg¯|?ð¿ü%?¼O©j^'ðµçˆ?äâK h †+}FÇfÿíiÿÕ +2M[øËÿIÕm|Að®Ì|Bøû?Zx¦ÓÆöÚþ©ñ"ÕtåÖ|7­éú4ÖhébHäžkùc–LI$6ñ±‚2"Kû,þÎ>>ñïÂÿ„_¾øëÁþÖücã ωÖé1"FŠÛçþÿíÅðs↡áý7OÓ~i^6}“ûD}GÏÖR‚I..änµÓZòÞßt޶ö:œ3¬‡ŸþÏ?ðP/ж—„¾YøKNðÿÂßüAÿ„û[wñ¯„ï/¦Ñtïøš :ëL‹P¶’=BHï­ži>ÖR)m'A ”ÃêàšWÇïˆZŸ‰>%jÚˆnõ¿øGJ½ƒNÑRÎÜÜh·º½ÅÛF·\•³Ô Ön¬'µbÄÙOuM"Ü1úwì ⯆WÚˆ~üBðþ—ãmUñÄÑÝø‡Â“júTšwŠ|Ö»o§Ã­é^ ×¼-¨I`­õƬÞé2Ýų¼1Ü=“N°´’˜DÂ3,Å<×õ +óÿÙ‹à_ü3¯Â(|9&©ý·¨]jº·ˆuKå¶û,7Ž©©\êw­;ÜÃoö«É„Q<’¼qÕå••¤o@ Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ¨é?ñÿ©ÿ×Êÿ蘪õQÒãÿSÿ¯•ÿÑ1Pê(¢€ +(¢€ +üàÿ‚ú ê^ÿ±KÄ?úwðÅ~×çüÈgRð/ýŠ~!ÿÓ¿†+ÞáùÐÿ<>%ÿ‘]ðŸ„ßðWQ·ÅÿìŸýHµÊ)à¯ò6|ÿ²võ"×(¯[6ÿ~­þ9~ló2¯÷*?àäÒ/ÇŸÙ³Ãçþ¨‡þ¡ÑWÍuô߇?³7‡ýQ ýC¢¯™+öŽþÿ¯t¿öóñÜå~ö§ý}«ÿ¶…Q_xxEPEP§ëßô{/ØëÃ^*ŠÏn½¨x³QÓ..¼×>e¼V¶rF›7lid9 + ÝÉ u³ ž(øuàíoSñŸ¦xq<+yâ-Fâ %º°¶‹R’ÐF62µìòJP!•Ó`RꉚäüûH/†¾Ûx/Vð?ƒ¼]£Ùj“êöͪɩE4MQ¾ÒîT¬)Þy­8?lrÊM*Úß@ð´—¤Þh-¡ùWRXÞØ\ÝItöó¦!dpQÖU‘|´;÷Çç«SÌ>KU9;»5Êã+%{´îÕ´²óWOÙ¡<£*Ûr¤Ò½ïΛnÖMrß®öê“W>þÊúOǯMaàMÅ Òt½]gU?ð‹cX€G/•äAeÌ«q#—ˆ®'UÄ„±@¦º}cö‹ÂšÞ«.¿âøsÃú„¿á-GÕ<&öº»D·©g%´–/8ͽ˜§ï™ydº%<æÏö”mĦëHðW‚ômëK}QЭ㼒ÃW·yL­ç´·/p_xFWY•Å»hŸö–žÎÏ^´Ðü#àï iþ!Ї®mtèn™DFí.ŒÞd÷JÓE]Ò;€€(Qˆ«K5”ײ›QóP¿[Ý­/µ¬š¶úêiF¦\£ûØ&î¶rµ½Ý“×ù¯vžºyu3þÇštßÙúퟋ®€n¼3/ŠgÕo4…ƒP¶·ŠðÙ<"ÍguyÚãb „a"–tÃb¯ÂÿÙ_Iøõãé¬< ¯ø£ÄN—¢Ë¬ê§þlkåò¼ˆ,¢¹•n$rñÄ긖(ÖG†¿kxoHðþ™ýŸ ßhú‰uáÙ´û¨%h5{+‹—¹xîvÈ"W ¯FÊcBa“^Ïö”mĦëHðW‚ômëK}QЭ㼒ÃW·yL­ç´·/p_xFWY•Å»jÝ<Ñ)ÇŸ_{•û¶µånedù­m­ïÖòªeÿ/2÷¯´9¹u¶üûôµº[Òþ ßÄØ4ynüaç†ßÄ–¶’øJH¼Mr‰9·{dÒÚqºq /9_$yܯøÙðîÛáWÄ{í +ÚãZ¸K4„¸Ö4gÑïàw‰âšÙÝÌnŒÅN”ã EnºWöñœü.øpt¯ìïìñ¤yZŸç}£Ïû_Úüìü›¼üy&ݼVÆ‹ZÆcQ·±²òm-ôû[K$u·²¶·‰b†ÞÏ#Es»1êXšÛ ÁVO+ÆÏ¤V·ÑèÛ½´káëw²Ï< ¥%F6•Õµ“ÒÊû¤­{»½uµ­©ýÑEü„J…Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ðàtŸ³ßÂ}7Âzn¬—Öº|—3ù÷6‡Ì’K‹‰n$8W/™+…¡A,AcÙ}ŸRÿŸ»üþ9W¨  +?gÔ¿çîÇÿÿŽQö}Kþ~ìðÿøå^¢€(ýŸRÿŸ»üþ9GÙõ/ùû±ÿÀGÿã•zŠ£ö}Kþ~ìðÿøågÔ¿çîÇÿÿŽUê(Ùõ/ùû±ÿÀGÿã”}ŸRÿŸ»üþ9W¨  +?gÔ¿çîÇÿÿŽQö}Kþ~ìðÿøå^¢€(ýŸRÿŸ»üþ9GÙõ/ùû±ÿÀGÿã•zŠ£ö}Kþ~ìðÿøågÔ¿çîÇÿÿŽUê(Ùõ/ùû±ÿÀGÿã”}ŸRÿŸ»üþ9W¨  +?gÔ¿çîÇÿÿŽQö}Kþ~ìðÿøå^¢€(ýŸRÿŸ»üþ9GÙõ/ùû±ÿÀGÿã•zŠ£ö}Kþ~ìðÿøågÔ¿çîÇÿÿŽUê(Ùõ/ùû±ÿÀGÿã”}ŸRÿŸ»üþ9W¨  +?gÔ¿çîÇÿÿŽQö}Kþ~ìðÿøå^¢€(ýŸRÿŸ»üþ9GÙõ/ùû±ÿÀGÿã•zŠ£ö}Kþ~ìðÿøågÔ¿çîÇÿÿŽUê(Ùõ/ùû±ÿÀGÿã”}ŸRÿŸ»üþ9W¨  +?gÔ¿çîÇÿÿŽQö}Kþ~ìðÿøå^¢€(ýŸRÿŸ»üþ9RivÙ‡šXå’â_0”Œ¢‘W$ÿw×½Z¢€ +(¢€ +(¢€ +üáÿ‚ùº¿ìSñþü1_£Õù¹ÿÿ—É»ð3Ô©âý;øb½îÿ‘µñ#Ãâoù×ÿ ø[ÿyãÅŸ¿ìýHµÊ)?à®Íñ?ÁcÿTìÿêE®Q^¾oþý_ürÿÒ™åeOýŠø#ù#ô¿Ã)ÿ½áóÏü‘ýC¢¯—«êo §übχϯÁýC⯖kö^þÿ¯t¿öóò ëø•?ëí_ý´(¢Šûãà +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€?¦Š(¢¿‰ÏêÀ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¯Í?ø8NO+þsÿR®¿ÿ§ Wée~hÁÃgx ÿÔ«¯ÿéßÃïð·ü°ÿâG…Äßò*¯þ~ÁWåóµÏ‚ëðí¿õ"×(¨¿àª-»Tø$Oý¶ÿÔ]¢½lßýþ¿øåÿ¥3Éʿܨÿ‚?’?Q¼1e/ŸO‚?ú‡Å_)WÖ^ŒÿÃ&x{Ðü±ÿÔB*ù6¿dàoá¿ú÷Kÿo?#Îÿ‰?úûWÿm +(¢¾üð‚Š( ¾‰¼³ø}ðÇá/Â)5‡:V¾Þ7Òî®uKûSP·Ôã#P¹¶W¶ÛqödtDB»àu,¿0 šùÚ½{ÿµíÖ…àï 铸ÀzÅ÷í¦·Ñ5mF Ù®lüÉäœ9ˆ\‹YY%•™D°:ð¹VŸ33£V¢§ìÓiJòJ\­®Y-Ó_iÅü¯gc»Ru9ÚMÆÑms$ù¢ïk?²¤¶ën§M¦~Äö·¿|qà´|JÕ&ð–®Ö qáÿo ƒ{*Íq‹¨Z@¯œ67¬ÿfxá_Æ êšÄ!ð‹l´µKʪ~Ö­²9.­Õ„%Æä®ÝÛØ/áÏÚËW³ðÍî“â ÃÞ9¶»Öäñ"¶¸×‚Hu ,—¶¸‡Í,r&(ÛÀ›tÍû^jº¦¿ãû½oÃ^ñ —Ä}I5}SL¼[È­aºI%t’ÄR¦ß:@‘ ‚¯"¦7k’SvJ®UwA¶›þd§u$–ËTÏV5òÅ'QCw+'}UM'mƒM6ô{5®ïŸØÄ|cøE}â=*_ˆpMc¥^êmwwà¦_¹µG’HF¤—/†+& ˜CŒæ¼›áoýCâßÄ}ÃRÔ5ëè¬`ÏÝVv ¸ú(ÎIì¯J°ý¶5{M:Õ¥ð—ƒ/5Û/IáHuÉÒøÞE§½´–¢5n…²²Ã!PËn2ʼnbÜÁï‹Ú¯Àÿ¾¿¡­ºk esiivæA&œÓÄшJ2•™Ûc…'8ÈôpÿÚ ÛJvz{‰Ú×÷´ºÞ?®Ï} +ÿRp¥z;ûÍ_kG£Òéómtôïeî_ÿfïü\øððü3èñOˆåðMäÎÒß›[È®Uc»mî2n-¥Šo,2®å”.ãÀ±=Å[Å2xgXñlj´_˜m5I4ý·RžòYdEK[4ºÌm‰ÜÍ, {ˆS‹áOÛóâfж£Y×nüp4ýbÃ]±ÿ„žöëQ:}Õ¤…Ñ¡-0(3#Œá•»0V—‚~=ÞøNOÁ{¢è>$Ѧ·ÑçGgŠdh%ŠhÝ<É)(ÊÈÊÛƒ\°™µ:Nœj|;;©7y&î䓺ãRºW;jârÙÔçpÞ×VqJÊIZÍéð9=_ÅmNâïö4—Ãß´«àME~"ßÜÛXA©Ù'‡üÚŽ§4Gªn,¤¹…íÙRE7>É\Ÿ¼xÚOàeÏìçñrûÂ×7SÝ›{{k¸ä¸²{+*âçEš$Å*¬€:nm¬ÜqšÙÑj‰toøIl‡ü/…üR–KuáЗÖöµší‚E’¤¹frÞdî¤f`X)^[ãOÅûïŽ9:íý†•¦J,­4øítèž;ha¶·ŽÞ%Pîí÷#\åŽNk³Åb#õ‰^ +:éeh릩ߙ4¯šzÙsbe€t§ì•¥}5zk¶»«j›´º5¥ßôyEWòý(QEQEQEQEQEQEQEQEQEQEQEW!ÿ àú<ÿƒ›oþ.øhOÿÐñàÿüÛñt×Ñ\‡ü4'€èxðþm¿øº?á¡<ÿCǃÿðsmÿÅÐ_ErðОÿ¡ãÁÿø9¶ÿâèÿ†„ðýÿÁÍ·ÿ@}ÈÃBxþ‡ÿàæÛÿ‹£þÀ?ô+þͼ!ðå®>(]øËÀ¼;á¿„ÓøõÉ4 ¼}gmoxú‹XªZµ™–=©ñ-‰ŒÍ… öáZ4ðíàï…—¾.ø}­ü`Õ~-x¯âÅ +ÂÇY¼yô­GX|aqáäK; ,a·:…¦‡$×Hd)s ¸¹û‘[¿üeñKBøâ? é:½÷Ù5ê²hš$^L’}¶ñ,nïÚ,ª˜µ±º“s•_ÝmÎæUn‚¿ ~&ÿÂcâÿÚ‹WÓ¿fŸøh SPð~•§ë¾µø…ÿ <óhšõÏ„~(ÙÃz©â¬˜-åºDW hòˆÑ‰m¾¿ÿ‚RxsÆ>ÿ„÷û[Æ_<[á)¿³ÿ²¿á'ðo‰ü;öKáö¯¶y?ð”j—úÄÛ¢6;¿ÕX¦Äò7Ì×»=¿áŸí¡ð¿ã/Ã߆^+ð¯‹ôýÿîÚÃÂÖQË,z­ÂY^^É Âf #‚ÂózN#1½»ÄÁeÂP¯ÌØ«öUøû9è_°.‡cà¿]}—Åž,‚âÕ­døc®GðòÿN¸µ’Ûƒ¾¡uró¾è£0ê"õ¥–Y5(’ý{YøéñCÀ?³·ÃéôŸÚ>ÂïÂÞ +м+ñG[õ)u m|[à;}UEü2Gqq$v ­9Ôáco-½ÅãÛÝÌ©vbý/ø—ñKBø?áËm[ÄwßÙÚ}Þ«¦è‘KäÉ6ûÍBú 8±±eÕÌî#jïÜÅT3‚¿(?h…¿¡ø}¦éúÅí®øKVñ^ Þ(†¼G¬_Ûéžø«á«mâÌDÒ]Û\-ýÀžÇeÍúÄ÷’½ÌÑ‹…Ðø¹¢ü^× ±‡Eñ7Ç +þÎëâ aü=w©øgÇÚÿŠ$ÙÞqÝA¦_Ùx©c7çÅ¥d¿•­Â,!£il ©ôWȰo„|m¤xßźŸÆGã§ã ¯è6\ú“jºuÃAà-1®¦k ‰´‹[w¾ŸZ2˜ÙìÚøF‚Yg‚Я×ôQEQEQEQEðoìÝðYuïÙS¾øðŸâg‰õK^—SÕ¼cwo¤YÛE­q$—)c}w-ÆQ-±ˆGo6ù¢e†9ñþþÑ~2hú7Ž<5û5|4o„WZ¯„¼=©jš¯‰,õÚè×:zæGg-´Öè¾!ÒÄòµüN„^lŠ_&/´h|2ø_ñOãìeðÏDðvƒðÿÅ¿æÔ¼Lþ3ðïˆüSyáßøH1¬OöKI&ƒN¿ó´öÍɺµ)Ú6[Æò=³][\wzÿìwñOÆ^;×­ïm~Øxcâ_ÄüSñ%ü> ¼¸¿ðÞ£¢GáòúM©°Hõ ydðìJ/džÍÕoÝ©6á'á>üBðÆ;Âóéÿ²ÂIåø¹à§ñÿÃ;{YìMCKYô¨‹kfk“L’4Öôù¤KFÔˆHïD~t‘AÑ£øÇÃ~0ø™?­öYø 7ÆïSMsN¾Ô"¶ð½½½¦ƒw$–Ú¢hò]O#Eâm$,o§Â7‹Ð\bk›wŸ°GÅÏ |[ñ7Å/x3öpøqña¼?¨xpë¾ól[âêš¾“u¬ßÓ%:}äPi·2[E0ÖQn5æ¼ÑÂÿjì ñO‹5XO,Š$Mhê÷z,’¶ ÓM¨ Öke¹kÓ;^«ù±ÎÊhÿg?|Eý˜´|ð¦¥ÿ -¥Å<ÞÓ"ÿ„;N“C»Õ¬ÛPXÖM—cž("d¿cÔeo²2?¥~Ò ‚ü®ê²ïÂK[OŒþ±ñ'Âäµû%Äš½ö«¡év©­†Ó£\ž‰4–ZD" Ò­#AÜõ ¿àz×Á?~ÏZχþ3xÂñ~]èx‚ÚêÓJŽÖòËGð•ö…v"K îáŽi.]ÞÑï 1 STš—2¬µÏø?þ 7ãíÁw:`·ø_¡]éþµÑõûí2þåäý¡® Õt›Ù¯|Wþ…†KÈ4ËûY¼ÆÕˆOêYi•dKÀ ~<~ÑeßÙãx;ã.¿coû9|$½ø{à¯è?üG­Imi³³¬+ìfÓN ÅšsLÍ%ì(ûYX$òbWÅø#O‰¾3~Ê>:Ðl¼I§üÖõKO xÁ·6—~ð¹Õ4;M(Úƒw¥oXä{k»‡¹±´²¸‹ûU ™¤–oP×ÿaŸˆïã½{AYðÿˆ|ãˆø‘­x»WÔßĖך~_²2ÚÅlî~ÖÞ…žá.-#¨Ë²Õ…²$àéÿ _ðwþ‰?ÃOü&,øÕðÅÿè“ü4ÿÂbÇÿW¥Ñ@iÿ _ðwþ‰?ÃOü&,øÕðÅÿè“ü4ÿÂbÇÿW¥Ñ@iÿ _ðwþ‰?ÃOü&,øÕðÅÿè“ü4ÿÂbÇÿW¥Ñ@iÿ _ðwþ‰?ÃOü&,øÕðÅÿè“ü4ÿÂbÇÿW¥Ñ@iÿ _ðwþ‰?ÃOü&,øÕðÅÿè“ü4ÿÂbÇÿW¥Ñ@iÿ _ðwþ‰?ÃOü&,øÕðÅÿè“ü4ÿÂbÇÿW¥Ñ@iÿ _ðwþ‰?ÃOü&,øÕðÅÿè“ü4ÿÂbÇÿW¥Ñ@iÿ _ðwþ‰?ÃOü&,øÕðÅÿè“ü4ÿÂbÇÿW¥Ñ@iÿ _ðwþ‰?ÃOü&,øÕðÅÿè“ü4ÿÂbÇÿW¥Ñ@iÿ _ðwþ‰?ÃOü&,øÕðÅÿè“ü4ÿÂbÇÿW¥Ñ@iÿ _ðwþ‰?ÃOü&,øÕðÅÿè“ü4ÿÂbÇÿW¥Ñ@iÿ _ðwþ‰?ÃOü&,øÕðÅÿè“ü4ÿÂbÇÿW¥Ñ@iÿ _ðwþ‰?ÃOü&,øÕðÅÿè“ü4ÿÂbÇÿW¥Ñ@iÿ _ðwþ‰?ÃOü&,øÕðÅÿè“ü4ÿÂbÇÿW¥Ñ@iÿ _ðwþ‰?ÃOü&,øÕu_|£|<Ó.ô}IÓ4="Îäù:}ª[[Aº4vÛ«–fcÉbzšèjŽ“ÿúŸý|¯þ‰Š€/QEQEWæŸü&»—Áö*xƒÿNþ¯ÒÊüÖÿƒƒFáÿ±S_ÿÓ¿†+ßáoùaÿÄ ‰ÿäU_ü,ü'ÿ‚©Œjß?ìž?þ¤zíÿø*ÐÆµðSþÉãÿêG®Ñ^¾n¿Û«ÿŽ_úS<œ«ýÊø#ÿ¤£õÂiŸØÏçþ¨…þ¢1ׯÕöw„ÐÿÃøtöÿ…cÿ¨Œuñ~ÃÀŸÃ—ý{¥ÿ·Ÿ’ç¿ÄŸý}©ÿ¶…Q_ žQEW»x·öVÑ´ÙŠ=z-CS?të /kd­¶‡I½žH`hÔ/™æ/ú,ŽKmÙx˜ŸÓ%·ƒR·{¸d¸µI¦Š9O*7(ri# §pzWÐ_ðQwZø•¯êŸ†ü-sáŸYÜéU¾§ZÞ®$&­†¤¶¿i>J¶³“ +åH⼌Õc_'ÔÖÏ™ëkÚÞæÏâ»ì•–¨ôòÇ„R—ÖÞr­/kï.Ÿn·Ñ; øµû'XɯÃw¥^è¾ ð®™á/êZ®©«Mw-°½¾³ö(Š9æi%ÊÁ +ª£Ÿ•V°µ¿Ø£WðέªKÅž ±ðî§iÚ”Þ"‘ë’Ò4mÓHé¸í|¡±P3]Ï‚þ4[þÑú^¿¡jÚ.†šÐôg²ºñµ‡oe¹Óaû,w×w‘äy‹ÂÊNÙÖÊä»öˆý§ŒºjGw¼i6ze¼Öð@r€ÌÌ’Ò¿2“· ß·ý±l¯ü[¨\jÞººÐõ¯Yx+P²µÕÖÞåÒÚ;`·NÐH¨Åí‘¶´N0Årxjèœ3yÅ·£ÒÖåþX7Ö×rçZ颶š¼iË,…H­×[óoÎÕ»ò¨Y­.úëî®YýŒôOx#á4ñ_ƒ4ÿxÆÒî…Ôú–|Ovº•ͼMû;ˆ‘aU3‹u$óȯ1àïØGÄ>0ðö…t²ãˆ^âæ³÷zKÝm-nãföKn[œX…‚ú¿5'ïûº{Ýcd¯¥”¹·»zkßú0¢Š+ùþ– +(¢€ +(¢€ +Ïñg„ô¯øWSеÝ3OÖ´MjÒ[ CO¿·K›[ûyP¤°Ë‚’Fè̬Œ`H ƒZPðSözðì×á[ áÏüà îí¯çÓü7£[iV³\2"4͈Ҏ5.FHFp¢» +( Š( Š( Š( Š( Š( Š( Š( 0ý–~ k³·ÀÝ#ÂW麤ö^\ÉqϹ»šè  ! ÛnÛœ.vAûF¥ÿ>–?øÿün¯Q@~ѩϥþ¿ÿ£í—üúXÿà[ÿñº½EQûF¥ÿ>–?øÿün´j_óécÿoÿÆêõGí—üúXÿà[ÿñº>ѩϥþ¿ÿ«ÔP´j_óécÿoÿÆèûF¥ÿ>–?øÿün¯Q@~ѩϥþ¿ÿ£í—üúXÿà[ÿñº½EQûF¥ÿ>–?øÿün´j_óécÿoÿÆêõGí—üúXÿà[ÿñº>ѩϥþ¿ÿ«ÔP´j_óécÿoÿÆèûF¥ÿ>–?øÿün¯Q@~ѩϥþ¿ÿ£í—üúXÿà[ÿñº½EQûF¥ÿ>–?øÿün´j_óécÿoÿÆêõGí—üúXÿà[ÿñº>ѩϥþ¿ÿ«ÔP´j_óécÿoÿÆèûF¥ÿ>–?øÿün¯Q@~ѩϥþ¿ÿ£í—üúXÿà[ÿñº½EQûF¥ÿ>–?øÿün´j_óécÿoÿÆêõGí—üúXÿà[ÿñº>ѩϥþ¿ÿ«ÔP´j_óécÿoÿÆèûF¥ÿ>–?øÿün¯Q@~ѩϥþ¿ÿ£í—üúXÿà[ÿñº½EQûF¥ÿ>–?øÿün¤ZÏÝÉp±#ÜÌ$ — +"õ wÒ®Q@Q@Q@~lÁÁC'Áö*xƒÿNþ¯ÒzüÚÿƒtžõ)øƒÿNþ¯…¿äm‡ÿ<(ÿ‘Uð³ðŸþ +¹ÿ!¿‚ŸöOÿR=vŠ“þ +º»uß‚£þ©ãêE®Q^ÆnÿÛëÿŽ_úS<œ§ýÆø#ÿ¤£õ“ +?ቼ:ê‡Øÿê%|Y_lø=1ûøtÿÕ±ÿÔJ:øš¿`à?‚_õî—þÞ~OŸõö§þÚQE~‚|øQEQEQEQEQEQEý4QEüNVQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@~nÿÁ—uÇ‚ýJ~ ÿÓ¿†+ôŠ¿8?à¾ëºïÁö)øƒÿNþ¯…¿äm‡ÿ<(ÿ‘UðŸ…ðV5Ûâ‚Ãþ©ãêE®QNÿ‚µ x›à¿ý“ÆÿÔ‹\¢½lãýþ¿øåÿ¥3ÉÊÜhÿ‚?úJ?Z¼ ™ý†ü8ê‡Øÿê%|C_qx5sû +øp÷ÿ…cÿ¨œuðí~ÁÀ_×ø)íçåÿñ%ÿ_*í¡EWègÏQ@¶¶{˘á‰KÉ+EX“€+èéfwǸ> Ý_ø³þWºMo%äGƒVs´B,M¿œÐ,¤BdûJ·Y<¿ùf~oÚ' ¤«)È#‚ {àý²´)¾%ÛüI¸ðÏñRÜ-Çö—öÊ®‹-ú «|úÙ÷™xW*.DfQ»fÒc¯5†*Vú½Ú´¾“æÓ‘êÕÒ÷®µWjñkoG/•kdïs&Õ®ù•’nïݳ¶‰JÍ;?á–4Ù·Oñv¥âý3Hñx“PÑ®4ËżeŸìÑÀDy6®å¤bYåXö¼2°p6¿jÏØâ˾&ÿ­øbâÇÁWMq?†íg½›QÒìšxáFi%‡É“ ,[•.$ußóUÂðšÇý.çàŒžñ.ƒªê÷šÝLj4ÍFËXŽÈÁs<1Ç ž7·—Î0ÆØV¾ðÝÈÆ·ˆ¿kÖ×~&|]ñ"hgŠvrZ¬nßý”^îÞã~ï,y¸ò6ã Ùíƒçª9¢Ä)Ý´¹ºÇ•ÞTì’ÞÊ<ûêº=uô\¹ÒåI+¸ÿ72W©vÞ׳†×OªvÓ?Ʋ&³àÝX3xƒÂ×Zÿ†c‚mwÃÖóÜhè±ÊñÆRЬ²IbGXf‘‘¤†ÛûB|›ösñ…LJµøcZ×l.$¶¿³Ò^êS§²cä’âmÁ²nåpC„a¶½3âßüRøÃá=bJOˆÍªë±Â.­ßÇ—xr)HžG‡MòAPÞ[b7ãC!*¸TUòOÚâÇü/_~'ñØ?²ÿá#Ô$¾û'ŸçýŸyÎÝûWv=v¥tåÒÍ%R?[\«Þ½¹^¶…’ëËw;uÑ]÷çÆ,¾4åõgÌôµî´÷®ßNo‡ËWeÛÑüû7ø{âwÀo\è°ëVÞ:ñ·‹äð¢Ï}«Åý“ªÛ°”–¾j†*¤y·Ë-ón +¸$ý”'ðöŠú”^4ðf±§éÚݾƒ­Í§5óyŒ›ZmöÉæÇû™~{o8œgrîÛø[ûZè_ <ðóL‹ÂµÞ©à?Ç×ã[{ù „<>H´Ý”·Œæ1 YŽàB¯%añûì_ |gáßìßð—ëÖ:ßÚ>Õ²}˜ÜŸ+nÏŸwÚ>öW:ñ£™F¬šº>—qwNi>®ÉBí-5[td¥‚t"¥nnG²jÏ–m_D›æäMê¬Þ½W®þÓ²vƒ§üPñ>•á½Cá÷…<'ðêE±Õ5Én5¹¥iä.®ÕâÉtþ\‹(<•òØQø±ð·Sø7ã{ U6ÒÍq\Ask!’ÚúÞTY!¸…È£’6VR@88 @ôïþך_Ä?üJ—ľº¼ð×ÄVjK amo´Ë¨ZO)¢º{y“LŒ¸>FÒ3^yñÇâËüfñëj˧äX[Z[išm„ry¢ÊÎچ̄#A¹È˜“…(2jy.JX«´¢®ÛO^X·­Ûo™Í/*V×}3Iàj9Ïdîì’kK´´jÖäQoís7ÓoèæŠ(¯ä“ú<(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š+óþ Þ»¯ü?êSñþü1_£•ùËÿëÔ|ÿbŸˆ?ôíáŠ÷ø[þFØñ#Áâù×ÿ ? +à®Coо ú§‡ÿR-rŠ_ø+¯üŸ?ìžýHµÊ+ÖÎ?ßëÿŽ_úS<œ£ýÆø#ÿ¤£õ·Á‘çöðéÿªcÿ¨œuðÍ}éà_3öðëc§ÀëýD㯂ëõþ~ä¿ÁKÿo?+âÚ¤¿ëåOý´(¢Šýù°¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(úh¢Š+øœþ¬ +(¢€ +϶ñf•yâ«Ý +OO—[Ó­-ïîôô¸Fºµ·æH&’ w¬r=µÂ£%’ +ùCÆß´/€e?ø)'Ä=wâŽ<ðÛDñwÃ_XhZ‡Šu›m×Z¸²ÕþÎÿ´Gƒõo‰> ñÎ…iÿ gÂyaÖôÍ&½µo…—ž.¤eglF —L,Ç–R×ìh¡­šçuÓtnÿˆÑõM3á_ÇïüNødÚ®ƒ ÿÆ}o\ðþŸaáin­|E-팚ݎ‘q£Úùr鞌-Λ<»µõ™ZòÎH?O评?bŸÚ7â'ůŠiñã.Ÿ§èš‚¼'sg6‚,?±¼Gu¨ø»_²¶¹·º]¼·r_Úi:m¨–Ö+k[“<ÖP žÎXþï Š( Š( Š( Š( Íφžø!àÙ×áψ>$xcâF½¯üHñ„ž¶ºÑ^šÊî±þÑÔ->)hºÜ±yÑòÏOø…oy.de˵¶žM îm›T3SöÕx/ü;/àÇý šçþšÇÿ%QÿËø1ÿBæ¹ÿ…f±ÿÉUïTP‚ÿòþ й®áY¬òUð쿃ô.kŸøVkü•^õEx/ü;/àÇý šçþšÇÿ%QÿËø1ÿBæ¹ÿ…f±ÿÉUïTP‚ÿòþ й®áY¬òUð쿃ô.kŸøVkü•^õEx/ü;/àÇý šçþšÇÿ%QÿËø1ÿBæ¹ÿ…f±ÿÉUïTP‚ÿòþ й®áY¬òUð쿃ô.kŸøVkü•^õEx/ü;/àÇý šçþšÇÿ%QÿËø1ÿBæ¹ÿ…f±ÿÉUïTP‚ÿòþ й®áY¬òUð쿃ô.kŸøVkü•^õEx/ü;/àÇý šçþšÇÿ%QÿËø1ÿBæ¹ÿ…f±ÿÉUïTP‚ÿòþ й®áY¬òUð쿃ô.kŸøVkü•^õEx/ü;/àÇý šçþšÇÿ%QÿËø1ÿBæ¹ÿ…f±ÿÉUïTP‚ÿòþ й®áY¬òUð쿃ô.kŸøVkü•^õEx/ü;/àÇý šçþšÇÿ%QÿËø1ÿBæ¹ÿ…f±ÿÉUïTP‚ÿòþ й®áY¬òUð쿃ô.kŸøVkü•^õEx/ü;/àÇý šçþšÇÿ%QÿËø1ÿBæ¹ÿ…f±ÿÉUïTP‚ÿòþ й®áY¬òUð쿃ô.kŸøVkü•^õEx/ü;/àÇý šçþšÇÿ%QÿËø1ÿBæ¹ÿ…f±ÿÉUïTP‚ÿòþ й®áY¬òUzOÁO„ÚÁ? ]øÃV/a¥[^4‰—2ÜÈÌñÆÌÏ,¬ò9ÉÆYŽ +0±ª:Oüêõò¿ú&*½EPEP_œßð^OÀãþ¥?ÿéÛÃú3_ð^AWÀÿö)x‡ÿNÞ¯…¿äm‡ÿ<(ÿ‘Mð³ð£þ +ð»|]ð`ÕËÿQHëàýw€> ÿ‚—þÞ~]ÄjÓõò§þÚQE~Š|ÁÔ|ømÿ “ã…¼%ößìïøIu[m3í^Oöo:EMû7.ìnÎ7 㨭¿üo7ÄUMSÈi’j*>Í»û@­äÞ_ß^|íÙù±·ç#žøCñ„_|5â«hê ê–Úš@íµf0ʲl'íÆqÆkÖÆ?‡ÞÓn@oGý±þ)xKàÿÇÏŽ0è·$Ö|]ã+ÇÒ.â½Óâ²Ót¨~ÕĬޗIrå rB3±ákñí9ðçZºøµâ[sãfñ/Å}#ìÒé’éÖËc¤ÜIsmq0[¯´´“Gº|ˆÈr§·‰C2̱8ZumÏÊî£.¼ŽÖm´µŸ¼ô´vÕ7ìÔËð1R§)_–V³’Ù9+·eÙ{›ë¾/#Õÿf¿i¹ñ2Å jZ=„qMxúWˆ´íNkå!Qç†Úy%…KRdE˜)Á WWñ{ö#ñ7ÃxgKÓ/4]x¢ËO¸µ¶°Õ,e½ó®­„æ?³Gq$¾Re‡Ú +ˆ˜ÙŠî|mûUü6o„^:м1¦_iiâ­ÛNÓ´¨ü¥Z Çuk;,ºªL÷·£¸ß(RÌC§¦~ÖþÐ~(øǶÉâµÝ#ÃÖÞÖ4™´«V³&œö\A;Í •ö•uŠkm„åX•ëºÇf²N¢§ksYr½}Ô➺{×NI¸ùµ«çXL¹.YN÷JîëOy]­5÷[j-);lžÞ-ñ3àŸˆ¾A§O¬A§=–®²;Ý7U´Õlî d gµ’H·©+¹7nPÊH;Ÿ¾ iZŸÃ+Ÿø¿Ä7~ðÈ¿:E—ö~–5-CR»²:Ç Íb8ãe.í(Át +®XíÙý¤>7iü èº.­{©Ûé×·W²«ø#Gð­´-*@€¤:{Hdv|Ï#ôXÀ^ 5þüTðˆ>7ÃÿÿÂC§[iš¬ºÞ‹¬h¶q_Ím,ÑÃż¶ÒÍ +¼N°£YU‘Óá°½ê¾2XHÎjÒæ×•;òßu+ÞÛ¦ž—i7dr:8Hâybï=Ú·7+²n.ÖnÛ5m›Vlχö}?ð¯ð¿Å·š»dÖ‹,EÖE!”2º:’#)VWBU•ƒ) ƒ_Lß~Ü~¸Ôµ­Ò^ÏÃ:ž YC¨jÒµë¨gÒíM¾^ÂíÍ»¤ä!–Tt!H$nCá´gÄ»oŠÿåÕ,ïou 8ì­, žëI²Òdu†Þ8°-lÇ‘ +¥Q¶(,MN#1•EO£Ë½Ÿ3vŽ¿Êµr\·æÒûaC©óГæÓK¦—uÝ÷æK–únEÔQE$ŸÒEPEP?¦ü-дŠzÏmì|¿øƒJ°Ñ/ï|éÚ,ìf½šÖ/,·–»$Ô/r¨fó°Å‚ ^‚Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(È?c?†º÷ÀÙÓDðÆ¹¦¹Õ-.oî¦ÓÅ$h.o®.Q7eI•[n ‚ÃúöµÇý/¿ï¸øå^¢€(ÿk\Ð2ûþû‡ÿŽQý­qÿ@Ëïûîþ9W¨  +?Ú×ô ¾ÿ¾áÿã”k\Ð2ûþû‡ÿŽUê(öµÇý/¿ï¸øåÚ×ô ¾ÿ¾áÿã•zŠ£ý­qÿ@Ëïûîþ9GöµÇý/¿ï¸øå^¢€(ÿk\Ð2ûþû‡ÿŽQý­qÿ@Ëïûîþ9W¨  +?Ú×ô ¾ÿ¾áÿã”k\Ð2ûþû‡ÿŽUê(öµÇý/¿ï¸øåÚ×ô ¾ÿ¾áÿã•zŠ£ý­qÿ@Ëïûîþ9GöµÇý/¿ï¸øå^¢€(ÿk\Ð2ûþû‡ÿŽQý­qÿ@Ëïûîþ9W¨  +?Ú×ô ¾ÿ¾áÿã”k\Ð2ûþû‡ÿŽUê(öµÇý/¿ï¸øåÚ×ô ¾ÿ¾áÿã•zŠ£ý­qÿ@Ëïûîþ9GöµÇý/¿ï¸øå^¢€(ÿk\Ð2ûþû‡ÿŽQý­qÿ@Ëïûîþ9W¨  +?Ú×ô ¾ÿ¾áÿã”k\Ð2ûþû‡ÿŽUê(öµÇý/¿ï¸øåÚ×ô ¾ÿ¾áÿã•zŠ£ý­qÿ@Ëïûîþ9GöµÇý/¿ï¸øå^¢€(ÿk\Ð2ûþû‡ÿŽQý­qÿ@Ëïûîþ9W¨  +?Ú×ô ¾ÿ¾áÿã”h±ËæÞË,2AçÎUÊ–À?)#ªžõzŠ(¢Š(¢Š+ó«þ À3«øþÅ/ÿéÛÃú+_ð]ÑgÀßö)x‡ÿNÞ¯…äo‡ÿ<(ÿ‘Mð³ð£þ +þ1ã/ƒ?öNÏþ¤:å¿ðX!üÿ²võ!×(¯k7ÿ¯þ9éLòr÷ +àþ’×ÿË·þ ùáÁÿT>ËÿQHëà*ûÓÁ¯ŸØÃþ¨}—þ¢‘×Áuú×/rà¥ÿ·Ÿ–ñ½I×ÊŸûhQEú)óAEPEPEPEPEPEPôÑEWñ9ýXQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEùÙÿÙ]Ú߇ýJ^!ÿÓ·†+ôN¿;ÿàºxþÞð6zÂ%âý;xb½þÿ‘¶üHð8£þE5ÿÂÏÂø,4dxßà×ý“³ÿ©¹E;þ øñ×Á¯û'û°ë”W³›ßëõÿÇ/ý)žNQþáCüÿÒQúßà±ÿáÃÿT>ÇÿQ8ëàÚûÓÁ+ÿáÓÿT:ÇÿQ8ëàºýs€‡?ðRÿÛÏË8‡ø’ÿ¯•?öТŠ+ôCæÂŠ( Š( Š( Š( Š( Š( 颊(¯âsú°(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š+ó»þ ¯Î¹àoû¼Cÿ§o Wè~wÁu9×¼ ÿb—ˆôíáŠúÿ‘¾üHð8£þE5ÿÂÏŸø,Oü¿ìŸýHuÊ)ృ;ø5ÿdïÿvrŠös÷úÿã—þ”Ï'(ÿp¡þÿé(ýuðJÿÆxsþÈ}þ¢‘×Á÷Ï‚Wþ5ÿáÓÿT>ËÿQHëàjýk€> ÿ‚—þÞ~[Ä_Ä—ý|©ÿ¶…Q_¢Ÿ4QEQEQEQEQEQEMQEŸÕEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_ÿð]OùxþÅ/ÿéÛÃú!_ÿð]?ùxþÅ/ÿéÛÃô+ÿ#|?ø‘àqOüŠkÿ…Ÿ…?ðXßùþ Ù;ÿ݇\¢ø,oü¿ìÿîîQ^Îqþÿ_ürÿÒ™ääÿî?Áý%¯~_ø×ç‡?ì‡Øÿê)|_  ñ¯Ÿ{|²ÿÔR:üÿ¯Ö¸àŸø)íçå¼EüI×ÊŸûhQEú)óAEPEPEPEPEPEPôÑEWñ9ýXQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEùáÿÓÿ÷¿ìRñþ¼1_¡õùáÿÓÿ÷¿ìRñþ¼1_A¿ò7Ãÿ‰?Å_ò)Ä…Ÿ…ðXßùþ Ù;ÿ݇\¢ø,oü¿ìÿîîQ^Îqþÿ_ürÿÒ™ådÿî?Áý%¯ÞlÁ?<;ÿd>ÇÿQHëóþ¾üðA?ðïÿú¡ö?úŠG_×ë\ðOü¿öóòÞ"þ$¿ëåOý´(¢Šýù ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(úh¢Š+øœþ¬ +(¢€ +(¯/¶ý¯<?í¡{ð§Ô!ø…kà«Å Ú“ky¥É}5ƒ´s@’)â@èáI1ó1/–êWû=|kÒ¿iO€^ø¡[êš'ü?aâM> ôHî¡·¼¶Žâ$•Q@’(`®ÀpÄsZ >)h_<9s«xrûûGO´Õu-Y|™!Ùy§ßOay$U'˺¶ž=Àmm›”²•bÐQExþ»ûkxWHø»qà›}?Ħ³Šôÿ¡µ‚†ãX¹Ó_XšÕZYP²i +5 ¤`±´R,P=ÅÖëeö +(¢€ +(¢€ +(¢€ +(¢€ +(®>çã^•§ü}²øswo¨Zëz·‡î"øj ?Lñ.‡à¯ Ü|5Öµ¡ýœ¾%°—ÆÍä(Sg%¦¶–óŸ+w“+[º\D’Ãõ}|–Ÿ³w„?hïÛ¿ã<>0±Ôut=?ïe¾±{`°´Ö÷"S‹yc XC-œlÇ4ó¦§ÿ÷ø˜?e‡ÞÕ¾ÿÂUãk_ÙÿÃðf¯öí&oøQÞ2³³¾Šï[óç¹Im?}s¥?ÚôqsrßØÙØL6¢Cã·üûÅͬwþñˆ<-Ĉ$×4ŸØx3R›Å—úî±m©húÓÛx™ÂO±éÆãM’y–;øeU¸’ÎG™þÅÿ‡eüÿ¡s\ÿ³Xÿäª?áÙ?è\×?ð¬Ö?ù*€<«özý’¹­x;PէѼa¤jþ;Õ|j5»©¶™±…u–Ú…Ä’]šãNžÏû.ॶ«–zŠÏkqÏÉðçâ÷íó¯Ayáí?X´ðwí¦üG¿´Ô– ÖÚ_ü*ôÓ4ýb8f!¤ŒkPaš%b.,¦*CZÊc÷_øv_Áú5Ïü+5þJ£þ—ðcþ…Ísÿ +Ícÿ’¨â«ø&Wü[àxb÷àÆŸ¦K¤ZxcHøÁ}.%¯ÇJßž½»×¥ò®$—RŽ;M/Ä4š¼p]¸ÕФ/%ÍÂ'¸ÁQ|ÿ ûã·„~x[[ðýç¾$ü?ñwÃ]_H’óý3Â~×ííåŸÅrÁ’W·¶›B[HãtŠ›­FݹÁoeÿ‡eüÿ¡s\ÿ³Xÿäª?áÙ?è\×?ð¬Ö?ù*€>JøóÿÞø‰ñ¶ˆ~Ò|§ø{âŠnþ m|]¿»°K_è:Ö¯ÛhÚ·0I&¯4vm©èA­î­Ú¡%¤û=Ÿ›ØkŸ³WÄÏÚ—þ +OàŸŠž0ø/ÿ×€´]WÂ×Ùëú¾“©_Úei~?Qusoo4ÐÅq¥¬éO·–ç -´ÂD‘."µúþ—ðcþ…Ísÿ +Ícÿ’¨ÿ‡eüÿ¡s\ÿ³Xÿäªñ¯ø(çì‘âÿŽü_{¦|9ÿ„ûPñ7Ãûo|5ñ'Ÿ¦øS^&IµS.¿¾òx®lwµæ‘'Út¤¸»?Øù1†‚ÔIçÿ¿à˜ßøƒ@ðÜ-õ¯èZF¯áýgWñý²éúœr“­æhº¾ÍJòÂtÕu˜­u;Ûkšò}§Z\]zÀ¯Rü1øõðÁÚ·„|AãøAþøžê÷EÕnô}VÿÂqj>1ðÍÖ†÷~DvºuŸÙ’ÂæX-íÊt+ˆl ߨ‘ßè_øv_Áú5Ïü+5þJ£þ—ðcþ…Ísÿ +Ícÿ’¨Þ¨¯ÿ‡eüÿ¡s\ÿ³Xÿäª?áÙ?è\×?ð¬Ö?ù*€=êŠð_øv_Áú5Ïü+5þJ£þ—ðcþ…Ísÿ +Ícÿ’¨Þ¨¯ÿ‡eüÿ¡s\ÿ³Xÿäª?áÙ?è\×?ð¬Ö?ù*€=êŠð_øv_Áú5Ïü+5þJ£þ—ðcþ…Ísÿ +Ícÿ’¨Þ¨¯ÿ‡eüÿ¡s\ÿ³Xÿäª?áÙ?è\×?ð¬Ö?ù*€=êŠð_øv_Áú5Ïü+5þJ£þ—ðcþ…Ísÿ +Ícÿ’¨Þ¨¯ÿ‡eüÿ¡s\ÿ³Xÿäª?áÙ?è\×?ð¬Ö?ù*€=êŠð_øv_Áú5Ïü+5þJ£þ—ðcþ…Ísÿ +Ícÿ’¨Þ¨¯ÿ‡eüÿ¡s\ÿ³Xÿäª?áÙ?è\×?ð¬Ö?ù*€=êŠð_øv_Áú5Ïü+5þJ£þ—ðcþ…Ísÿ +Ícÿ’¨Þ¨¯ÿ‡eüÿ¡s\ÿ³Xÿäª?áÙ?è\×?ð¬Ö?ù*€=êŠð_øv_Áú5Ïü+5þJ£þ—ðcþ…Ísÿ +Ícÿ’¨Þ¨¯ÿ‡eüÿ¡s\ÿ³Xÿäª?áÙ?è\×?ð¬Ö?ù*€=êŠð_øv_Áú5Ïü+5þJ£þ—ðcþ…Ísÿ +Ícÿ’¨Þ¨¯ÿ‡eüÿ¡s\ÿ³Xÿäª?áÙ?è\×?ð¬Ö?ù*€=êŠð_øv_Áú5Ïü+5þJ£þ—ðcþ…Ísÿ +Ícÿ’¨Þ¨¯ÿ‡eüÿ¡s\ÿ³Xÿäª?áÙ?è\×?ð¬Ö?ù*€=êŠð_øv_Áú5Ïü+5þJ£þ—ðcþ…Ísÿ +Ícÿ’¨Þ¨¯ÿ‡eüÿ¡s\ÿ³Xÿäª?áÙ?è\×?ð¬Ö?ù*€=êŠð_øv_Áú5Ïü+5þJ£þ—ðcþ…Ísÿ +Ícÿ’¨Þ¨¯ÿ‡eüÿ¡s\ÿ³XÿäªôŸ‚Ÿ ´‚~»ðÿ†¬^ÃJ¶¼i9.e¹‘™ã™žYYäs“Œ³`cEPEP_žð]?ùxþÅ/ÿéÛÃú_žð]?ùxþÅ/ÿéÛÃô+ÿ#|?ø‘óüUÿ"œGøYøQÿÿ‘ïà×ý“¿ýØuÊ(ÿ‚ÆÿÈ÷ðkþÉßþì:åìçïõÿÇ/ý)žVOþáCüÿÒQúùàùGç‡?ì‡Øÿê)|_ >þ5÷áÃéð>ÇÿQHëóú¿Zà‚à¥ÿ·Ÿ—qñ%ÿ_*í¡EWè§Ì…Q@Q@Q@Q@Q@Q@ÓEQ_Äçõ`QEW‚ü ÿ“øøûÿ`ß è‹ê÷ªð_òìáoý}@õEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPTtŸøÿÔÿëåôLUz¨é?ñÿ©ÿ×Êÿ蘨õQ@Q@~wÿÁu?ä;àoû¼Cÿ§o Wè…~wÿÁu?ä;àoû¼Cÿ§o WÐp¯üðÿâGÏñWüŠqágáOü7þG¿ƒ_öNÿ÷a×(£þ ÿ#ßÁ¯û'û°ë”W³œ¿×ÿ¿ô¦yY?û…ðGÿIGë÷‚eÇüóËÿT>ËÿQHëóþ¾ûðIÇüÿßöC¬õ޾¯Öø{“ÿ/ý¼ü·ˆêKþ¾TÿÛBŠ(¯Ñš +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€?¦Š(¢¿‰ÏêÀ¢Š(¯øÿ'ññ÷þÁ¾ÿÑÕïUà¿ÿäþ>>ÿØ7Âßú"ú€=êŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ¨é?ñÿ©ÿ×Êÿ蘪õQÒãÿSÿ¯•ÿÑ1Pê(¢€ +(¢€ +üïÿ‚êœkžÿ±KÄ?úvðÅ~ˆWçüWþCžÿ±KÄ?úvðÅ} +ÿÈßþ$|ÿÈ£þ~ÿÁc|uðkþÉßþì:åŸðX¯ù~ Ù;ÿ݇\¢½låÿÂ…ñËÿJg”?ö +àþ’×þÀÿ²cÿ¨¤uð=}íà“ÿ áßû!ö?úŠG_×ëÜü9‚—þÞ~]Ä÷’ÿ¯•?öТŠ+ôCçŠ( Š( Š( Š( Š( Š( 颊(¯âsú°(¢Š+Á~ÿÉü|}ÿ°o…¿ôEõ{Õx/À¿ù?¿ö ð·þˆ¾ z¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(ª:Oüêõò¿ú&*½TtŸøÿÔÿëåôLTzŠ( Š( ¿;ÿ຿òð7¿„¼Cÿ§o Wè…~wÁu¸×| ÿb—ˆôíáŠúÿ‘¾üHùþ*ÿ‘F#ü,ü*ÿ‚ÅŒxëà×ý“¿ýØuÊ(ÿ‚Æøëà×ý“¿ýØuÊ+ÖÎäa_ürÿÒ™ãåî4?Áý%®> oøÀzÿ±ÿÔN:ø2¾ððKÆøsÛà}þ¢‘×Áõúÿ|ÿ/ý¼ü·?þ$ÿëåOý´(¢Šý ùТŠ(¢Š(¢Š(¢Š(¢Š(¢Š(úh¢Š+øœþ¬ +(¢€ +ð_òìáoý}^õ^ ðqN‘ûr|u¾»ÖÊîËÃpAq7ÉÒGmtÒ"±á™D±–ä ?xdÞ¨ª?ð“é¿ô±ÿ¿éþ4ÂO¦ÿÐBÇþÿ§øÐê*ü$úoý,ïúð“é¿ô±ÿ¿éþ4zŠ£ÿ >›ÿA ûþŸãGü$úoý,ïú^¢¨ÿÂO¦ÿÐBÇþÿ§øÑÿ >›ÿA ûþŸã@¨ª?ð“é¿ô±ÿ¿éþ4ÂO¦ÿÐBÇþÿ§øÐê*ü$úoý,ïúð“é¿ô±ÿ¿éþ4zŠ£ÿ >›ÿA ûþŸãGü$úoý,ïú^¢¨ÿÂO¦ÿÐBÇþÿ§øÑÿ >›ÿA ûþŸã@¨ª?ð“é¿ô±ÿ¿éþ4ÂO¦ÿÐBÇþÿ§øÐê*ü$úoý,ïúð“é¿ô±ÿ¿éþ4zŠ£ÿ >›ÿA ûþŸãGü$úoý,ïú^¢¨ÿÂO¦ÿÐBÇþÿ§øÑÿ >›ÿA ûþŸã@¨ª?ð“é¿ô±ÿ¿éþ4ÂO¦ÿÐBÇþÿ§øÐê*ü$úoý,ïúð“é¿ô±ÿ¿éþ4zŠ£ÿ >›ÿA ûþŸãGü$úoý,ïú^¢¨ÿÂO¦ÿÐBÇþÿ§øÑÿ >›ÿA ûþŸã@¨ª?ð“é¿ô±ÿ¿éþ4ÂO¦ÿÐBÇþÿ§øÐê*ü$úoý,ïúð“é¿ô±ÿ¿éþ4zŠ£ÿ >›ÿA ûþŸãGü$úoý,ïú^¢¨ÿÂO¦ÿÐBÇþÿ§øÑÿ >›ÿA ûþŸã@¨ª?ð“é¿ô±ÿ¿éþ4ÂO¦ÿÐBÇþÿ§øÐê*ü$úoý,ïúð“é¿ô±ÿ¿éþ4zŠ£ÿ >›ÿA ûþŸãGü$úoý,ïú^¢¨ÿÂO¦ÿÐBÇþÿ§øÑÿ >›ÿA ûþŸã@¨ª?ð“é¿ô±ÿ¿éþ4ÂO¦ÿÐBÇþÿ§øÐê*ü$úoý,ïúð“é¿ô±ÿ¿éþ4zŠ£ÿ >›ÿA ûþŸãGü$úoý,ïú^ª:Oüêõò¿ú&*?á'Óè!cÿÓüišÔW·:”°É±µÈãSû˜ÇQ@4QEQEùÛÿØ8Öü ÿb—ˆôíáŠý¯Îßø.Ïü†ü ÿb—ˆôíáŠúÿ‘¾üHùþ*ÿ‘F#ü,ü*ÿ‚ÅøçàÑÿªwÿ»¹E'ü#þGƒ?öNÏþ¤:åêç?ò0¯þ9éLñò÷ +àþ’Ö¿Kÿáåÿª!cÿ¨œuð¥}»à‹¿±/‡Ó·ü) ýD£¯ˆ«õþø%þ +_ûyù^|ÿy?úûSÿm +(¢¿C>|(¢Š(¢Š(¢Š(¢Š(¢Š(¢Šþš(¢Šþ'?«Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ¿;à»G׿ìRñþ¼1_¢UùÙÿÜÿ׿ìSñþ¼1_CŸò7Ãÿ‰?Å_ò(Ä…Ÿ…_ðX~|oðgþÉßþì:åÁa¿ävø3ÿdìÿêC®Q^®sÿ# +ÿã—þ”Ï(ÿp¡þÿé(ýRð\ØýŒü<ŸõDlõ޾-¯²¼Øý¼:=~ Xê#|k_°ðÁ/ú÷Kÿo?+ω?úûSÿm +(¢¿A<¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(úh¢Š+øœþ¬ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +üëÿ‚îÈgÀßö)ø‡ÿNÞ¯ÑJüëÿ‚îÈgÀßö)ø‡ÿNÞ¯¡á?ùaÿÄŸâ¯ùb?Âϯø,/üŽßìŸýHuÊ(ÿ‚ÂÿÈíðgþÉÙÿÔ‡\¢½lëþFÿÇ/ý)ž6QþáCüÿÒQú‘áÿ…áÏû"VúˆÅ_WØÞŒÿÃxpö?¬?õо9¯Ø8à—ý{¥ÿ·Ÿ”çßÄŸý}«ÿ¶…Q_ Ÿ<QEQEQEQEQEQELjr ûzb–’>c_§®ZZþ'gõ€QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW埉¿nÚoãoíµã…ÿ |M£éÏ£kº¥­Œ2iö*«mkq$ct“Ääª îNkõ2¿)a&Çüóâ?8ηâa×ÿJ—Ü_§q÷œJ‡±ÆâjÒGNŸ4T⤮¼™ñÜWR¯µÂP§RPU'gÊÚvõGsâ¯ìó¥>½¬ZèÞ7Ò¬–æ;{ Ÿ-Aþ(­–)Êà”$‘ÛÝ¿àŸðT öÛ[S°‡Ã~9Óá7 d’—·Ô! , yI£l °Ý·êºü‡øŸ¡[~Î_ð]? ¶V×þ(ÓÁ +áa]F(’é@ý¢c€0cµwerÁñ F®«Bq•5ÊŸ/I+Û[­{yœ™‚Ådµ¨×§^U)NJŒß3WêžúXú÷ã/ÁïÚ7Yÿ‚‹xgÄ~ñ,¶ÿ­¤³{«TÔ–+Xí“hº‚kRs,Ò4¤htù”­}w_š¾Ã`¡ŠÄÚm*®.îúíxö^[Ÿ¦4Wæ/Çÿ€¶sü5¿ø¡«üN—O¹Óm[T¸ðÖ‡¬Odö0(Þш¡U‚FG*]Ë8go½ô/ü'öÚÖÿl‚ÚÅ·‹&ŠïÅ^ºŠÞêñ#XÍì+eu\ùŽU8€õ&¼L +N†XúáV0iO‘¿u½·Jêú_î=\ƶ1`ëQ9I7d½ä·Ù»?#坸7­¿âõ|Bë¢@qŸúoõþŸˆïúµ_ŽðGžý™®þ-øËÄ·7Hðô."B<ëÉLøŽÔ‘—v!Gaœ’ ^ñûøãGíÓñ«Pø½ã?øãÂß¾Ýö;BÓµ›«;-L¡Ú°Fˆê¿gj‡}¹•ƒ ’\¯ã¬ŠXŒÏ«5N”ßÚ—*´bº¿Ë®‡Ìð~o~Nu&äì¾ÌyŸ½'Ñ~}Ñz+âÏø(÷íÁã|dð·Á?„ m0¹ð¦æË6¯púr\ÞHæ8ÖÞQH¢Y0¡p¤ÄF8¯øñ럳wüÿâg‰üiªC‹Ä>#·{‘m5Æîå +6B¬Ü‘×iN£ìò>Y~#‡©b*Ó¤¤“2Rz¥g»ÛnçÊfÙëÆÐÂׄåFœê4Ú—+qZ^ýûžŸñköŽý¶bí$h±ßE§e¬$ÒÅ“8ݲÈ<’à&èÞ6Ód‘çax>¥EJkÂZ©8Aó]§µÚMFý.õ;±O +n¤éÑ”éÓv”Õ¬šÞɴݺØý1¯Î¿ø.鯳àoûüCÿ§o WÜ?³ÇÆ‹Ú'à‡†0üE×sg9ÎÁÏÊe™¾†IŒÀTož«§Ë¦žì®îúh}?,¯W6Âã!nJjwïïFÈüŠý„?b{ÿÛsTñ¦§ëK¥\è:+jV¸Ìw×yÙoÏÊ„³ø%Cp9¯³ÿàŒŸ¶Õæ™y?À_4–:·$Ðè&ì”ÙŒöžCÆC°uãjƒô¿ìmÿÞð?ìAâmgUð¦«â½Fç\µKI×Vº‚XÑ÷‚¢(cù³Ü“øV?Ç¿ø%/ߟÄyu_x[Äáà¸3h¶öÈ×0Rç÷HD¿*|Ê@ùÆì“öyßå¹­JøW)ál~]NŽ+—¶M©ÆúJ-÷è×çé¯ÂßðVO…Úv•ÿ4¶¾ñíί¦xÆPéòÉ¨ÙÆí­Ò$¶”Ç• ˜Þ2ì¸fÃŒ™Aõmþ û:kÚj–®ntçO0\Ǭi¦= I;p1ÎsÓ¿Jû¿ã·ìËàßÚgáòxoÇ:Lzý¤ 4Sˈóc’0¥÷Û…=Çó +Á~ &¨.±ñ ¢ »ìÇRµòˆþîE¶üÀ³ïX`¸Ò”ðpóÄÔ¡:QQ|±RŒ’Ñ=lÓ¶ý ±|+V8ʵãB£Qó{Òqqou¥ÓWØöØÛö:ðÀïÙ›Wðw‡5ɼkàïOsyqw=Ä3ÇyżvÒ"< )Œ¤]Fy'ž˜ü±—⎹ûØ~Ðß'iÙüD‰¥ÛNÀ®BΓag²šCï”ê8?¯¶ ð÷öýž--'ÔÃ>ð´f(å¾¹–å“Ì‘ŸmÒ;3»aW=p üÓ´Ñm?௟ðSc«éZ$ö^Ñã·}VycÙ%Å•¿Í àK;~í@;•9çËjÛƒ±²«[‹Ç^xm&ç%kÊN\Ϫ^K±Ÿa#N– „´q +Œu÷g¥çʺ7æ}ËÿýŸOìýûxj+˜ _Å øƒP0Á§U1)AX AèÁ¸ŠøSöføGáŸßðXÿ‰Z‹4{-wH—Ä$™­.1³¥Ô¥NÇéÜ~¾¢Ð*€ª£€|ÿð—þ ½àoƒµ6·ñwLÕ|Y?‰5ë«ë»‹k«¨ÅîF’@¨°«à;AsŒäó_=•ñLa<~'&ªW‹å·I6í¯Ktgµ˜ðëœ0T(Å8Q’æ¿T–ºu¹òüÏþ Ñூ-~%|7Ñ…ïlÛöí’`ñ©ÎxÃ0çzŽÿ«Ÿ>i¿³ÿÂ=Áš=ÅýÖ™áëQko-ì‹$î “—*ª¤äžŠµyWìoÿÞð7ìAâmgVðž«âÍBç\µKI×Vº‚XÑ÷‚¢(cç=ÉÏöNƒÂ×>$ÐìüI½rƒM¸¼Ž©Œ» e#bÃts’¤gŒ·ù¯6`±yf'˜9Bu*º©Å]s5ð¾ÇuL—†ÇáñX$¥STÚnÎÉî?ho¾‡þ +ãO|[Öõ_ +xoÄšÍÕü:¼6·DÍlì̬¾NXFÍŒ)qX¡'ÿ‚=~ÎÖú)ÔŸãuÄzvÏ3íM­i‚§£oÛ·Žsüøû[öŸý‹þþ×Ú½§tAwsd³Ô-ä0^ÚÉ ê§û¬sÎ3Í|õ¤Á¾ +iº¢ÜMª|@Ô"&ÚãS¶X›Ø˜íÑÿñê÷éñÅøjJXš”%¨¸Æ1”enªöi¾·Óó~=N«F½G=:Ñ”œ“”œZ¿Gmíåÿú_öTø¢þÍ<;àÏêWz¾‹¥G4–——.%ÂÏ<—²€)”ã¦:õ¯‹?à¼òð7ýŠ~ ÿÓ·†+ôÂ>±ð/„ô½L‰áÓtkH¬m#y^VŽ(")w%˜…P71$õ$šüûÿ‚ðœjÞÿ±OÄúvðÅ|gוlú•i¶Ü§vÞí¶Ýß›>“ˆ¨Æ–GV”U”ak-•¬¬~Á`4ø3ÿdì÷ÿ©‡\¢“þ +ûÏŒ¾ ÿÙ;?úë”W¡œßûB¿øåÿ¥3ÌÊ?Ü(‚?úJ?R~ ^Xx÷öXð%½½ü1Új¿ ì<ä‹ö@ðDãå´“ññüßüÎT¿ðÆž Çüy¿þ ¿ùœ¯‡"ÿ‚ïøöòü+ø4?펹ÿË:›þÛñòK~ ßsÿ–tÿ×ÿÏê¿zúµŽÿŸt>é‘öçü1·ƒ3ÿOÿ‡oþg)ìmàÐãÉÿðàMÿÌå|GÿíøƒÿD·àÏýø×?ùgHßð^ÿˆ@ãþgÁŸûñ®òΩqŒÿçõ_½ ý[ÇϺt¿ÈûwþßÁ¿óäÿøp&ÿænøcÿÏ“ÿáÀ›ÿ™ºø‡þáñ þ‰gÁŸûñ®òÎø‡Ä/ú%ŸïƹÿË:ë„¿çõo½ ý\ÇϺt¿ÈûxþÇ òäÿøp&ÿæn“þëÁŸóäÿøp&ÿæn¾"?ð^ÿˆGþigÁŸûñ®òΓþÝñþ‰gÁŸûñ®òΩq‹ÿŸÕ¾ôêÞ;þ}Ðû¥þGÛßðÇ^ ÿŸ'ÿÃ7ÿ3t‡ö<ð`ÿ—'ÿÃ7ÿ3uñü?·âýσ?÷ã\ÿå'ü?¯âýσ?÷ã\ÿå5Æ?ôú·Þƒý[ÇϺt¿ÈûtþǾ òæßøpfÿænþÇþ òæßøpfÿæn¾#ÿ‡õ|@ÿ¢YðgþükŸü³¤?ð^ŸŸù¥ïƹÿË:ëŠÿŸÕ¾ø‹ý[ÇϺt¿ÈýÁÿ‡¡xÁ?á økÇýN:§ÿ)é§þ +‘âñÿ2oÃ_ü,5OþSWáóÁy¼}ƒÿ¯àÏýø×?ùgL?ð^_¿ +þ ÿßsÿ–uó +–Cü•>õþgÐýc‰¿çå/¹ÿ‘û‚ßðTÿ(çÁ¿ ð°Õ?ùMLÿ‡«x°Ì›ðÛÿ +ýSÿ”Õø~ßð^0ÁøUðgþüëŸü´¦ø.ÏŽüÒŸƒ?÷ç]ÿå¥Z£%O½˜ž#‰ÿçå/¹ÿ‘û€ÿðUÏGœø7á·õ7ê¿ü¦¨Ûþ +Ïâ„ëàï†ÿøWê¿ü¦¯Äÿ‚êxáúü(ø3ÿ~ußþZToÿÉñ«õøOðkþýk¿ü´¦¨ðÿòTû×ù“õŽ(ÿŸ”¾çþGíóÁ[üL‡Áß ÿð¯ÕùMM?ðW?ù“¾ÿá]ªÿòš¿Ÿþ ‹ã2ä“|ÿ¿zïÿ-)‡þ ƒã"ä“|ÿ¿z÷ÿ-*•þJŸzÿ1}cŠ?çå/º_ä~áø+¿‰üÉß?ð®ÕùMM?ðW߃ÿ"wÃü+µ_þSWáñÿ‚ßxÄÿÍ%ø5ÿ~õïþZSOüçÅçþi/Á¯û÷¯òÒŸ°áßä©÷¯óÄñOüü¥÷KüÜ&ÿ‚Àx‰æNøqÿ…v«ÿÊjaÿ‚Âø…G>øqÿ…v«ÿÊjü??ð[o7üÒOƒ_÷ƽÿËJÿà¶~-$ÿŤø5ÿ|kßü´£ØpïòUû×ù‡Öx§þ~Rû¥þGîÿ‚Ãø„Ÿùþÿá]ªÿòš¤Oø+÷ˆß§ƒ¾á_ªÿòš¿ ‡üÇÅ€ÿÉ#ø5ÿ|kßü´§§üçÅéÓá'Á¯ûã^ÿå¥WÕøwù*}ëüÃëõþcúÏÏÊ_t¿ÈýÈÿ‡¶ø¤ôðoÃ_ü,5_þRÓþ +åâ„ëàφ¿øXj¿ü¥¯Ã¡ÿÎñ¨ÿšMðgþýkßü´¦¿ü+Æ’uøKðgŸúe¯òÒ…C‡’§Þ¿ÌXâùùKî—ù¸ÿÁaêýëüÅõž+ÿŸ”~éò'î1ÿ‚Êx„Ì›ðßÿ +ý[ÿ”´É?à³zü]|ðßÿ +ý[ÿ”µøvàµþ+?óH¾ ÿßÿÿ-i¯ÿ©ñLƒáÁŸûç_ÿå­Wá¯ù÷Wï_æ?¬ñWüü£÷Kÿ‘?p[þ O®)çÁß?ð®Õ¿ùKMoø-f´½|ðãÿ +í[ÿ”µøvßðYß·_ƒÿ¿-ÿ–´Óÿ˜ñ#ù#ÿ¿/òÖ«ð×üû«÷¯óÄqWüü£÷Kÿ‘?qüÇYó'|8ÿ»Vÿå-1¿à¶ÚÂÿÌðãÿ +í[ÿ”µøxಞ"=~üü¼AÿËZcÁd¼C“ÿ{à×åâþZÒú¿ ÿϺ¿zÿ1¬GÿÏÊ_t¿ÈýÅÿ‡Üëô'ü8ÿ»Vÿå-#Ánõuëàÿ‡øWjßü¥¯ÃŸø|ˆ?è|ÿ˃ÿ–´ÿñuø;ðkÿ.þZÑõ~ÿŸu~õþcúÇÿÏÊ_t¿ù÷þ«Пðãÿ +í[ÿ”µ$?ð[}bv|ðß'þ¦í[ÿ”µøhà±:ñÿš;ðoÿ.þZÓ£ÿ‚Çx‚#•ø=ðláAÿËZÿŸu~õþcúÇÏÊ_t¿ÈýÔþ 9â ~ïƒ~ÿáa«ò–œà²Þ"þDφ¿øXjßü¥¯Ã8à´Þ(€|¿~ ~#_?û•§·üÇÅ`É!ø3ÿ|kÿüµ§ì8kþ}Õû×ù‹ëQÿ?)}ÒÿäOÜ“ÿ—ñò&|5ÿÂÃVÿå%7þ5â/ú>ÿác«ò’¿ üËÅgþiÁŸûç_ÿå­'ü>ÃÅôH~ ÿß:ÿÿ-i¬? Ϻ¿zÿ0XŽ(ÿŸ”¾é‘û’ೞ!þDφ¿øXjßü¤¦·üƒÄ ÿ2gÃ_ü,5oþRWá¹ÿ‚×x¨Ÿù$?ïÿ–´ÿ«ñKuøAðgŸöuÿþZÑõ~ÿŸu~õþcúÇÏÊ_sÿ#÷þK¯ÿЙð×ÿ [ÿ””‡þ O¯ù“~ÿáa«ò’¿ ÿáôÞ'ÿ¢?ðgþù×ÿùkHßðZoíÿ’?ðgþù×ÿùkG°áŸù÷Wï_æXâùùKîä~ãIÿ®×£ëàÏ†ßøXjßü¤ª³ÿÁqµ{|îðoÃú›õþRWáûÁh¼Lý~üü¼AÿËZ­7ü;_¸ûÿ> Ÿü(?ùkOêü3ÿ>êýëüÃëQÒ¥/º_ä~á7ü[S_ù“¾ÿá]«ÿò’›ÿÚÔ¿èNøqÿ…v¯ÿÊJü9oø+î´Ý~ üüüCÿËZoü=ãX?óF¾ ~~!ÿå­5‡áŸù÷Wï_æ/¬qGüü¥÷KüÙŸ_ðV›/ÚCáF­àÏø#áüÚ.²#¬2Õã”åIP«aœȦ¢øÿWðÿìÕà”ðÿ‚~|,дÀþd‹‹µ†–æNžd²6Š^FÆXœÀWãWü=ãXÿ¢5ðoþúñÿ-h?ðW}`ÿÍø7ÿ}x‡ÿ–ÕÔªpú¡õT«{;ß—™Zú+Ûš×9Úâ7[ëÔyíkÙÞݯ˱û‘ÿÝÔ±ŸøC¾á]«ÿò’“þ½©Лðãÿ +í_ÿ”•øqÿvÕÿèŒüÿ¾¼CÿËZoü=ßXÝøS?¿ï¯ÿòÚ¹¾¯Âÿóî¯ßó:>³Åóò—Ý/ò?rGüwR'þDï‡øWjÿü¤¥?ð]ÍLù¾ÿá_«ÿò’¿ OüãXSÿ$gà×ýõâþ[Rø+ΰæŒüÿ¾¼CÿËjj‡ ÿϺ¿|Ì>³Åóò—Ý/ò?rOüRó&ü7ÿ¿Wÿå%ðþKþ„߆ÿøWêÿü¤¯ÃcÿxÖüÑŸƒ_÷׈ùmIÿvÕÿèŒüÿ¾¼CÿËj¯«p·üû«÷ÇüÃë6EŠ¡<5z”¹d¬ì¥·Ü/ü»S‡Tø•ð¿O¶:÷BðVÚ„* kIeÕõKÈ‘ý [][Ê=Vd=è®>æêçâV£wâ]ÜëÞ³)º¼¼º`ÒLäl*€ª¨ +ª¡T¢½œ3,\劔ìæÜ­ÚîöüO2K$#…Œ. ”oÞÊ×?ÿÙ +endstream +endobj +871 0 obj +76857 +endobj +872 0 obj +<< +/Type /XObject +/Subtype /Image +/BitsPerComponent 8 +/Width 336 +/Height 498 +/ColorSpace /DeviceRGB /Filter /DCTDecode +/Length 873 0 R +>> +stream +ÿØÿàJFIF``ÿÛC  + + + +    ÿÛC  ÿÀòP"ÿÄ + ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ +%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ + ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ +$4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?èÿ`OØ;Á6_¼1ãïxKDñ‹¼g§G®E»lšž¥ØÝÆ%´Š;IC[³µ³Ã#É"<‹$®ªÊªúÛöpø[søþ |•wÊü<ÑHÈ$ÿ½AqW?eë0d߃MŒgáÇ…ÿôËg]Àñüløãy<5§húŸ|5âyL¶7vñÈ÷¶#·W8x€Øû62}Âc³Œxª¾YõwF‚¯R²œŸ3w|Š-¥£mêôì´¾Åpg +áóUˆxŒC£NŒ¡u+.w$›Õ$´JýÞ¶Zœ_ü3O¨À2|ø'fTþèª bñëÔ’÷5§mû ü1ºéðkà°ÏýSÍÿ‘kñ¼=á Ñh†{Ë¿íi¬N·~l®Û¬±°o\y K² àšöÚŸÆzŸÂ¯ÙëS×4 ¡cª[Þé°Ç7“»V[ûxd]YyÜtã9 ò¸/ÿ¶á‰–' +n/Âù“æMõKkXô¸ë‚#¼3ÃâgQVæø—+\®+dÞ÷¿§©Ç?ìUðß~ ŒÿÕ<Ñù™ÿ [ðàgþ,÷Áü7z/ÿ"× |tý¢|/ðâîŸoâ-[Å–ëá-S^k; {› ¨í®ôø !ckǼ2^Ã1BÛÌ2–×ñËþ +eá?Ù£ÃÚßüâëþ$žétßëºï†l.î­í’šì\I« iãA\‰Ù‰+Ufq𽇌µë¯x¥~ø +;ïí…²4SÙn[‹xã7"öYUh·GjÑ™¨s‚C–&„oÍ¥ï§òîý×Úúo¡œhÕ•¹dõ²Ýîö^¯{omvÔá×ö;ø|ð§¾ ÿá»Ñ?ù¦_Øçá烿ÿðÝè¿ü‹]Ÿìmûnø ößÄqøP}ŸPð«ÛB͵}'U1Çp®aO¦^]ÛaŒR®Ã(‘Lgr(*[Å<ãÿ‰ú'ÀÍKãLÿ5~ÛGñ毥_x;QÑô±¦O¥Áâ+1aµ’ÞÖ´ºXR&丕^D*èD›“YU¥Ï*i-5²Òÿ‰>ʧ+—;ÞÛ½ìß§Cµ—ö;øx½>|÷NôOþE¨öAø~þHÿÁü7Z'ÿ"Ôcþ +Çð·ÄŸõŸ‡Þ¶½ñ‰¬äÔì4ØìõMÛXÔ,!šI­Ôß­ä6óªÍw½»˜¾Yˆ’#'6¿ðU½á?ìwð£â_Å_ê:ÿ4õk„ƒVÐmQH‚ $šÚÚçT8›|q@³ÜÚ¯ÈUÓ¯BqçPV÷u¶žõí­¿ºÇ<6"/•ÊW×K»é¾Ÿ×mζ?Ùáâ ŸƒßÿðÝèŸü‹LŸö\økf>oƒßÎ?êžh¿ü‹Y~2ý¨fƒöƒðî‘¡k¾%¹Ò‡Ä›¿x‚Ö÷L³‘ð”Úª[ÙbóÚæÚL¾g2y‰“Õ=¿ÃOŽ)ñ·Ám®§†5ÿ YM!ÚÒØ»ßÅ€Dè-ngؤ’»%1ʬ¬ÕÑrŒeM^QRµ–ÎÍ_O?ž¶Øæ¬ªÓ_Ä›_§â»œ“þÏ¿ ál7Áï‚ÿøot_þF©`ýŸ¾Jä|ÿÃ}¢ÿò5lëšôI+`Š«§ø‘O½Šôဠ×ð×Ü2xÚÉÛýìfÏ…Òý߃ÿ?ðßh¿ü‹I/ì¹ðÝÆSàÿÁŸü7º/ÿ"×_¢k‘1"º{n×`oJ§‚ ¿åÚû‘+Yý·÷³ÅµÙƒÀSáÁ‘ÿtïDÿäZç5ÙçÁV¹Ùð—àÈÿºu¡ÿò-}#6¥e(çeeêvVwˆpªx­!…Ãõ¥¹‘œ±5úT{>WÕ¾xNÍŽß…F?êœh_ü‰Yñ|3ð«6Ÿƒþ鯅ÿÈ•ô^¹á(fc„\}+|“ˆÇ_JíŽoáGÿ_ärˉ¿ñ%÷³ÉtƒÞ»#wÂoƒþéÎ…ÿÈ•Ö蟳·®€ßð‹àÉÿºu¢ò-z‡†|#uÜ‹Œ×u¦h¶¶±}Õé\µ°Ø^”£÷#¢–'Ö£ûÙãV?²ßùoø?ðdÿÝ<Ñù¯§ì£ðÙ±ÿwàÇþÝÿ‘kØ Í­¹ÆŠÐÓo-' ¼×°Ô?çÚû‘ÕMoç{ |ÿÃ}£ò5{»iÖÓÕ W7®X­»šÃPòí}È¿¬V_mýìó…ý—þ㟃¿ðßèÿüM“ögø?_ƒ¿ð€Ñ¿ùºë‹‘žqYwW-4ƒ¨Ða}È>¹[ùßÞdZ~Ì?îŽÁ‚ßø@hÿüZÖ_² Ç?¾ Ÿû4þF­ÿ À7eù®âÂH ˆtéXTÂÑŽÐ_r6†&«Þoïg˜\~ÇŸ¢Lÿ–ø/œУÿò5b겿Âvù~ ü÷OôþF¯cÔõXBà\æ¥y¤ò*c…£ü‹îEKWùŸÞytŸ³7Â<à|ø-ÿ†ûFÿäjà#ø9ð‹Â_ülÿþ 4i¯Z£¸ð2Û«xE™’0öäF†Idr©…Ý#¶2ÄŸ|’H‹v¯…ÿlßø¯Aý¥|}‡taµþ޲ȣóÿ¿‡OR§Ô×Êñœã…ÁÆ¥%g~šá® f9·Õë´×+~ö«§{ŸAÛü;ø9'_ƒ¿OýÓ­ÿ‘h¾ðÂ5-O±øð[VÕ5ëôÓl-!ð†íšyÝX¢y—E–ÛµC8,숡™•OǺ_Å/ˆlFoßÿbÿâkQwƒxjžiB­Lm*tåuÓåÑ«ÞíYß·Ky£ëí7á×Á˽vÒÜüøË4éð®´>A`?çÖ¾eý£ÿaÿÉûhüá½?Ã8ðÇÃÍ'Ä×-¦²Yë¶ÐéP\ß-Ì ˆŒ¦<ÂeU•åE̬qÌøâÄþ#è)%ûßR· >Í#Í\ÿ¥}7<ísÿ£ye9š_ÙÞVsŒeƒXšú¾ ÇμªÍ·xÆêýô>Å,†Ž]ì!IFÓ•Ÿ*üôG¡~ÌöGø3ÿdãÂÿúe³®ÿöAñ®û>ø¯Ä~$Õô_ëš½äÂa5²ZÇlÇvÇŽKˆËH¶IV_”$ÇËÿgnÓß±oÂÝWP™ Ó´o…^Ô¯%T24pAáûY¥*£–`ˆØÎëüø ÿ’Cñ3ÿ|5ÿËšösþÁæ/ˆÄVös¢›Ž‰üI&ìÓÚÚ ÃÜIŠËaŒÃQ£í!]¥-Z~ëm+¦´wÔæ¾8|Aÿ…¹ã6Ôì¾[èSêPÍs©Å¨£I}SŒ½º¢bRûˆ›-·,:?‹?4ÿÿ µ? j¦«£[êfûn˜Ð‹»Y!™&ãó£’<‡N6R2¤à¿ÄˆÛ#áÄ¿ü ð×ÿ.jýŸÃ‰VßóHþ&àW†ÿùq\¼?ÃyvVñúÏ´u­{¨ÇkíÈ£¿3»ßÌéâ.&ÇfÑÃÓú²§7µœ¥¿.üî[r«-—cÖ¿b} â1[øïÇÞ;Ô@Ô¼:—ºŒºuÄV׳ØÜC§ÙÛšl x¤PIbw»iøöI¸Õ®ü=«\|iø®|iáv»†ÃÅJš +j"Æé!iòDº`³–ÝžÞA’Ý¥F+ÒWÀŸcþ'Ä¿ü +ðßÿ.*÷Ã/‰·\„ßÁÿ¯Ÿ ÿò⾓Ÿ uûÅ¢¶ý.ßâå+½ÝÚz3æmŠþGýY~‹O$qÞ%ý™¼;ã]ÆÖšßˆ¼O©Üü@Ð,<=¬ßÉ%¤WGh³Dp,I3™ÝŸùyÆÔ@1TnÿcÏê1x×Jÿ„ÓÇxǦö}GÂ\Y.—ouv35Õ´ßeûu¼¦m×Grfvpƒ8®½þüRf$|)ø•Ïý<øoÿ—4ôøEñMæ”üHÇý|øoÿ—Tx)ßš¢Õ4úh÷^Ÿ­ŸDLaŠŠ²¦ú?šÙþkѵ³f§Áo j_ +´{›M_â?Œ~!´Ì†E¥Ç5¢ªãj›;`Àõ&@í‘Ôs^]á/ØÃ~Õ"‡PñßÄøBÓÄ—^-´ð†£>œš5¾£=ô·þc{8®gHîfy#Šâyc гF…}|&ø§ÿD«âGþøsÿ—ðâ™?òJ¾#ÿàG‡?ùqWí0¦ê­<ÿUß{꘥UMÛúýVí¦Æ'ÃoÙö×á?‹õ9ôˆ:Oê——·ïàÙÛM›F‚[¶y&ò¤6nE2Èò„[œ€¡0ƒÊ>ž{9´ƒsy¡|9ž[‘+2‰!Í #ΖR¨WÛ›àÿÅCÓá_Äüðçÿ.*½ÇÁ?ŠÓÿÍ,øŒ?íãßü¸¢?QV^ÑiçÙ4½l›ZômlÚm!uÿžžÿåÍmi_°7ÅKnøuñãþšxwÿ—4åœeVÒ²üIYVcÿ>™§âºæÕÛ-q.œcºwìcñ:Ð ü7ø‚qÿM|;ÿËŠé4/Ù{â6šÀÉðËâ cþ›ø{ÿ–õ„³œ¹mUG)Çõ¦Æèò1\¨üªýÕô±ÅÆzWAaðgǶ‘€~|@àÏLJÿùkR\ü#ñü«ð¯âþxÿ–µÊóœ ÄGBÊq‰| óÛýZ}٪Ƈ­Ü,œ“Öº[¯æ' +þ àG‡¿ùmKeð?â-³çþ_Äüð÷ÿ-¨yÆßÄ@²¼eÿ†Í-V‘â'¥C¯Ìïà“ŠÒÓþ|@µ\7¯ˆ$cþ~|?ÿËZ±?ÃïJ˜? þ!ûyð÷ÿ-k›ûWâ#u–âíð3ʵ»é¢”€­E¥K,’Aë]þ©ðwÇ×LJü%ø‡ø\øwÿ–ÕF?ƒ?¡l¯Â/ˆ¿øáÏþ\VŸÚø+²Ì]þ3DfØ­ûušDã5—ðÛâ%¡ùþ|FÿÀŸòÞº+ xêþ|EÿÀ¯ÿòÚ¹gša:MËñ=`ÎWY²¸ÚH Ò¹KïµG)7\W¬ÝøkÆó&ˆ¿øáïþ[V£ðãÇw•øAñðºðçÿ-éC5Âõš²ìGò3ˆ´†y1k“ø‘û/'ÄßÜëv:Í–‹¨jBí5 µk;©!‚;xîc»´–)¼ˆ¡‰¿zÈË Gb°f`ƒáÇ¢aÿâF?ëëßü·­;/xê nøAñÿ¼;ÿËjãÌ+eغ~Ê»Mùd³_o…¼eµÏáýŠõ{(²|]à\äŸ_òú³õ/Ù¾÷L8“Åž +=¸ðïÿ/kêÏ xâh +¯Âˆù#ñõáßþ[Wã‚õ™ ƒáıô¹ð×õÖEx+‡øzOߊûÙôÏŒ¸¢+Ý­/¹‘â û=\Ü’Å^ ?÷ Þÿòöž¿²Ýýã`x£Á£ëà ßþ_W©i~)YM–øCñ8ŒÿÏφ?ùu]vð¯âº¯›ðƒâVG­Ï†ÿ¦°jßpävŠûÙ?ëŸ¿Š´¾åþG…韱}ëÜ«Ïã= +Ö#÷¦Ò<5­üc¹†kZæ(ßÑÚ œ§­OÚwÂöÞý޾)éÚu¤v:^ð³Ä:u•´y)mo‡î¡Š0I$…d’N9¯}·ð?Ž¡L ø‘ÿ^ÿå½yíC¬Øx¯öø§¬é®óiú×­R³‘ÓËw‚}æXË)û­±×#±¯G„Ëðôê,WiÜñó,Ó3ÆÔ¦ó ·f­sÌ|!/ükWBõA¬ÿõŽ¿]kñ÷—›?àœçøP¶úˆÇ_°UǯrøȬ£â«þ ¢¹ {Çÿü'×z‡¢è÷ÿ`Óí¯§žûV’Ïý|—¨ª–òçgbI#ï+Èÿj©õ ŽŸ²Kê–ÖvwÍñWPóaµ¹k˜“þ(Ÿcle²0NP`’9ÆO€{GÑtWÈ´íCâ¯ÁAÂÿi?ôøóJð®›eâíWC›PšÏ͇Ç:”‹w76ò^[LJÞ8!YàòeÔî&/ Ì/çÿà£ÿ¼ãKDðw„~øÿþ_…‰üu¬èךxе jšÕƒ@÷z޵§ÿ`íþÁ¹3¹M_ìrM4n²}ˆ=èßôWÀà©?þ|,×þ)x§ÃõŸÛx¯â7„ôJkË]Vëþ˜|O}ýÅì$QyÐøu­Õ-¤ùæbäl°ý¢ÿjÿ?³d'¡“áÅOŠ^6ñŽ›£Ÿ h†ÆëK·›NÖ¯Þ[ÿZ‰$Œ¦ƒp‘Nu‹q)–|GºÇ˼û>Šøƒöñ–£ûXÁ1<,ÿ<'áøu g⯃¼9âm¦±Õ,.¾ÍñLÓ®#ž(./-“ÎXXËeö›Ÿ³´’[<³4NíŸãÿ‹?ðOÿ|pѾ ø;O›Á¾´ð‘áÏ +höÐG£hž,×õ»½:òx ÖöñH¶÷:ôšrÜZE!¸IšKgÔe¼p»è¯Ï‡ÿ·'Å ?ö ðæ«ñ–ïOøo¢|+ðWÄ=OÇö) W ©ØXEàûèo$ÓtÝ[RM:òÔÛbIq{3Û¬®‘Ä5ø‡íÿûqüXñ/ìÛñOáoÆ?†~Ó¼M…5›Ë]OQÐ,ì.m,õxöD–ÊÞ×ZÕã‚á$ðüЛ“yºH/î"6Ñ&˜õúŠùëà—í5㈴¿<-¨Mðæ}&Ò=B_ ÚXÝN·QØÝ%”²%èi¡¿äÉ ìk ¤úEÌQÁ$7‘Ý[^ÉêßÛ^>ÿ¡kÁÿøRÜÿòuôW!ýµãïú¼ÿ…-Ïÿ Qýµãïú¼ÿ…-Ïÿ P_ErÛ^>ÿ¡kÁÿøRÜÿòÛ^>ÿ¡kÁÿøRÜÿòuôW!ýµãïú¼ÿ…-Ïÿ Qýµãïú¼ÿ…-Ïÿ P_ErÛ^>ÿ¡kÁÿøRÜÿòÛ^>ÿ¡kÁÿøRÜÿòuôW!ýµãïú¼ÿ…-Ïÿ Qýµãïú¼ÿ…-Ïÿ P_ErÛ^>ÿ¡kÁÿøRÜÿòÛ^>ÿ¡kÁÿøRÜÿòuôW!ýµãïú¼ÿ…-Ïÿ Qýµãïú¼ÿ…-Ïÿ P_ErÛ^>ÿ¡kÁÿøRÜÿòÛ^>ÿ¡kÁÿøRÜÿòuôW!ýµãïú¼ÿ…-Ïÿ Qýµãïú¼ÿ…-Ïÿ P_ErÛ^>ÿ¡kÁÿøRÜÿòÛ^>ÿ¡kÁÿøRÜÿòuôW!ýµãïú¼ÿ…-Ïÿ Qýµãïú¼ÿ…-Ïÿ P_ErÛ^>ÿ¡kÁÿøRÜÿòÛ^>ÿ¡kÁÿøRÜÿòuôW!ýµãïú¼ÿ…-Ïÿ U¿‡~2Ô:ý™¯Ç/ Xÿ‚thoŽOÀ[?ýD#¯ØÚ×<ø(‡üŒò…ïÖÿùœ†‹ÿ%óÄ¿ö/é?úS©Ò|kýž¼ûJxVßBøàøÿD´»[ø4ÿhÖÚ­¬7 +Ž‹2Å::,$‘C$aœ1¥Ñä¾x—þÅý'ÿJu:ëëçÏlòûo؋ཟÃ;ßCð‡á|^ Ôm-ì.ôð­Šé—Vð]Í{2[¼¦Ž;»›‹„B¤,ÓË ݘèk²wÂÏ ý¥ðÓáþ¡ÿ +¿Êÿ„7í>³—þ/+Éòÿ³·F~ɳìöû|›|ˆ±‹@¢€9û?„þÓ¿³~ÏáŸÁýªÝë¶^ +ý‡Q»ûOÚ¯bÂü—}²óÌ•pïö¹÷æ>xýö"ø/áσZ·Ã?áÂû‡ºýÚßê~·ð­ŒZ6£p¦"³Mh±d !Ù ùù¡Eqþ&ýž¼ãOƒQü9Ö|àý[áì6–Öøb÷F¶ŸFK{c·„Z:Dq¢(›0†4ÚуÃ?³×€|ðjO‡:7ü¤ü=šÒæÂO YhÖÐhÏord7›DA ŽS,¥ÓfÈûÜsØQ@¿g¯ü0ð¯†ô/ xÁþÑ<w5ÿ‡ôý3F¶´µÐ®&K„–kX£@Héwt¬ñ…,.f‘#gðüÛàÃýQÓ´ÿôM?XÏÛíl<§[C{›[«3æ¢BæÖúö¸Ý^\'Ý•Ã{Ïøwá?…|!ã¿ø§Iðχô¿øÃìßÛÚ½¦ úßÙ£1[}ªuQ$þTd¤~amŠH\+ ¢Š(¢Š(¢¾iðßÇ/ŽŸüoãÛèÿ ÿ±|â{¯¬šÕî¡ou3D‘J¬QȸÙ2 äd†ù@Å}-Ex/ÛÿjúüÿÁ¶­ÿÈô}¿ö ÿ OÀOüjßü@õEx/ÛÿjúüÿÁ¶­ÿÈô}¿ö ÿ OÀOüjßü@õEx/ÛÿjúüÿÁ¶­ÿÈô}¿ö ÿ OÀOüjßü@õEx/ÛÿjúüÿÁ¶­ÿÈô}¿ö ÿ OÀOüjßü@õEx/ÛÿjúüÿÁ¶­ÿÈô}¿ö ÿ OÀOüjßü@õEx/ÛÿjúüÿÁ¶­ÿÈô}¿ö ÿ OÀOüjßü@õEx/ÛÿjúüÿÁ¶­ÿÈô}¿ö ÿ OÀOüjßü@õEx/ÛÿjúüÿÁ¶­ÿÈô}¿ö ÿ OÀOüjßü@õEx/ÛÿjúüÿÁ¶­ÿÈõ£¯~Óúm©”èß$ù•¦­ªîbÌmÀêGzúŠù¿þ¯Ú{þ…ÿø<¿ÿãuãÿÚGãçÂ5Ðî|M£|¶Óµ­rÃCW°¿¿¼¸Y.§Xƒ,{QNÐÌçs¨!ÎHêúä>Èéñ þÆ¿ôÕ§×_\‡ÃOù>!ØÁþš´úëëò‡Ç“nÿ‚ekÃ?óAïõ’¿W«ò'Æ:¨“þ ·®Gž¿¯õ×»’«Æ·øÌñóWiRÿù^½Uÿ‚sèjOO€¶úˆG_±uøÉá­6å¿àž,[gü(K<qÿ"|cù×ìÝVvÓ… /ù”¦¥VÿÌr/ü—ÏÿØ¿¤ÿéN§^}ûWø³UðçÇŸÙ’ÏOÔõ MâU冧½ÃÅ£n¾ñ-ÂÃ2©HÄðA(FÈ mȤz‹ÿ%óÄ¿ö/é?úS©Öwí û1xCö Ñô/Ãâø¥õ_í½&ïDñ&¥áûý>óì·†Xî´ùàsows]ûYe`AãíAñÇöʼøUûdÝü7ðǃ¿á"ñï‰ô¯ Úè‡VñmÖ¡\Ët¾-½d ‘eåZøzõÄÓKs$öÈ8VXøÿðUoüø…§xBo€þ0×|W¥ø~ßÄž.Òô(5}~Kkyïoí!M*M/K»†æIΙw$#S“I’Zoh]®’Ï×î?à +¯4çŽãOñ…Þ¤m,¬£×® ñ·…­5; z ý_W½ðÊk·S͉Ž8ÒÎk=ð,’ܤËwˆ~ÎÖûoŸ ø÷û}üKý–~éÏ㟃Zyñ—Š|Ao øf×ÂÞ Ô¼M£jo%•ýô¢Y-4vÕ£’4Ë–u‹I3=¡”k§³õýOö/ø_¯xWNеiú¦‰¦xƒZñD:}ü’ÝÚɬ&¦š›ËŽÉ4w ¬êJÐÊ.ˆTP‘íçí¿à + ð­î›&Ÿã Û»Û»{ßøH/¼s®Þx¢ÍàI£„[krÞ6¥kGux‹(/ïWnÛ» ~×ü}ûBÿÁ/tŸø>ëÆ¾!x·Æ¾Ð-oot«˜ï|?q/ŒôÝ2Kiy´×rò$wPÛ›«YM ^kĹÿ +?o«Í[ãgÆïkŸñOêþ øUà‘ªxTÖ.¥‡Ã^-¹ÔŸƒö\ð%¿Â-#À‹¡gÃ&«c®ÛÛµíÃM&£g©EªÅ{=Á“θ¸køRæYfw{‰L1”É&ìÿþÅÿ ü_â¯k·žÓÓ[øŸi¥Zø›P´’[;­Héo+é·>l.¯å«ÊZ¸Š\Fb·+(6ðy`([ÿÁmõ‰t}Fáþ}ši^(ñÄ(/µ}SH›JÓ´]úá´Ë}CH¶»½¸–ÏÄ6ÍW°iÈÒÃ*‰L-Ëôÿà®^%øcâ1à6øIý«ñwNÕu gJÒnõÝsBµŠÎÇD¾y »Òô;ÍB]Ðø‹J˦A]£J<»suì/üÿணøªÊOøƒXÿ„ãJÖtMzï[ñ޵¬_ê–z½®™i¨E%ÕÝܳŸ2ßGÓc 4Kj¢3çÝ¿ñ öøgñ+ÄzÆ·y¥øƒJñ½ª¶³}¬ø{ÅZ·‡õYgk ]ØÜÃ:[Éo¦iÂKdqeK¸ì>üGÕ~/|=°ñ>¡áCšý¥ž¥¦iš©xµ›kyì­æhµVEäSÉ'ø‹_ðÑ·Ö5ëèzŒºw™uý›sž²ˆ¤ +^8¦šÂ6dÈ}š …¨àÏŒŸõ_ž$ý˜î¼Ku¨]øËÃ7cÃ^ ›SÒŸEÔï®,þ*|1Š-FëL’(¥ÓdÔm>Ë©-œ‘©†F7¦Ùï‡?ò”ߌŸöJ¼ÿ§× ê¿þë¾*—]¾ð‡ou¹îÒþ]B ¤—R\#Ø:Le12+éZ[' é¶dÛÅ·Ÿø×û!üý¥¹¦\Ûišý¹ñ—‹tÿšî+¨ÓI§‡¦¸»Ô$†ø<ÚŒ“}™D&9¸ÿŒðUߎÞÑþ,øÚËá·‡íþøoþíÃwš¹Óíá“QðÕ®´É0¸Ù¾Ô¼ùô9wØÇ¤ÚeÅ»G Hb²‰PÏÞ(ý³~4x[ö‡Óþ j ð¾ÃâŒîôk3^·Ó/¯ôo [ê)¾k)­Zê µI žv³X Ž£¿eƒìí üÇŸø(ÿÇoxÇRÑ<á‡þ?ÿ…WáAâk:5æž4-C¦µ`Ð=Þ£­iÿØ;°nLîSWû“M¬Ÿb{öÄŸƒ~2éÚÝŸŒ<áßÚx–ÒÒÃWƒXðÊ_GªÛÚO%Ť7 ,L%Ž æ–XÑò#y]”bN~·û7ü$ñ7ü ¿Ú_ <¨¯ò¿á ûO„b—þ/+Éòÿ³·B~ɳìöû|›|ˆ±‹€;àí/⯈Ÿµ?|)­Ýü?ÿ„~ÛíÒxv 2Yžòx,o#²šh®÷¼ŽÛ†–Ø„vsé7QGo$Wq]Û^ÉïõÈøwÀþð‡ŽüGâ'ÂÚn—â}›û{W´Ð|‹ýoìј­¾Õ:Æ$ŸÊŒ”Ì-±I ÅtðÛÿÏ;ïü›ÿ‰  ÔUøHmÿç÷þMÿÄÑÿ ¿üó¾ÿÀ)¿øš½EQÿ„†ßþyßàßüMðÛÿÏ;ïü›ÿ‰  ÔUøHmÿç÷þMÿÄÑÿ ¿üó¾ÿÀ)¿øš½EQÿ„†ßþyßàßüMðÛÿÏ;ïü›ÿ‰  ÕGÄ?ñáý|Ûÿèä£þùç}ÿ€Sñ5Ï|Uñµî…à;ÛÝúωõ[VŠ[m.Ú1m%ã PíM²4d’ÍÀŽ€|_ÿYÿ‚üWÿ‚séþ×|%û;_ülð†¿u‘=îâI-µ /Sžq µ¼–Ic;4s»ÅR£Ó?”ÊŒðùÝ'ÇŸx¿Æß³—ÁÝ_ÇÞ°ð'‹õ/ø~ãRðõž´5˜ô‡k̬íb‰e‘Snò‰°>õG‘BÈý¯ü/¿‹ÿônþ*ÿ‹Mÿã•Ç|_Ÿâ×Çé<¦\|ñ‡-t¯iZÍÅôÚÅ…ÊG ½Ê¼™D“qù7”òãÐÚõÈ|4ÿ‘ÓâýŒé«O®¾¹†Ÿò:|Bÿ±‚/ý5iô××㿬‰¿àžšÜyäü¼=êO×ìå~-kžº‹þ í¬Üpƒàà'þäéó¯{%v…oðÿ™ãfѼé‹ü}øyà{)ÿà”>¹e_1¾YŽŸõ,"ÿ*ý(¯Í/‡ZŒ£þ QáôÉÚ>Yÿê.†¿Kk0›”iß±ÓŠNvîr/ü—ÏÿØ¿¤ÿéN§]}r/ü—ÏÿØ¿¤ÿéN§]}y§ QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEÈ|4ÿ‘ÓâýŒé«O®¾¹†Ÿò:|Bÿ±‚/ý5iô××çWć¶ßðIÞ¬k½~^.qÿR˯ò¯ÑZø[âbÆœ¼Jê†]ÿê8õêeÒj5-Øó±ñNTýN?áÖ‚¯ÿ›ðä½Ûà]˜?øL ¯Ñšüôøo‡þ á¦Çü(»?ýF’¿Bêqñ´iúƒÞ~§!¢ÿÉ|ñ/ý‹úOþ”êuâÏÅ- àwÂÏx×Å7ßÙ~ð~•u­ê÷¾L“ý’ÎÚšy|¸Õ¤}±£6ÔVcŒNPÑä¾x—þÅý'ÿJu:ñÿÛçDñ÷ÄÏ|)ð|'§øž+k°ëÚ΋ ]ÛèÏ ¶v’êvö—rÛ^k\iwÐD°ââ="ñÄ{ã“Í;£ëŸÿ…¥¡Kâ?ì›[ïí-B-Wûî-:/¿²¯>Ãöñé…XYæÔÇ kƒ·Ú-ÔÓ¯ð„<9ã…ÞøðãâÎñƒÃÿ +þÂE᫘~Éâ{¤‰4‹¿ +[ÙÞèÁ¬ßéözÕþŸ%Ô°¤^iòý£|ëm#óÿþþÐ_üSãý[á½Æ OŠž9ñ\ZÝœºœÐÉm{| ¿°ÓåÔ³¥Àñ%ˆŽáT,^|Z{H<†ÓÙ€?Oè¯Î ;À1ø¥û@x+@øo­þÓþýŸµ?é‘êךÝç‰ìµ³8ðÿŒ[W†KtV >P<3”‚;‰Uìå†ù^TúƒöþØ·ð–¹câ¯øXÄú&«¬hÐ7ˆµ4?k¶º¤·?¹¸¸kbi.C=ÝÄFÎk™%[ÈÀÿEPEPEPEP_%ü"øE¯þÑÞ>øµ}}ñkâLJ¡ð÷Žï´[X†XmÒi”– Ó¸á€(b¾´¯‰n~)k¿þ~Ñ:ï‡ï¿±gOŒðXê:ד¿ði7WZ-®§«~õZþÃa5Õß›poټɑâI€z…Ïì ŸŠ¬´)¿hqkz¥Åý¦žþ&°[««xžhâ6»Ú8ÞæÝ]À!LñAu·ü0Íÿý_ø>³ÿäJù«ÃW×íûh|#´ðí'¨x·F‡Á^>‚/ˆÚg‡4©õ;û%¾ðL­Ø·þƺ‘.ßËkÈ,d…aŽk3½†[´óûoø+GÄOx«öuñ2ø¯Áþ»ñµ§Ã»=sÀz¿ˆì4Öñ[øôÃy©hº<ºlú•õœ1êÏ\¦±Gq¥\«Á2ÚL.€>Õÿ†¿ÿ¢ëñïÿÖü‰Gü0Íÿý_ø>³ÿäJøëÁ?¶ŸÇo~ÌÿüEâ_‰ßð‘ÞütøU¦øÏÄz»xsO°¶øjº·„l¯µK5HŠGäiž Ô/®¦¿76«=‚N°ÛZ,¶gñWü/âKkzþ‰àïÚoÁúçÂÝ;ƺ®ŸkñwÄž.ðdžíg6ú„î­´…Õ¢Ð/´™d’}[[q±[‰œÅnm&ŽPµ~"þÎZ'Áý5þÓü-§ËçìºÕü_¦ØÂþE¬÷“aå¶P|»[k™ßŸ–+y\áQˆè?á†oÿèºü{ÿÁõŸÿ"WÍ_ðTߎþ>ðì%ðât·Z~‹ñKE´×|P÷6U͵­†³ÂïÜ—ŠÏQˆ\G\.VÈ„ŠYP0e­ oöÓñÞ•ÿ wTÐþ'oümðÇü&é¦üÿ„rßUò­t¿í1¡Ýý–Î(õ‹O¶Åi¥\}ªîæK[Ÿí?*Ñï¬ Bÿà ßÿÑuø÷ÿƒë?þD£þfÿþ‹¯Ç¿üYÿò%|uð3ö©øíñWžð†“ûA|?ñ.㈺ž/ð¶£§øòkhÃ>(¾¾²öú“¥-ÄgMÓ¦‚%‚yí¥q-ØžÖâ Y: þÜÞ/Ö|O{¤øëã¿ü*øD?µ4¿ݶ…¦ÝÍñwVÓ¼Wâ=[Yì^ÜϪ\-¾£I-–„l®]fEÊûMšÀõ/ü0Íÿý_ø>³ÿäJÏÑ¿dh|G¨êÖzíñ®þï@»[ N XK&pÐEp°Ì«jLr'‚P‚RhÛ]Ið¯Ù§ö¸øËñ þ +9©xk^ñ·Ãø´…ñ_ˆô{ÿ‡Ûks®èÚ-“ßG¦êŸØðh«y§ý¥m´ÙþÛ«Ëe4zî¢G½±Š Ÿ?~8ÿÁN5êÖÝÜØI=—‰¬'.-§’ÞâÉj@’)â–'N¨ñº° ¤:ñ_í¡âoÁ?¿foˆúß‹ôÿ„oÆ+MÿÇÞ5°ŽÒ _[ÝøvïRE.¤—vÑË©Åcb¯x“/„J|ù"‘~Pø/ûexáOìëâßøFþ7y_ØŸðšx«á_Ë¡Íÿ â|qâýÚo6§ûCÌû&ûì“ÄïåaçÚy@ ŸðÃ7ÿô]~=ÿàúÏÿ‘+?Yý‘¡ð棤Ùê´GÆ» ½~í¬4È.7þÙ^#ÿ†Š´ÿ…Iñ»þËþ¯‘⯠üº³ÿ Þø¡»Mÿ‰­§æÿgi߸9›÷Ÿ+/˜(ôþfÿþ‹¯Ç¿üYÿò%ðÃ7ÿô]~=ÿàúÏÿ‘+Î¿à”Ÿ|wñ£þØ|MñGáÿÅïé?Ùï¥ë¾ñ=¿Š¼‹©~Ô.­&Ô¬4M#N;+IÖ8eº‡Ïy'“ʹ´Qõýx/ü0Íÿý_ø>³ÿäJ©­~Äš•Žø~;|w4±Æ ë–Œ£tйÀ´ëë_BÕÿÇ„õóoÿ£’€>nÿ†DÕÿè¾|tÿÁ•§ÿ®ãßÃOü±ð–¥kñ“ãºÚ¿‹4[[ý^íÚ‹¤Yw¢YcÜ£k)Ï<ßügàÇíuãm?Ã:ßì¥ñ~ÃÁúœ7Piºß†õ#KŸO¹·–p§RŽæâÒi£’奋,$†<Ä¢dòîzO>ñ'ÃÙËàî‰ãßüFñNŸãŸ¦©âKÍ:×M“V¸7›žAmj‰ 1‚v¤j TT ò8iíºä>Èéñ þÆ¿ôÕ§×_\‡ÃOù>!ØÁþš´úëëá‰s)ÿ‚6ø—žáEÞê8õ÷E|ñ%ÿ‡9øŒ“Çü(›¿ýFÞ½,¿á©èpã½R_†!ÿ‚–?øÿün´j_óécÿoÿÆêõGí—üúXÿà[ÿñº>ѩϥþ¿ÿ«ÔP´j_óécÿoÿÆèûF¥ÿ>–?øÿün¯Q@~ѩϥþ¿ÿ£í—üúXÿà[ÿñº½E`ø³Aºñ§…u=ò†ÓV´–Êy,5«› ¤I£® Tš 'l‘:º2²°qÿÿf­öuþԓÚv¥u¨k~Rßjž!ñ~©â=Vâ(w˜mÍî¢óÜýž&–wŽ'•ÜNêŠÓHÍéÔP´j_óécÿoÿÆèûF¥ÿ>–?øÿün¯Q@~ѩϥþ¿ÿ¬‰º?‹hÿ†lý ?èµøWÿ”ÿãõ•â?اâßÄMC@_|Wðæ±¥èzÝ–·öX|+öG–Ki–UQ"ÎvçrC»8$ +ú²Š+øiÿ#§Ä/û"ÿÓVŸ]}r ?ätø…ÿc_újÓ误‡>&"ø#‰HÆáE]ÿê8õ÷|ñíäÿ‚0xˆóÏÀk³ÿ–ÓšíÂJÊ^‡&&7qáSù¿ðF?¿óAìÏþ[I_|WÁ? ¯l¡ÿ‚2ønßíP “ðÑ|­ã~áNßJûÚ£Ÿ,nU¯+†‹ÿ%óÄ¿ö/é?úS©×_\†‹ÿ%óÄ¿ö/é?úS©×ÿÁHk-WöPðÿÂÙ4ÿü/øki㯟 ê~)ñý›ÝhÚ-¸Ñ5mA]•o¬G™$ö@¥®fsò³ÊtŸGÑ^¥þ×Þø=ðkJÕ~$üIðˆ®æðV±ñOxWB»ƒFÔ¼?§i.5 h’{ãåÇýâWœÈ^%+•M ÿo_„ö;Õôïÿdÿb}¹nu­OL¼°ðÛËc²ß[ìÍiÓÜ[%½ÓO7,"ÊóÌEû,þX°Q^?ðûöîøgñ+Äz>‰gªxƒJñ½ª®c£x‡Âº·‡õYgkëøÜÚ_[C:[Éo¦j&;—Aeݧ›xf’b®×-p±Kog1p§è¯½ÿ‚£ü Ñü9©kz¯ŽáðþöIWYÖô]CJÒµK[›ëk¯ì.î`Ž ý?í¶aï­[X’òÞI%H¦ÚýÏüoàöŸá[-^÷Äú†™ÍÝÅ­Õž¡áÝNÏSÐEºC%ÍΩc-ºÝivpEui4·wÑAo7¶’¼«Ì/ ¸WËß¶íŸqð‡Qñ|x¿Â ¼ðÛB‹\ñ¿õ»w¼:žÿèvÖö/Ú¦¸ØÈ¨…‹¨ó|¸åúGÃ>&¶ñf%Õ¬z„QEwsdË{a=”…àžH„™Ú2ñ±I)*’6xݼ“ãgì/à¯úÄ|[¥Xø—¿4+]ľ¿BmuO³»´>h̰Íaå< +:ù™2Þ0?a?Ž—íð¢ÃÅiã¯üNðG‰,aÔ<-â½ +Ö[)µxËH.VæÕ²¶ÒA&ÈL[·«FâEI‘t¿moÛBý‰¾iþ(×aûTº¬v†-ò'—g 3_ê·™Hä'ìZE–§}åctÿaò#&i¢Vé?g_Ùן²ïÂøÀþÒ¼)á +X?HÒ4õc”{‹ÈÍ#óI#þñå“.îÎìÌîÌÞyñÓöIñÇÚŸKñ­ŸÄ¯|3ÓüáItM÷Âqi³ê·rê7‰6­ìz…å·Ùöéš+[´*’‡ÉVŒPÿÛãöøðüóà‰<_âÿx>Ç[±ðþ©¬xwúLj­´‹¯\Y[yßb´óròHîÐÇû¸ä*gå%€'Ä¿ÛãÀ>ýª¾üÓüIàý⌼A.©ø~ßÄVßÛ>·M PÕÖök%Ý7–ÂÎÆáÅìo¸üªÿ0xËþ ¡ñ£Á²ÿŽ~ø!~øŠ/|_ÐÏ®xŽûHmFÓ%×­ô]Aš:ëí×’éúÄî0–‘¥ÅœžS4s¨‡Ô<ûüSð—Ço‡Ù~Ü|2øñWÅ_·ÿá ¼MvÿûnßÄöì¿°#ò.³ÿäJ?á†oÿèºü{ÿÁõŸÿ"P½Q^ ÿ 3ÿE×ãßþ¬ÿùøa›ÿú.¿ÿð}gÿÈ”ïTW‚ÿà ßÿÑuø÷ÿƒë?þD£þfÿþ‹¯Ç¿üYÿò%{Õà¿ðÃ7ÿô]~=ÿàúÏÿ‘(ÿ†¿ÿ¢ëñïÿÖü‰@õEx/ü0Íÿý_ø>³ÿäJ?á†oÿèºü{ÿÁõŸÿ"P½Q^ ÿ 3ÿE×ãßþ¬ÿùªk_±&§ec¾ŽßÄ,q‚úå£(Ý"®p-zúÐдWÌðÈš¿ýÏŽŸø2´ÿã5Áü{øi‶>Ô­~2|b×[Wñf“£Kk«Ã»Cqt‹.ãK!Ì{”me °9ãíºä>Èéñ þÆ¿ôÕ§×_\‡ÃOù>!ØÁþš´úëëàÈÑÿÁ§¥I–ðÞYÉþ¯Sw³ 4K•`Mv:/ü—ÏÿØ¿¤ÿéN§]}xçª|ÁûJþÀÞ*ý°¼ à‹|BðûøŸá÷ÛüA¡ßèžšÆÃNñzIмC¬·óHßÙ±ý©M”óËov×lÒÆ‹çú§üÁ>#ñßÄY/¿á_Ûxâü%RÜêºgÃÍ>ˆ&_G~—É7ˆ¦i·ÛÇý§t Hm •8¤šh£.¾ß¢€>pñOìŸñsâ4×üGñwÁ÷_¼ âõï +Icàm|/§¿öv£¦ÌntöÔ¤½¹’[mVì3.¥+ÁdÉùwïÏüÿ‹¹ð ”È~)êíÞ±â /^×u WAƒíZ£éŸ.üefT[É 0ÈÇRÔmnb)!’Úh¢¶X^޳蠌4?ø$檺'Ã}Wø“§ÞèŸm4=ÀQÙø]ín Ñ´íÃڳêJײ%íä©á­>soœq™nd6òŽ(»‰ßðOmwÅÿ|Uâ â_ü#sø«â·ò<;ÍΈÑhzF‘æXÏç$‘j —(IÜÉfðj—–×z}ô/Šú~ŠÏðͶ«k§HºÍîŸvnî^9l¬žÒ5·iäkxÊ<²“"@bG“p:<Š‘+ˆ“âßÇüðáÕ¼aâ3@±þº— /̈v Ë> ¦vƒÀœ +ê«À|5áXµø(§ŠµOé±Ý^iÓÿá +»’Ü:Ù[Ènÿc¨Ú’¼óH” ”G˜üÚõO„Ÿ|#ñãÃVðˆtÍ~ÇøžÖ\´_3 Þ‡ ™(øÜv’2+ª®{Ið®¤|EÕuM7MÓ-u]^¿¶nà·D¸½hÀ[o9ÀÜåÈ$áH W€þß?³×ü/ïŠbÿ„oàÿÅŸìÍ+ZøV?õO±éZ¦ù´Áý½ýŠÿ}ÆŸ·ìª~Èv¦»/ïâÝåÜ}?E~xxÿþ +qñNð¯„.¾|;ÔŸ¨ÂiâÛÏ"¬ÙXá‰"?!ÜvÀž.Td.æôê*Ú5/ùô±ÿÀ·ÿãt}£RÿŸKü þ7@¨ª?hÔ¿çÒÇÿßÿÑöKþ},ð-ÿøÝ^¢¨ý£RÿŸKü þ7GÚ5/ùô±ÿÀ·ÿãtzŠ£öKþ},ð-ÿøÝhÔ¿çÒÇÿßÿÐê*Ú5/ùô±ÿÀ·ÿãt}£RÿŸKü þ7@¨ª?hÔ¿çÒÇÿßÿÑöKþ},ð-ÿøÝ^¢¨ý£RÿŸKü þ7GÚ5/ùô±ÿÀ·ÿãtzŠ£öKþ},ð-ÿøÝhÔ¿çÒÇÿßÿÐê£âøðþ¾mÿôrQöKþ},ð-ÿøÝ`üMÑüYâßXøz÷FÐ5©¶]Fæ7¿ŽÑ–EmÆÝï8p À ÁV~ ~×^6Óü3­þÊ_ì<©Ãu›­øoYÒ4¹ôû›yg +u(în-&š9 ZX²ÂHcÌJ&O.ç¤øóà|7ýœ¾èž0ñ­ÿÄoéþ9ðújž$¼Ó­tÙ5kƒy¹äÖ¨Ã'jF •E@Ï#†‘½þ³ö€ÿ¢×á_ü"SÿÖWˆÿbŸ‹5 |Uñ_ÚƗ¡ëvZßÙað¯ÙY-¦YUD‹9ÛœÉ ìà(êÊä>Èéñ þÆ¿ôÕ§×_\‡ÃOù>!ØÁþš´úëëóSâãþ ƒâQÿT>÷ÿQ‰+ô®¿6~!Ù‘ÿ½ñ+ú|½ÿÔfJöò†·øYãæ¿/ñ"ŸÃˆ”ÿÁ6|0p3ÿ +JÇÿQˆëôÊ¿4~/ükWÂçþ¨•—þ£1×éuVuðÐÿ +'(ø«‰œ†‹ÿ%óÄ¿ö/é?úS©×_\†‹ÿ%óÄ¿ö/é?úS©×_^íQ@Q@Q@2æÖ+Ø)£ŽXÛª:†Sß¡§Ñ@ ¶µŠÊŠãŠ5舡Twè+’ø×û=xö”ð­¾…ñÀþñþ‰iv·ðiþ$Ñ­µ[XneŠttYI"‡ HÃ8c]…ÇüGýž¼ñÅ^×|_àø«[ðMßÛü;¨k5µõÖq¾'ó­%•íäß -¾2§1Fs•è4o é^ÔukÍ?LÓì.õûµ¿Ôç··H¤Ôn­Öi™@2H ‚ƒ¶HHc\íEBŠ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š+øiÿ#§Ä/û"ÿÓVŸ]}r ?ätø…ÿc_újÓ误ίˆÑøuw‰ýQ ßýF¤¯ÑZüíøÿ(¬ñ7ý‘ ßýF¤¯w%øk…ž6oñQÿ1~ŒÿÁ4|1ÿdJËÿQ˜ëô²¿5~øÖ‡†ýQ+/ýFc¯Òªy×ÃGü(2Š·ø™Èh¿ò_&½ŒÁ5¯‡ÖÑa°A®]¥ß—g§-´sL,n$N[¾ÿ‚âüÑ>;x»Àú§ˆ³¿á þÜŽ÷Tû~w¾}ÞêçT‡û2Úê]b"+óæÜXE¿eýÔ²}¢×í_Ñ^áÛn;¯xGÃ^+øcñCá׈¼kâì 6Ë^¶Ó¦‰Òµ=Mn ÝåÍ£FcÒ/#1Ç3ÜFþA’âž)_Èþ +?hxr #ÆOü7wá2-sMµÓêk7?µo \YÜ-Äò³ºŸLFW†1-Eë™!¸kTgÑ_(_ÿÁ_ü x/Mñ.¯àߊo‡|Ui§jþ ½M&ÛR“Ç:M鉩XZY\Ov#I5­.F·º† ÆKÅ[K*Kt?jŸ|Eý‘þ&øŸá÷‡|aáÿ‰îÖãVðMí…¥þ³uqcž°ú6²]Û4šž›,0¤ö²\F¦ŒÜBШÑôWÌÿà¨ð‡ü-øFSÃþ9ÿ„3áþŸã fxŽ?á>Ôo<ï+E²òÒM× çh|¯9ßþm3¤[ùç‰à ý޾)ü%ø%ñWÄÿð‘x÷ÄúVa7Š¾Ù¡ißÛzÔÇOŽoìe¾šýªö>¶¶S[Cçå¥Háâú~ŠùÃ_ðYø‹Àš‰á¿Æ "_‡úoÅmVâm3O’ øVöMD&©y,W¯Ùœ÷Ò–öH§O&ÚgŠê;sNÿ‚³x'ÂÞ6Ó&Ðþ0xž‡¿ÚúÿŠuÉ4müPñ&•¯øƒZðŽ…â;Ñ"Ó5ÍoI´Ôç¼Ó¢KF+¸ähú…²Ëqo»M"_%Òfú>€ +ð[öþÐ,¼aâ ÇÀßüq…®$XÄ—> +¸·… 8ËÉ!TFyg`ª2I^ëT|Oÿ"Ö£ÿ^Òè€/W!ðÓþGOˆ_ö0Eÿ¦­>ºúä>Èéñ þÆ¿ôÕ§Ð__¿ÿåž&ÿ²!{ÿ¨Ô•ú%_ŸŽà•~%ÿ²!{ÿ¨Ô•îä¿ oð3ÆÍþ*?âFWÃuÇü/Ãþ¨•—þ£1×éE~m|7ÿ‚cøcþÈ•—þ£1×é-×ÃCü(YGÅ[üLä4_ù/ž%ÿ±IÿÒN¹ïÚwöbö”ƒÁsCãOx[ðˆ‰4}cÃk§Iu Ãi×Ús£%ý¥Õ»ÆÖú…À ÅJÀ­t:/ü—ÏÿØ¿¤ÿéN§]}xG´xÅø'¾ñÿÀš‘ãÿ|@ñŽ¡á½+V³Óu»Ó¥Ûߨê7²Böúô meµ¾±§,%,o †7·YçáÚVb_Á:ü+­ÿÂ]¢êž*ø¨ü2ñŸöä—¿´á´Ð’}kíGT›Î¶†-Fo=ï¯äò®/%‚).·ÅmojmýþŠð Cö —ÄZ=¬úçÆ_Œ÷´mV_@ñ…ÜÚ:ßønXío,ñkcžšIßm¨êHóXK,‹v7HMµ¡·çüÿ™øqðïK†ËI×> Gö­–¯z÷šÊê7:¼¶>/—Ŷæâê9f“ì÷÷WчÞ%š ù„òO2Áî}=!ðV™§kV­—jÐÚG-ż“hzTrI~÷W&+@ty&’OoøiðSJøWãOˆZîŸq¨Mwñ+Äx“SK‡FŽ ˆô­?KT„*©Xü6!‹ï!Ý´ª¯aExƒÿàš? <ÿwØ4Ÿð„ø®÷ÅVyµ³ióóö}6m° Ú}•¤ý’·ìÿðŽè˜cö°|Wÿ‚{èÿ~)Üø†/|@ðΑ¬ø¯Cñ¶¿á(ém¥xXÒ&Óä´º¸{›)¯#ùt:'ŽÖæÙ-ØI^O¢€>pÑà—þоx›áÌ:¿ŒDñWÁý'à¥Üïuln£Ñ´ÛmNÞ ˆØ@^2j·Ü¡Œ”‹( ‡þ à<ñ¯B¿Œ §Çê~×ÜÝ[y–v÷ú¯ˆuIžÔùIߪ™€$VÀ«2ÈÒ}E|A¦ÿÁ>~,kµžª|Yÿ +ãáO„üWâ?øMÑÇþü'øQÿÆ›ÿ@ûûðŸá@¨ª?ðŒi¿ô±ÿ¿ þÂ1¦ÿÐ>Çþü'øPê*ü#oýìïÂ…ðŒi¿ô±ÿ¿ þzŠ£ÿÆ›ÿ@ûûðŸáGü#oýìïÂ…^¢¨ÿÂ1¦ÿÐ>Çþü'øQÿÆ›ÿ@ûûðŸá@¨ª?ðŒi¿ô±ÿ¿ þÂ1¦ÿÐ>Çþü'øPê*ü#oýìïÂ…ðŒi¿ô±ÿ¿ þzŠ£ÿÆ›ÿ@ûûðŸáGü#oýìïÂ…^¢¨ÿÂ1¦ÿÐ>Çþü'øQÿÆ›ÿ@ûûðŸá@ª‰ÿäZÔëÚOýÑÿÆ›ÿ@ûûðŸáGü#oýìïÂ…^®Cá§üŽŸ¿ì`‹ÿMZ}uõÈ|4ÿ‘ÓâýŒé«O ¾¿;>"ŸøÕ_‰ìˆ^ÿê5%~‰×çWÄSø%w‰ìˆ^ÿê5%{¹/Ã[ü ñsŠø‘Oá¼xÿ‚`ø]¿êˆÙê5~×ç/ÃdÝÿ¸ðÁôø#eÿ¨Ôuú5FuðÐÿ + Ÿâ­þ&r/ü—ÏÿØ¿¤ÿéN§]}r/ü—ÏÿØ¿¤ÿéN§]}xG´QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEÈ|4ÿ‘ÓâýŒé«O®¾¹†Ÿò:|Bÿ±‚/ý5iô××ç_ÄùE‡‰¿ìˆ^ÿê5%~ŠWç_ÄùE‡‰¿ìˆ^ÿê5%{¹/Ã[ü ñsŠø‘ÃQÿ¶ðÇý‘ /ýF£¯Ñšüèøh3ÿ³ðÏý‘ /ýF£¯Ñz3¯†øP²Š·ø™Èh¿ò_ßðK_ˆÿ´oÀŸø#âŒü?áo ]ø¯ân«á=;NðÓMªé²ø†ãĶ6÷··¿Ú2Cynl5éîE´vö²«½º¼Êa•eú>oø(ßÁë];Åw—'Ô-m<iâ›ýV{êpƶþžÞß\š{p.cµžê‹Áæ ÌXŒ¡(~Òÿ>)ÿÃSü9øgðÏ^øáøJ<)â?êZ—‰ü-yâùÞhVÑA VúŽÍÿÚÒ3;;ÿª@dšñÿˆ¿ðNGÆ>1ð·Ãñoâ <%wªøçQñÇ‹£’ÆÎÏY𿊵MGRÔ<#M4÷Kq-ÙÑÄ—Io ¶s´–ÓIäŸoý£¿gx÷ãï~#|9ñ׃ü­ø?Ãúç†çƒÄž¹ñ ­ý¾§s¤Ü3ªÁ¨Ø¼RFúL`îLß( <ûrh·Ÿ³Å—ŽüCáïYËÿ §á-GMðχ5_Ékªi·÷º}ç–ºu¤—gö‹ *æX! t†ICÂ?ðSχ~ Öþ%G<š„ºW‚3ÿѹkŸøYèÿüvøiŒÿônZçþz?ÿ¯z¢€<þCã?ý–¹ÿ…žÿÇhÿ†øÏÿFå®ág£ÿñÚ÷ª(Áá¤>3ÿѹkŸøYèÿüvøiŒÿônZçþz?ÿ¯z¢€<þCã?ý–¹ÿ…žÿÇhÿ†øÏÿFå®ág£ÿñÚ÷ª(Áá¤>3ÿѹkŸøYèÿüvøiŒÿônZçþz?ÿ¯z¢€<þCã?ý–¹ÿ…žÿÇhÿ†øÏÿFå®ág£ÿñÚ÷ª(Áá¤>3ÿѹkŸøYèÿüvøiŒÿônZçþz?ÿ¯z¢€<þCã?ý–¹ÿ…žÿÇjßÚwãŸne—ös×BåñŽÄ’@!'$Šú¨ø‡þ<#ÿ¯›ý”à¿ðÖ?ÿèÛ¼Uÿ…6›ÿÅÖoˆnoˆ>}-üEð+Xðí–­©Úi^^øžÄijÜÌ°Æ +ǾFù˜±… q€kÊà¦ßðXÁ)á¼ø‰ðïâÖµá¿fOøoM°»Òâ»ɲ•弉â¸1¡‘U,‰¸£9ŠQ¯ÇŸŠWg/ƒ¾-ºð‹| &¿ãŸÞ.…â‹x-µ=óä0Ã,«Œ›_Ë/½…‘R@è m×!ðÓþGOˆ_ö0Eÿ¦­>ºúä>Èéñ þÆ¿ôÕ§Ð__ÿå&ÿ²!{ÿ¨Ô•ú)_þ5gâqÿTB÷ÿQ©+ÝÉ~ßág‹›üTÄ…øgÿ(³ðÏý‘ /ýF£¯Ñjüéøgÿ(³ðÏý‘ /ýF£¯ÑjyßÃGü(Y?Å[üLä4_ù/ž%ÿ±IÿÒN¸ïÚãоüEø xZ_ÛÂÉøÿö¯>«§Í{åiÐèz¾­:Û¬sòâOìʼn%réš\Å.Ї±Ñä¾x—þÅý'ÿJu:óïÚóÀÞ&ñÅoÙÛ]ð÷†õÚx+âSjzêY\ÚC&aqáÍwK7„\Í’8§ÔmÙÒ"óÞR9m> íœ×ügÁŸ´®‡¡iךƒ|=›ÁZç‰/5ë¯ë0G¬Ü[êZ–šš%ËÀ°ëÝVUŒiâèÜ<–B>tk6yÿ‚ë1ýžÿix[Gòõx®ßÁ?´ïxoTÐîubûFÐßKµÔ-/D}£YÕÖßÌu·Œ@ñH]4石ÿ‚Iø©­|¤^üVðüþø)áH<1ðæÞÍ ýŸØµêºtú½ÁÔZ=Cdž±IÒÚ=f¸ØÖÅ“Ëô¿°7м/û@Kñâ'Ä/øËP›Åwþ6:v‰áI´u‰|?¥xzÒê1%ýÜÃìúmž§åxåmaœ¢5´&€: ÿà¨m5^ÊãÄ^ µþÂÕo´‹ë»kPØBÖRÚj7bé­ §ØÜDc»ÔÍ£<"y¢ó¢ÞOÿ@ø+i¬jöW"ñ¯ö«}¤_]Üx;Z†Â°º–ÓQ»Mh m>Æâ#Þ ®líáÍÿ?ñ÷ü“þ‡^*Ð?á=û/ü$Þø«á?ûÙ¿á7×!Õ¼ý¿h¾Ãåy[2>Ñ»~èq°ž>ÿ‚RÂqðëÅZü'¿eÿ„›ÂŸ|1çÿboû7ü&úä:·Ÿ·íwØ|¯+fGÚ7oÝ6Oø©û^[|/ý«´¯ÞϧÁáKOÚÜx’ñíg’ëOÕ5­rËGðÌì8hïg]eª8ˆÚDÒ¼ÊeÐÓo_„ú½ö³moâ¿2ê¶%úÿf^³Þ_xŠ÷ÃV±dņ߫é÷–Û—*¾O˜Åad‘¼Ãö‘ý”üM¤þËÿ´_ iú‡Žþ)|Vñ¬ž)²ñ?dÓ­|3¬Ã,RxwT½Š{•F³ÒKÐà•mãžK‘aæ5œí<êÜü0T¾ý¡>Ó¥øSâ×¼¥mø•¦Ôô¶|jñ¶³ÿ .,ÍQmöm^÷\¹™OöL/uykX!Ž ð?íëðŸâGˆü ¤è¾+ûn¡ñ'JÒµ¿Eý™yöž©cªßØË—ˆüÛ]S“l…Y>͵´‘+à~Ì_µ¥çíûGx¾ÇLÔü?®|2¼øàïˆ^ +¿´Òn¬/ä³ÖÛX–èÏ+y¹þÌŽhȂݑn nŒÉ½¾oð‡üÇÆþøgðêßCÒ¼aáï‰Ä+ ø¡5 h> ø;K»¿·Ó´I#È—w‘øoYÕì’Smªï¿¼•æºhc¶¸èÙgöu¹øû\xò Áš‡…¾ø{᯼á‹B ¨õÒe×¥‘aâ[¡j6—»XÝÝ$#ÌP$`£è¢Š(¢Š+Àÿc_k_ŸP"Åu‰zÍ©¸>P¹ˆ[ÙÆdMØÜ¾dr&FFäaÔ^ùEQÿ„ŸMÿ …ýÿOñ£þ}7þ‚?÷ý?ƯQ@á'Óè!cÿÓühÿ„ŸMÿ …ýÿOñ«ÔPøIôßúXÿßôÿ?á'Óè!cÿÓüjõGþ}7þ‚?÷ý?ÆøIôßúXÿßôÿ½EQÿ„ŸMÿ …ýÿOñ£þ}7þ‚?÷ý?ƯQ@á'Óè!cÿÓühÿ„ŸMÿ …ýÿOñ«ÔPøIôßúXÿßôÿ?á'Óè!cÿÓüjõGþ}7þ‚?÷ý?ÆøIôßúXÿßôÿ½EQÿ„ŸMÿ …ýÿOñ®sâÏÅ='Àž½Ö%k½Q4ç†ci¤Û½ýíÆ&O–8bÜŸ¦Éb;(ä/þØÞñŽŸ¦¯ð¯â¶«i Õ½ôpÞxâxÒâÞt¸·˜+)H¦Š9Qº£ÆŒ¤2‚8ÿ¿Gí¾ÑôüN²žËÆš6¥4Ú—…n­mã‚+¥23HTª…S¸–ÀžkîÚ(®Cá§üŽŸ¿ì`‹ÿMZ}uõÈ|4ÿ‘ÓâýŒé«O ¾¿8þ"?üjçÄãþ¨ïþ£RWèå~oüDlÿÁ0Þÿê5%{¹/Ã[ü,ñsŠø‘káŸü¢ÏÃ?öD,¿õŽ¿E«ó£á™ÿZxgþÈ…—þ£Q×è½VwðÐÿ Ÿâ­þ&r/ü—ÏÿØ¿¤ÿéN§]}r/ü—ÏÿØ¿¤ÿéN§]}x´QEQEQEQ^[ñ»ö› |q¦ø;@ð¶¹ãë2jvšE†Ëx–Ú9Yî¥++ɱù˜*pΛ€=JŠà>ühÕ>(˪éú÷‚Ûx–7wíUHLZØÝI¹Ê¯î¶çs*°AEPEPEPEPEPEPEPEPEPEPEP\‡ÃOù>!ØÁþš´úëëøiÿ#§Ä/û"ÿÓVŸ@}~n|D?ñ¬_Ù½Ïþ2Wé~m|E?ñ¬Ù½ÿÔfJ÷²_†·øYâgñ"ïÃ3ø%·†ìˆYê5~ŒWç7ÃOùE·†?ìˆYê5~ŒÓÎþàCÉþ*ßâg!¢ÿÉ|ñ/ý‹úOþ”êuÇ~Õÿ¶.…û"xàõ·ˆáÆŸñoâ§ÃدwÉÿûËËé¬ÛËŽ72y·V°[`ìTûW˜Î6±Ñä¾x—þÅý'ÿJu:óïÛ[öC¶ý±_ᶬÁ§ßx7Eñ§qâ« ‹©í¤Ô´»ß ëº,°Bð€âF}V,ñ‚FWª­àÐx[öòðoˆÿjŽ?¦½Óô»OÙÿÃúµâÍvþìÚZéÏ©E¨]4R™Q#Hà³´·¸iÄ®„]•;Ïa¡~Ö? »Òµ v ^×Ä6sXM§iò$W÷«:Èck{Y$&”‘3¨r¤_8xOþ Åãï„Z'×Âþ7ÓäÖü]௠i·ºÂMs£Ýx›Y¶×üA¬øŠY#é1êÏ­L‰=“I%»–KxÁ¶[Çâÿ‚BüWñ?‡ü`׳ø?Ãwz—ˆ5oiÖOñ\ñ|šµÁÑ<;§Yø{[ÕuE»Ô<7&™xú“.dH´Èãb° _þÑß´w¼ñ÷À¿~øÁþ0ÖüaáýsÄ“ÏâOÜøzÖÂßL¹ÒmÙ Ó¯žY$}Z2D +!o˜’hYþÝÿ 4ï:oÄ?øÃÃÿ ¼?}ªÝøvVñ–­g£ý‡X´¸¹µ¼Ó^Y%òâ‹;¸Ï“,‘¿ÙâybÛ!Àý¥þüSÿ†§øsñ3ឃðÿÅð‹øSÄ~Ô´ßø¦óÃÿò¼Ð®bžmôëíû?²dVFDÿZ„1Áçÿÿa?ˆ^øEáÂZÿü%Zj¾ ×üQ£¯ŽuŸ†ëƳ©>©&¡¥¤%ÍôVöÓÜjE¦¹’7Šþ7šy&³‰äúþÇ…á#þÇÿ„›ÃÿÚÿÚ¿Ø_aþчí?Ú?aþÑû—»wÚ>Ãþ•åc‘ûÜlù«?á·í àŒºv‰yàÿx?Åvž%´»¿Ò'Ñõ›kèõ[{Iã·»šÝ¢vÇóEŽ™¼¨¬C0àØ«þ Ëâ*/jƒO>øgáý!n¤ñ'ƒogÓdöý‰¿d߇ мKãx>èŸÙ)®ë§Zi<©% ·‡(!%¼¨(÷¸{yíýðoÆßµgÇmÁº_ÃøóÀ^ð¦§u®Øø³Äš‡„ô­Nó\·ºÑá{-FÆÆòin-´Ñ®CqnDJ‰®YÌ H"h¾‚ø!ûGøsãßö¥¾”𯛬è^Wö®¬iòØj:_¼ÃçC |ÄŒºòr¥Oz»ñ¯ö…ðì×á[}wâ7Ž<à îíl Ô'|dý¼q¡ü`Ò?h kÄïðVçÂ~ƒÁzGˆâ³ñ/Ží[\Óµ»«›m +5ŽM>úHtYí?µbKYmnwE¼Aê7„õÏþß¿¯-øßǶþ Ñþÿbø7Ä÷^Y5«ÝBÞêf‰"”1X£‘q²dÈÉ òŠúZ¼öÿ÷Ç_û*Z—þ‘ØPöÿÚƒþ??ðm«ò=oý¨?èðÿÚ·ÿ#×½Q@ öÿÚƒþ??ðm«ò=oý¨?èðÿÚ·ÿ#×½Q@ öÿÚƒþ??ðm«ò=oý¨?èðÿÚ·ÿ#×½Q@ öÿÚƒþ??ðm«ò=oý¨?èðÿÚ·ÿ#×½Q@ öÿÚƒþ??ðm«ò=oý¨?èðÿÚ·ÿ#×½Q@ öÿÚƒþ??ðm«ò=oý¨?èðÿÚ·ÿ#×½Q@ öÿÚƒþ??ðm«ò=oý¨?èðÿÚ·ÿ#×½Q@ öÿÚƒþ??ðm«ò=oý¨?èðÿÚ·ÿ#×½Q@ öÿÚƒþ??ðm«ò=A¨ëß´þ›je:7À‰>e@©«j»˜³›p:‘Þ¾ª>!ÿÿëæßÿG%|ûÿ ×í=ÿBÿÀ¿ü_ÿñºÀñÿí#ñóáèw>&ѾÛiÚÖ¹a¡«Ø_ßÞ\,—S¬A–=¨§hfs¹Ô„g$åÿðUŸø(ßÅø'>ŸáwÂ_³µÿÆÏk÷PiÞèÞ$’ÛPÒõ9çÛ[Éd–3³G;¼QÅ*9 3ùL¨ÏÒ|yñG‹ümû9|Õü}á;x¿Rñχî5/YëCYHv¼ÊÀnÖ(–Y6ï(›ïTy,ŽöÝr ?ätø…ÿc_újÓ믮Cá§üŽŸ¿ì`‹ÿMZ}uõùµñþQâoû"W¿úŒÉ_¤µù¹ñãXÞ%?õDoõ’½ì—á­þx™ÇÅGüHµðÓþQmáû"_úG_£5ùÍðÓþQmáû"_úG_£4󿆇ødÿoñ3Ñä¾x—þÅý'ÿJu:ëëÑä¾x—þÅý'ÿJu:ëëÀ=°¢Š(¢Š(¢Š(¯ð—„5? þÛ~;ñµg5Α­xwL‡DÕœoƒHXžasg½ðb3IåJV<£yJd*ÞXoi¢€3­.SRÖÄö;à(ò¨ù&%P­Ñ¶áóé¿Î>qý¾|K¡|ø§ð÷â%ÇÆ‡ÿ|O¦iZׇ,5ˆ:<—¾¼³½›L¸º¶yí„qêM:ÍàV¼ ðÅ~VÞaÉoôýùûCþÚ|ÿ +§NðLÿfí"O…^ñ‡|â}Qtoí-jçíK7†!Óÿ°oo5°-¶iúHÓ¯WíÈ‹Ý[}Ÿëø&>sᯅ?ôëý[PºÔ øÁ㫉ô›Ô‚9<:—^#¾¼¶€"F’¬sÚ\[jn Žé©$ˆþD*ýEâ²w…õ?‡z·Å¹u7P±O|AÔ5m8µ³¿ÚmZ X–Q´ðÉŒà•”Ÿl¢€(ÿÂCoÿ<ï¿ð +oþ&øHmÿç÷þMÿÄÕê(ü$6ÿóÎûÿ¦ÿâhÿ„†ßþyßàßüM^¢€(ÿÂCoÿ<ï¿ð +oþ&øHmÿç÷þMÿÄÕê(ü$6ÿóÎûÿ¦ÿâhÿ„†ßþyßàßüM^¢€(ÿÂCoÿ<ï¿ð +oþ&øHmÿç÷þMÿÄÕê(ü$6ÿóÎûÿ¦ÿâhÿ„†ßþyßàßüM^¢€(ÿÂCoÿ<ï¿ð +oþ&øHmÿç÷þMÿÄÕê(ü$6ÿóÎûÿ¦ÿâhÿ„†ßþyßàßüM^¢€(ÿÂCoÿ<ï¿ð +oþ&¹ïо6½Ð¼{{¢øwYñ>«jÑKm¥ÛF-¤¼a*¢I¶F€ ’Y¸à1ž¾ŠùgþßÅÿú7áE¦ÿñÊã¾/ÏñkãôžÓ.> +øÃ–ºW‹4­fâúmbÂå#†Þå^L¢I¸ü›Ê ùqŽkíz(®Cá§üŽŸ¿ì`‹ÿMZ}uõÈ|4ÿ‘ÓâýŒé«O ¾¿7~"ÿÊ1Ñ}ÐÿðÝÁÿÉtïTW‚ÿ‹øùÿE÷CÿÃwÿ%Ñÿ +/ãçýÝÿ Üü—@õEx/ü(¿Ÿô_t?ü7pò]ð¢þ>Ñ}ÐÿðÝÁÿÉtïTW‚ÿ‹øùÿE÷CÿÃwÿ%Ñÿ +/ãçýÝÿ Üü—@õEx/ü(¿Ÿô_t?ü7pò]ð¢þ>Ñ}ÐÿðÝÁÿÉtïTW‚ÿ‹øùÿE÷CÿÃwÿ%Ñÿ +/ãçýÝÿ Üü—@õEx/ü(¿Ÿô_t?ü7pò]ð¢þ>Ñ}ÐÿðÝÁÿÉtïTW‚ÿ‹øùÿE÷CÿÃwÿ%Ñÿ +/ãçýÝÿ Üü—@õEx/ü(¿Ÿô_t?ü7pò] ðsã–Âîûã®—wekûëˆ ð´ÍòÈ’‡Ä` ÎÖÆ½W!ðÓþGOˆ_ö0Eÿ¦­>ºúä>Èéñ þÆ¿ôÕ§Ð__›¿åž&ÿ²#{ÿ¨Ì•úE_›¿åž&ÿ²#{ÿ¨Ì•ïd¿ oð³ÄÎ>*?âE¿†«ÿ³ðÇý‘ /ýF£¯Ñzüëøh?ãUþ?õD,¿õŽ¿E(ÎþáCÊ>*ßâg!¢ÿÉ|ñ/ý‹úOþ”êuóü³áÇü-½Sökð÷ü þ(h|U›þ)Ü}ŸBÔöxCÄÒ¤?Øï1åìóSýLÉcäÎõúCEÿ’ùâ_ûôŸý)Ôé>5þÏ^ý¥<+o¡|Fð?ƒü¢Z]­ü‰4kmVÖ…GE™b@’H¡ÀÈ0Îׂ{GÌ´÷í ªÿÁ5¾ |<ðç>ü/𕦻áýZÙ|; Z<š7‚5–6“&µwä­ ‡ÂvSÏvÚž¡äG$fîÅÄhÓ8¯/ý¦à _ü û,|Dñ§Štïƒþ5ðOˆõ_ŠÒ<%sá;Äû?ü#Ö~)š u)äÔ&‹Q·¸‡Ã öÉmm»í儊")/Ûúìð³Âþ·ð¶™ðÓáþá‹M+PРÒ-|=g „:v¡"Kd°,b5·º’8Þh€Ù+"— @5Çü"ÿ‚qüø9?¯,þx?TÖþ#ÝëÓxŸZÔôõ=~ßXÔg¿»°ºœB¯qg¾aÃ.áäÁ +¶ò›ˆÎ>ÿ‚›üSøoðëÅZýå§ÃûíøZº_ þȼ·þÒñ‡õÈtŸ xq¼o·j“©Kä@"šãÊÙiöyO`ý®|ÿ iûGhÿŸDñµáøRóÁ¾&±Ð,þÝ©jz«>£áÈÒ9 +Æ›¤}oO„$ˆ÷7úö›YKÄÐz}ïìŸáëÏŒ¾ñX»Ô-4ß]Þk:G…ì­ì­4k]nð_%Þ´|«uº’òhµ;øÜIpÖìn^S Ÿ@ñ7„ô¯iÑÙë:fŸ«ZCwm¶é|wÕ|c¨øKÅîµ {OØûÁZ¶¯ñGX»ÒžÞÞoźsjVimy#\íè·hâÝeâ]ám™§‡ìùÿ +à ß´ïí1àïƒþ:ðŸ‡ü#â}_Åz/ÛµWÃpÛ}§C½Ò|U}$VöV> Ô£ŽãÌð»Æ—R_0l;¬±µÇÝú7„ô¯j:µæŸ¦iözýÚßêsÛÛ¤Rj7 Vë4Ì $AAÛ$$1®v¢çÿ ?b/‚ÿu¼ð'Â…þ +»K¸ïÖ}¶:l‚â8.mÒ`ÐħÌX/.âÔ%ÔêÙŒ ëÞ/Ò>ÿmþÑ^ +ÑuïÅ£Úß_Ü^ë>Ñ|ë³,ûõÝüQ ïÙ£û!€YÉiö‹“ ¾O·Ûözð éÞ³>ðy´ðu¤6F¶òô;xg´¸†UÙˆ#Ž{ U#Úì­˜ÐÆWŸø·û$xKâgÁ¦ð^Ÿg§ø.ÒÉá=>ïGÐ4‰äÒ4iM°¸Ó-ྴ¹´sÇiR[´ $iò†Ž6@Cö9ø¡ñOâÄ_ŠšÄ {áþ¯ÿ +»Åoá‰'ð÷…¯4í_;CÐ5kiÂϨÝù>WöäR!2y¹Õ¡òÝ%÷úðÿØËþ ïðÓöð«Ùx;EÓßU¸»¼½¹ÖŸFÓtû©^é,ãœGŸmmikǧiêñÚÛÂ’›(¥‘d›|¯îQEW‚þÃ?òøëÿeKRÿÒ; +÷ªò/ٯᖻðSø™6©`d_øÞû_±óFåm¤ŠÞß–b`fÀΗ8l¨õÚ*öµÇý/¿ï¸øåÚ×ô ¾ÿ¾áÿã”zŠ£ý­qÿ@Ëïûîþ9GöµÇý/¿ï¸øå^¢¨ÿk\Ð2ûþû‡ÿŽQý­qÿ@Ëïûîþ9@¨ª?Ú×ô ¾ÿ¾áÿã”k\Ð2ûþû‡ÿŽPê*öµÇý/¿ï¸øåÚ×ô ¾ÿ¾áÿã”zŠ£ý­qÿ@Ëïûîþ9GöµÇý/¿ï¸øå^¢¨ÿk\Ð2ûþû‡ÿŽQý­qÿ@Ëïûîþ9@¨ª?Ú×ô ¾ÿ¾áÿã”k\Ð2ûþû‡ÿŽPê*öµÇý/¿ï¸øåÚ×ô ¾ÿ¾áÿã”z¨øŸþE­Gþ½¤ÿÐ Ú×ô ¾ÿ¾áÿã•[XººÔ4‹«tÓ/Ï Æ¥žTŸž€5ëøiÿ#§Ä/û"ÿÓVŸ]}r ?ätø…ÿc_újÓ误Í߈¿òŒOÙ½ÿÔfJý"¯Í߈¿òŒOÙ½ÿÔfJ÷²_†·øYâgñ#Cá ÿUøcþÈ…—þ£Q×è•~wü3ÿ‚TøgþÈ…Ÿþ£Q×è…,ëá£þVQñVÿ9 þKç‰ì_Òô§S®¾¹ þKç‰ì_Òô§S®¾¼#Ù +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +ä>Èéñ þÆ¿ôÕ§×_\‡ÃOù>!ØÁþš´úëëówâ/ü£ÄßöDoõ’¿H«ówâ/ü£ÄßöDoõ’½ì—á­þx™ÇÅGüHÒøeÿ(©ðÏý‘ ?ýF£¯Ñ +üïøeÿ(©ðÏý‘ ?ýF£¯Ñ +Y×ÃGü(¬£â­þ&r/ü—ÏÿØ¿¤ÿéN§]}r/ü—ÏÿØ¿¤ÿéN§_7ÿÁ[>ÂÛÕ?f¿Âðÿâ‡ö‡ÅY¿â˜ñ½ÇÙô-Og„Lï_öO¯è¯€>9~Ô?bb/‡?~|?Ðü1ð§áý‡¼[¤èŸÙ6¾±û}Öªf²ŽúóRÑ£Ó-ÖM.ñΠ,¯w †šKHŒ>]Ïÿÿ‚‘|Pð§þ0Cá}?P |AáÿxGÃ>1°ÓbÑ®´OhÞÖî®eŠùu‰og’íþI²@@–;©(ÍØé}òŠÿoŸ|&Ñüa¦ø—Pø7‰ü;ñ«Àÿ ´ÙÒm:ÿkÚøZãPx-¤»’O´,z¶©4Q¬¯åÅkq0ŠW“Ãôßø*§í¬üðˆ4oø?ÅWp|Ð~1xÚêÊÎËJÑ…¾°u¡ÓÍΩâ S¤Çl¨÷ûu0ÅÞfµbXgý/¢¾pøOûGxûâí+ã¶±ð¾ÇJµ»–}`·¹¾¸¹°Óõ(,ïÚ„¸ê17V×*Òmõ Žk}B‹{™þ Š( Š( Š( ¾iðßÇ/ŽŸüoãÛèÿ ÿ±|â{¯¬šÕî¡ou3D‘J¬QȸÙ2 äd†ù@Å}-^ û ÿÈ{ã¯ý•-KÿHì(ûíAÿ@Ÿ€Ÿø6Õ¿ù·þÔô ø ÿƒm[ÿ‘ëÞ¨ ûíAÿ@Ÿ€Ÿø6Õ¿ù·þÔô ø ÿƒm[ÿ‘ëÞ¨ ûíAÿ@Ÿ€Ÿø6Õ¿ù·þÔô ø ÿƒm[ÿ‘ëÞ¨ ûíAÿ@Ÿ€Ÿø6Õ¿ù·þÔô ø ÿƒm[ÿ‘ëÞ¨ ûíAÿ@Ÿ€Ÿø6Õ¿ù·þÔô ø ÿƒm[ÿ‘ëÞ¨ ûíAÿ@Ÿ€Ÿø6Õ¿ù·þÔô ø ÿƒm[ÿ‘ëÞ¨ ûíAÿ@Ÿ€Ÿø6Õ¿ù·þÔô ø ÿƒm[ÿ‘ëÞ¨ ûíAÿ@Ÿ€Ÿø6Õ¿ù·þÔô ø ÿƒm[ÿ‘ëÞ¨ ûíAÿ@Ÿ€Ÿø6Õ¿ù·þÔô ø ÿƒm[ÿ‘ëÞ¨ ûíAÿ@Ÿ€Ÿø6Õ¿ù¯ûJZÌ’ê:Àè4øØ=Ô¶×ú¤óGåÙ#hP;É +]A8—¨÷Š£âùµúö“ÿ@4z¹†Ÿò:|Bÿ±‚/ý5iõ××!ðÓþGOˆ_ö0Eÿ¦­>€:úüÝø‹ÿ(Äñ7ý‘ßýFd¯Ò*üÝø‹ÿ(Äñ7ý‘ßýFd¯{%øk…ž&qñQÿ4¾Ê*|3ÿdBÏÿQ¨ëôB¿;þøÕO†ìˆYÿê4•ú!K:øhÿ…(ø«‰œ†‹ÿ%óÄ¿ö/é?úS©Öþ³á=+ÄzŽ“y¨iš}ýÞv×úd÷é,šuÃA-»M 0&9 ÏuÁ)4‹®Ààh¿ò_³—þ/+Éòÿ³·F~ɳìöû|›|ˆ±‹@¢€8ù?g¯Ëâ­{]oø=µ¿]é·úÖ tkcu¬\i®§Ms.ÍóIhñ£@îI„¢”*@®ÂŠ(¢Š(¢Š(¢Š(¯ý“¼/©ü;Õ¾-ˬ麅Šx‹â¡«iÅ­þÓjÐZIJ à†Lg€|¬¤ûeGþùç}ÿ€Sñ4ÂCoÿ<ï¿ð +oþ&¯Q@á!·ÿžwßø7ÿGü$6ÿóÎûÿ¦ÿâjõGþùç}ÿ€Sñ4ÂCoÿ<ï¿ð +oþ&¯Q@á!·ÿžwßø7ÿGü$6ÿóÎûÿ¦ÿâjõGþùç}ÿ€Sñ4ÂCoÿ<ï¿ð +oþ&¯Q@á!·ÿžwßø7ÿGü$6ÿóÎûÿ¦ÿâjõGþùç}ÿ€Sñ4ÂCoÿ<ï¿ð +oþ&¯Q@á!·ÿžwßø7ÿGü$6ÿóÎûÿ¦ÿâjõGþùç}ÿ€Sñ4ÂCoÿ<ï¿ð +oþ&¯Q@á!·ÿžwßø7ÿUuÝb;Íò¢¾i%ÑØæ%HîÖÅW!ðÓþGOˆ_ö0Eÿ¦­>ºúä>Èéñ þÆ¿ôÕ§Ð__›¿åž&ÿ²#{ÿ¨Ì•úE_›¿åž&ÿ²#{ÿ¨Ì•ïd¿ oð³ÄÎ>*?âF‡Ã#ø%g†ìˆYê5~‰WçoÃ?ùEg†ìˆYê5~‰Rξ?áEeoñ3Ñä¾x—þÅý'ÿJu:ëëÑä¾x—þÅý'ÿJu:ëëÂ=¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠùæÛÇž*ñŸ‹´ß|Õ|Wcá r}ãP‡ÄÚ}šIÜË/ì箄/Ëã!‰$€BNIôó¿ü5Åÿú6ïáM¦ÿñu›âÛ›â‚K| +Ö<;e«jvšDW—¾'±1,÷3,1‚±ï‘¾fìF!C`új¹†Ÿò:|Bÿ±‚/ý5iõ××!ðÓþGOˆ_ö0Eÿ¦­>€:úüÝø‹ÿ(Äñ7ý‘ßýFd¯Ò*üÝø‹ÿ(Äñ7ý‘ßýFd¯{%øk…ž&qñQÿ4>ÿÊ+<3ÿdBËÿQ¨ëôJ¿:þÈ?áÕÞõD,¿õŽ¿E)g_ 𢲊·ø™Èh¿ò_0ø-ûyx‡_ý¥i¿ê7ºyøo¥x+·? 4Û›»Ø­õ¤“Rñ6ŸÎØëÌ“WÔ-ì’éðN÷–Si8f™–"[ÿÁk¤±øz—ÚÇÂÝCKñLj/~Øé·ZŽŸ­ãy,´ÛýA„jm¥ìQêV×ò}{ek³ÙHÌŠX'—éýSö/ø_ªiÚ­˜ð†Ÿci«xGð»A§I-„v6D÷7RY¬‚ÊK9îæ– ­¼©¡)‘Õ¡ˆ§!¢ÿÁ/þ +èú?Ь¤ðïˆ5øN4­gD×®õ¿ëZÅþ©g«Úé–š„R]]ÝË9ó-ô}60ÁÃD¶ª#1î}Àÿà¦Þ,Õ|ÿÛý õÝ SÔ4]oEøkâ;ý?P°¸{k« ˆ´»—Šh¥B9ÕY]H*@ ‚+çýºu߀?4[OŠÚψ/üAð;à¯Ä-{â—f±ÛÍâÈ´­CÂÃÄQY+Gj´-îx3Em-Õí—œ%¶ºUû?Æ<3ñà׊¾ëöº†³áOÚjvÍ¥î«w4—Vú‰˜ÝB'iLÑÆDò"$n¢Ø‘Ò4UÏñ¯ì«ðãâGÅ9¼k¯ø/Ãúωîü){àkËÛËU›ûGC»š)®4ë˜Û÷wí$*Á%W ¾`»DÒ‡ùCŸðROŠÿ¾+|Ð`øi¨x +ïVø•m£kcR³×,4m{FŸÃž#¼–;{­gC°»kËi4¤¸h¡´“ö(ÍÚ­Ìâ †_ðZÍ â_‡<s„ëL¶¼ñ§ykáÑc¨ÚêV¶Ú\\4ZešÝØØ¹´²XmÜY[Fñ4pÆ‹Øx[ö\ð'‚uQÒt/°jÕu½fÊê+Û2O¬ÝMy©£¿™™mî.§3µ´… Ãlëµµ¹ˆæÚâÇŠ´OÙSþ +=¨Ùx›Äš‡¿µÿẇQš9¼?³áÖ…xŸcpÙ·Ûu4³,®%•Ü|ÌIõÚþ +sû4üLñÅ·ˆ<¨Ià¿ø*ÿÆ—Z¶«Õõ+[+I.®nl¬eÃqgD´‘ÒïíPÝÝZ ¬â´¹†ùúÿŠ_°Ã?Œž;¾ñ»¥øçÖ¼¿í­:ÇÅZ¶›¢x—dküLôËk˜ìuðG¼Ÿk‚_6Þ( “|1¤cCÅŸ±ÂÿüLÔüY®øCOÖµ-jÒ[]BÖþInt‹ó-¡±–æ]9ÜÙIxö,ÖMvЛ†´&ØÊ`>UxÂ/ø*7Ž~#øÓÁ~Ô>êÖü]ã[/ ý¯Rhú2ÙM¥kœ÷ójÚÕÕäh³†¶[E‡7v_é`É ‡×ÿfoÚ{Æ_´£¬ÇyðóOð¬^ñéšœw>%ÞépùºÁqn¶áãÕÖÍä·¬ž×Q·º´Ôo£e ¡ðûöøgð×Äz>·g¥øƒUñƒª®³c¬ø‡ÅZ·ˆ5X§[ëÐÝß\Í;ÛÇo©ê";gso{<‰Ë#9ÐøIû|;ø¨­×„´}CE•.ã¸b×/Þ8aŠ ˜-ôäG˜¢ivÉwrmôÕÊÙå2CràÔ+ÁaŸù|uÿ²¥©é…{ÕxìbëáíkãSêX®¡ñ/S¹µ7Ê1 {8̉»—ÌŽDÈÈÜŒ:‚(ß(ª?ð“é¿ô±ÿ¿éþ4ÂO¦ÿÐBÇþÿ§øÐê*ü$úoý,ïúð“é¿ô±ÿ¿éþ4zŠ£ÿ >›ÿA ûþŸãGü$úoý,ïú^¢¨ÿÂO¦ÿÐBÇþÿ§øÑÿ >›ÿA ûþŸã@¨ª?ð“é¿ô±ÿ¿éþ4ÂO¦ÿÐBÇþÿ§øÐê*ü$úoý,ïúð“é¿ô±ÿ¿éþ4zŠ£ÿ >›ÿA ûþŸãGü$úoý,ïú^¢¨ÿÂO¦ÿÐBÇþÿ§øÑÿ >›ÿA ûþŸã@ªˆãÂ?úù·ÿÑÉGü$úoý,ïúsŸ~)é>ð î±+]ꉧ<3M&Ýïïn12|±Ã.äý0K òüÛþ àÏø%/ü#·Ÿ>üZÖ¼7âlÃiâ é¶z\Wcy6R¼·‘€:úüÝø‹ÿ(Äñ7ý‘ßýFd¯Ò*üÛø‹ ÿ‡bø˜Õ½ÿÔfJ÷²O†·øYâçñ"ÏÃ5?ðëO ú‚_úG_£uùÇðÆp?à—^^8ø#eÿ¨Ìuú9K:øhÿ…Pýêßâg!¢ÿÉ|ñ/ý‹úOþ”êu××!¢ÿÉ|ñ/ý‹úOþ”êu×ׄ{AEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP\‡ÃOù>!ØÁþš´úëëøiÿ#§Ä/û"ÿÓVŸ@}~jüDSÿÌñ7§ü)ßýFd¯ÒªüÚøŠ?ãXþ&ÿ²%{ÿ¨Ì•ïdŸ ð³ÅÍþ*?âGø#ãôV°÷‡´&|±ã?õ)Ç%~Á×󻥸†døo¡Û;?áHéügþ¤˜DUéq^4iáûTÓüŽ^ªçIŸCÜÁF>+Û1«|5zƒàûßþZÕ?à¦ÈþÓøi€xÏ„/yÿÊ­|Ûq¬Éu!flíTÝ‹¹$ä“־⟇¹-½ê î>N\mšßݪϧ?áæ_?è'ðÓÿ ßþZÒÃ̾,îñ2øgŒsÿïÿ-k„Ñ<á»Ox_À×zwwž%¶²khÜÜ-լױ¤‘˜QXEåÆ$ŒxÝŸa×rì¹ÁM#Ã?4ß^Ø[jqÛiNeÓõƒÞÜ›ë‹qq*«‰RÚ0!¦ÝÎѨ#.ÃÇŸpÜ9T°ßJ:/{šü¶×¯+ÞÖÒöZž¥,÷=©~ZËEw¿º•¯}:'Òû4®ìŸaÿ2ø±ÿA/†ŸøHÞÿòÖøy—Åú ü4ÿÂF÷ÿ–µó±8=‡jJ÷?âäóá}Ç“þ»fÿóõŸNÿÃ̾,ÐKá§þ7¿üµ©¼ ÿKø‘mñoÁšn¿5Ä~ Óô)áÓt;­>é~ÛwšÊ³I}:¯–ó¬…LM½c)”,~\¤ðË“ñ»ápÄ ü­ÙW&aÀ9%<j‘ ®¡&½T[Gn[Æ­\e*sªìåþm#ö¦Š(¯åC÷ð¢Š(¯š¿à¡¿¶gˆÿeCá Xèßxon¥ºÕãšxaŠÔÛ)b‰ãbî×HC—ˆ˜mmà¯ÒµùåÿÙ»6šçÂr íuÅ8ÿL?Ò¾ÏÃ첆aŸáðx˜©B\×Om!&¿™óÜU‹«…Êêס.Y+Y¯9%ùÌÿðXŠÖùÝÃGP4[ìÿémUoø,ïÅ%ýŸá±Çý@ï¹ÿÉêø’êáî$%‰<ñíI&âtpØ(ÏNkú’>pý½ì<~ãñ9qŽjµöÒþ¾GÛÿ£ø¦«Å§Ã’}´;ßþNªÒÿÁl~++ºwö¹ÐïGþßW…ü^ ðgŒuïAá 8¥Ñ®•ˆ›R¼Íu$¸™7IÂXIû¨íÕ”ÖS¿WÄÿ°G‰ülך¶¹ iZLvRßK¨ÚjšzF‘Mo*âÎ;‡9ºˆ‘0o˜), +בO„øN1„±UiðÝ|JÉéÊß}Ÿ‘èK:Ï\¥ +UÜœ~+=µ¶·K¯k¯3Ø¡ÿ‚ÕüU’ÍaðéH=?±/OþßÔmÿ²ø¯¸ãMøtGlè—£ÿo«Àgý”5 y­âÏhÖsÏ ¾—{{qt–úÓKoÂù$@Z5Ïg¸XQ<Õ Fouðþ ÷â‹ëÿëºõ‚]xsQ¾ÓæÔ,Ò ä?a¸¹Ž0âéa[f $C¶+†+çhÚÛV#†¸.…?kRŒ,öÑë¥ì¯dû=tz;0¥œqIòB¤¯ê»Úþ»ô¹é/ÿ¬ø¨‘6?òFqý‡xqÿ“õ ÿ‚ÙüXÿ oïü^ÿòu|gv‚+©pªäžœÔ©lb½ØøkÖ»ÂÄóçŹ¼dãíå§§ùxüÿ‚ÏüEñÇø]Ñ< u£ø—]²Ñg]>ÊêÒê?µÜ%²H²=̪6<ªåJá +‚¥·/éu~þÎJOíQð¤wÇ^ÿÓ­­~üWà^0ðþ_•cðôòúJš”.Òêù™úŸæX¬n¤ñSrjZ_ÑQ_tQEQEùñDÿÆ´|IÿdFûÿQ‰+ôÆ¿3~(ÿÁ4¼KíðFûÿQ‰kÞÉ>ÿàg‹›üTÄ´/—·¿4 qcc |°çÈ™:ýï¯Ì‡~¶“þ ³á‹“ù§à—8çþEˆÅ~›×WbåZe/³Œ²:J¯n³aEWËžøQEQEðü‚ü]øSžŸØ>#ÿÒ­¾J’eßü tÎkõoöý‘~~ÖÚ6™cãÿ j=fžÊX¯®l.m‹®×UžÚHå¾´{¶1Ž2T”B<ˆÿÁÿgÿ2Fµÿ…¦»ÿÉ•ûoø•eYM<*£Í~Uµ“}fŸ^ÇæMÁÌËͧëSE)¾±¡q ‰Še¶<‘»¦FÖlÇ-K÷š3Ç<:F6’ÖÓ#´:…¬²K$‘ÌÀ™›î•#j‘†]Õö¿ü9öqÿ¡#[ÿÂÓ]ÿäÊ?áËÿ³ý ßþšïÿ&WñC†ZiЫ¯÷açÿO4Z½š·»;‡ùµ«ÃMµ}-ýßîÇîKd~}=Â;’6¨' ÎçÚ›ç§÷…~ƒÿ×ÿgú5¿ü-5ßþL£þ¿û8ÿБ­ÿái®ÿòewÄbÈ¿çÝ_üü°ä~f?óò|¿ùóãÏOï +‡ÂÉ7ÇO…ÈIøƒáŒàêÊ¿CáËÿ³ý ßþšïÿ&VçÃø%/À_ƒßtŸh~¸]kC¸vR_x‡TÔ¡‚eû’y772D· ŒÈJ:«®U‡.?ÅÜ–¶µR«Í8Ê*ñ…®ÓJþûÓäu`|9Ì(biÖ•HZ2‹ɧü§ÑQE9²…Q@~tÁ{¥êÿò@ ¶9ÿ{M5ú/^qûFþÉÿkMM°øá¸µètyÚâÊEºžÎâÙ™v¸Y xäÀ.äݵŠ! ”R>«‚sê6uC2ÄÅÊ溯¬e.ÒëÜñx‡-ža—ÔÁÒi9[W¶?Ðü(ó“ûËùÑç'÷—ó¯×ßøs'ìßÿB÷þZÏÿ%Ñÿdý›ÿè@¾ÿ«Yÿäºþ„ÿˆï‘ÏŠ¿t?ù3òßø†Y‡üý‡þMÿÈŸšÖÿµn¥­m­ÅáŸÛÉo#ø‰ì¥šöwãusÊÖË!òÐ4‘Â’1Ý—rËâÏÚ¢ÿ_ð÷†ì¼+áoiZ‚Ü}¡lô’HóOi<’¸¹•·n²„uÚn2A¥ðæOÙ¿þ„ ïü*µŸþK¦·üölc“ðúðŸëü—^Bño…Tã5…«x´Ö‘ÒÛií-eöVÑè‘ܸ9IÅW†»ïÿÈîú½ßVÏÍhjCR´‚[Ã>ñ%µ€µ:|ZµÃǧˬ6¢TT™C™#·„ÉÞdLc ƒ&—ûYêº-Þ‹©Éá¿Ýø‡D6‰µse+]Ë ¬ˆðBTJ!@¢8ãßi/–wà¶I‡üöoÀ úšµŸþK¦ø"÷ìØGÃë°GýM:Çÿ%ÐüZáV­õZ¶íhíÛø›>«fõwb\ œ/ùÇÿ‘éÓ·K‘R;\HÒþ°–àqÍE$‹Ã§Þ¿_þÅû70ÁøzG¿ŠµŸþK¤_ø#ìÚ‡#áõà>Þ)Ö?ù.½Uã¶Eÿ>jýÐÿäÎ7ážbÝÝXäßä~VþÎcµG“ƒ†ñׇÿôëk_¾µó×Ãø%WÀOƒÿtŸè^Xµ½quc5Þµ¨_Ç ²®'xË¡;•Š’ŽªË†U#èZüsľ3Áñ2Ž# EB<¯šÉÞíôlûþÈ+åXyѯ%''}/Ù.©Q_›XQEQEùñ:2ÿðMŸO‚WßúŒI_¦5ù§ñÆ´|MÿdJ÷ÿQ™+ÞÉ>ÿàg‹›üTĉþsÿÇðÇý‘/ýFc¯ÒZüÒý†|k£|qýŠ<9áùQ¼Ï xj/x’Áf sc5µ°“wΉñ9Žd<@÷fñŸŽüÕ/ˆø  ò®»q™}\]*S¡f”RÜãÂc©a*U…k¦äÞÇÖôWÈÍãoùª^?ÿÀmÿ•t‰ã³cþ—ÿðAÿå]yÿêþ3²ûÎïíÌ/w÷]Q_'Aâ¯Lp~*|@öë ò®­¦³ãWþ.¿Äé×@ÿå]êþ3²ûÁg˜Nïî>¦¢¾ZþÖñ·ýoˆ?ø  ò®”j¾5'þJ·ÄüÐ?ùWKûÙ}ãþÜÂ÷qõ%òïö—è«üBÿÀ]ÿ•tix×þŠ¿Ä/üÐ?ùWGö/²ûÃûs ÝýÇÔTWËoªxÙæ«|AÿÀ]ÿ•uëž6_ùª¿ð@ÿå]5ÃøÇÑ}âyæ»ûªh¯•?á ñ·ý_ˆ?ø  ò®øH«¢¾T ñ±?òU~ ÿà.ÿʺwöï¿èªüAÿÀ]ÿ•t«ØÎËïöî»ûªh¯•¿·|mÿEWâþèü«¦¶¿ã`äªüAÿÀ]ÿ•t¿Õüge÷‹ûw ÝýÇÕtWÉóøŸÇáiü@8ÿ§mÿ•u]üiã…òT¼ÿ€Úÿ*èÿWñ—Þ?íÜ'w÷\Q_!7Â.¯î>Õ¢¾@Ó~&ø§RRSâ×Ïý»hü«¥Ô¾$x·O*âÇÄ›þ´þUÒÿWq½—Þ?íÜ'w÷_Q_%é~4ñލ¹OŠÿð@ÿå]Z›]ñ¼k‘ñWâ ÿ·]ÿ•tŸã;/¼y…îþãêª+ãÍWâ7Ž4ÈÙÅ£?ñí ýÅ×{ûQø¾ÎðB~'øû%¶ÿ¨Ð?ùUMpî5ì—Þ'žáíýÇÞ´WÆGÅßj°+¯ÅàŒÿǾÿʺ½ÿ Ç?ôT<ÿ€Úÿ*髨ÎËïöî»û°kóSâ'ü£GÄßöD¯õ’½­~!xá¿æ¨xÿÿôþUׂþÝß4/Ù÷öñF”U”kþ›À^°iÁ¹¿šæÄéñ„ÈC Ng“îBç‚@>†W N¬ëÙ'·8qXêXª”£Fí©'±ù±ÿ#ñö»ð/âů‰¼­jÞñ#?Ù«¡ÞI§ßXJZ/:¯°2¹ÁÀâ¾xÿ‡‹þÐô]¾2ÿák©ñê(¯‡À{U~ ÿ‡‹þÐô]¾2ÿák©ñê?áâÿ´ýoŒ¿øZê_üzŠ+S1áã´'ýŒ¿øZê_üzøx×í ÿEßã7þº—ÿ¢Š?áã_´/ýŒßøZê_üzøx×í ÿEßã7þº—ÿ¢Š?áã_´/ýŒßøZê_üzøx×í ÿEßã7þº—ÿ¢Š?áã_´/ýŒßøZê_üzøx×í ÿEßã7þº—ÿ¢Š?áã_´/ýŒßøZê_üzøx×í ÿEßã7þº—ÿ¢Š?áã_´/ýŒßøZê_üzøx×í ÿEßã7þº—ÿ¢Š?áã_´/ýŒßøZê_üzøx×í ÿEßã7þº—ÿ¢Šügö„?ó]þ2ÿák©ñê?áâÿ´ýoŒ¿øZê_üzŠ(@'ü<_öƒÿ¢íñ—ÿ ]KÿQÿý ÿè»|eÿÂ×RÿãÔQC?ðQoÚ ÿÍvøÉÿ…®¥ÿǨÿ‡ŠþÐô]¾2ái©ñê(¡ÃÅh?ú.ß?ð´Ô¿øõðñ_Úþ‹·ÆOü-5/þ=E˜ü<[öƒó]¾2ák©ñê_øxÏí?æ»üeÿÂ×RÿãÔQM€ÃÆ¿h_ú.ÿ¿ðµÔ¿øõ$¿ðQ¯Úoü—ŒßøZê_üzŠ(``ë?ðQßÚÿçã?þÚŸÿª+ÿý¡÷ø¿?ÿð¶ÔÿøõUDÍ—l?ࣿ´1ÿšóñŸÿ mOÿU©¿à£´/Ëÿãã7_úµ/þ=E˜úlࣴ/ýŒßøZê_üz­ÃÆÿhSÿ5ãã7þº—ÿ¢ŠE";ø(Çíc?ñ}þ2ÿák©ñê¹ÿ‚Œ~Пiñ}þ2õó:ê_üzŠ)¡Hرÿ‚‹þÐ~_ü—oŒ¿øZê_üz­'ü_öƒÛÿ%Ûã'þº—ÿ¢ŠLhiÿ‚‹þÐ`Ÿø¾ßðµÔ¿øõz§ìcñÄ~+\ø‹Æúî³ã*‹eÔõËÙ5Á„ÛšfgÚ2p3“E„Ö—ÄÿÙ +endstream +endobj +873 0 obj +43647 +endobj +874 0 obj +<< +/Type /XObject +/Subtype /Image +/BitsPerComponent 8 +/Width 489 +/Height 207 +/ColorSpace /DeviceRGB /Filter /DCTDecode +/Length 875 0 R +>> +stream +ÿØÿàJFIF``ÿÛC  +   $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀÏé"ÿÄ + ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ +%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ + ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ +$4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?½ h:e–‹g,Ö—w—VñÜK5Ô+67¨pª™Îk@[iXû'F]:ÿ²S¬ä ¤ÿØ6ÓÿD%:ÊËí·áL*yÊI0BÀžÙ9?…vâk:1ƒŠM¾äà0°Ä9ûI4£m¾cE®“ÿ@­ðÓ ?û%\M#O8ÿ‰6“ÿ‚è?øŠ«{eö-@¨’O8…ʨ¾GãZ~"Bž¸1É$L^%ß”` ŠGô¬èâyÔœ¢´/ƒ…GNM©_‘«§èC¨ß¢é…ŒCù-hŸh™ÿ&™ÿ€qÿñ5Í=âx7Wò –öòÖ{F”[OrÓ2Ì%Ž4ÚòÀ9“'n@çB÷Å×úgÚ-ï´X´c{P[ÞïŽDž_)HvE † ®:sÏ))5e¿ùØÂ1j7f¨ðæ‹ÿ@]3ÿãÿâi¯áÍŽ4]3ÿ£ÿâk:_\\.-&ÜëKq,2@פ@ªˆŽ_ÍòòF%frÞÄÖCxÎQ{i«\ÚÜAv€’Â)L»åŠæ(— ù‰9ÁÇ$Óþ¼®W+þ½lo é[óý¥ãþ¼bÿâjoøG4qütÌÿ×”_üM/†µËr;¯¶iSXI(£˜$€ŒåL±Fă~\täæ¹›xä²ðü~ RÔ>Ûý¤bdšòYb™ZèÅåùnÅW‚*Ù_ÈFÓøwLÏ6—ÿ€ñ4ßøGôßúiøÿTnÛ{—µ¼I¥òÙâÀ ³@<œìgÁR­Cqã[Ý#FÒæ½Ó­î®$µK‹´·šgxÐü°?9A@'¤¤ž‹Ëñ¿ù ¦·óü-þf‘ðþŸùiøÿM:Ÿÿ@}/ÿ"ÿâjÇõ}7ÃÞ[êéÏ}2Z%ËÌ"ò·Ÿ™ÃT G¸•¢ø¦Yü?£Edj÷³O-ƒÎn‚£<*Ù° Áp ù…4Ó¿õýtVþ¿¯3F?é¤ó£iøÿV[úNÞ4]/?õãÿYV9ûeÜÌt‰`ÓV9/¦YÒ0<ÈÍTàૹéǦ¯…|I'ˆ¾ÝÆœÖsZ2¿½Ã«.AlQ·b>î= ¡I5pjÛÂ=¦ÿÐKÿÀ¿øšTðtm/ÿbÿâiž±“V°¶ñú¥ø»¸f‘âY± +&Hò|£•ploÈ?7QY^ñ]í¿‡´Ñ«ÚÅË¥Éu åÅéc/•°1—ä;Þ ¹ÇP).¥r>†ÄžÓ3Æ¥ÿà _üM8øwKÙÿ m/?õãÿY–Þ:½ºˆF¾ÿOmA,VšHî„È™aGm üFî»kâ«íDÅke£Búˆ3ý¦)o +GŠ_,íq.KtùGÉ Ì¿¯K’âÒ»þº XgKÿÀøšOøGìüÁ´¿ü‡ÿ‰¬öø‡$–öRZxvêæIl⼸ŠšVŒIœ"áefù[ï˜ÇNz㢲ÕÞóÄ7zd¶ÖÖÂ.‰%ÏúL‹ù[1åœýàçž RiôŒ×ÐôЇþ$Ú^ëÂ/þ&¨K£ÙŽš>•ÿ‚øøšíd‰qÒ«< Ž•i'ÐͶq­¥Úÿ +ÿðÿñ/öe—ÿ }/?ö‡ÿ‰®ŠX=)žRúUr®Âæg8šm™“HÒñÿ`øøššM*Ëo>—ÿ‚øøšÜòPâŸå¯¥>UØ\ϹË2Ûwü‚4¬Ø:þ"žtË]¿òÒÿð_ÿ]/’ž”¢ô§Ê»3îsK¥ÚwÒ4¿üÃÿÄÐúe S#KÏýƒáÿâk¦òSÒƒ +ÂŽXö3îrcO¶gHÒ¿ð]ÿW—I°dñ'Ò³úÃÿÄÖá¶CÚ¤X””¹cØ9Ÿs™:M˜—ÙV?ìÿW§lçFÒóÿ^ÿñ5·ä¡9Å;Ë\cr®Ãæ}ÎhèöYÿ>•ÿ‚øøšô«0À JÿÁ|?üMu>RúRyNqK•vfsK²UÉÑ´¯üÃÿÄÓ#ÓlœÿÈJÿÁ|?üMu/n¬1ŠÕŽUØ|ÌÃFÓˆçFÒ¿ðþ&št]?þ€ÚWþ áÿâk£¨íA‰})r®ÁÌÎe´kÚ6•ÿ‚øøšaÆtm+ÿðÿñ5ÒùKéHb_J\¨wfö&™ÿ@m+ÿ!ÿâiCÓNâK¥à?üMnùj*dEr¡Ýœúè:f9Ñt¯ü‡ÿ‰©S@Ò‹ èšWþEÿÄ×@#_JpE©YÙ›‡tB>mKÿÀ(¿øš“þÝ þ€z_þÇÿÄÖ€¥¢Èwfwü#šýô¿üÿ‰¥ÿ„sBÿ —ÿ€qÿñ5£KJÈ.ÌßøG4/úéøÿGü#šýô¿üÿ‰­*)YÙœ¾ÐKý‡¥õÿŸ8ÿøšâ´¨´¿ìm?~™¦»›HK3ÙÄÌÄ $’W$פ!ù×ë^kkö &•GÙaÜx"5~`×.&N)Xôrúq©&¤wB ÿÌ'JÿÀøšŽÊÍu x&µð΋:Ìæ/ÝÁ`qÉÙ“‘»§ܹäÒÚÿþ{Ëÿ}ÕÓ/N²’Ó§ºkÁ·Pyd ¹0@HðÝ·N3í‘·ž^fùßâwb°Ê^É]ú¶ßÙS wi)Ù!@ðÚFñ¾1ʱŒdg#8íÆF HbÒüÂt¯ü‡ÿ‰®I­nÕa–éa H·¶v’3ÛŽ¸íÒ¡6º‹0 <ÄžÁC­.f‘¬p”œv¿¥ŽÑ<5§_øR{›{h­o#ží£š ÷g@À+€;˜â¼¿þ ç©ü{‡C¯fÞI%ïŽOpg”ƒùWÍ[Ï­zV¼>y¶ªÊ?×SÝ´è7hšIÿ¨u¯þ‰JbØÝ,âdX0q“Ðç4û+¡mákü")v“ÛmÃcô®»þmKþ‚ZwþIÿÇë§ +sŒUKè,"­ MÒIß{œØ.šs3…,[yÁêsšÖ½Šë'³ºVh$Æà®Èx Œ2AÈ lÿÂ+©ÐKOÿÀ ?øý#xORnº–Ÿÿ€ñúÎ’¡M4®ïܼM|F#•É%nÅ=+BÒ>ÇylöÍ:^®Ë–¹™çyW +]ض8ÀÉ#“ZxgG<‰¥/4S4—RÍ!h˜4ywbØV œrxäækmT¶ûºŽžíÆOþ=VN›«ÿ! üþ=JS‡5âgÎÖf.·áènU¦±Ó!šî[“q$©OfÊÆ1e’%fUPT`dóQhÞÓtý + ëxgu‚â +XFy<É#QÇË$g +:W@4íXÌBÃÿŸÿR>™«8Çö…‡þ?ÿ¨Rõ÷iôë{}*&†Þ[·VmÄÜÞKpAéÁ‘˜ì8ªvžѬïî('i#‘åf»–Xâv$³$nÅQ¹<¨“ëWÿ±µLçûBÃÿ¤ÿãÔÿìWþаÿÀ'ÿãÔsD\²2¢ðþ‰m©}½-äó¶HНs+F‹'ß bŠ9À¾ðýͬvòAtÑ"ñöùÆôRYUÈ|º©'²'­fеF?ò°ÿÀ?øõCÕGMJÃÿdÿãÔ'°í!ó[ÚÜ^ÚÞJ›§µä±c„Ü0N3‚p1“ÓŸSU×JÓSRmEmñtÓyåÄÌž_—»ÇÜtýj_ì-[þ‚Vø'ÿ èZ©ÿ˜•‡þÉÿǨ戹dR‹ÃúL-s²)ü«â[sw)€ï9b"-±I99“ëV4}'NÑdº’Égón™Zy'º–wr£-#1àqS.‡ªù‰Xà Ÿüzì=W9•‡þÉÿǨR‚Y2ü=¤Å¨µüQM/œÑ%Ô« Iýóo,¶yÎÜçž¼ÒŸhÆÒÖÔÙƒ ­»ÛB†F;#m¹yû‹ÉäcƒSÿbêÿô°ÿÀ?øõ;û#WÆ?´¬?ðOþ=EákÓ(ÙøoF°˜K 3¼ßiFYîå™Ì¡ a‹;~RF›®øz)V1¦éV²È^gy%Ôçµ`emÎ3±ufä¡!xznVδ¬?ðOþ=Chz«ÌJÃÿdÿãÔ7ù“¦øOM³ÓtÈ$’àÝXÚÇln-®e¶óBô #a¹s’g>¦´àÒìmõ95Étá†ùîd” c’]ˆ@p8PÐRÿ`êßô°ÿÀ?øõ=t]Yæ%aÿ€2ñê®xnO,Ë &{ÔeïQ¶‰«7üĬ?ðOþ=MþÂÕè%aÿ€2ñê¥R(^ÎA(ÍSi•[«ŸØZ©:•þÉÿǪð¾ ç'Q±ÏýyIÿÇ©ûX‹ÙÈ`u#­(aëNÿ„cQÿ •þIÿÇ©G†µ!ÿ1+ü“ÿQí¢ÊCKÞ•X”ÿøFõ×Q±ÿÀ)?øõHš¢Ÿòÿcÿ€Rñê=´CÙHŽŠ±ý‹©Ïýþ?ÿ£ûRÿŸûüþ=G¶ˆ½”Šôµ?ö6¥ÿ?ö?øÿüzìmOþìð ÿøõÚ!ì¤CKScêóÿcÿ€OÿǨþÇÔÿçþÇÿŸÿQí¢ÊDTT¿ØúŸüÿØÿàÿñê?²5?ùÿ±ÿÀ'ÿãÔ{XÙH4´ÿìOþìð ÿøõ/öF©ÿ?ö?øÿüz—µˆ{9ÑRdêŸóÿcÿ€OÿǨþÉÕ?çþÇÿŸÿQíbÎDt•/öF©ÿ?ö?øÿüzìSþìð ÿøõ/iû9R«Sÿ²5?ùÿ±ÿÀ'ÿãÔ¿ÙŸüÿØÿàÿñê=¤CÙÈ‘4úˆiz¨éaÿ€OÿÇ©³µoùÿ°ÿÀ'ÿãÔ½¤GÈÉ)j/ìí[þ‚øÿüz—û;Wÿ …‡þ?ÿ£Ú äd”µö~­ÿA üþ=Gö~¯ÿA üþ=GÅóÕîcÂ5¦á¾ÿÁ•Ïÿ¤ÿ„cJ?z;ÖÕµ’Ô0kkû7VÿŸûüþ=Iý›ªÿÏþŸÿ€/ÿǨµ>ÁÍS¹Ní"xac‰ dDEUBàA_(n5õ{H÷Û˳ÌAq)(Ι“ŒíÎ2z×ÊX­eð¯ŸèsÃø²ô_©ïÙÈ| óì%ÿÒZõºáí OøV°¶9þÄ_ý]ÅMióXÒ”9nV±©lØé\¶–óÜÛÏt×P4ê&‰vWC’fvî6‘ƒœŽ~ïÇ·6K5¤r˾«4þZ>ÙM‹˜ÈÏ”°Û˜°\lù‹¬MNòŠÃƒÄúdb(/uÒámijK%¼–ñ+y~c_ˆßf_ÊfީɪòxÓOûV›]»Þ^­£Ç5¬ÐËè¥uÄè¡1Ý€¼1ÏÈÔÒQ\ýö¼öÚüÖ&X-­íâ³v’HZS#ÜÜ4H€)Õ²ä癜!¬hÞ)ѼA°éwžzÉš6òTã% i![nv1 +ØûSºÓbba,MŸûÆ“qìíò„\yƒæ;~` ¿ðšøsþ‚°þMþÂkáÏú +Ãù7øVýÿ ¯‡?è+äßáGü&¾ÿ ¬?“…oÑ@ðšøsþ‚°þMþÂkáÏú +Ãù7øVýÿ ¯‡?è+äßáGü&¾ÿ ¬?“…oÑ@ðšøsþ‚°þMþÂkáÏú +Ãù7øVýÿ ¯‡?è+äßáGü&¾ÿ ¬?“…oÑ@ðšøsþ‚°þMþÂkáÏú +Ãù7øVýÿ ¯‡?è+äßáGü&¾ÿ ¬?“…oÑ@´Ý^ÃWä°¸¢¬Ê¤}2E]¦õïþêÿ3O Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( a?ä¨×kßý%|©_UÆ?âE¨×kßý%|§[Ëà_?Ðçñeè¿Sé˜eÛðÒû/þ“×u\D0nø_ÿ¨ÿÒzíë)DÇÕ´›Ë­FÓRÓo`µ¾¶Š[pnmŒñ´rÙ¾Ut;³`îÆ7prǹð/ÚtÉmN£¶I´ýJÖY/dYÕwpªÊØRIÁ¶FOaEIG7«xQµ‹ûæŸR’;+Û),投e(èWnþ…,ê +³aö3!§¥ø4éíîÐéV×P]Çp«¦éKk I#!”331I¤—À!^?aErúŸ‡®5\L[e¬ñi µí.šrŒ ç#8ÚÙÆ5ÃÙ_ØéžoöF”Úoú­¾nï#çêvÿ¨éÏÞëÇ=ÃÞxBálæŠý¿µôÄ»»º‹N³·NæäÌ®­+̨K™:<)Œ!ð#\é©ý«¨É.§ye=¶­p~gŠ$Ç…P…|ˆ‚¸Ú§*Y·ÒŠâàð#[éw–öòèÖsܼd‹ mà!7,«'š\ÜeR¬ˆWmú–f£Š.ïšlÛ›KKF’áU¤¹ò„ìÎ6©–™9ÇTq°­]QEQEU=[þ@×ßõï'þ‚jå2h’xd†EÝŠU†qx4ÇÙhÚÅݦƒ¨Øê–1Go¦Â±Ay`óˆ¤(CH¥fO˜© ’ 0`oÚø^k}RÞF¿ôûKÛBÚnD¢i¼ÝûäÞC'ïåÀ¤|™cƒ»z;Xa‰"‰JFŠQX€ tvÿ)}_þû?ã@¢™å/«ÿßgühò—Õÿï³þ4ú)žRú¿ýöÆ)}_þû?ã@¢™å/«ÿßgühò—Õÿï³þ4ú)žRú¿ýöÆ)}_þû?ã@¢™å/«ÿßgühò—Õÿï³þ4ú)žRú¿ýöÆ)}_þû?ã@¢™å/«ÿßgühò—Õÿï³þ4ú)žRú¿ýöÆ)}_þû?ã@ÿ^ÿî¯ó4újƨIÉë’Oó§PEPEPEPEPEPEPEPEPEPEPEP1ÿ‰¡ÿ]¯ôt•ò•}a ðj?õÚ÷ÿGI_'î³øÏô9ãüYz/Ôú~ÚîðÆóób/þˆ®Ö¼†+·‰3Çöÿé(¯^¢µ>Ky—J|×ò +(¢±5 +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¦M*A “HÛcK1Æp&€E`ÂkáÏú +Ãù7øQÿ ¯‡?è+äßá@ôVü&¾ÿ ¬?“…ðšøsþ‚°þMþ¿E`ÂkáÏú +Ãù7øQÿ ¯‡?è+äßá@ôVü&¾ÿ ¬?“…ðšøsþ‚°þMþ¿E`ÂkáÏú +Ãù7øQÿ ¯‡?è+äßá@ôVü&¾ÿ ¬?“…ðšøsþ‚°þMþ¿E`ÂkáÏú +Ãù7øQÿ ¯‡?è+äßá@ôVü&¾ÿ ¬?“…ðšøsþ‚°þMþ¿E`ÂkáÏú +Ãù7øQÿ ¯‡?è+äßá@ôU-7W°Õãy,.è‡k2©L‘Wh¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(˜†E]QCœ™¯ôtµò~+ê´?ñ&¿ÿ®×Ÿú:Jù_5»^âùþ‡<_ïeè¿SÝ¢„Äê¿úJ+׫ȢœD¿õ_ý%ëµx›Ú>BÞñ‡âmcRÑmmî,4ëKÄ’â+wÞ4ZYR$#¾FçÉé€8ÏJÐMB‘ú{K{°‘¡†Ò6Ĥ†pUIq ñUõý6mWNŠÞ]/m. r@ÛÄr°àv¡ß:Ö£¥¾¯ã}°‰ÒÑb¶}BI-ÙA{y„öÉ ¶îi$.Fü ò1¹NƒrÏĺ¡ouqe­é·0Z&û™!ºGXWåÈ8Q…''ÐúUËû=NÎ;Ë ¸.ídÎÉ H‚AÃ#ð¯7Ó|#­ëžÐQ‚ >M?J·†VêQ$¤Im10DkvÿF òï*\‘ÊÝ%¯„åkšLæ;Iõ„™deºšôÆ^f’bBƒÑ\q¸€\ŸÆ:?•§Ia¨XßG}¨&ž“Ev†%©rÆ~mªv¯VfAÀmÂOø§Mð¦s{{uh“¥¼²Û[Mr±5Ë"çbg’IÀà¼8¬´ðö±}â«-~ý,m¤†XƒÛApó.8nÔ0se‹]—h&wpø{XÔ?¶¿²RÆ_í(i²}®ááò6ùØq¶7ߟ<ðvã`äîàcRñF¦Eªy—ÐMu¦Z=åÍ”2£N±ªî'fr2Æp>aÏ5a5ÝKË[8õ[º»ˆOm +Ü!y£ è¹Ë.9pk‹×¼ ¬ëÚŒ‰qwÙä{¼Þ5üìV9mæ‰lñå)O5FàÀ°BN ‘W5 ëú¶­ks+@Ñ‹»;’«:%ªÅ$nñ,*ž\ù(äHû[ç"ÐiðÝ[Åqo,sA*ŽHØ2º‘AG9©*8 Ío\Gs”D˪¶9ˆŒ÷ÀÏ ©(¢Š(¢Š(ªz·ü¯¿ëÞOýÕʧ«Èûþ½äÿÐMfiÚ¶›£x?G¸Õ5 KÖY.¦X”·–bp DZ­·Ùÿhÿg}®·y^Ù¼ÁæyyÛ¿o]¹ã=3\¤š^§©xcÃæÅüÈc²O6×ûFkìQ6¿/ò€Ãf6¶üžPVtÔŽ‡<ºlP6Ž,æ¸Cç}—ìûÄd¼ß½ ¥£>[!º€uø£M—Mûv—ªh×p‘WÔU" ±4˜Þ¡†@PHì››¸:—Wöv>GÛ.à·óåX!ó¤ æHßu=XààMq~%ð¾½â>O>ßF²»),CÊ™å,­iuî”Æ¤€÷…Ùò€ç,[hÜñ>y«}”Ù%‰eßt¾‚"XÈ4,|©"µ ã{;§‹P±ŠêníÖ Ë´„™-Ë 2~bªN Áˆç©­¦ÜÞ›(5 InÂ3˜eg +®cc´à8*Obë\}ÿ‚µ+‹]JÖ)í6Me¬[Âîì kÙc•K §hV§ä?ÄUcÕ¼òøf{C$ûõ Núêh!i]’â+¤RFé$ 4co}˜àd°Ó5Ý[ó²u[ÿ'gÙ.]™Î3´œg¯¡­ +ãü'u©êÞ!Õõ‹í3ìPÉikkýðÞѼìÜMOÀ•yÛ·ž@ì(¢Š(¢Š(¢Š(¢Š(…äÐZÇ=ÍÃÅ1eä–\E + $ž€ œÖM—м9©]¥¥Ž·¤]\ÉÁs»`dáAÉàøV¥Ý孼̓\Ãç;]À8Àçšå|?áŸøcSÔ5 %l฾|¹®#^2‘áBFìçÐ(b×ZñbIþÐaøP+£®kÂL¯>¸èÁ•µ ƒFÅ®–€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€9D_ø’ߟúmyÿ£¤¯•±_V'ü€õúíyÿ£¤¯•ky| çúÑþ,½ê{ê•ù<ÏJ±c¥ø_S³ŽòÂÇG»µ“;&‚¤FÁ á€ÁÁ~û[Mÿ …§ýþ_ñ£û[Mÿ …§ýþ_ñ®R×Uð-ÝGáÖÓì-íå—PW¢ +È»±…#Ë^§ã[‰/‚ßQšÏìš:ùZ|z—œÑÂ#{w.<Ånê6d·@yæ€7ÿµ´ßúZßåÿ?µ´ßúZßåÿ¡c¥ø_S³ŽòÂÇG»µ“;&‚¤FÁ á€ÁÁ~cþÍþ€Úwþ§øPÿÚÚoý-?ïòÿÚÚoý-?ïòÿAÿæ‡ÿ@m;ÿSü(ÿ„sCÿ 6ÿ€©þ?ö¶›ÿA Oûü¿ãGö¶›ÿA Oûü¿ãPÂ9¡ÿÐNÿÀTÿ +?áÐÿè §à*…Oý­¦ÿÐBÓþÿ/øÑý­¦ÿÐBÓþÿ/øÔðŽhôÓ¿ð?ÂøG4?úißø +Ÿá@ÿki¿ô´ÿ¿Ëþ4ki¿ô´ÿ¿Ëþ5ü#šý´ïüOð£þÍþ€Úwþ§øPÿÚÚoý-?ïòÿÚÚoý-?ïòÿAÿæ‡ÿ@m;ÿSü(ÿ„sCÿ 6ÿ€©þ?ö¶›ÿA Oûü¿ãGö¶›ÿA Oûü¿ãPÂ9¡ÿÐNÿÀTÿ +?áÐÿè §à*…Oý­¦ÿÐBÓþÿ/øÑý­¦ÿÐBÓþÿ/øÔðŽhôÓ¿ð?ÂøG4?úißø +Ÿá@ÿki¿ô´ÿ¿Ëþ4ki¿ô´ÿ¿Ëþ5ü#šý´ïüOð£þÍþ€Úwþ§øPÿÚÚoý-?ïòÿÚÚoý-?ïòÿAÿæ‡ÿ@m;ÿSü(ÿ„sCÿ 6ÿ€©þ?ö¶›ÿA Oûü¿ãGö¶›ÿA Oûü¿ãPÂ9¡ÿÐNÿÀTÿ +?áÐÿè §à*…Oý­¦ÿÐBÓþÿ/øÑý­¦ÿÐBÓþÿ/øÔðŽhôÓ¿ð?ÂøG4?úißø +Ÿá@ÿki¿ô´ÿ¿Ëþ4ki¿ô´ÿ¿Ëþ5ü#šý´ïüOð£þÍþ€Úwþ§øPÿÚÚoý-?ïòÿÚÚoý-?ïòÿAÿæ‡ÿ@m;ÿSü(ÿ„sCÿ 6ÿ€©þ?ö¶›ÿA Oûü¿ãGö¶›ÿA Oûü¿ãPÂ9¡ÿÐNÿÀTÿ +?áÐÿè §à*…Oý­¦ÿÐBÓþÿ/øÕ˜¦ŽxÄÈ’Fz20 þ"³ÿáÐÿè §à*…]µŽ8mÖ(‘R4%U`(àØPÔQEQErÉÿ MCþ»^èé+åjú¡ä ¨×kÏý%|¯]øÏô9£üYz/ÔõXÜ5Ï]ôW¾×ÏÊâUÿ¨*ÿé ¯ klnÐô# ¼ýNY²Ö?á!Óum&ÚÆçìö—6ÒEwtð¬xX0+çI uŸyáN-2ÎÚÊçíJ²ÜOu¾›NÍ4†S"Ég +¬ÒÈ!Á,J{ ++„ì<ÿLðf·¤xmtØn ‘Ù$™"»–ÛÎ1Ú¥»Åç"ïCE×–å +¨É=„4«ýE±À1,ó†ŽîKƒ™g–M¥C6“ç<±-1“ÐQ@Q@Q@Q@Q@Q@R:–FPÅ  ¸È÷â€8Ûòî^[¥ÙÖÊØ\4 —*˜u0VO›Q¢`XÈiGà½aí´KYžÅ#Ðâ¶µ·‘&v7QÇsk#;)Aå¶Û^¾7¹=ŵšZZÃmºC +Ñx8P0Hô©|¶ÿžÏùð  Pðýì1!¸€yRßNM$e̺„7q¨u“+Rã•' 6+R×Âr¿„5Í&s¤úÂL²2ÝMzc/ˆ3I1 !Aè€ .8ÜzŸ-¿ç³þCü(òÛþ{?ä?€8«­ ÄúŽ£}¨Ì–6­4V°›KMReóÒ#pH7 ¼_4Èß(9òÊžÕ}#ÁšÞ—§Þ¬WPEqyWT»•Ê…¼žq˜®ó¾;‡C.¡]À1Šg–ßóÙÿ!þymÿ=Ÿòá@¢™å·üöÈ…[Ïgü‡øPè¦ymÿ=ŸòáG–ßóÙÿ!þú)ž[Ïgü‡øQå·üöÈ…>Šg–ßóÙÿ!þymÿ=Ÿòá@¢™å·üöÈ…[Ïgü‡øPè¦ymÿ=ŸòáG–ßóÙÿ!þú)ž[Ïgü‡øQå·üöÈ…>Šg–ßóÙÿ!þymÿ=Ÿòá@¢™å·üöÈ…[Ïgü‡øPè¦ymÿ=ŸòáG–ßóÙÿ!þúd?pÿ¼ßÌÑå·üöÈ…*.ÅÆI䜚uQ@Q@ªÿÈPÿ®×Ÿú:Jù^¾§_ù_ÿ×kÏý%|±]øÏô9¡üYz/ÔõEþ%Ÿú‚¯þ’ +÷êðhÜcÂ?ê +ŸúH+ÞklnÐô' ¼ýBŠ(®¬(¢Š(¢Š(¢Š(¢Š(¬CÄú>™vmnîöÌ T‰ßnzgh8=ñ×zÕoøMü?ÿ?²à,¿üMl°õ¤® þæfêÓNÎKï: ++Ÿÿ„ßÃÿóû'þËÿÄÒÂoáÿùý“ÿeÿâiýZ¿ò?¹‹ÛRþe÷ ÏÂsáßùþü—ÿ‰£þÏìŸø /ÿGÕ«ÿ#û˜{z_̾󡢹ïøN|;ÿ?Ïÿ€²ÿñ4xxu½“ÿeÿâhúµäsoKù—Þt4W;ÿ χGü¿?þKÿÄÕÝ+ÄzNµ4Ø]‰ew222tÈ GN2=E)aêÅsJ-/F5Vœ”—ÞjÑE‰ QEQEQEQEQEQEQEQT5=gOÑÒ7¿¸ ³³c¯ + ÀãžœQYßð›øþdÿÀYøšÖ4*Í^1mz*°‹³iÏÿÂoáÿùý“ÿeÿâi?á7ðÿüþÉÿ€²ÿñ5_V¯üîdûj_̾󡢹ãã·Òà,¿üMðœxxô½“ÿeÿâhúµäsoKù—Þt4W=ÿ LJ‡ü¿Iÿ€²ÿñ4Âoáïùý“ÿeÿâhúµäsoKù—Þt4W;ÿ χçùÿð_þ&¥µñ–{y¬7ÿ¾•¶ xd@Oa–P2zy/—'þ\%ÿÑ‘W']_Ã?ù¥ÿ¯ôdUǘºÏÐéÂ'®QEñ§¾QEQEQEQEQEQEQEyÿÄ© SéDu1Î?X«ÏÞêBxjîþ)q.‘þìÿÎ:óÚúÜ®)ábߟæÏ ÿ|þ_‘''÷ªýÆ%¼Oæ^Úùñ¨g¶ÞÁÔqÆHÚO#€IöàÖh8 úVÜÿÙ·:›j/©Ie˜c¼ä%aœmçÛNºš5m½ #ªf&ãJ$8Åu÷Þ „XÈaÔ¯|·T’ˆã n—p¬xà}MW:¼Rá­õSg11½Ä¥ÇîÔpâ? €wu¬£^m]ÂßùéE;s_yÎÚA%åä6Ñ•+„RÇŒ“Žj"ÍО•Ø[ëö) šùÐ%¼f,ÂRbêÊÀ³í åŒàœ€O8Ç&¸æ9bG­iJr›|ѵ‰œTR³¸"¬é OˆtžåþßÿF­U«:?üŒZWý[ÿèÕª­ü)z1Rø×©ïÔQE|1ôEPEPEPEPEP&?äÿ]¯?ôt•òÍ}J?äÿ]¯?ôt•òÕtÏàÏô9¡üYz/Ôô…ÿ8¿ì ŸúF+èªùÕãÎ/û§þ‘Šú*º1ûSô2Áo?P¢Š+Î;‚Š( Š( Š( Š( <ñOum[Ä……Å—•8BVvde!Bã…9(9ã®1ÆN?ü+OÿÏ}/þÿIÿÆëÖè¯Fži‰„TÑy²ÁÒ”œšÜòOøVž#ÿžú_ýþ“ÿÑÿ +×ÄóÛJÿ¿ÒñëtUk⻯¸Ÿ¨Ñìyü+_Ï}+þÿIÿÄRÿµñüöÒ¿ïôŸüEzÝkâ{¯¸>£G±äð­øŒË}(ÿÛi?øÝzÝkâ{¯¸>£G±äð­|Iÿ=ô¯ûý'ÿKÿ +×ÄóÛJÿ¿ÒñëtQý¯‰î¾àúÇ‘ÿ´ñ'ü÷Ò¿ ¤ÿâ*æ“ðçZ·Ölnnîtõ‚ ÒfòÝŽÆ @ä€:ñœóÒ½BŠ™f¸™Eŵ¯‘KE;¤QEyÇPQEQEQEQEQEÉù_ÿ×kÏý%|µ_Rù_ÿ×kÏý%|µ]3ø#óýX^‹õ=%kHUA$èÈÏÙ{ü%¾ÿ¡‡IÿÀØÿƾt°ñ%œvvðÞÎÖ—vÈ#Y‚±WE_»’*÷ü&Ÿô2?þGÿâkÑ«FãÍ++TëÊ‹’ånï³=÷þß ÿÐäÿàlãGü%¾ÿ¡‡IÿÀØÿƼþûOúÿ#ÿñ4Ÿð—ÚdÅHÿùÿ‰¬>£Oþ~#_¯Ëþ}¿¹ÿ‘ôø›@»®i­ô»ŒÿZqñ†:ë:wþ'ø×é?´{emfi²J˜­–ø£áÞŸÚ3ãþ¹?øW4ðê.ÊKïFñÅ]]ÅýÏüG#ÐÏMgNÿÀ¤ÿ_øH´Oú éÿøŸã^{Å_ ¯Þ¿¸?öÅÿ¦ÿ…±áùý¸ÿ¿Qì|×ÞŠúÂìþçþGyÿ ‰ÿA?ÿ“ühÿ„‹Dÿ ÎŸÿIþ5ÁÿÂØð¿üþÜ߇£þÇ…ÿçöãþü=ÇÍ}èX]ŸÜÿÈï?á"Ñ?è3§ÿàRð‘hŸôÓÿð)?Ƹ?ø[ÿŸÛûðô‡â¿†ü¿\ß—§ì|×Þ…õ…ÙýÏüŽ÷þ-þƒ:þ'øÑÿ ‰ÿA?ÿ“ükÿ…­áŸùþ¸ÿ¿/Gü-o ÿÏõÇýùz=‚î¾ôYþëûŸù÷ü$Z'ýtÿü +Oñ£þ-þƒ:þ'ø×ÿ [Ã?óýqÿ~^øZÞÿŸëûòô{Ý}è>³ý×÷?ò;ïøH´Oú éÿøŸãGü$Z'ýtÿü +Oñ®þ·†çúãþü½ðµ¼1ÿ?×÷åèö ºûÐ}e+ûŸù÷ü$Z'ýtÿü +Oñ£þ-þƒ:þ'ø×~+x`øþ¸ÿ¿/L?<5ÿ?÷÷åÿÂ`»¯½ÖºþçþG ÿÂE¢ÐgOÿÀ¤ÿ?á"Ñ?è3§ÿàRyïü-? ÏýÇýùð¤ÿ…¥á¿ùÿ¸ÿ¿/þ{Ý}è>²»?¹ÿ‘èð‘hŸôÓÿð)?ÆøH´Oú éÿøŸã^wÿ KÃô¸ÿ¿/þŸð´|9ÿA ûòÿáG°]×Þƒë ³ûŸù‹ÿ ‰ÿA?ÿ“ühÿ„‹Dÿ ÎŸÿIþ5ç_ð´|9ÿA ûòÿáIÿ Cßô¸ÿ¿/þ{5÷ úÂìþçþG£ÂE¢ÐgOÿÀ¤ÿ?á"Ñ?è3§ÿàRyÐø£áÀä!qÿ~_ü*eø­á9¾¸ÿ¿/þ{5÷ úÂìþçþGÿ ‰ÿA?ÿ“ühÿ„‹Dÿ ÎŸÿIþ5ÁÂ×ðÇüþÜ߇£þ¿†?çöãþü=ÃÍ}è>°»?¹ÿ‘ÞÿÂE¢ÐgOÿÀ¤ÿ?á"Ñ?è3§ÿàRp_ðµü1ÿ?·÷áèÿ…¯áùý¸ÿ¿G°ó_z¬.Ïîäw¿ð‘hŸôÓÿð)?ÆøH´Oú éÿøŸã\ü- ÏíÇýøz?ákøcþn?ïÃÑì<×Þƒë ³ûŸùïü$Z'ýtÿü +Oñ£þ-þƒ:þ'ø×ÿ _Ãóûqÿ~øZþÿŸëûòô{5÷ úÂìþçþG{ÿ ‰ÿA?ÿ“ühÿ„‹Dÿ ÎŸÿIþ5ç¯ñOÃMÒþàÛÿ +gü-ÐBãþü¿øQì<×Þƒë ³ûŸù‹ÿ ‰ÿA?ÿ“ühÿ„‹Dÿ ÎŸÿIþ5çð´|9ÿA ûòÿáGü-/ ÿÐBãþü¿øQìu÷ úÂìþçþG¢ÂE¢ÐgOÿÀ¤ÿ?á"Ñ?è3§ÿàRyçü-/ ÿÏýÇýùð£þŸ†ÿçþãþü¿øQìu÷ úÂìþçþG¡ÿÂE¢ÐgOÿÀ¤ÿ?á"Ñ?è3§ÿàRyïü-? ÏýÇýùð£þŸ†ÿçþãþü¿øQìu÷ úÊþW÷?ò= þ-þƒ:þ'øÑÿ ‰ÿA?ÿ“ükÏ¿áiøkþî?ïËÿ…ðµ<5ÿ?÷÷åÿÂ`»¯½ÖºþçþG ÿÂE¢ÐgOÿÀ¤ÿ?á"Ñ?è3§ÿàRy÷ü-O ÏýÇýùð£þ§†¿çþãþü¿øQìu÷ úÏ÷_ÜÿÈôøH´Oú éÿøŸãGü$Z'ýtÿü +Oñ¯>ÿ…©á¯ùÿ¸ÿ¿/þÂÔð×üÿÜß—ÿ +=‚î¾ôYþëûŸùƒÿ ‰ÿA?ÿ“ühÿ„‹Dÿ ÎŸÿIþ5çßðµ<5ÿ?÷÷åÿÂøZžÿŸûûòÿáG°]×Þƒë?Ýsÿ#Ðá"Ñ?è3§ÿàRð‘hŸôÓÿð)?Ƽûþ§†¿çþãþü¿øQÿ SÃ_óÿqÿ~_ü(ö ºûÐ}gû¯îäzü$Z'ýtÿü +Oñ£þ-þƒ:þ'ø×žÿÂÓð×üÿÜß—ÿ +OøZ^ÿŸûûòÿáG°]×Þƒë ³ûŸù‡ÿ ‰ÿA?ÿ“ühÿ„‹Dÿ ÎŸÿIþ5çð´|9ÿA ûòÿáN_Š~oî?ïËÿ…Áw_z¬.Ïîäzü$Z'ýtÿü +Oñ£þ-þƒ:þ'ø×>+øc½íÇýùz_øZþÿŸÛûòô{5÷ úÂìþçþGA¬š%äˆÁ‘ä»te9 ¦Y ÷×˕Ľ:úÂ[mÉ=ÔªP4ˆT&{œõ¯<ÿ„i?Ùü…ID)')ÊvÓOÔÿÙ +endstream +endobj +875 0 obj +15995 +endobj +876 0 obj +<< +/Font << /F9 148 0 R /F10 154 0 R /F14 830 0 R /F15 836 0 R /F46 842 0 R /F74 854 0 R >> +/XObject << /Im47 848 0 R /Im54 850 0 R /Im61 852 0 R /Im102 860 0 R /Im112 862 0 R /Im119 864 0 R /Im129 866 0 R /Im139 868 0 R /Im170 870 0 R /Im177 872 0 R /Im184 874 0 R >> +>> +endobj +877 0 obj +<< +/Title +/Producer (Amyuni PDF Converter version 4.0.0.7) +/CreationDate (D:20211207150006+01'00') +/ModDate (D:20211207150015+01'00') +>> +endobj +878 0 obj +<< +/Type /Pages +/Count 90 +/Rotate 0 +/Kids [145 0 R 160 0 R 163 0 R 249 0 R 359 0 R 459 0 R 473 0 R 476 0 R 485 0 R 491 0 R 494 0 R 499 0 R 502 0 R 508 0 R 511 0 R 516 0 R 521 0 R 524 0 R 535 0 R 538 0 R 541 0 R 544 0 R 549 0 R 555 0 R 558 0 R 561 0 R 566 0 R 569 0 R 576 0 R 582 0 R 587 0 R 590 0 R 593 0 R 598 0 R 603 0 R 609 0 R 614 0 R 617 0 R 622 0 R 627 0 R 632 0 R 635 0 R 640 0 R 643 0 R 648 0 R 654 0 R 659 0 R 664 0 R 671 0 R 674 0 R 683 0 R 688 0 R 691 0 R 694 0 R 699 0 R 702 0 R 705 0 R 708 0 R 711 0 R 714 0 R 720 0 R 727 0 R 732 0 R 737 0 R 744 0 R 747 0 R 750 0 R 753 0 R 756 0 R 761 0 R 764 0 R 767 0 R 770 0 R 775 0 R 778 0 R 781 0 R 784 0 R 787 0 R 792 0 R 797 0 R 800 0 R 803 0 R 806 0 R 809 0 R 812 0 R 815 0 R 818 0 R 821 0 R 824 0 R 827 0 R ] +>> +endobj +xref +0 879 +0000000000 65535 f +0000000017 00000 n +0000000061 00000 n +0000000167 00000 n +0000000226 00000 n +0000000394 00000 n +0000000555 00000 n +0000000748 00000 n +0000000937 00000 n +0000001134 00000 n +0000001401 00000 n +0000001536 00000 n +0000001700 00000 n +0000001948 00000 n +0000002103 00000 n +0000002279 00000 n +0000002474 00000 n +0000002685 00000 n +0000002890 00000 n +0000003009 00000 n +0000003210 00000 n +0000003425 00000 n +0000003644 00000 n +0000003787 00000 n +0000004000 00000 n +0000004123 00000 n +0000004243 00000 n +0000004452 00000 n +0000004578 00000 n +0000004778 00000 n +0000004965 00000 n +0000005219 00000 n +0000005386 00000 n +0000005570 00000 n +0000005735 00000 n +0000005873 00000 n +0000006005 00000 n +0000006174 00000 n +0000006328 00000 n +0000006464 00000 n +0000006596 00000 n +0000006736 00000 n +0000006929 00000 n +0000007064 00000 n +0000007268 00000 n +0000007627 00000 n +0000007820 00000 n +0000007935 00000 n +0000008094 00000 n +0000008294 00000 n +0000008502 00000 n +0000008703 00000 n +0000008914 00000 n +0000009086 00000 n +0000009249 00000 n +0000009512 00000 n +0000009753 00000 n +0000010028 00000 n +0000010320 00000 n +0000010636 00000 n +0000011016 00000 n +0000011368 00000 n +0000011700 00000 n +0000012028 00000 n +0000012276 00000 n +0000012643 00000 n +0000012881 00000 n +0000013052 00000 n +0000013237 00000 n +0000013368 00000 n +0000013500 00000 n +0000013636 00000 n +0000013776 00000 n +0000013916 00000 n +0000014083 00000 n +0000014303 00000 n +0000014516 00000 n +0000014727 00000 n +0000014899 00000 n +0000015062 00000 n +0000015210 00000 n +0000015386 00000 n +0000015573 00000 n +0000015782 00000 n +0000016017 00000 n +0000016164 00000 n +0000016364 00000 n +0000016512 00000 n +0000016672 00000 n +0000016839 00000 n +0000017038 00000 n +0000017209 00000 n +0000017465 00000 n +0000017674 00000 n +0000017853 00000 n +0000018045 00000 n +0000018184 00000 n +0000018320 00000 n +0000018452 00000 n +0000018704 00000 n +0000018987 00000 n +0000019181 00000 n +0000019354 00000 n +0000019505 00000 n +0000019739 00000 n +0000020028 00000 n +0000020165 00000 n +0000020379 00000 n +0000020644 00000 n +0000020883 00000 n +0000021126 00000 n +0000021263 00000 n +0000021450 00000 n +0000021641 00000 n +0000021838 00000 n +0000022020 00000 n +0000022135 00000 n +0000022381 00000 n +0000022586 00000 n +0000022763 00000 n +0000022946 00000 n +0000023055 00000 n +0000023214 00000 n +0000023385 00000 n +0000023568 00000 n +0000023743 00000 n +0000023926 00000 n +0000024101 00000 n +0000024304 00000 n +0000024507 00000 n +0000024712 00000 n +0000024887 00000 n +0000025073 00000 n +0000025194 00000 n +0000025377 00000 n +0000025576 00000 n +0000025791 00000 n +0000025990 00000 n +0000026217 00000 n +0000026414 00000 n +0000026652 00000 n +0000026781 00000 n +0000026940 00000 n +0000027101 00000 n +0000027272 00000 n +0000027381 00000 n +0000027581 00000 n +0000028242 00000 n +0000028263 00000 n +0000028412 00000 n +0000029068 00000 n +0000030108 00000 n +0000030343 00000 n +0000052994 00000 n +0000053017 00000 n +0000053169 00000 n +0000053893 00000 n +0000055097 00000 n +0000055334 00000 n +0000099486 00000 n +0000099509 00000 n +0000099723 00000 n +0000101909 00000 n +0000101931 00000 n +0000102160 00000 n +0000103831 00000 n +0000103853 00000 n +0000104531 00000 n +0000104676 00000 n +0000104821 00000 n +0000104966 00000 n +0000105111 00000 n +0000105256 00000 n +0000105401 00000 n +0000105546 00000 n +0000105691 00000 n +0000105836 00000 n +0000105981 00000 n +0000106126 00000 n +0000106271 00000 n +0000106416 00000 n +0000106561 00000 n +0000106706 00000 n +0000106851 00000 n +0000106996 00000 n +0000107141 00000 n +0000107286 00000 n +0000107431 00000 n +0000107576 00000 n +0000107721 00000 n +0000107866 00000 n +0000108011 00000 n +0000108156 00000 n +0000108301 00000 n +0000108446 00000 n +0000108591 00000 n +0000108736 00000 n +0000108881 00000 n +0000109026 00000 n +0000109171 00000 n +0000109316 00000 n +0000109461 00000 n +0000109606 00000 n +0000109751 00000 n +0000109896 00000 n +0000110041 00000 n +0000110186 00000 n +0000110330 00000 n +0000110473 00000 n +0000110625 00000 n +0000110773 00000 n +0000110925 00000 n +0000111077 00000 n +0000111229 00000 n +0000111381 00000 n +0000111533 00000 n +0000111685 00000 n +0000111837 00000 n +0000111989 00000 n +0000112141 00000 n +0000112293 00000 n +0000112445 00000 n +0000112597 00000 n +0000112749 00000 n +0000112901 00000 n +0000113053 00000 n +0000113202 00000 n +0000113351 00000 n +0000113499 00000 n +0000113648 00000 n +0000113793 00000 n +0000113941 00000 n +0000114090 00000 n +0000114236 00000 n +0000114385 00000 n +0000114534 00000 n +0000114682 00000 n +0000114831 00000 n +0000114976 00000 n +0000115125 00000 n +0000115274 00000 n +0000115423 00000 n +0000115572 00000 n +0000115718 00000 n +0000115867 00000 n +0000116016 00000 n +0000116165 00000 n +0000116311 00000 n +0000116459 00000 n +0000116606 00000 n +0000116835 00000 n +0000119204 00000 n +0000119226 00000 n +0000120096 00000 n +0000120241 00000 n +0000120386 00000 n +0000120531 00000 n +0000120676 00000 n +0000120821 00000 n +0000120966 00000 n +0000121111 00000 n +0000121256 00000 n +0000121401 00000 n +0000121546 00000 n +0000121691 00000 n +0000121836 00000 n +0000121981 00000 n +0000122126 00000 n +0000122271 00000 n +0000122416 00000 n +0000122561 00000 n +0000122706 00000 n +0000122851 00000 n +0000122996 00000 n +0000123141 00000 n +0000123286 00000 n +0000123431 00000 n +0000123576 00000 n +0000123721 00000 n +0000123866 00000 n +0000124011 00000 n +0000124156 00000 n +0000124301 00000 n +0000124446 00000 n +0000124591 00000 n +0000124736 00000 n +0000124881 00000 n +0000125026 00000 n +0000125171 00000 n +0000125316 00000 n +0000125461 00000 n +0000125606 00000 n +0000125751 00000 n +0000125896 00000 n +0000126041 00000 n +0000126186 00000 n +0000126331 00000 n +0000126476 00000 n +0000126621 00000 n +0000126766 00000 n +0000126911 00000 n +0000127056 00000 n +0000127201 00000 n +0000127346 00000 n +0000127491 00000 n +0000127635 00000 n +0000127778 00000 n +0000127927 00000 n +0000128076 00000 n +0000128225 00000 n +0000128374 00000 n +0000128520 00000 n +0000128666 00000 n +0000128812 00000 n +0000128958 00000 n +0000129107 00000 n +0000129253 00000 n +0000129399 00000 n +0000129548 00000 n +0000129697 00000 n +0000129846 00000 n +0000129991 00000 n +0000130140 00000 n +0000130289 00000 n +0000130435 00000 n +0000130584 00000 n +0000130733 00000 n +0000130882 00000 n +0000131031 00000 n +0000131177 00000 n +0000131323 00000 n +0000131472 00000 n +0000131617 00000 n +0000131766 00000 n +0000131915 00000 n +0000132064 00000 n +0000132212 00000 n +0000132361 00000 n +0000132507 00000 n +0000132653 00000 n +0000132802 00000 n +0000132951 00000 n +0000133100 00000 n +0000133249 00000 n +0000133398 00000 n +0000133547 00000 n +0000133696 00000 n +0000133845 00000 n +0000133991 00000 n +0000134140 00000 n +0000134289 00000 n +0000134438 00000 n +0000134587 00000 n +0000134736 00000 n +0000134885 00000 n +0000135034 00000 n +0000135182 00000 n +0000135331 00000 n +0000135479 00000 n +0000135623 00000 n +0000135852 00000 n +0000137835 00000 n +0000137857 00000 n +0000138647 00000 n +0000138792 00000 n +0000138937 00000 n +0000139082 00000 n +0000139227 00000 n +0000139372 00000 n +0000139517 00000 n +0000139662 00000 n +0000139807 00000 n +0000139952 00000 n +0000140097 00000 n +0000140242 00000 n +0000140387 00000 n +0000140532 00000 n +0000140677 00000 n +0000140822 00000 n +0000140967 00000 n +0000141112 00000 n +0000141257 00000 n +0000141402 00000 n +0000141547 00000 n +0000141692 00000 n +0000141837 00000 n +0000141982 00000 n +0000142127 00000 n +0000142272 00000 n +0000142417 00000 n +0000142562 00000 n +0000142707 00000 n +0000142852 00000 n +0000142997 00000 n +0000143142 00000 n +0000143287 00000 n +0000143432 00000 n +0000143577 00000 n +0000143722 00000 n +0000143867 00000 n +0000144012 00000 n +0000144157 00000 n +0000144302 00000 n +0000144447 00000 n +0000144592 00000 n +0000144737 00000 n +0000144882 00000 n +0000145027 00000 n +0000145172 00000 n +0000145317 00000 n +0000145462 00000 n +0000145605 00000 n +0000145751 00000 n +0000145900 00000 n +0000146049 00000 n +0000146198 00000 n +0000146346 00000 n +0000146495 00000 n +0000146644 00000 n +0000146793 00000 n +0000146939 00000 n +0000147088 00000 n +0000147237 00000 n +0000147386 00000 n +0000147535 00000 n +0000147681 00000 n +0000147830 00000 n +0000147979 00000 n +0000148128 00000 n +0000148277 00000 n +0000148425 00000 n +0000148574 00000 n +0000148723 00000 n +0000148872 00000 n +0000149021 00000 n +0000149170 00000 n +0000149319 00000 n +0000149465 00000 n +0000149614 00000 n +0000149763 00000 n +0000149912 00000 n +0000150060 00000 n +0000150206 00000 n +0000150354 00000 n +0000150503 00000 n +0000150651 00000 n +0000150800 00000 n +0000150946 00000 n +0000151094 00000 n +0000151243 00000 n +0000151388 00000 n +0000151537 00000 n +0000151686 00000 n +0000151834 00000 n +0000151979 00000 n +0000152124 00000 n +0000152273 00000 n +0000152422 00000 n +0000152571 00000 n +0000152718 00000 n +0000152947 00000 n +0000153485 00000 n +0000153506 00000 n +0000153608 00000 n +0000153753 00000 n +0000153898 00000 n +0000154043 00000 n +0000154188 00000 n +0000154333 00000 n +0000154479 00000 n +0000154628 00000 n +0000154774 00000 n +0000154923 00000 n +0000155071 00000 n +0000155284 00000 n +0000158656 00000 n +0000158678 00000 n +0000158907 00000 n +0000162458 00000 n +0000162480 00000 n +0000162542 00000 n +0000162689 00000 n +0000162841 00000 n +0000162990 00000 n +0000163142 00000 n +0000163292 00000 n +0000163521 00000 n +0000164331 00000 n +0000164352 00000 n +0000164390 00000 n +0000164542 00000 n +0000164690 00000 n +0000164903 00000 n +0000167876 00000 n +0000167898 00000 n +0000168127 00000 n +0000170065 00000 n +0000170087 00000 n +0000170117 00000 n +0000170265 00000 n +0000170533 00000 n +0000172894 00000 n +0000172916 00000 n +0000173187 00000 n +0000175960 00000 n +0000175982 00000 n +0000176020 00000 n +0000176168 00000 n +0000176309 00000 n +0000176577 00000 n +0000178110 00000 n +0000178132 00000 n +0000178374 00000 n +0000182494 00000 n +0000182516 00000 n +0000182546 00000 n +0000182695 00000 n +0000182950 00000 n +0000187051 00000 n +0000187073 00000 n +0000187103 00000 n +0000187255 00000 n +0000187494 00000 n +0000189073 00000 n +0000189095 00000 n +0000189324 00000 n +0000191515 00000 n +0000191537 00000 n +0000191615 00000 n +0000191764 00000 n +0000191913 00000 n +0000192061 00000 n +0000192209 00000 n +0000192358 00000 n +0000192510 00000 n +0000192659 00000 n +0000192885 00000 n +0000195781 00000 n +0000195803 00000 n +0000196029 00000 n +0000198436 00000 n +0000198458 00000 n +0000198697 00000 n +0000201337 00000 n +0000201359 00000 n +0000201601 00000 n +0000205508 00000 n +0000205530 00000 n +0000205560 00000 n +0000205709 00000 n +0000205951 00000 n +0000209880 00000 n +0000209902 00000 n +0000209940 00000 n +0000210086 00000 n +0000210238 00000 n +0000210464 00000 n +0000213258 00000 n +0000213280 00000 n +0000213493 00000 n +0000216871 00000 n +0000216893 00000 n +0000217178 00000 n +0000220302 00000 n +0000220324 00000 n +0000220354 00000 n +0000220502 00000 n +0000220715 00000 n +0000224369 00000 n +0000224391 00000 n +0000224650 00000 n +0000227618 00000 n +0000227640 00000 n +0000227686 00000 n +0000227835 00000 n +0000227984 00000 n +0000228126 00000 n +0000228411 00000 n +0000231780 00000 n +0000231802 00000 n +0000231840 00000 n +0000231982 00000 n +0000232124 00000 n +0000232366 00000 n +0000237706 00000 n +0000237728 00000 n +0000237758 00000 n +0000237907 00000 n +0000238163 00000 n +0000240739 00000 n +0000240761 00000 n +0000241000 00000 n +0000245267 00000 n +0000245289 00000 n +0000245561 00000 n +0000248388 00000 n +0000248410 00000 n +0000248440 00000 n +0000248592 00000 n +0000248834 00000 n +0000252220 00000 n +0000252242 00000 n +0000252272 00000 n +0000252424 00000 n +0000252653 00000 n +0000256350 00000 n +0000256372 00000 n +0000256410 00000 n +0000256559 00000 n +0000256704 00000 n +0000256959 00000 n +0000261974 00000 n +0000261996 00000 n +0000262026 00000 n +0000262175 00000 n +0000262414 00000 n +0000266139 00000 n +0000266161 00000 n +0000266416 00000 n +0000269656 00000 n +0000269678 00000 n +0000269708 00000 n +0000269860 00000 n +0000270089 00000 n +0000273260 00000 n +0000273282 00000 n +0000273312 00000 n +0000273460 00000 n +0000273689 00000 n +0000276310 00000 n +0000276332 00000 n +0000276362 00000 n +0000276511 00000 n +0000276737 00000 n +0000280142 00000 n +0000280164 00000 n +0000280436 00000 n +0000282786 00000 n +0000282808 00000 n +0000282838 00000 n +0000282986 00000 n +0000283242 00000 n +0000286090 00000 n +0000286112 00000 n +0000286397 00000 n +0000289750 00000 n +0000289772 00000 n +0000289802 00000 n +0000289954 00000 n +0000290183 00000 n +0000294304 00000 n +0000294326 00000 n +0000294364 00000 n +0000294516 00000 n +0000294661 00000 n +0000294916 00000 n +0000299490 00000 n +0000299512 00000 n +0000299542 00000 n +0000299691 00000 n +0000299946 00000 n +0000304254 00000 n +0000304276 00000 n +0000304306 00000 n +0000304453 00000 n +0000304708 00000 n +0000308673 00000 n +0000308695 00000 n +0000308741 00000 n +0000308892 00000 n +0000309044 00000 n +0000309193 00000 n +0000309419 00000 n +0000312606 00000 n +0000312628 00000 n +0000312870 00000 n +0000316125 00000 n +0000316147 00000 n +0000316209 00000 n +0000316357 00000 n +0000316503 00000 n +0000316655 00000 n +0000316804 00000 n +0000316953 00000 n +0000317182 00000 n +0000319285 00000 n +0000319307 00000 n +0000319337 00000 n +0000319489 00000 n +0000319702 00000 n +0000322871 00000 n +0000322893 00000 n +0000323106 00000 n +0000323959 00000 n +0000323980 00000 n +0000324209 00000 n +0000327282 00000 n +0000327304 00000 n +0000327334 00000 n +0000327486 00000 n +0000327699 00000 n +0000331589 00000 n +0000331611 00000 n +0000331824 00000 n +0000335701 00000 n +0000335723 00000 n +0000335962 00000 n +0000339857 00000 n +0000339879 00000 n +0000340105 00000 n +0000340964 00000 n +0000340985 00000 n +0000341198 00000 n +0000344334 00000 n +0000344356 00000 n +0000344611 00000 n +0000348602 00000 n +0000348624 00000 n +0000348662 00000 n +0000348814 00000 n +0000348966 00000 n +0000349208 00000 n +0000352306 00000 n +0000352328 00000 n +0000352374 00000 n +0000352523 00000 n +0000352675 00000 n +0000352862 00000 n +0000353104 00000 n +0000355328 00000 n +0000355350 00000 n +0000355380 00000 n +0000355532 00000 n +0000355761 00000 n +0000357729 00000 n +0000357751 00000 n +0000357781 00000 n +0000357929 00000 n +0000358158 00000 n +0000360652 00000 n +0000360674 00000 n +0000360720 00000 n +0000360872 00000 n +0000361021 00000 n +0000361166 00000 n +0000361392 00000 n +0000364304 00000 n +0000364326 00000 n +0000364539 00000 n +0000367378 00000 n +0000367400 00000 n +0000367626 00000 n +0000370565 00000 n +0000370587 00000 n +0000370813 00000 n +0000373769 00000 n +0000373791 00000 n +0000374046 00000 n +0000377688 00000 n +0000377710 00000 n +0000377740 00000 n +0000377885 00000 n +0000378124 00000 n +0000381395 00000 n +0000381417 00000 n +0000381643 00000 n +0000384682 00000 n +0000384704 00000 n +0000384930 00000 n +0000387817 00000 n +0000387839 00000 n +0000388094 00000 n +0000391445 00000 n +0000391467 00000 n +0000391497 00000 n +0000391642 00000 n +0000391881 00000 n +0000394220 00000 n +0000394242 00000 n +0000394481 00000 n +0000396706 00000 n +0000396728 00000 n +0000396941 00000 n +0000399598 00000 n +0000399620 00000 n +0000399833 00000 n +0000402401 00000 n +0000402423 00000 n +0000402665 00000 n +0000405687 00000 n +0000405709 00000 n +0000405739 00000 n +0000405913 00000 n +0000406155 00000 n +0000409973 00000 n +0000409995 00000 n +0000410025 00000 n +0000410167 00000 n +0000410380 00000 n +0000414010 00000 n +0000414032 00000 n +0000414245 00000 n +0000417163 00000 n +0000417185 00000 n +0000417411 00000 n +0000420574 00000 n +0000420596 00000 n +0000420809 00000 n +0000422596 00000 n +0000422618 00000 n +0000422844 00000 n +0000424624 00000 n +0000424646 00000 n +0000424809 00000 n +0000424916 00000 n +0000424936 00000 n +0000425149 00000 n +0000427199 00000 n +0000427221 00000 n +0000427447 00000 n +0000429745 00000 n +0000429767 00000 n +0000429980 00000 n +0000431379 00000 n +0000431401 00000 n +0000431614 00000 n +0000433790 00000 n +0000433812 00000 n +0000434025 00000 n +0000435028 00000 n +0000435049 00000 n +0000435206 00000 n +0000435779 00000 n +0000436608 00000 n +0000436851 00000 n +0000462167 00000 n +0000462190 00000 n +0000462335 00000 n +0000462678 00000 n +0000462966 00000 n +0000463193 00000 n +0000466932 00000 n +0000466954 00000 n +0000467113 00000 n +0000467670 00000 n +0000468480 00000 n +0000468724 00000 n +0000490982 00000 n +0000491005 00000 n +0000556614 00000 n +0000556637 00000 n +0000646917 00000 n +0000646940 00000 n +0000733529 00000 n +0000733552 00000 n +0000733701 00000 n +0000734212 00000 n +0000734882 00000 n +0000735115 00000 n +0000750986 00000 n +0000751009 00000 n +0000848043 00000 n +0000848066 00000 n +0000884883 00000 n +0000884906 00000 n +0000949363 00000 n +0000949386 00000 n +0001034186 00000 n +0001034209 00000 n +0001048428 00000 n +0001048451 00000 n +0001125483 00000 n +0001125506 00000 n +0001169328 00000 n +0001169351 00000 n +0001185521 00000 n +0001185544 00000 n +0001185833 00000 n +0001186170 00000 n +trailer +<< +/Size 879 +/Root 2 0 R +/Info 877 0 R +/ID [] +>> +startxref +1186955 +%%EOF diff --git a/Dinkey Pro 7.6.1/Manual/EULA.pdf b/Dinkey Pro 7.6.1/Manual/EULA.pdf new file mode 100644 index 0000000..0ccb349 Binary files /dev/null and b/Dinkey Pro 7.6.1/Manual/EULA.pdf differ diff --git a/Dinkey Pro 7.6.1/Modules/32bit/DinkeyChange.dll b/Dinkey Pro 7.6.1/Modules/32bit/DinkeyChange.dll new file mode 100644 index 0000000..14ef834 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/32bit/DinkeyChange.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/32bit/DinkeyChangeDebug.dll b/Dinkey Pro 7.6.1/Modules/32bit/DinkeyChangeDebug.dll new file mode 100644 index 0000000..7c2f733 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/32bit/DinkeyChangeDebug.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/32bit/dpcom32.dll b/Dinkey Pro 7.6.1/Modules/32bit/dpcom32.dll new file mode 100644 index 0000000..52383f4 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/32bit/dpcom32.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/32bit/dpwin32.dll b/Dinkey Pro 7.6.1/Modules/32bit/dpwin32.dll new file mode 100644 index 0000000..679acac Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/32bit/dpwin32.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/32bit/dpwin32_coff.obj b/Dinkey Pro 7.6.1/Modules/32bit/dpwin32_coff.obj new file mode 100644 index 0000000..9963519 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/32bit/dpwin32_coff.obj differ diff --git a/Dinkey Pro 7.6.1/Modules/32bit/dpwin32_coff_debug.obj b/Dinkey Pro 7.6.1/Modules/32bit/dpwin32_coff_debug.obj new file mode 100644 index 0000000..f0de077 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/32bit/dpwin32_coff_debug.obj differ diff --git a/Dinkey Pro 7.6.1/Modules/32bit/dpwin32_omf.obj b/Dinkey Pro 7.6.1/Modules/32bit/dpwin32_omf.obj new file mode 100644 index 0000000..bbf3f76 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/32bit/dpwin32_omf.obj differ diff --git a/Dinkey Pro 7.6.1/Modules/32bit/dpwin32_omf_debug.obj b/Dinkey Pro 7.6.1/Modules/32bit/dpwin32_omf_debug.obj new file mode 100644 index 0000000..a510ae8 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/32bit/dpwin32_omf_debug.obj differ diff --git a/Dinkey Pro 7.6.1/Modules/32bit/dpwin32debug.dll b/Dinkey Pro 7.6.1/Modules/32bit/dpwin32debug.dll new file mode 100644 index 0000000..c645831 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/32bit/dpwin32debug.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/32bit/import_libs/DinkeyChange.lib b/Dinkey Pro 7.6.1/Modules/32bit/import_libs/DinkeyChange.lib new file mode 100644 index 0000000..7fc1bc4 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/32bit/import_libs/DinkeyChange.lib differ diff --git a/Dinkey Pro 7.6.1/Modules/32bit/import_libs/DinkeyChangeDebug.lib b/Dinkey Pro 7.6.1/Modules/32bit/import_libs/DinkeyChangeDebug.lib new file mode 100644 index 0000000..256c39d Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/32bit/import_libs/DinkeyChangeDebug.lib differ diff --git a/Dinkey Pro 7.6.1/Modules/32bit/import_libs/DinkeyChangeDebug_borland.lib b/Dinkey Pro 7.6.1/Modules/32bit/import_libs/DinkeyChangeDebug_borland.lib new file mode 100644 index 0000000..b3dd1b6 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/32bit/import_libs/DinkeyChangeDebug_borland.lib differ diff --git a/Dinkey Pro 7.6.1/Modules/32bit/import_libs/DinkeyChange_borland.lib b/Dinkey Pro 7.6.1/Modules/32bit/import_libs/DinkeyChange_borland.lib new file mode 100644 index 0000000..61a7187 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/32bit/import_libs/DinkeyChange_borland.lib differ diff --git a/Dinkey Pro 7.6.1/Modules/32bit/import_libs/README.txt b/Dinkey Pro 7.6.1/Modules/32bit/import_libs/README.txt new file mode 100644 index 0000000..d2ea6aa --- /dev/null +++ b/Dinkey Pro 7.6.1/Modules/32bit/import_libs/README.txt @@ -0,0 +1,31 @@ +Import Libraries +~~~~~~~~~~~~~~~~ + +These are used with C/C++ languages so that the compiler knows what functions +can be found in which DLLs. You need to link the appropriate import library to +your source code so that the DLL can be called correctly. + +Microsoft import libraries +~~~~~~~~~~~~~~~~~~~~~~~~~~ +dpwin32.lib +dpwin32debug.lib +DinkeyChange.lib +DinkeyChangeDebug.lib + +Borland C++ Builder import libraries +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +dpwin32_borland.lib +dpwin32debug_borland.lib +DinkeyChange_borland.lib +DinkeyChangeDebug_borland.lib + +Dev C++ and MinGW import libraries +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +libdpwin32.a +libdpwin32debug.a +libDinkeyChange.a +libDinkeyChangeDebug.a + +If you look at the sample code for the relevant language / compiler then it +will tell you how to use these import libraries. + diff --git a/Dinkey Pro 7.6.1/Modules/32bit/import_libs/dpwin32.lib b/Dinkey Pro 7.6.1/Modules/32bit/import_libs/dpwin32.lib new file mode 100644 index 0000000..912ecf0 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/32bit/import_libs/dpwin32.lib differ diff --git a/Dinkey Pro 7.6.1/Modules/32bit/import_libs/dpwin32_borland.lib b/Dinkey Pro 7.6.1/Modules/32bit/import_libs/dpwin32_borland.lib new file mode 100644 index 0000000..f718ac2 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/32bit/import_libs/dpwin32_borland.lib differ diff --git a/Dinkey Pro 7.6.1/Modules/32bit/import_libs/dpwin32debug.lib b/Dinkey Pro 7.6.1/Modules/32bit/import_libs/dpwin32debug.lib new file mode 100644 index 0000000..404b47c Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/32bit/import_libs/dpwin32debug.lib differ diff --git a/Dinkey Pro 7.6.1/Modules/32bit/import_libs/dpwin32debug_borland.lib b/Dinkey Pro 7.6.1/Modules/32bit/import_libs/dpwin32debug_borland.lib new file mode 100644 index 0000000..1d248bc Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/32bit/import_libs/dpwin32debug_borland.lib differ diff --git a/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/Info.plist b/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/Info.plist new file mode 100644 index 0000000..8766a6d --- /dev/null +++ b/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ddpro + CFBundleIdentifier + com.4D.4DPlugin + CFBundleInfoDictionaryVersion + 12.0 + CFBundlePackageType + 4DCB + CFBundleSignature + 4D12 + CFBundleVersion + 12.0 + CSResourcesFileMapped + + + diff --git a/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/MacOS/ddpro b/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/MacOS/ddpro new file mode 100644 index 0000000..fbc3021 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/MacOS/ddpro differ diff --git a/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/Resources/English.lproj/InfoPlist.strings b/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/Resources/English.lproj/InfoPlist.strings new file mode 100644 index 0000000..e8546d6 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/Resources/English.lproj/InfoPlist.strings differ diff --git a/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/Resources/ddpro.rsrc b/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/Resources/ddpro.rsrc new file mode 100644 index 0000000..82763d9 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/Resources/ddpro.rsrc differ diff --git a/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/Windows/ddpro.4dx b/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/Windows/ddpro.4dx new file mode 100644 index 0000000..244d17c Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/Windows/ddpro.4dx differ diff --git a/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/Windows/ddpro.rsr b/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/Windows/ddpro.rsr new file mode 100644 index 0000000..82763d9 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/Windows/ddpro.rsr differ diff --git a/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/Windows64/ddpro.4dx b/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/Windows64/ddpro.4dx new file mode 100644 index 0000000..d2f7042 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/Windows64/ddpro.4dx differ diff --git a/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/Windows64/ddpro.rsr b/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/Windows64/ddpro.rsr new file mode 100644 index 0000000..c6346bc Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/4D/ddpro.bundle/Contents/Windows64/ddpro.rsr differ diff --git a/Dinkey Pro 7.6.1/Modules/64bit/DinkeyChange64.dll b/Dinkey Pro 7.6.1/Modules/64bit/DinkeyChange64.dll new file mode 100644 index 0000000..6f6aa8a Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/64bit/DinkeyChange64.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/64bit/DinkeyChange64Debug.dll b/Dinkey Pro 7.6.1/Modules/64bit/DinkeyChange64Debug.dll new file mode 100644 index 0000000..2c31c44 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/64bit/DinkeyChange64Debug.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/64bit/dpcom64.dll b/Dinkey Pro 7.6.1/Modules/64bit/dpcom64.dll new file mode 100644 index 0000000..e493640 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/64bit/dpcom64.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/64bit/dpwin64.dll b/Dinkey Pro 7.6.1/Modules/64bit/dpwin64.dll new file mode 100644 index 0000000..d3416ae Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/64bit/dpwin64.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/64bit/dpwin64.obj b/Dinkey Pro 7.6.1/Modules/64bit/dpwin64.obj new file mode 100644 index 0000000..2d34def Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/64bit/dpwin64.obj differ diff --git a/Dinkey Pro 7.6.1/Modules/64bit/dpwin64_delphi.obj b/Dinkey Pro 7.6.1/Modules/64bit/dpwin64_delphi.obj new file mode 100644 index 0000000..6ff67c1 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/64bit/dpwin64_delphi.obj differ diff --git a/Dinkey Pro 7.6.1/Modules/64bit/dpwin64_delphi_debug.obj b/Dinkey Pro 7.6.1/Modules/64bit/dpwin64_delphi_debug.obj new file mode 100644 index 0000000..5c567eb Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/64bit/dpwin64_delphi_debug.obj differ diff --git a/Dinkey Pro 7.6.1/Modules/64bit/dpwin64debug.dll b/Dinkey Pro 7.6.1/Modules/64bit/dpwin64debug.dll new file mode 100644 index 0000000..efddc05 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/64bit/dpwin64debug.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/64bit/dpwin64debug.obj b/Dinkey Pro 7.6.1/Modules/64bit/dpwin64debug.obj new file mode 100644 index 0000000..7b37923 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/64bit/dpwin64debug.obj differ diff --git a/Dinkey Pro 7.6.1/Modules/64bit/import_libs/DinkeyChange64.lib b/Dinkey Pro 7.6.1/Modules/64bit/import_libs/DinkeyChange64.lib new file mode 100644 index 0000000..3dc35b7 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/64bit/import_libs/DinkeyChange64.lib differ diff --git a/Dinkey Pro 7.6.1/Modules/64bit/import_libs/DinkeyChange64Debug.lib b/Dinkey Pro 7.6.1/Modules/64bit/import_libs/DinkeyChange64Debug.lib new file mode 100644 index 0000000..5a4f3d7 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/64bit/import_libs/DinkeyChange64Debug.lib differ diff --git a/Dinkey Pro 7.6.1/Modules/64bit/import_libs/README.txt b/Dinkey Pro 7.6.1/Modules/64bit/import_libs/README.txt new file mode 100644 index 0000000..0ef9457 --- /dev/null +++ b/Dinkey Pro 7.6.1/Modules/64bit/import_libs/README.txt @@ -0,0 +1,31 @@ +Import Libraries +~~~~~~~~~~~~~~~~ + +These are used with C/C++ languages so that the compiler knows what functions +can be found in which DLLs. You need to link the appropriate import library to +your source code so that the DLL can be called correctly. + +Microsoft import libraries +~~~~~~~~~~~~~~~~~~~~~~~~~~ +dpwin64.lib +dpwin64debug.lib +DinkeyChange64.lib +DinkeyChange64Debug.lib + +Borland C++ Builder import libraries +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +dpwin64_borland.a +dpwin64debug_borland.a +DinkeyChange64_borland.a +DinkeyChange64Debug_borland.a + +Dev C++ and MinGW import libraries +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +libdpwin64.a +libdpwin64debug.a +libDinkeyChange64.a +libDinkeyChange64Debug.a + +If you look at the sample code for the relevant language / compiler then it +will tell you how to use these import libraries. + diff --git a/Dinkey Pro 7.6.1/Modules/64bit/import_libs/dpwin64.lib b/Dinkey Pro 7.6.1/Modules/64bit/import_libs/dpwin64.lib new file mode 100644 index 0000000..0f71232 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/64bit/import_libs/dpwin64.lib differ diff --git a/Dinkey Pro 7.6.1/Modules/64bit/import_libs/dpwin64debug.lib b/Dinkey Pro 7.6.1/Modules/64bit/import_libs/dpwin64debug.lib new file mode 100644 index 0000000..fe890fd Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/64bit/import_libs/dpwin64debug.lib differ diff --git a/Dinkey Pro 7.6.1/Modules/FileMaker/v14/DinkeyPro.fmplugin/Contents/Info.plist b/Dinkey Pro 7.6.1/Modules/FileMaker/v14/DinkeyPro.fmplugin/Contents/Info.plist new file mode 100644 index 0000000..da2125c --- /dev/null +++ b/Dinkey Pro 7.6.1/Modules/FileMaker/v14/DinkeyPro.fmplugin/Contents/Info.plist @@ -0,0 +1,25 @@ + + + + +CFBundleIdentifier +com.microcosm.dpro +CFBundleName +DinkeyPro +CFBundleGetInfoString +DinkeyPro version 7.6.1, (c) 2021 Microcosm Ltd0 +CFBundleShortVersionString +DinkeyPro version 7.6.1 +CFBundlePackageType +BNDL +CFBundleSignature +Dpro +CFBundleVersion +7.6.1 +CFBundleDevelopmentRegion +English +CFBundleInfoDictionaryVersion +6.0 + + + diff --git a/Dinkey Pro 7.6.1/Modules/FileMaker/v14/DinkeyPro.fmplugin/Contents/MacOS/DinkeyPro b/Dinkey Pro 7.6.1/Modules/FileMaker/v14/DinkeyPro.fmplugin/Contents/MacOS/DinkeyPro new file mode 100644 index 0000000..87c249f Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/FileMaker/v14/DinkeyPro.fmplugin/Contents/MacOS/DinkeyPro differ diff --git a/Dinkey Pro 7.6.1/Modules/FileMaker/v14/DinkeyPro.fmplugin/Contents/PkgInfo b/Dinkey Pro 7.6.1/Modules/FileMaker/v14/DinkeyPro.fmplugin/Contents/PkgInfo new file mode 100644 index 0000000..43c9cb0 --- /dev/null +++ b/Dinkey Pro 7.6.1/Modules/FileMaker/v14/DinkeyPro.fmplugin/Contents/PkgInfo @@ -0,0 +1 @@ +BNDL???? diff --git a/Dinkey Pro 7.6.1/Modules/FileMaker/v14/DinkeyPro.fmplugin/Contents/Resources/English.lproj/Localizable.strings b/Dinkey Pro 7.6.1/Modules/FileMaker/v14/DinkeyPro.fmplugin/Contents/Resources/English.lproj/Localizable.strings new file mode 100644 index 0000000..ded7350 --- /dev/null +++ b/Dinkey Pro 7.6.1/Modules/FileMaker/v14/DinkeyPro.fmplugin/Contents/Resources/English.lproj/Localizable.strings @@ -0,0 +1,34 @@ +/* Plug-In name appearing in FM's preferences dialog */ +String1 = "Dinkey Dongle Pro/FD Plug-in"; +/* Options text appearing in FM's preferences dialog */ +String2 = "This plug-in allows you to do a protection check using Microcosm's Dinkey Pro or FD dongle."; +/* Version */ +String3 = "7.6.1"; +/* External functions prototypes go here */ +String101 = "DinkeyProVersion( version format )"; +String102 = "DDProtCheck(flags {; execs_decrement; alt_licence_name})"; +String103 = "DDProtCheckWithAlg(flags; alg_number; var_a; var_b; var_c; var_d; var_e; var_f; var_g; var_h)"; +String104 = "DDWriteData(flags; offset; length; data)"; +String105 = "DDReadData(flags; offset; length)"; +String106 = "DDGetExtendedError(dummy)"; +String107 = "DDGetType(dummy)"; +String108 = "DDGetModel(dummy)"; +String109 = "DDGetSDSN(dummy)"; +String110 = "DDGetProdCode(dummy)"; +String111 = "DDGetDongleNumber(dummy)"; +String112 = "DDGetUpdateNumber(dummy)"; +String113 = "DDGetDataAreaSize(dummy)"; +String114 = "DDGetMaxAlgNum(dummy)"; +String115 = "DDGetExecs(dummy)"; +String116 = "DDGetExpDay(dummy)"; +String117 = "DDGetExpMonth(dummy)"; +String118 = "DDGetExpYear(dummy)"; +String119 = "DDGetFeatures(dummy)"; +String120 = "DDGetNetUsers(dummy)"; +String121 = "DDGetAlgAnswer(dummy)"; +String122 = "DDGetFDCapacity(dummy)"; +String123 = "DDGetFDDrive(dummy)"; +String124 = "DDGetSWKeyType(dummy)"; +String125 = "DDGetSWKeyExpDay(dummy)"; +String126 = "DDGetSWKeyExpMonth(dummy)"; +String127 = "DDGetSWKeyExpYear(dummy)"; diff --git a/Dinkey Pro 7.6.1/Modules/FileMaker/v14/DinkeyPro.fmx b/Dinkey Pro 7.6.1/Modules/FileMaker/v14/DinkeyPro.fmx new file mode 100644 index 0000000..32e6763 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/FileMaker/v14/DinkeyPro.fmx differ diff --git a/Dinkey Pro 7.6.1/Modules/FileMaker/v14/DinkeyPro.fmx64 b/Dinkey Pro 7.6.1/Modules/FileMaker/v14/DinkeyPro.fmx64 new file mode 100644 index 0000000..f9a96f5 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/FileMaker/v14/DinkeyPro.fmx64 differ diff --git a/Dinkey Pro 7.6.1/Modules/FileMaker/v7/DinkeyPro.fmplugin/Contents/Info.plist b/Dinkey Pro 7.6.1/Modules/FileMaker/v7/DinkeyPro.fmplugin/Contents/Info.plist new file mode 100644 index 0000000..e793f98 --- /dev/null +++ b/Dinkey Pro 7.6.1/Modules/FileMaker/v7/DinkeyPro.fmplugin/Contents/Info.plist @@ -0,0 +1,25 @@ + + + + +CFBundleIdentifier +com.microcosm.dpro +CFBundleName +DinkeyPro +CFBundleGetInfoString +DinkeyPro version 7.5.1, (c) 2020 Microcosm Ltd0 +CFBundleShortVersionString +DinkeyPro version 7.5.1 +CFBundlePackageType +BNDL +CFBundleSignature +Dpro +CFBundleVersion +7.5.1 +CFBundleDevelopmentRegion +English +CFBundleInfoDictionaryVersion +6.0 + + + diff --git a/Dinkey Pro 7.6.1/Modules/FileMaker/v7/DinkeyPro.fmplugin/Contents/MacOS/DinkeyPro b/Dinkey Pro 7.6.1/Modules/FileMaker/v7/DinkeyPro.fmplugin/Contents/MacOS/DinkeyPro new file mode 100644 index 0000000..56ec139 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/FileMaker/v7/DinkeyPro.fmplugin/Contents/MacOS/DinkeyPro differ diff --git a/Dinkey Pro 7.6.1/Modules/FileMaker/v7/DinkeyPro.fmplugin/Contents/PkgInfo b/Dinkey Pro 7.6.1/Modules/FileMaker/v7/DinkeyPro.fmplugin/Contents/PkgInfo new file mode 100644 index 0000000..43c9cb0 --- /dev/null +++ b/Dinkey Pro 7.6.1/Modules/FileMaker/v7/DinkeyPro.fmplugin/Contents/PkgInfo @@ -0,0 +1 @@ +BNDL???? diff --git a/Dinkey Pro 7.6.1/Modules/FileMaker/v7/DinkeyPro.fmplugin/Contents/Resources/English.lproj/Localizable.strings b/Dinkey Pro 7.6.1/Modules/FileMaker/v7/DinkeyPro.fmplugin/Contents/Resources/English.lproj/Localizable.strings new file mode 100644 index 0000000..773f694 --- /dev/null +++ b/Dinkey Pro 7.6.1/Modules/FileMaker/v7/DinkeyPro.fmplugin/Contents/Resources/English.lproj/Localizable.strings @@ -0,0 +1,34 @@ +/* Plug-In name appearing in FM's preferences dialog */ +String1 = "Dinkey Dongle Pro/FD Plug-in"; +/* Options text appearing in FM's preferences dialog */ +String2 = "This plug-in allows you to do a protection check using Microcosm's Dinkey Pro or FD dongle."; +/* Version */ +String3 = "7.5.1"; +/* External functions prototypes go here */ +String101 = "DinkeyProVersion( version format )"; +String102 = "DDProtCheck(flags {; execs_decrement; alt_licence_name})"; +String103 = "DDProtCheckWithAlg(flags; alg_number; var_a; var_b; var_c; var_d; var_e; var_f; var_g; var_h)"; +String104 = "DDWriteData(flags; offset; length; data)"; +String105 = "DDReadData(flags; offset; length)"; +String106 = "DDGetExtendedError(dummy)"; +String107 = "DDGetType(dummy)"; +String108 = "DDGetModel(dummy)"; +String109 = "DDGetSDSN(dummy)"; +String110 = "DDGetProdCode(dummy)"; +String111 = "DDGetDongleNumber(dummy)"; +String112 = "DDGetUpdateNumber(dummy)"; +String113 = "DDGetDataAreaSize(dummy)"; +String114 = "DDGetMaxAlgNum(dummy)"; +String115 = "DDGetExecs(dummy)"; +String116 = "DDGetExpDay(dummy)"; +String117 = "DDGetExpMonth(dummy)"; +String118 = "DDGetExpYear(dummy)"; +String119 = "DDGetFeatures(dummy)"; +String120 = "DDGetNetUsers(dummy)"; +String121 = "DDGetAlgAnswer(dummy)"; +String122 = "DDGetFDCapacity(dummy)"; +String123 = "DDGetFDDrive(dummy)"; +String124 = "DDGetSWKeyType(dummy)"; +String125 = "DDGetSWKeyExpDay(dummy)"; +String126 = "DDGetSWKeyExpMonth(dummy)"; +String127 = "DDGetSWKeyExpYear(dummy)"; diff --git a/Dinkey Pro 7.6.1/Modules/FileMaker/v7/DinkeyPro.fmx b/Dinkey Pro 7.6.1/Modules/FileMaker/v7/DinkeyPro.fmx new file mode 100644 index 0000000..d98d38d Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/FileMaker/v7/DinkeyPro.fmx differ diff --git a/Dinkey Pro 7.6.1/Modules/Java/DinkeyChange/DinkeyChange.class b/Dinkey Pro 7.6.1/Modules/Java/DinkeyChange/DinkeyChange.class new file mode 100644 index 0000000..6a6b136 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Java/DinkeyChange/DinkeyChange.class differ diff --git a/Dinkey Pro 7.6.1/Modules/Java/DinkeyChange/DinkeyChangeException.class b/Dinkey Pro 7.6.1/Modules/Java/DinkeyChange/DinkeyChangeException.class new file mode 100644 index 0000000..0da855a Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Java/DinkeyChange/DinkeyChangeException.class differ diff --git a/Dinkey Pro 7.6.1/Modules/Java/DinkeyChange/DongleToChange.class b/Dinkey Pro 7.6.1/Modules/Java/DinkeyChange/DongleToChange.class new file mode 100644 index 0000000..a8d6b3e Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Java/DinkeyChange/DongleToChange.class differ diff --git a/Dinkey Pro 7.6.1/Modules/Java/DinkeyChange/x86-amd64/DCJava.dll b/Dinkey Pro 7.6.1/Modules/Java/DinkeyChange/x86-amd64/DCJava.dll new file mode 100644 index 0000000..2355a38 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Java/DinkeyChange/x86-amd64/DCJava.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/Java/DinkeyChange/x86-amd64/DCJava64.dll b/Dinkey Pro 7.6.1/Modules/Java/DinkeyChange/x86-amd64/DCJava64.dll new file mode 100644 index 0000000..2bddde0 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Java/DinkeyChange/x86-amd64/DCJava64.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/Java/DinkeyChange/x86-amd64/libDCJava64.dylib b/Dinkey Pro 7.6.1/Modules/Java/DinkeyChange/x86-amd64/libDCJava64.dylib new file mode 100644 index 0000000..801e5a7 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Java/DinkeyChange/x86-amd64/libDCJava64.dylib differ diff --git a/Dinkey Pro 7.6.1/Modules/Java/Runtime/DinkeyPro.class b/Dinkey Pro 7.6.1/Modules/Java/Runtime/DinkeyPro.class new file mode 100644 index 0000000..292eba5 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Java/Runtime/DinkeyPro.class differ diff --git a/Dinkey Pro 7.6.1/Modules/Java/Runtime/arm/libDPJava64.dylib b/Dinkey Pro 7.6.1/Modules/Java/Runtime/arm/libDPJava64.dylib new file mode 100644 index 0000000..955dca3 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Java/Runtime/arm/libDPJava64.dylib differ diff --git a/Dinkey Pro 7.6.1/Modules/Java/Runtime/x86-amd64/DPJava.dll b/Dinkey Pro 7.6.1/Modules/Java/Runtime/x86-amd64/DPJava.dll new file mode 100644 index 0000000..1e498f5 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Java/Runtime/x86-amd64/DPJava.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/Java/Runtime/x86-amd64/DPJava64.dll b/Dinkey Pro 7.6.1/Modules/Java/Runtime/x86-amd64/DPJava64.dll new file mode 100644 index 0000000..e54d816 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Java/Runtime/x86-amd64/DPJava64.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/Java/Runtime/x86-amd64/libDPJava64.dylib b/Dinkey Pro 7.6.1/Modules/Java/Runtime/x86-amd64/libDPJava64.dylib new file mode 100644 index 0000000..e3efe5b Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Java/Runtime/x86-amd64/libDPJava64.dylib differ diff --git a/Dinkey Pro 7.6.1/Modules/Java/dinkeydongle.jar b/Dinkey Pro 7.6.1/Modules/Java/dinkeydongle.jar new file mode 100644 index 0000000..f6efaf0 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Java/dinkeydongle.jar differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-5.6-nts-vc11.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-5.6-nts-vc11.dll new file mode 100644 index 0000000..e139232 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-5.6-nts-vc11.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-5.6-ts-vc11.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-5.6-ts-vc11.dll new file mode 100644 index 0000000..c314500 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-5.6-ts-vc11.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.0-nts-vc14.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.0-nts-vc14.dll new file mode 100644 index 0000000..8cc3d8f Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.0-nts-vc14.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.0-ts-vc14.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.0-ts-vc14.dll new file mode 100644 index 0000000..a66e119 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.0-ts-vc14.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.1-nts-vc14.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.1-nts-vc14.dll new file mode 100644 index 0000000..49f9b27 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.1-nts-vc14.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.1-ts-vc14.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.1-ts-vc14.dll new file mode 100644 index 0000000..021074d Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.1-ts-vc14.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.2-nts-vc15.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.2-nts-vc15.dll new file mode 100644 index 0000000..66849e5 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.2-nts-vc15.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.2-ts-vc15.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.2-ts-vc15.dll new file mode 100644 index 0000000..75abe54 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.2-ts-vc15.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.3-nts-vc15.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.3-nts-vc15.dll new file mode 100644 index 0000000..0e0f7cf Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.3-nts-vc15.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.3-ts-vc15.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.3-ts-vc15.dll new file mode 100644 index 0000000..9a16278 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.3-ts-vc15.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.4-nts-vc15.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.4-nts-vc15.dll new file mode 100644 index 0000000..020baaf Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.4-nts-vc15.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.4-ts-vc15.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.4-ts-vc15.dll new file mode 100644 index 0000000..215db34 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-7.4-ts-vc15.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-8.0-nts-vc16.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-8.0-nts-vc16.dll new file mode 100644 index 0000000..d1cf4dd Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-8.0-nts-vc16.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-8.0-ts-vc16.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-8.0-ts-vc16.dll new file mode 100644 index 0000000..4f9c712 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-8.0-ts-vc16.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-8.1-nts-vc16.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-8.1-nts-vc16.dll new file mode 100644 index 0000000..f06780f Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-8.1-nts-vc16.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-8.1-ts-vc16.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-8.1-ts-vc16.dll new file mode 100644 index 0000000..568d68e Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-8.1-ts-vc16.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-8.2-nts-vc16.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-8.2-nts-vc16.dll new file mode 100644 index 0000000..0094418 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-8.2-nts-vc16.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-8.2-ts-vc16.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-8.2-ts-vc16.dll new file mode 100644 index 0000000..952787d Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win32-8.2-ts-vc16.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.0-nts-vc14.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.0-nts-vc14.dll new file mode 100644 index 0000000..270fb54 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.0-nts-vc14.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.0-ts-vc14.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.0-ts-vc14.dll new file mode 100644 index 0000000..60c0dc3 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.0-ts-vc14.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.1-nts-vc14.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.1-nts-vc14.dll new file mode 100644 index 0000000..957b5ba Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.1-nts-vc14.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.1-ts-vc14.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.1-ts-vc14.dll new file mode 100644 index 0000000..69c933e Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.1-ts-vc14.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.2-nts-vc15.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.2-nts-vc15.dll new file mode 100644 index 0000000..38828bb Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.2-nts-vc15.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.2-ts-vc15.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.2-ts-vc15.dll new file mode 100644 index 0000000..dfa07d9 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.2-ts-vc15.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.3-nts-vc15.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.3-nts-vc15.dll new file mode 100644 index 0000000..863a86c Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.3-nts-vc15.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.3-ts-vc15.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.3-ts-vc15.dll new file mode 100644 index 0000000..4376083 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.3-ts-vc15.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.4-nts-vc15.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.4-nts-vc15.dll new file mode 100644 index 0000000..8968f73 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.4-nts-vc15.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.4-ts-vc15.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.4-ts-vc15.dll new file mode 100644 index 0000000..8bc2691 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-7.4-ts-vc15.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-8.0-nts-vc16.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-8.0-nts-vc16.dll new file mode 100644 index 0000000..a5a706f Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-8.0-nts-vc16.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-8.0-ts-vc16.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-8.0-ts-vc16.dll new file mode 100644 index 0000000..32ae5e3 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-8.0-ts-vc16.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-8.1-nts-vc16.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-8.1-nts-vc16.dll new file mode 100644 index 0000000..097b796 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-8.1-nts-vc16.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-8.1-ts-vc16.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-8.1-ts-vc16.dll new file mode 100644 index 0000000..9d60f4b Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-8.1-ts-vc16.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-8.2-nts-vc16.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-8.2-nts-vc16.dll new file mode 100644 index 0000000..e96c607 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-8.2-nts-vc16.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-8.2-ts-vc16.dll b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-8.2-ts-vc16.dll new file mode 100644 index 0000000..1299a66 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/PHP/dpphp-win64-8.2-ts-vc16.dll differ diff --git a/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.10/dpwin32py.pyd b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.10/dpwin32py.pyd new file mode 100644 index 0000000..97c316b Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.10/dpwin32py.pyd differ diff --git a/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.10/dpwin64py.pyd b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.10/dpwin64py.pyd new file mode 100644 index 0000000..084199e Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.10/dpwin64py.pyd differ diff --git a/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.11/dpwin32py.pyd b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.11/dpwin32py.pyd new file mode 100644 index 0000000..e857642 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.11/dpwin32py.pyd differ diff --git a/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.11/dpwin64py.pyd b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.11/dpwin64py.pyd new file mode 100644 index 0000000..fd55eae Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.11/dpwin64py.pyd differ diff --git a/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.5/dpwin32py.pyd b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.5/dpwin32py.pyd new file mode 100644 index 0000000..d154919 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.5/dpwin32py.pyd differ diff --git a/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.5/dpwin64py.pyd b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.5/dpwin64py.pyd new file mode 100644 index 0000000..f58f619 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.5/dpwin64py.pyd differ diff --git a/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.6/dpwin32py.pyd b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.6/dpwin32py.pyd new file mode 100644 index 0000000..1ad3aaf Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.6/dpwin32py.pyd differ diff --git a/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.6/dpwin64py.pyd b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.6/dpwin64py.pyd new file mode 100644 index 0000000..6f33ba6 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.6/dpwin64py.pyd differ diff --git a/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.7/dpwin32py.pyd b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.7/dpwin32py.pyd new file mode 100644 index 0000000..48099d6 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.7/dpwin32py.pyd differ diff --git a/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.7/dpwin64py.pyd b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.7/dpwin64py.pyd new file mode 100644 index 0000000..db112d7 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.7/dpwin64py.pyd differ diff --git a/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.8/dpwin32py.pyd b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.8/dpwin32py.pyd new file mode 100644 index 0000000..add37c5 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.8/dpwin32py.pyd differ diff --git a/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.8/dpwin64py.pyd b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.8/dpwin64py.pyd new file mode 100644 index 0000000..173f25f Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.8/dpwin64py.pyd differ diff --git a/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.9/dpwin32py.pyd b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.9/dpwin32py.pyd new file mode 100644 index 0000000..f87b7e3 Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.9/dpwin32py.pyd differ diff --git a/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.9/dpwin64py.pyd b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.9/dpwin64py.pyd new file mode 100644 index 0000000..aeb04da Binary files /dev/null and b/Dinkey Pro 7.6.1/Modules/Python/x86-amd64/3.9/dpwin64py.pyd differ diff --git a/Dinkey Pro 7.6.1/QuickTour/hello.exe b/Dinkey Pro 7.6.1/QuickTour/hello.exe new file mode 100644 index 0000000..1f25673 Binary files /dev/null and b/Dinkey Pro 7.6.1/QuickTour/hello.exe differ diff --git a/Dinkey Pro 7.6.1/QuickTour/quicktour.dapfj b/Dinkey Pro 7.6.1/QuickTour/quicktour.dapfj new file mode 100644 index 0000000..34463c9 --- /dev/null +++ b/Dinkey Pro 7.6.1/QuickTour/quicktour.dapfj @@ -0,0 +1,88 @@ +{ + "Notes": "Protects the hello.exe program as part of the Quick Tour", + "Models": ["Pro Plus"], + "ProductCode": "DEMO", + "NetUserType": "per product", + "ProductMaxNetUsers": 2, + + "Advanced": { + "DongleNumbers": "all", + "DongleNumberRangeMin": null, + "DongleNumberRangeMax": null, + "DataEncKeyProductCode": null, + "LockDongleToComputer": false, + "AllowUSBOverNetwork": true, + "AllowSoftwareKeys": true + }, + + "Licences": [ + { + "Name": "hello", + "Executions": 5, + "ExecutionWarning": null, + "ExpiryDate": "no limit", + "MaxDays": "no limit", + "ExpiryWarning": null, + "Features": 0, + "LicenceMaxNetUsers": null + } + ], + + "Files": [ + { + "InputName": "", + "OutputName": "", + "CallingProgram": null, + "Licence": "hello", + "Method": "Shell", + "ShellOptions": { + "DecrementExecution": true, + "StartNetworkUser": true, + "BackgroundCheck": 5, + "DataFileEncryption": false, + "DataFileTypes": null, + "DataFileExceptions": null, + "ExtraAntiDebug": true, + "ExtraAntiPiracy": 6 + } + } + ], + + "DataArea": { + "ZeroDataSize": null, + "DataFile": "" + }, + + "ShellMessages": { + "Success": "", + "DongleNotFound": "Error! A valid dongle for MyProduct has not been detected.", + "ExpiryError": "MyProduct has expired!", + "ExecsLimit": "MyProduct has used up all of its allowed executions.", + "ExpiryWarning": "Warning! MyProduct will expire in %1 days.", + "ExecsWarning": "Warning! You will only be able to run MyProduct %1 more times.", + "NetUserLimit": "The maximum number of permitted network users has been exceeded.", + "OtherError": "The error %1/%2 has occurred checking the dongle in MyProduct.", + "Background": "This program will terminate in 30 seconds.\r\nPlease save your work or attach a valid dongle.", + "NetNoServer": "Error! Cannot detect DinkeyServer on the network." + }, + + "Algorithms": [ + ], + + "ExtraSecurity": { + "DRISEncryptionKeys": null, + "DataEncryptionKeys": null, + "RWAlgorithm": null, + "SecureUpdatesOnly": false + }, + + "Actions": { + "ProgramDongle": true, + "LockSoftware": true + }, + + "DataFileEncryptionTool": { + "Files": [ + ] + } +} \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/QuickTour/quicktour.drpfj b/Dinkey Pro 7.6.1/QuickTour/quicktour.drpfj new file mode 100644 index 0000000..82f54c5 --- /dev/null +++ b/Dinkey Pro 7.6.1/QuickTour/quicktour.drpfj @@ -0,0 +1,47 @@ +{ + "Notes": "Used by the Quick Tour to add 5 executions to the dongle so that the protected hello.exe program can run 5 more times.", + + "DongleInfo": { + "ProductCode": "DEMO", + "DongleNumber": 123456789, + "UpdateNumber": 1 + }, + + "Licences": [ + { + "Name": "*.*", + "Action": "change", + "AddExecutions": 5, + "ExecutionWarning": null, + "ExpiryDate": null, + "SetMaxDays": null, + "ExpiryWarning": null, + "Features": null, + "LicenceMaxNetUsers": null + } + ], + + "DataArea": { + "DataAreaSize": null, + "DataChanges": [ + ] + }, + + "Algorithms": { + }, + + "OtherInfo": { + "NetUserType": null, + "ProductMaxNetUsers": null, + "LastUsedDate": null, + "DataEncKeyProductCode": null, + "SecureUpdatesOnly": null, + "LockDongleToComputer": null, + "ResetDongleLock": null + }, + + "UpdateCode": { + "OutputFileName": null, + "Type": "short" + } +} \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/4D/README.txt b/Dinkey Pro 7.6.1/Samples/4D/README.txt new file mode 100644 index 0000000..a13599b --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/4D/README.txt @@ -0,0 +1,123 @@ +sample - sample code for DinkeyPro/FD in 4D +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This sample code is written using 4D v12 but will work with later versions of 4D. + +The sample code calls a 4D plugin which we provide. This plugin is compatible with +4D versions 11 and higher. It is called ddpro.bundle. This is a series of directories +and files. The most important are shown here: + +ddpro.bundle + Contents + Windows + ddpro.4dx + Windows64 + ddpro.4dx + MacOS + ddpro + Resources + +This same bundle is provided in the Windows and Mac OSX SDKs and will support Mac OS X and +Windows 32-bit and 64-bit Operating Systems. + +For Mac OS X this directory structure is recognised as a single file: ddpro.bundle. You can +explore the contents of the bundle by choosing "Show Package Contents". + +For the sample database to work properly you need to have a Plugins folder (located in the same +place as the sample database) and include the protected ddpro.bundle in the Plugins folder. + +For Mac machines you just place ddpro.bundle in this folder. For Windows you need to copy +the whole structure to the Plugins folder. + +Note - the actual Plugin file you need to protect is the file in Contents\. +For Windows it is called ddpro.4dx. For Mac OSX it is called ddpro. You need to protect +this file (and not your database) with DinkeyAdd with the API Method. You should protect +the relevant file for each Operating System you want to support. So, for example, if you +want to support MacOSX and 32-bit, 64-bit Windows you should protect these files: +ddpro.bundle\Contents\Windows\ddpro.4dx +ddpro.bundle\Contents\Windows64\ddpro.4dx +ddpro.bundle\Contents\MacOS\ddpro + +If you don't want to support a particular operating system you can delete that folder. + +Because your database is dependent on the protected plugin then it is itself protected. + +You can then supply the whole protected bundle to your customers. + +The sample code contains many Project Methods. However, there are 10 main functions +that you can use in your code. You will not need to use all these functions in your +code. Just use which ever functions are most appropriate and customise in your own way. +The sample code is just a guide. You should implement the protection in a stronger way +using the techniques described in the "Increasing your Protection" chapter of the manual. + +For example you can call one (or more) of these functions when your database opens. +(Database Methods | On Startup). This has been implemented in the sample code but has +been commented out otherwise you would need a correctly programmed dongle to open it! +For this reason it is probably best to keep an unprotected copy of your database before +you start adding protection. + +The 10 main functions are: + +// this file contains 10 protection-check functions. +ProtCheck a standard protection check +ProtCheckWithAlg a protection check & executing an Algorithm +WriteBytes a protection check & write data to the dongle +ReadBytes a protection check & read data from the dongle +EncryptUserData a protection check & encrypting data and then decrypting the data +// these functions are the same as the functions listed above but encrypting all parameters passed to our API +ProtCheckEnc a standard protection check +ProtCheckWithAlgEnc a protection check & executing an Algorithm +WriteBytesEnc a protection check & write data to the dongle +ReadBytesEnc a protection check & read data from the dongle +EncryptUserDataEnc a protection check & encrypting data and then decrypting the data + +If you are using Dinkey Lite then you can only use 4 functions: +ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + +These functions also depend on some other simpler functions (check to see which functions +are references and also include those in your code). For example, you will always need +to include: + +InitialiseDris +SetDrisFunction +SetDrisFlags +DisplayError +GetDrisSDSN +GetDrisExtErr + +The sample code has been implemented so that you build up the DRIS as a BLOB variable. +We have provided SetDris... functions to set various values in the DRIS and GetDris... +functions to get values fro the Dris. So you will also need to include all the GetDris... +and SetDris... functions that you need. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the SDSN value from 10101 to the value of your SDSN in the 10 main functions. +* Change the Product Code value from DEMO if you are using ProtCheck or ProtCheckEnc functions. +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages (DisplayError) with your own. + +Note: + +When you first use the plug-in you will get error 413. This is because you have not +protected it. To do this run DinkeyAdd and protect the plug-in file specifying the API Method. +Note - you should protect our 4D plugin and not your program. Because your program depends +on the 4D plugin it is also protected. See notes at the beginning of this file for more details. + +Note: + +We needed to insert an extra line of code into the sample just before the protection check: + +// this line is only required because of a bug in 4D (see readme.txt for more info) +SET BLOB SIZE($dris;DRIS SIZE;0) + +This is due to a bug in 4D which causes 4D to crash if the database is running in compiled +mode (or as a 4DC file). This bug existed in 4D v12.6. It may have been fixed in later versions +in which case you can remove this line. However, there is no harm in continuing to include +this line in your code. + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/4D/sample.4db b/Dinkey Pro 7.6.1/Samples/4D/sample.4db new file mode 100644 index 0000000..97386cb Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/4D/sample.4db differ diff --git a/Dinkey Pro 7.6.1/Samples/4D/sample.4dd b/Dinkey Pro 7.6.1/Samples/4D/sample.4dd new file mode 100644 index 0000000..8b28239 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/4D/sample.4dd differ diff --git a/Dinkey Pro 7.6.1/Samples/Access/DPSample.bas b/Dinkey Pro 7.6.1/Samples/Access/DPSample.bas new file mode 100644 index 0000000..39e887f --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Access/DPSample.bas @@ -0,0 +1,905 @@ +Attribute VB_Name = "DPSample" +Option Compare Database + +' The sample code contains 12 functions. You will not need to use all these +' functions in your code. Just use which ever functions are most appropriate +' and customise in your own way. The sample code is just a guide. You should +' implement the protection in a stronger way using the techniques described in +' the "Increasing your Protection" chapter of the manual. +' +' The 12 functions are: +' ProtCheck a standard protection check +' ProtCheckWithAlg a protection check & executing an Algorithm +' WriteString a protection check & write data to the dongle +' ReadString a protection check & read data from the dongle +' WriteBytes a protection check & write data to the dongle +' ReadBytes a protection check & read data from the dongle +' EncryptUserData a protection check,& encrypting data and then decrypting the data +' +' these functions are the same as some of the functions listed above but encrypting all parameters passed to our API +' ProtCheckEnc a standard protection check +' ProtCheckWithAlgEnc a protection check & executing an Algorithm +' WriteBytesEnc a protection check & write data to the dongle +' ReadBytesEnc a protection check & read data from the dongle +' EncryptUserDataEnc a protection check & encrypting data and then decrypting the data + +' If you are using Dinkey Lite then you can only use 4 functions: +' ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + +' !!!! +Public Const MY_SDSN = 10101 ' !!!! change this value to be the value of your SDSN (demo = 10101) +Public Const MY_PRODCODE = "DEMO" ' !!!! change this value to match the Product Code in the dongle + +' Used in OnOpen property of Startup form. +Function OpenStartup() As Boolean +On Error GoTo open_failure + +' call the function(s) of your choice here +' here I have chosen a standard protection check +If ProtCheck() <> 0 Then + Call CloseCurrentDatabase + Exit Function +End If + +Exit Function + +open_failure: + 'DLL failed to load + MsgBox "Cannot find Dinkey Pro Runtime Module (dpwin32.dll / dpwin64.dll). This should be in the Windows System directory", vbOKOnly, "Error" + Call CloseCurrentDatabase +End Function + +Function ProtCheck() As Long +Dim mydris As DRIS +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = PROTECTION_CHECK ' standard protection check +mydris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + +ret_code = DDProtCheck(mydris, 0) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ProtCheck = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ProtCheck = -1 + Exit Function +End If + +'NB to access product code you will need to use the TrimCString function +If (TrimCString(mydris.prodcode) <> MY_PRODCODE) Then + MsgBox "Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", vbOKOnly, "Error" + ProtCheck = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ProtCheck = -1 + Exit Function +End If + +' NB to access the dongle number you will need to use the ConvertToUnsigned function like this: +'ConvertToUnsigned(mydris.dongle_number) + +ProtCheck = 0 +End Function + +' !!!! You should replace this function with the one generated by the +' "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) +' or from DinkeyLook if you are using Dinkey Lite dongles. +' see readme.txt notes concerning using the algorithm in VB +Private Function MyAlgorithm(ByVal a As Long, ByVal b As Long, ByVal c As Long, ByVal d As Long, ByVal e As Long, ByVal f As Long, ByVal g As Long, ByVal h As Long) As Long + MyAlgorithm = a + b + c + d + e + f + g + h +End Function + +' NB for this to work you must program at least "user algorithm" into the dongle +' NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +' sample code generated by DinkeyAdd for the algorithm that you are using. +Function ProtCheckWithAlg() As Long +Dim mydris As DRIS +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = EXECUTE_ALGORITHM ' standard protection check & execute an algorithm +mydris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... +mydris.alg_number = 1 ' execute first algorithm (you do not need to specify this field for Dinkey Lite dongles) +' you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random +mydris.var_a = 1 ' sample values +mydris.var_b = 2 +mydris.var_c = 3 +mydris.var_d = 4 +mydris.var_e = 5 +mydris.var_f = 6 +mydris.var_g = 7 +mydris.var_h = 8 + +ret_code = DDProtCheck(mydris, 0) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ProtCheckWithAlg = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ProtCheckWithAlg = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ProtCheckWithAlg = -1 + Exit Function +End If + +' if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code +' !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd +If MyAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) <> mydris.alg_answer Then + MsgBox "Dinkey Dongle protection error / You have not patched your algorithm in the MyAlgorithm routine", vbOKOnly, "Error" + ProtCheckWithAlg = -1 + Exit Function +End If + +ProtCheckWithAlg = 0 +End Function + + +' This writes the String "Hello, World" to the dongle data area at offset 7 +' In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +' If you want to write data that isn't a string use the WriteBytes function +Function WriteString() As Long +Dim mydris As DRIS +Dim StringToWrite As String * 13 +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = WRITE_DATA_AREA ' standard protection check and write data provided +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 13 + +StringToWrite = "Hello, World!" + +ret_code = DDProtCheckString(mydris, StringToWrite) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + WriteString = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + WriteString = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + WriteString = -1 + Exit Function +End If + +WriteString = 0 +End Function + + +' This writes the data 0,1,2,...19 to the dongle data area at offset 7 +' In order for this function to work you will need to have a data area in your dongle that is at least 28 bytes long. +' If you want to write strings it is easier to use the WriteString function +Function WriteData() As Long +Dim mydris As DRIS +Dim DataToWrite As FixedByteArray +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = WRITE_DATA_AREA ' standard protection check and write data provided +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 20 + +For i = 0 To 19 + DataToWrite.Data(i) = i +Next + +ret_code = DDProtCheckData(mydris, DataToWrite) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + WriteData = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + WriteData = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + WriteData = -1 + Exit Function +End If + +WriteData = 0 +End Function + + +' This reads 13 bytes of data from offset 7 in the dongle data area +' In order for this function to work you will need to have a data area in your dongle that is at least 20 bytes long. +' In order for the data to be displayed properly by this routine it will need to be text data +Function ReadString() As Long +Dim mydris As DRIS +Dim StringToRead As String * 13 +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = READ_DATA_AREA ' standard protection check and read data +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 13 + +ret_code = DDProtCheckString(mydris, StringToRead) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ReadString = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ReadString = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ReadString = -1 + Exit Function +End If + +MsgBox "Dinkey Data Area at offset 7 contains: " + StringToRead, vbOKOnly + +ReadString = 0 +End Function + + +' This reads 20 bytes of data from offset 7 in the dongle data area +' In order for this function to work you will need to have a data area in your dongle that is at least 27 bytes long. +Function ReadData() As Long +Dim mydris As DRIS +Dim DataToRead As FixedByteArray +Dim ret_code As Long +Dim DisplayString As String + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = READ_DATA_AREA ' standard protection check and write data provided +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 20 + +ret_code = DDProtCheckData(mydris, DataToRead) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ReadData = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ReadData = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ReadData = -1 + Exit Function +End If + +DisplayString = "Dinkey Data Area at offset 7 contains: " +For i = 0 To 19 + DisplayString = DisplayString + Str(DataToRead.Data(i)) +Next + +MsgBox DisplayString, vbOKOnly +ReadData = 0 +End Function + +' This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +' It will then do another protection check & decrypt the data +' The data used in this example is 0,1,2...19. If you wanted to encrypt and/or decrypt Strings +' then you could use a technique similar to that employed in WriteString & ReadString +Function EncryptUserData() As Long +Dim mydris As DRIS +Dim MyData As FixedByteArray +Dim DisplayString As String +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = ENCRYPT_USER_DATA ' standard protection check & encrypt data +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.data_crypt_key_num = 1 +mydris.rw_length = 20 + +For i = 0 To 19 ' initialise data + MyData.Data(i) = i +Next + +ret_code = DDProtCheckData(mydris, MyData) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + EncryptUserData = ret_code + Exit Function +End If + +' ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn as per previous example functions + +' Now decrypt the same data to get the original values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = DECRYPT_USER_DATA ' standard protection check & decrypt data +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.data_crypt_key_num = 1 +mydris.rw_length = 20 + +ret_code = DDProtCheckData(mydris, MyData) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + EncryptUserData = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + EncryptUserData = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + EncryptUserData = -1 + Exit Function +End If + +DisplayString = "Decrypted Data is : " +For i = 0 To 19 + DisplayString = DisplayString + Str(MyData.Data(i)) +Next + +MsgBox DisplayString, vbOKOnly +EncryptUserData = 0 +End Function + +' !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! +' In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" +' in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm +' but the code can be modified easily to use the 3 encryption parameters. + +' !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm +Private Function MyRWAlgorithm(ByVal a As Long, ByVal b As Long, ByVal c As Long, ByVal d As Long, ByVal e As Long, ByVal f As Long, ByVal g As Long, ByVal h As Long) As Long + MyRWAlgorithm = a Xor b Xor c Xor d Xor e Xor f + MyRWAlgorithm = MyRWAlgorithm And &HFFFFFF ' we only use bottom 3 bytes and -ve numbers can cause problems with CryptApiData +End Function + +' !!!! please overwrite this function with the one generated by DinkeyAdd +Private Sub CryptDRIS(mydris As DRIS) + Dim i, j, k, t As Integer + Dim bigseed(256) As Byte + Dim S(256) As Byte + Dim temp As Byte + Dim temp_dris(Len(mydris)) As Byte + + Call CopyMemory(temp_dris(0), mydris, Len(mydris)) + For i = 0 To 255 Step 8 + Call CopyMemory(bigseed(i), mydris.seed1, 4) + Call CopyMemory(bigseed(i + 4), mydris.seed2, 4) + Next + For i = 0 To 255 + S(i) = i + Next + j = 0 + For i = 0 To 255 + j = (j + CInt(S(i)) + CInt(bigseed(i)) + 123) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + Next + i = 0 + j = 0 + For k = 16 To Len(mydris) - 1 + i = (i + 1) Mod 256 + j = (j + CInt(S(i)) + 212) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + t = (CInt(S(i)) + CInt(S(j)) + 97) Mod 256 + temp_dris(k) = temp_dris(k) Xor S(t) + Next + + Call CopyMemory(mydris, temp_dris(0), Len(mydris)) +End Sub + +' !!!! please overwrite this function with the one generated by DinkeyAdd +Private Sub CryptApiData(ByRef Data() As Byte, ByVal length As Long, ByVal seed1 As Long, ByVal seed2 As Long, ByVal AlgAnswer As Long) + Dim i, j, k, t As Integer + Dim bigseed(256) As Byte + Dim S(256) As Byte + Dim temp As Byte + + For i = 0 To 255 Step 8 + Call CopyMemory(bigseed(i), seed1, 4) + Call CopyMemory(bigseed(i + 4), seed2, 4) + Next + For i = 0 To 255 + S(i) = i + Next + j = 0 + For i = 0 To 255 + j = (j + CInt(S(i)) + CInt(bigseed(i)) + (AlgAnswer And &HFF)) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + Next + i = 0 + j = 0 + For k = 0 To length - 1 + i = (i + 1) Mod 256 + j = (j + CInt(S(i)) + ((AlgAnswer \ &H100) And &HFF)) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + t = (CInt(S(i)) + CInt(S(j)) + ((AlgAnswer \ &H10000) And &HFF)) Mod 256 + Data(k) = Data(k) Xor S(t) + Next +End Sub + +' We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +Function ProtCheckEnc() As Long +Dim mydris As DRIS +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = PROTECTION_CHECK ' standard protection check +mydris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheck(mydris, 0) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ProtCheckEnc = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ProtCheckEnc = -1 + Exit Function +End If + +'NB to access product code you will need to use the TrimCString function +If (TrimCString(mydris.prodcode) <> MY_PRODCODE) Then + MsgBox "Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", vbOKOnly, "Error" + ProtCheckEnc = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ProtCheckEnc = -1 + Exit Function +End If + +ProtCheckEnc = 0 +End Function + + +' NB for this to work you must program at least "user algorithm" into the dongle +' NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +' sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite copy source from DinkeyLook. +' We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +Function ProtCheckWithAlgEnc() As Long +Dim mydris As DRIS +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = EXECUTE_ALGORITHM ' standard protection check & execute an algorithm +mydris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... +mydris.alg_number = 1 ' execute first algorithm - you do not need to specify this field if you are only using Lite models +' you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random +mydris.var_a = 1 ' sample values +mydris.var_b = 2 +mydris.var_c = 3 +mydris.var_d = 4 +mydris.var_e = 5 +mydris.var_f = 6 +mydris.var_g = 7 +mydris.var_h = 8 + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheck(mydris, 0) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ProtCheckWithAlgEnc = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ProtCheckWithAlgEnc = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ProtCheckWithAlgEnc = -1 + Exit Function +End If + +' if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code +' !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd +If MyAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) <> mydris.alg_answer Then + MsgBox "Dinkey Dongle protection error / You have not patched your algorithm in the MyAlgorithm routine", vbOKOnly, "Error" + ProtCheckWithAlgEnc = -1 + Exit Function +End If + +ProtCheckWithAlgEnc = 0 +End Function + + +' This writes the data 0,1,2,...19 to the dongle data area at offset 7 +' In order for this function to work you will need to have a data area in your dongle that is at least 28 bytes long. +' We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +Function WriteDataEnc() As Long +Dim mydris As DRIS +Dim DataToWrite As FixedByteArray +Dim ret_code As Long +Dim alg_ans As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = WRITE_DATA_AREA ' standard protection check and write data provided +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 20 +' NB we restrict the algorithm variables to be 24-bit values to avoid any possible overruns in the algorithm +mydris.var_a = Rand(&HFFFFFF) ' random values +mydris.var_b = Rand(&HFFFFFF) +mydris.var_c = Rand(&HFFFFFF) +mydris.var_d = Rand(&HFFFFFF) +mydris.var_e = Rand(&HFFFFFF) +mydris.var_f = Rand(&HFFFFFF) +mydris.var_g = Rand(&HFFFFFF) +mydris.var_h = Rand(&HFFFFFF) + +For i = 0 To 19 ' initialise data to write + DataToWrite.Data(i) = i +Next + +' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm +alg_ans = MyRWAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) + +' encrypt data we want to write. +Call CryptApiData(DataToWrite.Data, 20, mydris.seed1, mydris.seed2, alg_ans) + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheckData(mydris, DataToWrite) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + WriteDataEnc = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + WriteDataEnc = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + WriteDataEnc = -1 + Exit Function +End If + +WriteDataEnc = 0 +End Function + + +' This reads 20 bytes of data from offset 7 in the dongle data area +' In order for this function to work you will need to have a data area in your dongle that is at least 27 bytes long. +' We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +Function ReadDataEnc() As Long +Dim mydris As DRIS +Dim DataToRead As FixedByteArray +Dim ret_code As Long +Dim DisplayString As String + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = READ_DATA_AREA ' standard protection check and write data provided +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 20 +' NB we restrict the algorithm variables to be 24-bit values to avoid any possible overruns in the algorithm +mydris.var_a = Rand(&HFFFFFF) ' random values +mydris.var_b = Rand(&HFFFFFF) +mydris.var_c = Rand(&HFFFFFF) +mydris.var_d = Rand(&HFFFFFF) +mydris.var_e = Rand(&HFFFFFF) +mydris.var_f = Rand(&HFFFFFF) +mydris.var_g = Rand(&HFFFFFF) +mydris.var_h = Rand(&HFFFFFF) + +' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm +alg_ans = MyRWAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheckData(mydris, DataToRead) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ReadDataEnc = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ReadDataEnc = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ReadDataEnc = -1 + Exit Function +End If + +' encrypt data we want to write. +Call CryptApiData(DataToRead.Data, 20, mydris.seed1, mydris.seed2, alg_ans) + +DisplayString = "Dinkey Data Area at offset 7 contains: " +For i = 0 To 19 + DisplayString = DisplayString + Str(DataToRead.Data(i)) +Next + +MsgBox DisplayString, vbOKOnly +ReadDataEnc = 0 +End Function + +' This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +' It will then do another protection & decrypt the data +' We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +Function EncryptUserDataEnc() As Long +Dim mydris As DRIS +Dim MyData As FixedByteArray +Dim DisplayString As String +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = ENCRYPT_USER_DATA ' standard protection check & encrypt data +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.data_crypt_key_num = 1 +mydris.rw_length = 20 +' NB we restrict the algorithm variables to be 24-bit values to avoid any possible overruns in the algorithm +mydris.var_a = Rand(&HFFFFFF) ' random values +mydris.var_b = Rand(&HFFFFFF) +mydris.var_c = Rand(&HFFFFFF) +mydris.var_d = Rand(&HFFFFFF) +mydris.var_e = Rand(&HFFFFFF) +mydris.var_f = Rand(&HFFFFFF) +mydris.var_g = Rand(&HFFFFFF) +mydris.var_h = Rand(&HFFFFFF) + +For i = 0 To 19 ' initialise data + MyData.Data(i) = i +Next + +' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm +alg_ans = MyRWAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) + +' encrypt data we want to pass. +Call CryptApiData(MyData.Data, 20, mydris.seed1, mydris.seed2, alg_ans) + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheckData(mydris, MyData) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + EncryptUserDataEnc = ret_code + Exit Function +End If + +' ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn as per previous example functions + +' Now decrypt the same data to get the original values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = DECRYPT_USER_DATA ' standard protection check & decrypt data +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.data_crypt_key_num = 1 +mydris.rw_length = 20 +' NB we restrict the algorithm variables to be 24-bit values to avoid any possible overruns in the algorithm +mydris.var_a = Rand(&HFFFFFF) ' random values +mydris.var_b = Rand(&HFFFFFF) +mydris.var_c = Rand(&HFFFFFF) +mydris.var_d = Rand(&HFFFFFF) +mydris.var_e = Rand(&HFFFFFF) +mydris.var_f = Rand(&HFFFFFF) +mydris.var_g = Rand(&HFFFFFF) +mydris.var_h = Rand(&HFFFFFF) + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheckData(mydris, MyData) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + EncryptUserDataEnc = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + EncryptUserDataEnc = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + EncryptUserDataEnc = -1 + Exit Function +End If + +' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm +alg_ans = MyRWAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) + +' decrypt data passed to us from the API. +Call CryptApiData(MyData.Data, 20, mydris.seed1, mydris.seed2, alg_ans) + +DisplayString = "Decrypted Data is : " +For i = 0 To 19 + DisplayString = DisplayString + Str(MyData.Data(i)) +Next + +MsgBox DisplayString, vbOKOnly +EncryptUserDataEnc = 0 +End Function + +' look at the error code and try to display an appropriate message +' !!!! you will want to replace these error messages with your own messages. +Public Sub DisplayError(ret_code As Long, extended_error As Long) + Select Case ret_code + Case 401 + MsgBox "Error! No dongles detected!", vbOKOnly, "Error" + Case 403 + MsgBox "Error! A dongle was detected but it was a different type to the one specified in DinkeyAdd.", vbOKOnly, "Error" + Case 404 + MsgBox "Error! A dongle was detected but it was a different model to those specified in DinkeyAdd.", vbOKOnly, "Error" + Case 409 + MsgBox "Error! The dongle detected has not been programmed by DinkeyAdd.", vbOKOnly, "Error" + Case 410 + MsgBox "Error! A dongle was detected but it has a different Product Code to the one specified in DinkeyAdd.", vbOKOnly, "Error" + Case 411 + MsgBox "Error! The dongle detected does not contain the licence associated with this program.", vbOKOnly, "Error" + Case 413 + MsgBox "Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual.", vbOKOnly, "Error" + Case 417 + MsgBox "Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.", vbOKOnly, "Error" + Case 423 + MsgBox "Error! The number of network users has been exceeded.", vbOKOnly, "Error" + Case 435 + MsgBox "Error! DinkeyServer has not been detected on the network.", vbOKOnly, "Error" + Case 922 + MsgBox "Error! The Software Key has expired.", vbOKOnly, "Error" + Case Else + MsgBox "An error occurred checking the dongle. Error: " + Str(ret_code) + ". Extended Error: " + str$(extended_error) + ".", vbOKOnly, "Error" + End Select +End Sub diff --git a/Dinkey Pro 7.6.1/Samples/Access/DinkeyPro.bas b/Dinkey Pro 7.6.1/Samples/Access/DinkeyPro.bas new file mode 100644 index 0000000..523408f --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Access/DinkeyPro.bas @@ -0,0 +1,163 @@ +' A VBA Interface to the Dinkey Pro/FD API + + +Attribute VB_Name = "DinkeyPro" +' API functions +' DDProtCheck - so we can ignore the second argument +' DDProtCheckString - so we can pass data as a String +' DDProtCheckData - so we can pass data in any format + +#If VBA7 Then + ' For Office 2010 and newer + #If Win64 Then + Declare PtrSafe Function DDProtCheck Lib "dpwin64.dll" (mydris As DRIS, Data As String) As Long + Declare PtrSafe Function DDProtCheckString Lib "dpwin64.dll" Alias "DDProtCheck" (mydris As DRIS, ByVal String1 As Any) As Long + Declare PtrSafe Function DDProtCheckData Lib "dpwin64.dll" Alias "DDProtCheck" (mydris As DRIS, Data As FixedByteArray) As Long + #Else + Declare PtrSafe Function DDProtCheck Lib "dpwin32.dll" (mydris As DRIS, Data As String) As Long + Declare PtrSafe Function DDProtCheckString Lib "dpwin32.dll" Alias "DDProtCheck" (mydris As DRIS, ByVal String1 As Any) As Long + Declare PtrSafe Function DDProtCheckData Lib "dpwin32.dll" Alias "DDProtCheck" (mydris As DRIS, Data As FixedByteArray) As Long + #End If +#Else + ' For versions of Office before 2010 + Declare Function DDProtCheck Lib "dpwin32.dll" (myDris As DRIS, Data As String) As Long + Declare Function DDProtCheckString Lib "dpwin32.dll" Alias "DDProtCheck" (myDris As DRIS, ByVal String1 As Any) As Long + Declare Function DDProtCheckData Lib "dpwin32.dll" Alias "DDProtCheck" (myDris As DRIS, Data As FixedByteArray) As Long +#End If + +'Dinkey Runtime Information Structure (DRIS) +Type DRIS + ' the first 4 fields are never encrypted + header As String * 4 ' should be set to DRIS + ' inputs + size As Long ' size of this structure + seed1 As Long ' seed for data/dris encryption + seed2 As Long ' as above + function As Long ' specify only one function + flags As Long ' options for the function selected. To use more than one OR them together: OPTION1 Or OPTION2... + execs_decrement As Long ' amount by which to dec execs if we use flag: DEC_MANY_EXECS + data_crypt_key_num As Long ' number of the key (1-3) that the dongle uses to encrypt or decrypt user data + rw_offset As Long ' offset in the dongle data area to read or write data + rw_length As Long ' length of data are to read/write/encrypt/decrypt +#If VBA7 Then + not_used As LongPtr ' This field is a pointer used in other programming languages. 4 bytes in 32-bit Access, 8 bytes in 64-bit Access +#Else + not_used As Long +#End If + alt_licence_name As String * 256 ' protection check for different licence instead of this one, must be null-terminated ascii + var_a As Long ' variable values for user algorithms + var_b As Long + var_c As Long + var_d As Long + var_e As Long + var_f As Long + var_g As Long + var_h As Long + alg_number As Long ' the number of the user algorithm that you want to execute + + ' outputs + ret_code As Long ' the return code from the protection check + ext_err As Long ' extended error + type As Long ' type of dongle detected. 1 = Pro, 2 = FD + model As Long ' model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + sdsn As Long ' Software Developer's Serial Number + prodcode As String * 12 ' product code (null-terminated) + dongle_number As Long ' dongle number. This number should be converted to a Double before being displayed otherwise it my appear as a negative number. + update_number As Long + data_area_size As Long ' size of the data area in the dongle detected + max_alg_num As Long ' the maximum algorithm number in the dongle detected + execs As Long ' executions left: -1 indicates 'no limit' + exp_day As Long ' expiry day: -1 indicates 'no limit' + exp_month As Long ' expiry month: -1 indicates 'no limit' + exp_year As Long ' expiry year: -1 indicates 'no limit' + features As Long ' features value + net_users As Long ' maximum number of network users for the dongle detected: -1 indicates 'mo limit' + alg_answer As Long ' answer to the user algorithm executed with the given variable values + fd_capacity As Long ' capacity of the data area in FD dongle. Currently fixed at ~10MB but may change in the future. + fd_drive As String * 128 ' drive letter of FD dongle detected e.g. 'f:\' + swkey_type As Long ' 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + swkey_exp_day As Long ' software key expiry date (if software key detected) + swkey_exp_month As Long + swkey_exp_year As Long +End Type + +' We need a structure for an array of bytes because otherwise the VB runtime can move the data in-between function calls +Type FixedByteArray + Data(0 To 1023) As Byte +End Type + +' Functions +Public Const PROTECTION_CHECK = 1 ' checks for dongle, check program params... +Public Const EXECUTE_ALGORITHM = 2 ' protection check + calculate answer for specified algorithm with specified inputs +Public Const WRITE_DATA_AREA = 3 ' protection check + writes dongle data area +Public Const READ_DATA_AREA = 4 ' protection check + reads dongle data area +Public Const ENCRYPT_USER_DATA = 5 ' protection check + the dongle will encrypt user data +Public Const DECRYPT_USER_DATA = 6 ' protection check + the dongle will decrypt user data +Public Const FAST_PRESENCE_CHECK = 7 ' checks for the presence of the correct dongle only with minimal security, no flags allowed +Public Const STOP_NET_USER = 8 ' stops a network user (a protection check is NOT performed) + +' Flags +Public Const DEC_ONE_EXEC = 1 ' decrement execs by 1 +Public Const DEC_MANY_EXECS = 2 ' decrement execs by number specified in execs +Public Const START_NET_USER = 4 ' starts a network user +Public Const USE_FUNCTION_ARGUMENT = 16 ' use the extra argument in the function for pointers +Public Const CHECK_LOCAL_FIRST = 32 ' always look in local ports before looking in network ports +Public Const CHECK_NETWORK_FIRST = 64 ' always look on the network before looking in local ports +Public Const USE_ALT_LICENCE_NAME = 128 ' use name specified in alt_licence_name instead of the default one +Public Const DONT_SET_MAXDAYS_EXPIRY = 256 ' if the max days expiry date has not been calculated then do not do it this time +Public Const MATCH_DONGLE_NUMBER = 512 ' restrict the search to match the dongle number specified in the DRIS +Public Const DONT_RETURN_FD_DRIVE = 1024 ' if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + +' Useful functions +#If VBA7 Then + Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long) + Declare PtrSafe Function SetCurrentDirectory Lib "kernel32" Alias "SetCurrentDirectoryA" (ByVal lpPathName As String) As Long +#Else + Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long) + Declare Function SetCurrentDirectory Lib "kernel32" Alias "SetCurrentDirectoryA" (ByVal lpPathName As String) As Long +#End If + +' given the maximum possible value generate a random number between 0 and the maximum +Public Function Rand(ByVal High As Long) As Long + Rand = Int((High + 1) * Rnd) +End Function + +' initialise the DRIS with random values +Public Sub RandomSet(myDris As DRIS) + Dim tempDris(Len(myDris)) As Byte + + Call Randomize + Call CopyMemory(tempDris(0), myDris, Len(myDris)) + + For i = 0 To Len(myDris) - 1 + tempDris(i) = Rand(255) + Next + + Call CopyMemory(myDris, tempDris(0), Len(myDris)) +End Sub + +' This function will convert the C string returned in the DRIS to a VB string +' e.g. to access the product code use TrimCString(mydris.prodcode) +Function TrimCString(s As String) As String + Dim i As Integer + Dim length As Integer + + length = Len(s) + + For i = 1 To length + If Mid(s, i, 1) = Chr(0) Then + TrimCString = Left(s, i - 1) ' Take off null and rest of string + Exit For + End If + Next + +End Function + +' this function should be used if you want to display the dongle_number. It will always display as a positive value +Public Function ConvertToUnsigned(number As Long) As Double +If (number >= 0) Then + ConvertToUnsigned = number +Else + ConvertToUnsigned = number + 4294967296# +End If +End Function diff --git a/Dinkey Pro 7.6.1/Samples/Access/README.txt b/Dinkey Pro 7.6.1/Samples/Access/README.txt new file mode 100644 index 0000000..f727e7e --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Access/README.txt @@ -0,0 +1,73 @@ +Notes for protecting Access Databases with Dinkey Pro/FD +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Before doing anything it is a good idea to make a back-up of your database. It is + possible to protect your database so well that you may have trouble accessing + it yourself! + +1. For Access 2007 and newer, view your form and then chose design view and view + the properties for your form (choose the event tab). + + For versions before Access 2007, open your form in Design View. Now click on + View > Properties and choose the "Event" tab. + +2. You should now see the list of events associated with your form. Set the + "On Open" entry to "=OpenStartup()". This will cause your database to launch + this function when it is first loaded. + +3. For Access 2007 and higher in the Database Tools tab launch the Visual Basic editor. + +4. In the editor, select File > Import File... and choose the file DinkeyPro.bas + to add this module to your project. + Repeat this step to add DPSample.bas to your project as well. + This VBA code will check for the Dinkey Pro/FD Dongle. If a dongle is found your + database will continue to load. If a dongle is not found then it will display + an error message and your database will not be loaded. + +5. You will need to supply a locked copy of dpwin32.dll with your database. To + support 64-bit versions of Access, you will also need to supply a locked dpwin64.dll. + These DLLs should be located in the same directory as your database. If the + relevant DLL is not found an error will occur. It is recommended that you rename + the DLLs with names individual to you. In this case you must also modify the + references to dpwin32.dll and dpwin64.dll in DinkeyPro.bas to use the new names. + + If you load your database at this point and dpwin32.dll is found it will + return error 413: program not protected. + +6. Lock the DLL(s) using the API method of protection using DinkeyAdd. You can + specify the output path to be the folder that contains your database so that + the locked DLLs are in the correct location. + +7. You now have to do one more thing. Currently the user could load your + database and then remove the call to check the protection and therefore have + an unprotected copy. You must stop them doing this by saving your database + as an ACCDE file (MDE file for Access prior to 2007). This compiles all the + VBA code and stops it from being editable by an end user. You must save a + copy of your original database otherwise you will not be able to make any + changes either! You will distribute the ACCDE (MDE) file to your customers. + + To save your database as an ACCDE file, choose the Database Tools tab and choose + "Make ACCDE". (for versions prior to 2007 choose "Save As" and change the type + to a MDE file). + +Note - the VBA code in this sample is the same as the Visual Basic sample code we + provide, except that we need to catch whether the DLL is missing or not (VB + will terminate the program if the DLL is not found but VBA will display an error + but continue to load the database). + +Note - You only need to copy the relevant sample code functions that you need. All + comments in your VBA code are visible in your spreadsheet file so be careful + what you say! You should remove all our comments. + +Note - Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the SDSN value from 10101 to the value of your SDSN in the 10 main functions. +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages (DisplayError) with your own. + diff --git a/Dinkey Pro 7.6.1/Samples/Ada/README.txt b/Dinkey Pro 7.6.1/Samples/Ada/README.txt new file mode 100644 index 0000000..6a491ba --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Ada/README.txt @@ -0,0 +1,51 @@ +ApiTest - Runtime sample code in Ada +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tested with GNAT gnatmake command-line utility 2011 but should work +with other Ada Compilers. + +The dris.ads file contains the DRIS structure definition and other useful constants +The apitest.adb file is the main sample code file. You can compile it like this: + +gnatmake apitest.adb + +The sample code contains 12 functions: + +DDProtCheck +DDProtCheckWithAlg +WriteBytes +ReadBytes +EncryptUserData + +(There are also encrypted versions of these functions where the parameters passed +to and from our API are encrypted for greater security). + +The best approach is to compile the sample code and see how it works and then to take +the appropriate code and apply it to your own project. You should include the dris.ads +file in your project and use/modify which ever functions from apitest.adb you feel are +appropriate. The dris.ads file should not be modified. + +You will not need to use all these functions in your code. Just use which ever +functions are most appropriate and customise in your own way. The sample code +is just a guide. You should implement the protection in a stronger way using +the techniques described in the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. + +Note - you should use DinkeyAdd to protect dpwin32.dll and not your program. +Because your program is linked to the DLL it is protected. + +Note - the protected dpwin32.dll should reside in the same folder as your compiled +code. + +Note - because of our strong anti-debug code you may not be able to debug your code +after calling our DLL. diff --git a/Dinkey Pro 7.6.1/Samples/Ada/apitest.adb b/Dinkey Pro 7.6.1/Samples/Ada/apitest.adb new file mode 100644 index 0000000..e1c28c8 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Ada/apitest.adb @@ -0,0 +1,830 @@ +with Interfaces; use Interfaces; +with Interfaces.C; use Interfaces.C; +with System; use System; +with DRIS; use DRIS; +with Ada.Text_IO; use Ada.Text_IO; +with Ada.Numerics.Discrete_Random; + +-- !! We strongly recommend that you read the "readme.txt" file in the sample code folder. +-- !! It contains important instructions on how to use the sample code + +procedure apitest is + + MY_SDSN : constant int32 := 10101; + -- !!!! change this value to be the value of your SDSN (demo = 10101) + + -- The sample code contains 10 functions. You will not need to use all these + -- functions in your code. Just use which ever functions are most appropriate + -- and customise in your own way. The sample code is just a guide. You should + -- implement the protection in a stronger way using the techniques described in + -- the "Increasing your Protection" chapter of the manual. + -- + -- If you are using Dinkey Lite then you can only use 4 functions: + -- ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + + -- this file contains 10 protection-check functions. + -- ProtCheck a standard protection check + -- ProtCheckWithAlg a protection check & executing an Algorithm + -- WriteBytes a protection check & write data to the dongle + -- ReadBytes a protection check & read data from the dongle + -- EncryptUserData a protection check & encrypting data and then decrypting the data + + -- these functions are the same as the functions listed above but encrypting all parameters passed to our API + -- ProtCheckEnc a standard protection check + -- ProtCheckWithAlgEnc a protection check & executing an Algorithm + -- WriteBytesEnc a protection check & write data to the dongle + -- ReadBytesEnc a protection check & read data from the dongle + -- EncryptUserDataEnc a protection check & encrypting data and then decrypting the data + + -- useful routines that are called by our functions - implemented at the end of this file + procedure random_set(dris : t_DRIS_access); + procedure DisplayError(ret_code : int32; extended_error : int32); + + -- ************************* our 10 functions ********************************** + + dris : t_DRIS_access := new t_DRIS; + + ---------------------------------- + -- ProtCheck + ---------------------------------- + function ProtCheck return int32 is + ret_code : int32; + begin + + -- set the DRIS to have random values + random_set(dris); + + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := PROTECTION_CHECK; -- standard protection check + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + ret_code := DDProtCheck(dris, System.Null_Address); + + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + -- later in your code you can check other values in the DRIS... + if (dris.sdsn /= MY_SDSN) then + Put_Line ("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + end if; + + -- later on in your program you can check the return code again + if (dris.ret_code /= 0) then + Put_Line ("Dinkey Dongle protection error"); + return -1; + end if; + + Put_Line ("ProtCheck worked"); + return 0; + end; + + ---------------------------------- + -- ProtCheckWithAlg + ---------------------------------- + -- !!!! You should replace this function with the one generated by the + -- "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) + -- or from DinkeyLook if you are using a Dinkey Lite dongle. + function MyAlgorithm(a,b,c,d,e,f,g,h : int32) return int32 is + begin + return (a + b + c + d + e + f + g + h); + end; + + -- NB for this to work you must program at least "user algorithm" into the dongle + -- NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + -- sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample + -- code from DinkeyLook + function ProtCheckWithAlg return int32 is + ret_code : int32; + begin + -- set the DRIS to have random values + random_set(dris); + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := EXECUTE_ALGORITHM; -- standard protection check & execute algorithm + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number := 1; -- execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + -- you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.var_a := 1; -- sample values + dris.var_b := 2; + dris.var_c := 3; + dris.var_d := 4; + dris.var_e := 5; + dris.var_f := 6; + dris.var_g := 7; + dris.var_h := 8; + + ret_code := DDProtCheck(dris, System.Null_Address); + + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + -- later in your code you can check other values in the DRIS... + + if (dris.sdsn /= MY_SDSN) then + Put_Line ("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + end if; + + -- ...later on in your program you can check the return code again + if (dris.ret_code /= 0) then + Put_Line ("Dinkey Dongle protection error"); + return -1; + end if; + + -- if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + -- !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) /= dris.alg_answer) then + Put_Line ("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine"); + return -1; + end if; + + Put_Line ("ProtCheckWithAlg worked"); + return 0; + end; + + ---------------------------------- + -- WriteBytes + ---------------------------------- + -- This writes the Data "Hello, World" to the dongle data area at offset 7 + -- In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. + function WriteBytes return int32 is + szDataToWrite : Interfaces.C.char_array := Interfaces.C.To_C ("Hello, World!", True); -- append null so we write that too! + ret_code : int32; + begin + + -- set the DRIS to have random values + random_set(dris); + + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := WRITE_DATA_AREA; -- standard protection check and write data + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset := 7; + dris.rw_length := szDataToWrite'Length; + dris.rw_data_ptr := szDataToWrite'Address; + + ret_code := DDProtCheck(dris, System.Null_Address); + + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + -- ...later in your code you can check other values in the DRIS... + if (dris.sdsn /= MY_SDSN) then + Put_Line ("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + end if; + + -- later on in your program you can check the return code again + if (dris.ret_code /= 0) then + Put_Line ("Dinkey Dongle protection error"); + return -1; + end if; + + Put_Line ("WriteBytes worked"); + return 0; + end; + + ---------------------------------- + -- ReadBytes + ---------------------------------- + -- This reads 14 bytes of data from offset 7 in the dongle data area + -- In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. + -- In order for the data to be displayed properly by this routine it will need to be text data + function ReadBytes return int32 is + szDataRead : Interfaces.C.char_array (1..14); + ret_code : int32; + begin + -- set the DRIS to have random values + random_set(dris); + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := READ_DATA_AREA; -- standard protection check & read data + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset := 7; + dris.rw_length := szDataRead'Length; -- it also should read the null + dris.rw_data_ptr := szDataRead'Address; + + ret_code := DDProtCheck(dris, System.Null_Address); + + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + -- ...later in your code you can check other values in the DRIS... + + if (dris.sdsn /= MY_SDSN) then + Put_Line ("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + end if; + + -- later on in your program you can check the return code again + if (dris.ret_code /= 0) then + Put_Line ("Dinkey Dongle protection error"); + return -1; + end if; + + Put_Line("ReadBytes worked! Dinkey Dongle Data area, offset 7 is: " & Interfaces.C.To_Ada(szDataRead)); + return 0; + end; + + ---------------------------------- + -- EncryptUserData + ---------------------------------- + -- This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 + -- It will then do another protection check & decrypt the data + function EncryptUserData return int32 is + szData : Interfaces.C.char_array := Interfaces.C.To_C ("Hello, World!"); + ret_code : int32; + begin + -- set the DRIS to have random values + random_set(dris); + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := ENCRYPT_USER_DATA; -- standard protection check & encrypt user data + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num := 1; + dris.rw_length := szData'Length; + dris.rw_data_ptr := szData'Address; + + ret_code := DDProtCheck(dris, System.Null_Address); + + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + -- ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + -- Now decrypt the same data to get the original values + random_set(dris); + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := DECRYPT_USER_DATA; -- standard protection check & decrypt user data + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num := 1; + dris.rw_length := szData'Length; + dris.rw_data_ptr := szData'Address; + + ret_code := DDProtCheck(dris, System.Null_Address); + + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + -- ...later in your code you can check other values in the DRIS... + + if (dris.sdsn /= MY_SDSN) then + Put_Line ("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + end if; + + -- later on in your program you can check the return code again + if (dris.ret_code /= 0) then + Put_Line ("Dinkey Dongle protection error"); + return -1; + end if; + + Put_Line("EncryptUserData worked. Data decrypted is: " & Interfaces.C.To_Ada (szData)); + return 0; + end; + + + + -- !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! + -- In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" + -- in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm + -- but the code can be modified easily to use the 3 encryption parameters. + + ---------------------------------- + -- MyRWAlgorithm + ---------------------------------- + -- !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm + -- NB The logical operators xor, or, and only work on unsigned integers so you may have to convert signed to unsigned + function MyRWAlgorithm(a,b,c,d,e,f,g,h : int32) return uint32 is + a2,b2,c2,d2,e2,f2 : uint32; + for a2'Address use a'Address; + for b2'Address use b'Address; + for c2'Address use c'Address; + for d2'Address use d'Address; + for e2'Address use e'Address; + for f2'Address use f'Address; + begin + return a2 xor b2 xor c2 xor d2 xor e2 xor f2; + end; + + ---------------------------------- + -- CryptDRIS + ---------------------------------- + -- !!!! please overwrite the 3 parameters with the parameters specfied in DinkeyAdd + -- NB seed32, seed64 and bigseed64 are a clever way of initialising the bigseed array + procedure CryptDRIS(dris : t_DRIS_access; seed1, seed2 : uint32) is + i,j,k : uint32; + + type t_seed32 is array (1..2) of uint32; + type t_seed64 is array (1..1) of uint64; + seed32 : t_seed32; + seed64 : t_seed64; + for seed32'Address use seed64'Address; + + type t_uint64_array is array (1..32) of uint64; + bigseed64 : t_uint64_array; + + type t_uint8_array is array (uint8(0)..255) of uint8; + bigseed : t_uint8_array; + for bigseed'Address use bigseed64'Address; + + S : t_uint8_array; + temp, t : uint8; + + dris_size : uint32 := t_DRIS'Size/8; + type t_array is array (0..dris_size-1) of Interfaces.Unsigned_8; + dris_array : t_array; + for dris_array'Address use dris.all'Address; + + begin + + seed32 := (1=> seed1, 2 => seed2); + bigseed64 := (others => seed64(1)); + + for i in S'Range loop + S(i) := i; + end loop; + + j := 0; + for i in S'Range loop + j := (j + uint32(S(i)) + uint32(bigseed(i)) + 123) mod 256; -- !!!! parameter 1 (123) + temp := S(i); + S(i) := S(uint8(j)); + S(uint8(j)) := temp; + end loop; + + i := 0; + j := 0; + k := 16; + + while k < dris_size loop + i := (i + 1) mod 256; + j := (j + uint32(S(uint8(i))) + 212) mod 256; -- !!!! parameter 2 (212) + temp := S(uint8(i)); + S(uint8(i)) := S(uint8(j)); + S(uint8(j)) := temp; + t := uint8 (uint32(S(uint8(i)) + S(uint8(j)) + 97) mod 256); -- !!!! parameter 3 (97) + dris_array(k) := dris_array(k) xor S(t); + k := k + 1; + end loop; + end; + + + ---------------------------------- + -- CryptApiData + ---------------------------------- + -- !!!! if you specify parameters then you need to overwrite the parameters in this function. + -- However, if you use the R/W algorithm then you can use this function as it is. + -- NB seed32, seed64 and bigseed64 are a clever way of initialising the bigseed array + procedure CryptApiData (data : System.Address; + length : int32; + seed1, seed2 : uint32; + alg_answer : uint32) + is + i,j : uint32; + + type t_seed32 is array (1..2) of uint32; + type t_seed64 is array (1..1) of uint64; + seed32 : t_seed32; + seed64 : t_seed64; + for seed32'Address use seed64'Address; + + + type t_uint64_array is array (1..32) of uint64; + bigseed64 : t_uint64_array; + + type t_uint8_array is array (uint8(0)..255) of uint8; + bigseed : t_uint8_array; + for bigseed'Address use bigseed64'Address; + + S : t_uint8_array; + temp, t : uint8; + + type t_array is array (0..length-1) of Interfaces.Unsigned_8; + data_array : t_array; + for data_array'Address use data; + + begin + + seed32 := (1=> seed1, 2 => seed2); + bigseed64 := (others => seed64(1)); + + for i in S'Range loop + S(i) := i; + end loop; + + j := 0; + for i in S'Range loop + j := (j + uint32(S(i)) + uint32(bigseed(i)) + (uint32(alg_answer) and uint32(255))) mod 256; -- parameter 1 + temp := S(i); + S(i) := S(uint8(j)); + S(uint8(j)) := temp; + end loop; + + i := 0; + j := 0; + for k in data_array'Range loop + i := (i + 1) mod 256; + j := (j + uint32(S(uint8(i))) + (Shift_Right(uint32(alg_answer),8) and 255)) mod 256; -- parameter 2 + temp := S(uint8(i)); + S(uint8(i)) := S(uint8(j)); + S(uint8(j)) := temp; + t := uint8 ((uint32(S(uint8(i))) + uint32(S(uint8(j))) + uint32(Shift_Right(uint32(alg_answer),16) and 255)) mod 256); -- parameter 3 + data_array(k) := data_array(k) xor S(t); + end loop; + end; + + ---------------------------------- + -- ProtCheckEnc + ---------------------------------- + -- We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. + -- NB if you are using the debug module then do not call CryptDRIS as DRIS encryption is not supported. See notes in C readme.txt + function ProtCheckEnc return int32 is + ret_code : int32; + begin + + -- set the DRIS to have random values + random_set(dris); -- NB this also fills seed1, seed2 with random values + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := PROTECTION_CHECK; -- standard protection check + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + CryptDRIS(dris, dris.seed1, dris.seed2); -- encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code := DDProtCheck(dris, System.Null_Address); + + CryptDRIS(dris, dris.seed1, dris.seed2); -- decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + -- later in your code you can check other values in the DRIS... + + if (dris.sdsn /= MY_SDSN) then + Put_Line ("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + end if; + + -- later on in your program you can check the return code again + if (dris.ret_code /= 0) then + Put_Line ("Dinkey Dongle protection error"); + return -1; + end if; + + Put_Line ("ProtCheckEnc worked"); + return 0; + end; + + ---------------------------------- + -- ProtCheckWithAlgEnc + ---------------------------------- + -- NB for this to work you must program at least "user algorithm" into the dongle + -- NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + -- sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample code from DinkeyLook. + -- We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. + function ProtCheckWithAlgEnc return int32 is + ret_code : int32; + begin + -- set the DRIS to have random values + random_set(dris); -- NB this also fills seed1, seed2 with random values + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := EXECUTE_ALGORITHM; -- standard protection check & execute algorithm + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number := 1; -- execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + -- you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.var_a := 1; -- sample values + dris.var_b := 2; + dris.var_c := 3; + dris.var_d := 4; + dris.var_e := 5; + dris.var_f := 6; + dris.var_g := 7; + dris.var_h := 8; + + CryptDRIS(dris, dris.seed1, dris.seed2); -- encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code := DDProtCheck(dris, System.Null_Address); + + CryptDRIS(dris, dris.seed1, dris.seed2); -- decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + -- later in your code you can check other values in the DRIS... + + if (dris.sdsn /= MY_SDSN) then + Put_Line ("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + end if; + + -- ...later on in your program you can check the return code again + if (dris.ret_code /= 0) then + Put_Line ("Dinkey Dongle protection error"); + return -1; + end if; + + -- if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + -- !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) /= dris.alg_answer) then + Put_Line ("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine"); + return -1; + end if; + + Put_Line ("ProtCheckWithAlgEnc worked"); + return 0; + end; + + + ---------------------------------- + -- WriteBytesEnc + ---------------------------------- + -- This writes the Data "Hello, World!" to the dongle data area at offset 7 + -- In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. + -- We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + function WriteBytesEnc return int32 is + szDataToWrite : Interfaces.C.char_array := Interfaces.C.To_C ("Hello, World!", True); -- append null so we write that too! + ret_code : int32; + alg_ans : uint32; + begin + + -- set the DRIS to have random values + random_set(dris); -- NB this also fills seed1, seed2, var_a...var_h with random values + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := WRITE_DATA_AREA; -- standard protection check & write data + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset := 7; + dris.rw_length := szDataToWrite'Length; + dris.rw_data_ptr := szDataToWrite'Address; + + -- calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + -- encrypt data we want to write. + CryptApiData(szDataToWrite'Address, szDataToWrite'Length, dris.seed1, dris.seed2, alg_ans); + + CryptDRIS(dris, dris.seed1, dris.seed2); -- encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code := DDProtCheck(dris, System.Null_Address); + + CryptDRIS(dris, dris.seed1, dris.seed2); -- decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + -- ...later in your code you can check other values in the DRIS... + + if (dris.sdsn /= MY_SDSN) then + Put_Line ("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + end if; + + -- later on in your program you can check the return code again + if (dris.ret_code /= 0) then + Put_Line ("Dinkey Dongle protection error"); + return -1; + end if; + + Put_Line ("WriteBytesEnc worked"); + return 0; + end; + + ---------------------------------- + -- ReadBytesEnc + ---------------------------------- + -- This reads 14 bytes of data from offset 7 in the dongle data area + -- In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. + -- In order for the data to be displayed properly by this routine it will need to be text data + -- We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + function ReadBytesEnc return int32 is + szDataRead : Interfaces.C.char_array (1..14); + ret_code : int32; + alg_ans : uint32; + begin + -- set the DRIS to have random values + random_set(dris); -- NB this also fills seed1, seed2, var_a...var_h with random values + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := READ_DATA_AREA; -- standard protection check & read data + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset := 7; + dris.rw_length := szDataRead'Length; + dris.rw_data_ptr := szDataRead'Address; + + -- calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + CryptDRIS(dris, dris.seed1, dris.seed2); -- encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code := DDProtCheck(dris, System.Null_Address); + + CryptDRIS(dris, dris.seed1, dris.seed2); -- decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + -- ...later in your code you can check other values in the DRIS... + + if (dris.sdsn /= MY_SDSN) then + Put_Line ("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + end if; + + -- later on in your program you can check the return code again + if (dris.ret_code /= 0) then + Put_Line ("Dinkey Dongle protection error"); + return -1; + end if; + + -- decrypt data that was read. + CryptApiData(szDataRead'Address, szDataRead'Length, dris.seed1, dris.seed2, alg_ans); + + Put_Line("It worked! Dinkey Dongle Data area, offset 7 is: " & Interfaces.C.To_Ada(szDataRead)); + return 0; + end; + + + + ---------------------------------- + -- EncryptUserDataEnc + ---------------------------------- +-- ************************* EncryptUserDataEnc ****************************** +-- This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +-- It will then do another protection & decrypt the data +-- We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + function EncryptUserDataEnc return int32 is + szData : Interfaces.C.char_array := Interfaces.C.To_C ("Hello, World!"); + ret_code : int32; + alg_ans : uint32; + begin + -- set the DRIS to have random values + random_set(dris); + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := ENCRYPT_USER_DATA; -- standard protection check & encrypt user data + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num := 1; + dris.rw_length := szData'Length; + dris.rw_data_ptr := szData'Address; + + -- calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + -- encrypt data we want to pass. + CryptApiData(szData'Address, szData'Length, dris.seed1, dris.seed2, alg_ans); + + CryptDRIS(dris, dris.seed1, dris.seed2); -- encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code := DDProtCheck(dris, System.Null_Address); + + CryptDRIS(dris, dris.seed1, dris.seed2); -- decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + -- ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + -- Now decrypt the same data to get the original values + random_set(dris); + -- then set the values we want to use + dris.header := ('D','R','I','S'); + dris.size := dris.all'Size/8; + dris.funct := DECRYPT_USER_DATA; -- standard protection check & decrypt user data + dris.flags := 0; -- no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num := 1; + dris.rw_length := szData'Length; + dris.rw_data_ptr := szData'Address; + + CryptDRIS(dris, dris.seed1, dris.seed2); -- encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code := DDProtCheck(dris, System.Null_Address); + + CryptDRIS(dris, dris.seed1, dris.seed2); -- decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + -- ...later in your code you can check other values in the DRIS... + if (ret_code /= 0) then + DisplayError(ret_code, dris.ext_err); -- display messages for any errors that have occurred + return ret_code; + end if; + + if (dris.sdsn /= MY_SDSN) then + Put_Line ("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + end if; + + -- later on in your program you can check the return code again + if (dris.ret_code /= 0) then + Put_Line ("Dinkey Dongle protection error"); + return -1; + end if; + + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + -- decrypt data that was passed to us by the API + CryptApiData(szData'Address, szData'Length, dris.seed1, dris.seed2, alg_ans); + + Put_Line("It worked. Data decrypted is: " & Interfaces.C.To_Ada(szData)); + return 0; + end; + + -- ************* useful routines that are called from our functions ********** + + ---------------------------------- + -- random_set + ---------------------------------- + -- fills the buffer with length bytes of random data + -- NB there are better ways of doing this (for example with the Windows Crypto API calls) + procedure random_set(dris : t_DRIS_access) + is + package p_rand is new Ada.Numerics.Discrete_Random (Interfaces.Unsigned_8); + + G : p_rand.Generator; + size : Natural := t_DRIS'Size/8; + type t_array is array (1..size) of Interfaces.Unsigned_8; + T : t_array; + for T'Address use dris.all'Address; + begin + p_rand.Reset (G); + for i in T'Range loop + T(i) := p_rand.Random (G); + end loop; + end; + + ---------------------------------- + -- DisplayError + ---------------------------------- + -- displays messages for the most common errors. You will want to change this for your code + procedure DisplayError(ret_code : int32; extended_error : int32) + is + use Ada.Text_IO; + begin + case ret_code is + when 401 => Put_Line ("Error! No dongles detected!"); + when 403 => Put_Line ("Error! The dongle detected has a different type to the one specified in DinkeyAdd."); + when 404 => Put_Line ("Error! The dongle detected has a different model to those specified in DinkeyAdd."); + when 409 => Put_Line ("Error! The dongle detected has not been programmed by DinkeyAdd."); + when 410 => Put_Line ("Error! The dongle detected has a different Product Code to the one specified in DinkeyAdd."); + when 411 => Put_Line ("Error! The dongle detected does not contain the licence associated with this program."); + when 413 => Put_Line ("Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual."); + when 417 => Put_Line ("Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa."); + when 423 => Put_Line ("Error! The number of network users has been exceeded."); + when 435 => Put_Line ("Error! DinkeyServer has not been detected on the network."); + when 922 => Put_Line ("Error! The Software Key has expired."); + when others => + Put_Line ("An error occurred checking the dongle."); + Put_Line ("Error:" & int32'Image(ret_code) & ", Extended Error:" & int32'Image(extended_error) ); + end case; + end; + + ---------------------------------- + -- main + ---------------------------------- + +begin + -- call the function(s) of your choice here + -- by default I have chosen a standard protection check + + if (ProtCheck /= 0) then + return; -- terminate your program + end if; + + -- continue your program + +end apitest; diff --git a/Dinkey Pro 7.6.1/Samples/Ada/dris.ads b/Dinkey Pro 7.6.1/Samples/Ada/dris.ads new file mode 100644 index 0000000..85cf512 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Ada/dris.ads @@ -0,0 +1,110 @@ +-- dris.ads +-- Dinkey Runtime Information Structure (DRIS) +-- !! this file should not be modified + +with System; +with Interfaces; + +package dris is + + pragma linker_options ("-ldpwin32"); + + subtype uint8 is Interfaces.Unsigned_8; + subtype int32 is Interfaces.Integer_32; + subtype uint32 is Interfaces.Unsigned_32; + subtype uint64 is Interfaces.Unsigned_64; + + type t_DRIS; + + type t_DRIS_access is access all t_DRIS; + + -- functions - must specify only one + type t_functions is + (NONE, + PROTECTION_CHECK, -- checks for dongle, check program params... + EXECUTE_ALGORITHM, -- protection check + calculate answer for specified algorithm with specified inputs + WRITE_DATA_AREA, -- protection check + writes dongle data area + READ_DATA_AREA, -- protection check + reads dongle data area + ENCRYPT_USER_DATA, -- protection check + the dongle will encrypt user data + DECRYPT_USER_DATA, -- protection check + the dongle will decrypt user data + FAST_PRESENCE_CHECK, -- checks for the presence of the correct dongle only with minimal security, no flags allowed. + STOP_NET_USER -- stops a network user (a protection check is NOT performed) + ); + for t_functions'Size use 32; + + -- flags - can specify as many as you like + type t_flag is new int32; + DEC_ONE_EXEC : t_flag := 1; -- decrement execs by 1 + DEC_MANY_EXECS : t_flag := 2; -- decrement execs by number specified in execs_decrement + START_NET_USER : t_flag := 4; -- starts a network user + USE_FUNCTION_ARGUMENT : t_flag := 16; -- use the extra argument in the function for pointers + CHECK_LOCAL_FIRST : t_flag := 32; -- always look in local ports before looking in network ports + CHECK_NETWORK_FIRST : t_flag := 64; -- always look on the network before looking in local ports + USE_ALT_PROG_NAME : t_flag := 128; -- use name specified in prog_name instead of this program name + DONT_SET_MAXDAYS_EXPIRY : t_flag := 256; -- if the max days expiry date has not been calculated then do not do it this time + MATCH_DONGLE_NUMBER : t_flag := 512; -- restrict the search to match the dongle number specified in the DRIS + DONT_RETURN_FD_DRIVE : t_flag := 1024; -- if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + + -- DDProtCheck + function DDProtCheck (dris : t_DRIS_access; data : System.Address) return int32; + pragma import (StdCall, DDProtCheck, "DDProtCheck"); + + type t_array_4_char is array (0..3) of Character; + type t_array_12_char is array (0..11) of Character; + type t_array_128_char is array (0..127) of Character; + type t_array_256_char is array (0..255) of Character; + + type t_DRIS is record + -- the first 4 fields are never encrypted + header : t_array_4_char; + + -- inputs + size : int32; -- size of this structure + seed1 : uint32; -- seed for data/dris encryption + seed2 : uint32; -- as above + -- (maybe encrypted from now on) + funct : t_functions; -- specify only one function + flags : int32; -- options for the function selected. To use more than one OR them together: OPTION1 | OPTION2... + execs_decrement : uint32; -- amount by which to dec execs if we use flag: DEC_MANY_EXECS + data_crypt_key_num : int32; -- number of the key (1-3) that the dongle uses to encrypt or decrypt user data + rw_offset : int32; -- offset in the dongle data area to read or write data + rw_length : int32; -- length of data are to read/write/encrypt/decrypt + rw_data_ptr : System.Address; -- pointer to data to write / be read + alt_prog_name : t_array_256_char; -- protection check for different program instead of this one, must be null-terminated + var_a : int32; -- variable values for user algorithm + var_b : int32; + var_c : int32; + var_d : int32; + var_e : int32; + var_f : int32; + var_g : int32; + var_h : int32; + alg_number : int32; -- the number of the user algorithm that you want to execute + + -- outputs + ret_code : int32; -- return code from the protection check + ext_err : int32; -- extended error + dongle_type : int32; -- type of dongle detected. 1 = Pro, 2 = FD + model : int32; -- model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + sdsn : int32; -- Software Developer's Serial Number + prodcode : t_array_12_char; -- Product Code (null-terminated) + dongle_number : uint32; + update_number : int32; + data_area_size : uint32; -- size of the data area used in the dongle detected + max_alg_num : int32; -- the maximum algorithm number in the dongle detected + execs : int32; -- executions left: -1 indicates 'no limit' + exp_day : int32; -- expiry day: -1 indicates 'no limit' + exp_month : int32; -- expiry month: -1 indicates 'no limit' + exp_year : int32; -- expiry year: -1 indicates 'no limit' + features : uint32; -- features value + net_users : int32; -- maximum number of network users for the dongle detected: -1 indicates 'no limit' + alg_answer : int32; -- answer to the user algorithm executed with the given variable values + fd_capacity : uint32; -- capacity of the data area in FD dongle. + fd_drive : t_array_128_char; -- drive letter of FD dongle detected e.g. 'f:\' (or mount name under Linux) + swkey_type : int32; -- 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + swkey_exp_day : int32; -- software key expiry date (if software key detected) + swkey_exp_month : int32; + swkey_exp_year : int32; + end record; + +end dris; diff --git a/Dinkey Pro 7.6.1/Samples/AutoCAD/README.txt b/Dinkey Pro 7.6.1/Samples/AutoCAD/README.txt new file mode 100644 index 0000000..2eff74d --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/AutoCAD/README.txt @@ -0,0 +1,196 @@ +Notes on using AutoCAD with Dinkey Pro/FD +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To access a Dinkey Pro or FD dongle from AutoCAD, you must call an ActiveX DLL +using Visual LISP (AutoLISP). It is called dpcom32.dll (for 32-bit AutoCAD) and +dpcom64.dll (for 64-bit AutoCAD). These files are located in the Modules folder of +your SDK installation directory. + +This ActiveX control is an intermediary layer that calls the normal dpwin32.dll (32-bit) +or dpwin64.dll (64-bit) Runtime module. To protect your application, you should add +protection to dpwin32.dll (or dpwin64.dll) using DinkeyAdd specifying the API method +of protection. You should not protect dpcom32.dll (dpcom64.dll). [if you used a version +of the SDK previous to v7.0 please read the notes at the end of this file]. + +On 64-bit operating systems AutoCAD will always be 64-bit and on 32-bit operating +systems AutoCAD will always be 32-bit. You need to use the appropriate protected +ActiveX control (dpcom32.dll or dpcom64.dll) and protected Runtime module (dpwin32.dll +or dpwin64.dll) depending on whether 32-bit AutoCAD or 64-bit AutoCAD is being used. + +We recommend that you rename the protected runtime module. (reason: you may have more than +one Autocad product you want to protect. In this case, for each product, you can protect +our Runtime module (renamed in each case to a different filename) to different protection +parameters). + +To use the ActiveX control you must first register it with Windows: + +go to Start > All Programs > Accessories, right-click Command Prompt and choose +"Run As Administrator". Then enter: + + regsvr32 "\dpcom32.dll" + +To unregister it enter: + + regsvr32 /U "\dpcom32.dll" + +[For 64-bit Windows, replace dpcom32.dll with dpcom64.dll]. + +The ActiveX control needs to be registered on your end-users's machines. +Most installation programs allow you to do this automatically so that your +customers do not have to. + +The ActiveX control internally contains a DRIS structure. The idea is that, +after calling the initialisation function, you call one of the protection check +functions and then call as many of the Get... functions as you like to get the +parameters normally filled-in to the DRIS. These values remain valid until the +next protection check call when they are updated. + +Protecting AutoCAD programs using this ActiveX is not as secure compared to other +languages because of limitations of the AutoLISP programming language. For example +you cannot encrypt the DRIS or data passed to and from the API. To increase +security you can use an algorithm (see the ProtCheckWithAlg function). + +The API provided by dpcom32.dll / dpcom64.dll is listed below. There is also some +very simple sample code - dpsample.lsp. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in the +"Increasing your Protection" chapter of the manual. + +(See "Structures > DRIS Structure" in the user manual for an explanation of the parameters). + +** You must call the Initialisation Function, InitDPCOM, first ** + +InitDPCOM +~~~~~~~~~ +syntax: + (InitDPCOM bsDllName) +return: + return code (0 is success, otherwise one of the following errors can be returned: + 9003 - dll you specified cannot be loaded. Either not present in the correct + folder or you specified the wrong name / path. + 9004 - dll is loaded correctly but is not our runtime module! +notes: + this function must be called first to initialise the COM control + the parameter you pass is the renamed version of the protected runtime module + this module should be in the same folder as the COM control (if not you need + to specify the relative path and the filename). A typical call would be: + "InitDPCOM" "my_protected_dpwin32.dll" + +** Then you should call one of the Protection Check Functions listed below. ** +** In addition to the normal runtime errors returned by our runtime modules ** +** they can also return the error 9000 (InitDPCom not called). + +ProtCheck +~~~~~~~~~ +syntax: + (ProtCheck flags execs_decrement alt_licence_name) +returns: + return code (0 = success, otherwise an error number is returned) +notes: + performs a standard protection check. + see table below for details of flags values. You must specify execs_decrement + and alt_licence_name even if they are not used. A typical call would be: + "ProtCheck" 0 0 "" + +ProtCheckWithAlg +~~~~~~~~~~~~~~~~ +syntax: + (ProtCheckWithAlg flags alg_number var_a var_b var_c var_d var_e var_f var_g var_h ) +returns: + return code (0 = success, o.w. error number) +notes: + Performs a protection check and executes the user algorithm 'alg_number' + with variable values 'var_a'...'var_h'. + Call (GetAlgAnswer) to get the result of this algorithm after successfully calling + this function. + +WriteString +~~~~~~~~~~~ +syntax: + (WriteString flags offset DataString) +returns: + return code (0 = success, o.w. error number) +notes: + Performs a protection check and writes the string "DataString" to the dongle + data area at the offset specified. + +ReadString +~~~~~~~~~~~ +syntax: + (ReadString flags offset length) +returns: + return code (0 = success, o.w. error number) +notes: + Performs a protection check and reads data from the dongle data area. + Call (GetDataRead) to read the data string after successfully calling this function. + + +** After you have called either the ProtCheck or ProtCheckWithAlg or WriteString or ** +** ReadString functions you can call one of the following functions to get data from ** +** the DRIS. These functions will all return -2 (or "-2") if a protection check has ** +** not been performed. They will return -3 (or "-3") if a protection check has been ** +** performed but failed. Refer to the documentation regarding the DRIS for more ** +** information on each of these fields. + +None of these methods require input parameters. + +GetExtendedError - returns the extended error (only set if one of the protection check functions has failed) +GetType - returns the type of dongle detected. Numerical value - see DRIS documentation. +GetModel - returns the model of the dongle detected. Numerical value - see documentation on DRIS. +GetSDSN - returns the SDSN. +GetProdCode - returns the Product Code as a string. +GetDongleNumber - returns the donglenumber as a string. +GetUpdateNumber - returns the update number +GetDataAreaSize - returns the size of the data are +GetMaxAlgNum - returns the maximum algorithm number in the dongle detected +GetExecs - returns the execs left (-1 is "no limit") +GetExpDay - returns the expiry day (-1 is "no limit") +GetExpMonth - returns the expiry month (-1 is "no limit") +GetExpYear - returns the expiry year (-1 is "no limit") +GetFeatures - returns the features value. +GetNetUsers - returns the maximum number of simultaneous network user allowed by the dongle (-1 is "no lmiit") +GetAlgAnswer - returns the answer of the Algorithm (only valid if ProtCheckWithAlg previously called) +GetFDCapacity - returns the maximum capacity for the data area if an FD dongle is detected +GetFDDrive - returns the drive letter (mount name) of FD dongle detected e.g. f:\ +GetDataRead - returns the read read from the dongle data area (only valid if ReadString previously called). +GetSWKeyType - returns whether a software key was detected and what type it is +GetSWKeyExpDay - software key expiry day (if a software key was detected) +GetSWKeyExpMonth - software key expiry month +GetSWKeyExpYear - software key expiry year + +Visual LISP Code Example +~~~~~~~~~~~~~~~~~~~~~~~~ +dpsample.lsp gives a simple example of using the Dinkey Pro/FD API from Visual LISP. +To run dpsample.lsp: + +1. Enter 'vlisp' (without the quotes) on the AutoCAD command line to open the Visual LISP editor. +2. Open dpsample.lsp (and then click on the Window that contains the script to give it focus). +3. Use the toolbar or the menu 'Tools > Load Text in Editor' to load the dpsample function. +4. Enter '(dpsample)' (without the quotes) on the command line to execute the function. + +DRIS Flags Values +~~~~~~~~~~~~~~~~~ +In general the flags value will be 0. If you want to use more than one flag then add the values. + +Value Name in Manual Description +1 DEC_ONE_EXEC decrement executions by 1 +2 DEC_MANY_EXECS decrement executions by number specified in execs_decrement +4 START_NET_USER start a network user +8 STOP_NET_USER stops a network user (a protection check is NOT performed) +16 USE_FUNCTION_ARGUMENT use the extra argument in the function to pass data +32 CHECK_LOCAL_FIRST always look for a dongle locally before looking in network ports +64 CHECK_NETWORK_FIRST always look for a network dongle before looking for a dongle locally +128 USE_ALT_LICENCE_NAME use name specified in alt_licence_name instead of the default one +256 DONT_SET_MAXDAYS_EXPIRY if the max days expiry date has not been calculated then do not do it this time +512 MATCH_DONGLE_NUMBER restrict the search to match the dongle number specified in the DRIS +1024 DONT_RETURN_FD_DRIVE if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + +Notes on Changes Made to the ActiveX Control since version previous to 7.0 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The ActiveX controls we provided with versions of the SDK previous to 7.0 did not depend on +the runtime module and had to be protected directly. However, you can only register one of these +COMs per machine (renaming the file does not help in this case because it is identified by an internal +GUID which cannot be change). + +This meant that you could only protect one Product per machine. These old COM controls were loaded +using "DPro.DPro.1". The new COM controls can be loaded using "DPro.DPro.2". You can register both +COM controls on one machine at the same time if you need too as they have different internal GUIDs. diff --git a/Dinkey Pro 7.6.1/Samples/AutoCAD/dpsample.lsp b/Dinkey Pro 7.6.1/Samples/AutoCAD/dpsample.lsp new file mode 100644 index 0000000..eab743c --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/AutoCAD/dpsample.lsp @@ -0,0 +1,27 @@ +; Note - this code is provided only to illustrate the syntax of calling methods in dpcom32.dll / dpcom64.dll. +; You should modify it to use the Dinkey Pro/FD Visual LISP API to best suit your own needs. +; See the Dinkey Pro/FD Manual for more information on how best to use the API to improve the level of protection. + +(defun dpsample() + (vl-load-com) ; You MUST call this command first, to load all external COM objects including dpcom32.dll or dpcom64.dll + + (setq dinkeyobject (vlax-create-object "DPro.DPro.2")) ; Get a reference to the Dinkey Pro object + + (setq retvalue (vlax-invoke-method dinkeyobject "InitDPCOM" "my_renamed_dpwin32or64.dll")) + (if (= retvalue 0) ; Check the return value of intialisation + (princ "Initialisation worked OK") ; init successful + (princ (strcat "Initialisation failed with error " (itoa retvalue))) ; init failed - dll not in correct place, or wrong name specified? + ) + + (princ "\n") + + (setq retvalue (vlax-invoke-method dinkeyobject "ProtCheck" 0 0 "")) ; Call this object's 'ProtCheck' method + (if (= retvalue 0) ; Check the return value of the protection check + (princ "It worked!") ; Protection check successful + (princ (strcat "Protection check failed with error " (itoa retvalue))) ; Protection check failed, display an error message + ) + + (vlax-release-object dinkeyobject) ; Release the Dinkey object reference + + (princ) +) diff --git a/Dinkey Pro 7.6.1/Samples/C#/DinkeyAdd/App.ico b/Dinkey Pro 7.6.1/Samples/C#/DinkeyAdd/App.ico new file mode 100644 index 0000000..3a5525f Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C#/DinkeyAdd/App.ico differ diff --git a/Dinkey Pro 7.6.1/Samples/C#/DinkeyAdd/AssemblyInfo.cs b/Dinkey Pro 7.6.1/Samples/C#/DinkeyAdd/AssemblyInfo.cs new file mode 100644 index 0000000..9f89a32 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/DinkeyAdd/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/Dinkey Pro 7.6.1/Samples/C#/DinkeyAdd/Form1.cs b/Dinkey Pro 7.6.1/Samples/C#/DinkeyAdd/Form1.cs new file mode 100644 index 0000000..4eb8d1c --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/DinkeyAdd/Form1.cs @@ -0,0 +1,548 @@ +// !! We strongly recommend that you read the "readme.txt" file in the sample code folder. +// !! It contains important instructions on how to use the sample code + +using System; +using System.Drawing; +using System.Collections; +using System.ComponentModel; +using System.Windows.Forms; +using System.Data; +using System.Runtime.InteropServices; // so we can marshal our structures in dapf.cs + +namespace dapfTest +{ + /// + /// Summary description for Form1. + /// + public class Form1 : System.Windows.Forms.Form + { + /// + /// Required designer variable. + /// + private System.ComponentModel.Container components = null; + + public Form1() + { + // + // Required for Windows Form Designer support + // + InitializeComponent(); + + // + // TODO: Add any constructor code after InitializeComponent call + // + } + + /// + /// Clean up any resources being used. + /// + protected override void Dispose( bool disposing ) + { + if( disposing ) + { + if (components != null) + { + components.Dispose(); + } + } + base.Dispose( disposing ); + } + + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.TextBox machineIDText; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.TextBox expdayText; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.TextBox expmonthText; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.TextBox expyearText; + private GroupBox groupBox2; + private Label label9; + private TextBox maxDaysText; + private Button demoSoftwareKey; + + public string AppName = "dapfTest"; + + #region Windows Form Designer generated code + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.dapfFile = new System.Windows.Forms.TextBox(); + this.programDongle = new System.Windows.Forms.Button(); + this.programDongleMod = new System.Windows.Forms.Button(); + this.lockSoftware = new System.Windows.Forms.Button(); + this.tempSoftwareKey = new System.Windows.Forms.Button(); + this.encryptShellData = new System.Windows.Forms.Button(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.expyearText = new System.Windows.Forms.TextBox(); + this.label5 = new System.Windows.Forms.Label(); + this.expmonthText = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.expdayText = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.machineIDText = new System.Windows.Forms.TextBox(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.label9 = new System.Windows.Forms.Label(); + this.maxDaysText = new System.Windows.Forms.TextBox(); + this.demoSoftwareKey = new System.Windows.Forms.Button(); + this.groupBox1.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.SuspendLayout(); + // + // label1 + // + this.label1.Location = new System.Drawing.Point(16, 24); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(416, 16); + this.label1.TabIndex = 0; + this.label1.Text = "Full path of dapf file:"; + // + // dapfFile + // + this.dapfFile.Location = new System.Drawing.Point(16, 40); + this.dapfFile.Name = "dapfFile"; + this.dapfFile.Size = new System.Drawing.Size(344, 20); + this.dapfFile.TabIndex = 1; + // + // programDongle + // + this.programDongle.Location = new System.Drawing.Point(84, 88); + this.programDongle.Name = "programDongle"; + this.programDongle.Size = new System.Drawing.Size(208, 23); + this.programDongle.TabIndex = 2; + this.programDongle.Text = "Program Dongle"; + this.programDongle.Click += new System.EventHandler(this.programDongle_Click); + // + // programDongleMod + // + this.programDongleMod.Location = new System.Drawing.Point(84, 128); + this.programDongleMod.Name = "programDongleMod"; + this.programDongleMod.Size = new System.Drawing.Size(208, 23); + this.programDongleMod.TabIndex = 3; + this.programDongleMod.Text = "Program Dongle with modification"; + this.programDongleMod.Click += new System.EventHandler(this.programDongleMod_Click); + // + // lockSoftware + // + this.lockSoftware.Location = new System.Drawing.Point(84, 168); + this.lockSoftware.Name = "lockSoftware"; + this.lockSoftware.Size = new System.Drawing.Size(208, 23); + this.lockSoftware.TabIndex = 4; + this.lockSoftware.Text = "Lock Software"; + this.lockSoftware.Click += new System.EventHandler(this.lockSoftware_Click); + // + // tempSoftwareKey + // + this.tempSoftwareKey.Location = new System.Drawing.Point(64, 88); + this.tempSoftwareKey.Name = "tempSoftwareKey"; + this.tempSoftwareKey.Size = new System.Drawing.Size(208, 23); + this.tempSoftwareKey.TabIndex = 5; + this.tempSoftwareKey.Text = "Create Software Key"; + // + // encryptShellData + // + this.encryptShellData.Location = new System.Drawing.Point(84, 208); + this.encryptShellData.Name = "encryptShellData"; + this.encryptShellData.Size = new System.Drawing.Size(208, 23); + this.encryptShellData.TabIndex = 6; + this.encryptShellData.Text = "Encrypt Shell Data Files"; + this.encryptShellData.Click += new System.EventHandler(this.encryptShellData_Click); + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.expyearText); + this.groupBox1.Controls.Add(this.label5); + this.groupBox1.Controls.Add(this.expmonthText); + this.groupBox1.Controls.Add(this.label4); + this.groupBox1.Controls.Add(this.expdayText); + this.groupBox1.Controls.Add(this.label3); + this.groupBox1.Controls.Add(this.label2); + this.groupBox1.Controls.Add(this.machineIDText); + this.groupBox1.Controls.Add(this.tempSoftwareKey); + this.groupBox1.Location = new System.Drawing.Point(16, 256); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(336, 128); + this.groupBox1.TabIndex = 7; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Temporary Software Key"; + // + // expyearText + // + this.expyearText.Location = new System.Drawing.Point(240, 56); + this.expyearText.Name = "expyearText"; + this.expyearText.Size = new System.Drawing.Size(32, 20); + this.expyearText.TabIndex = 13; + this.expyearText.Text = "yyyy"; + // + // label5 + // + this.label5.Location = new System.Drawing.Point(224, 56); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(8, 20); + this.label5.TabIndex = 12; + this.label5.Text = "/"; + this.label5.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // expmonthText + // + this.expmonthText.Location = new System.Drawing.Point(184, 56); + this.expmonthText.Name = "expmonthText"; + this.expmonthText.Size = new System.Drawing.Size(32, 20); + this.expmonthText.TabIndex = 11; + this.expmonthText.Text = "mm"; + // + // label4 + // + this.label4.Location = new System.Drawing.Point(168, 56); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(8, 20); + this.label4.TabIndex = 10; + this.label4.Text = "/"; + this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // expdayText + // + this.expdayText.Location = new System.Drawing.Point(128, 56); + this.expdayText.Name = "expdayText"; + this.expdayText.Size = new System.Drawing.Size(32, 20); + this.expdayText.TabIndex = 9; + this.expdayText.Text = "dd"; + // + // label3 + // + this.label3.Location = new System.Drawing.Point(24, 56); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(100, 20); + this.label3.TabIndex = 8; + this.label3.Text = "Expiry Date:"; + this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // label2 + // + this.label2.Location = new System.Drawing.Point(24, 24); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(100, 20); + this.label2.TabIndex = 7; + this.label2.Text = "Machine ID:"; + this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // machineIDText + // + this.machineIDText.Location = new System.Drawing.Point(128, 24); + this.machineIDText.Name = "machineIDText"; + this.machineIDText.Size = new System.Drawing.Size(184, 20); + this.machineIDText.TabIndex = 6; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.label9); + this.groupBox2.Controls.Add(this.maxDaysText); + this.groupBox2.Controls.Add(this.demoSoftwareKey); + this.groupBox2.Location = new System.Drawing.Point(19, 400); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(336, 99); + this.groupBox2.TabIndex = 14; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Demo Software Key"; + // + // label9 + // + this.label9.Location = new System.Drawing.Point(24, 24); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(100, 20); + this.label9.TabIndex = 7; + this.label9.Text = "Max Days:"; + this.label9.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // maxDaysText + // + this.maxDaysText.Location = new System.Drawing.Point(128, 24); + this.maxDaysText.Name = "maxDaysText"; + this.maxDaysText.Size = new System.Drawing.Size(184, 20); + this.maxDaysText.TabIndex = 6; + // + // demoSoftwareKey + // + this.demoSoftwareKey.Location = new System.Drawing.Point(61, 59); + this.demoSoftwareKey.Name = "demoSoftwareKey"; + this.demoSoftwareKey.Size = new System.Drawing.Size(208, 23); + this.demoSoftwareKey.TabIndex = 5; + this.demoSoftwareKey.Text = "Create Demo Template"; + this.demoSoftwareKey.Click += new System.EventHandler(this.demoSoftwareKey_Click); + // + // Form1 + // + this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); + this.ClientSize = new System.Drawing.Size(376, 523); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.encryptShellData); + this.Controls.Add(this.lockSoftware); + this.Controls.Add(this.programDongleMod); + this.Controls.Add(this.programDongle); + this.Controls.Add(this.dapfFile); + this.Controls.Add(this.label1); + this.Name = "Form1"; + this.Text = "Form1"; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox dapfFile; + private System.Windows.Forms.Button programDongle; + private System.Windows.Forms.Button programDongleMod; + private System.Windows.Forms.Button lockSoftware; + private System.Windows.Forms.Button tempSoftwareKey; + private System.Windows.Forms.Button encryptShellData; + + /* The sample code contains 5 functions. You will not need to use all these functions in your code. + Just use which ever functions are most appropriate and customise in your own way. The sample code + is just a guide. + + There are two methods to loading a DAPF file. These are shown in the first two functions + programDongle_Click and programDongleMod_Click: + + programDongle_Click: we load the DAPF file from disk and get a handle and use it "as is" using the API + call LoadDAPFFromFile. You can make some limited changes to overwrite the default + behaviour by using API flags. + + programDongleMod_Click: we load the DAPF file from disk and load into structures. We can then modify the + DAPF settings by modifying this structure. This method uses the API calls + ReadDAPFEx and LoadDAPF. + + The other functions use the first method (as it is simpler) but you can use the second method instead if + you prefer. + + Note - an alternative to using the programDongleMod_Click technique is to modify the DAPF file on disk + and then use the programDongle_Click technique. To modify a binary DAPF you would use the binary structures + that are defined in dapf.h. To modify JSON DAPF you would need to use a JSON parser. + + lockSoftware_Click : locks software (protect it) to a dongle as specified by the DAPF file. + + encryptShellData_Click: encrypts the shell data files specified in the DAPF file (this is used with encrypting + data file if you use the Shell Method with "Data File Encryption" enabled). + + tempSoftwareKey_Click: creates a Temporary Software Key based on the DAPF file and settings the user has entered. + + demoSoftwareKey_Click: creates a Demo Software Key Template based on the DAPF file and settings the user has entered. + + */ + + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.Run(new Form1()); + } + + // load a DAPF file from disk and program the dongle as specified by the DAPF file + private void programDongle_Click(object sender, System.EventArgs e) + { + IntPtr dapfHandle; + int err_code; + uint dongle_number; + + // load DAPF from File into memory + dapfHandle = DinkeyAdd.LoadDAPFFromFile(dapfFile.Text, out err_code); + if (dapfHandle == IntPtr.Zero) + { + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + // program dongle as specified by the DAPF file + err_code = DinkeyAdd.AddProtection(dapfHandle, DinkeyAdd.ACTION_PROGRAM_DONGLE, 0, 0, out dongle_number); + + // Unload DAPF from memory + DinkeyAdd.UnloadDAPF(ref dapfHandle); + + // display message (error or success) + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + + // load a DAPF file from disk, modify it in memory and then program the dongle + private void programDongleMod_Click(object sender, System.EventArgs e) + { + IntPtr dapfHandle; + int dummy1, dummy2, err_code; + uint dongle_number; + DINKEYINFO DinkeyInfo; + LICENCEINFO[] LicenceInfo; + FILEINFO[] FileInfo; + ALGORITHM[] Algorithms; + DATAFILEENC[] DataFileEnc; + + // in this case we need to read the DAPF into our structures, so that the DAPF values can be modified + err_code = DinkeyAdd.ReadDAPFEx(dapfFile.Text, out DinkeyInfo, out LicenceInfo, out FileInfo, out Algorithms, out DataFileEnc, out dummy1, out dummy2); + if (err_code != 0) + { + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + // patch new values + LicenceInfo[0].Features = 12345; + LicenceInfo[0].Execs = 100; + LicenceInfo[0].LicenceName = "fred"; + + // get DAPF handle + dapfHandle = DinkeyAdd.LoadDAPF(DinkeyInfo, LicenceInfo, FileInfo, Algorithms, DataFileEnc, out err_code); + if (dapfHandle == IntPtr.Zero) + { + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + // program dongle + err_code = DinkeyAdd.AddProtection(dapfHandle, DinkeyAdd.ACTION_PROGRAM_DONGLE, 0, 0, out dongle_number); + + // Unload DAPF from memory + DinkeyAdd.UnloadDAPF(ref dapfHandle); + + // display message (error or success) + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + + // load a DAPF file from disk and protect the files specified + // (in practice it is better to protect the files one at a time and output messages as you go along, similar to DinkeyAdd.exe) + // In this example we specify the flag to overwrite any existing output file that might exist. + private void lockSoftware_Click(object sender, System.EventArgs e) + { + IntPtr dapfHandle; + int err_code; + uint dummy; + + // load DAPF from File into memory + dapfHandle = DinkeyAdd.LoadDAPFFromFile(dapfFile.Text, out err_code); + if (dapfHandle == IntPtr.Zero) + { + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + // protect all the files listed in the DAPF file + err_code = DinkeyAdd.AddProtection(dapfHandle, DinkeyAdd.ACTION_PROTECT_SOFTWARE, -1, DinkeyAdd.FLAGS_OVERWRITE_OUTPUT, out dummy); + + // Unload DAPF from memory + DinkeyAdd.UnloadDAPF(ref dapfHandle); + + // display message (error or success) + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + + // load a DAPF file from disk and encrypt the shell data files specified + // (in practice it is better to encrypt the files one at a time and output messages as you go along, similar to DinkeyAdd.exe) + // In this example we specify the flag to overwrite any existing output file that might exist. + private void encryptShellData_Click(object sender, System.EventArgs e) + { + IntPtr dapfHandle; + int err_code; + + // load DAPF from File into memory + dapfHandle = DinkeyAdd.LoadDAPFFromFile(dapfFile.Text, out err_code); + if (dapfHandle == IntPtr.Zero) + { + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + // encrypt all the shell data files listed in the DAPF file + err_code = DinkeyAdd.EncryptShellDataFiles(dapfHandle, -1, DinkeyAdd.FLAGS_OVERWRITE_OUTPUT); + + // Unload DAPF from memory + DinkeyAdd.UnloadDAPF(ref dapfHandle); + + // display message (error or success) + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + + // load a DAPF file from disk and create a Temporary Software Key using the info that the user entered + private void tempSoftwareKey_Click(object sender, System.EventArgs e) + { + IntPtr dapfHandle; + int err_code; + TEMP_SWKEY_INFO swkey_info = new TEMP_SWKEY_INFO(); + + // load DAPF from File into memory + dapfHandle = DinkeyAdd.LoadDAPFFromFile(dapfFile.Text, out err_code); + if (dapfHandle == IntPtr.Zero) + { + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + // fill out the SWKEY structure from the values the user entered + swkey_info.size = Marshal.SizeOf(typeof(TEMP_SWKEY_INFO)); + swkey_info.machineID = Convert.ToUInt32(machineIDText.Text, 16); + swkey_info.expiry_day = Convert.ToInt32(expdayText.Text, 10); + swkey_info.expiry_month = Convert.ToInt32(expmonthText.Text, 10); + swkey_info.expiry_year = Convert.ToInt32(expyearText.Text, 10); + // !!!! in this case we just choose Pro Plus. You could load the DAPF file into structures and see which model is selected. + // If there is more than one model selected you can ask the customer to choose which model they want. + swkey_info.dongle_model = DinkeyAdd.SWKEY_MODEL_PRO_PLUS; + swkey_info.dongle_number = 0; + + // attempt to create the Temporary Software Key + err_code = DinkeyAdd.CreateTempSoftwareKey(dapfHandle, swkey_info, 0); + + // Unload DAPF from memory + DinkeyAdd.UnloadDAPF(ref dapfHandle); + + // display message (error or success) + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + + private void demoSoftwareKey_Click(object sender, EventArgs e) + { + IntPtr dapfHandle; + int err_code; + DEMO_SWKEY_INFO swkey_info = new DEMO_SWKEY_INFO(); + + // load DAPF from File into memory + dapfHandle = DinkeyAdd.LoadDAPFFromFile(dapfFile.Text, out err_code); + if (dapfHandle == IntPtr.Zero) + { + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + // fill out the SWKEY structure from the values the user entered + swkey_info.size = Marshal.SizeOf(typeof(DEMO_SWKEY_INFO)); + swkey_info.max_days = Convert.ToInt32(maxDaysText.Text, 10); + // !!!! in this case we just choose the default model (assuming you only selected one in the DAPF file). + // If you want to specify more than one model then OR the flags together. e.g. DinkeyAdd.SWKEY_BITMAP_PRO_LITE | DinkeyAdd.SWKEY_BITMAP_PRO_PLUS + swkey_info.models = DinkeyAdd.SWKEY_BITMAP_DEFAULT; + + // attempt to create the Temporary Software Key + err_code = DinkeyAdd.CreateDemoSoftwareKeyTemplate(dapfHandle, swkey_info, 0); + + // Unload DAPF from memory + DinkeyAdd.UnloadDAPF(ref dapfHandle); + + // display message (error or success) + MessageBox.Show(DinkeyAdd.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + + } +} diff --git a/Dinkey Pro 7.6.1/Samples/C#/DinkeyAdd/Form1.resx b/Dinkey Pro 7.6.1/Samples/C#/DinkeyAdd/Form1.resx new file mode 100644 index 0000000..19dc0dd --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/DinkeyAdd/Form1.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/C#/DinkeyAdd/README.txt b/Dinkey Pro 7.6.1/Samples/C#/DinkeyAdd/README.txt new file mode 100644 index 0000000..6f54b94 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/DinkeyAdd/README.txt @@ -0,0 +1,50 @@ +dapfTest - sample code to call DinkeyAdd Module in C# +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 2002 but will work in more recent +versions of Visual Studio (they will upgrade the Project to the latest version. +If prompted you should also upgrade the .NET framework the project requires). + +For users of Visual Studio 2005 or higher, the default setting to projects is to +compile for the Target Platform "Any". This means that on 32-bit Windows, your +code will run as 32-bit code (and needs to call DinkeyAdd32.dll) and under 64-bit +Windows your code will run as 64-bit code (and needs to call DinkeyAdd64.dll). +The sample code works this out automatically. If you select the target platform as "x86" +then it will always be 32-bit and so you only need to use DinkeyAdd32.dll. If you +select "x64" then your code will be 64-bit and you only need to use DinkeyAdd64.dll. + +The main source files in the project are: + +dapf.cs - the source file contains declarations of our API. We automatically + work out whether your code is running in 32-bit or 64-bit and load + the appropriate DinkeyAdd module. + +Form1.cs - this is the sample code giving an example on how you can call our API. + It contains 5 functions. Just use which ever functions are most appropriate + and customise in your own way. + +The best approach is to compile the sample code and see how it works and then to take +the appropriate code and apply it to your own project. You should include the dapf.cs +file in your project and use/modify which ever functions from Form1.cs you feel are +appropriate. The dapf.cs file should not be modified. + +The sample code is just a guide. As none of the parameters are security sensitive then +there is no need to implement strong security in calling DinkeyAdd. + +Make sure you remember to do the following when creating your own project: + +1) Insert the following namespaces in your code file: +using System.Runtime.InteropServices; + +2) Insert the dapf.cs file in your project. + +3) You need to put DinkeyAdd32.dll and/or DinkeyAdd64.dll into the folder that +contains dapfTest. Otherwise the System.DllNotFoundException error will appear +when you run dapfTest. + +Notes on Debugging 64-bit Code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +When you use the 64-bit module (DinkeyAdd64.dll) the anti-debug code is so strong +that if you are debugging your code, after calling our API then it will crash with +an SEH exception. There are no debug modules for DinkeyAdd so you will have to find +other ways of debugging your code (for example taking out the call altogether). diff --git a/Dinkey Pro 7.6.1/Samples/C#/DinkeyAdd/dapf.cs b/Dinkey Pro 7.6.1/Samples/C#/DinkeyAdd/dapf.cs new file mode 100644 index 0000000..bc2f08a --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/DinkeyAdd/dapf.cs @@ -0,0 +1,552 @@ +// !! this file should not be modified + +// DAPF file is in the following format: +// DINKEYINFO +// LICENCEINFO (however many are needed) +// FILEINFO (however many are needed) +// ALGORITHM (however many are needed) +// DATAFILEENC (however many are needed) + +using System; +using System.Runtime.InteropServices; // so we can marshal the structures as a block of memory +using System.Text; // for StringBuilder class for GetLastMessage API + +// *********** define structures that make up the DAPF file ******************* + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct DINKEYINFO +{ + public byte Header1; // should be set to "DAPF" + public byte Header2; + public byte Header3; + public byte Header4; + public int Version; // version of this structure. Currently 9. + public int SelectedModels; // BIT0 = Dinkey Pro Lite, BIT1 = Dinkey Pro Plus, BIT2 = Dinkey Pro Net etc... + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=12)] + public string ProdCode; + public int PerLicence; // 1 = per licence, 0 = per product (default) + public int MaxNetUsers; // product net users, unlimited = -1, no entry = -2 + public int RangeSettings; // 0 = any number, 1 = dongle in computer, 2 = range + public uint RangeMin; + public uint RangeMax; + public int NumLicences; // number of LICENCEINFO structures in this DAPF file + public int NumProgs; // number of FILEINFO structures in this DAPF file + public int NumAlgs; + public int DataSizeType; // 1 = set the zero data size, 0 = use file to initialise data area + public int ZeroDataSize; // size of the data area area in bytes + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string DataFile; // path to data file (0 = no data file) + public int DataAreaSize; // file size in bytes, -1 = file not found + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string ShellSuccessMsg; // Shell Method messages... + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string ShellNoDongleMsg; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string ShellExpiryDateMsg; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string ShellExpiryExecsMsg; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string ShellWarnDateMsg; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string ShellWarnExecsMsg; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string ShellNetUserLimitMsg; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string ShellOtherErrorMsg; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string ShellBackgroundMsg; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string NetNoServerMsg; + [MarshalAs(UnmanagedType.ByValArray, SizeConst=12)] + public byte[] rwalg; // coded form of rw algorithm (0 = no algorithm) + public int SecOptions; // BIT0: DRIS encryption, BIT1: Data encryption, BIT2: Data enc with alg, BIT3: only secure update codes + public byte SecDRISEncKey1; // DRIS encryption parameters + public byte SecDRISEncKey2; + public byte SecDRISEncKey3; + public byte Ignored1; // this byte is ignored + public byte SecDataEncKey1; // API Data encryption parameters + public byte SecDataEncKey2; + public byte SecDataEncKey3; + public byte Ignored2; // this byte is ignored + public int ProtectionType; // 0 = software + dongle, 1 = dongle only, 2 = program only + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=12)] + public string DataEncKeyProdCode; // Alternative Product Code used to generate internal encryption keys. Normally set to 0. + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string Notes; // user-defined notes + public int LockDongle; // 0 = don't lock (default), 1 = lock dongle to user's computer + public int Reserved1; // must be 0 + public int Reserved2; // must be 0 + public int AdvancedOptions; // BIT0 = do not allow usb-over-network for non-Net dongles, BIT1 = do not check for Software Key at Runtime. + public int NumDataFileEnc; // Number of data files in our encryption list +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct LICENCEINFO +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string LicenceName; + public int MaxDays; // -1 = no limit + public int ExpiryDay; // -1 = no limit, 0 = no change + public int ExpiryMonth; + public int ExpiryYear; + public int Execs; // -1 = no limit + public int ExecsWarn; // 0 = no warning (just for Shell method) + public int DaysWarn; // 0 = no warning (just for Shell method) + public uint Features; + public int LicenceNetUsers; // unlimited = -1 (-2 = not needed (this is for display only)) +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct FILEINFO +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string InputName; // input file (full path) + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string OutputName; // output file/folder + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string CallingProg; // calling program name + public int LicenceIndex; // index (of licence) in the LicenceInfo structure (1-based index. 0 = no selection) + public int Method; // 0-api, 1-shell, 2-shell & api + public int ShellFlags; // same bit flag values as in dris. i.e. 1 = DEC_ONE_EXEC, 4 = START_NET_USER + public int BackGround; // 0=no background, 1=1min, 2=5min, 3=10min, 4=30min, 5=60min + public int OtherShellOptions; // BIT0 = Shell Data Encryption is enabled, BIT1: Extra Anti-Debug is disabled, BIT2: Extra Anti-Piracy is disabled + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string EncFileList; // files (or file types) that the Shell-protected program will treat as encrypted (separated by ':') + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string ExceptList; // files (or file types) that are exceptions to the above list (separated by ':') + public int ExtraAntiPiracy; // 0 = off, 1=min, 10=max +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct ALGORITHM +{ + [MarshalAs(UnmanagedType.ByValArray, SizeConst=12)] + public byte[] alg; +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct DATAFILEENC +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string InputName; // file name, wild cards are allowed + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string OutputName; // file name (or folder name if input is a wildcard) +} + +// this structure is used for creating temporary software keys +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct TEMP_SWKEY_INFO +{ + public int size; // size of this structure (must be initialised) + public uint machineID; // machine ID in (hex) integer form + public int expiry_day; // expiry date of the Software Key + public int expiry_month; + public int expiry_year; + public int dongle_model; // model of the Software Key. See constant values below + public uint dongle_number; // dongle number of the Software Key. 0 = default (random) +} + +// this structure is used for creating demo software key templates +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct DEMO_SWKEY_INFO +{ + public int size; // size of this structure (must be initialised) + public int max_days; // max days demo swkey installation is valid (0-60) + public int models; // bitmap of valid dongle models. See constant values below. 0 = default (only use if only one model is selected in DINKEYINFO) +} + + +// ********************** API functions ************************ +// we declare classes for all the API functions for each bitness + +// Loads DAPF from disk and returns handle +class LoadDAPFFromFile32 +{ + [DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)] + public static extern IntPtr LoadDAPFFromFile(string dapf_file, out int err_code); +} + +class LoadDAPFFromFile64 +{ + [DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)] + public static extern IntPtr LoadDAPFFromFile(string dapf_file, out int err_code); +} + +// Loads DAPF from disk into structures supplied (so we can modify DAPF in memory) +class ReadDAPFEx32 +{ + [DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)] + public static extern int ReadDAPFEx(string dapf_file, out DINKEYINFO DinkeyInfo, byte[] licence_bytes, byte[] fileinfo_bytes, byte[] alg_bytes, byte[] datafile_bytes, out int dapf_version, out int dapf_format); +} + +class ReadDAPFEx64 +{ + [DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)] + public static extern int ReadDAPFEx(string dapf_file, out DINKEYINFO DinkeyInfo, byte[] licence_bytes, byte[] fileinfo_bytes, byte[] alg_bytes, byte[] datafile_bytes, out int dapf_version, out int dapf_format); +} + +// Loads DAPF from structures and returns a handle +class LoadDAPF32 +{ + [DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)] + public static extern IntPtr LoadDAPF(ref DINKEYINFO DinkeyInfo, byte[] licence_bytes, byte[] fileinfo_bytes, byte[] alg_bytes, byte[] datafile_bytes, out int ret_code); +} + +class LoadDAPF64 +{ + [DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)] + public static extern IntPtr LoadDAPF(ref DINKEYINFO DinkeyInfo, byte[] licence_bytes, byte[] fileinfo_bytes, byte[] alg_bytes, byte[] datafile_bytes, out int ret_code); +} + +// saves the DAPF file to disk +class WriteDAPFEx32 +{ + [DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)] + public static extern int WriteDAPFEx(IntPtr dapf_handle, string dapf_file, int dapf_format, int dapf_version, int flags); +} + +class WriteDAPFEx64 +{ + [DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)] + public static extern int WriteDAPFEx(IntPtr dapf_handle, string dapf_file, int dapf_format, int dapf_version, int flags); +} + +// unloads the DAPF file +class UnloadDAPF32 +{ + [DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)] + public static extern void UnloadDAPF(ref IntPtr dapf_handle); +} + +class UnloadDAPF64 +{ + [DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)] + public static extern void UnloadDAPF(ref IntPtr dapf_handle); +} + +class AddProtection32 +{ + [DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)] + public static extern int AddProtection(IntPtr dapf_handle, int action, int file_num, int flags, out uint dongle_number); +} + +class AddProtection64 +{ + [DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)] + public static extern int AddProtection(IntPtr dapf_handle, int action, int file_num, int flags, out uint dongle_number); +} + +class CreateTempSoftwareKey32 +{ + [DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)] + public static extern int CreateTempSoftwareKey(IntPtr dapf_handle, ref TEMP_SWKEY_INFO swkey_info, int flags); +} + +class CreateTempSoftwareKey64 +{ + [DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)] + public static extern int CreateTempSoftwareKey(IntPtr dapf_handle, ref TEMP_SWKEY_INFO swkey_info, int flags); +} + +class CreateDemoSoftwareKeyTemplate32 +{ + [DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)] + public static extern int CreateDemoSoftwareKeyTemplate(IntPtr dapf_handle, ref DEMO_SWKEY_INFO swkey_info, int flags); +} + +class CreateDemoSoftwareKeyTemplate64 +{ + [DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)] + public static extern int CreateDemoSoftwareKeyTemplate(IntPtr dapf_handle, ref DEMO_SWKEY_INFO swkey_info, int flags); +} + +class EncryptShellDataFiles32 +{ + [DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)] + public static extern int EncryptShellDataFiles(IntPtr dapf_handle, int file_num, int flags); +} + +class EncryptShellDataFiles64 +{ + [DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)] + public static extern int EncryptShellDataFiles(IntPtr dapf_handle, int file_num, int flags); +} + +class GetLastMessage32 +{ + [DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)] + public static extern void GetLastMessage(StringBuilder message, int buffer_size, out int message_length); +} + +class GetLastMessage64 +{ + [DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)] + public static extern void GetLastMessage(StringBuilder message, int buffer_size, out int message_length); +} + +class GetLastExtendedError32 +{ + [DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)] + public static extern int GetLastExtendedError(); +} + +class GetLastExtendedError64 +{ + [DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)] + public static extern int GetLastExtendedError(); +} + +// ********************* DinkeyAdd class ********************** +class DinkeyAdd +{ + // constants + public const int DAPF_VERSION = 9; // current DAPF version + + // WriteDAPFEx API flags + public const int FLAGS_LOSE_FEATURES = 1; // means that you can save the DAPF file to an earlier version even if it means losing some new features that have been currently set + + // AddProtection API action values + public const int ACTION_USE_DAPF_SETTINGS = 0; // means you just ignore the action value and use the default dapf settings + public const int ACTION_PROGRAM_DONGLE = 1; // program the dongle only + public const int ACTION_PROTECT_SOFTWARE = 2; // protect a software file (index indicated by separate parameter) + public const int ACTION_PROGRAM_AND_PROTECT = 3; // program the dongle and protect software + + // AddProtection API flags values + public const int FLAGS_OVERWRITE_OUTPUT = 1; // overwrite the output file if it already exists (default is to give an error) + + // SoftwareKey API flags + public const int FLAGS_OVERWRITE_SWKEY = 1; // overwrite an existing swkey with the new one + public const int FLAGS_EXPIRY_DONTCARE = 2; // create the Software Key even though the expiry date (or max days) is less than the expiry date of the key itself. + + // constants for dapf_format in ReadDAPFEx and WriteDAPFEx functions + public const int DAPF_FORMAT_BINARY = 1; + public const int DAPF_FORMAT_JSON = 2; + public const int DAPF_FORMAT_JSON_MIN = 3; // this value is only used with WriteDAPEx. ReadDAPFEx cannot return this value. + + // constants for values for model in the TEMP_SWKEY_INFO structure + public const int SWKEY_MODEL_PRO_LITE = 0; + public const int SWKEY_MODEL_PRO_PLUS = 1; + public const int SWKEY_MODEL_PRO_NET = 2; + public const int SWKEY_MODEL_FD_LITE = 3; + public const int SWKEY_MODEL_FD_PLUS = 4; + public const int SWKEY_MODEL_FD_NET = 5; + + // constants for models bitmap in the DEMO_SWKEY_INFO structure + public const int SWKEY_BITMAP_DEFAULT = 0; // use default value set in DINKEYINFO.SelectedModels + public const int SWKEY_BITMAP_PRO_LITE = 1; // BIT0 + public const int SWKEY_BITMAP_PRO_PLUS = 2; // BIT1 + public const int SWKEY_BITMAP_PRO_NET = 4; // BIT2 + public const int SWKEY_BITMAP_FD_LITE = 8; // BIT3 + public const int SWKEY_BITMAP_FD_PLUS = 16; // BIT4 + public const int SWKEY_BITMAP_FD_NET = 32; // BIT5 + + // private constants + private const int MAX_LICENCES = 255; // max number of licences in a DAPF file + private const int MAX_FILE_INFO = 1000; // theoretically unlimited but in practice it is easier if we limit it + private const int MAX_USER_ALGS = 20; // max number of user algs in DAPF file + private const int MAX_DATA_ENCS = 255; // max number of Shell data encryption files in DAPF file + + // **** main API + // We only want to load the correct DLL for the bit-ness of the computer. The other DLL may not exist. + // if the appropriate DLL does not exist in the same directory as this test program you will receive a DllNotFoundException + + public static IntPtr LoadDAPFFromFile(string dapf_file, out int err_code) + { + if (IntPtr.Size == 4) + return LoadDAPFFromFile32.LoadDAPFFromFile(dapf_file, out err_code); + return LoadDAPFFromFile64.LoadDAPFFromFile(dapf_file, out err_code); + } + + // we have to do some marshalling of arrays of bytes into arrays of structures + public static int ReadDAPFEx(string dapf_file, out DINKEYINFO DinkeyInfo, out LICENCEINFO[] LicenceInfo, out FILEINFO[] FileInfo, out ALGORITHM[] Algorithms, out DATAFILEENC[] DataFileEnc, out int dapf_version, out int dapf_format) + { + int ret_code, i; + byte[] licence_bytes = new byte[MAX_LICENCES * Marshal.SizeOf(typeof(LICENCEINFO))]; + byte[] licence_bytes_one_struct = new byte[Marshal.SizeOf(typeof(LICENCEINFO))]; + byte[] fileinfo_bytes = new byte[MAX_FILE_INFO * Marshal.SizeOf(typeof(FILEINFO))]; + byte[] fileinfo_bytes_one_struct = new byte[Marshal.SizeOf(typeof(FILEINFO))]; + byte[] alg_bytes = new byte[MAX_USER_ALGS * Marshal.SizeOf(typeof(ALGORITHM))]; + byte[] alg_bytes_one_struct = new byte[Marshal.SizeOf(typeof(ALGORITHM))]; + byte[] datafile_bytes = new byte[MAX_DATA_ENCS * Marshal.SizeOf(typeof(DATAFILEENC))]; + byte[] datafile_bytes_one_struct = new byte[Marshal.SizeOf(typeof(DATAFILEENC))]; + GCHandle MyGC; + DinkeyInfo = new DINKEYINFO(); + LicenceInfo = null; + FileInfo = null; + Algorithms = null; + DataFileEnc = null; + + if (IntPtr.Size == 4) + ret_code = ReadDAPFEx32.ReadDAPFEx(dapf_file, out DinkeyInfo, licence_bytes, fileinfo_bytes, alg_bytes, datafile_bytes, out dapf_version, out dapf_format); + else + ret_code = ReadDAPFEx64.ReadDAPFEx(dapf_file, out DinkeyInfo, licence_bytes, fileinfo_bytes, alg_bytes, datafile_bytes, out dapf_version, out dapf_format); + + if (ret_code != 0) + return ret_code; + + // convert byte array to an array of structs + LicenceInfo = new LICENCEINFO[DinkeyInfo.NumLicences]; + for (i=0; i + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/Samples/C#/DinkeyAdd/dapfTest.sln b/Dinkey Pro 7.6.1/Samples/C#/DinkeyAdd/dapfTest.sln new file mode 100644 index 0000000..12dca26 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/DinkeyAdd/dapfTest.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dapfTest", "dapfTest.csproj", "{6535AF22-2AF4-4401-BFE2-889CD40C8F2F}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {6535AF22-2AF4-4401-BFE2-889CD40C8F2F}.Debug.ActiveCfg = Debug|.NET + {6535AF22-2AF4-4401-BFE2-889CD40C8F2F}.Debug.Build.0 = Debug|.NET + {6535AF22-2AF4-4401-BFE2-889CD40C8F2F}.Release.ActiveCfg = Release|.NET + {6535AF22-2AF4-4401-BFE2-889CD40C8F2F}.Release.Build.0 = Release|.NET + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/Samples/C#/DinkeyChange/App.ico b/Dinkey Pro 7.6.1/Samples/C#/DinkeyChange/App.ico new file mode 100644 index 0000000..3a5525f Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C#/DinkeyChange/App.ico differ diff --git a/Dinkey Pro 7.6.1/Samples/C#/DinkeyChange/AssemblyInfo.cs b/Dinkey Pro 7.6.1/Samples/C#/DinkeyChange/AssemblyInfo.cs new file mode 100644 index 0000000..9f89a32 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/DinkeyChange/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/Dinkey Pro 7.6.1/Samples/C#/DinkeyChange/ChangeTest.csproj b/Dinkey Pro 7.6.1/Samples/C#/DinkeyChange/ChangeTest.csproj new file mode 100644 index 0000000..bc40a2e --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/DinkeyChange/ChangeTest.csproj @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/Samples/C#/DinkeyChange/ChangeTest.sln b/Dinkey Pro 7.6.1/Samples/C#/DinkeyChange/ChangeTest.sln new file mode 100644 index 0000000..c8c1896 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/DinkeyChange/ChangeTest.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChangeTest", "ChangeTest.csproj", "{1B4F9D4B-2045-4A7D-9007-1FBDB9E30F2C}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {1B4F9D4B-2045-4A7D-9007-1FBDB9E30F2C}.Debug.ActiveCfg = Debug|.NET + {1B4F9D4B-2045-4A7D-9007-1FBDB9E30F2C}.Debug.Build.0 = Debug|.NET + {1B4F9D4B-2045-4A7D-9007-1FBDB9E30F2C}.Release.ActiveCfg = Release|.NET + {1B4F9D4B-2045-4A7D-9007-1FBDB9E30F2C}.Release.Build.0 = Release|.NET + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/Samples/C#/DinkeyChange/DinkeyChange.cs b/Dinkey Pro 7.6.1/Samples/C#/DinkeyChange/DinkeyChange.cs new file mode 100644 index 0000000..bb9bfbd --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/DinkeyChange/DinkeyChange.cs @@ -0,0 +1,203 @@ +// !! this file should not be modified + +using System; +using System.Runtime.InteropServices; // so we can import DLL functions +using System.Text; // so we can extract prodcode from array + +// classes to load the correct 32-bit/64-bit DinkeyChange.dll functions - used by DinkeyChange class + +// loads DCGetInfo from the 32-bit DinkeyChange.dll +class DCGetInfo32 +{ + [DllImport("DinkeyChange.dll", CharSet = CharSet.Ansi)] + public static extern int DCGetInfo(int type_mask, int model_mask, string prodcode_mask, int array_length, out int num_found, int[] type, int[] model, byte[] prodcode, uint[] dongle_number, int[] update_number); +} + +// loads DCGetInfo from the 64-bit DinkeyChange64.dll +class DCGetInfo64 +{ + [DllImport("DinkeyChange64.dll", CharSet = CharSet.Ansi)] + public static extern int DCGetInfo(int type_mask, int model_mask, string prodcode_mask, int array_length, out int num_found, int[] type, int[] model, byte[] prodcode, uint[] dongle_number, int[] update_number); +} + +// loads DCGetDiagnosticInfo from the 32-bit DinkeyChange.dll +class DCGetDiagnosticInfo32 +{ + [DllImport("DinkeyChange.dll", CharSet = CharSet.Ansi)] + public static extern int DCGetDiagnosticInfo(string filename); +} + +// loads DCGetDiagnosticInfo from the 64-bit DinkeyChange64.dll +class DCGetDiagnosticInfo64 +{ + [DllImport("DinkeyChange64.dll", CharSet = CharSet.Ansi)] + public static extern int DCGetDiagnosticInfo(string filename); +} + +// loads DCDoUpdateCodeString from the 32-bit DinkeyChange.dll +class DCDoUpdateCodeString32 +{ + [DllImport("DinkeyChange.dll", CharSet = CharSet.Ansi)] + public static extern int DCDoUpdateCodeString(string update_code_string, out int confirmation_code, out int extended_error); +} + +// loads DCDoUpdateCodeString from the 64-bit DinkeyChange64.dll +class DCDoUpdateCodeString64 +{ + [DllImport("DinkeyChange64.dll", CharSet = CharSet.Ansi)] + public static extern int DCDoUpdateCodeString(string update_code_string, out int confirmation_code, out int extended_error); +} + +// loads DCDoUpdateCodeFromFile from the 32-bit DinkeyChange.dll +class DCDoUpdateCodeFromFile32 +{ + [DllImport("DinkeyChange.dll", CharSet = CharSet.Ansi)] + public static extern int DCDoUpdateCodeFromFile(string update_code_file, out int confirmation_code, out int extended_error); +} + +// loads DCDoUpdateCodeFromFile from the 64-bit DinkeyChange64.dll +class DCDoUpdateCodeFromFile64 +{ + [DllImport("DinkeyChange64.dll", CharSet = CharSet.Ansi)] + public static extern int DCDoUpdateCodeFromFile(string update_code_file, out int confirmation_code, out int extended_error); +} + +// loads DCRestoreDinkeyFDLite from the 32-bit DinkeyChange.dll +class DCRestoreDinkeyFDLite32 +{ + [DllImport("DinkeyChange.dll", CharSet = CharSet.Ansi)] + public static extern int DCRestoreDinkeyFDLite(); +} + +// loads DCRestoreDinkeyFDLite from the 64-bit DinkeyChange64.dll +class DCRestoreDinkeyFDLite64 +{ + [DllImport("DinkeyChange64.dll", CharSet = CharSet.Ansi)] + public static extern int DCRestoreDinkeyFDLite(); +} + +// loads DCGetMachineID from the 32-bit DinkeyChange.dll +class DCGetMachineID32 +{ + [DllImport("DinkeyChange.dll", CharSet = CharSet.Ansi)] + public static extern int DCGetMachineID(out uint machineID, out int extended_error); +} + +// loads DCGetMachineID from the 64-bit DinkeyChange64.dll +class DCGetMachineID64 +{ + [DllImport("DinkeyChange64.dll", CharSet = CharSet.Ansi)] + public static extern int DCGetMachineID(out uint machineID, out int extended_error); +} + +// loads DCDownloadTempSoftwareKey from the 32-bit DinkeyChange.dll +class DCDownloadTempSoftwareKey32 +{ + [DllImport("DinkeyChange.dll", CharSet = CharSet.Ansi)] + public static extern int DCDownloadTempSoftwareKey(uint machineID, out int extended_error); +} + +// loads DCDownloadTempSoftwareKey from the 64-bit DinkeyChange64.dll +class DCDownloadTempSoftwareKey64 +{ + [DllImport("DinkeyChange64.dll", CharSet = CharSet.Ansi)] + public static extern int DCDownloadTempSoftwareKey(uint machineID, out int extended_error); +} + +// loads DCDownloadDemoSoftwareKey from the 32-bit DinkeyChange.dll +class DCDownloadDemoSoftwareKey32 +{ + [DllImport("DinkeyChange.dll", CharSet = CharSet.Ansi)] + public static extern int DCDownloadDemoSoftwareKey(uint machineID, string prodcode, int model, out int extended_error); +} + +// loads DCDownloadDemoSoftwareKey from the 64-bit DinkeyChange64.dll +class DCDownloadDemoSoftwareKey64 +{ + [DllImport("DinkeyChange64.dll", CharSet = CharSet.Ansi)] + public static extern int DCDownloadDemoSoftwareKey(uint machineID, string prodcode, int model, out int extended_error); +} + +class DinkeyChange +{ + + // **** main API + // We only want to load the correct DLL for the bit-ness of the computer. The other DLL may not exist. + // if the appropriate DLL does not exist in the same directory as this test program you will receive a DllNotFoundException + + // detects whether running 32-bit code or 64-bit code and loads appropriate Dll. + public static int DCGetInfo(int type_mask, int model_mask, string prodcode_mask, int array_length, out int num_found, int[] type, int[] model, byte[] prodcode, uint[] dongle_number, int[] update_number) + { + if (IntPtr.Size == 4) + return DCGetInfo32.DCGetInfo(type_mask, model_mask, prodcode_mask, array_length, out num_found, type, model, prodcode, dongle_number, update_number); + return DCGetInfo64.DCGetInfo(type_mask, model_mask, prodcode_mask, array_length, out num_found, type, model, prodcode, dongle_number, update_number); + } + + public static int DCGetDiagnosticInfo(string filename) + { + if (IntPtr.Size == 4) + return DCGetDiagnosticInfo32.DCGetDiagnosticInfo(filename); + return DCGetDiagnosticInfo64.DCGetDiagnosticInfo(filename); + } + + public static int DCDoUpdateCodeString(string update_code_string, out int confirmation_code, out int extended_error) + { + if (IntPtr.Size == 4) + return DCDoUpdateCodeString32.DCDoUpdateCodeString(update_code_string, out confirmation_code, out extended_error); + return DCDoUpdateCodeString64.DCDoUpdateCodeString(update_code_string, out confirmation_code, out extended_error); + } + + public static int DCDoUpdateCodeFromFile(string update_code_string, out int confirmation_code, out int extended_error) + { + if (IntPtr.Size == 4) + return DCDoUpdateCodeFromFile32.DCDoUpdateCodeFromFile(update_code_string, out confirmation_code, out extended_error); + return DCDoUpdateCodeFromFile64.DCDoUpdateCodeFromFile(update_code_string, out confirmation_code, out extended_error); + } + + public static int DCRestoreDinkeyFDLite() + { + if (IntPtr.Size == 4) + return DCRestoreDinkeyFDLite32.DCRestoreDinkeyFDLite(); + return DCRestoreDinkeyFDLite64.DCRestoreDinkeyFDLite(); + } + + public static int DCGetMachineID(out uint machineID, out int extended_error) + { + if (IntPtr.Size == 4) + return DCGetMachineID32.DCGetMachineID(out machineID, out extended_error); + return DCGetMachineID64.DCGetMachineID(out machineID, out extended_error); + } + + public static int DCDownloadTempSoftwareKey(uint machineID, out int extended_error) + { + if (IntPtr.Size == 4) + return DCDownloadTempSoftwareKey32.DCDownloadTempSoftwareKey(machineID, out extended_error); + return DCDownloadTempSoftwareKey64.DCDownloadTempSoftwareKey(machineID, out extended_error); + } + + public static int DCDownloadDemoSoftwareKey(uint machineID, string prodcode, int model, out int extended_error) + { + if (IntPtr.Size == 4) + return DCDownloadDemoSoftwareKey32.DCDownloadDemoSoftwareKey(machineID, prodcode, model, out extended_error); + return DCDownloadDemoSoftwareKey64.DCDownloadDemoSoftwareKey(machineID, prodcode, model, out extended_error); + } + + // **** general purpose routines + + // routine to extract product code string from array of product codes + public static string GetProductCode(byte[] prodcode, int index) + { + int i; + StringBuilder sb = new StringBuilder(8); + + for (i=index*9; i<(index+1)*9; i++) + { + if (prodcode[i] == 0) + return sb.ToString(); + else + sb.Append((char)prodcode[i]); + } + return sb.ToString(); + } + +} diff --git a/Dinkey Pro 7.6.1/Samples/C#/DinkeyChange/Form1.cs b/Dinkey Pro 7.6.1/Samples/C#/DinkeyChange/Form1.cs new file mode 100644 index 0000000..4ff5c5c --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/DinkeyChange/Form1.cs @@ -0,0 +1,581 @@ +// !! We strongly recommend that you read the "readme.txt" file in the sample code folder. +// !! It contains important instructions on how to use the sample code + +using System; +using System.Drawing; +using System.Collections; +using System.ComponentModel; +using System.Windows.Forms; +using System.Data; + +namespace ChangeTest +{ + + /// + /// Summary description for Form1. + /// + public class Form1 : System.Windows.Forms.Form + { + private System.Windows.Forms.Button get_dongle_info; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox diag_filename; + private System.Windows.Forms.Button write_diag_file; + private System.Windows.Forms.Button do_update_code_string; + private System.Windows.Forms.TextBox update_code_string; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Button do_update_code_file; + private System.Windows.Forms.TextBox update_code_file; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Button restore_fd_lite; + private System.Windows.Forms.Button get_machine_id; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.TextBox swkey_prod_code; + private System.Windows.Forms.Button download_temp_swkey; + private System.Windows.Forms.Button download_demo_swkey; + private System.Windows.Forms.TextBox machine_id; + /// + /// Required designer variable. + /// + private System.ComponentModel.Container components = null; + + public Form1() + { + // + // Required for Windows Form Designer support + // + InitializeComponent(); + + // + // TODO: Add any constructor code after InitializeComponent call + // + } + + /// + /// Clean up any resources being used. + /// + protected override void Dispose( bool disposing ) + { + if( disposing ) + { + if (components != null) + { + components.Dispose(); + } + } + base.Dispose( disposing ); + } + + // maximum number of USB devices that can be attached to a machine at any time + public const int MAX_USB_DEVICES = 128; + public const int MAX_PRODCODE_LEN = 9; // including terminating null + + public string AppName = "ChangeTest"; + + // mask values + public const int TYPE_MASK_PRO = 1; + public const int TYPE_MASK_FD = 2; + public const int TYPE_MASK_ALL = (TYPE_MASK_PRO | TYPE_MASK_FD); + + public const int MODEL_MASK_LITE = 1; + public const int MODEL_MASK_PLUS = 2; + public const int MODEL_MASK_NET = 4; + public const int MODEL_MASK_ALL = (MODEL_MASK_LITE | MODEL_MASK_PLUS | MODEL_MASK_NET); + public const int MODEL_MASK_DEFAULT = (MODEL_MASK_PLUS | MODEL_MASK_NET); + + // type values for DCGetInfo (returned in the array) + public const int TYPE_PRO = 1; + public const int TYPE_FD = 2; + + // model values for DCGetInfo (returned in the array) + public const int MODEL_LITE = 1; + public const int MODEL_PLUS = 2; + public const int MODEL_NET5 = 4; + public const int MODEL_NETU = 7; + + // model values for DCDownloadDemoSoftwareKey + public const int SWKEY_MODEL_DEFAULT = -1; // NB this assumes that the Demo Software Key Template was created with only one valid dongle model + public const int SWKEY_MODEL_PRO_LITE = 0; + public const int SWKEY_MODEL_PRO_PLUS = 1; + public const int SWKEY_MODEL_PRO_NET = 2; + public const int SWKEY_MODEL_FD_LITE = 3; + public const int SWKEY_MODEL_FD_PLUS = 4; + public const int SWKEY_MODEL_FD_NET = 5; + + private void InitializeComponent() + { + this.get_dongle_info = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.diag_filename = new System.Windows.Forms.TextBox(); + this.write_diag_file = new System.Windows.Forms.Button(); + this.do_update_code_string = new System.Windows.Forms.Button(); + this.update_code_string = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.do_update_code_file = new System.Windows.Forms.Button(); + this.update_code_file = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.restore_fd_lite = new System.Windows.Forms.Button(); + this.get_machine_id = new System.Windows.Forms.Button(); + this.machine_id = new System.Windows.Forms.TextBox(); + this.download_temp_swkey = new System.Windows.Forms.Button(); + this.label4 = new System.Windows.Forms.Label(); + this.swkey_prod_code = new System.Windows.Forms.TextBox(); + this.download_demo_swkey = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // get_dongle_info + // + this.get_dongle_info.Location = new System.Drawing.Point(48, 24); + this.get_dongle_info.Name = "get_dongle_info"; + this.get_dongle_info.Size = new System.Drawing.Size(224, 24); + this.get_dongle_info.TabIndex = 0; + this.get_dongle_info.Text = "Get Dongle Information"; + this.get_dongle_info.Click += new System.EventHandler(this.get_dongle_info_Click); + // + // label1 + // + this.label1.Location = new System.Drawing.Point(16, 72); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(280, 16); + this.label1.TabIndex = 1; + this.label1.Text = "Enter diagnostic filename:"; + // + // diag_filename + // + this.diag_filename.Location = new System.Drawing.Point(16, 88); + this.diag_filename.Name = "diag_filename"; + this.diag_filename.Size = new System.Drawing.Size(288, 20); + this.diag_filename.TabIndex = 2; + this.diag_filename.Text = ""; + // + // write_diag_file + // + this.write_diag_file.Location = new System.Drawing.Point(48, 120); + this.write_diag_file.Name = "write_diag_file"; + this.write_diag_file.Size = new System.Drawing.Size(224, 24); + this.write_diag_file.TabIndex = 3; + this.write_diag_file.Text = "Write Diagnostics to File"; + this.write_diag_file.Click += new System.EventHandler(this.write_diag_file_Click); + // + // label2 + // + this.label2.Location = new System.Drawing.Point(16, 168); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(280, 16); + this.label2.TabIndex = 4; + this.label2.Text = "Enter short Update Code here:"; + // + // update_code_string + // + this.update_code_string.Location = new System.Drawing.Point(16, 184); + this.update_code_string.Name = "update_code_string"; + this.update_code_string.Size = new System.Drawing.Size(288, 20); + this.update_code_string.TabIndex = 5; + this.update_code_string.Text = ""; + // + // do_update_code_string + // + this.do_update_code_string.Location = new System.Drawing.Point(48, 216); + this.do_update_code_string.Name = "do_update_code_string"; + this.do_update_code_string.Size = new System.Drawing.Size(224, 24); + this.do_update_code_string.TabIndex = 6; + this.do_update_code_string.Text = "Make Changes"; + this.do_update_code_string.Click += new System.EventHandler(this.do_update_code_string_Click); + // + // do_update_code_file + // + this.do_update_code_file.Location = new System.Drawing.Point(48, 312); + this.do_update_code_file.Name = "do_update_code_file"; + this.do_update_code_file.Size = new System.Drawing.Size(224, 24); + this.do_update_code_file.TabIndex = 9; + this.do_update_code_file.Text = "Make Changes"; + this.do_update_code_file.Click += new System.EventHandler(this.do_update_code_file_Click); + // + // update_code_file + // + this.update_code_file.Location = new System.Drawing.Point(16, 280); + this.update_code_file.Name = "update_code_file"; + this.update_code_file.Size = new System.Drawing.Size(288, 20); + this.update_code_file.TabIndex = 8; + this.update_code_file.Text = ""; + // + // label3 + // + this.label3.Location = new System.Drawing.Point(16, 264); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(280, 16); + this.label3.TabIndex = 7; + this.label3.Text = "Enter path to Update Code file:"; + // + // restore_fd_lite + // + this.restore_fd_lite.Location = new System.Drawing.Point(48, 368); + this.restore_fd_lite.Name = "restore_fd_lite"; + this.restore_fd_lite.Size = new System.Drawing.Size(224, 24); + this.restore_fd_lite.TabIndex = 10; + this.restore_fd_lite.Text = "Restore Dinkey FD Lite"; + this.restore_fd_lite.Click += new System.EventHandler(this.restore_fd_lite_Click); + // + // get_machine_id + // + this.get_machine_id.Location = new System.Drawing.Point(16, 424); + this.get_machine_id.Name = "get_machine_id"; + this.get_machine_id.Size = new System.Drawing.Size(144, 24); + this.get_machine_id.TabIndex = 11; + this.get_machine_id.Text = "Get Machine ID"; + this.get_machine_id.Click += new System.EventHandler(this.get_machine_id_Click); + // + // machine_id + // + this.machine_id.Location = new System.Drawing.Point(168, 424); + this.machine_id.Name = "machine_id"; + this.machine_id.Size = new System.Drawing.Size(136, 20); + this.machine_id.TabIndex = 12; + this.machine_id.Text = ""; + // + // download_temp_swkey + // + this.download_temp_swkey.Location = new System.Drawing.Point(48, 480); + this.download_temp_swkey.Name = "download_temp_swkey"; + this.download_temp_swkey.Size = new System.Drawing.Size(224, 24); + this.download_temp_swkey.TabIndex = 13; + this.download_temp_swkey.Text = "Download Temporary Software Key"; + this.download_temp_swkey.Click += new System.EventHandler(this.download_temp_swkey_Click); + // + // label4 + // + this.label4.Location = new System.Drawing.Point(16, 528); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(280, 16); + this.label4.TabIndex = 14; + this.label4.Text = "Demo Software Key Product Code:"; + // + // swkey_prod_code + // + this.swkey_prod_code.Location = new System.Drawing.Point(16, 544); + this.swkey_prod_code.Name = "swkey_prod_code"; + this.swkey_prod_code.Size = new System.Drawing.Size(288, 20); + this.swkey_prod_code.TabIndex = 15; + this.swkey_prod_code.Text = ""; + // + // download_demo_swkey + // + this.download_demo_swkey.Location = new System.Drawing.Point(48, 576); + this.download_demo_swkey.Name = "download_demo_swkey"; + this.download_demo_swkey.Size = new System.Drawing.Size(224, 24); + this.download_demo_swkey.TabIndex = 16; + this.download_demo_swkey.Text = "Download Demo Software Key"; + this.download_demo_swkey.Click += new System.EventHandler(this.download_demo_swkey_Click); + // + // Form1 + // + this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); + this.ClientSize = new System.Drawing.Size(320, 624); + this.Controls.Add(this.download_demo_swkey); + this.Controls.Add(this.swkey_prod_code); + this.Controls.Add(this.label4); + this.Controls.Add(this.machine_id); + this.Controls.Add(this.download_temp_swkey); + this.Controls.Add(this.get_machine_id); + this.Controls.Add(this.restore_fd_lite); + this.Controls.Add(this.do_update_code_file); + this.Controls.Add(this.update_code_file); + this.Controls.Add(this.label3); + this.Controls.Add(this.do_update_code_string); + this.Controls.Add(this.update_code_string); + this.Controls.Add(this.label2); + this.Controls.Add(this.write_diag_file); + this.Controls.Add(this.diag_filename); + this.Controls.Add(this.label1); + this.Controls.Add(this.get_dongle_info); + this.Name = "Form1"; + this.Text = "ChangeTest"; + this.ResumeLayout(false); + + } + + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.Run(new Form1()); + } + + // routine to get & display information for all dongles attached + private void get_dongle_info_Click(object sender, System.EventArgs e) + { + int ret_code, i, num_found; + string DisplayString = null; + string Type, Model, ProdCodeString; + // return arrays of dongle details filedin by DCGetInfo + int[] type = new int[MAX_USB_DEVICES]; + int[] model = new int[MAX_USB_DEVICES]; + byte[] prodcode = new Byte[MAX_USB_DEVICES*MAX_PRODCODE_LEN]; + uint[] dongle_number = new uint[MAX_USB_DEVICES]; + int[] update_number = new int[MAX_USB_DEVICES]; + + // find dongle information for all dongle types, Plus & Net models, for all product codes + // NB In practice you will probably want to set the prodcode_mask to the value of your product code + ret_code = DinkeyChange.DCGetInfo(TYPE_MASK_ALL, MODEL_MASK_DEFAULT, null, MAX_USB_DEVICES, out num_found, type, model, prodcode, dongle_number, update_number); + + // check error code and display error if an error occurs + if (ret_code == 401) + { + MessageBox.Show("No dongles detected matching the search criteria specified", AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + else if (ret_code != 0) + { + DisplayString = "An error occurred getting dongle information. Error: " + String.Format("{0:D}", ret_code); + MessageBox.Show(DisplayString, AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + // display info for dongle(s) detected + for (i=0; i + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Form1 + + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/C#/DinkeyChange/README.txt b/Dinkey Pro 7.6.1/Samples/C#/DinkeyChange/README.txt new file mode 100644 index 0000000..df7e9b5 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/DinkeyChange/README.txt @@ -0,0 +1,64 @@ +ChangeTest - sample code to call DinkeyChange Module in C# +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 2003 but will work in more recent versions of +Visual Studio (they will upgrade the Project to the latest version. If prompted you +should also upgrade the .NET framework the project requires). + +For users of Visual Studio 2005 or higher, the default setting to projects is to compile +for the Target Platform "Any". This means that on 32-bit Windows, your code will run as +32-bit code (and needs to call DinkeyChange.dll) and under 64-bit Windows your code will +run as 64-bit code (and needs to call DinkeyChange64.dll). The sample code works this out +automatically. If you select the target platform as "x86" then it will always be 32-bit +and so you only need to use DinkeyChange.dll. If you select "x64" then your code will be +64-bit and you only need to use DinkeyChange64.dll. + +The main source files in the project are: + +DinkeyChange.cs - the source file contains declarations of our API. We automatically + work out whether your code is running in 32-bit or 64-bit and load the + appropriate DinkeyChange module. + +Form1.cs - this is the sample code giving an example on how you can call our API. + It contains 7 functions. Just use which ever functions are most appropriate + and customise in your own way. + +The best approach is to compile the sample code and see how it works and then to take the +appropriate code and apply it to your own project. You should include the DinkeyChange.cs +file in your project and use/modify which ever functions from Form1.cs you feel are +appropriate. The DinkeyChange.cs file should not be modified. + +The sample code is just a guide. As none of the parameters are security sensitive then +there is no need to implement strong security in calling DinkeyChange. + +Make sure you remember to do the following when creating your own project: + +1) Insert the DinkeyChange.cs file in your project. + +2) You need to put DinkeyChange.dll and/or DinkeyChange64.dll into the folder that +contains your EXE file. Otherwise the System.DllNotFoundException error will appear +when you run ChangeTest. + +You can rename DinkeyChange.dll (DinkeyChange64.dll) to a name of your choice. In this +case you will need to modify the dll names specified in the DinkeyChange.cs file. + +Notes on Debugging 64-bit Code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +When you use the 64-bit module (DinkeyChange64.dll) the anti-debug code is so strong that +if you are debugging your code, after calling our API then it will crash with an SEH +exception. If you want to be able to debug your code then you can setup your project so +that your code calls the debug module (DinkeyChange64Debug.dll) in your "debug" build and +the standard module (DinkeyChange64.dll) in your release build. In this case you will +need to modify the declarations of our API in DinkeyChange.cs. This is an example for +DCDoUpdateCodeFromFile64: + +class DCDoUpdateCodeFromFile64 +{ +#if DEBUG ' debug module + [DllImport("DinkeyChange64Debug.dll", CharSet = CharSet.Ansi)] + public static extern int DCDoUpdateCodeFromFile(string update_code_file, out int confirmation_code, out int extended_error); +#else ' standard module + [DllImport("DinkeyChange64.dll", CharSet = CharSet.Ansi)] + public static extern int DCDoUpdateCodeFromFile(string update_code_file, out int confirmation_code, out int extended_error); +#endif +} diff --git a/Dinkey Pro 7.6.1/Samples/C#/DinkeyRemote/App.ico b/Dinkey Pro 7.6.1/Samples/C#/DinkeyRemote/App.ico new file mode 100644 index 0000000..3a5525f Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C#/DinkeyRemote/App.ico differ diff --git a/Dinkey Pro 7.6.1/Samples/C#/DinkeyRemote/AssemblyInfo.cs b/Dinkey Pro 7.6.1/Samples/C#/DinkeyRemote/AssemblyInfo.cs new file mode 100644 index 0000000..9f89a32 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/DinkeyRemote/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/Dinkey Pro 7.6.1/Samples/C#/DinkeyRemote/Form1.cs b/Dinkey Pro 7.6.1/Samples/C#/DinkeyRemote/Form1.cs new file mode 100644 index 0000000..6da931c --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/DinkeyRemote/Form1.cs @@ -0,0 +1,214 @@ +// !! We strongly recommend that you read the "readme.txt" file in the sample code folder. +// !! It contains important instructions on how to use the sample code + +using System; +using System.Drawing; +using System.Collections; +using System.ComponentModel; +using System.Windows.Forms; +using System.Data; +using System.IO; // for file I/O +using System.Runtime.InteropServices; // so we can marshal our structures in drpf.cs + +namespace drpfTest +{ + /// + /// Summary description for Form1. + /// + public class Form1 : System.Windows.Forms.Form + { + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox drpfFile; + private System.Windows.Forms.Button updatecode; + private System.Windows.Forms.Button updatecodeMod; + /// + /// Required designer variable. + /// + private System.ComponentModel.Container components = null; + + public string AppName = "drpfTest"; + + public Form1() + { + // + // Required for Windows Form Designer support + // + InitializeComponent(); + + // + // TODO: Add any constructor code after InitializeComponent call + // + } + + /// + /// Clean up any resources being used. + /// + protected override void Dispose( bool disposing ) + { + if( disposing ) + { + if (components != null) + { + components.Dispose(); + } + } + base.Dispose( disposing ); + } + + #region Windows Form Designer generated code + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.drpfFile = new System.Windows.Forms.TextBox(); + this.updatecode = new System.Windows.Forms.Button(); + this.updatecodeMod = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.Location = new System.Drawing.Point(16, 24); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(440, 16); + this.label1.TabIndex = 0; + this.label1.Text = "Full path of drpf file:"; + // + // drpfFile + // + this.drpfFile.Location = new System.Drawing.Point(16, 40); + this.drpfFile.Name = "drpfFile"; + this.drpfFile.Size = new System.Drawing.Size(424, 20); + this.drpfFile.TabIndex = 1; + this.drpfFile.Text = ""; + // + // updatecode + // + this.updatecode.Location = new System.Drawing.Point(96, 88); + this.updatecode.Name = "updatecode"; + this.updatecode.Size = new System.Drawing.Size(264, 23); + this.updatecode.TabIndex = 2; + this.updatecode.Text = "Generate Update Code"; + this.updatecode.Click += new System.EventHandler(this.updatecode_Click); + // + // updatecodeMod + // + this.updatecodeMod.Location = new System.Drawing.Point(96, 128); + this.updatecodeMod.Name = "updatecodeMod"; + this.updatecodeMod.Size = new System.Drawing.Size(264, 23); + this.updatecodeMod.TabIndex = 3; + this.updatecodeMod.Text = "Generate Update Code with modifications "; + this.updatecodeMod.Click += new System.EventHandler(this.updatecodeMod_Click); + // + // Form1 + // + this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); + this.ClientSize = new System.Drawing.Size(456, 174); + this.Controls.Add(this.updatecodeMod); + this.Controls.Add(this.updatecode); + this.Controls.Add(this.drpfFile); + this.Controls.Add(this.label1); + this.Name = "Form1"; + this.Text = "Form1"; + this.ResumeLayout(false); + + } + #endregion + + /* The sample code contains 2 functions. Use which ever functions are most appropriate and customise + in your own way. The sample code is just a guide. + + There are two methods to loading a DRPF file. These are shown in the these two functions + updatecode_Click and updatecodeMod_Click: + + updatecode_Click: we load the DRPF file from disk and get a handle and use it "as is" using the API + call LoadDRPFFromFile. You can make some limited changes to overwrite the default + behaviour by using API flags. + + updatecodeMod_Click: we load the DRPF file from disk and load into structures. We can then modify the + DRPF settings by modifying this structure. This method uses the API calls + ReadDRPFEx and LoadDRPF. + + */ + + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.Run(new Form1()); + } + + private void updatecode_Click(object sender, System.EventArgs e) + { + IntPtr drpfHandle; + int err_code; + UPDATE_CODE_OUTPUTS Outputs = new UPDATE_CODE_OUTPUTS(); + + // load DRPF from File into memory + drpfHandle = DinkeyRemote.LoadDRPFFromFile(drpfFile.Text, out err_code); + if (drpfHandle == IntPtr.Zero) + { + MessageBox.Show(DinkeyRemote.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + // generate update code as specified by the DRPF file + err_code = DinkeyRemote.GenerateUpdateCode(drpfHandle, 0, 0, null, null, out Outputs); + + // Unload DRPF from memory + DinkeyRemote.UnloadDRPF(ref drpfHandle); + + // display message (error or success) + MessageBox.Show(DinkeyRemote.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Information); + + } + + private void updatecodeMod_Click(object sender, System.EventArgs e) + { + IntPtr drpfHandle; + int dummy1, dummy2, err_code; + REMOTEINFO RemoteInfo; + LICENCEINFO[] LicenceInfo; + ALGCHANGE[] AlgChanges; + DATACHANGE[] DataChanges; + UPDATE_CODE_OUTPUTS Outputs = new UPDATE_CODE_OUTPUTS(); + + // in this case we need to read the DRPF into our structures, so that the DRPF values can be modified + err_code = DinkeyRemote.ReadDRPFEx(drpfFile.Text, out RemoteInfo, out LicenceInfo, out AlgChanges, out DataChanges, out dummy1, out dummy2); + if (err_code != 0) + { + MessageBox.Show(DinkeyRemote.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + // patch new values in the RemoteInfo, LicenceInfo, AlgChanges, DataChanges structures + LicenceInfo[0].FeaturesFlag = 1; // so that the features value below will be recognised + LicenceInfo[0].Features = 12345; + LicenceInfo[0].AddSetExecs = 1; // so the executions will be added to existing + LicenceInfo[0].Execs = 100; + + // get DRPF handle + drpfHandle = DinkeyRemote.LoadDRPF(RemoteInfo, LicenceInfo, AlgChanges, DataChanges, out err_code); + if (drpfHandle == IntPtr.Zero) + { + MessageBox.Show(DinkeyRemote.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + // generate update code as specified by the modified DRPF file + err_code = DinkeyRemote.GenerateUpdateCode(drpfHandle, 0, 0, null, null, out Outputs); + + // Unload DRPF from memory + DinkeyRemote.UnloadDRPF(ref drpfHandle); + + // display message (error or success) + MessageBox.Show(DinkeyRemote.GetLastMessage(), AppName, MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + + } +} diff --git a/Dinkey Pro 7.6.1/Samples/C#/DinkeyRemote/Form1.resx b/Dinkey Pro 7.6.1/Samples/C#/DinkeyRemote/Form1.resx new file mode 100644 index 0000000..ec14cef --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/DinkeyRemote/Form1.resx @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + False + + + Private + + + Private + + + Private + + + False + + + Private + + + False + + + Private + + + Private + + + False + + + Private + + + Private + + + False + + + Form1 + + + (Default) + + + False + + + False + + + 8, 8 + + + True + + + 80 + + + True + + + Private + + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/C#/DinkeyRemote/README.txt b/Dinkey Pro 7.6.1/Samples/C#/DinkeyRemote/README.txt new file mode 100644 index 0000000..122c464 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/DinkeyRemote/README.txt @@ -0,0 +1,50 @@ +drpfTest - sample code to call DinkeyRemote Module in C# +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 2002 but will work in more recent +versions of Visual Studio (they will upgrade the Project to the latest version. +If prompted you should also upgrade the .NET framework the project requires). + +For users of Visual Studio 2005 or higher, the default setting to projects is to +compile for the Target Platform "Any". This means that on 32-bit Windows, your +code will run as 32-bit code (and needs to call DinkeyRemote32.dll) and under 64-bit +Windows your code will run as 64-bit code (and needs to call DinkeyRemote64.dll). +The sample code works this out automatically. If you select the target platform as "x86" +then it will always be 32-bit and so you only need to use DinkeyRemote32.dll. If you +select "x64" then your code will be 64-bit and you only need to use DinkeyRemote64.dll. + +The main source files in the project are: + +drpf.cs - the source file contains declarations of our API. We automatically + work out whether your code is running in 32-bit or 64-bit and load + the appropriate DinkeyRemote module. + +Form1.cs - this is the sample code giving an example on how you can call our API. + It contains 2 functions. Just use the function most appropriate for you + and customise in your own way. + +The best approach is to compile the sample code and see how it works and then to take +the appropriate code and apply it to your own project. You should include the drpf.cs +file in your project and use/modify which ever functions from Form1.cs you feel are +appropriate. The drpf.cs file should not be modified. + +The sample code is just a guide. As none of the parameters are security sensitive then +there is no need to implement strong security in calling DinkeyRemote. + +Make sure you remember to do the following when creating your own project: + +1) Insert the following namespaces in your code file: +using System.Runtime.InteropServices; + +2) Insert the drpf.cs file in your project. + +3) You need to put DinkeyRemote32.dll and/or DinkeyRemote64.dll into the folder that +contains drpfTest. Otherwise the System.DllNotFoundException error will appear +when you run drpfTest. + +Notes on Debugging 64-bit Code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +When you use the 64-bit module (DinkeyRemote64.dll) the anti-debug code is so strong +that if you are debugging your code, after calling our API then it will crash with +an SEH exception. There are no debug modules for DinkeyRemote so you will have to +find other ways of debugging your code (for example taking out the call altogether). diff --git a/Dinkey Pro 7.6.1/Samples/C#/DinkeyRemote/drpf.cs b/Dinkey Pro 7.6.1/Samples/C#/DinkeyRemote/drpf.cs new file mode 100644 index 0000000..b71c877 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/DinkeyRemote/drpf.cs @@ -0,0 +1,385 @@ +// !! this file should not be modified + +// DRPF file is in the following format: +// REMOTEINFO +// LICENCEINFO (however many are needed) +// ALGCHANGE (however many are needed) +// DATACHANGE (however many are needed) - may refer to external files. + +// Remember: you only need to specify a value if you want to change it. Otherwise you +// specify the default "no change" setting. For most entries this is indicated by 0. +// However, for MaxNetUsers and LicenceNetUsers it is "-2" because 0 is a valid value to change to. + +using System; +using System.Runtime.InteropServices; // so we can marshal the structures as a block of memory +using System.Text; // for StringBuilder class for GetLastMessage API + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct REMOTEINFO +{ + public byte Header1; // Should be set to "DRPF" = DinkeyRemote Parameter File + public byte Header2; + public byte Header3; + public byte Header4; + public int Version; // version of this structure - currently 2 + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=12)] + public string ProdCode; // Product Code + public uint DongleNumber; + public int UpdateNumber; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string Notes; // user-defined notes + public int NumLicences; + public int NumAlgs; // number of algs to set (incl r/w alg) + public int NumDataChanges; // number of data change blocks specified + public int DataAreaSize; // -1 = increase as necessary. specifies the new size of the data area + public int PerLicence; // 0 = no change, 1 = per licence net users, 2 = per product net users + public int MaxNetUsers; // product net users, unlimited = -1, no change = -2 + public int LastUsedDay; // Day = 0 (only) -> no change + public int LastUsedMonth; + public int LastUsedYear; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=12)] + public string DataEncKeyProdCode; + public int ChangeCodeType; // 0 = no change, bit0 = only accept secure codes, bit1 = accept secure & short codes + public int CodeType; // type of code to generate. 0 = secure code, 1 = short code + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string OutputFileName; // name of file to output code to. Null (default) -> UpdateCode.ducf + public int LockDongle; // 1 = lock dongle to user's computer + public int ResetDongleLock; // 1 = reset the dongle lock so that the dongle can be locked to a new machine +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct LICENCEINFO +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string LicenceName; // name of the licence + public int Action; // 0 = change, 1 = delete, 2 = add + public int AddSetExecs; // 0 = no change to execs, 1 = add, 2 = set + public int Execs; // -1 = no limit + public int ExecsWarn; // 0 = remove warning, -1 = no change + public int ExpiryDay; // -1 = no limit, 0 = no change + public int ExpiryMonth; + public int ExpiryYear; + public int AddSetMaxDays; // 0 = no change, 1 = add, 2 = set + public int MaxDays; // -1 = no limit + public int DaysWarn; // 0 = remove warning, -1 = no change + public int FeaturesFlag; // 0 = don't change features, 1 = change features + public uint Features; // all values OK + public int LicenceNetUsers; // unlimited = -1, no change = -2 +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct ALGCHANGE +{ + public int alg_number; // number of algorithm to set (0 = r/w algorithm) + [MarshalAs(UnmanagedType.ByValArray, SizeConst=12)] + public byte[] alg; // algorithm +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct DATACHANGE +{ + public int type; // 1 = file, 2 = hex data, 3 = ascii, 4 = ascii null-term string + public int offset; // offset in dongle data memory to write data + public int length; // length of data to change + [MarshalAs(UnmanagedType.ByValArray, SizeConst=256)] + public byte[] data; // data to write OR name of data file depending on which method set +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct UPDATE_CODE_OUTPUTS +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128*3)] + public string ShortCode; // the update code (for short update codes only) + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string UpdateCodeFile; // the output ducf that contains the update code + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=8)] + public string ConfirmationCode; // the confirmation code +} + + + +// ********************** API functions ************************ +// we declare classes for all the API functions for each bitness + +// Loads DRPF from disk and returns handle +class LoadDRPFFromFile32 +{ + [DllImport("DinkeyRemote32.dll", CharSet = CharSet.Ansi)] + public static extern IntPtr LoadDRPFFromFile(string drpf_file, out int err_code); +} + +class LoadDRPFFromFile64 +{ + [DllImport("DinkeyRemote64.dll", CharSet = CharSet.Ansi)] + public static extern IntPtr LoadDRPFFromFile(string drpf_file, out int err_code); +} + +// Loads DRPF from disk into structures supplied (so we can modify DRPF in memory) +class ReadDRPFEx32 +{ + [DllImport("DinkeyRemote32.dll", CharSet = CharSet.Ansi)] + public static extern int ReadDRPFEx(string drpf_file, out REMOTEINFO RemoteInfo, byte[] licence_bytes, byte[] algchange_bytes, byte[] datachange_bytes, out int drpf_version, out int drpf_format); +} + +class ReadDRPFEx64 +{ + [DllImport("DinkeyRemote64.dll", CharSet = CharSet.Ansi)] + public static extern int ReadDRPFEx(string drpf_file, out REMOTEINFO RemoteInfo, byte[] licence_bytes, byte[] algchange_bytes, byte[] datachange_bytes, out int drpf_version, out int drpf_format); +} + +// Loads DRPF from structures and returns a handle +class LoadDRPF32 +{ + [DllImport("DinkeyRemote32.dll", CharSet = CharSet.Ansi)] + public static extern IntPtr LoadDRPF(ref REMOTEINFO RemoteInfo, byte[] licence_bytes, byte[] algchange_bytes, byte[] datachange_bytes, out int ret_code); +} + +class LoadDRPF64 +{ + [DllImport("DinkeyRemote64.dll", CharSet = CharSet.Ansi)] + public static extern IntPtr LoadDRPF(ref REMOTEINFO RemoteInfo, byte[] licence_bytes, byte[] algchange_bytes, byte[] datachange_bytes, out int ret_code); +} + +// saves the DRPF file to disk +class WriteDRPFEx32 +{ + [DllImport("DinkeyRemote32.dll", CharSet = CharSet.Ansi)] + public static extern int WriteDRPFEx(IntPtr drpf_handle, string drpf_file, int drpf_format, int drpf_version, int flags); +} + +class WriteDRPFEx64 +{ + [DllImport("DinkeyRemote64.dll", CharSet = CharSet.Ansi)] + public static extern int WriteDRPFEx(IntPtr drpf_handle, string drpf_file, int drpf_format, int drpf_version, int flags); +} + +// unloads the DRPF file +class UnloadDRPF32 +{ + [DllImport("DinkeyRemote32.dll", CharSet = CharSet.Ansi)] + public static extern void UnloadDRPF(ref IntPtr drpf_handle); +} + +class UnloadDRPF64 +{ + [DllImport("DinkeyRemote64.dll", CharSet = CharSet.Ansi)] + public static extern void UnloadDRPF(ref IntPtr drpf_handle); +} + +class GenerateUpdateCode32 +{ + [DllImport("DinkeyRemote32.dll", CharSet = CharSet.Ansi)] + public static extern int GenerateUpdateCode(IntPtr drpf_handle, uint dongle_number, int update_number, string ducf_file, string logfile, out UPDATE_CODE_OUTPUTS Outputs); +} + +class GenerateUpdateCode64 +{ + [DllImport("DinkeyRemote64.dll", CharSet = CharSet.Ansi)] + public static extern int GenerateUpdateCode(IntPtr drpf_handle, uint dongle_number, int update_number, string ducf_file, string logfile, out UPDATE_CODE_OUTPUTS Outputs); +} + +class GetLastMessage32 +{ + [DllImport("DinkeyRemote32.dll", CharSet = CharSet.Ansi)] + public static extern void GetLastMessage(StringBuilder message, int buffer_size, out int message_length); +} + +class GetLastMessage64 +{ + [DllImport("DinkeyRemote64.dll", CharSet = CharSet.Ansi)] + public static extern void GetLastMessage(StringBuilder message, int buffer_size, out int message_length); +} + +class GetLastExtendedError32 +{ + [DllImport("DinkeyRemote32.dll", CharSet = CharSet.Ansi)] + public static extern int GetLastExtendedError(); +} + +class GetLastExtendedError64 +{ + [DllImport("DinkeyRemote64.dll", CharSet = CharSet.Ansi)] + public static extern int GetLastExtendedError(); +} + +// ********************* DinkeyRemote class ********************** +class DinkeyRemote +{ + // constants + public const int DRPF_VERSION = 2; // current DRPF version + + // WriteDRPFEx API flags + public const int FLAGS_LOSE_FEATURES = 1; // means that you can save the DRPF file to an earlier version even if it means losing some new features that have been currently set + + // constants for drpf_format in ReadDRPFEx and WriteDRPFEx functions + public const int DRPF_FORMAT_BINARY = 1; + public const int DRPF_FORMAT_JSON = 2; + public const int DRPF_FORMAT_JSON_MIN = 3; // this value is only used with WriteDRPFEx. ReadDRPFEx cannot return this value. + + // private constants + private const int MAX_LICENCES = 255; // max number of licence changes in a DRPF file (theoretically unlimited but easier if we limit it) + private const int MAX_ALG_CHANGES = 21; // max number of alg changes in DRPF file + private const int MAX_DATA_CHANGES = 127; // max number of data area changes in DRPF file + + // **** main API + // We only want to load the correct DLL for the bit-ness of the computer. The other DLL may not exist. + // if the appropriate DLL does not exist in the same directory as this test program you will receive a DllNotFoundException + + public static IntPtr LoadDRPFFromFile(string drpf_file, out int err_code) + { + if (IntPtr.Size == 4) + return LoadDRPFFromFile32.LoadDRPFFromFile(drpf_file, out err_code); + return LoadDRPFFromFile64.LoadDRPFFromFile(drpf_file, out err_code); + } + + // we have to do some marshalling of arrays of bytes into arrays of structures + public static int ReadDRPFEx(string drpf_file, out REMOTEINFO RemoteInfo, out LICENCEINFO[] LicenceInfo, out ALGCHANGE[] AlgChanges, out DATACHANGE[] DataChanges, out int drpf_version, out int drpf_format) + { + int ret_code, i; + byte[] licence_bytes = new byte[MAX_LICENCES * Marshal.SizeOf(typeof(LICENCEINFO))]; + byte[] licence_bytes_one_struct = new byte[Marshal.SizeOf(typeof(LICENCEINFO))]; + byte[] algchange_bytes = new byte[MAX_ALG_CHANGES * Marshal.SizeOf(typeof(ALGCHANGE))]; + byte[] algchange_bytes_one_struct = new byte[Marshal.SizeOf(typeof(ALGCHANGE))]; + byte[] datachange_bytes = new byte[MAX_DATA_CHANGES * Marshal.SizeOf(typeof(DATACHANGE))]; + byte[] datachange_bytes_one_struct = new byte[Marshal.SizeOf(typeof(DATACHANGE))]; + GCHandle MyGC; + RemoteInfo = new REMOTEINFO(); + LicenceInfo = null; + AlgChanges = null; + DataChanges = null; + + if (IntPtr.Size == 4) + ret_code = ReadDRPFEx32.ReadDRPFEx(drpf_file, out RemoteInfo, licence_bytes, algchange_bytes, datachange_bytes, out drpf_version, out drpf_format); + else + ret_code = ReadDRPFEx64.ReadDRPFEx(drpf_file, out RemoteInfo, licence_bytes, algchange_bytes, datachange_bytes, out drpf_version, out drpf_format); + + if (ret_code != 0) + return ret_code; + + // convert byte array to an array of structs + LicenceInfo = new LICENCEINFO[RemoteInfo.NumLicences]; + for (i=0; i + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/Samples/C#/DinkeyRemote/drpfTest.sln b/Dinkey Pro 7.6.1/Samples/C#/DinkeyRemote/drpfTest.sln new file mode 100644 index 0000000..3d22dc3 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/DinkeyRemote/drpfTest.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "drpfTest", "drpfTest.csproj", "{7C474B2E-28FA-4821-8FF0-FD2181A0B242}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {7C474B2E-28FA-4821-8FF0-FD2181A0B242}.Debug.ActiveCfg = Debug|.NET + {7C474B2E-28FA-4821-8FF0-FD2181A0B242}.Debug.Build.0 = Debug|.NET + {7C474B2E-28FA-4821-8FF0-FD2181A0B242}.Release.ActiveCfg = Release|.NET + {7C474B2E-28FA-4821-8FF0-FD2181A0B242}.Release.Build.0 = Release|.NET + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2002/App.ico b/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2002/App.ico new file mode 100644 index 0000000..3a5525f Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2002/App.ico differ diff --git a/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2002/AssemblyInfo.cs b/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2002/AssemblyInfo.cs new file mode 100644 index 0000000..9f89a32 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2002/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2002/DllTest.csproj b/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2002/DllTest.csproj new file mode 100644 index 0000000..16051cf --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2002/DllTest.csproj @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2002/DllTest.sln b/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2002/DllTest.sln new file mode 100644 index 0000000..5e14c3b --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2002/DllTest.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DllTest", "DllTest.csproj", "{8199C796-57A5-4EA6-B0E0-41022918FCC2}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {8199C796-57A5-4EA6-B0E0-41022918FCC2}.Debug.ActiveCfg = Debug|.NET + {8199C796-57A5-4EA6-B0E0-41022918FCC2}.Debug.Build.0 = Debug|.NET + {8199C796-57A5-4EA6-B0E0-41022918FCC2}.Release.ActiveCfg = Release|.NET + {8199C796-57A5-4EA6-B0E0-41022918FCC2}.Release.Build.0 = Release|.NET + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2002/Form1.cs b/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2002/Form1.cs new file mode 100644 index 0000000..19e659d --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2002/Form1.cs @@ -0,0 +1,874 @@ +// !! We strongly recommend that you read the "readme.txt" file in the sample code folder. +// !! It contains important instructions on how to use the sample code + +using System; +using System.Drawing; +using System.Collections; +using System.ComponentModel; +using System.Windows.Forms; +using System.Data; +using System.Runtime.InteropServices; + +namespace DllTest +{ + /// + /// Summary description for Form1. + /// + public class Form1 : System.Windows.Forms.Form + { + private System.Windows.Forms.Label label1; + /// + /// Required designer variable. + /// + private System.ComponentModel.Container components = null; + + public Form1() + { + // + // Required for Windows Form Designer support + // + InitializeComponent(); + + // + // TODO: Add any constructor code after InitializeComponent call + // + } + + /// + /// Clean up any resources being used. + /// + protected override void Dispose( bool disposing ) + { + if( disposing ) + { + if (components != null) + { + components.Dispose(); + } + } + base.Dispose( disposing ); + } + + #region Windows Form Designer generated code + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // label1 + // + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 21.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0))); + this.label1.Location = new System.Drawing.Point(72, 72); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(160, 40); + this.label1.TabIndex = 0; + this.label1.Text = "It Worked!"; + // + // Form1 + // + this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); + this.ClientSize = new System.Drawing.Size(296, 205); + this.Controls.AddRange(new System.Windows.Forms.Control[] { + this.label1}); + this.Name = "Form1"; + this.Text = "Form1"; + this.ResumeLayout(false); + + } + #endregion + + public const int MY_SDSN = 10101; // !!!! change this value to be the value of your SDSN (demo = 10101) + public const string MY_PRODCODE = "DEMO"; // !!!! change this value to match the Product Code in the dongle + + /// + /// The main entry point for the application. + /// + /* The sample code contains 11 functions. You will not need to use all these + functions in your code. Just use which ever functions are most appropriate + and customise in your own way. The sample code is just a guide. You should + implement the protection in a stronger way using the techniques described in + the "Increasing your Protection" chapter of the manual. + + ProtCheck // a standard protection check + ProtCheckWithAlg // a protection check & executing an Algorithm + WriteBytes // a protection check & write data to the dongle + ReadBytes // a protection check & read data from the dongle + EncryptUserData // a protection check & encrypting data and then decrypting the data + // these functions are the same as the functions listed above but encrypting all parameters passed to our API + ProtCheckEnc // a standard protection check + ProtCheckWithAlgEnc // a protection check & executing an Algorithm + WriteBytesEnc // a protection check & write data to the dongle + ReadBytesEnc // a protection check & read data from the dongle + EncryptUserDataEnc // a protection check & encrypting data and then decrypting the data + // this function displays the current network users + DisplayNetUsers + + If you are using Dinkey Lite then you can only use 4 functions: + ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + */ + + [STAThread] + static void Main() + { + // call the function(s) of your choice here + // in this example I have chosen a standard protection check + if (ProtCheck() != 0) + return; // check fails - exit program + Application.Run(new Form1()); + } + + // ************************* our 10 functions follow ************************* + + // **************************** ProtCheck ********************************* + // standard protection check + public static int ProtCheck() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.PROTECTION_CHECK; // standard protection check + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + ret_code = DinkeyPro.DDProtCheck(dris, null); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + if (dris.prodcode != MY_PRODCODE) + { + MessageBox.Show("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // if you are using a network dongle and you want to list the network users then use this function: + // DisplayNetUsers(dris); + + return 0; + } + + // **************************** ProtCheckWithAlg **************************** + + // !!!! You should replace this function with the one generated by the + // "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) + // or from DinkeyLook if you are using a Dinkey Lite dongle. + private static int MyAlgorithm(int a, int b, int c, int d, int e, int f, int g, int h) + { + return a + b + c + d + e + f + g + h; + } + + // NB for this to work you must program at least "user algorithm" into the dongle + // NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + // sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite copy the sample code from DinkeyLook + public static int ProtCheckWithAlg() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.EXECUTE_ALGORITHM; // standard protection check & execute algorithm + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number = 1; // execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + // you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.var_a = 1; // sample values + dris.var_b = 2; + dris.var_c = 3; + dris.var_d = 4; + dris.var_e = 5; + dris.var_f = 6; + dris.var_g = 7; + dris.var_h = 8; + + ret_code = DinkeyPro.DDProtCheck(dris, null); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + // !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) != dris.alg_answer) + { + MessageBox.Show("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + return 0; + } + + // ************************** WriteBytes ****************************** + // This writes the Data 0,1,2,3,4,5,6,7,8,9 to the dongle data area at offset 7 + // In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + // if you want to write a string then you need to convert it to a byte array first: + // encoding.GetBytes(your_string, 0, your_string.Length, data, 0) where encoding is of ASCIIEncoding type. + public static int WriteBytes() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + byte[] DataToWrite = {0,1,2,3,4,5,6,7,8,9}; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.WRITE_DATA_AREA; // standard protection check & write data to dongle + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris.rw_offset = 7; + dris.rw_length = DataToWrite.GetLength(0); + + ret_code = DinkeyPro.DDProtCheck(dris, DataToWrite); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + return 0; + } + + // ************************ ReadBytes ************************************ + // This reads 10 bytes of data from offset 7 in the dongle data area + // In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + // if you want to read a string then you need to convert it from a byte array (via an array of char) + // CharArray = encoding.GetChars(data); where CharArray is of type char[] and encoding is of type ASCIIEncoding + // your_string = new String(CharArray, 0, your_string_length); + public static int ReadBytes() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + byte[] DataToRead = new byte[10]; + string DisplayString; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.READ_DATA_AREA; // standard protection check & read data + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris.rw_offset = 7; + dris.rw_length = DataToRead.GetLength(0); + + ret_code = DinkeyPro.DDProtCheck(dris, DataToRead); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + DisplayString = "Dinkey Dongle data area, offset 7: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}", + DataToRead[0], DataToRead[1], DataToRead[2], DataToRead[3], DataToRead[4], DataToRead[5], DataToRead[6], DataToRead[7], DataToRead[8], DataToRead[9]); + MessageBox.Show(DisplayString, "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return 0; + } + + // ************************** EncryptUserData ************************************ + // This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 + // It will then do another protection check & decrypt the data + // if you want to encrypt of decrypt string then see comment for WriteBytes and ReadBytes + public static int EncryptUserData() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + byte[] Data = {0,1,2,3,4,5,6,7,8,9}; + string DisplayString; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.ENCRYPT_USER_DATA; // standard protection check & encrypt data + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; + dris.rw_length = Data.GetLength(0); + dris.data_crypt_key_num = 1; + + ret_code = DinkeyPro.DDProtCheck(dris, Data); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + // Now decrypt the same data to get the original values + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.DECRYPT_USER_DATA; // standard protection check & read data + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris.rw_length = Data.GetLength(0); + dris.data_crypt_key_num = 1; + + ret_code = DinkeyPro.DDProtCheck(dris, Data); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + DisplayString = "decrypted data is: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}", + Data[0], Data[1], Data[2], Data[3], Data[4], Data[5], Data[6], Data[7], Data[8], Data[9]); + MessageBox.Show(DisplayString, "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return 0; + } + + // !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! + // In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" + // in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm + // but the code can be modified easily to use the 3 encryption parameters. + + // !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm + private static int MyRWAlgorithm(int a, int b, int c, int d, int e, int f, int g, int h) + { + return a ^ b ^ c ^ d ^ e ^ f; + } + + + // !!!! please overwrite this function with the one generated by DinkeyAdd + private static void CryptDRIS(DRIS dris) + { + int i, j, k; + byte[] bigseed = new byte[256]; + byte[] S = new byte[256]; + byte temp, t; + byte[] dris_bytes = new byte[Marshal.SizeOf(dris)]; + + dris.DrisToByteArray(dris, dris_bytes); // convert DRIS to byte array so we can encrypt it + + for (i=0; i<256; i+=8) + { + dris.Set4Bytes(bigseed, i, dris.seed1); + dris.Set4Bytes(bigseed, i+4, dris.seed2); + } + for (i=0; i<256; i++) + S[i] = (byte)i; + for (i=0, j=0; i<256; i++) + { + j = (j + S[i] + bigseed[i] + 123) % 256; + temp = S[i]; + S[i] = S[j]; + S[j] = temp; + } + for (i=0, j=0, k=16; k> 8) & 0xff)) % 256; + temp = S[i]; + S[i] = S[j]; + S[j] = temp; + t = (byte)(S[i] + S[j] + ((alg_answer >> 16) & 0xff)); + data[k] ^= S[t]; + } + return; + } + + // **************************** ProtCheckEnc ****************************** + // We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. + public static int ProtCheckEnc() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.PROTECTION_CHECK; // standard protection check + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris, null); + + CryptDRIS(dris); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + if (dris.prodcode != MY_PRODCODE) + { + MessageBox.Show("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + return 0; + } + + // **************************** ProtCheckWithAlgEnc ************************* + // NB for this to work you must program at least "user algorithm" into the dongle + // NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + // sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite copy source from DinkeyLook. + // We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. + public static int ProtCheckWithAlgEnc() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.EXECUTE_ALGORITHM; // standard protection check & execute algorithm + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number = 1; // execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + // you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.var_a = 1; // sample values + dris.var_b = 2; + dris.var_c = 3; + dris.var_d = 4; + dris.var_e = 5; + dris.var_f = 6; + dris.var_g = 7; + dris.var_h = 8; + + CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris, null); + + CryptDRIS(dris); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + // !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) != dris.alg_answer) + { + MessageBox.Show("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + return 0; + } + + // ************************** WriteBytesEnc *************************** + // This writes the Data 0,1,2,3,4,5,6,7,8,9 to the dongle data area at offset 7 + // In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + // We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + // if you want to write strings then see comment for WriteBytes + public static int WriteBytesEnc() + { + int ret_code, alg_ans; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + byte[] DataToWrite = {0,1,2,3,4,5,6,7,8,9}; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.WRITE_DATA_AREA; // standard protection check & write data to dongle + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris.rw_offset = 7; + dris.rw_length = DataToWrite.GetLength(0); + + // calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + // encrypt data we want to write. + CryptApiData(dris, DataToWrite, DataToWrite.GetLength(0), alg_ans); + + CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris, DataToWrite); + + CryptDRIS(dris); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + return 0; + } + + // ************************ ReadBytesEnc ********************************* + // This reads 10 bytes of data from offset 7 in the dongle data area + // In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + // We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + // if you want to read strings then see comment for ReadBytes + public static int ReadBytesEnc() + { + int ret_code, alg_ans; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + byte[] DataRead = new byte[10]; + string DisplayString; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.READ_DATA_AREA; // standard protection check & read data + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris.rw_offset = 7; + dris.rw_length = DataRead.GetLength(0); + + // calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris, DataRead); + + CryptDRIS(dris); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // decrypt data that was read. + CryptApiData(dris, DataRead, DataRead.GetLength(0), alg_ans); + + DisplayString = "Dinkey Dongle data area, offset 7: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}", + DataRead[0], DataRead[1], DataRead[2], DataRead[3], DataRead[4], DataRead[5], DataRead[6], DataRead[7], DataRead[8], DataRead[9]); + MessageBox.Show(DisplayString, "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return 0; + } + + // ************************** EncryptUserDataEnc ********************************* + // This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 + // It will then do another protection & decrypt the data + // We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + // if you want to encrypt of decrypt strings then see comment for WriteBytes and ReadBytes + public static int EncryptUserDataEnc() + { + int ret_code, alg_ans; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + DRIS dris2 = new DRIS(); // initialise the DRIS with random values & set the header + byte[] Data = {0,1,2,3,4,5,6,7,8,9}; + string DisplayString; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.ENCRYPT_USER_DATA; // standard protection check & encrypt data + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; + dris.rw_length = Data.GetLength(0); + dris.data_crypt_key_num = 1; + + // calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + // encrypt data we pass to our API. + CryptApiData(dris, Data, Data.GetLength(0), alg_ans); + + CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris, Data); + + CryptDRIS(dris); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + // NB use another dris so that we can ensure elements are initialised to different random numbers + dris2.size = Marshal.SizeOf(dris2); + dris2.function = DRIS.DECRYPT_USER_DATA; // standard protection check & read data + dris2.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris2.rw_length = Data.GetLength(0); + dris2.data_crypt_key_num = 1; + + CryptDRIS(dris2); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris2, Data); + + CryptDRIS(dris2); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris2.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris2.sdsn != MY_SDSN) + { + MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + // later on in your program you can check the return code again + if (dris2.ret_code != 0) + { + MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + alg_ans = MyRWAlgorithm(dris2.var_a, dris2.var_b, dris2.var_c, dris2.var_d, dris2.var_e, dris2.var_f, dris2.var_g, dris2.var_h); + // decrypt data that was passed to us by the API. + CryptApiData(dris2, Data, Data.GetLength(0), alg_ans); + + DisplayString = "decrypted data is: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}", + Data[0], Data[1], Data[2], Data[3], Data[4], Data[5], Data[6], Data[7], Data[8], Data[9]); + MessageBox.Show(DisplayString, "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return 0; + } + + // *********************** DisplayNetUsers ******************************* + // This function displays the current network users (for DinkeyNet only). + // The DDProtCheck function must be called before this function is called. + // (Normally you would use DinkeyServer to view the network users but this enables you to do it from the client if you want) + public static int DisplayNetUsers(DRIS dris) + { + string DisplayString; + int num_net_users, extended_error, ret_code, i, max_net_users; + NU_INFO[] nu_info; + + if (dris.net_users == -1) + max_net_users = 100; // if unlimited network users are allowed then display up to 100 users (for example) + else + max_net_users = dris.net_users; + + if (max_net_users == 0) // no network users are allowed, so nothing to do! + return 0; + + if (dris.model < 3) { + MessageBox.Show("A network dongle has not been detected. Therefore you cannot display the network users.", "Net Users", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return -1; + } + + ret_code = DinkeyPro.DDGetNetUserList(null, out num_net_users, out nu_info, max_net_users, out extended_error); + + if (ret_code != 0) + { + MessageBox.Show(String.Format("Error {0}/{1} finding network user information.", ret_code, extended_error), "Net Users", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + else + { + DisplayString = String.Format("number of net users: {0}", num_net_users) + Environment.NewLine; + for (i=0; i + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Form1 + + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2002/dris.cs b/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2002/dris.cs new file mode 100644 index 0000000..51e14b2 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2002/dris.cs @@ -0,0 +1,287 @@ +// !! this file should not be modified + +using System; +using System.Runtime.InteropServices; // so we can marshal the DRIS as a block of memory +using System.Text; // so we can extract / set strings in the DRIS +using System.Windows.Forms; // for MessageBox + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public class DRIS +{ + // the first 4 fields are never encrypted + public byte header1; // should be set to "DRIS" + public byte header2; + public byte header3; + public byte header4; + // inputs + public int size; // size of this structure + public int seed1; // seed for data/dris encryption + public int seed2; // as above + // (maybe encrypted from now on) + public int function; // specify only one function + public int flags; // options for the function selected. To use more than one OR them together: OPTION1 | OPTION2... + public uint execs_decrement; // amount by which to dec execs if we use flag: DEC_MANY_EXECS + public int data_crypt_key_num; // number of the key (1-3) that the dongle uses to encrypt or decrypt user data + public int rw_offset; // offset in the dongle data area to read or write data + public int rw_length; // length of data are to read/write/encrypt/decrypt + public IntPtr DoNotUse; // do not use the rw_data_ptr element use the "Data" argument of the DDProtCheck function + [MarshalAs(UnmanagedType.ByValArray, SizeConst=256)] // NB access this field by using alg_licence_name (see below) + private byte[] _alt_licence_name = null; // protection check for different licence instead of this one + public int var_a; // variable values for user algorithm + public int var_b; + public int var_c; + public int var_d; + public int var_e; + public int var_f; + public int var_g; + public int var_h; + public int alg_number; // the number of the user algorithm that you want to execute + + // outputs + public int ret_code; // return code from the protection check + public int ext_err; // extended error + public int type; // type of dongle detected. 1 = Pro, 2 = FD + public int model; // model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + public int sdsn; // Software Developer's Serial Number + [MarshalAs(UnmanagedType.ByValArray, SizeConst=12)] // NB access this field by using prodcode (see below) + private byte[] _prodcode = null; // product code (null-terminated) + public uint dongle_number; + public int update_number; + public uint data_area_size; // size of the data area in the dongle detected + public int max_alg_num; // number of algorithms in the dongle detected + public int execs; // executions left: -1 indicates 'no limit' + public int exp_day; // expiry day: -1 indicates 'no limit' + public int exp_month; // expiry month: -1 indicates 'no limit' + public int exp_year; // expiry year: -1 indicates 'no limit' + public uint features; // features value + public int net_users; // maximum number of network users for the dongle detected: -1 indicates 'mo limit' + public int alg_answer; // answer to the user algorithm executed with the given variable values + public uint fd_capacity; // capacity of the data area in FD dongle. Currently fixed at ~10MB but may change in the future. + [MarshalAs(UnmanagedType.ByValArray, SizeConst=128)] // NB access this field by using fd_drive (see below) + private byte[] _fd_drive = null; // fd drive letter (null-terminated) + public int swkey_type; // 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + public int swkey_exp_day; // software key expiry date (if software key detected) + public int swkey_exp_month; + public int swkey_exp_year; + + // NB we have to do it this way because we cannot encrypt strings correctly unless they are byte arrays + public string prodcode + { + get + { + StringBuilder sb = new StringBuilder(12); + foreach (byte b in _prodcode) + { + if (b == 0) + return sb.ToString(); + else + sb.Append((char)b); + } + return sb.ToString(); + } + } + + public string fd_drive + { + get + { + StringBuilder sb = new StringBuilder(128); + foreach (byte b in _fd_drive) + { + if (b == 0) + return sb.ToString(); + else + sb.Append((char)b); + } + return sb.ToString(); + } + } + + // NB we have to do it this way because we cannot encrypt strings correctly unless they are byte arrays + public string alt_licence_name + { + set + { + int i; + StringBuilder sb = new StringBuilder(value, 256); + for (i=0; i> 8) & 0xff); + data[offset+2] = (byte)((value >> 16) & 0xff); + data[offset+3] = (byte)((value >> 24) & 0xff); + return; + } + + // converts to DRIS structure to a byte array (so we can do encryption) + public void DrisToByteArray(DRIS dris, byte[] data) + { + GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned); + Marshal.StructureToPtr(dris, MyGC.AddrOfPinnedObject(), false); + MyGC.Free(); + return; + } + + // converts a byte array to the DRIS structure (so we can do encryption) + public void ByteArrayToDris(byte[] data, DRIS dris) + { + GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned); + Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), dris); + MyGC.Free(); + return; + } + + // to make a new instance of this class, initialise every element to a random value and then set the header + public DRIS() + { + Random rnd = new Random(); + Byte[] temp = new Byte[Marshal.SizeOf(this)]; + rnd.NextBytes(temp); + ByteArrayToDris(temp, this); + this.header1 = (byte)'D'; + this.header2 = (byte)'R'; + this.header3 = (byte)'I'; + this.header4 = (byte)'S'; + } + + // functions - must specify only one + public const int PROTECTION_CHECK = 1; // checks for dongle, check program params... + public const int EXECUTE_ALGORITHM = 2; // protection check + calculate answer for specified algorithm with specified inputs + public const int WRITE_DATA_AREA = 3; // protection check + writes dongle data area + public const int READ_DATA_AREA = 4; // protection check + reads dongle data area + public const int ENCRYPT_USER_DATA = 5; // protection check + the dongle will encrypt user data + public const int DECRYPT_USER_DATA = 6; // protection check + the dongle will decrypt user data + public const int FAST_PRESENCE_CHECK = 7; // checks for the presence of the correct dongle only with minimal security, no flags allowed. + public const int STOP_NET_USER = 8; // stops a network user (a protection check is NOT performed) + + // flags - can specify as many as you like + public const int DEC_ONE_EXEC = 1; // decrement execs by 1 + public const int DEC_MANY_EXECS = 2; // decrement execs by number specified in execs_decrement + public const int START_NET_USER = 4; // starts a network user + public const int USE_FUNCTION_ARGUMENT = 16; // use the extra argument in the function for pointers + public const int CHECK_LOCAL_FIRST = 32; // always look in local ports before looking in network ports + public const int CHECK_NETWORK_FIRST = 64; // always look on the network before looking in local ports + public const int USE_ALT_LICENCE_NAME = 128; // use name specified in alt_licence_name instead of the default one + public const int DONT_SET_MAXDAYS_EXPIRY = 256; // if the max days expiry date has not been calculated then do not do it this time + public const int MATCH_DONGLE_NUMBER = 512; // restrict the search to match the dongle number specified in the DRIS + public const int DONT_RETURN_FD_DRIVE = 1024; // if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct NU_INFO +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string licenceName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=50)] + public string userName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string computerName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=16)] + public string ipAddress; +} + +// 32-bit protection check (loads 32-bit DLL) +class DDProtCheck32 +{ + [DllImport("dpwin32.dll", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// 64-bit protection check (loads 64-bit DLL) +class DDProtCheck64 +{ + [DllImport("dpwin64.dll", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// 32-bit get network user info (loads 32-bit DLL) +class DDGetNetUserList32 +{ + [DllImport("dpwin32.dll", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// 64-bit get network user info (loads 64-bit DLL) +class DDGetNetUserList64 +{ + [DllImport("dpwin64.dll", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// call our API - we only want to load the correct DLL for the bit-ness of the computer. The other DLL may not exist. +class DinkeyPro +{ + // calls the DDProtCheck function in the appropriate DLL + public static int DDProtCheck(DRIS dris, byte[] data) + { + int ret_code = -1; + + if (IntPtr.Size == 4) + { + try + { + ret_code = DDProtCheck32.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dpwin32.dll. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + else { + try + { + ret_code = DDProtCheck64.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dpwin64.dll. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + return ret_code; + } + + public static int DDGetNetUserList(string licence_name, out int num_net_users, out NU_INFO[] nu_info, int num_info_structs, out int extended_error) + { + int ret_code = -1; + int i; + extended_error = num_net_users = 0; + byte[] nu_info_bytes = new byte[num_info_structs * Marshal.SizeOf(typeof(NU_INFO))]; + byte[] nu_info_one_struct = new byte[Marshal.SizeOf(typeof(NU_INFO))]; + GCHandle MyGC; + nu_info = null; + + // call the function and get info as a byte array + if (IntPtr.Size == 4) + ret_code = DDGetNetUserList32.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + else + ret_code = DDGetNetUserList64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + + if (ret_code != 0) + return ret_code; + + // convert byte array to an array of structs + nu_info = new NU_INFO[num_net_users]; + for (i=0; i> 8) & 0xff); + data[offset+2] = (byte)((value >> 16) & 0xff); + data[offset+3] = (byte)((value >> 24) & 0xff); + return; + } + + // converts to DRIS structure to a byte array (so we can do encryption) + public void DrisToByteArray(DRIS dris, byte[] data) + { + GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned); + Marshal.StructureToPtr(dris, MyGC.AddrOfPinnedObject(), false); + MyGC.Free(); + return; + } + + // converts a byte array to the DRIS structure (so we can do encryption) + public void ByteArrayToDris(byte[] data, DRIS dris) + { + GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned); + Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), dris); + MyGC.Free(); + return; + } + + // to make a new instance of this class, initialise every element to a random value and then set the header + public DRIS() + { + Random rnd = new Random(); + Byte[] temp = new Byte[Marshal.SizeOf(this)]; + rnd.NextBytes(temp); + ByteArrayToDris(temp, this); + this.header1 = (byte)'D'; + this.header2 = (byte)'R'; + this.header3 = (byte)'I'; + this.header4 = (byte)'S'; + } + + // functions - must specify only one + public const int PROTECTION_CHECK = 1; // checks for dongle, check program params... + public const int EXECUTE_ALGORITHM = 2; // protection check + calculate answer for specified algorithm with specified inputs + public const int WRITE_DATA_AREA = 3; // protection check + writes dongle data area + public const int READ_DATA_AREA = 4; // protection check + reads dongle data area + public const int ENCRYPT_USER_DATA = 5; // protection check + the dongle will encrypt user data + public const int DECRYPT_USER_DATA = 6; // protection check + the dongle will decrypt user data + public const int FAST_PRESENCE_CHECK = 7; // checks for the presence of the correct dongle only with minimal security, no flags allowed. + public const int STOP_NET_USER = 8; // stops a network user (a protection check is NOT performed) + + // flags - can specify as many as you like + public const int DEC_ONE_EXEC = 1; // decrement execs by 1 + public const int DEC_MANY_EXECS = 2; // decrement execs by number specified in execs_decrement + public const int START_NET_USER = 4; // starts a network user + public const int USE_FUNCTION_ARGUMENT = 16; // use the extra argument in the function for pointers + public const int CHECK_LOCAL_FIRST = 32; // always look in local ports before looking in network ports + public const int CHECK_NETWORK_FIRST = 64; // always look on the network before looking in local ports + public const int USE_ALT_LICENCE_NAME = 128; // use name specified in alt_licence_name instead of the default one + public const int DONT_SET_MAXDAYS_EXPIRY = 256; // if the max days expiry date has not been calculated then do not do it this time + public const int MATCH_DONGLE_NUMBER = 512; // restrict the search to match the dongle number specified in the DRIS + public const int DONT_RETURN_FD_DRIVE = 1024; // if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct NU_INFO +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string licenceName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=50)] + public string userName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string computerName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=16)] + public string ipAddress; +} + +// DDProtCheck + +// Windows 32-bit protection check (loads 32-bit DLL) +class DDProtCheckWin32 +{ + [DllImport("dpwin32.dll", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// Windows 64-bit protection check (loads 64-bit DLL) +class DDProtCheckWin64 +{ + [DllImport("dpwin64.dll", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// Linux 64-bit protection check (loads 64-bit so) (NB only 64-bit Linux is supported by .NET Core) +class DDProtCheckLin64 +{ + [DllImport("dplin64.so", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// Mac 64-bit protection check (loads 64-bit dylib) (NB only 64-bit Mac code is supported by .NET Core) (NB we found that the release module dpmac64.dylib crashed) +class DDProtCheckMac64 +{ + [DllImport("dpmac64debug.dylib", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// DDGetNetUserList + +// Windows 32-bit get network user info (loads 32-bit DLL) +class DDGetNetUserListWin32 +{ + [DllImport("dpwin32.dll", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// Windows 64-bit get network user info (loads 64-bit DLL) +class DDGetNetUserListWin64 +{ + [DllImport("dpwin64.dll", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// Linux 64-bit get network user info (loads 64-bit DLL) +class DDGetNetUserListLin64 +{ + [DllImport("dplin64.so", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// call our API - we only want to load the correct DLL for the OS and bit-ness of the computer. The other DLLs may not exist. +class DinkeyPro +{ + // calls the DDProtCheck function in the appropriate DLL + public static int DDProtCheck(DRIS dris, byte[] data) + { + int ret_code = -1; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // method valid from .NET Core 1.0 and .NET framework 4.7 + { + if (Environment.Is64BitProcess) // method valid from .NET Core 2.0 and .NET framework 4.0 + { + try + { + ret_code = DDProtCheckWin64.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dpwin64.dll. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + else + { + try + { + ret_code = DDProtCheckWin32.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dpwin32.dll. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + try + { + ret_code = DDProtCheckLin64.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dplin64.so. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + try + { + ret_code = DDProtCheckMac64.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dpmac64debug.dylib. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + else + { + MessageBox.Show("Error! Dinkey Pro/FD not supported on this OS.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + return ret_code; + } + + public static int DDGetNetUserList(string licence_name, out int num_net_users, out NU_INFO[] nu_info, int num_info_structs, out int extended_error) + { + int ret_code = -1; + int i; + extended_error = num_net_users = 0; + byte[] nu_info_bytes = new byte[num_info_structs * Marshal.SizeOf(typeof(NU_INFO))]; + byte[] nu_info_one_struct = new byte[Marshal.SizeOf(typeof(NU_INFO))]; + GCHandle MyGC; + nu_info = null; + + // call the function and get info as a byte array + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + if (Environment.Is64BitProcess) + ret_code = DDGetNetUserListWin64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + else + ret_code = DDGetNetUserListWin32.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + ret_code = DDGetNetUserListLin64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + MessageBox.Show("Error! This function is not supported in the Mac debug module.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + + if (ret_code != 0) + return ret_code; + + // convert byte array to an array of structs + nu_info = new NU_INFO[num_net_users]; + for (i=0; i> 8) & 0xff); + data[offset+2] = (byte)((value >> 16) & 0xff); + data[offset+3] = (byte)((value >> 24) & 0xff); + return; + } + + // converts to DRIS structure to a byte array (so we can do encryption) + public void DrisToByteArray(DRIS dris, byte[] data) + { + GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned); + Marshal.StructureToPtr(dris, MyGC.AddrOfPinnedObject(), false); + MyGC.Free(); + return; + } + + // converts a byte array to the DRIS structure (so we can do encryption) + public void ByteArrayToDris(byte[] data, DRIS dris) + { + GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned); + Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), dris); + MyGC.Free(); + return; + } + + // to make a new instance of this class, initialise every element to a random value and then set the header + public DRIS() + { + Random rnd = new Random(); + Byte[] temp = new Byte[Marshal.SizeOf(this)]; + rnd.NextBytes(temp); + ByteArrayToDris(temp, this); + this.header1 = (byte)'D'; + this.header2 = (byte)'R'; + this.header3 = (byte)'I'; + this.header4 = (byte)'S'; + } + + // functions - must specify only one + public const int PROTECTION_CHECK = 1; // checks for dongle, check program params... + public const int EXECUTE_ALGORITHM = 2; // protection check + calculate answer for specified algorithm with specified inputs + public const int WRITE_DATA_AREA = 3; // protection check + writes dongle data area + public const int READ_DATA_AREA = 4; // protection check + reads dongle data area + public const int ENCRYPT_USER_DATA = 5; // protection check + the dongle will encrypt user data + public const int DECRYPT_USER_DATA = 6; // protection check + the dongle will decrypt user data + public const int FAST_PRESENCE_CHECK = 7; // checks for the presence of the correct dongle only with minimal security, no flags allowed. + public const int STOP_NET_USER = 8; // stops a network user (a protection check is NOT performed) + + // flags - can specify as many as you like + public const int DEC_ONE_EXEC = 1; // decrement execs by 1 + public const int DEC_MANY_EXECS = 2; // decrement execs by number specified in execs_decrement + public const int START_NET_USER = 4; // starts a network user + public const int USE_FUNCTION_ARGUMENT = 16; // use the extra argument in the function for pointers + public const int CHECK_LOCAL_FIRST = 32; // always look in local ports before looking in network ports + public const int CHECK_NETWORK_FIRST = 64; // always look on the network before looking in local ports + public const int USE_ALT_LICENCE_NAME = 128; // use name specified in alt_licence_name instead of the default one + public const int DONT_SET_MAXDAYS_EXPIRY = 256; // if the max days expiry date has not been calculated then do not do it this time + public const int MATCH_DONGLE_NUMBER = 512; // restrict the search to match the dongle number specified in the DRIS + public const int DONT_RETURN_FD_DRIVE = 1024; // if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct NU_INFO +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string licenceName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=50)] + public string userName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string computerName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=16)] + public string ipAddress; +} + +// DDProtCheck + +// Windows 32-bit protection check (loads 32-bit DLL) +class DDProtCheckWin32 +{ + [DllImport("dpwin32.dll", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// Windows 64-bit protection check (loads 64-bit DLL) +class DDProtCheckWin64 +{ + [DllImport("dpwin64.dll", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// Linux 32-bit protection check (loads 32-bit so) +class DDProtCheckLin32 +{ + [DllImport("dplin32.so", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// Linux 64-bit protection check (loads 64-bit so) +class DDProtCheckLin64 +{ + [DllImport("dplin64.so", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// Mac 32-bit protection check (loads 32-bit dylib) +class DDProtCheckMac32 +{ + [DllImport("dpmac32.dylib", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// Mac 64-bit protection check (loads 64-bit dylib) +class DDProtCheckMac64 +{ + [DllImport("dpmac64.dylib", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data); +} + +// DDGetNetUserList + +// Windows 32-bit get network user info (loads 32-bit DLL) +class DDGetNetUserListWin32 +{ + [DllImport("dpwin32.dll", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// Windows 64-bit get network user info (loads 64-bit DLL) +class DDGetNetUserListWin64 +{ + [DllImport("dpwin64.dll", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// Linux 32-bit get network user info (loads 32-bit so) +class DDGetNetUserListLin32 +{ + [DllImport("dplin32.so", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// Linux 64-bit get network user info (loads 64-bit so) +class DDGetNetUserListLin64 +{ + [DllImport("dplin64.so", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// Mac 32-bit get network user info (loads 32-bit dylib) +class DDGetNetUserListMac32 +{ + [DllImport("dpmac32.dylib", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// Mac 64-bit get network user info (loads 64-bit dylib) +class DDGetNetUserListMac64 +{ + [DllImport("dpmac64.dylib", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// call our API - we only want to load the correct DLL for the OS and bit-ness of the computer. The other DLLs may not exist. +class DinkeyPro +{ + // calls the DDProtCheck function in the appropriate DLL + public static int DDProtCheck(DRIS dris, byte[] data) + { + int ret_code = -1; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // method valid from .NET Core 1.0 and .NET framework 4.7 + { + if (Environment.Is64BitProcess) // method valid from .NET Core 2.0 and .NET framework 4.0 + { + try + { + ret_code = DDProtCheckWin64.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dpwin64.dll. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + else + { + try + { + ret_code = DDProtCheckWin32.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dpwin32.dll. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + if (Environment.Is64BitProcess) + { + try + { + ret_code = DDProtCheckLin64.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dplin64.do. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + else + { + try + { + ret_code = DDProtCheckLin32.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dplin32.so. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + if (Environment.Is64BitProcess) + { + try + { + ret_code = DDProtCheckMac64.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dpmac64.dylib. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + else + { + try + { + ret_code = DDProtCheckMac32.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + MessageBox.Show("Error! Cannot find dpmac32.dylib. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + } + else + { + MessageBox.Show("Error! Dinkey Pro/FD not supported on this OS.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + return ret_code; + } + + public static int DDGetNetUserList(string licence_name, out int num_net_users, out NU_INFO[] nu_info, int num_info_structs, out int extended_error) + { + int ret_code = -1; + int i; + extended_error = num_net_users = 0; + byte[] nu_info_bytes = new byte[num_info_structs * Marshal.SizeOf(typeof(NU_INFO))]; + byte[] nu_info_one_struct = new byte[Marshal.SizeOf(typeof(NU_INFO))]; + GCHandle MyGC; + nu_info = null; + + // call the function and get info as a byte array + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + if (Environment.Is64BitProcess) + ret_code = DDGetNetUserListWin64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + else + ret_code = DDGetNetUserListWin32.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + if (Environment.Is64BitProcess) + ret_code = DDGetNetUserListLin64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + else + ret_code = DDGetNetUserListLin32.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + if (Environment.Is64BitProcess) + ret_code = DDGetNetUserListMac64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + else + ret_code = DDGetNetUserListMac32.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + } + + if (ret_code != 0) + return ret_code; + + // convert byte array to an array of structs + nu_info = new NU_INFO[num_net_users]; + for (i=0; i". + +If you publish a "single-file executable" file then although this file can be protected we do not recommend +it because it is not secure. (The single-file executable just comprises a stub loader with your compiled +assemblies and configuration files appended to the end of the executable. These files are just considered as +data appended to the executable file in a custom format and therefore are not protected. When you shell +protect your executable you are just protecting the loader but not your assemblies). Instead you need to +build your code and then add protection before publishing. You should protect your assemblies in the obj +directory (and in the platform type you specified) e.g. obj/Release/net5.0/win-x64, because the publish +process takes your assemblies from this location when it builds the single-file executable. You will also +need to distribute all the extra files that DinkeyAdd generates. e.g. .dp64.dll. + +If you publish using the ReadytoRun compilation this will not work because it includes mixtures of .NET +assemblies and native code and the .NET Shell Method does not support that. + +Mono +~~~~ + +The sample code provided also works with Mono. However, Mono also supports Linux and macOS, and so if you want +to support those OS then please replace dris.cs with dris_mono.cs. Note, dris_mono.cs is very similar to +dris_dotnetcore.cs (see above) but with Mono, 32-bit Linux and 32-bit Mac are also supported and you don't +need to use the debug modules (for release) under macOS. + +Visual Studio Installer Projects Extension +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can use this extension to create a project in your solution that will create an installation program / msi +file. Please note that after your application has been built you need to protect it with DinkeyAdd before you +can invoke the installer project. You can do this manually by building your application project (not the entire +solution); then adding protection to your application using DinkeyAdd; then building your installer project. +Or you can automate this by executing DinkeyAddCmd as a post-build step. For example: +"c:\program files (x86)\Dinkey Pro 7.6.0\DinkeyAdd\DinkeyAddCmd.exe" c:\adir\mydapf.dapfj /a2 + +Note - if you specify "primary output" in your installer project then it will take the files from +obj\Release\net5.0 (for example), rather than bin\Release\net5.0. So, you need to add protection to your files +in this folder. + +Note - if you use the API Method you will also need to include the protected runtime modules that you use +(e.g. dpwin64.dll). If you use the Shell Method you will also need to include in your installer project all +of the output files mentioned by DinkeyAdd. e.g. .dp64.dll diff --git a/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2022/DllTest.csproj b/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2022/DllTest.csproj new file mode 100644 index 0000000..74abf5c --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2022/DllTest.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2022/DllTest.sln b/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2022/DllTest.sln new file mode 100644 index 0000000..15551a7 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2022/DllTest.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DllTest", "DllTest.csproj", "{EDCD7B70-034F-417C-B7C0-E86583C2FC5C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EDCD7B70-034F-417C-B7C0-E86583C2FC5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EDCD7B70-034F-417C-B7C0-E86583C2FC5C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EDCD7B70-034F-417C-B7C0-E86583C2FC5C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EDCD7B70-034F-417C-B7C0-E86583C2FC5C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {02BA6556-AD6D-40BD-A7EE-65BEE2095E5C} + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2022/Program.cs b/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2022/Program.cs new file mode 100644 index 0000000..528a671 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2022/Program.cs @@ -0,0 +1,808 @@ +// See https://aka.ms/new-console-template for more information + +using System; +using System.Runtime.InteropServices; + + +namespace DllTest +{ + public class Program + { + public const int MY_SDSN = 10101; // !!!! change this value to be the value of your SDSN (demo = 10101) + public const string MY_PRODCODE = "DEMO"; // !!!! change this value to match the Product Code in the dongle + + /* The sample code contains 11 functions. You will not need to use all these + functions in your code. Just use which ever functions are most appropriate + and customise in your own way. The sample code is just a guide. You should + implement the protection in a stronger way using the techniques described in + the "Increasing your Protection" chapter of the manual. + + ProtCheck // a standard protection check + ProtCheckWithAlg // a protection check & executing an Algorithm + WriteBytes // a protection check & write data to the dongle + ReadBytes // a protection check & read data from the dongle + EncryptUserData // a protection check & encrypting data and then decrypting the data + // these functions are the same as the functions listed above but encrypting all parameters passed to our API + ProtCheckEnc // a standard protection check + ProtCheckWithAlgEnc // a protection check & executing an Algorithm + WriteBytesEnc // a protection check & write data to the dongle + ReadBytesEnc // a protection check & read data from the dongle + EncryptUserDataEnc // a protection check & encrypting data and then decrypting the data + // this function displays the current network users + DisplayNetUsers + + If you are using Dinkey Lite then you can only use 4 functions: + ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + */ + + public static void Main(string[] args) + { + // call the function(s) of your choice here + // in this example I have chosen a standard protection check + if (ProtCheck() == 0) + { + DisplayMessage("It worked!"); // NB on failure a message will have already been displayed + } + } + + // **************************** ProtCheck ********************************* + // standard protection check + public static int ProtCheck() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.PROTECTION_CHECK; // standard protection check + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + ret_code = DinkeyPro.DDProtCheck(dris, null); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + DisplayMessage("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + } + + if (dris.prodcode != MY_PRODCODE) + { + DisplayMessage("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle."); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + DisplayMessage("Dinkey Dongle protection error"); + return -1; + } + + // if you are using a network dongle and you want to list the network users then use this function: + //DisplayNetUsers(dris); + + return 0; + } + + // **************************** ProtCheckWithAlg **************************** + + // !!!! You should replace this function with the one generated by the + // "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) + // or from DinkeyLook if you are using a Dinkey Lite dongle. + private static int MyAlgorithm(int a, int b, int c, int d, int e, int f, int g, int h) + { + return a + b + c + d + e + f + g + h; + } + + // NB for this to work you must program at least "user algorithm" into the dongle + // NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + // sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite copy the sample code from DinkeyLook + public static int ProtCheckWithAlg() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.EXECUTE_ALGORITHM; // standard protection check & execute algorithm + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number = 1; // execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + // you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.var_a = 1; // sample values + dris.var_b = 2; + dris.var_c = 3; + dris.var_d = 4; + dris.var_e = 5; + dris.var_f = 6; + dris.var_g = 7; + dris.var_h = 8; + + ret_code = DinkeyPro.DDProtCheck(dris, null); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + DisplayMessage("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + DisplayMessage("Dinkey Dongle protection error"); + return -1; + } + + // if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + // !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) != dris.alg_answer) + { + DisplayMessage("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine"); + return -1; + } + return 0; + } + + // ************************** WriteBytes ****************************** + // This writes the Data 0,1,2,3,4,5,6,7,8,9 to the dongle data area at offset 7 + // In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + // if you want to write a string then you need to convert it to a byte array first: + // encoding.GetBytes(your_string, 0, your_string.Length, data, 0) where encoding is of ASCIIEncoding type. + public static int WriteBytes() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + byte[] DataToWrite = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.WRITE_DATA_AREA; // standard protection check & write data to dongle + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris.rw_offset = 7; + dris.rw_length = DataToWrite.GetLength(0); + + ret_code = DinkeyPro.DDProtCheck(dris, DataToWrite); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + DisplayMessage("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + DisplayMessage("Dinkey Dongle protection error"); + return -1; + } + return 0; + } + + // ************************ ReadBytes ************************************ + // This reads 10 bytes of data from offset 7 in the dongle data area + // In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + // if you want to read a string then you need to convert it from a byte array (via an array of char) + // CharArray = encoding.GetChars(data); where CharArray is of type char[] and encoding is of type ASCIIEncoding + // your_string = new String(CharArray, 0, your_string_length); + public static int ReadBytes() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + byte[] DataToRead = new byte[10]; + string DisplayString; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.READ_DATA_AREA; // standard protection check & read data + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris.rw_offset = 7; + dris.rw_length = DataToRead.GetLength(0); + + ret_code = DinkeyPro.DDProtCheck(dris, DataToRead); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + DisplayMessage("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + DisplayMessage("Dinkey Dongle protection error"); + return -1; + } + + DisplayString = "Dinkey Dongle data area, offset 7: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}", + DataToRead[0], DataToRead[1], DataToRead[2], DataToRead[3], DataToRead[4], DataToRead[5], DataToRead[6], DataToRead[7], DataToRead[8], DataToRead[9]); + DisplayMessage(DisplayString); + return 0; + } + + // ************************** EncryptUserData ************************************ + // This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 + // It will then do another protection check & decrypt the data + // if you want to encrypt of decrypt string then see comment for WriteBytes and ReadBytes + public static int EncryptUserData() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + byte[] Data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + string DisplayString; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.ENCRYPT_USER_DATA; // standard protection check & encrypt data + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; + dris.rw_length = Data.GetLength(0); + dris.data_crypt_key_num = 1; + + ret_code = DinkeyPro.DDProtCheck(dris, Data); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + // Now decrypt the same data to get the original values + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.DECRYPT_USER_DATA; // standard protection check & read data + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris.rw_length = Data.GetLength(0); + dris.data_crypt_key_num = 1; + + ret_code = DinkeyPro.DDProtCheck(dris, Data); + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + DisplayMessage("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + DisplayMessage("Dinkey Dongle protection error"); + return -1; + } + + DisplayString = "decrypted data is: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}", + Data[0], Data[1], Data[2], Data[3], Data[4], Data[5], Data[6], Data[7], Data[8], Data[9]); + DisplayMessage(DisplayString); + return 0; + } + + // !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! + // In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" + // in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm + // but the code can be modified easily to use the 3 encryption parameters. + + // !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm + private static int MyRWAlgorithm(int a, int b, int c, int d, int e, int f, int g, int h) + { + return a ^ b ^ c ^ d ^ e ^ f; + } + + + // !!!! please overwrite this function with the one generated by DinkeyAdd + private static void CryptDRIS(DRIS dris) + { + int i, j, k; + byte[] bigseed = new byte[256]; + byte[] S = new byte[256]; + byte temp, t; + byte[] dris_bytes = new byte[Marshal.SizeOf(dris)]; + + dris.DrisToByteArray(dris, dris_bytes); // convert DRIS to byte array so we can encrypt it + + for (i = 0; i < 256; i += 8) + { + dris.Set4Bytes(bigseed, i, dris.seed1); + dris.Set4Bytes(bigseed, i + 4, dris.seed2); + } + for (i = 0; i < 256; i++) + S[i] = (byte)i; + for (i = 0, j = 0; i < 256; i++) + { + j = (j + S[i] + bigseed[i] + 123) % 256; + temp = S[i]; + S[i] = S[j]; + S[j] = temp; + } + for (i = 0, j = 0, k = 16; k < Marshal.SizeOf(dris); k++) + { + i = (i + 1) % 256; + j = (j + S[i] + 212) % 256; + temp = S[i]; + S[i] = S[j]; + S[j] = temp; + t = (byte)(S[i] + S[j] + 97); + dris_bytes[k] ^= S[t]; + } + dris.ByteArrayToDris(dris_bytes, dris); // convert it back again + return; + } + + // !!!! please overwrite this function with the one generated by DinkeyAdd + private static void CryptApiData(DRIS dris, byte[] data, int length, int alg_answer) + { + int i, j, k; + byte[] bigseed = new byte[256]; + byte[] S = new byte[256]; + byte temp, t; + + for (i = 0; i < 256; i += 8) + { + dris.Set4Bytes(bigseed, i, dris.seed1); + dris.Set4Bytes(bigseed, i + 4, dris.seed2); + } + for (i = 0; i < 256; i++) + S[i] = (byte)i; + for (i = 0, j = 0; i < 256; i++) + { + j = (j + S[i] + bigseed[i] + (alg_answer & 0xff)) % 256; + temp = S[i]; + S[i] = S[j]; + S[j] = temp; + } + for (i = 0, j = 0, k = 0; k < length; k++) + { + i = (i + 1) % 256; + j = (j + S[i] + ((alg_answer >> 8) & 0xff)) % 256; + temp = S[i]; + S[i] = S[j]; + S[j] = temp; + t = (byte)(S[i] + S[j] + ((alg_answer >> 16) & 0xff)); + data[k] ^= S[t]; + } + return; + } + + // **************************** ProtCheckEnc ****************************** + // We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. + public static int ProtCheckEnc() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.PROTECTION_CHECK; // standard protection check + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris, null); + + CryptDRIS(dris); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + DisplayMessage("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + } + + if (dris.prodcode != MY_PRODCODE) + { + DisplayMessage("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle."); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + DisplayMessage("Dinkey Dongle protection error"); + return -1; + } + return 0; + } + + // **************************** ProtCheckWithAlgEnc ************************* + // NB for this to work you must program at least "user algorithm" into the dongle + // NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + // sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite copy source from DinkeyLook. + // We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. + public static int ProtCheckWithAlgEnc() + { + int ret_code; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.EXECUTE_ALGORITHM; // standard protection check & execute algorithm + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number = 1; // execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + // you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.var_a = 1; // sample values + dris.var_b = 2; + dris.var_c = 3; + dris.var_d = 4; + dris.var_e = 5; + dris.var_f = 6; + dris.var_g = 7; + dris.var_h = 8; + + CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris, null); + + CryptDRIS(dris); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + DisplayMessage("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + DisplayMessage("Dinkey Dongle protection error"); + return -1; + } + + // if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + // !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) != dris.alg_answer) + { + DisplayMessage("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine"); + return -1; + } + return 0; + } + + // ************************** WriteBytesEnc *************************** + // This writes the Data 0,1,2,3,4,5,6,7,8,9 to the dongle data area at offset 7 + // In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + // We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + // if you want to write strings then see comment for WriteBytes + public static int WriteBytesEnc() + { + int ret_code, alg_ans; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + byte[] DataToWrite = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.WRITE_DATA_AREA; // standard protection check & write data to dongle + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris.rw_offset = 7; + dris.rw_length = DataToWrite.GetLength(0); + + // calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + // encrypt data we want to write. + CryptApiData(dris, DataToWrite, DataToWrite.GetLength(0), alg_ans); + + CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris, DataToWrite); + + CryptDRIS(dris); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + DisplayMessage("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + DisplayMessage("Dinkey Dongle protection error"); + return -1; + } + return 0; + } + + // ************************ ReadBytesEnc ********************************* + // This reads 10 bytes of data from offset 7 in the dongle data area + // In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + // We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + // if you want to read strings then see comment for ReadBytes + public static int ReadBytesEnc() + { + int ret_code, alg_ans; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + byte[] DataRead = new byte[10]; + string DisplayString; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.READ_DATA_AREA; // standard protection check & read data + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris.rw_offset = 7; + dris.rw_length = DataRead.GetLength(0); + + // calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris, DataRead); + + CryptDRIS(dris); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris.sdsn != MY_SDSN) + { + DisplayMessage("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) + { + DisplayMessage("Dinkey Dongle protection error"); + return -1; + } + + // decrypt data that was read. + CryptApiData(dris, DataRead, DataRead.GetLength(0), alg_ans); + + DisplayString = "Dinkey Dongle data area, offset 7: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}", + DataRead[0], DataRead[1], DataRead[2], DataRead[3], DataRead[4], DataRead[5], DataRead[6], DataRead[7], DataRead[8], DataRead[9]); + DisplayMessage(DisplayString); + return 0; + } + + // ************************** EncryptUserDataEnc ********************************* + // This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 + // It will then do another protection & decrypt the data + // We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + // if you want to encrypt of decrypt strings then see comment for WriteBytes and ReadBytes + public static int EncryptUserDataEnc() + { + int ret_code, alg_ans; + DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header + DRIS dris2 = new DRIS(); // initialise the DRIS with random values & set the header + byte[] Data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + string DisplayString; + + dris.size = Marshal.SizeOf(dris); + dris.function = DRIS.ENCRYPT_USER_DATA; // standard protection check & encrypt data + dris.flags = DRIS.USE_FUNCTION_ARGUMENT; + dris.rw_length = Data.GetLength(0); + dris.data_crypt_key_num = 1; + + // calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + // encrypt data we pass to our API. + CryptApiData(dris, Data, Data.GetLength(0), alg_ans); + + CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris, Data); + + CryptDRIS(dris); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris.ext_err); + return ret_code; + } + + // ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + // NB use another dris so that we can ensure elements are initialised to different random numbers + dris2.size = Marshal.SizeOf(dris2); + dris2.function = DRIS.DECRYPT_USER_DATA; // standard protection check & read data + dris2.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C# + dris2.rw_length = Data.GetLength(0); + dris2.data_crypt_key_num = 1; + + CryptDRIS(dris2); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DinkeyPro.DDProtCheck(dris2, Data); + + CryptDRIS(dris2); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) + { + DisplayError(ret_code, dris2.ext_err); + return ret_code; + } + + // later in your code you can check other values in the DRIS... + if (dris2.sdsn != MY_SDSN) + { + DisplayMessage("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN."); + return -1; + } + + // later on in your program you can check the return code again + if (dris2.ret_code != 0) + { + DisplayMessage("Dinkey Dongle protection error"); + return -1; + } + + alg_ans = MyRWAlgorithm(dris2.var_a, dris2.var_b, dris2.var_c, dris2.var_d, dris2.var_e, dris2.var_f, dris2.var_g, dris2.var_h); + // decrypt data that was passed to us by the API. + CryptApiData(dris2, Data, Data.GetLength(0), alg_ans); + + DisplayString = "decrypted data is: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}", + Data[0], Data[1], Data[2], Data[3], Data[4], Data[5], Data[6], Data[7], Data[8], Data[9]); + DisplayMessage(DisplayString); + return 0; + } + + // *********************** DisplayNetUsers ******************************* + // This function displays the current network users (for DinkeyNet only). + // The DDProtCheck function must be called before this function is called. + // (Normally you would use DinkeyServer to view the network users but this enables you to do it from the client if you want) + public static int DisplayNetUsers(DRIS dris) + { + string DisplayString; + int num_net_users, extended_error, ret_code, i, max_net_users; + NU_INFO[]? nu_info; + + if (dris.net_users == -1) + max_net_users = 100; // if unlimited network users are allowed then display up to 100 users (for example) + else + max_net_users = dris.net_users; + + if (max_net_users == 0) // no network users are allowed, so nothing to do! + return 0; + + if (dris.model < 3) + { + DisplayMessage("A network dongle has not been detected. Therefore you cannot display the network users."); + return -1; + } + + ret_code = DinkeyPro.DDGetNetUserList(null, out num_net_users, out nu_info, max_net_users, out extended_error); + + if (ret_code != 0) + { + DisplayMessage(String.Format("Error {0}/{1} finding network user information.", ret_code, extended_error)); + } + else + { + DisplayString = String.Format("number of net users: {0}", num_net_users) + Environment.NewLine; + if (nu_info != null) + { + for (i = 0; i < num_net_users; i++) + { + DisplayString += String.Format("{0}. licence: {1}, user: {2}, computer: {3}, ip address: {4}", i + 1, + nu_info[i].licenceName, nu_info[i].userName, nu_info[i].computerName, nu_info[i].ipAddress); + DisplayString += Environment.NewLine; + } + } + DisplayMessage(DisplayString); + } + + return ret_code; + } + + // to display common errors that occur - !!!! you will want to change these messages + private static void DisplayError(int ret_code, int ext_err) + { + string DisplayString; + + switch (ret_code) + { + case 401: + DisplayMessage("Error! No dongles detected!"); + break; + + case 403: + DisplayMessage("Error! A dongle was detected but it was a different type to the one specified in DinkeyAdd."); + break; + + case 404: + DisplayMessage("Error! A dongle was detected but it was a different model to those specified in DinkeyAdd."); + break; + + case 409: + DisplayMessage("Error! The dongle detected has not been programmed by DinkeyAdd."); + break; + + case 410: + DisplayMessage("Error! A dongle was detected but it has a different Product Code to the one specified in DinkeyAdd."); + break; + + case 411: + DisplayMessage("Error! The dongle detected does not contain the licence associated with this program."); + break; + + case 413: + DisplayMessage("Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual."); + break; + + case 417: + DisplayMessage("Error! One or more of the parameters set in the DRIS is incorrect.\nIt could also be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa."); + break; + + case 423: + DisplayMessage("Error! The number of network users has been exceeded."); + break; + + case 435: + DisplayMessage("Error! DinkeyServer has not been detected on the network."); + break; + + case 922: + DisplayMessage("Error! The Software Key has expired."); + break; + + // internal error - cannot load DLL + case -1: + DisplayMessage("Error! Cannot call protection check because DLL is not loaded."); + break; + + default: + DisplayString = "An error occurred checking the dongle. Error: " + String.Format("{0:D}", ret_code) + "\nExtended Error: " + String.Format("{0:D}", ext_err); + DisplayMessage(DisplayString); + break; + } + return; + } + private static void DisplayMessage(string my_message) + { + // !!!! for Console programs use this line + Console.WriteLine(my_message); + // !!!! for Windows programs use this line + // MessageBox.Show(my_message, "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + } +} diff --git a/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2022/dris.cs b/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2022/dris.cs new file mode 100644 index 0000000..0082a03 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/Runtime/Visual Studio 2022/dris.cs @@ -0,0 +1,361 @@ +// !! this file should not be modified + +using System; +using System.Runtime.InteropServices; // so we can marshal the DRIS as a block of memory +using System.Text; // so we can extract / set strings in the DRIS + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public class DRIS +{ + // the first 4 fields are never encrypted + public byte header1; // should be set to "DRIS" + public byte header2; + public byte header3; + public byte header4; + // inputs + public int size; // size of this structure + public int seed1; // seed for data/dris encryption + public int seed2; // as above + // (maybe encrypted from now on) + public int function; // specify only one function + public int flags; // options for the function selected. To use more than one OR them together: OPTION1 | OPTION2... + public uint execs_decrement; // amount by which to dec execs if we use flag: DEC_MANY_EXECS + public int data_crypt_key_num; // number of the key (1-3) that the dongle uses to encrypt or decrypt user data + public int rw_offset; // offset in the dongle data area to read or write data + public int rw_length; // length of data are to read/write/encrypt/decrypt + public IntPtr DoNotUse; // do not use the rw_data_ptr element use the "Data" argument of the DDProtCheck function + [MarshalAs(UnmanagedType.ByValArray, SizeConst=256)] // NB access this field by using alg_licence_name (see below) + private byte[] _alt_licence_name = { 0 }; // protection check for different licence instead of this one + public int var_a; // variable values for user algorithm + public int var_b; + public int var_c; + public int var_d; + public int var_e; + public int var_f; + public int var_g; + public int var_h; + public int alg_number; // the number of the user algorithm that you want to execute + + // outputs + public int ret_code; // return code from the protection check + public int ext_err; // extended error + public int type; // type of dongle detected. 1 = Pro, 2 = FD + public int model; // model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + public int sdsn; // Software Developer's Serial Number + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] // NB access this field by using prodcode (see below) + private byte[] _prodcode = { 0 }; // product code (null-terminated) + public uint dongle_number; + public int update_number; + public uint data_area_size; // size of the data area in the dongle detected + public int max_alg_num; // number of algorithms in the dongle detected + public int execs; // executions left: -1 indicates 'no limit' + public int exp_day; // expiry day: -1 indicates 'no limit' + public int exp_month; // expiry month: -1 indicates 'no limit' + public int exp_year; // expiry year: -1 indicates 'no limit' + public uint features; // features value + public int net_users; // maximum number of network users for the dongle detected: -1 indicates 'mo limit' + public int alg_answer; // answer to the user algorithm executed with the given variable values + public uint fd_capacity; // capacity of the data area in FD dongle. Currently fixed at ~10MB but may change in the future. + [MarshalAs(UnmanagedType.ByValArray, SizeConst=128)] // NB access this field by using fd_drive (see below) + private byte[] _fd_drive = { 0 }; // fd drive letter (null-terminated) + public int swkey_type; // 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + public int swkey_exp_day; // software key expiry date (if software key detected) + public int swkey_exp_month; + public int swkey_exp_year; + + // NB we have to do it this way because we cannot encrypt strings correctly unless they are byte arrays + public string prodcode + { + get + { + StringBuilder sb = new StringBuilder(12); + foreach (byte b in _prodcode) + { + if (b == 0) + return sb.ToString(); + else + sb.Append((char)b); + } + return sb.ToString(); + } + } + + public string fd_drive + { + get + { + StringBuilder sb = new StringBuilder(128); + foreach (byte b in _fd_drive) + { + if (b == 0) + return sb.ToString(); + else + sb.Append((char)b); + } + return sb.ToString(); + } + } + + // NB we have to do it this way because we cannot encrypt strings correctly unless they are byte arrays + public string alt_licence_name + { + set + { + int i; + StringBuilder sb = new StringBuilder(value, 256); + for (i=0; i> 8) & 0xff); + data[offset+2] = (byte)((value >> 16) & 0xff); + data[offset+3] = (byte)((value >> 24) & 0xff); + return; + } + + // converts to DRIS structure to a byte array (so we can do encryption) + public void DrisToByteArray(DRIS dris, byte[] data) + { + GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned); + Marshal.StructureToPtr(dris, MyGC.AddrOfPinnedObject(), false); + MyGC.Free(); + return; + } + + // converts a byte array to the DRIS structure (so we can do encryption) + public void ByteArrayToDris(byte[] data, DRIS dris) + { + GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned); + Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), dris); + MyGC.Free(); + return; + } + + // to make a new instance of this class, initialise every element to a random value and then set the header + public DRIS() + { + Random rnd = new Random(); + Byte[] temp = new Byte[Marshal.SizeOf(this)]; + rnd.NextBytes(temp); + ByteArrayToDris(temp, this); + this.header1 = (byte)'D'; + this.header2 = (byte)'R'; + this.header3 = (byte)'I'; + this.header4 = (byte)'S'; + } + + // functions - must specify only one + public const int PROTECTION_CHECK = 1; // checks for dongle, check program params... + public const int EXECUTE_ALGORITHM = 2; // protection check + calculate answer for specified algorithm with specified inputs + public const int WRITE_DATA_AREA = 3; // protection check + writes dongle data area + public const int READ_DATA_AREA = 4; // protection check + reads dongle data area + public const int ENCRYPT_USER_DATA = 5; // protection check + the dongle will encrypt user data + public const int DECRYPT_USER_DATA = 6; // protection check + the dongle will decrypt user data + public const int FAST_PRESENCE_CHECK = 7; // checks for the presence of the correct dongle only with minimal security, no flags allowed. + public const int STOP_NET_USER = 8; // stops a network user (a protection check is NOT performed) + + // flags - can specify as many as you like + public const int DEC_ONE_EXEC = 1; // decrement execs by 1 + public const int DEC_MANY_EXECS = 2; // decrement execs by number specified in execs_decrement + public const int START_NET_USER = 4; // starts a network user + public const int USE_FUNCTION_ARGUMENT = 16; // use the extra argument in the function for pointers + public const int CHECK_LOCAL_FIRST = 32; // always look in local ports before looking in network ports + public const int CHECK_NETWORK_FIRST = 64; // always look on the network before looking in local ports + public const int USE_ALT_LICENCE_NAME = 128; // use name specified in alt_licence_name instead of the default one + public const int DONT_SET_MAXDAYS_EXPIRY = 256; // if the max days expiry date has not been calculated then do not do it this time + public const int MATCH_DONGLE_NUMBER = 512; // restrict the search to match the dongle number specified in the DRIS + public const int DONT_RETURN_FD_DRIVE = 1024; // if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + +} + +[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)] +public struct NU_INFO +{ + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string licenceName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=50)] + public string userName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public string computerName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=16)] + public string ipAddress; +} + +// DDProtCheck + +// Windows 32-bit protection check (loads 32-bit DLL) +class DDProtCheckWin32 +{ + [DllImport("dpwin32.dll", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[]? data); +} + +// Windows 64-bit protection check (loads 64-bit DLL) +class DDProtCheckWin64 +{ + [DllImport("dpwin64.dll", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[]? data); +} + +// Linux 64-bit protection check (loads 64-bit so) (NB only 64-bit Linux is supported by .NET Core) +class DDProtCheckLin64 +{ + [DllImport("dplin64.so", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[]? data); +} + +// Mac 64-bit protection check (loads 64-bit dylib) (NB only x64 Mac code is supported by .NET Core) (NB we found that the release module dpmac64.dylib crashed) +class DDProtCheckMac64 +{ + [DllImport("dpmac64debug.dylib", CharSet = CharSet.Ansi)] + public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[]? data); +} + +// DDGetNetUserList + +// Windows 32-bit get network user info (loads 32-bit DLL) +class DDGetNetUserListWin32 +{ + [DllImport("dpwin32.dll", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string? licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// Windows 64-bit get network user info (loads 64-bit DLL) +class DDGetNetUserListWin64 +{ + [DllImport("dpwin64.dll", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string? licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// Linux 64-bit get network user info (loads 64-bit DLL) +class DDGetNetUserListLin64 +{ + [DllImport("dplin64.so", CharSet = CharSet.Ansi)] + public static extern int DDGetNetUserList(string? licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error); +} + +// call our API - we only want to load the correct DLL for the OS and bit-ness of the computer. The other DLLs may not exist. +class DinkeyPro +{ + // calls the DDProtCheck function in the appropriate DLL + public static int DDProtCheck(DRIS dris, byte[]? data) + { + int ret_code = -1; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // method valid from .NET Core 1.0 and .NET framework 4.7 + { + if (Environment.Is64BitProcess) // method valid from .NET Core 2.0 and .NET framework 4.0 + { + try + { + ret_code = DDProtCheckWin64.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + DisplayMessage("Error! Cannot find dpwin64.dll. This should be in the same folder as DllTest."); + } + } + else + { + try + { + ret_code = DDProtCheckWin32.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + DisplayMessage("Error! Cannot find dpwin32.dll. This should be in the same folder as DllTest."); + } + } + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + try + { + ret_code = DDProtCheckLin64.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + DisplayMessage("Error! Cannot find dplin64.so. This should be in the same folder as DllTest."); + } + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + try + { + ret_code = DDProtCheckMac64.DDProtCheck(dris, data); + } + catch (DllNotFoundException) + { + DisplayMessage("Error! Cannot find dpmac64debug.dylib. This should be in the same folder as DllTest."); + } + } + else + { + DisplayMessage("Error! Dinkey Pro/FD not supported on this OS."); + } + return ret_code; + } + + public static int DDGetNetUserList(string? licence_name, out int num_net_users, out NU_INFO[]? nu_info, int num_info_structs, out int extended_error) + { + int ret_code = -1; + int i; + extended_error = num_net_users = 0; + byte[] nu_info_bytes = new byte[num_info_structs * Marshal.SizeOf(typeof(NU_INFO))]; + byte[] nu_info_one_struct = new byte[Marshal.SizeOf(typeof(NU_INFO))]; + GCHandle MyGC; + nu_info = null; + + // call the function and get info as a byte array + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + if (Environment.Is64BitProcess) + ret_code = DDGetNetUserListWin64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + else + ret_code = DDGetNetUserListWin32.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + ret_code = DDGetNetUserListLin64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + DisplayMessage("Error! This function is not supported in the Mac debug module."); + } + + if (ret_code != 0) + return ret_code; + + // convert byte array to an array of structs + nu_info = new NU_INFO[num_net_users]; + for (i=0; i". + +If you publish a "single-file executable" file then although this file can be protected we do not recommend +it because it is not secure. (The single-file executable just comprises a stub loader with your compiled +assemblies and configuration files appended to the end of the executable. These files are just considered as +data appended to the executable file in a custom format and therefore are not protected. When you shell +protect your executable you are just protecting the loader but not your assemblies). Instead you need to +build your code and then add protection before publishing. You should protect your assemblies in the obj +directory (and in the platform type you specified) e.g. obj/Release/net6.0/win-x64, because the publish +process takes your assemblies from this location when it builds the single-file executable. You will also +need to distribute all the extra files that DinkeyAdd generates. e.g. .dp64.dll. + +If you publish using the ReadytoRun compilation this will not work because it includes mixtures of .NET +assemblies and native code and the .NET Shell Method does not support that. + + +Visual Studio Installer Projects Extension +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can use this extension to create a project in your solution that will create an installation program / msi +file. Please note that after your application has been built you need to protect it with DinkeyAdd before you +can invoke the installer project. You can do this manually by building your application project (not the entire +solution); then adding protection to your application using DinkeyAdd; then building your installer project. +Or you can automate this by executing DinkeyAddCmd as a post-build step. For example: +"c:\program files (x86)\Dinkey Pro 7.6.0\DinkeyAdd\DinkeyAddCmd.exe" c:\adir\mydapf.dapfj /a2 + +Note - if you specify "primary output" in your installer project then it will take the files from +obj\Release\net5.0 (for example), rather than bin\Release\net5.0. So, you need to add protection to your files +in this folder. + +Note - you will also need to include in your installer project all of the output files mentioned by DinkeyAdd. +e.g. .dp64.dll diff --git a/Dinkey Pro 7.6.1/Samples/C#/Runtime/which project should I use.txt b/Dinkey Pro 7.6.1/Samples/C#/Runtime/which project should I use.txt new file mode 100644 index 0000000..4f29c54 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C#/Runtime/which project should I use.txt @@ -0,0 +1,23 @@ +Which Project should I use? +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Visual Studio 2002 project will work for any version of Visual Studio from +Visual Studio 2002 to Visual Studio 2019. This project is a Windows Form +application targeting the .NET 4 Framework. However, it can be easily adapted to +target .NET Core or .NET 5 (and higher). The C# code is written in C# version 1. + +The Visual Studio 2022 project will work with Visual Studio 2022 (and higher). +It is a Console application targeting .NET 6 and using C# version 10. If you want +to target earlier versions of .NET or C# then use the Visual Studio 2002 project. + +The C# code is very similar in both projects. However, C# v8 required changes to +account for possible Null reference exceptions. + +Visual Studio 2019 was the first version of VS to support C# v8. However, null +reference warnings are turned off by default, so you will get warnings if you +compile the VS2022 C# code. + +On the other hand in Visual Studio 2022 null reference warnings are turned on by +default so you will get warnings if you compile the VS2002 C# code. + +Whichever project you use always read the "readme" file for important instructions. \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/C/C++Builder XE3/DinkeyChange/ChangeTest.cbproj b/Dinkey Pro 7.6.1/Samples/C/C++Builder XE3/DinkeyChange/ChangeTest.cbproj new file mode 100644 index 0000000..45d5ece --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/C++Builder XE3/DinkeyChange/ChangeTest.cbproj @@ -0,0 +1,224 @@ + + + {2960c946-f28b-4c7c-9c85-55a82b8728d0} + Release + None + 14.4 + True + Win32 + 3 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + true + Cfg_2 + true + true + + + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + exe + System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) + 2057 + true + JPHNE + true + ..\..\..\C;..\..\Visual Studio 5\DinkeyChange;..\..\C++Builder\DinkeyChange;$(ILINK_ObjectSearchPath) + true + true + CppGuiApplication + vcl.bpi;rtl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;$(PackageImports) + false + ..\..\;$(BDS)\include;..\..\..\C;..\..\Visual Studio 5\DinkeyChange;..\..\C++Builder\DinkeyChange;$(IncludePath) + rtl.lib;vcl.lib + ..\..\;$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\..\..\C;..\..\Visual Studio 5\DinkeyChange;$(ILINK_LibraryPath) + + + true + $(BDS)\bin\default_app.manifest + 1033 + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + NO_STRICT;$(Defines) + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + + + $(BDS)\bin\default_app.manifest + 1033 + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + true + + + false + false + true + true + false + true + None + DEBUG;$(DCC_Define) + true + Debug + true + true + $(BDS)\lib\debug;$(ILINK_LibraryPath) + true + Full + true + + + _DEBUG;$(Defines) + + + _DEBUG;$(Defines) + + + Release + $(BDS)\lib\release;$(ILINK_LibraryPath) + None + + + rtl.bpi;vcl.bpi + NDEBUG;$(Defines) + + + rtl.bpi;vcl.bpi + NDEBUG;$(Defines) + + + CPlusPlusBuilder.Personality.12 + CppGuiApplication + + + + False + False + 1 + 0 + 0 + 0 + False + False + False + False + False + 2057 + 1252 + + + + + 1.0.0.0 + + + + + + 1.0.0.0 + + + + + + + + + False + + + + + + + False + + False + + True + False + + + + + + + + False + True + True + + + + False + True + True + + + 12 + + + + +
ChangeTest.res
+ 1 +
+ + 2 + + + 0 + + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + +
+ +
diff --git a/Dinkey Pro 7.6.1/Samples/C/C++Builder XE3/DinkeyChange/README.txt b/Dinkey Pro 7.6.1/Samples/C/C++Builder XE3/DinkeyChange/README.txt new file mode 100644 index 0000000..1bf7531 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/C++Builder XE3/DinkeyChange/README.txt @@ -0,0 +1,50 @@ +ChangeTest - sample code to call DinkeyChange.dll in C++ Builder XE3 (and more recent) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in C++ Builder XE3 but will work in more recent +versions (they will upgrade the Project to the latest version). For earlier versions +you should use the project in the C++Builder folder. + +The source files in the project are: + +File name Folder Description +changetest.c Samples\c main source code file for C +changetest.h Samples\c contains some useful constants +DinkeyChange_borland.lib Samples\c\import_libs contains the function definitions for DinkeyChange.dll +DinkeyChange64_borland.a Samples\c\import_libs contains the function definitions for DinkeyChange64.dll +changetest_imports.c Samples\c\C++Builder XE3\DinkeyChange contains code to link the correct import library +changetest.rc Samples\c\C++Builder\DinkeyChange resource for main dialog +resource.h Samples\c\C++Builder\DinkeyChange header file for resource + +Note that the source paths are structured to minimise files. If you want to +move this project the references to these files will probably be no longer valid. + +The project can compile to both 32-bit and 64-bit platforms and will link the appropriate +import library. For 32-bit you will call DinkeyChange.dll and for 64-bit you will call +DinkeyChange64.dll. + +The sample code contains 7 functions. Just use which ever functions are most +appropriate and customise in your own way. The sample code is just a guide. +As none of the parameters are sensitive then there is no need to implement +strong security in calling DinkeyChange. + +Note - you will not be able to debug your program after DinkeyChange has been called. +Our strong anti-debug code will cause the debugger to throw an exception. However, +if you do need to debug your code you can use our debug module for DinkeyChange: +DinkeyChangeDebug.dll (or 64-bit version). So, you can use DinkeyChange.dll +for your release build and DinkeyChangeDebug.dll for your debug build. + +Note - the 32-bit DinkeyChange_borland.lib was created using Borland's IMPLIB tool. If there is a problem +with the file we provide you can create your own by running (for example): + +c:\program files\CodeGear\Rad Studio 5.0\bin\implib import_libs\DinkeyChange_borland.lib DinkeyChange.dll + +(This assumes that the current directory is the Samples\C directory). + +Note - the 64-bit DinkeyChange64_borland.a was created using Borland's MKEXP tool. If there is a problem +with the file we provide you can create your own by running (for example): +(from a RAD Studio Command Prompt) + +mklib import_libs\DinkeyChange64_borland.a DinkeyChange64.dll + +(This assumes that the current directory is the Samples\C directory). \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/C/C++Builder XE3/DinkeyChange/changetest_imports.c b/Dinkey Pro 7.6.1/Samples/C/C++Builder XE3/DinkeyChange/changetest_imports.c new file mode 100644 index 0000000..c2f940b --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/C++Builder XE3/DinkeyChange/changetest_imports.c @@ -0,0 +1,12 @@ +// this file exists just to conditionally link in the correct import library +// (32-bit or 64-bit depending on the build) +// It is not very elegant but we cannot see any other way of doing it. +// If you know a better way of doing this then please let us know! + +#ifdef __BORLANDC__ + #ifdef __clang__ + #pragma link "..\\..\\import_libs\\DinkeyChange64_borland.a" // link 64-bit import library + #else + #pragma link "..\\..\\import_libs\\DinkeyChange_borland.lib" // link 32-bit import library + #endif +#endif diff --git a/Dinkey Pro 7.6.1/Samples/C/C++Builder XE3/Runtime/DllTest.cbproj b/Dinkey Pro 7.6.1/Samples/C/C++Builder XE3/Runtime/DllTest.cbproj new file mode 100644 index 0000000..9eeadc1 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/C++Builder XE3/Runtime/DllTest.cbproj @@ -0,0 +1,229 @@ + + + {139221f8-7474-4beb-9d31-ff91c75d2342} + Release + None + 14.4 + True + Win64 + 3 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + true + Cfg_2 + true + true + + + System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + exe + 2057 + true + JPHNE + true + ..\..\..\C;$(ILINK_ObjectSearchPath) + true + true + CppGuiApplication + vcl.bpi;rtl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;$(PackageImports) + false + ..\..\;$(BDS)\include;..\..\..\C;$(IncludePath) + rtl.lib;vcl.lib + ..\..\;$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\..\..\C;$(ILINK_LibraryPath) + + + true + NO_STRICT;$(Defines) + 1033 + $(BDS)\bin\default_app.manifest + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + + + true + 1033 + $(BDS)\bin\default_app.manifest + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + + + false + false + true + true + false + true + None + DEBUG;$(DCC_Define) + true + Debug + true + true + $(BDS)\lib\debug;$(ILINK_LibraryPath) + true + Full + true + + + 1033 + true + rtl.bpi;vcl.bpi + _DEBUG;$(Defines) + + + _DEBUG;$(Defines) + + + Release + $(BDS)\lib\release;$(ILINK_LibraryPath) + None + + + rtl.bpi;vcl.bpi + NDEBUG;$(Defines) + + + rtl.bpi;vcl.bpi + NDEBUG;$(Defines) + + + CPlusPlusBuilder.Personality.12 + CppGuiApplication + + + + False + False + 1 + 0 + 0 + 0 + False + False + False + False + False + 2057 + 1252 + + + + + 1.0.0.0 + + + + + + 1.0.0.0 + + + + + + + + + False + + + + + + + False + + False + + True + False + + + + + + + + False + True + True + + + Embarcadero C++Builder Office 2000 Servers Package + Embarcadero C++Builder Office XP Servers Package + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + False + True + True + + + 12 + + + + + 0 + + + 3 + + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + + + + diff --git a/Dinkey Pro 7.6.1/Samples/C/C++Builder XE3/Runtime/README.txt b/Dinkey Pro 7.6.1/Samples/C/C++Builder XE3/Runtime/README.txt new file mode 100644 index 0000000..11ca64c --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/C++Builder XE3/Runtime/README.txt @@ -0,0 +1,71 @@ +Sample code to call Runtime Modules in C++ Builder XE3 (or more recent) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in C++ Builder XE3 but will work in more recent +versions (they will upgrade the Project to the latest version). For earlier versions +you should use the C++ Builder sample. + +The source files in the project are: + +File name Folder Description +apitest.c Samples\c main source code file for C +dris.h Samples\c contains the DRIS structure +dlltest_imports.c Samples\c\C++Builder\Runtime contains code to link the correct import library +dpwin32_borland.lib Samples\c\import_libs contains the function definitions for dpwin32.dll +dpwin64_borland.a Samples\c\import_libs contains the function definitions for dpwin64.dll + +Note that the source paths are structured to minimise files. If you want to +move this project the references to these files will probably be no longer valid. + +The DllTest project uses the dynamic runtime library (e.g. dpwin32.dll or dpwin64.dll). + +NB There is no ObjTest project because currently there is no 64-bit static module for 64-bit C++ Builder. + +The project can compile to both 32-bit and 64-bit platforms and will link the appropriate +import library. For 32-bit builds you need to protect dpwin32.dll and for 64-bit builds you +need to protect dpwin64.dll. The protected DLL will need to be in the same folder as your +compiled program for it to run correctly. + +The sample code contains 10 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. + +NB You need to protect dpwin32.dll (dpwin64.dll) and *not* your program. +Because your program is linked to the DLL it is protected. + +Note - once dpwin32.dll (dpwin64.dll) is protected you will not be able to debug your program - +after our API has been called. Our strong anti-debug code will cause the debugger to +throw an exception. If you do want to debug your code then you can use the debug module: +dpwin32debug.dll (dpwin64debug.dll), but this should not be used for release. NB You will need +to link to the dpwin32debug_borland.lib (dpwin64debug_borland.a) import library if you use the +debug module. Edit dlltest_imports.c to do this. +(See readme.txt in samples\c for restrictions concerning the debug module). + +Note - the 32-bit dpwin32_borland.lib was created using Borland's IMPLIB tool. If there is a problem +with the file we provide you can create your own by running (for example): + +c:\program files\CodeGear\Rad Studio\5.0\bin\implib import_libs\dpwin32_borland.lib dpwin32.dll + +(This assumes that the current directory is the Samples\C directory). + +Note - the 64-bit dpwin64_borland.a was created using Borland's MKEXP tool. If there is a problem +with the file we provide you can create your own by running (for example): +(from a RAD Studio Command Prompt) + +mklib import_libs\dpwin64_borland.lib dpwin64.dll + +(This assumes that the current directory is the Samples\C directory). diff --git a/Dinkey Pro 7.6.1/Samples/C/C++Builder XE3/Runtime/dlltest_imports.c b/Dinkey Pro 7.6.1/Samples/C/C++Builder XE3/Runtime/dlltest_imports.c new file mode 100644 index 0000000..b9d92c5 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/C++Builder XE3/Runtime/dlltest_imports.c @@ -0,0 +1,12 @@ +// this file exists just to conditionally link in the correct import library +// (32-bit or 64-bit depending on the build) +// It is not very elegent but we cannot see any other way of doing it. +// If you know a better then please let us know! + +#ifdef __BORLANDC__ + #ifdef __clang__ + #pragma link "..\\..\\import_libs\\dpwin64_borland.a" // link 64-bit import library + #else + #pragma link "..\\..\\import_libs\\dpwin32_borland.lib" // link 32-bit import library + #endif +#endif diff --git a/Dinkey Pro 7.6.1/Samples/C/C++Builder/DinkeyChange/ChangeTest.cbproj b/Dinkey Pro 7.6.1/Samples/C/C++Builder/DinkeyChange/ChangeTest.cbproj new file mode 100644 index 0000000..7ec1574 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/C++Builder/DinkeyChange/ChangeTest.cbproj @@ -0,0 +1,143 @@ + + + + {2960c946-f28b-4c7c-9c85-55a82b8728d0} + Debug + + + true + + + true + true + Base + + + true + true + Base + + + true + NO_STRICT + JPHNE + true + ..\..\..\C;..\..\Visual Studio 5\DinkeyChange + true + true + CppGuiApplication + vcl.bpi;rtl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi + false + $(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\..\..\C;..\..\Visual Studio 5\DinkeyChange + rtl.lib;vcl.lib + $(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\..\..\C;..\..\Visual Studio 5\DinkeyChange + + + false + false + _DEBUG;$(Defines) + true + true + false + true + None + DEBUG + true + Debug + true + true + $(BDS)\lib\debug;$(ILINK_LibraryPath) + true + Full + true + + + NDEBUG;$(Defines) + Release + $(BDS)\lib\release;$(ILINK_LibraryPath) + None + + + CPlusPlusBuilder.Personality + CppGuiApplication + + + False + False + 1 + 0 + 0 + 0 + False + False + False + False + False + 2057 + 1252 + + + + + 1.0.0.0 + + + + + + 1.0.0.0 + + + + + + + + + False + + + + + + + False + + False + + True + False + + + + + + + + False + True + True + + + + + + + 0 + + + ChangeTest.rc +
ChangeTest.res
+ 1 +
+ + 2 + + + Cfg_1 + + + Cfg_2 + +
+
\ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/C/C++Builder/DinkeyChange/ChangeTest.rc b/Dinkey Pro 7.6.1/Samples/C/C++Builder/DinkeyChange/ChangeTest.rc new file mode 100644 index 0000000..53a76c2 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/C++Builder/DinkeyChange/ChangeTest.rc @@ -0,0 +1,35 @@ +#include "resource.h" + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 215, 358 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "ChangeTest" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "Get Dongle Information...",IDC_DONGLEINFO,45,14,119,14 + LTEXT "Enter Diagnostic filename:",IDC_STATIC,7,40,201,8 + EDITTEXT IDC_DIAG_PATH,7,49,201,14,ES_AUTOHSCROLL + PUSHBUTTON "Write Diagnostics to File",IDC_GETDIAGS,45,68,119,14 + LTEXT "Enter short Update Code here:",IDC_STATIC,7,96,201,8 + EDITTEXT IDC_UPDATE_CODE_STRING,7,106,201,14,ES_AUTOHSCROLL + PUSHBUTTON "Make Changes",IDC_DO_UPDATE_CODE_STRING,69,125,68,14 + LTEXT "Enter path to Update Code file:",IDC_STATIC,7,153,201,8 + EDITTEXT IDC_UPDATE_CODE_FILE,7,163,201,14,ES_AUTOHSCROLL + PUSHBUTTON "Make Changes",IDC_DO_UPDATE_CODE_FILE,68,183,68,14 + PUSHBUTTON "Restore Dinkey FD Lite",IDC_RESTORE_FD_LITE,45,215,119,14 + PUSHBUTTON "Get Machine ID",IDC_GET_MACHINE_ID,7,245,95,14 + EDITTEXT IDC_MACHINE_ID,110,245,98,14,ES_UPPERCASE + PUSHBUTTON "Download Temporary Software Key",IDC_GET_TEMP_SWKEY,35,275,139,14 + LTEXT "Demo Software Key Product Code:",IDC_STATIC,7,305,201,8 + EDITTEXT IDC_SWKEY_PRODCODE,7,314,201,14,ES_AUTOHSCROLL | ES_UPPERCASE + PUSHBUTTON "Download Demo Software Key",IDC_GET_DEMO_SWKEY,35,333,139,14 +END \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/C/C++Builder/DinkeyChange/README.txt b/Dinkey Pro 7.6.1/Samples/C/C++Builder/DinkeyChange/README.txt new file mode 100644 index 0000000..4ed0d7e --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/C++Builder/DinkeyChange/README.txt @@ -0,0 +1,35 @@ +ChangeTest - sample code to call DinkeyChange.dll in C++ Builder +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in C++ Builder 2007 but will work in more recent +versions (they will upgrade the Project to the latest version). For earlier versions +you can make your own project using the files listed below. + +The source files in the project are: + +File name Folder Description +changetest.c Samples\c main source code file for C +changetest.h Samples\c contains some useful constants +DinkeyChange_borland.lib Samples\c\import_libs contains the function definitions for DinkeyChange.dll +ChangeTest.rc Samples\c\C++Builder\DinkeyChange resource for main dialog + +Note that the source paths are structured to minimise files. If you want to +move this project the references to these files will probably be no longer valid. + +The sample code contains 7 functions. Just use which ever functions are most +appropriate and customise in your own way. The sample code is just a guide. +As none of the parameters are sensitive then there is no need to implement +strong security in calling DinkeyChange. + +Note - you will not be able to debug your program after DinkeyChange has been called. +Our strong anti-debug code will cause the debugger to throw an exception. However, +if you do need to debug your code you can use our debug module for DinkeyChange: +DinkeyChangeDebug.dll. So, you can use DinkeyChange.dll for your release build +and DinkeyChangeDebug.dll for your debug build. + +Note - the DinkeyChange_borland.lib was created using Borland's IMPLIB tool. If there is a problem +with the file we provide you can create your own by running (for example): + +c:\program files\CodeGear\Rad Studio 5.0\bin\implib import_libs\DinkeyChange_borland.lib DinkeyChange.dll + +(This assumes that the current directory is the Samples\C directory). diff --git a/Dinkey Pro 7.6.1/Samples/C/C++Builder/DinkeyChange/resource.h b/Dinkey Pro 7.6.1/Samples/C/C++Builder/DinkeyChange/resource.h new file mode 100644 index 0000000..422b9b5 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/C++Builder/DinkeyChange/resource.h @@ -0,0 +1,16 @@ +// Used by ChangeTest.rc + +#define IDD_DIALOG1 101 +#define IDC_DONGLEINFO 1000 +#define IDC_UPDATE_CODE_STRING 1001 +#define IDC_DO_UPDATE_CODE_STRING 1002 +#define IDC_DIAG_PATH 1003 +#define IDC_GETDIAGS 1004 +#define IDC_UPDATE_CODE_FILE 1005 +#define IDC_DO_UPDATE_CODE_FILE 1006 +#define IDC_RESTORE_FD_LITE 1007 +#define IDC_GET_MACHINE_ID 1008 +#define IDC_MACHINE_ID 1009 +#define IDC_GET_TEMP_SWKEY 1010 +#define IDC_SWKEY_PRODCODE 1011 +#define IDC_GET_DEMO_SWKEY 1012 diff --git a/Dinkey Pro 7.6.1/Samples/C/C++Builder/Runtime/DllTest.cbproj b/Dinkey Pro 7.6.1/Samples/C/C++Builder/Runtime/DllTest.cbproj new file mode 100644 index 0000000..f989234 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/C++Builder/Runtime/DllTest.cbproj @@ -0,0 +1,138 @@ + + + + {139221f8-7474-4beb-9d31-ff91c75d2342} + Debug + + + true + + + true + true + Base + + + true + true + Base + + + true + NO_STRICT + JPHNE + true + ..\..\..\C + true + true + CppGuiApplication + vcl.bpi;rtl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi + false + $(BDS)\include;$(BDS)\include\dinkumware;..\..\..\C + rtl.lib;vcl.lib + $(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\..\..\C + + + false + false + _DEBUG;$(Defines) + true + true + false + true + None + DEBUG + true + Debug + true + true + $(BDS)\lib\debug;$(ILINK_LibraryPath) + true + Full + true + + + NDEBUG;$(Defines) + Release + $(BDS)\lib\release;$(ILINK_LibraryPath) + None + + + CPlusPlusBuilder.Personality + CppGuiApplication + + + False + False + 1 + 0 + 0 + 0 + False + False + False + False + False + 2057 + 1252 + + + + + 1.0.0.0 + + + + + + 1.0.0.0 + + + + + + + + + False + + + + + + + False + + False + + True + False + + + + + + + + False + True + True + + + + + + + 0 + + + 1 + + + Cfg_1 + + + Cfg_2 + + + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/C/C++Builder/Runtime/ObjTest.cbproj b/Dinkey Pro 7.6.1/Samples/C/C++Builder/Runtime/ObjTest.cbproj new file mode 100644 index 0000000..4f52f86 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/C++Builder/Runtime/ObjTest.cbproj @@ -0,0 +1,138 @@ + + + + {e6943fc9-7514-48ab-91bc-57e69cb8cb4f} + Debug + + + true + + + true + true + Base + + + true + true + Base + + + true + NO_STRICT + JPHNE + true + ..\..\..\C + true + true + CppGuiApplication + vcl.bpi;rtl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi + false + $(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\..\..\C + rtl.lib;vcl.lib + $(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\..\..\C + + + false + false + _DEBUG;$(Defines) + true + true + false + true + None + DEBUG + true + Debug + true + true + $(BDS)\lib\debug;$(ILINK_LibraryPath) + true + Full + true + + + NDEBUG;$(Defines) + Release + $(BDS)\lib\release;$(ILINK_LibraryPath) + None + + + CPlusPlusBuilder.Personality + CppGuiApplication + + + False + False + 1 + 0 + 0 + 0 + False + False + False + False + False + 2057 + 1252 + + + + + 1.0.0.0 + + + + + + 1.0.0.0 + + + + + + + + + False + + + + + + + False + + False + + True + False + + + + + + + + False + True + True + + + + + + + 0 + + + 1 + + + Cfg_1 + + + Cfg_2 + + + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/C/C++Builder/Runtime/README.txt b/Dinkey Pro 7.6.1/Samples/C/C++Builder/Runtime/README.txt new file mode 100644 index 0000000..58a31ee --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/C++Builder/Runtime/README.txt @@ -0,0 +1,57 @@ +Sample code to call Runtime Modules in C++ Builder +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in C++ Builder 2007 but will work in more recent +versions (they will upgrade the Project to the latest version). For earlier versions +you can make your own project using the files listed below. + +The source files in the project are: + +File name Folder Description +apitest.c Samples\c main source code file for C +dris.h Samples\c contains the DRIS structure +dpwin32_omf.obj Samples\c\object_modules static object modules +dpwin32_borland.lib Samples\c\import_libs contains the function definitions for dpwin32.dll + +Note that the source paths are structured to minimise files. If you want to +move this project the references to these files will probably be no longer valid. + +The ObjTest project links to the static runtime library module (e.g dpwin32_omf.obj) + +The DllTest project uses the dynamic runtime library (e.g. dpwin32.dll). + +The sample code contains 10 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. + +Note - if you are link the static module dpwin32_omf.obj then you should protect your program. +If you are linking to dpwin32.dll then you need to protect dpwin32.dll and *not* your program. +Because your program is linked to the DLL it is protected. The protected DLL will need to be +in the same folder as your compiled program for it to run correctly. + +Note - once your program (or dpwin32.dll) is protected you will not be able to debug +your program - after our API has been called. Our strong anti-debug code will cause +the debugger to throw an exception. If you do want to debug your code then you can +use our debug module: dpwin32_omf_debug.obj (or dpwin32debug.dll), but these should not be +used for release. See readme.txt in samples\c for restrictions concerning the debug module. + +Note - the dpwin32_borland.lib was created using Borland's IMPLIB tool. If there is a problem +with the file we provide you can create your own by running (for example): + +c:\program files\CodeGear\Rad Studio\5.0\bin\implib import_libs\dpwin32_borland.lib dpwin32.dll + +(This assumes that the current directory is the Samples\C directory). diff --git a/Dinkey Pro 7.6.1/Samples/C/Dev-C++/DinkeyChange/ChangeTest.dev b/Dinkey Pro 7.6.1/Samples/C/Dev-C++/DinkeyChange/ChangeTest.dev new file mode 100644 index 0000000..97e70da --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Dev-C++/DinkeyChange/ChangeTest.dev @@ -0,0 +1,68 @@ +[Project] +FileName=ChangeTest.dev +Name=ChangeTest +UnitCount=2 +Type=1 +Ver=1 +ObjFiles= +Includes= +Libs= +PrivateResource=ChangeTest_private.rc +ResourceIncludes= +MakeIncludes= +Compiler= +CppCompiler= +Linker=../../import_libs/libDinkeyChange.a_@@_ +IsCpp=0 +Icon= +ExeOutput= +ObjectOutput= +OverrideOutput=0 +OverrideOutputName=ChangeTest.exe +HostApplication= +Folders= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000000000000000000 + +[Unit1] +FileName=..\..\changetest.c +CompileCpp=0 +Folder=ChangeTest +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + +[Unit2] +FileName=..\..\Visual Studio 5\DinkeyChange\ChangeTest.rc +Folder=ChangeTest +Compile=1 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + diff --git a/Dinkey Pro 7.6.1/Samples/C/Dev-C++/DinkeyChange/README.txt b/Dinkey Pro 7.6.1/Samples/C/Dev-C++/DinkeyChange/README.txt new file mode 100644 index 0000000..9946688 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Dev-C++/DinkeyChange/README.txt @@ -0,0 +1,30 @@ +ChangeTest - sample code to call DinkeyChange.dll in Dev-C++ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written using Dev C++ 4.9.9.2 but should also work in other +versions (for olders version you may have to create the project yourself). + +The source files in the project are: + +File name Folder Description +changetest.c Samples\c main source code file for C +changetest.h Samples\c contains some useful constants +libDinkeyChange.a Samples\c\import_libs contains the function definitions for DinkeyChange.dll +changetest.rc Samples\c\Visual Studio 5\DinkeyChange resource for main dialog + +Note that the source paths are structured to minimise files. If you want to +move this project the references to these files will probably be no longer valid. + +The sample code contains 7 functions. Just use which ever functions are most +appropriate and customise in your own way. The sample code is just a guide. +As none of the parameters are sensitive then there is no need to implement +strong security in calling DinkeyChange. + +Note - you will not be able to debug your program after DinkeyChange has been called. +Our strong anti-debug code will cause the debugger to throw an exception. However, +if you do need to debug your code you can use our debug module for DinkeyChange: +DinkeyChangeDebug.dll. So, you can use DinkeyChange.dll for your release build +and DinkeyChangeDebug.dll for your debug build. + +Note - if you are interested in creating the libDinkeyChange.a import library yourself +then read the notes in the MinGW\Runtime\readme.txt file (Dev-C++ uses the minGW compiler). diff --git a/Dinkey Pro 7.6.1/Samples/C/Dev-C++/Runtime/DllTest.dev b/Dinkey Pro 7.6.1/Samples/C/Dev-C++/Runtime/DllTest.dev new file mode 100644 index 0000000..a6d0c6f --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Dev-C++/Runtime/DllTest.dev @@ -0,0 +1,59 @@ +[Project] +FileName=DllTest.dev +Name=DllTest +UnitCount=1 +Type=1 +Ver=1 +ObjFiles= +Includes= +Libs= +PrivateResource= +ResourceIncludes= +MakeIncludes= +Compiler= +CppCompiler= +Linker=../../import_libs/libdpwin32.a_@@_ +IsCpp=0 +Icon= +ExeOutput= +ObjectOutput= +OverrideOutput=0 +OverrideOutputName=DllTest.exe +HostApplication= +Folders= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000000000000000000 + +[Unit1] +FileName=..\..\apitest.c +CompileCpp=0 +Folder=DllTest +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + diff --git a/Dinkey Pro 7.6.1/Samples/C/Dev-C++/Runtime/ObjTest.dev b/Dinkey Pro 7.6.1/Samples/C/Dev-C++/Runtime/ObjTest.dev new file mode 100644 index 0000000..9866aec --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Dev-C++/Runtime/ObjTest.dev @@ -0,0 +1,59 @@ +[Project] +FileName=ObjTest.dev +Name=ObjTest +UnitCount=1 +Type=1 +Ver=1 +ObjFiles= +Includes= +Libs= +PrivateResource= +ResourceIncludes= +MakeIncludes= +Compiler= +CppCompiler= +Linker=../../object_modules/dpwin32_coff.obj_@@_ +IsCpp=0 +Icon= +ExeOutput= +ObjectOutput= +OverrideOutput=0 +OverrideOutputName=ObjTest.exe +HostApplication= +Folders= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000000000000000000 + +[Unit1] +FileName=..\..\apitest.c +CompileCpp=0 +Folder=DllTest +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + diff --git a/Dinkey Pro 7.6.1/Samples/C/Dev-C++/Runtime/README.txt b/Dinkey Pro 7.6.1/Samples/C/Dev-C++/Runtime/README.txt new file mode 100644 index 0000000..fe93c27 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Dev-C++/Runtime/README.txt @@ -0,0 +1,53 @@ +Sample code to call dpwin32_coff.obj OR dpwin32.dll using Dev C++ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written using Dev C++ 4.9.9.2 but should also work in other +versions (for olders version you may have to create the project yourself). + +The source files in the project are: + +File name Folder Description +apitest.c Samples\c main source code file for C +dris.h Samples\c contains the DRIS structure +dpwin32_coff.obj Samples\c\object_modules static object modules e.g. dpwin32_coff.obj +libdpwin32.a Samples\c\import_libs contains the function definitions for dpwin32.dll + +Note that the source paths are structured to minimise files. If you want to +move this project the references to these files will probably be no longer valid. + +The ObjTest project links to the static runtime library module (e.g dpwin32_coff.obj) + +The DllTest project uses the dynamic runtime library (e.g. dpwin32.dll). + +The sample code contains 10 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. + +Note - if you are link the static module dpwin32_coff.obj then you should protect your program. +If you are linking to dpwin32.dll then you need to protect dpwin32.dll and *not* your program. +Because your program is linked to the DLL it is protected. The protected DLL will need to be +in the same folder as your compiled program for it to run correctly. + +Note - once your program (or dpwin32.dll) is protected you will not be able to debug +your program - after our API has been called. Our strong anti-debug code will cause +the debugger to throw an exception. If you do want to debug your code then you can +use our debug module: dpwin32_coff_debug.obj (or dpwin32debug.dll), but these should not be +used for release. See readme.txt in samples\c for restrictions concerning the debug module. + +Note - if you are interested in creating the libdpwin32.a import library yourself then +read the notes in the MinGW\Runtime\readme.txt file (Dev-C++ uses the minGW compiler). + diff --git a/Dinkey Pro 7.6.1/Samples/C/MinGW/DinkeyChange/README.txt b/Dinkey Pro 7.6.1/Samples/C/MinGW/DinkeyChange/README.txt new file mode 100644 index 0000000..4d6be62 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/MinGW/DinkeyChange/README.txt @@ -0,0 +1,40 @@ +ChangeTest - sample code to call DinkeyChange in MinGW +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tested using minGW 3.4.2 and 4.8.1 and minGW-w64 4.8.1 + +The source files in the project are: + +File name Folder Description +changetest.c Samples\c main source code file for C +changetest.h Samples\c contains some useful constants +libDinkeyChange.a Samples\c\import_libs contains the function definitions for DinkeyChange.dll +libDinkeyChangeDebug.a Samples\c\import_libs contains the function definitions for DinkeyChangeDebug.dll +libDinkeyChange64.a Samples\c\import_libs contains the function definitions for DinkeyChange64.dll +libDinkeyChangeDebug64.a Samples\c\import_libs contains the function definitions for DinkeyChangeDebug64.dll +changetest.rc Samples\c\Visual Studio 5\DinkeyChange resource for main dialog + +(NB for compiling you will also need to compile the resources) + +To compile for 32-bit: +gcc -m32 ..\..\changetest.c -L..\..\import_libs -lDinkeyChange -o ChangeTest.exe + +To compile for 64-bit: +gcc -m64 ..\..\changetest.c -L..\..\import_libs -lDinkeyChange64 -o ChangeTest64.exe + +Note that the source paths are structured to minimise files. If you want to +move this project the references to these files will probably be no longer valid. + +The sample code contains 7 functions. Just use which ever functions are most +appropriate and customise in your own way. The sample code is just a guide. +As none of the parameters are sensitive then there is no need to implement +strong security in calling DinkeyChange. + +Note - you will not be able to debug your program after DinkeyChange has been called. +Our strong anti-debug code will cause the debugger to throw an exception. However, +if you do need to debug your code you can use our debug module for DinkeyChange: +DinkeyChangeDebug.dll. So, you can use DinkeyChange.dll for your release build +and DinkeyChangeDebug.dll for your debug build. + +Note - if you are interested in creating the libDinkeyChange.a import library yourself +then read the notes in the MinGW\Runtime\readme.txt file. diff --git a/Dinkey Pro 7.6.1/Samples/C/MinGW/Runtime/README.txt b/Dinkey Pro 7.6.1/Samples/C/MinGW/Runtime/README.txt new file mode 100644 index 0000000..45b8f48 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/MinGW/Runtime/README.txt @@ -0,0 +1,84 @@ +Sample code to call static or dynamic runtime modules using MinGW +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tested using minGW 3.4.2 and 4.8.1 and minGW-w64 4.8.1 + +The source files you need are: + +File name Folder Description +apitest.c Samples\c main source code file for C +dris.h Samples\c contains the DRIS structure +dpwin32_coff.obj Samples\c\object_modules static object modules e.g. dpwin32_coff.obj, dpwin64.obj +libdpwin32.a Samples\c\import_libs contains the function definitions for dpwin32.dll + +To link the static runtime module compile like this: + +32-bit: +gcc -m32 ..\..\apitest.c ..\..\object_modules\dpwin32_coff.obj -o ObjTest.exe + +64-bit: +gcc -m64 ..\..\apitest.c ..\..\object_modules\dpwin64.obj -o ObjTest64.exe +(please ignore the warning about uuid.lib) + +Alternatively to link with the dynamic runtime module compile like this: + +32-bit: +gcc -m32 ..\..\apitest.c -L..\..\import_libs -ldpwin32 -o DllTest.exe + +64-bit: +gcc -m64 ..\..\apitest.c -L..\..\import_libs -ldpwin64 -o DllTest64.exe + +The sample code contains 10 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. + +Note - if you are link the static module dpwin32_coff.obj then you should protect your program. +If you are linking to dpwin32.dll then you need to protect dpwin32.dll and *not* your program. +Because your program is linked to the DLL it is protected. The protected DLL will need to be +in the same folder as your compiled program for it to run correctly. + +Note - once your program (or dpwin32.dll) is protected you will not be able to debug +your program - after our API has been called. Our strong anti-debug code will cause +the debugger to throw an exception. If you do want to debug your code then you can +use our debug module: dpwin32_coff_debug.obj (or dpwin32debug.dll), but these should not be +used for release. See readme.txt in samples\c for restrictions concerning the debug module. + +Creating your own import library +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +In order for MinGW to call functions in dpwin32.dll you need to link the import library +libdpwin32.a. We have created these for you, but if for some reason you need to create it +yourself then you should do the following: + +1) Create a dpwin32.def file with the following format: + LIBRARY dpwin32.dll + EXPORTS + + + + where etc.. are the function names that the linker complains about when you + don't link with the import library. e.g. for dpwin32.dll you just need two functions: + DDProtCheck@8 + DDGetNetUserList@20 + + (you do not need to specify the @n part for 64-bit modules) + +2) Now use dlltool to create the import library: + dlltool --input-def dpwin32.def --output-lib libdpwin32.a -k + + Note: for our DLLs you need to use the -k option otherwise you will get an "file format + not recognised error" when you link the import library. + diff --git a/Dinkey Pro 7.6.1/Samples/C/Qt Creator/README.txt b/Dinkey Pro 7.6.1/Samples/C/Qt Creator/README.txt new file mode 100644 index 0000000..e71d1b8 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Qt Creator/README.txt @@ -0,0 +1,18 @@ +Using the Runtime Protection Check API in Qt Creator Projects +============================================================= + +The runtime protection API sample code (apitest.c and dris.h) has been tested with Qt Creator 4.10.2 on Windows, +using MinGW as the compiler and qmake as the build system. +As Qt Creator supports such a wide variety of different compilers and build systems, no project files are included in this sample code. +It is better to create your own project using your preferred toolchain, and then use 'Add Existing Files...' to add apitest.c and dris.h. + +Qt Creator may complain about the symbols BYTE and WINAPI in dris.h. +If it does, insert "#include " at the top of dris.h. + +Qt Creator projects are Unicode by default, it may complain about the use of C strings in calls to MessageBox() in apitest.c. +To solve this issue, either set your project explicitly as an ANSI project, or change all occurrences of MessageBox() to MessageBoxA(). + +You will need to add a reference to the relevant static library (OBJ file) for your compiler. +For projects that use qmake, add the following to your *.pro project file: + + LIBS += path\to\object_module.obj diff --git a/Dinkey Pro 7.6.1/Samples/C/README.txt b/Dinkey Pro 7.6.1/Samples/C/README.txt new file mode 100644 index 0000000..0dbdf57 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/README.txt @@ -0,0 +1,117 @@ +C and C++ Sample Code +===================== + +The source files in this folder are common to all C/C++ implementations: + +apitest.c examples of calling the runtime protection API, e.g. protection checks, reading/writing the dongle secure data area. +dris.h defines structures, constants and function prototypes for the runtime protection API. + +changetest.c examples of calling the DinkeyChange API. +changetest.h defines structures, constants and function prototypes for the DinkeyChange API. + +dapftest.c examples of calling the DinkeyAdd API. +dapf.h defines structures, constants and function prototypes for the DinkeyAdd API. + +drpftest.c examples of calling the DinkeyRemote API. +drpf.h defines structures, constants and function prototypes for the DinkeyRemote API. + +In order for the projects to compile without modification we have also included the folders: + +import_libs import libraries that contain the function definitions for the dynamic API libraries (e.g. dpwin32.dll). +object_modules static API libraries: + Use dpwin32_coff.obj for Visual Studio, MinGW and other compilers that expect the COFF object module format. + Use dpwin32_omf.obj for C++ Builder and other compilers that expects an OMF object module. + There is only one 64-bit object module because in 64-bit Windows only the COFF format exists. + +The subfolders contain projects for different IDEs and/or compilers: + +Visual Studio 2008 for all version of Visual Studio from 2008 onwards. 32-bit and 64-bit. +Visual Studio 5 for earlier versions of Visual Studio. 32-bit only. + +C++ Builder XE3 for versions of C++ Builder from XE3 onwards. +C++ Builder for versions of C++ Builder from 2007 to XE2. If you are using a version earlier than this then please read the README.txt file in that folder. + +Within the subfolders are different projects: + +The ObjTest project checks the dongle by calling the appropriate static library (object module). + +The DllTest project checks the dongle by calling the dynamic library dpwin32.dll (or dpwin64.dll for 64-bit code). + +The ChangeTest project calls the DinkeyChange API which accepts update codes generated by DinkeyRemote. + +The dapfTest project calls the DinkeyAdd API to program dongles and lock your software. + +The drpfTest project calls the DinkeyRemote API to generate remote update codes. + + +Notes concerning Debug Modules +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The debug modules are: + +dpwin32_coff_debug.obj dpwin32_omf_debug.obj dpwin64debug.obj +dpwin32debug.dll dpwin64debug.dll +DinkeyChangeDebug.dll DinkeyChange64Debug.dll + +Note - the DinkeyAdd and DinkeyRemote modules have no debug versions. + +When you use a normal runtime module (e.g. dpwin32.dll) to protect your software the anti-debug code is +so strong that if you are debugging your code after the call DDProtCheck then it will crash. If you want to +be able to debug your code then you can setup your project so that your code calls one of the debug modules +when you are producing your debug code and one of the standard runtime modules when you produce your release +code. The Runtime debug module has the following restrictions: + +1) It will not correctly start a network user (network dongles only). However, other than that the protection check + will function correctly and return success. +2) You will not be able to encrypt the DRIS. (If you do encrypt the DRIS in your release build then you should make + sure that CryptDRIS does not get called in your debug build). +3) The protection check will take slightly longer than normal. +4) The DDGetNetUserList function will return error 428 (not implemented). +5) A temporary subprocess is created which may be (falsely) detected as malicious by anti-virus programs. + +Note: the debug DinkeyChange modules have no restrictions (except for number 5 above). + + +Loading Runtime module using LoadLibrary +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you want to control when the DLL is loaded / unloaded or you want to rename dpwin32.dll +(but cannot change the import library, e.g. with Microsoft Visual Studio), +then you should use LoadLibrary / GetProcAddress to load our library instead of linking the relevant import library. +The DLL is normally placed in the same folder as the program that is calling it. +This code snippet shows how you can do this: + +#include "dris.h" + +// declare function type +typedef int (__stdcall * TypeDDProtCheck)(DRIS*, BYTE *); + +HMODULE hProtLib; +TypeDDProtCheck DDProtCheck; + +hProtLib = LoadLibrary("dpwin32.dll"); // if you have renamed the dll then you should use the new name. + +DDProtCheck = (TypeDDProtCheck)GetProcAddress(hProtLib, "DDProtCheck"); + +// use function as normal (see sample code) + +// free handle when you no longer need to call the DLL (typically the end of your program) +FreeLibrary(hProtLib); + + +Unresolved External Symbol Errors +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you using a static runtime module (e.g. dpwin64.obj) then in rare cases you can receive errors like this: +dpwin64.obj : error LNK2019: unresolved external symbol __imp_SetSecurityDescriptorDacl referenced in function +fatal error LNK1120: 6 unresolved externals + +To fix this problem you need to make sure the following libraries are included in your project: +User32.lib +Advapi32.lib +ws2_32.lib + +Normally these libraries are included as standard by your C/C++ IDE (e.g Visual Studio). However, in rare cases, +such as using the Qt platform or if you are using a C/C++ compiler/linker on the command line, these +libraries may not be included by default so you have include them yourself. + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyAdd/README.txt b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyAdd/README.txt new file mode 100644 index 0000000..174c5e0 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyAdd/README.txt @@ -0,0 +1,31 @@ +dapfTest - Sample code for calling the DinkeyAdd Module in C +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 2008 but will work in more recent +versions of Visual Studio (they will upgrade the Project to the latest version). + +The main source files in the project are: + +dapf.h - the source file contains declarations of our API. + +dapftest.c - this is the sample code giving an example on how you can call our API. + It contains 5 functions. Just use which ever functions are most appropriate + and customise in your own way. + +Note that the source paths of this project are structured to minimise files. If you +want to move this project the references to these files will probably be no longer valid. + +The solutions have been modified to link in the correct library file (DinkeyAdd32.lib, +DinkeyAdd64.lib) depending on whether the output is 32-bit or 64-bit. They have also +been modified to assume Unicode characters are not the default (this sample uses ascii +characters because that is what the Dinkey dongle SDK requires). + +Note - you will not be able to debug your program after the DinkeyAdd Module has been +called. Our strong anti-debug code will cause the debugger to throw an exception. +There are no debug modules for DinkeyAdd so you will have to find other ways of +debugging your code (for example taking out the call altogether). + +Note - If you are using Visual Studio 2012 or higher then you may get the linker error +"LNK2026: module unsafe for SAFESEH image". To stop this please turn off SAFESEH by +going to your project properties > Linker > Advanced and setting +"Image Has Safe Exception Handlers" to "No". diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyAdd/dapfTest.sln b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyAdd/dapfTest.sln new file mode 100644 index 0000000..b3e5a7e --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyAdd/dapfTest.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dapfTest", "dapfTest.vcproj", "{4FDBE0B2-9115-4CF3-ABCC-786CBE7DB7E0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4FDBE0B2-9115-4CF3-ABCC-786CBE7DB7E0}.Debug|Win32.ActiveCfg = Debug|Win32 + {4FDBE0B2-9115-4CF3-ABCC-786CBE7DB7E0}.Debug|Win32.Build.0 = Debug|Win32 + {4FDBE0B2-9115-4CF3-ABCC-786CBE7DB7E0}.Debug|x64.ActiveCfg = Debug|x64 + {4FDBE0B2-9115-4CF3-ABCC-786CBE7DB7E0}.Debug|x64.Build.0 = Debug|x64 + {4FDBE0B2-9115-4CF3-ABCC-786CBE7DB7E0}.Release|Win32.ActiveCfg = Release|Win32 + {4FDBE0B2-9115-4CF3-ABCC-786CBE7DB7E0}.Release|Win32.Build.0 = Release|Win32 + {4FDBE0B2-9115-4CF3-ABCC-786CBE7DB7E0}.Release|x64.ActiveCfg = Release|x64 + {4FDBE0B2-9115-4CF3-ABCC-786CBE7DB7E0}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyAdd/dapfTest.vcproj b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyAdd/dapfTest.vcproj new file mode 100644 index 0000000..290d30a --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyAdd/dapfTest.vcproj @@ -0,0 +1,351 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyChange/ChangeTest.sln b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyChange/ChangeTest.sln new file mode 100644 index 0000000..ee0ad72 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyChange/ChangeTest.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ChangeTest", "ChangeTest.vcproj", "{4DB5C093-DFF8-4EF9-92AF-73CAC5A2E0D6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4DB5C093-DFF8-4EF9-92AF-73CAC5A2E0D6}.Debug|Win32.ActiveCfg = Debug|Win32 + {4DB5C093-DFF8-4EF9-92AF-73CAC5A2E0D6}.Debug|Win32.Build.0 = Debug|Win32 + {4DB5C093-DFF8-4EF9-92AF-73CAC5A2E0D6}.Debug|x64.ActiveCfg = Debug|x64 + {4DB5C093-DFF8-4EF9-92AF-73CAC5A2E0D6}.Debug|x64.Build.0 = Debug|x64 + {4DB5C093-DFF8-4EF9-92AF-73CAC5A2E0D6}.Release|Win32.ActiveCfg = Release|Win32 + {4DB5C093-DFF8-4EF9-92AF-73CAC5A2E0D6}.Release|Win32.Build.0 = Release|Win32 + {4DB5C093-DFF8-4EF9-92AF-73CAC5A2E0D6}.Release|x64.ActiveCfg = Release|x64 + {4DB5C093-DFF8-4EF9-92AF-73CAC5A2E0D6}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyChange/ChangeTest.vcproj b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyChange/ChangeTest.vcproj new file mode 100644 index 0000000..317d61e --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyChange/ChangeTest.vcproj @@ -0,0 +1,346 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyChange/README.txt b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyChange/README.txt new file mode 100644 index 0000000..acac4d0 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyChange/README.txt @@ -0,0 +1,35 @@ +ChangeTest - sample code to call DinkeyChange Module in Visual Studio 2008 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 2008 but will work in more recent +versions of Visual Studio (they will upgrade the Project to the latest version). + +The main source files in the project are: + +changetest.c Samples\c main source code file for C +changetest.h Samples\c contains some useful constants + +Note that the source paths are structured to minimise files. If you want to +move this project the references to these files will probably be no longer valid. + +The solutions have been modified to link in the correct library file (DinkeyChange.lib, +DinkeyChange64.lib) depending on whether the output is 32-bit or 64-bit. They have also +been modified to assume Unicode characters are not the default (this sample uses ascii +characters because that is what the Dinkey dongle SDK requires). + +The sample code contains 7 functions. Just use which ever functions are most +appropriate and customise in your own way. The sample code is just a guide. +As none of the parameters are sensitive then there is no need to implement +strong security in calling DinkeyChange. + +Note - you will not be able to debug your program after DinkeyChange has been called. +Our strong anti-debug code will cause the debugger to throw an exception. However, +if you do need to debug your code you can use our debug module for DinkeyChange: +DinkeyChangeDebug.dll. So, you can use DinkeyChange.dll for your release build +and DinkeyChangeDebug.dll for your debug build. (64-bit versions of these files +also exist). + +Note - If you are using Visual Studio 2012 or higher then you may get the linker error +"LNK2026: module unsafe for SAFESEH image". To stop this please turn off SAFESEH by +going to your project properties > Linker > Advanced and setting +"Image Has Safe Exception Handlers" to "No". diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyRemote/README.txt b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyRemote/README.txt new file mode 100644 index 0000000..361d8c9 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyRemote/README.txt @@ -0,0 +1,31 @@ +drpfTest - Sample code for calling the DinkeyRemote Module in C +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 2008 but will work in more recent +versions of Visual Studio (they will upgrade the Project to the latest version). + +The main source files in the project are: + +drpf.h - the source file contains declarations of our API. + +drpftest.c - this is the sample code giving an example on how you can call our API. + It contains 2 functions. Just use which ever functions are most appropriate + and customise in your own way. + +Note that the source paths of this project are structured to minimise files. If you +want to move this project the references to these files will probably be no longer valid. + +The solutions have been modified to link in the correct library file (DinkeyRemote32.lib, +DinkeyRemote64.lib) depending on whether the output is 32-bit or 64-bit. They have also +been modified to assume Unicode characters are not the default (this sample uses ascii +characters because that is what the Dinkey dongle SDK requires). + +Note - you will not be able to debug your program after the DinkeyRemote Module has been +called. Our strong anti-debug code will cause the debugger to throw an exception. +There are no debug modules for DinkeyRemote so you will have to find other ways of +debugging your code (for example taking out the call altogether). + +Note - If you are using Visual Studio 2012 or higher then you may get the linker error +"LNK2026: module unsafe for SAFESEH image". To stop this please turn off SAFESEH by +going to your project properties > Linker > Advanced and setting +"Image Has Safe Exception Handlers" to "No". diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyRemote/drpfTest.sln b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyRemote/drpfTest.sln new file mode 100644 index 0000000..022bd5c --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyRemote/drpfTest.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "drpfTest", "drpfTest.vcproj", "{C56A2849-1C1D-4307-937F-D7DF9EA56CB0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C56A2849-1C1D-4307-937F-D7DF9EA56CB0}.Debug|Win32.ActiveCfg = Debug|Win32 + {C56A2849-1C1D-4307-937F-D7DF9EA56CB0}.Debug|Win32.Build.0 = Debug|Win32 + {C56A2849-1C1D-4307-937F-D7DF9EA56CB0}.Debug|x64.ActiveCfg = Debug|x64 + {C56A2849-1C1D-4307-937F-D7DF9EA56CB0}.Debug|x64.Build.0 = Debug|x64 + {C56A2849-1C1D-4307-937F-D7DF9EA56CB0}.Release|Win32.ActiveCfg = Release|Win32 + {C56A2849-1C1D-4307-937F-D7DF9EA56CB0}.Release|Win32.Build.0 = Release|Win32 + {C56A2849-1C1D-4307-937F-D7DF9EA56CB0}.Release|x64.ActiveCfg = Release|x64 + {C56A2849-1C1D-4307-937F-D7DF9EA56CB0}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyRemote/drpfTest.vcproj b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyRemote/drpfTest.vcproj new file mode 100644 index 0000000..262c126 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/DinkeyRemote/drpfTest.vcproj @@ -0,0 +1,351 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/Runtime/DllTest/DllTest.vcproj b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/Runtime/DllTest/DllTest.vcproj new file mode 100644 index 0000000..e92941d --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/Runtime/DllTest/DllTest.vcproj @@ -0,0 +1,341 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/Runtime/ObjTest/ObjTest.vcproj b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/Runtime/ObjTest/ObjTest.vcproj new file mode 100644 index 0000000..fafbb97 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/Runtime/ObjTest/ObjTest.vcproj @@ -0,0 +1,341 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/Runtime/README.txt b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/Runtime/README.txt new file mode 100644 index 0000000..e8f1cf8 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/Runtime/README.txt @@ -0,0 +1,69 @@ +Sample code to call Runtime modules in Visual Studio 2008 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 2008 but will work in more recent versions of +Visual Studio (they will upgrade the Project to the latest version). + +The source files in the project are: + +File name Folder Description +apitest.c Samples\c main source code file for C +dris.h Samples\c contains the DRIS structure +dpwin32.lib Samples\c\import_libs contains the function definitions for dpwin32.dll +dpwin64.lib Samples\c\import_libs contains the function definitions for dpwin64.dll +dpwin32_coff.obj Samples\c\object_modules static object module +dpwin64.obj Samples\c\object_modules static object module + +Note that the source paths are structured to minimise files. If you want to move this +project the references to these files will probably be no longer valid. + +The ObjTest project links to the static runtime library module (e.g dpwin32_coff.obj or dpwin64.obj) + +The DllTest project uses the dynamic runtime library (e.g. dpwin32.dll or dpwin64.obj). + +The solutions have been modified to assume Unicode characters are not the default +(this sample uses ascii characters because that is what the Dinkey dongle SDK requires). + +The DllTest solution has been modified to link in the correct library file (dpwin32.lib, dpwin64.lib) +depending on whether the output is 32-bit or 64-bit. + +The sample code contains 10 functions. You will not need to use all these functions in your +code. Just use which ever functions are most appropriate and customise in your own way. +The sample code is just a guide. You should implement the protection in a stronger way using +the techniques described in the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. + +Note - if you are link the static module dpwin32_coff.obj (dpwin64.obj) then you should protect +your program. If you are linking to dpwin32.dll (dpwin64.dll) then you need to protect dpwin32.dll +(dpwin64.dll) and *not* your program. Because your program is linked to the DLL it is protected. +The protected DLL will need to be in the same folder as your compiled program for it to run correctly. + +Note - once your program (or dpwin32.dll / dpwin64.dll) is protected you will not be able to debug +your program - after our API has been called. Our strong anti-debug code will cause the debugger +to throw an exception. If you do want to debug your code then you can use our debug module: +dpwin32_coff_debug.obj or dpwin32debug.dll (or 64-bit equivalents), but these should not be used +for release. See readme.txt in samples\c for restrictions concerning the debug module. + +Note - If you are using Visual Studio 2012 or higher then you may get the linker error +"LNK2026: module unsafe for SAFESEH image". To stop this please turn off SAFESEH by +going to your project properties > Linker > Advanced and setting +"Image Has Safe Exception Handlers" to "No". + +Important Note for Windows Store App Developers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Windows Store Apps (Metro Apps) are not compatible with Lite or Plus dongles because the restrictions +imposed by these applications. However, you can protect these Apps with network dongles (because the +restrictive access is performed by the non-Metro DinkeyServer process). If you do this you will need +to enable the "Private Networks (Client and Server)" Capability in your package manifest. diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/Runtime/Runtime.sln b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/Runtime/Runtime.sln new file mode 100644 index 0000000..a698644 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 2008/Runtime/Runtime.sln @@ -0,0 +1,50 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DllTest", "DllTest\DllTest.vcproj", "{F0F1232C-ECAB-47CB-97EB-91D0C18316FF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ObjTest", "ObjTest\ObjTest.vcproj", "{C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Debug|Any CPU.ActiveCfg = Debug|x64 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Debug|Mixed Platforms.ActiveCfg = Debug|x64 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Debug|Mixed Platforms.Build.0 = Debug|x64 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Debug|Win32.ActiveCfg = Debug|Win32 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Debug|Win32.Build.0 = Debug|Win32 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Debug|x64.ActiveCfg = Debug|x64 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Debug|x64.Build.0 = Debug|x64 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Release|Any CPU.ActiveCfg = Release|x64 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Release|Mixed Platforms.ActiveCfg = Release|x64 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Release|Mixed Platforms.Build.0 = Release|x64 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Release|Win32.ActiveCfg = Release|Win32 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Release|Win32.Build.0 = Release|Win32 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Release|x64.ActiveCfg = Release|x64 + {F0F1232C-ECAB-47CB-97EB-91D0C18316FF}.Release|x64.Build.0 = Release|x64 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Debug|Mixed Platforms.ActiveCfg = Debug|x64 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Debug|Mixed Platforms.Build.0 = Debug|x64 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Debug|Win32.ActiveCfg = Debug|Win32 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Debug|Win32.Build.0 = Debug|Win32 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Debug|x64.ActiveCfg = Debug|Win32 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Release|Any CPU.ActiveCfg = Release|Win32 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Release|Mixed Platforms.Build.0 = Release|Win32 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Release|Win32.ActiveCfg = Release|Win32 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Release|Win32.Build.0 = Release|Win32 + {C4DFF331-8ABF-4EE5-BBDC-B7873E3C1CC1}.Release|x64.ActiveCfg = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyAdd/README.txt b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyAdd/README.txt new file mode 100644 index 0000000..00968c2 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyAdd/README.txt @@ -0,0 +1,23 @@ +dapfTest - Sample code for calling the DinkeyAdd Module in C +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 5.0 but will work in more recent +versions of Visual Studio (they will upgrade the Project to the latest version). +For Visual Studio 2008 and higher please use the Visual Studio 2008 sample code. + +The main source files in the project are: + +dapf.h - the source file contains declarations of our API. + +dapftest.c - this is the sample code giving an example on how you can call our API. + It contains 5 functions. Just use which ever functions are most appropriate + and customise in your own way. + +Note that the source paths of this project are structured to minimise files. If you +want to move this project the references to these files will probably be no longer valid. + +Note - you will not be able to debug your program after the DinkeyAdd Module has been +called. Our strong anti-debug code will cause the debugger to throw an exception. +There are no debug modules for DinkeyAdd so you will have to find other ways of +debugging your code (for example taking out the call altogether). + diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyAdd/dapfTest.dsp b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyAdd/dapfTest.dsp new file mode 100644 index 0000000..f0f840f --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyAdd/dapfTest.dsp @@ -0,0 +1,100 @@ +# Microsoft Developer Studio Project File - Name="dapfTest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=dapfTest - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "dapfTest.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "dapfTest.mak" CFG="dapfTest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "dapfTest - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "dapfTest - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "dapfTest - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "dapfTest - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "dapfTest - Win32 Release" +# Name "dapfTest - Win32 Debug" +# Begin Source File + +SOURCE=..\..\dapftest.c +# End Source File +# Begin Source File + +SOURCE=.\dapftest.rc +# End Source File +# Begin Source File + +SOURCE=..\..\import_libs\DinkeyAdd32.lib +# End Source File +# End Target +# End Project diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyAdd/dapfTest.dsw b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyAdd/dapfTest.dsw new file mode 100644 index 0000000..5064319 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyAdd/dapfTest.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 5.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "dapfTest"=".\dapfTest.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyAdd/dapftest.rc b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyAdd/dapftest.rc new file mode 100644 index 0000000..7520188 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyAdd/dapftest.rc @@ -0,0 +1,117 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 252, 328 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Full path of dapf file:",IDC_STATIC,7,15,238,8 + EDITTEXT IDC_DAPF_PATH,7,25,238,14,ES_AUTOHSCROLL + PUSHBUTTON "Program Dongle",IDC_PROGRAM_DONGLE,53,56,145,14 + PUSHBUTTON "Program Dongle with Modification", + IDC_PROGRAM_DONGLE_MOD,53,84,145,14 + PUSHBUTTON "Lock Software",IDC_LOCK_SOFTWARE,53,112,145,14 + PUSHBUTTON "Encrypt Shell Data Files",IDC_ENCRYPT_SHELL_DATA_FILES, + 53,140,145,14 + GROUPBOX "Temporary Software Key",IDC_STATIC,7,170,238,82 + LTEXT "Machine ID:",IDC_STATIC,22,189,40,8 + EDITTEXT IDC_MACHINEID,91,187,132,14,ES_AUTOHSCROLL + LTEXT "Expiry Date:",IDC_STATIC,22,209,39,8 + EDITTEXT IDC_TEMP_EXP_DAY,91,208,18,14,ES_AUTOHSCROLL + LTEXT "/",IDC_STATIC,114,210,8,8 + EDITTEXT IDC_TEMP_EXP_MONTH,123,208,18,14,ES_AUTOHSCROLL + LTEXT "/",IDC_STATIC,148,210,8,8 + EDITTEXT IDC_TEMP_EXP_YEAR,158,208,28,14,ES_AUTOHSCROLL + PUSHBUTTON "Create Software Key",IDC_CREATE_TEMP_SWKEY,53,230,145,14 + GROUPBOX "Demo Software Key",IDC_STATIC,7,260,238,61 + LTEXT "Max Days:",IDC_STATIC,22,279,40,8 + EDITTEXT IDC_DEMO_MAX_DAYS,91,277,132,14,ES_AUTOHSCROLL + PUSHBUTTON "Create Demo Template",IDC_CREATE_DEMO_SWKEY,53,299,145,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_DIALOG1, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 245 + TOPMARGIN, 7 + BOTTOMMARGIN, 321 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyAdd/resource.h b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyAdd/resource.h new file mode 100644 index 0000000..1b771bc --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyAdd/resource.h @@ -0,0 +1,18 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by dapftest.rc +// +#define IDD_DIALOG1 101 +#define IDC_DAPF_PATH 1000 +#define IDC_PROGRAM_DONGLE 1001 +#define IDC_PROGRAM_DONGLE_MOD 1002 +#define IDC_LOCK_SOFTWARE 1003 +#define IDC_ENCRYPT_SHELL_DATA_FILES 1004 +#define IDC_MACHINEID 1005 +#define IDC_TEMP_EXP_DAY 1006 +#define IDC_TEMP_EXP_MONTH 1007 +#define IDC_TEMP_EXP_YEAR 1008 +#define IDC_CREATE_TEMP_SWKEY 1009 +#define IDC_DEMO_MAX_DAYS 1010 +#define IDC_CREATE_DEMO_SWKEY 1011 +#define IDC_STATIC -1 diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyChange/ChangeTest.dsp b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyChange/ChangeTest.dsp new file mode 100644 index 0000000..cd68a78 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyChange/ChangeTest.dsp @@ -0,0 +1,100 @@ +# Microsoft Developer Studio Project File - Name="ChangeTest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=ChangeTest - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ChangeTest.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ChangeTest.mak" CFG="ChangeTest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ChangeTest - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "ChangeTest - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ChangeTest - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "ChangeTest - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "ChangeTest - Win32 Release" +# Name "ChangeTest - Win32 Debug" +# Begin Source File + +SOURCE=..\..\changetest.c +# End Source File +# Begin Source File + +SOURCE=.\ChangeTest.rc +# End Source File +# Begin Source File + +SOURCE=..\..\import_libs\DinkeyChange.lib +# End Source File +# End Target +# End Project diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyChange/ChangeTest.dsw b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyChange/ChangeTest.dsw new file mode 100644 index 0000000..f02e931 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyChange/ChangeTest.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 5.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "ChangeTest"=".\ChangeTest.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyChange/ChangeTest.rc b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyChange/ChangeTest.rc new file mode 100644 index 0000000..c380995 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyChange/ChangeTest.rc @@ -0,0 +1,112 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "windows.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 215, 358 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "ChangeTest" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "Get Dongle Information...",IDC_DONGLEINFO,45,14,119,14 + LTEXT "Enter Diagnostic filename:",IDC_STATIC,7,40,201,8 + EDITTEXT IDC_DIAG_PATH,7,49,201,14,ES_AUTOHSCROLL + PUSHBUTTON "Write Diagnostics to File",IDC_GETDIAGS,45,68,119,14 + LTEXT "Enter short Update Code here:",IDC_STATIC,7,96,201,8 + EDITTEXT IDC_UPDATE_CODE_STRING,7,106,201,14,ES_AUTOHSCROLL + PUSHBUTTON "Make Changes",IDC_DO_UPDATE_CODE_STRING,69,125,68,14 + LTEXT "Enter path to Update Code file:",IDC_STATIC,7,153,201,8 + EDITTEXT IDC_UPDATE_CODE_FILE,7,163,201,14,ES_AUTOHSCROLL + PUSHBUTTON "Make Changes",IDC_DO_UPDATE_CODE_FILE,68,183,68,14 + PUSHBUTTON "Restore Dinkey FD Lite",IDC_RESTORE_FD_LITE,45,215,119,14 + PUSHBUTTON "Get Machine ID",IDC_GET_MACHINE_ID,7,245,95,14 + EDITTEXT IDC_MACHINE_ID,110,245,98,14,ES_UPPERCASE + PUSHBUTTON "Download Temporary Software Key",IDC_GET_TEMP_SWKEY,35,275,139,14 + LTEXT "Demo Software Key Product Code:",IDC_STATIC,7,305,201,8 + EDITTEXT IDC_SWKEY_PRODCODE,7,314,201,14,ES_AUTOHSCROLL | ES_UPPERCASE + PUSHBUTTON "Download Demo Software Key",IDC_GET_DEMO_SWKEY,35,333,139,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_DIALOG1, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 208 + TOPMARGIN, 7 + BOTTOMMARGIN, 347 + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""windows.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyChange/README.txt b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyChange/README.txt new file mode 100644 index 0000000..d8c6d78 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyChange/README.txt @@ -0,0 +1,29 @@ +ChangeTest - sample code to call DinkeyChange.dll in Visual Studio +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 5.0 but will work in more recent +versions of Visual Studio (they will upgrade the Project to the latest version). +For Visual Studio 2008 and higher please use the Visual Studio 2008 sample code. + +The source files in the project are: + +File name Folder Description +changetest.c Samples\c main source code file for C +changetest.h Samples\c contains some useful constants +DinkeyChange.lib Samples\c\import_libs contains the function definitions for DinkeyChange.dll +changetest.rc Samples\c\Visual Studio\DinkeyChange resource for main dialog + + +Note that the source paths are structured to minimise files. If you want to +move this project the references to these files will probably be no longer valid. + +The sample code contains 7 functions. Just use which ever functions are most +appropriate and customise in your own way. The sample code is just a guide. +As none of the parameters are sensitive then there is no need to implement +strong security in calling DinkeyChange. + +Note - you will not be able to debug your program after DinkeyChange has been called. +Our strong anti-debug code will cause the debugger to throw an exception. However, +if you do need to debug your code you can use our debug module for DinkeyChange: +DinkeyChangeDebug.dll. So, you can use DinkeyChange.dll for your release build +and DinkeyChangeDebug.dll for your debug build. diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyChange/resource.h b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyChange/resource.h new file mode 100644 index 0000000..e8fd0a7 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyChange/resource.h @@ -0,0 +1,31 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by ChangeTest.rc +// +#define IDD_DIALOG1 101 +#define IDC_DONGLEINFO 1000 +#define IDC_UPDATE_CODE_STRING 1001 +#define IDC_DO_UPDATE_CODE_STRING 1002 +#define IDC_DIAG_PATH 1003 +#define IDC_GETDIAGS 1004 +#define IDC_UPDATE_CODE_FILE 1005 +#define IDC_DO_UPDATE_CODE_FILE 1006 +#define IDC_RESTORE_FD_LITE 1007 +#define IDC_GET_MACHINE_ID 1008 +#define IDC_MACHINE_ID 1009 +#define IDC_GET_TEMP_SWKEY 1010 +#define IDC_SWKEY_PRODCODE 1011 +#define IDC_GET_DEMO_SWKEY 1012 + +#define IDC_STATIC (-1) + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1013 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyRemote/README.txt b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyRemote/README.txt new file mode 100644 index 0000000..77d562c --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyRemote/README.txt @@ -0,0 +1,23 @@ +drpfTest - Sample code for calling the DinkeyRemote Module in C +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 5 but will work in more recent +versions of Visual Studio (they will upgrade the Project to the latest version). +For Visual Studio 2008 and higher please use the Visual Studio 2008 sample code. + +The main source files in the project are: + +drpf.h - the source file contains declarations of our API. + +drpftest.c - this is the sample code giving an example on how you can call our API. + It contains 2 functions. Just use which ever functions are most appropriate + and customise in your own way. + +Note that the source paths of this project are structured to minimise files. If you +want to move this project the references to these files will probably be no longer valid. + +Note - you will not be able to debug your program after the DinkeyRemote Module has been +called. Our strong anti-debug code will cause the debugger to throw an exception. +There are no debug modules for DinkeyRemote so you will have to find other ways of +debugging your code (for example taking out the call altogether). + diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyRemote/drpfTest.dsp b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyRemote/drpfTest.dsp new file mode 100644 index 0000000..bd2d5d3 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyRemote/drpfTest.dsp @@ -0,0 +1,100 @@ +# Microsoft Developer Studio Project File - Name="drpfTest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=drpfTest - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "drpfTest.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "drpfTest.mak" CFG="drpfTest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "drpfTest - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "drpfTest - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "drpfTest - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "drpfTest - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "drpfTest - Win32 Release" +# Name "drpfTest - Win32 Debug" +# Begin Source File + +SOURCE=..\..\import_libs\DinkeyRemote32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\drpftest.c +# End Source File +# Begin Source File + +SOURCE=.\drpftest.rc +# End Source File +# End Target +# End Project diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyRemote/drpfTest.dsw b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyRemote/drpfTest.dsw new file mode 100644 index 0000000..c05dc95 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyRemote/drpfTest.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 5.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "drpfTest"=".\drpfTest.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyRemote/drpftest.rc b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyRemote/drpftest.rc new file mode 100644 index 0000000..9fc2873 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyRemote/drpftest.rc @@ -0,0 +1,100 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 343, 111 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Full path of drpf file:",IDC_STATIC,7,14,329,10 + EDITTEXT IDC_DRPF_PATH,7,26,329,14,ES_AUTOHSCROLL + PUSHBUTTON "Generate Update Code",IDC_UPDATE_CODE,90,54,164,14 + PUSHBUTTON "Generate Update Code with Modifications", + IDC_UPDATE_CODE_MOD,90,82,164,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_DIALOG1, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 336 + TOPMARGIN, 7 + BOTTOMMARGIN, 104 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyRemote/resource.h b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyRemote/resource.h new file mode 100644 index 0000000..f251426 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/DinkeyRemote/resource.h @@ -0,0 +1,20 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by drpftest.rc +// +#define IDD_DIALOG1 101 +#define IDC_DRPF_PATH 1000 +#define IDC_UPDATE_CODE 1001 +#define IDC_UPDATE_CODE_MOD 1002 +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1003 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/Runtime/DllTest.dsp b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/Runtime/DllTest.dsp new file mode 100644 index 0000000..df1bae8 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/Runtime/DllTest.dsp @@ -0,0 +1,104 @@ +# Microsoft Developer Studio Project File - Name="DllTest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=DllTest - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "DllTest.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "DllTest.mak" CFG="DllTest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "DllTest - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "DllTest - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "DllTest - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "DllTest - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "DllTest - Win32 Release" +# Name "DllTest - Win32 Debug" +# Begin Source File + +SOURCE=..\..\apitest.c +# End Source File +# Begin Source File + +SOURCE=..\..\import_libs\dpwin32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\dris.h +# End Source File +# Begin Source File + +SOURCE=.\readme.txt +# End Source File +# End Target +# End Project diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/Runtime/ObjTest.dsp b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/Runtime/ObjTest.dsp new file mode 100644 index 0000000..82da5dc --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/Runtime/ObjTest.dsp @@ -0,0 +1,96 @@ +# Microsoft Developer Studio Project File - Name="ObjTest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=ObjTest - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ObjTest.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ObjTest.mak" CFG="ObjTest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ObjTest - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "ObjTest - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ObjTest - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "ObjTest - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "ObjTest - Win32 Release" +# Name "ObjTest - Win32 Debug" +# Begin Source File + +SOURCE=..\..\apitest.c +# End Source File +# Begin Source File + +SOURCE=..\..\object_modules\dpwin32_coff.obj +# End Source File +# End Target +# End Project diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/Runtime/README.txt b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/Runtime/README.txt new file mode 100644 index 0000000..477b64a --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/Runtime/README.txt @@ -0,0 +1,50 @@ +Sample code to call Runtime Modules in Visual Studio +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 5.0 but will work in more recent +versions of Visual Studio (they will upgrade the Project to the latest version). +For Visual Studio 2008 and higher please use the Visual Studio 2008 sample code. + +The source files in the project are: + +File name Folder Description +apitest.c Samples\c main source code file for C +dris.h Samples\c contains the DRIS structure +dpwin32_coff.obj Samples\c\object_modules static object modules +dpwin32.lib Samples\c\import_libs contains the function definitions for dpwin32.dll + +Note that the source paths are structured to minimise files. If you want to +move this project the references to these files will probably be no longer valid. + +The ObjTest project links to the static runtime library module (e.g dpwin32_coff.obj) + +The DllTest project uses the dynamic runtime library (e.g. dpwin32.dll). + +The sample code contains 10 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. + +Note - if you are link the static module dpwin32_coff.obj then you should protect your program. +If you are linking to dpwin32.dll then you need to protect dpwin32.dll and *not* your program. +Because your program is linked to the DLL it is protected. The protected DLL will need to be +in the same folder as your compiled program for it to run correctly. + +Note - once your program (or dpwin32.dll) is protected you will not be able to debug +your program - after our API has been called. Our strong anti-debug code will cause +the debugger to throw an exception. If you do want to debug your code then you can +use our debug module: dpwin32_coff_debug.obj (or dpwin32debug.dll), but these should not be +used for release. See readme.txt in samples\c for restrictions concerning the debug module. diff --git a/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/Runtime/Runtime.dsw b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/Runtime/Runtime.dsw new file mode 100644 index 0000000..22ef930 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/Visual Studio 5/Runtime/Runtime.dsw @@ -0,0 +1,41 @@ +Microsoft Developer Studio Workspace File, Format Version 5.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "DllTest"=".\DllTest.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "ObjTest"=".\ObjTest.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Dinkey Pro 7.6.1/Samples/C/apitest.c b/Dinkey Pro 7.6.1/Samples/C/apitest.c new file mode 100644 index 0000000..f525abb --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/apitest.c @@ -0,0 +1,823 @@ +// !! We strongly recommend that you read the "readme.txt" file for this sample. +// !! It contains important instructions on how to use the sample code + +#include // for windows programs +#include // for sprintf +#include // for memset +#include "dris.h" // for DRIS definition + +#define MY_SDSN 10101 // !!!! change this value to be the value of your SDSN (demo = 10101) +#define MY_PRODCODE "DEMO" // !!!! change this value to match the Product Code in the dongle + +#ifdef _MSC_VER + #pragma warning(disable:4996) // to disable warnings about sprintf etc... means we can use the same source for all compilers +#endif + +/* The sample code contains 11 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +If you are using Dinkey Lite then you can only use 4 functions: +ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc +*/ + +// this file contains 10 protection-check functions. +int ProtCheck(void); // a standard protection check +int ProtCheckWithAlg(void); // a protection check & executing an Algorithm +int WriteBytes(void); // a protection check & write data to the dongle +int ReadBytes(void); // a protection check & read data from the dongle +int EncryptUserData(void); // a protection check & encrypting data and then decrypting the data +// these functions are the same as the functions listed above but encrypting all parameters passed to our API +int ProtCheckEnc(void); // a standard protection check +int ProtCheckWithAlgEnc(void); // a protection check & executing an Algorithm +int WriteBytesEnc(void); // a protection check & write data to the dongle +int ReadBytesEnc(void); // a protection check & read data from the dongle +int EncryptUserDataEnc(void); // a protection check & encrypting data and then decrypting the data +// this function displays the current network users +int DisplayNetUsers(DRIS *dris); + +// useful routines that are called by our functions - implemented at the end of this file +void random_set(void *buffer, int length); +void DisplayError(int ret_code, int extended_error); + +char g_szAppName[] = "test program"; + +// *************************** WinMain *************************************** + +int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdParam, int nCmdShow) { + // call the function(s) of your choice here + // by default I have chosen a standard protection check + ProtCheck(); + return 0; +} + + +// ************************* 10 protection check functions ********************************** + +// ************************** ProtCheck *************************************** +int ProtCheck(void) { + DRIS dris; + int ret_code; + + // set the DRIS to have random values + random_set(&dris, sizeof(DRIS)); + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = PROTECTION_CHECK; // standard protection check + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + ret_code = DDProtCheck(&dris, NULL); + + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + // later in your code you can check other values in the DRIS... + + if (dris.sdsn != MY_SDSN) { + MessageBox(NULL, "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", NULL, MB_OK); + return -1; + } + + if (strcmp(dris.prodcode, MY_PRODCODE) != 0) { + MessageBox(NULL, "Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", NULL, MB_OK); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) { + MessageBox(NULL, "Dinkey Dongle protection error", NULL, MB_OK); + return -1; + } + + MessageBox(NULL, "It worked", g_szAppName, MB_OK); + + // if you are using a network dongle and you want to list the network users then use this function: +// DisplayNetUsers(&dris); + + return 0; +} + +// ************************** ProtCheckWithAlg ****************************** + +// !!!! You should replace this function with the one generated by the +// "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) +// or from DinkeyLook if you are using a Dinkey Lite dongle. +int MyAlgorithm(int a, int b, int c, int d, int e, int f, int g, int h) { + return a + b + c + d + e + f + g + h; +} + +// NB for this to work you must program at least "user algorithm" into the dongle +// NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +// sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +// code from DinkeyLook +int ProtCheckWithAlg(void) { + DRIS dris; + int ret_code; + + // set the DRIS to have random values + random_set(&dris, sizeof(DRIS)); + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = EXECUTE_ALGORITHM; // standard protection check & execute algorithm + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number = 1; // execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + // you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.var_a = 1; // sample values + dris.var_b = 2; + dris.var_c = 3; + dris.var_d = 4; + dris.var_e = 5; + dris.var_f = 6; + dris.var_g = 7; + dris.var_h = 8; + + ret_code = DDProtCheck(&dris, NULL); + + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + // later in your code you can check other values in the DRIS... + + if (dris.sdsn != MY_SDSN) { + MessageBox(NULL, "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", NULL, MB_OK); + return -1; + } + + // ...later on in your program you can check the return code again + if (dris.ret_code != 0) { + MessageBox(NULL, "Dinkey Dongle protection error", NULL, MB_OK); + return -1; + } + + // if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + // !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) != dris.alg_answer) { + MessageBox(NULL, "Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine", NULL, MB_OK); + return -1; + } + + MessageBox(NULL, "It worked", g_szAppName, MB_OK); + return 0; +} + +// ************************** WriteBytes ****************************** +// This writes the Data "Hello, World" to the dongle data area at offset 7 +// In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +int WriteBytes(void) { + DRIS dris; + char szDataToWrite[] = "Hello, World!"; + int ret_code; + + // set the DRIS to have random values + random_set(&dris, sizeof(DRIS)); + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = WRITE_DATA_AREA; // standard protection check and write data + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset = 7; + dris.rw_length = sizeof(szDataToWrite); + dris.rw_data_ptr = szDataToWrite; + + ret_code = DDProtCheck(&dris, NULL); + + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + // ...later in your code you can check other values in the DRIS... + + if (dris.sdsn != MY_SDSN) { + MessageBox(NULL, "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", NULL, MB_OK); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) { + MessageBox(NULL, "Dinkey Dongle protection error", NULL, MB_OK); + return -1; + } + + MessageBox(NULL, "It worked", g_szAppName, MB_OK); + return 0; +} + + +// ************************ ReadBytes ************************************ +// This reads 14 bytes of data from offset 7 in the dongle data area +// In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +// In order for the data to be displayed properly by this routine it will need to be text data +int ReadBytes(void) { + DRIS dris; + char szDataRead[14], szBuffer[200]; + int ret_code; + + // set the DRIS to have random values + random_set(&dris, sizeof(DRIS)); + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = READ_DATA_AREA; // standard protection check & read data + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset = 7; + dris.rw_length = sizeof(szDataRead)-1; + dris.rw_data_ptr = szDataRead; + + ret_code = DDProtCheck(&dris, NULL); + + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + // ...later in your code you can check other values in the DRIS... + + if (dris.sdsn != MY_SDSN) { + MessageBox(NULL, "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", NULL, MB_OK); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) { + MessageBox(NULL, "Dinkey Dongle protection error", NULL, MB_OK); + return -1; + } + + szDataRead[sizeof(szDataRead)-1] = 0; // null - terminate string so it displays OK. NB we assume that we are reading text that can be displayed + sprintf(szBuffer, "It worked! Dinkey Dongle Data area, offset 7 is: %s", szDataRead); + MessageBox(NULL, szBuffer, g_szAppName, MB_OK); + return 0; +} + + +// ************************** EncryptUserData ************************************ +// This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +// It will then do another protection check & decrypt the data +int EncryptUserData(void) { + DRIS dris; + char szBuffer[100]; + char szData[16] = "Hello, World!"; // pad message so it is multiple of 8-bytes long i.e. make array 16 bytes long (improves encryption) + int ret_code; + + // set the DRIS to have random values + random_set(&dris, sizeof(DRIS)); + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = ENCRYPT_USER_DATA; // standard protection check & encrypt user data + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num = 1; + dris.rw_length = sizeof(szData); + dris.rw_data_ptr = szData; + + ret_code = DDProtCheck(&dris, NULL); + + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + // ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + // Now decrypt the same data to get the original values + random_set(&dris, sizeof(DRIS)); + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = DECRYPT_USER_DATA; // standard protection check & decrypt user data + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num = 1; + dris.rw_length = sizeof(szData); + dris.rw_data_ptr = szData; + + ret_code = DDProtCheck(&dris, NULL); + + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + // ...later in your code you can check other values in the DRIS... + + if (dris.sdsn != MY_SDSN) { + MessageBox(NULL, "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", NULL, MB_OK); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) { + MessageBox(NULL, "Dinkey Dongle protection error", NULL, MB_OK); + return -1; + } + + sprintf(szBuffer, "It worked. Data decrypted is: %s", szData); + MessageBox(NULL, szBuffer, g_szAppName, MB_OK); + return 0; +} + + +// !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! +// In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" +// in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm +// but the code can be modified easily to use the 3 encryption parameters. + +// !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm +int MyRWAlgorithm(int a, int b, int c, int d, int e, int f, int g, int h) { + return a ^ b ^ c ^ d ^ e ^ f; +} + +// !!!! please overwrite this function with the one generated by DinkeyAdd +void CryptDRIS(DRIS *dris, unsigned int seed1, unsigned int seed2) { + int i, j, k; + unsigned char bigseed[256], S[256]; + unsigned char temp, t; + + for (i=0; i<256; i+=8) { + memcpy(bigseed+i, &seed1, 4); + memcpy(bigseed+i+4, &seed2, 4); + } + for (i=0; i<256; i++) + S[i] = i; + for (i=0, j=0; i<256; i++) { + j = (j + S[i] + bigseed[i] + 123) % 256; + temp = S[i]; + S[i] = S[j]; + S[j] = temp; + } + for (i=0, j=0, k=16; k<(int)sizeof(DRIS); k++) { + i = (i + 1) % 256; + j = (j + S[i] + 212) % 256; + temp = S[i]; + S[i] = S[j]; + S[j] = temp; + t = (S[i] + S[j] + 97) % 256; + ((unsigned char *)dris)[k] ^= S[t]; + } + return; +} + +// !!!! please overwrite this function with the one generated by DinkeyAdd +void CryptApiData(unsigned char *data, int length, unsigned int seed1, unsigned int seed2, int alg_answer) { + int i, j, k; + unsigned char bigseed[256], S[256]; + unsigned char temp, t; + + for (i=0; i<256; i+=8) { + memcpy(bigseed+i, &seed1, 4); + memcpy(bigseed+i+4, &seed2, 4); + } + for (i=0; i<256; i++) + S[i] = i; + for (i=0, j=0; i<256; i++) { + j = (j + S[i] + bigseed[i] + (alg_answer & 0xFF)) % 256; + temp = S[i]; + S[i] = S[j]; + S[j] = temp; + } + for (i=0, j=0, k=0; k> 8) & 0xFF)) % 256; + temp = S[i]; + S[i] = S[j]; + S[j] = temp; + t = (S[i] + S[j] + ((alg_answer >> 16) & 0xFF)) % 256; + data[k] ^= S[t]; + } + return; +} + +// **************************** ProtCheckEnc *************************** +// We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +// NB if you are using the debug module then do not call CryptDRIS as DRIS encryption is not supported. See notes in C readme.txt +int ProtCheckEnc(void) { + DRIS dris; + int ret_code; + + // set the DRIS to have random values + random_set(&dris, sizeof(DRIS)); // NB this also fills seed1, seed2 with random values + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = PROTECTION_CHECK; // standard protection check + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + CryptDRIS(&dris, dris.seed1, dris.seed2); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL); + + CryptDRIS(&dris, dris.seed1, dris.seed2); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + // later in your code you can check other values in the DRIS... + + if (dris.sdsn != MY_SDSN) { + MessageBox(NULL, "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", NULL, MB_OK); + return -1; + } + + if (strcmp(dris.prodcode, MY_PRODCODE) != 0) { + MessageBox(NULL, "Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", NULL, MB_OK); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) { + MessageBox(NULL, "Dinkey Dongle protection error", NULL, MB_OK); + return -1; + } + + MessageBox(NULL, "It worked", g_szAppName, MB_OK); + return 0; +} + +// ************************* ProtCheckWithAlgEnc ***************************** +// NB for this to work you must program at least "user algorithm" into the dongle +// NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +// sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample code from DinkeyLook. +// We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +int ProtCheckWithAlgEnc(void) { + DRIS dris; + int ret_code; + + // set the DRIS to have random values + random_set(&dris, sizeof(DRIS)); // NB this also fills seed1, seed2 with random values + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = EXECUTE_ALGORITHM; // standard protection check & execute algorithm + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number = 1; // execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + // you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.var_a = 1; // sample values + dris.var_b = 2; + dris.var_c = 3; + dris.var_d = 4; + dris.var_e = 5; + dris.var_f = 6; + dris.var_g = 7; + dris.var_h = 8; + + CryptDRIS(&dris, dris.seed1, dris.seed2); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL); + + CryptDRIS(&dris, dris.seed1, dris.seed2); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + // later in your code you can check other values in the DRIS... + + if (dris.sdsn != MY_SDSN) { + MessageBox(NULL, "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", NULL, MB_OK); + return -1; + } + + // ...later on in your program you can check the return code again + if (dris.ret_code != 0) { + MessageBox(NULL, "Dinkey Dongle protection error", NULL, MB_OK); + return -1; + } + + // if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + // !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) != dris.alg_answer) { + MessageBox(NULL, "Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine", NULL, MB_OK); + return -1; + } + + MessageBox(NULL, "It worked", g_szAppName, MB_OK); + return 0; +} + +// **************************** WriteBytesEnc ******************************** +// This writes the Data "Hello, World" to the dongle data area at offset 7 +// In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +// We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +int WriteBytesEnc(void) { + DRIS dris; + char szDataToWrite[] = "Hello, World!"; + int ret_code, alg_ans; + + // set the DRIS to have random values + random_set(&dris, sizeof(DRIS)); // NB this also fills seed1, seed2, var_a...var_h with random values + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = WRITE_DATA_AREA; // standard protection check & write data + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset = 7; + dris.rw_length = sizeof(szDataToWrite); + dris.rw_data_ptr = szDataToWrite; + + // calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + // encrypt data we want to write. + CryptApiData((BYTE *)szDataToWrite, sizeof(szDataToWrite), dris.seed1, dris.seed2, alg_ans); + + CryptDRIS(&dris, dris.seed1, dris.seed2); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL); + + CryptDRIS(&dris, dris.seed1, dris.seed2); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + // ...later in your code you can check other values in the DRIS... + + if (dris.sdsn != MY_SDSN) { + MessageBox(NULL, "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", NULL, MB_OK); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) { + MessageBox(NULL, "Dinkey Dongle protection error", NULL, MB_OK); + return -1; + } + + MessageBox(NULL, "It worked", g_szAppName, MB_OK); + return 0; +} + +// **************************** ReadBytesEnc ********************************* +// This reads 14 bytes of data from offset 7 in the dongle data area +// In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +// In order for the data to be displayed properly by this routine it will need to be text data +// We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +int ReadBytesEnc(void) { + DRIS dris; + char szDataRead[14], szBuffer[200]; + int ret_code, alg_ans; + + // set the DRIS to have random values + random_set(&dris, sizeof(DRIS)); // NB this also fills seed1, seed2, var_a...var_h with random values + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = READ_DATA_AREA; // standard protection check & read data + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset = 7; + dris.rw_length = sizeof(szDataRead)-1; + dris.rw_data_ptr = szDataRead; + + // calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + CryptDRIS(&dris, dris.seed1, dris.seed2); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL); + + CryptDRIS(&dris, dris.seed1, dris.seed2); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + // ...later in your code you can check other values in the DRIS... + + if (dris.sdsn != MY_SDSN) { + MessageBox(NULL, "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", NULL, MB_OK); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) { + MessageBox(NULL, "Dinkey Dongle protection error", NULL, MB_OK); + return -1; + } + + // decrypt data that was read. + CryptApiData((BYTE *)szDataRead, sizeof(szDataRead)-1, dris.seed1, dris.seed2, alg_ans); + + szDataRead[sizeof(szDataRead)-1] = 0; // null - terminate string so it displays OK. NB we assume that we are reading text that can be displayed + sprintf(szBuffer, "It worked! Dinkey Dongle Data area, offset 7 is: %s", szDataRead); + MessageBox(NULL, szBuffer, g_szAppName, MB_OK); + return 0; +} + +// ************************* EncryptUserDataEnc ****************************** +// This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +// It will then do another protection & decrypt the data +// We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +int EncryptUserDataEnc(void) { + DRIS dris; + char szBuffer[100]; + char szData[16] = "Hello, World!"; // pad message so it is multiple of 8-bytes long i.e. make array 16 bytes long (improves encryption) + int ret_code, alg_ans; + + // set the DRIS to have random values + random_set(&dris, sizeof(DRIS)); + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = ENCRYPT_USER_DATA; // standard protection check & encrypt user data + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num = 1; + dris.rw_length = sizeof(szData); + dris.rw_data_ptr = szData; + + // calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + // encrypt data we want to pass. + CryptApiData((BYTE *)szData, sizeof(szData), dris.seed1, dris.seed2, alg_ans); + + CryptDRIS(&dris, dris.seed1, dris.seed2); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL); + + CryptDRIS(&dris, dris.seed1, dris.seed2); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + // ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + // Now decrypt the same data to get the original values + random_set(&dris, sizeof(DRIS)); + // then set the values we want to use + memcpy(dris.header, "DRIS", 4); + dris.size = sizeof(DRIS); + dris.function = DECRYPT_USER_DATA; // standard protection check & decrypt user data + dris.flags = 0; // no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num = 1; + dris.rw_length = sizeof(szData); + dris.rw_data_ptr = szData; + + CryptDRIS(&dris, dris.seed1, dris.seed2); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL); + + CryptDRIS(&dris, dris.seed1, dris.seed2); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + // ...later in your code you can check other values in the DRIS... + if (ret_code != 0) { + DisplayError(ret_code, dris.ext_err); // display messages for any errors that have occurred + return ret_code; + } + + if (dris.sdsn != MY_SDSN) { + MessageBox(NULL, "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", NULL, MB_OK); + return -1; + } + + // later on in your program you can check the return code again + if (dris.ret_code != 0) { + MessageBox(NULL, "Dinkey Dongle protection error", NULL, MB_OK); + return -1; + } + + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + // decrypt data that was passed to us by the API + CryptApiData((BYTE *)szData, sizeof(szData), dris.seed1, dris.seed2, alg_ans); + + sprintf(szBuffer, "It worked. Data decrypted is: %s", szData); + MessageBox(NULL, szBuffer, g_szAppName, MB_OK); + return 0; +} + +// ********************* DisplayNetUsers *********************** +// This function displays the current network users (for DinkeyNet only). +// The DDProtCheck function must be called before this function is called. +// (Normally you would use DinkeyServer to view the network users but this enables you to do it from the client if you want) + +char net_user_display_msg[] = "%d. licence: %s, user: %s, computer: %s, ipaddress: %s\n"; +#define MAX_MESSAGE_SIZE (sizeof(NU_INFO) + sizeof(net_user_display_msg)) + +// !!!! NB You should check for errors when dynamic allocating memory +int DisplayNetUsers(DRIS *dris) { + int ret_code, extended_error, max_net_users, num_net_users, i; + char szBuffer[MAX_MESSAGE_SIZE]; + char *szMsg; + NU_INFO *nu_info; + + if (dris->net_users == -1) + max_net_users = 100; // if unlimited network users are allowed then display up to 100 users (for example) + else + max_net_users = dris->net_users; + + if (max_net_users == 0) // no network users are allowed, so nothing to do! + return 0; + + if (dris->model < 3) { + MessageBox(NULL, "A network dongle has not been detected. Therefore you cannot display the network users.", "Net Users", MB_OK); + return -1; + } + + // allocate memory for array of network user information structures and also to display the message to users + nu_info = (NU_INFO *)malloc(sizeof(NU_INFO) * max_net_users); + szMsg = (char *)malloc(MAX_MESSAGE_SIZE * max_net_users); + + // get network user information + ret_code = DDGetNetUserList(NULL, &num_net_users, nu_info, max_net_users, &extended_error); + + if (ret_code != 0) { + sprintf(szMsg, "Error %d/%d finding network user information.", ret_code, extended_error); + MessageBox(NULL, szMsg, "Net Users", MB_OK); + } + else { + sprintf(szMsg, "number of net users: %d\n", num_net_users); + for (i=0; i +#include + +#include "Visual Studio 5\DinkeyChange\resource.h" +#include "ChangeTest.h" + +#ifdef _MSC_VER + #pragma warning(disable:4996) // to disable warnings about sprintf etc... means we can use the same source for all compilers +#endif + +char g_szAppName[] = "ChangeTest"; +void DisplayError(int ret_code, int extended_error); + + +// routine for main dialog box +BOOL CALLBACK MainDlgProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { + int ret_code, i, num_found, confirmation_code, extended_error; + char szType[4], szModel[5]; + char szDisplayMsg[12800], szBuffer[257], szProdCode[9]; + // these are the arrays that are filled-in by DCGetInfo + int type[MAX_USB_DEVICES]; + int model[MAX_USB_DEVICES]; + char prodcode[MAX_USB_DEVICES][MAX_PRODCODE_LEN]; + unsigned int dongle_number[MAX_USB_DEVICES]; + int update_number[MAX_USB_DEVICES]; + unsigned int machineID; + + switch (message) + { + case WM_INITDIALOG: + // nothing to do + break; + + case WM_COMMAND: + // *** Get Dongle Information button clicked *** + if (LOWORD(wParam) == IDC_DONGLEINFO && HIWORD(wParam) == BN_CLICKED) { + + // find dongle information for all dongle types, Plus & Net models, for all product codes + // NB In practice you will probably want to set the prodcode_mask to the value of your product code + ret_code = DCGetInfo(TYPE_MASK_ALL, MODEL_MASK_DEFAULT, NULL, MAX_USB_DEVICES, &num_found, type, model, prodcode, dongle_number, update_number); + + // check error code and display error if an error occurs + if (ret_code == 401) { + MessageBox(hwnd, "No dongles detected matching the search criteria specified", g_szAppName, MB_OK); + return 0; + } + else if (ret_code != 0) { + sprintf(szDisplayMsg, "Error %d getting dongle information", ret_code); + MessageBox(hwnd, szDisplayMsg, g_szAppName, MB_OK); + return 0; + } + + // display info from dongle(s) detected + szDisplayMsg[0] = 0; // null string + for (i=0; i +#include + +#include "Visual Studio 5\DinkeyAdd\resource.h" +#include "dapf.h" + +#ifdef _MSC_VER + #pragma warning(disable:4996) // to disable warnings about sprintf etc... means we can use the same source for all compilers +#endif + + +char g_szAppName[] = "dapfTest"; + +void DisplayLastMessage(void); // gets & displays the message from the DinkeyAdd Module + + +// load a DAPF file from disk and program the dongle as specified by the DAPF file +int DoProgramDongle(char *szFileDAPF) { + DAPF_HANDLE dapfHandle; + int err_code; + unsigned int dongle_number; + + // load DAPF from File into memory + dapfHandle = LoadDAPFFromFile(szFileDAPF, &err_code); + if (dapfHandle == NULL) { + DisplayLastMessage(); + return err_code; + } + + // program dongle as specified by the DAPF file + err_code = AddProtection(dapfHandle, ACTION_PROGRAM_DONGLE, 0, 0, &dongle_number); + + // Unload DAPF from memory + UnloadDAPF(&dapfHandle); + + // display message (error or success) + DisplayLastMessage(); + return err_code; +} + + +// load a DAPF file from disk, modify it in memory and then program the dongle +int DoProgramDongleWithMod(char *szFileDAPF) { + DAPF_HANDLE dapfHandle; + int dummy1, dummy2, err_code; + unsigned int dongle_number; + DINKEYINFO DinkeyInfo; + LICENCEINFO LicenceInfo[MAX_LICENCES]; + FILEINFO FileInfo[10]; + ALGORITHM Algorithms[MAX_USER_ALGS]; + DATAFILEENC DataFileEnc[MAX_DATA_ENCS]; + + // in this case we need to read the DAPF into our structures, so that the DAPF values can be modified + err_code = ReadDAPFEx(szFileDAPF, &DinkeyInfo, (LICENCEINFO *)&LicenceInfo, (FILEINFO *)&FileInfo, (ALGORITHM *)&Algorithms, (DATAFILEENC *)&DataFileEnc, &dummy1, &dummy2); + if (err_code != 0) { + DisplayLastMessage(); + return err_code; + } + + // patch new values + LicenceInfo[0].Features = 12345; + LicenceInfo[0].Execs = 100; + strcpy(LicenceInfo[0].LicenceName, "fred"); + + // get DAPF handle + dapfHandle = LoadDAPF(&DinkeyInfo, LicenceInfo, FileInfo, Algorithms, DataFileEnc, &err_code); + if (dapfHandle == NULL) { + DisplayLastMessage(); + return err_code; + } + + // program dongle + err_code = AddProtection(dapfHandle, ACTION_PROGRAM_DONGLE, 0, 0, &dongle_number); + + // Unload DAPF from memory + UnloadDAPF(&dapfHandle); + + // display message (error or success) + DisplayLastMessage(); + return err_code; +} + + +// load a DAPF file from disk and protect the files specified +// (in practice it is better to protect the files one at a time and output messages as you go along, similar to DinkeyAdd.exe) +// In this example we specify the flag to overwrite any existing output file that might exist. +int DoLockSoftware(char *szFileDAPF) { + DAPF_HANDLE dapfHandle; + int err_code; + unsigned int dummy; + + // load DAPF from File into memory + dapfHandle = LoadDAPFFromFile(szFileDAPF, &err_code); + if (dapfHandle == NULL) { + DisplayLastMessage(); + return err_code; + } + + // program dongle as specified by the DAPF file + err_code = AddProtection(dapfHandle, ACTION_PROTECT_SOFTWARE, -1, FLAGS_OVERWRITE_OUTPUT, &dummy); + + // Unload DAPF from memory + UnloadDAPF(&dapfHandle); + + // display message (error or success) + DisplayLastMessage(); + return err_code; +} + + +// load a DAPF file from disk and encrypt the shell data files specified +// (in practice it is better to encrypt the files one at a time and output messages as you go along, similar to DinkeyAdd.exe) +// In this example we specify the flag to overwrite any existing output file that might exist. +int DoEncryptShellDataFiles(char *szFileDAPF) { + DAPF_HANDLE dapfHandle; + int err_code; + + // load DAPF from File into memory + dapfHandle = LoadDAPFFromFile(szFileDAPF, &err_code); + if (dapfHandle == NULL) { + DisplayLastMessage(); + return err_code; + } + + // program dongle as specified by the DAPF file + err_code = EncryptShellDataFiles(dapfHandle, -1, FLAGS_OVERWRITE_OUTPUT); + + // Unload DAPF from memory + UnloadDAPF(&dapfHandle); + + // display message (error or success) + DisplayLastMessage(); + return err_code; +} + + +// load a DAPF file from disk and create a Temporary Software Key using the info that the user entered +int DoCreateTempSoftwareKey(char *szFileDAPF, char *szMachineID, char *szExpDay, char *szExpMonth, char *szExpYear) { + DAPF_HANDLE dapfHandle; + TEMP_SWKEY_INFO swkey_info; + int err_code; + unsigned int machineID = 0; + + // load DAPF from File into memory + dapfHandle = LoadDAPFFromFile(szFileDAPF, &err_code); + if (dapfHandle == NULL) { + DisplayLastMessage(); + return err_code; + } + + // fill out the SWKEY structure from the values the user entered + swkey_info.size = sizeof(TEMP_SWKEY_INFO); + if (szMachineID != NULL) + sscanf(szMachineID, "%x", &machineID); + swkey_info.machineID = machineID; + swkey_info.expiry_day = atoi(szExpDay); + swkey_info.expiry_month = atoi(szExpMonth); + swkey_info.expiry_year = atoi(szExpYear); + + // !!!! in this case we just choose Pro Plus. You could load the DAPF file into structures and see which model is selected. + // If there is more than one model selected you can ask the customer to choose which model they want. + swkey_info.dongle_model = SWKEY_MODEL_PRO_PLUS; + swkey_info.dongle_number = 0; // default + + // create the Temporary Software Key + err_code = CreateTempSoftwareKey(dapfHandle, &swkey_info, 0); + + // Unload DAPF from memory + UnloadDAPF(&dapfHandle); + + // display message (error or success) + DisplayLastMessage(); + return err_code; +} + +// load a DAPF file from disk and create a Demo Software Key Template using the info that the user entered +int DoCreateDemoSoftwareTemplate(char *szFileDAPF, char *szMaxDays) { + DAPF_HANDLE dapfHandle; + DEMO_SWKEY_INFO swkey_info; + int err_code; + + // load DAPF from File into memory + dapfHandle = LoadDAPFFromFile(szFileDAPF, &err_code); + if (dapfHandle == NULL) { + DisplayLastMessage(); + return err_code; + } + + // fill out the SWKEY structure from the values the user entered + swkey_info.size = sizeof(DEMO_SWKEY_INFO); + swkey_info.max_days = atoi(szMaxDays); + + // !!!! in this case we just choose the default model (assuming you only selected one in the DAPF file). + // If you want to specify more than one model then OR the flags together. e.g. SWKEY_BITMAP_PRO_LITE | SWKEY_BITMAP_PRO_PLUS + swkey_info.models = SWKEY_BITMAP_DEFAULT; + + // create the Temporary Software Key + err_code = CreateDemoSoftwareKeyTemplate(dapfHandle, &swkey_info, 0); + + // Unload DAPF from memory + UnloadDAPF(&dapfHandle); + + // display message (error or success) + DisplayLastMessage(); + return err_code; +} + + +// routine for main dialog box +BOOL CALLBACK MainDlgProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { + char szFileDAPF[256]; + char szMachineID[9], szMaxDays[3]; + char szExpDay[3], szExpMonth[3], szExpYear[5]; + + switch (message) + { + case WM_INITDIALOG: + SetDlgItemText(hwnd, IDC_TEMP_EXP_DAY, "dd"); + SetDlgItemText(hwnd, IDC_TEMP_EXP_MONTH, "mm"); + SetDlgItemText(hwnd, IDC_TEMP_EXP_YEAR, "yyyy"); + break; + + case WM_COMMAND: + GetDlgItemText(hwnd, IDC_DAPF_PATH, szFileDAPF, sizeof(szFileDAPF)); + + // *** Program Dongle button clicked *** + if (LOWORD(wParam) == IDC_PROGRAM_DONGLE && HIWORD(wParam) == BN_CLICKED) { + DoProgramDongle(szFileDAPF); + } + + // *** Program Dongle with Modification button clicked *** + if (LOWORD(wParam) == IDC_PROGRAM_DONGLE_MOD && HIWORD(wParam) == BN_CLICKED) { + DoProgramDongleWithMod(szFileDAPF); + } + + // *** Lock Software button clicked *** + if (LOWORD(wParam) == IDC_LOCK_SOFTWARE && HIWORD(wParam) == BN_CLICKED) { + DoLockSoftware(szFileDAPF); + } + + // *** Encrypt Shell Data Files button clicked *** + if (LOWORD(wParam) == IDC_ENCRYPT_SHELL_DATA_FILES && HIWORD(wParam) == BN_CLICKED) { + DoEncryptShellDataFiles(szFileDAPF); + } + + // *** Create Temporary Software Key button clicked *** + if (LOWORD(wParam) == IDC_CREATE_TEMP_SWKEY && HIWORD(wParam) == BN_CLICKED) { + GetDlgItemText(hwnd, IDC_MACHINEID, szMachineID, sizeof(szMachineID)); + GetDlgItemText(hwnd, IDC_TEMP_EXP_DAY, szExpDay, sizeof(szExpDay)); + GetDlgItemText(hwnd, IDC_TEMP_EXP_MONTH, szExpMonth, sizeof(szExpMonth)); + GetDlgItemText(hwnd, IDC_TEMP_EXP_YEAR, szExpYear, sizeof(szExpYear)); + DoCreateTempSoftwareKey(szFileDAPF, szMachineID, szExpDay, szExpMonth, szExpYear); + } + + // *** Create Demo Software Key Template button clicked *** + if (LOWORD(wParam) == IDC_CREATE_DEMO_SWKEY && HIWORD(wParam) == BN_CLICKED) { + GetDlgItemText(hwnd, IDC_DEMO_MAX_DAYS, szMaxDays, sizeof(szMaxDays)); + DoCreateDemoSoftwareTemplate(szFileDAPF, szMaxDays); + } + + break; + + case WM_CLOSE: + EndDialog(hwnd, TRUE); + return TRUE; + } + + return FALSE; +} + + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow ) { + // display dialog allow user to enter code + DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, (DLGPROC)MainDlgProc); // display main screen + return 0; +} + + +// gets & displays the message from the last API call to the DinkeyAdd Module +void DisplayLastMessage(void) { + char *szMessage; + int msg_len; + + GetLastMessage(NULL, 0, &msg_len); + + szMessage = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, msg_len); + + if (szMessage != NULL) { + GetLastMessage(szMessage, msg_len, NULL); + MessageBox(NULL, szMessage, g_szAppName, MB_OK); + HeapFree(GetProcessHeap(), 0, szMessage); + } + return; +} diff --git a/Dinkey Pro 7.6.1/Samples/C/dris.h b/Dinkey Pro 7.6.1/Samples/C/dris.h new file mode 100644 index 0000000..a3a7229 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/dris.h @@ -0,0 +1,101 @@ +// dris.h +// Dinkey Runtime Information Structure (DRIS) +// !! this file should not be modified + +#pragma pack(1) + +typedef struct DRIS { + // the first 4 fields are never encrypted + char header[4]; // should be set to DRIS + // inputs + int size; // size of this structure + int seed1; // seed for data/dris encryption + int seed2; // as above + // (maybe encrypted from now on) + int function; // specify only one function + int flags; // options for the function selected. To use more than one OR them together: OPTION1 | OPTION2... + unsigned int execs_decrement; // amount by which to dec execs if we use flag: DEC_MANY_EXECS + int data_crypt_key_num; // number of the key (1-3) that the dongle uses to encrypt or decrypt user data + int rw_offset; // offset in the dongle data area to read or write data + int rw_length; // length of data are to read/write/encrypt/decrypt + char *rw_data_ptr; // pointer to data to write / be read + char alt_licence_name[256]; // protection check for different licence instead of the default one, must be null-terminated + int var_a; // variable values for user algorithm + int var_b; + int var_c; + int var_d; + int var_e; + int var_f; + int var_g; + int var_h; + int alg_number; // the number of the user algorithm that you want to execute + + // outputs + int ret_code; // return code from the protection check + int ext_err; // extended error + int type; // type of dongle detected. 1 = Pro, 2 = FD + int model; // model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + int sdsn; // Software Developer's Serial Number + char prodcode[12]; // Product Code (null-terminated) + unsigned int dongle_number; + int update_number; + unsigned int data_area_size; // size of the data area used in the dongle detected + int max_alg_num; // the maximum algorithm number in the dongle detected + int execs; // executions left: -1 indicates 'no limit' + int exp_day; // expiry day: -1 indicates 'no limit' + int exp_month; // expiry month: -1 indicates 'no limit' + int exp_year; // expiry year: -1 indicates 'no limit' + unsigned int features; // features value + int net_users; // maximum number of network users for the dongle detected: -1 indicates 'no limit' + int alg_answer; // answer to the user algorithm executed with the given variable values + unsigned int fd_capacity; // capacity of the data area in FD dongle. + char fd_drive[128]; // drive letter of FD dongle detected e.g. 'f:\' (or mount name under Linux) + int swkey_type; // 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + int swkey_exp_day; // software key expiry date (if software key detected) + int swkey_exp_month; + int swkey_exp_year; +} DRIS; + +typedef struct NU_INFO { + char licenceName[256]; + char userName[50]; + char computerName[256]; + char ipAddress[16]; +} NU_INFO; + +#pragma pack() + +// functions - must specify only one +#define PROTECTION_CHECK 1 // checks for dongle, check program params... +#define EXECUTE_ALGORITHM 2 // protection check + calculate answer for specified algorithm with specified inputs +#define WRITE_DATA_AREA 3 // protection check + writes dongle data area +#define READ_DATA_AREA 4 // protection check + reads dongle data area +#define ENCRYPT_USER_DATA 5 // protection check + the dongle will encrypt user data +#define DECRYPT_USER_DATA 6 // protection check + the dongle will decrypt user data +#define FAST_PRESENCE_CHECK 7 // checks for the presence of the correct dongle only with minimal security, no flags allowed. +#define STOP_NET_USER 8 // stops a network user (a protection check is NOT performed) + +// flags - can specify as many as you like +#define DEC_ONE_EXEC 1 // decrement execs by 1 +#define DEC_MANY_EXECS 2 // decrement execs by number specified in execs_decrement +#define START_NET_USER 4 // starts a network user +#define USE_FUNCTION_ARGUMENT 16 // use the extra argument in the function for pointers +#define CHECK_LOCAL_FIRST 32 // always look in local ports before looking in network ports +#define CHECK_NETWORK_FIRST 64 // always look on the network before looking in local ports +#define USE_ALT_LICENCE_NAME 128 // use name specified in alt_licence_name instead of the default one +#define DONT_SET_MAXDAYS_EXPIRY 256 // if the max days expiry date has not been calculated then do not do it this time +#define MATCH_DONGLE_NUMBER 512 // restrict the search to match the dongle number specified in the DRIS +#define DONT_RETURN_FD_DRIVE 1024 // if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + + +// Runtime module API declarations +#ifdef __cplusplus + extern "C" { +#endif + +int WINAPI DDProtCheck(DRIS *dris, unsigned char *data); +int WINAPI DDGetNetUserList(char *licence_name, int *num_net_users, NU_INFO *nu_info, int num_info_structs, int *extended_error); + +#ifdef __cplusplus +} +#endif diff --git a/Dinkey Pro 7.6.1/Samples/C/drpf.h b/Dinkey Pro 7.6.1/Samples/C/drpf.h new file mode 100644 index 0000000..313190f --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/drpf.h @@ -0,0 +1,117 @@ +// drpf.h +// !! this file should not be modified + +// NB DRPF file is: +// REMOTEINFO +// LICENCEINFO (however many are needed) +// ALGCHANGE (however many are needed) +// DATACHANGE (however many are needed) - may refer to external files. + +// Remember: you only need to specify a value if you want to change it. Otherwise you +// specify the default "no change" setting. For most entries this is indicated by 0. +// However, for MaxNetUsers and LicenceNetUsers it is "-2" because 0 is a valid value to change to. + +#pragma pack (push,1) // so it is byte-aligned + +typedef struct REMOTEINFO { + char Header[4]; // Should be set to "DRPF" = DinkeyRemote Parameter File + unsigned int Version; // version of this structure - currently 2 + char ProdCode[12]; + unsigned int DongleNumber; + int UpdateNumber; + char Notes[256]; // user-defined notes + unsigned int NumLicences; + unsigned int NumAlgs; // number of algs to set (incl r/w alg) + unsigned int NumDataChanges; // number of data change blocks specified + unsigned int DataAreaSize; // -1 = increase as necessary. specifies the new size of the data area + int PerLicence; // 0 = no change, 1 = per licence net users, 2 = per product net users + int MaxNetUsers; // product net users, unlimited = -1, no change = -2 + unsigned int LastUsedDay; // Day = 0 (only) -> no change + unsigned int LastUsedMonth; + unsigned int LastUsedYear; + char DataEncKeyProdCode[12]; + unsigned int ChangeCodeType; // 0 = no change, bit0 = only accept secure codes, bit1 = accept secure & short codes + int CodeType; // type of code to generate. 0 = secure code, 1 = short code + char OutputFileName[256];// name of file to output code to. Null (default) -> UpdateCode.ducf + int LockDongle; // 1 = lock dongle to user's computer + int ResetDongleLock; // 1 = reset the dongle lock so that the dongle can be locked to a new machine +} REMOTEINFO; + +typedef struct LICENCEINFO { + char LicenceName[256]; + unsigned int Action; // 0 = change, 1 = delete, 2 = add + unsigned int AddSetExecs; // 0 = no change to execs, 1 = add, 2 = set + int Execs; // -1 = no limit + int ExecsWarn; // 0 = remove warning, -1 = no change + int ExpiryDay; // -1 = no limit, 0 = no change + int ExpiryMonth; + int ExpiryYear; + unsigned int AddSetMaxDays; // 0 = no change, 1 = add, 2 = set + int MaxDays; // -1 = no limit + int DaysWarn; // 0 = remove warning, -1 = no change + int FeaturesFlag; // 0 = don't change features, 1 = change features + unsigned int Features; // all values OK + int LicenceNetUsers; // unlimited = -1, no change = -2 +} LICENCEINFO; + +typedef struct ALGCHANGE { + int alg_number; // number of algorithm to set (0 = r/w algorithm) + unsigned char algorithm[12]; // algorithm +} ALGCHANGE; + +typedef struct DATACHANGE { + unsigned int type; // 1 = file, 2 = hex data, 3 = ascii, 4 = ascii null-term string + unsigned int offset; // offset in dongle data memory to write data + int length; // length of data to change + unsigned char data[256]; // data to write OR name of data file depending on which method set +} DATACHANGE; + +typedef struct UPDATE_CODE_OUTPUTS { + char szShortCode[128*3]; // the update code (for short update codes only) + char szUpdateCodeFile[256]; // the output ducf that contains the update code + char szConfirmationCode[8]; // the confirmation code +} UPDATE_CODE_OUTPUTS; + +typedef void *DRPF_HANDLE; // for DinkeyRemote Module API functions + +#pragma pack (pop) + +// constants +#define DRPF_VERSION 2 // current DRPF version + +// WriteDRPF API flags +#define FLAGS_LOSE_FEATURES 1 // means that you can save the DRPF file to an earlier version even if it means losing some new features that have been currently set + +// constants for drpf_format in ReadDRPFEx and WriteDRPFEx functions +#define DRPF_FORMAT_BINARY 1 +#define DRPF_FORMAT_JSON 2 +#define DRPF_FORMAT_JSON_MIN 3 // this value is only used with WriteDRPEx. ReadDRPFEx cannot return this value. + +#define MAX_LICENCES 255 // max number of licence changes in a DRPF file (theoretically unlimited but easier if we limit it) +#define MAX_ALG_CHANGES 21 // max number of alg changes in DRPF file +#define MAX_DATA_CHANGES 127 // max number of data area changes in DRPF file + +// DinkeyRemote module API declarations +#ifdef __cplusplus + extern "C" { +#endif + +int WINAPI ReadDRPFEx(char *szFileDRPF, REMOTEINFO *pRemoteInfo, LICENCEINFO *pLicenceInfo, ALGCHANGE *pAlgChanges, DATACHANGE *pDataChanges, int *drpf_version, int *drpf_format); + +DRPF_HANDLE WINAPI LoadDRPF(REMOTEINFO *pRemoteInfo, LICENCEINFO *pLicenceInfo, ALGCHANGE *pAlgChanges, DATACHANGE *pDataChanges, int *err_code); + +DRPF_HANDLE WINAPI LoadDRPFFromFile(char *szFileDRPF, int *err_code); + +int WINAPI WriteDRPFEx(DRPF_HANDLE handle, char *szFileDRPF, int drpf_format, int drpf_version, int flags); + +void WINAPI UnloadDRPF(DRPF_HANDLE *handle); + +int WINAPI GenerateUpdateCode(DRPF_HANDLE handle, unsigned int dongle_number, int update_number, char *ducf_file, char *logfile, UPDATE_CODE_OUTPUTS *pOutputs); + +void WINAPI GetLastMessage(char *szMessage, int buffer_size, int *message_length); + +int WINAPI GetLastExtendedError(void); + +#ifdef __cplusplus +} +#endif diff --git a/Dinkey Pro 7.6.1/Samples/C/drpftest.c b/Dinkey Pro 7.6.1/Samples/C/drpftest.c new file mode 100644 index 0000000..4276065 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/drpftest.c @@ -0,0 +1,156 @@ +// drpfTest + +// Sample code for calling the DinkeyRemote module + +// The sample code contains 2 functions. The sample code is just a guide. + +// There are two methods to loading a DRPF file. These are shown in the first two functions: +// DoUpdateCode and DoUpdateCodewithMod + +// DoUpdateCode: we load the DRPF file from disk and get a handle and use it "as is" using the API +// call LoadDRPFFromFile. You can make some limited changes to overwrite the default +// behaviour by using API flags. + +// DoUpdateCodewithMod: we load the DRPF file from disk and load into structures. We can then modify the +// DRPF settings by modifying this structure. This method uses the API calls +// ReadDRPFEx and LoadDRPF. + +#include +#include + +#include "Visual Studio 5\DinkeyRemote\resource.h" +#include "drpf.h" + +#ifdef _MSC_VER + #pragma warning(disable:4996) // to disable warnings about sprintf etc... means we can use the same source for all compilers +#endif + + +char g_szAppName[] = "drpfTest"; + +void DisplayLastMessage(void); // gets & displays the message from the DinkeyRemote Module + + +// load a DRPF file from disk and generate an update code as specified by the DRPF file +int DoUpdateCode(char *szFileDRPF) { + DRPF_HANDLE drpfHandle; + UPDATE_CODE_OUTPUTS Outputs; + int err_code; + + // load DRPF from File into memory + drpfHandle = LoadDRPFFromFile(szFileDRPF, &err_code); + if (drpfHandle == NULL) { + DisplayLastMessage(); + return err_code; + } + + // generate the update code as specified by the DRPF file + err_code = GenerateUpdateCode(drpfHandle, 0, 0, NULL, NULL, &Outputs); + + // Unload DRPF from memory + UnloadDRPF(&drpfHandle); + + // display message (error or success) + DisplayLastMessage(); + return err_code; +} + + +// load a DRPF file from disk, modify it in memory and then generate the update code +int DoUpdateCodeWithMod(char *szFileDRPF) { + DRPF_HANDLE drpfHandle; + int dummy1, dummy2, err_code; + REMOTEINFO RemoteInfo; + LICENCEINFO LicenceInfo[MAX_LICENCES]; + ALGCHANGE AlgChanges[MAX_ALG_CHANGES]; + DATACHANGE DataChanges[MAX_DATA_CHANGES]; + UPDATE_CODE_OUTPUTS Outputs; + + // in this case we need to read the DRPF into our structures, so that the DRPF values can be modified + err_code = ReadDRPFEx(szFileDRPF, &RemoteInfo, (LICENCEINFO *)&LicenceInfo, (ALGCHANGE *)&AlgChanges, (DATACHANGE *)&DataChanges, &dummy1, &dummy2); + if (err_code != 0) { + DisplayLastMessage(); + return err_code; + } + + // patch new values in the RemoteInfo, LicenceInfo, AlgChanges, DataChanges structures + LicenceInfo[0].FeaturesFlag = 1; // so that the features value below will be recognised + LicenceInfo[0].Features = 12345; + LicenceInfo[0].AddSetExecs = 1; // so the executions will be added to existing + LicenceInfo[0].Execs = 100; + + // get DRPF handle + drpfHandle = LoadDRPF(&RemoteInfo, LicenceInfo, AlgChanges, DataChanges, &err_code); + if (drpfHandle == NULL) { + DisplayLastMessage(); + return err_code; + } + + // generate the update code as specified by the DRPF file + err_code = GenerateUpdateCode(drpfHandle, 0, 0, NULL, NULL, &Outputs); + + // Unload DRPF from memory + UnloadDRPF(&drpfHandle); + + // display message (error or success) + DisplayLastMessage(); + return err_code; +} + + +// routine for main dialog box +BOOL CALLBACK MainDlgProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { + char szFileDRPF[256]; + + switch (message) + { + case WM_INITDIALOG: + break; + + case WM_COMMAND: + GetDlgItemText(hwnd, IDC_DRPF_PATH, szFileDRPF, sizeof(szFileDRPF)); + + // *** Generate Update Code button clicked *** + if (LOWORD(wParam) == IDC_UPDATE_CODE && HIWORD(wParam) == BN_CLICKED) { + DoUpdateCode(szFileDRPF); + } + + // *** Generate Update Code with Modification button clicked *** + if (LOWORD(wParam) == IDC_UPDATE_CODE_MOD && HIWORD(wParam) == BN_CLICKED) { + DoUpdateCodeWithMod(szFileDRPF); + } + + break; + + case WM_CLOSE: + EndDialog(hwnd, TRUE); + return TRUE; + } + + return FALSE; +} + + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow ) { + // display dialog allow user to enter code + DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, (DLGPROC)MainDlgProc); // display main screen + return 0; +} + + +// gets & displays the message from the last API call to the DinkeyRemote Module +void DisplayLastMessage(void) { + char *szMessage; + int msg_len; + + GetLastMessage(NULL, 0, &msg_len); + + szMessage = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, msg_len); + + if (szMessage != NULL) { + GetLastMessage(szMessage, msg_len, NULL); + MessageBox(NULL, szMessage, g_szAppName, MB_OK); + HeapFree(GetProcessHeap(), 0, szMessage); + } + return; +} diff --git a/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyAdd32.lib b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyAdd32.lib new file mode 100644 index 0000000..ed2fde6 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyAdd32.lib differ diff --git a/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyAdd32_borland.lib b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyAdd32_borland.lib new file mode 100644 index 0000000..b8555c6 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyAdd32_borland.lib differ diff --git a/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyAdd64.lib b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyAdd64.lib new file mode 100644 index 0000000..b85a461 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyAdd64.lib differ diff --git a/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyAdd64_borland.lib b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyAdd64_borland.lib new file mode 100644 index 0000000..307c511 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyAdd64_borland.lib differ diff --git a/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyChange.lib b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyChange.lib new file mode 100644 index 0000000..7fc1bc4 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyChange.lib differ diff --git a/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyChange64.lib b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyChange64.lib new file mode 100644 index 0000000..3dc35b7 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyChange64.lib differ diff --git a/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyChange64Debug.lib b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyChange64Debug.lib new file mode 100644 index 0000000..5a4f3d7 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyChange64Debug.lib differ diff --git a/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyChangeDebug.lib b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyChangeDebug.lib new file mode 100644 index 0000000..256c39d Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyChangeDebug.lib differ diff --git a/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyChangeDebug_borland.lib b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyChangeDebug_borland.lib new file mode 100644 index 0000000..b3dd1b6 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyChangeDebug_borland.lib differ diff --git a/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyChange_borland.lib b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyChange_borland.lib new file mode 100644 index 0000000..61a7187 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyChange_borland.lib differ diff --git a/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyRemote32.lib b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyRemote32.lib new file mode 100644 index 0000000..b1af486 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyRemote32.lib differ diff --git a/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyRemote32_borland.lib b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyRemote32_borland.lib new file mode 100644 index 0000000..579b9cd Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyRemote32_borland.lib differ diff --git a/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyRemote64.lib b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyRemote64.lib new file mode 100644 index 0000000..25e44d7 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyRemote64.lib differ diff --git a/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyRemote64_borland.lib b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyRemote64_borland.lib new file mode 100644 index 0000000..307c511 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/import_libs/DinkeyRemote64_borland.lib differ diff --git a/Dinkey Pro 7.6.1/Samples/C/import_libs/README.txt b/Dinkey Pro 7.6.1/Samples/C/import_libs/README.txt new file mode 100644 index 0000000..d2ea6aa --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/C/import_libs/README.txt @@ -0,0 +1,31 @@ +Import Libraries +~~~~~~~~~~~~~~~~ + +These are used with C/C++ languages so that the compiler knows what functions +can be found in which DLLs. You need to link the appropriate import library to +your source code so that the DLL can be called correctly. + +Microsoft import libraries +~~~~~~~~~~~~~~~~~~~~~~~~~~ +dpwin32.lib +dpwin32debug.lib +DinkeyChange.lib +DinkeyChangeDebug.lib + +Borland C++ Builder import libraries +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +dpwin32_borland.lib +dpwin32debug_borland.lib +DinkeyChange_borland.lib +DinkeyChangeDebug_borland.lib + +Dev C++ and MinGW import libraries +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +libdpwin32.a +libdpwin32debug.a +libDinkeyChange.a +libDinkeyChangeDebug.a + +If you look at the sample code for the relevant language / compiler then it +will tell you how to use these import libraries. + diff --git a/Dinkey Pro 7.6.1/Samples/C/import_libs/dpwin32.lib b/Dinkey Pro 7.6.1/Samples/C/import_libs/dpwin32.lib new file mode 100644 index 0000000..912ecf0 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/import_libs/dpwin32.lib differ diff --git a/Dinkey Pro 7.6.1/Samples/C/import_libs/dpwin32_borland.lib b/Dinkey Pro 7.6.1/Samples/C/import_libs/dpwin32_borland.lib new file mode 100644 index 0000000..f718ac2 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/import_libs/dpwin32_borland.lib differ diff --git a/Dinkey Pro 7.6.1/Samples/C/import_libs/dpwin32debug.lib b/Dinkey Pro 7.6.1/Samples/C/import_libs/dpwin32debug.lib new file mode 100644 index 0000000..404b47c Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/import_libs/dpwin32debug.lib differ diff --git a/Dinkey Pro 7.6.1/Samples/C/import_libs/dpwin32debug_borland.lib b/Dinkey Pro 7.6.1/Samples/C/import_libs/dpwin32debug_borland.lib new file mode 100644 index 0000000..1d248bc Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/import_libs/dpwin32debug_borland.lib differ diff --git a/Dinkey Pro 7.6.1/Samples/C/import_libs/dpwin64.lib b/Dinkey Pro 7.6.1/Samples/C/import_libs/dpwin64.lib new file mode 100644 index 0000000..0f71232 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/import_libs/dpwin64.lib differ diff --git a/Dinkey Pro 7.6.1/Samples/C/import_libs/dpwin64debug.lib b/Dinkey Pro 7.6.1/Samples/C/import_libs/dpwin64debug.lib new file mode 100644 index 0000000..fe890fd Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/import_libs/dpwin64debug.lib differ diff --git a/Dinkey Pro 7.6.1/Samples/C/object_modules/dpwin32_coff.obj b/Dinkey Pro 7.6.1/Samples/C/object_modules/dpwin32_coff.obj new file mode 100644 index 0000000..9963519 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/object_modules/dpwin32_coff.obj differ diff --git a/Dinkey Pro 7.6.1/Samples/C/object_modules/dpwin32_omf.obj b/Dinkey Pro 7.6.1/Samples/C/object_modules/dpwin32_omf.obj new file mode 100644 index 0000000..bbf3f76 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/object_modules/dpwin32_omf.obj differ diff --git a/Dinkey Pro 7.6.1/Samples/C/object_modules/dpwin64.obj b/Dinkey Pro 7.6.1/Samples/C/object_modules/dpwin64.obj new file mode 100644 index 0000000..2d34def Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/C/object_modules/dpwin64.obj differ diff --git a/Dinkey Pro 7.6.1/Samples/Delphi/FireMonkey/Runtime/DllTest.dpr b/Dinkey Pro 7.6.1/Samples/Delphi/FireMonkey/Runtime/DllTest.dpr new file mode 100644 index 0000000..af34fe8 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Delphi/FireMonkey/Runtime/DllTest.dpr @@ -0,0 +1,15 @@ +program DllTest; + +uses + System.StartUpCopy, + FMX.Forms, + apitest in 'apitest.pas' {Form1}, + dris in 'dris.pas'; + +{$R *.res} + +begin + Application.Initialize; + Application.CreateForm(TForm1, Form1); + Application.Run; +end. diff --git a/Dinkey Pro 7.6.1/Samples/Delphi/FireMonkey/Runtime/DllTest.dproj b/Dinkey Pro 7.6.1/Samples/Delphi/FireMonkey/Runtime/DllTest.dproj new file mode 100644 index 0000000..aab5059 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Delphi/FireMonkey/Runtime/DllTest.dproj @@ -0,0 +1,1106 @@ + + + {D7AD8AB7-4781-4244-99BD-D52E35E152EA} + 18.8 + FMX + DllTest.dpr + True + Debug + OSX64 + 4103 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Cfg_1 + true + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + true + Cfg_2 + true + true + + + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) + $(BDS)\bin\delphi_PROJECTICON.ico + $(BDS)\bin\delphi_PROJECTICNS.icns + DllTest + + + DBXSqliteDriver;IndyIPCommon;RESTComponents;bindcompdbx;DBXInterBaseDriver;IndyIPServer;IndySystem;tethering;fmxFireDAC;FireDAC;bindcompfmx;FireDACSqliteDriver;FireDACPgDriver;inetdb;soaprtl;DbxCommonDriver;fmx;FireDACIBDriver;fmxdae;xmlrtl;soapmidas;fmxobj;rtl;DbxClientDriver;CustomIPTransport;dbexpress;IndyCore;bindcomp;dsnap;FireDACCommon;IndyIPClient;RESTBackendComponents;soapserver;dbxcds;bindengine;DBXMySQLDriver;CloudService;dsnapxml;FireDACMySQLDriver;dbrtl;IndyProtocols;inetdbxpress;FireDACCommonODBC;FireDACCommonDriver;inet;fmxase;$(DCC_UsePackage) + CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts + Debug + true + + + DBXSqliteDriver;IndyIPCommon;RESTComponents;bindcompdbx;DBXInterBaseDriver;IndyIPServer;IndySystem;tethering;fmxFireDAC;FireDAC;bindcompfmx;FireDACSqliteDriver;FireDACPgDriver;inetdb;soaprtl;DbxCommonDriver;fmx;FireDACIBDriver;fmxdae;xmlrtl;soapmidas;fmxobj;rtl;DbxClientDriver;CustomIPTransport;dbexpress;IndyCore;bindcomp;dsnap;FireDACCommon;IndyIPClient;RESTBackendComponents;soapserver;dbxcds;bindengine;DBXMySQLDriver;CloudService;dsnapxml;FireDACMySQLDriver;dbrtl;IndyProtocols;inetdbxpress;FireDACCommonODBC;FireDACCommonDriver;inet;fmxase;$(DCC_UsePackage) + CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts + Debug + true + + + DBXSqliteDriver;IndyIPCommon;RESTComponents;bindcompdbx;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;vclFireDAC;IndySystem;tethering;svnui;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;vclimg;FireDAC;vcltouch;vcldb;bindcompfmx;svn;FireDACSqliteDriver;FireDACPgDriver;inetdb;soaprtl;DbxCommonDriver;fmx;FireDACIBDriver;fmxdae;xmlrtl;soapmidas;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;dbexpress;IndyCore;vclx;bindcomp;appanalytics;dsnap;FireDACCommon;IndyIPClient;bindcompvcl;RESTBackendComponents;VCLRESTComponents;soapserver;dbxcds;VclSmp;adortl;vclie;bindengine;DBXMySQLDriver;CloudService;dsnapxml;FireDACMySQLDriver;dbrtl;IndyProtocols;inetdbxpress;FireDACCommonODBC;FireDACCommonDriver;inet;fmxase;$(DCC_UsePackage) + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + Debug + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + $(BDS)\bin\default_app.manifest + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + + + DBXSqliteDriver;IndyIPCommon;RESTComponents;bindcompdbx;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;vclFireDAC;IndySystem;tethering;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;vclimg;FireDAC;vcltouch;vcldb;bindcompfmx;FireDACSqliteDriver;FireDACPgDriver;inetdb;soaprtl;DbxCommonDriver;fmx;FireDACIBDriver;fmxdae;xmlrtl;soapmidas;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;dbexpress;IndyCore;vclx;bindcomp;appanalytics;dsnap;FireDACCommon;IndyIPClient;bindcompvcl;RESTBackendComponents;VCLRESTComponents;soapserver;dbxcds;VclSmp;adortl;vclie;bindengine;DBXMySQLDriver;CloudService;dsnapxml;FireDACMySQLDriver;dbrtl;IndyProtocols;inetdbxpress;FireDACCommonODBC;FireDACCommonDriver;inet;fmxase;$(DCC_UsePackage) + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + Debug + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + $(BDS)\bin\default_app.manifest + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + /usr/X11/bin/xterm -e "%debuggee%" + true + (None) + + + false + true + PerMonitorV2 + + + true + PerMonitorV2 + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + true + PerMonitorV2 + + + true + PerMonitorV2 + + + + MainSource + + +
Form1
+ fmx +
+ + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + +
+ + Delphi.Personality.12 + Application + + + + DllTest.dpr + + + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + + + true + + + + + Info.plist + true + + + + + Info.plist + true + + + + + DllTest.icns + true + + + + + true + + + + + true + + + + + true + + + + + true + + + + + DllTest.icns + true + + + + + DllTest.exe + true + + + + + DllTest + true + + + + + DllTest + true + + + + + DllTest + true + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + classes + 1 + + + classes + 1 + + + + + res\xml + 1 + + + res\xml + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\armeabi + 1 + + + library\lib\armeabi + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\mips + 1 + + + library\lib\mips + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-v21 + 1 + + + res\values-v21 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-ldpi + 1 + + + res\drawable-ldpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-small + 1 + + + res\drawable-small + 1 + + + + + res\drawable-normal + 1 + + + res\drawable-normal + 1 + + + + + res\drawable-large + 1 + + + res\drawable-large + 1 + + + + + res\drawable-xlarge + 1 + + + res\drawable-xlarge + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + Contents\MacOS + 1 + .framework + + + Contents\MacOS + 1 + .framework + + + 0 + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .dll;.bpl + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .bpl + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + 1 + + + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + Contents + 1 + + + Contents + 1 + + + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + Contents\MacOS + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + + + + + + + + + + + True + True + True + True + + + 12 + + + + +
diff --git a/Dinkey Pro 7.6.1/Samples/Delphi/FireMonkey/Runtime/README.txt b/Dinkey Pro 7.6.1/Samples/Delphi/FireMonkey/Runtime/README.txt new file mode 100644 index 0000000..9c6a599 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Delphi/FireMonkey/Runtime/README.txt @@ -0,0 +1,105 @@ +Sample code to call Runtime modules in Delphi +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Delphi 10.3 but should also work in other versions. +If you want to create traditional Delphi applications under Windows please +use the VCL projects instead. + +The source files in the project are: + +File name Description +apitest.pas main source code file +dris.pas contains DRIS structure definition and other definitions. +apitest.fmx form design +DllTest.dpr project file +DllTest.dproj project file + +The idea is to include the dris.pas file in your project and use/modify which ever +functions from apitest.pas you feel are appropriate. + +This sample has been tested under Win32, Win64, Mac32 and Mac64 environments. In order +to build and deploy under MacOS you need to setup a remote Mac machine using profile. + +The sample code contains 11 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. However, you should +still display or log any error codes returned by the protection check otherwise you will not +be able to identify the cause of the error. (You can look up error codes in our knowledge +base: microcosm.com/kb). + +This project calls the appropriate dynamic runtime module for the OS. +(Note, in Windows you could link with the static module instead (we do this for the ObjTest +project in the VCL samples). However, we do not supply the correct static libraries for MacOS. +This is because Delphi requires the object modules to be in its own custom format.) + +Note - you should run DinkeyAdd and protect all the runtime modules that you require +(for each platform that you want to support. e.g. dpwin64.dll for Windows 64-bit). +Do not protect your program directly. Because your program is linked to this library it is +protected. + +The protected library will need to be in the same folder as your compiled program +for it to run correctly (in the Mac of MacOS it needs to reside in the Contents/MacOS directory +of your application bundle). You can add the protected library to the list of deployment files +(Project | Deployment) so that it is copied to the correct location when you deploy it. + +The Delphi compile has a few quirks under 64-bit MacOS build: +1) You need to have the runtime dynamic module dpmac64.dylib to be present in the project folder + for the project to build correctly (this is not necessary under the other build platforms). +2) There is a bug in the linker so that the dpmac64.dylib is not referenced correctly from the + deployed application (if you run otool -L on the application you will see that it only + references dpmac64.dylib. It should be @rpath/dpmac64.dylib.) The linker does this correctly for + the 32-bit build. After deploying you need to open a terminal, change directory to the application + /Contents/MacOS directory and then run the following command: + + install_name_tool -change dpmac64.dylib @rpath/dpmac64.dylib + + Ideally you would modify the deployment under MacOS64 so that a script executes this each time. + Unfortunately, there doesn't seem to be a way of doing this. + +Debug Modules +~~~~~~~~~~~~~~ +Note - once the runtime module is protected you will not be able to debug +your program - after our API has been called. Our strong anti-debug code will cause +the debugger to throw an exception. If you do want to debug your code +then you can use our debug modules: e.g. dpwin64debug.dll for 64-bit Windows, but these +should not be used for release. + +You could setup your project so that your code links the debug module during your debug build +and the standard module when you produce your release code. + +Note: the debug module has the following restrictions: + +1) It will not correctly start a network user (network dongles only). However, other than that + the protection check will function correctly and return success. +2) You will not be able to encrypt the DRIS. (If you do encrypt the DRIS in your release build + then you should make sure that CryptDRIS does not get called in your debug build). +3) The protection check will take slightly longer than normal. +4) The DDGetNetUserList function will return error 428 (not implemented). +5) A temporary subprocess is created which may be (falsely) detected as malicious by anti-virus + programs. + +Differences with the VCL code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +DRIS: + The longint type is changed to FixedInt because longint can be 8-bytes in some platforms + The longword type is change to FixedUInt because longword can be 8-bytes in some platforms + More conditional code to call native dynamic library on different platforms + Uses the dynamic modules and does not link with the static modules + +APITEST: + Uses ShowMessage rather than MessageDlg (now deprecated) + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/Delphi/FireMonkey/Runtime/apitest.Macintosh.fmx b/Dinkey Pro 7.6.1/Samples/Delphi/FireMonkey/Runtime/apitest.Macintosh.fmx new file mode 100644 index 0000000..3d1ea0e --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Delphi/FireMonkey/Runtime/apitest.Macintosh.fmx @@ -0,0 +1,3 @@ +inherited Form1_Macintosh: TForm1_Macintosh + DesignerMasterStyle = 0 +end diff --git a/Dinkey Pro 7.6.1/Samples/Delphi/FireMonkey/Runtime/apitest.fmx b/Dinkey Pro 7.6.1/Samples/Delphi/FireMonkey/Runtime/apitest.fmx new file mode 100644 index 0000000..885bc4d --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Delphi/FireMonkey/Runtime/apitest.fmx @@ -0,0 +1,22 @@ +object Form1: TForm1 + Left = 0 + Top = 0 + Caption = 'Form1' + ClientHeight = 197 + ClientWidth = 306 + FormFactor.Width = 320 + FormFactor.Height = 480 + FormFactor.Devices = [Desktop] + DesignerMasterStyle = 0 + object Label1: TLabel + StyledSettings = [Family, Style, FontColor] + Position.X = 80.000000000000000000 + Position.Y = 72.000000000000000000 + Size.Width = 145.000000000000000000 + Size.Height = 33.000000000000000000 + Size.PlatformDefault = False + TextSettings.Font.Size = 30.000000000000000000 + Text = 'It worked!' + TabOrder = 1 + end +end diff --git a/Dinkey Pro 7.6.1/Samples/Delphi/FireMonkey/Runtime/apitest.pas b/Dinkey Pro 7.6.1/Samples/Delphi/FireMonkey/Runtime/apitest.pas new file mode 100644 index 0000000..95490a1 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Delphi/FireMonkey/Runtime/apitest.pas @@ -0,0 +1,876 @@ +unit apitest; + +interface + +uses + System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, + FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, + FMX.Controls.Presentation, FMX.StdCtrls, + dris; + +type + TForm1 = class(TForm) + Label1: TLabel; + private + { Private declarations } + public + { Public declarations } + end; + +var + Form1: TForm1; + +implementation + +{$R *.fmx} +{$R *.Macintosh.fmx MACOS} + +{ !! We strongly recommend that you read the "readme.txt" file in the sample code folder. + !! It contains important instructions on how to use the sample code } + +{ The sample code contains 11 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. To choose which function +this code uses see the startup code at the bottom of this file. + +this file contains 11 protection-check functions. + longint ProtCheck(); a standard protection check + longint ProtCheckWithAlg(); a protection check & executing an Algorithm + longint WriteBytes(); a protection check & write data to the dongle + longint ReadBytes(); a protection check & read data from the dongle + longint EncryptUserData(); a protection check & encrypting data and then decrypting the data + +these functions are the same as the functions listed above but encrypting all parameters passed to our API + longint ProtCheckEnc(); a standard protection check + longint ProtCheckWithAlgEnc(); a protection check & executing an Algorithm + longint WriteBytesEnc(); a protection check & write data to the dongle + longint ReadBytesEnc(); a protection check & read data from the dongle + longint EncryptUserDataEnc(); a protection check & encrypting data and then decrypting the data + + longint DisplayNetUsers(net_users, model); this function displays the current network users + + If you are using Dinkey Lite then you can only use 4 functions: +ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + } + +const MY_SDSN = 10101; { !!!! change this value to be the value of your SDSN (demo = 10101) } +const MY_PRODCODE = 'DEMO'; + +{ this procedure initialises the DRIS with random bytes } +procedure random_set(data: PByte; length: integer); +var + i : integer; +begin + Randomize(); + for i := 0 to length-1 do + begin + data^ := Random(256); + Inc(data); { increment the pointer so we can access the next byte } + end; +end; + +{ displays messages for the most common errors. You will want to change this for your code } +procedure DisplayError(ret_code, extended_error:integer); +var + display : string; +begin + case ret_code of + 401: display := 'Error! No dongles detected!'; + 403: display := 'Error! The dongle detected has a different type to the one specified in DinkeyAdd.'; + 404: display := 'Error! The dongle detected has a different model to those specified in DinkeyAdd.'; + 409: display := 'Error! The dongle detected has not been programmed by DinkeyAdd.'; + 410: display := 'Error! The dongle detected has a different Product Code to the one specified in DinkeyAdd.'; + 411: display := 'Error! The dongle detected does not contain the licence associated with this program.'; + 413: display := 'Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual.'; + 417: display := 'Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.'; + 423: display := 'Error! The number of network users has been exceeded.'; + 435: display := 'Error! DinkeyServer has not been detected on the network.'; + 922: display := 'Error! The Software Key has expired.'; + else + display := 'An error occurred checking the dongle. Error: ' + IntToStr(ret_code) + '. Extended Error code: ' + IntToStr(extended_error); + end; + ShowMessage(display); +end; + +{ ************************* our 11 functions follow *************************** } + +{ *********************** DisplayNetUsers ******************************* } +{ This function displays the current network users (for DinkeyNet only). + The DDProtCheck function must be called before this function is called. + (Normally you would use DinkeyServer to view the network users but this enables you to do it from the client if you want) } +Function DisplayNetUsers (net_users, model : LongInt) : LongInt; +var + display : string; + nu_info: packed array[0..99] of nu_infoType; { !!!! this assumes that you will display max. 100 net users } + i, max_net_users, num_net_users, extended_error : LongInt; + +begin + if (net_users = -1) then + begin + max_net_users := 100; { if unlimited network users are allowed then display up to 100 users (for example) If you want more than 1000 net users you need to change the value above} + end + else + begin + max_net_users := net_users; + end; + + if (net_users = 0) then { no network users are allowed, so nothing to do! } + begin + result := 0; + exit; + end; + + if (model < 3) then + begin + ShowMessage('A network dongle has not been detected. Therefore you cannot display the network users.'); + result := -1; + exit; + end; + + { now get net users } + result := DDGetNetUserList(NIL, @num_net_users, @nu_info, max_net_users, @extended_error); + + if (result <> 0) then + begin + ShowMessage('Error ' + IntToStr(result) + '/' + IntToStr(extended_error) + ' finding network user information.'); + end + else + begin + display:= 'number of net users: ' + IntToStr(num_net_users) + #13#10; + for i := 0 to num_net_users-1 do + begin + display := display + IntToStr(i+1) + '. licence: ' + String(nu_info[i].licenceName) + ', user: ' + String(nu_info[i].userName) + + ', computer: ' + String(nu_info[i].computerName) + ', ipaddress: ' + String(nu_info[i].ipAddress) + #13#10; + end; + ShowMessage(display); + end; +end; + +{ ************************** ProtCheck *************************************** } +Function ProtCheck : LongInt; +var + dris: drisType; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= PROTECTION_CHECK; { standard protection check } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + ShowMessage('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.'); + result := -1; + exit; + end; + + if (dris.prodcode <> AnsiString(MY_PRODCODE)) then + begin + ShowMessage('Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.'); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + ShowMessage('Dinkey Dongle protection error.'); + result := -1; + exit; + end; + + { if you are using a network dongle and you want to list the network users then use this function: } + { DisplayNetUsers(dris.net_users, dris.model); } +end; + +{ ************************** ProtCheckWithAlg ******************************** } +{ !!!! You should replace this function with the one generated by the + "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm). +If you are using Dinkey Lite the copy the source code from DinkeyLook } +Function MyAlgorithm(a,b,c,d,e,f,g,h:LongInt):LongInt; +begin + MyAlgorithm:= a + b + c + d + e + f + g + h; +end; + +{ NB for this to work you must program at least "user algorithm" into the dongle + NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite copy source code from DinkeyLook} +Function ProtCheckWithAlg : LongInt; +var + dris: drisType; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= EXECUTE_ALGORITHM; { standard protection check & execute algorithm } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.alg_number := 1; { execute algorithm 1 (you do not need to specify this field if you are only using Lite models) } + { you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random } + dris.var_a := 1; { sample values } + dris.var_b := 2; + dris.var_c := 3; + dris.var_d := 4; + dris.var_e := 5; + dris.var_f := 6; + dris.var_g := 7; + dris.var_h := 8; + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + ShowMessage('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.'); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + ShowMessage('Dinkey Dongle protection error.'); + result := -1; + exit; + end; + + { if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd } + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) <> dris.alg_answer) then + begin + ShowMessage('Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine'); + result := -1; + exit; + end; +end; + +{ ************************** WriteBytes *************************************** } +{ This writes the Data "Hello, World" to the dongle data area at offset 7 + In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. } + +Function WriteBytes : LongInt; +var + dris: drisType; + DataToWrite : array[0..13] of AnsiChar; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= WRITE_DATA_AREA; { standard protection check & write data} + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.rw_offset := 7; + dris.rw_length := 13; + DataToWrite := 'Hello, World!'; { string to write } + dris.rw_data_ptr := Addr(DataToWrite); + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + ShowMessage('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.'); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + ShowMessage('Dinkey Dongle protection error.'); + result := -1; + exit; + end; +end; + +{ ************************** ReadBytes *************************************** } +{ This reads 14 bytes of data from offset 7 in the dongle data area + In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. + In order for the data to be displayed properly by this routine it will need to be text data } +Function ReadBytes : LongInt; +var + dris: drisType; + DataToRead : array[0..13] of AnsiChar; + display : string; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= READ_DATA_AREA; { standard protection check & write data} + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.rw_offset := 7; + dris.rw_length := 13; { we will add null termination after reading } + dris.rw_data_ptr := Addr(DataToRead); + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + ShowMessage('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.'); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + ShowMessage('Dinkey Dongle protection error.'); + result := -1; + exit; + end; + + DataToRead[13] := Chr(0); { null end of string } + display := 'Dinkey Dongle data area contains: ' + DataToRead; + ShowMessage(display); +end; + +{ ************************** EncryptUserData ********************************** } +{ This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 + It will then do another protection check & decrypt the data } +Function EncryptUserData : LongInt; +var + dris: drisType; + display : string; + DataString : array[0..13] of AnsiChar; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= ENCRYPT_USER_DATA; { standard protection check & encrypt data } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.data_crypt_key_num := 1; + dris.rw_length := 13; + DataString := 'Hello, World!'; { string to encrypt } + dris.rw_data_ptr := Addr(DataString); + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... } + + { Now decrypt the same data to get the original values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= DECRYPT_USER_DATA; { standard protection check & decrypt data } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.data_crypt_key_num := 1; + dris.rw_length := 13; + dris.rw_data_ptr := Addr(DataString); + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + ShowMessage('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.'); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + ShowMessage('Dinkey Dongle protection error.'); + result := -1; + exit; + end; + + DataString[13] := Chr(0); { null end of string } + display := 'Decrypted data is: ' + DataString; + ShowMessage(display); +end; + +{!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! + In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" + in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm + but the code can be modified easily to use the 3 encryption parameters. } + +{ !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm } +Function MyRWAlgorithm(a,b,c,d,e,f,g,h:LongInt):LongInt; +begin + MyRWAlgorithm:= a xor b xor c xor d xor e xor f; +end; + +{ !!!! please overwrite this function with the one generated by DinkeyAdd } +procedure CryptDRIS(dris : PByte; seed1,seed2 : Longword); +var + i,j,k : Integer; + bigseed,S : packed array[0..255] of byte; + temp,t : byte; +begin + i := 0; + while (i < 255) do + begin + Move(seed1, bigseed[i], 4); {NB move actually copies data} + Move(seed2, bigseed[i+4], 4); + i := i + 8; + end; + + for i := 0 to 255 do S[i]:= i; + + j := 0; + for i := 0 to 255 do + begin + j := (j + S[i] + bigseed[i] + 123) Mod 256; + temp := S[i]; + S[i] := S[j]; + S[j] := temp; + end; + i := 0; + j := 0; + Inc(dris, 16); {the first part of the DRIS is not encrypted} + for k := 16 to SizeOf(drisType)-1 do + begin + i := (i + 1) Mod 256; + j := (j + S[i] + 212) Mod 256; + temp := S[i]; + S[i] := S[j]; + S[j] := temp; + t := (S[i] + S[j] + 97) Mod 256; + dris^ := dris^ xor S[t]; + Inc(dris); + end; +end; +{ !!!! please overwrite this function with the one generated by DinkeyAdd } +procedure CryptApiData(data : pbyte; length : integer; seed1,seed2 : Longword; alg_answer: LongInt); +var + i,j,k : Integer; + bigseed,S : packed array[0..255] of byte; + temp,t : byte; +begin + i := 0; + while (i < 255) do + begin + Move(seed1, bigseed[i], 4); {NB move actually copies data} + Move(seed2, bigseed[i+4], 4); + i := i + 8; + end; + + for i := 0 to 255 do S[i]:= i; + + j := 0; + for i := 0 to 255 do + begin + j := (j + S[i] + bigseed[i] + (alg_answer And $FF)) Mod 256; + temp := S[i]; + S[i] := S[j]; + S[j] := temp; + end; + i := 0; + j := 0; + for k := 0 to length-1 do + begin + i := (i + 1) Mod 256; + j := (j + S[i] + ((alg_answer shr 8) And $FF)) Mod 256; + temp := S[i]; + S[i] := S[j]; + S[j] := temp; + t := (S[i] + S[j] + ((alg_answer shr 16) And $FF)) Mod 256; + data^ := data^ xor S[t]; + Inc(data); + end; +end; + +{ ************************** ProtCheckEnc ************************************ } +{ We encrypt the DRIS passed to the API. + Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. } +Function ProtCheckEnc : LongInt; +var + dris: drisType; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); { NB this also fills seed1, seed2 with random values } + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= PROTECTION_CHECK; { standard protection check } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!! you should separate from DDProtCheck for greater security } + + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!! you should separate from DDProtCheck for greater security } + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + ShowMessage('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.'); + result := -1; + exit; + end; + + if (dris.prodcode <> AnsiString(MY_PRODCODE)) then + begin + ShowMessage('Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.'); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + ShowMessage('Dinkey Dongle protection error.'); + result := -1; + exit; + end; +end; + +{ ************************** ProtCheckWithAlgEnc ******************************** } +{ NB for this to work you must program at least "user algorithm" into the dongle + NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite copy source code from DinkeyLook. + We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd.} +Function ProtCheckWithAlgEnc : LongInt; +var + dris: drisType; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); { NB this also fills seed1, seed2, var_a...var_h with random values } + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= EXECUTE_ALGORITHM; { standard protection check & execute algorithm } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.alg_number := 1; { execute algorithm 1 - you do not need to specify this field if you are only using Lite models} + { you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random } + dris.var_a := 1; { sample values } + dris.var_b := 2; + dris.var_c := 3; + dris.var_d := 4; + dris.var_e := 5; + dris.var_f := 6; + dris.var_g := 7; + dris.var_h := 8; + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + ShowMessage('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.'); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + ShowMessage('Dinkey Dongle protection error.'); + result := -1; + exit; + end; + + { if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd } + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) <> dris.alg_answer) then + begin + ShowMessage('Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine'); + result := -1; + exit; + end; +end; + +{ ************************** WriteBytesEnc************************************** } +{ This writes the Data 012...9 to the dongle data area at offset 7 + In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd.} +Function WriteBytesEnc : LongInt; +var + dris: drisType; + DataToWrite : packed array[0..9] of byte; + alg_ans, i: longint; + +begin + for i := 0 to 9 do + DataToWrite[i] := i; + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); { NB this also fills seed1, seed2, var_a...var_h with random values } + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= WRITE_DATA_AREA; { standard protection check & write data} + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.rw_offset := 7; + dris.rw_length := SizeOf(DataToWrite); + dris.rw_data_ptr := Addr(DataToWrite); + + { calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm } + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + { encrypt data we want to write } + CryptApiData(@DataToWrite, SizeOf(DataToWrite), dris.seed1, dris.seed2, alg_ans); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + ShowMessage('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.'); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + ShowMessage('Dinkey Dongle protection error.'); + result := -1; + exit; + end; +end; + +{ ************************** ReadBytesEnc *************************************** } +{ This reads 10 bytes of data from offset 7 in the dongle data area + In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd.} +Function ReadBytesEnc : LongInt; +var + dris: drisType; + DataToRead : packed array[0..9] of byte; + display : string; + alg_ans, i: longint; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); { NB this also fills seed1, seed2, var_a...var_h with random values } + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= READ_DATA_AREA; { standard protection check & write data} + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.rw_offset := 7; + dris.rw_length := SizeOf(DataToRead); + dris.rw_data_ptr := Addr(DataToRead); + + { calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm } + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + ShowMessage('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.'); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + ShowMessage('Dinkey Dongle protection error.'); + result := -1; + exit; + end; + + { decrypt data that was read } + CryptApiData(@DataToRead, SizeOf(DataToRead), dris.seed1, dris.seed2, alg_ans); + display := 'Dinkey Dongle data area contains: '; + for i:=0 to 9 do + display := display + IntToStr(DataToRead[i]) + ' '; + ShowMessage(display); +end; + +{ ************************** EncryptUserDataEnc ******************************* } +{ This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 + It will then do another protection & decrypt the data. + We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd.} +Function EncryptUserDataEnc : LongInt; +var + dris: drisType; + display : string; + DataBytes : packed array[0..9] of byte; + alg_ans,i : LongInt; + +begin + for i := 0 to 9 do + DataBytes[i] := i; { initialise data to 0,1,2,3,4,5,6,7,8,9} + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); { NB this also fills seed1, seed2, var_a...var_h with random values } + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= ENCRYPT_USER_DATA; { standard protection check & encrypt data } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.data_crypt_key_num := 1; + dris.rw_length := SizeOf(DataBytes); + dris.rw_data_ptr := Addr(DataBytes); + + { calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm } + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + { encrypt data we want to write } + CryptApiData(@DataBytes, Sizeof(DataBytes), dris.seed1, dris.seed2, alg_ans); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... } + + { Now decrypt the same data to get the original values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= DECRYPT_USER_DATA; { standard protection check & decrypt data } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.data_crypt_key_num := 1; + dris.rw_length := SizeOf(DataBytes); + dris.rw_data_ptr := Addr(DataBytes); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + ShowMessage('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.'); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + ShowMessage('Dinkey Dongle protection error.'); + result := -1; + exit; + end; + + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + { decrypt data that was read } + CryptApiData(@DataBytes, SizeOf(DataBytes), dris.seed1, dris.seed2, alg_ans); + display := 'Data decrypted by dongle is: '; + for i:=0 to 9 do + display := display + IntToStr(DataBytes[i]) + ' '; + ShowMessage(display); +end; + +{ *************** code that gets executed on startup *********************** } +begin + {call the function(s) of your choice here - in this example I have chosen a standard protection check} + if (ProtCheck() <> 0) then + halt; +end. + diff --git a/Dinkey Pro 7.6.1/Samples/Delphi/FireMonkey/Runtime/dris.pas b/Dinkey Pro 7.6.1/Samples/Delphi/FireMonkey/Runtime/dris.pas new file mode 100644 index 0000000..1c777d8 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Delphi/FireMonkey/Runtime/dris.pas @@ -0,0 +1,108 @@ +{ !! this file should not be modified } +unit dris; + +interface + + TYPE + drisType = packed record + { the first 4 fields are never encrypted } + header : array[0..3] of AnsiChar; { should be set to DRIS } + { inputs } + size : FixedInt; { size of this structure } + seed1 : FixedInt; { seed for data/dris encryption } + seed2 : FixedInt; { as above } + { maybe encrypted from now on } + myfunction : FixedInt; { specify only one function. NB can't name it "function" as it is a reserved keyword } + flags : FixedInt; { options for the function selected. To use more than one OR them together: OPTION1 or OPTION2... } + execs_decrement : FixedUint; { amount by which to dec execs if we use flag: DEC_MANY_EXECS } + data_crypt_key_num : FixedInt; { number of the key (1-3) that the dongle uses to encrypt or decrypt user data } + rw_offset : FixedInt; { offset in the dongle data area to read or write data } + rw_length : FixedInt; { length of data are to read/write/encrypt/decrypt } + rw_data_ptr : Pbyte; { pointer to data to write / be read } + alt_licence_name : array[0..255] of AnsiChar; { protection check for different licence instead of the default one, must be null-terminated } + var_a : FixedInt; { variable values for user algorithm } + var_b : FixedInt; + var_c : FixedInt; + var_d : FixedInt; + var_e : FixedInt; + var_f : FixedInt; + var_g : FixedInt; + var_h : FixedInt; + alg_number : FixedInt; { the number of the user algorithm that you want to execute } + { outputs } + ret_code : FixedInt; { return code from the protection check } + ext_err : FixedInt; { extended error } + dongle_type : FixedInt; { type of dongle detected. 1 = Pro, 2 = FD. NB "type" is a reserved word so I use dongle_type } + model : FixedInt; { model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited } + sdsn : FixedInt; { Software Developer's Serial Number } + prodcode : array[0..11] of AnsiChar; { Product Code (null-terminated) } + dongle_number : FixedUInt; + update_number : FixedInt; + data_area_size : FixedUint; { size of the data area in the dongle detected } + max_alg_num : FixedInt; { the maximum algorithm number in the dongle detected } + execs : FixedInt; { executions left: -1 indicates 'no limit' } + exp_day : FixedInt; { expiry day: -1 indicates 'no limit' } + exp_month : FixedInt; { expiry month: -1 indicates 'no limit' } + exp_year : FixedInt; { expiry year: -1 indicates 'no limit' } + features : FixedUint; { features value } + net_users : FixedInt; { maximum number of network users for the dongle detected: -1 indicates 'no limit' } + alg_answer : FixedInt; { answer to the user algorithm executed with the given variable values } + fd_capacity : FixedUint; { capacity of the data area in FD dongle. Currently fixed at ~10MB but may change in the future. } + fd_drive : array[0..127] of AnsiChar; { drive letter of FD dongle detected (if any) 'f:\' } + swkey_type : FixedInt; { 0 = no swkey detected, 1 = temporary software key, 2 = demo software key } + swkey_exp_day : FixedInt; { software key expiry date (if software key detected) } + swkey_exp_month : FixedInt; + swkey_exp_year : FixedInt; + end; + + TYPE + nu_infoType = packed record + licenceName : array[0..255] of AnsiChar; + userName : array[0..49] of AnsiChar; + computerName : array[0..255] of AnsiChar; + ipAddress : array[0..15] of AnsiChar; + end; + + { function constants - specify one only } + const PROTECTION_CHECK = 1; { checks for dongle, check program params... } + const EXECUTE_ALGORITHM = 2; { protection check + calculate answer for specified algorithm with specified inputs } + const WRITE_DATA_AREA = 3; { protection check + writes dongle data area } + const READ_DATA_AREA = 4; { protection check + reads dongle data area } + const ENCRYPT_USER_DATA = 5; { protection check + the dongle will encrypt user data } + const DECRYPT_USER_DATA = 6; { protection check + the dongle will decrypt user data } + const FAST_PRESENCE_CHECK = 7; { checks for the presence of the correct dongle only with minimal security, no flags allowed. } + const STOP_NET_USER = 8; { stops a network user (a protection check is NOT performed) } + + { flag constants - can specify more than one } + const DEC_ONE_EXEC = 1; { decrement execs by 1 } + const DEC_MANY_EXECS = 2; { decrement execs by number specified in execs_decrement } + const START_NET_USER = 4; { starts a network user } + const USE_FUNCTION_ARGUMENT = 16; { use the extra argument in the function for pointers } + const CHECK_LOCAL_FIRST = 32; { always look in local ports before looking in network ports } + const CHECK_NETWORK_FIRST = 64; { always look on the network before looking in local ports } + const USE_ALT_LICENCE_NAME = 128; { use name specified in alt_licence_name instead of the default one } + const DONT_SET_MAXDAYS_EXPIRY = 256; { if the max days expiry date has not been calculated then do not do it this time } + const MATCH_DONGLE_NUMBER = 512; { restrict the search to match the dongle number specified in the DRIS } + const DONT_RETURN_FD_DRIVE = 1024; { if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS } + +{$IFDEF WIN32} + function DDProtCheck( dris, data:pointer ):FixedInt; stdcall; external 'dpwin32.dll'; + function DDGetNetUserList(licence_name:PAnsiChar; num_net_users:PFixedInt; nu_info:pointer; num_info_structs:FixedInt; extended_error:PFixedInt):FixedInt; stdcall; external 'dpwin32.dll'; +{$ENDIF} +{$IFDEF WIN64} + function DDProtCheck( dris, data:pointer ):FixedInt; stdcall; external 'dpwin64.dll'; + function DDGetNetUserList(licence_name:PAnsiChar; num_net_users:PFixedInt; nu_info:pointer; num_info_structs:FixedInt; extended_error:PFixedInt):FixedInt; stdcall; external 'dpwin64.dll'; +{$ENDIF} +{$IFDEF MACOS32} + function DDProtCheck( dris, data:pointer ):FixedInt; cdecl; external 'dpmac32.dylib' name '_DDProtCheck'; + function DDGetNetUserList(licence_name:PAnsiChar; num_net_users:PFixedInt; nu_info:pointer; num_info_structs:FixedInt; extended_error:PFixedInt):FixedInt; cdecl; external 'dpmac32.dylib' name '_DDGetNetUserList'; +{$ENDIF} +{$IFDEF MACOS64} + function DDProtCheck( dris, data:pointer ):FixedInt; cdecl; external 'dpmac64.dylib'; + function DDGetNetUserList(licence_name:PAnsiChar; num_net_users:PFixedInt; nu_info:pointer; num_info_structs:FixedInt; extended_error:PFixedInt):FixedInt; cdecl; external 'dpmac64.dylib'; +{$ENDIF} + +implementation + +end. + diff --git a/Dinkey Pro 7.6.1/Samples/Delphi/VCL/DinkeyChange/Change.dfm b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/DinkeyChange/Change.dfm new file mode 100644 index 0000000..e0f9177 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/DinkeyChange/Change.dfm @@ -0,0 +1,151 @@ +object ChangeForm: TChangeForm + Left = 192 + Top = 107 + Width = 345 + Height = 658 + Caption = 'ChangeTest' + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + OldCreateOrder = False + PixelsPerInch = 96 + TextHeight = 13 + object Label1: TLabel + Left = 16 + Top = 72 + Width = 123 + Height = 13 + Caption = 'Enter Diagnostic filename:' + end + object Label2: TLabel + Left = 16 + Top = 168 + Width = 120 + Height = 13 + Caption = 'Enter short Update Code:' + end + object Label3: TLabel + Left = 16 + Top = 264 + Width = 146 + Height = 13 + Caption = 'Enter path to Update Code file:' + end + object Label4: TLabel + Left = 8 + Top = 528 + Width = 165 + Height = 13 + Caption = 'Demo Software Key Product Code:' + end + object DiagInfo: TButton + Left = 64 + Top = 24 + Width = 209 + Height = 25 + Caption = 'Get Dongle Information' + TabOrder = 0 + OnClick = DiagInfoClick + end + object DiagFilename: TEdit + Left = 16 + Top = 88 + Width = 305 + Height = 21 + TabOrder = 1 + end + object WriteDiags: TButton + Left = 72 + Top = 120 + Width = 193 + Height = 25 + Caption = 'Write Diagnostics to File' + TabOrder = 2 + OnClick = WriteDiagsClick + end + object UpdateCodeString: TEdit + Left = 16 + Top = 184 + Width = 305 + Height = 21 + TabOrder = 3 + end + object DoUpdateCodeString: TButton + Left = 72 + Top = 216 + Width = 193 + Height = 25 + Caption = 'Make Changes' + TabOrder = 4 + OnClick = DoUpdateCodeStringClick + end + object UpdateCodeFile: TEdit + Left = 16 + Top = 280 + Width = 305 + Height = 21 + TabOrder = 5 + end + object DoUpdateCodeFile: TButton + Left = 72 + Top = 312 + Width = 193 + Height = 25 + Caption = 'Make Changes' + TabOrder = 6 + OnClick = DoUpdateCodeFileClick + end + object RestoreFDLite: TButton + Left = 72 + Top = 368 + Width = 193 + Height = 25 + Caption = 'Restore FD Lite' + TabOrder = 7 + OnClick = DoRestoreFDLiteClick + end + object GetMachineID: TButton + Left = 16 + Top = 424 + Width = 145 + Height = 25 + Caption = 'Get Machine ID' + TabOrder = 8 + OnClick = DoGetMachineIDClick + end + object DownloadTempSWKey: TButton + Left = 56 + Top = 480 + Width = 225 + Height = 25 + Caption = 'Download Temporary Software Key' + TabOrder = 9 + OnClick = DoDownloadTempSWKeyClick + end + object ShowMachineID: TEdit + Left = 168 + Top = 424 + Width = 153 + Height = 21 + TabOrder = 10 + end + object DownloadDemoSWKey: TButton + Left = 56 + Top = 576 + Width = 225 + Height = 25 + Caption = 'Download Demo Software Key' + TabOrder = 11 + OnClick = DoDownloadDemoSWKeyClick + end + object SwkeyProdCode: TEdit + Left = 8 + Top = 544 + Width = 305 + Height = 21 + TabOrder = 12 + end +end diff --git a/Dinkey Pro 7.6.1/Samples/Delphi/VCL/DinkeyChange/Change.pas b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/DinkeyChange/Change.pas new file mode 100644 index 0000000..036a8bb --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/DinkeyChange/Change.pas @@ -0,0 +1,340 @@ +unit Change; + +interface + +uses + Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, + Dialogs, StdCtrls; + +type + TChangeForm = class(TForm) + DiagInfo: TButton; + Label1: TLabel; + DiagFilename: TEdit; + WriteDiags: TButton; + UpdateCodeString: TEdit; + Label2: TLabel; + DoUpdateCodeString: TButton; + UpdateCodeFile: TEdit; + Label3: TLabel; + DoUpdateCodeFile: TButton; + RestoreFDLite: TButton; + GetMachineID: TButton; + DownloadTempSWKey: TButton; + ShowMachineID: TEdit; + DownloadDemoSWKey: TButton; + SwkeyProdCode: TEdit; + Label4: TLabel; + procedure DiagInfoClick(Sender: TObject); + procedure WriteDiagsClick(Sender: TObject); + procedure DoUpdateCodeStringClick(Sender: TObject); + procedure DoUpdateCodeFileClick(Sender: TObject); + procedure DoRestoreFDLiteClick(Sender: TObject); + procedure DoGetMachineIDClick(Sender: TObject); + procedure DoDownloadTempSWKeyClick(Sender: TObject); + procedure DoDownloadDemoSWKeyClick(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + ChangeForm: TChangeForm; + + { constants } + const MAX_USB_DEVICES = 128; { maximum number of USB devices that can be attached to the system at one time } + const MAX_PRODCODE_LEN = 8; { maximum length of a Product Code } + + { mask values } + const TYPE_MASK_PRO = 1; + const TYPE_MASK_FD = 2; + const TYPE_MASK_ALL = TYPE_MASK_PRO or TYPE_MASK_FD; + + const MODEL_MASK_LITE = 1; + const MODEL_MASK_PLUS = 2; + const MODEL_MASK_NET = 4; + const MODEL_MASK_ALL = MODEL_MASK_LITE or MODEL_MASK_PLUS or MODEL_MASK_NET; + const MODEL_MASK_DEFAULT = MODEL_MASK_PLUS or MODEL_MASK_NET; + + { type values for DCGetInfo (returned in the array) } + const TYPE_PRO = 1; + const TYPE_FD = 2; + + { model values for DCGetInfo (returned in the array) } + const MODEL_LITE = 1; + const MODEL_PLUS = 2; + const MODEL_NET5 = 4; + const MODEL_NETU = 7; + + { model values for DCDownloadDemoSoftwareKey } + const SWKEY_MODEL_DEFAULT = -1; { NB this assumes that the Demo Software Key Template was created with only one valid dongle model } + const SWKEY_MODEL_PRO_LITE = 0; + const SWKEY_MODEL_PRO_PLUS = 1; + const SWKEY_MODEL_PRO_NET = 2; + const SWKEY_MODEL_FD_LITE = 3; + const SWKEY_MODEL_FD_PLUS = 4; + const SWKEY_MODEL_FD_NET = 5; + + { functions exported by DinkeyChange.dll } +{$IFDEF WIN32} + function DCGetInfo(type_mask, model_mask:LongInt; prodcode_mask:PAnsiChar; array_length:LongInt; num_found:PLongInt; type_array,model_array:pointer; prodcode_array:pointer; dongle_number_array:pointer; update_number_array: pointer) : LongInt; stdcall; external 'DinkeyChange.dll'; + function DCGetDiagnosticInfo(filename: PAnsiChar): LongInt; stdcall; external 'DinkeyChange.dll'; + function DCDoUpdateCodeString(UpdateCodeString: PAnsiChar; confirmation_code, extended_error: PLongInt): LongInt; stdcall; external 'DinkeyChange.dll'; + function DCDoUpdateCodeFromFile(filename: PAnsiChar; confirmation_code, extended_error: PLongInt): LongInt; stdcall; external 'DinkeyChange.dll'; + function DCRestoreDinkeyFDLite(): LongInt; stdcall; external 'DinkeyChange.dll'; + function DCGetMachineID(machineID:PLongWord; extended_error:PLongInt): LongInt; stdcall; external 'DinkeyChange.dll'; + function DCDownloadTempSoftwareKey(machineID:LongWord; extended_error:PLongInt): LongInt; stdcall; external 'DinkeyChange.dll'; + function DCDownloadDemoSoftwareKey(machineID:LongWord; prodcode: PAnsiChar; model: LongInt; extended_error:PLongInt): LongInt; stdcall; external 'DinkeyChange.dll'; +{$ELSE} + function DCGetInfo(type_mask, model_mask:LongInt; prodcode_mask:PAnsiChar; array_length:LongInt; num_found:PLongInt; type_array,model_array:pointer; prodcode_array:pointer; dongle_number_array:pointer; update_number_array: pointer) : LongInt; stdcall; external 'DinkeyChange64.dll'; + function DCGetDiagnosticInfo(filename: PAnsiChar): LongInt; stdcall; external 'DinkeyChange64.dll'; + function DCDoUpdateCodeString(UpdateCodeString: PAnsiChar; confirmation_code, extended_error: PLongInt): LongInt; stdcall; external 'DinkeyChange64.dll'; + function DCDoUpdateCodeFromFile(filename: PAnsiChar; confirmation_code, extended_error: PLongInt): LongInt; stdcall; external 'DinkeyChange64.dll'; + function DCRestoreDinkeyFDLite(): LongInt; stdcall; external 'DinkeyChange64.dll'; + function DCGetMachineID(machineID:PLongWord; extended_error:PLongInt): LongInt; stdcall; external 'DinkeyChange64.dll'; + function DCDownloadTempSoftwareKey(machineID:LongWord; extended_error:PLongInt): LongInt; stdcall; external 'DinkeyChange64.dll'; + function DCDownloadDemoSoftwareKey(machineID:LongWord; prodcode: PAnsiChar; model: LongInt; extended_error:PLongInt): LongInt; stdcall; external 'DinkeyChange64.dll'; +{$ENDIF} + +implementation + +{$R *.dfm} + +{ displays messages for the most common errors when updating the code. + You will want to change this for your code } +procedure DisplayError(ret_code, extended_error:integer); +var + display : string; +begin + case ret_code of + 401: display := 'Error! No dongles detected that meet the search criteria.'; + 409: display := 'Error! The dongle detected has not been programmed by DinkeyAdd.'; + 758: display := 'Error! Cannot open the Update Code file specified.'; + 759: display := 'Error! The file specified is not a valid Update Code file.'; + 762..764: display := 'Error! Update Code is not in a correct format / update code file is corrupt.'; + 765: display := 'Error! The Update Code does not match any dongle attached to your machine.'; + 766: display := 'Error! The update number for this Update Code is too high. You need to first enter an update code that was previously sent to you.'; + 767: display := 'Error! You have already entered this Update Code.'; + 1905: display := 'Error! There is no Software Key available for download.'; + 1907: display := 'Error! The Temporary Software Key has expired. Cannot download it.'; + 1910: display := 'Error! The Software Key has already been downloaded.'; + 1921: display := 'Error! You specified the default model but there is more than one model available. You need to specify a specific dongle model.'; + 1922: display := 'Error! The model you requested is not available.'; + 1923: display := 'Error! The Demo Software Key Template has been disabled.'; + 1924: display := 'Error! You have run out of Demo Software Key activations. You need to order some more.'; + else + display := 'An error occurred checking the dongle. Error: ' + IntToStr(ret_code) + '. Extended Error code: ' + IntToStr(extended_error); + end; + messagedlg(display, mtError, [mbok], 0); +end; + +procedure TChangeForm.DiagInfoClick(Sender: TObject); +var + i : Integer; + sType, sModel, sProdCode, display : string; + ret_code, num_found : LongInt; + type_array, model_array, update_number_array: packed array[0..(MAX_USB_DEVICES-1)] of LongInt; + dongle_number_array: packed array[0..(MAX_USB_DEVICES-1)] of LongWord; + prodcode_array: packed array[0..(MAX_USB_DEVICES-1)] of packed array[0..MAX_PRODCODE_LEN] of AnsiChar; +begin + +{ find dongle information for all dongle types, Plus & Net models, for all product codes + NB In practice you will probably want to set the prodcode_mask to the value of your product code } + + ret_code := DCGetInfo(TYPE_MASK_ALL, MODEL_MASK_DEFAULT, nil, MAX_USB_DEVICES, @num_found, @type_array, @model_array, @prodcode_array, @dongle_number_array, @update_number_array); + +{ check error code and display error if an error occurs } + if (ret_code = 401) then + begin + messagedlg('No dongles detected matching the search criteria specified', mtError, [mbok], 0); + exit; + end + else if (ret_code <> 0) then + begin + messagedlg('Error ' + IntToStr(ret_code) + ' getting dongle information', mtError, [mbok], 0); + exit; + end; + +{ display info from the dongle detected } + display := ''; + for i := 0 to num_found-1 do + begin + { get type of dongle } + if (type_array[i] = TYPE_PRO) then + sType := 'Pro' + else + sType := 'FD'; + + { get model of dongle } + if (model_array[i] = MODEL_LITE) then + sModel := 'Lite' + else if (model_array[i] = MODEL_PLUS) then + sModel := 'Plus' + else + sModel := 'Net'; + + sProdCode := String(prodcode_array[i]); + + display := display + IntToStr(i+1) + '. Dinkey ' + sType + ' ' + sModel + ' with dongle number: ' + IntToStr(dongle_number_array[i]) + + ', product code: ' + sProdCode + ', update number: ' + IntToStr(update_number_array[i]) + #13#10; + end; + messagedlg(display, mtInformation, [mbok], 0); + +end; + +{ write dongle diagnostics to file } +procedure TChangeForm.WriteDiagsClick(Sender: TObject); +var + ret_code: longInt; + diag_file : array[0..255] of AnsiChar; + +begin + StrPCopy(diag_file, AnsiString(DiagFilename.Text)); { to get a null-terminated string } + ret_code := DCGetDiagnosticInfo(@diag_file); + + { check error code and display error if an error occurs } + if (ret_code = 754) then + begin + messagedlg('Could not create the diagnostic file. Please check that the path exists: ' + DiagFileName.Text, mtError, [mbok], 0); + exit; + end + else if (ret_code <> 0) then + begin + messagedlg('Error ' + IntToStr(ret_code) + 'writing diagnostic file.', mtError, [mbok], 0); + exit; + end; + + { display success } + messagedlg('Diagnostic file written successfully.', mtInformation, [mbok], 0); +end; + +{ update dongle with short update code string typed-in } +procedure TChangeForm.DoUpdateCodeStringClick(Sender: TObject); +var + ret_code, confirmation_code, extended_error: LongInt; + update_code : array[0..255] of AnsiChar; +begin + StrPCopy(update_code, AnsiString(UpdateCodeString.Text)); { to get a null-terminated string } + ret_code := DCDoUpdateCodeString(@update_code, @confirmation_code, @extended_error); + + if (ret_code <> 0) then + begin + DisplayError(ret_code, extended_error); + exit; + end; + + messagedlg('Dongle updated successfully!' + #13#10 + 'Confirmation code is : ' + IntToHex(confirmation_code, 4), mtInformation, [mbok], 0); +end; + +{ update dongle with update code in file specified } +procedure TChangeForm.DoUpdateCodeFileClick(Sender: TObject); +var + ret_code, confirmation_code, extended_error: LongInt; + update_code_file : array[0..255] of AnsiChar; +begin + StrPCopy(update_code_file, AnsiString(UpdateCodeFile.Text)); { to get a null-terminated string } + ret_code := DCDoUpdateCodeFromFile(@update_code_file, @confirmation_code, @extended_error); + + if (ret_code <> 0) then + begin + DisplayError(ret_code, extended_error); + exit; + end; + + messagedlg('Dongle updated successfully!' + #13#10 + 'Confirmation code is : ' + IntToHex(confirmation_code, 4), mtInformation, [mbok], 0); +end; + +{ attempt to restore Dinkey FD Lite dongle } +procedure TChangeForm.DoRestoreFDLiteClick(Sender: TObject); +var + ret_code: LongInt; +begin + ret_code := DCRestoreDinkeyFDlite(); + + if (ret_code <> 0) then + begin + DisplayError(ret_code, 0); + exit; + end; + + messagedlg('Dinkey FD Lite dongle restored successfully!', mtInformation, [mbok], 0); +end; + +{ Get Machine ID (for use with Temporary Software Key) } +procedure TChangeForm.DoGetMachineIDClick(Sender: TObject); +var + ret_code, extended_error: LongInt; + machineID: LongWord; +begin + ret_code := DCGetMachineID(@machineID, @extended_error); + + if (ret_code <> 0) then + begin + DisplayError(ret_code, extended_error); + exit; + end; + {don't display mesage, just display the Machine ID } + ShowMachineID.Text := IntToHex(machineID, 8); +end; + +{ Download Temporary Software Key } +procedure TChangeForm.DoDownloadTempSWKeyClick(Sender: TObject); +var + ret_code, extended_error: LongInt; + machineID: LongWord; +begin + { first get the machine ID... } + ret_code := DCGetMachineID(@machineID, @extended_error); + + if (ret_code <> 0) then + begin + DisplayError(ret_code, extended_error); + exit; + end; + + { ... then try to download the temporary software key } + ret_code := DCDownloadTempSoftwareKey(machineID, @extended_error); + + if (ret_code <> 0) then + begin + DisplayError(ret_code, extended_error); + exit; + end; + + messagedlg('Temporary Software Key Downloaded Successfully!', mtInformation, [mbok], 0); +end; + +{ Download Demo Software Key } +procedure TChangeForm.DoDownloadDemoSWKeyClick(Sender: TObject); +var + ret_code, extended_error: LongInt; + machineID: LongWord; + prodcode : array[0..9] of AnsiChar; +begin + { first get the machine ID... } + ret_code := DCGetMachineID(@machineID, @extended_error); + + if (ret_code <> 0) then + begin + DisplayError(ret_code, extended_error); + exit; + end; + + { ... then try to download the demo software key } + { NB we are assuming only one dongle model is set in the Demo Software Template. } + { If multiple models are set you will also need to specify the exact model } + StrPCopy(prodcode, AnsiString(SwkeyProdCode.Text)); { to get a null-terminated string } + ret_code := DCDownloadDemoSoftwareKey(machineID, @prodcode, SWKEY_MODEL_DEFAULT, @extended_error); + + if (ret_code <> 0) then + begin + DisplayError(ret_code, extended_error); + exit; + end; + + messagedlg('Demo Software Key Downloaded Successfully!', mtInformation, [mbok], 0); +end; + +end. + diff --git a/Dinkey Pro 7.6.1/Samples/Delphi/VCL/DinkeyChange/ChangeTest.dpr b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/DinkeyChange/ChangeTest.dpr new file mode 100644 index 0000000..ded649e --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/DinkeyChange/ChangeTest.dpr @@ -0,0 +1,13 @@ +program ChangeTest; + +uses + Forms, + Change in 'Change.pas' {ChangeForm}; + +{$R *.res} + +begin + Application.Initialize; + Application.CreateForm(TChangeForm, ChangeForm); + Application.Run; +end. diff --git a/Dinkey Pro 7.6.1/Samples/Delphi/VCL/DinkeyChange/README.txt b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/DinkeyChange/README.txt new file mode 100644 index 0000000..7cdd06e --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/DinkeyChange/README.txt @@ -0,0 +1,22 @@ +ChangeTest - sample code to call DinkeyChange.dll in Delphi +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Delphi 6 but will also work in more recent versions +(they will upgrade the Project to the latest version). + +The sample code contains 7 functions. Just use which ever functions are most +appropriate and customise in your own way. The sample code is just a guide. +As none of the parameters are sensitive then there is no need to implement +strong security in calling DinkeyChange. + +It is also recommended that you rename DinkeyChange.dll to a name of your choice. In +this case you will need to modify the dll name in the change.pas file. + +Important Note - you will not be able to debug your program after our API has been called. +Our strong anti-debug code will cause the debugger to throw an exception. You will also +not be able to run your program from the development platform either as Delphi still has +the Debugger running. You should run it instead from My Computer or from the command line. + +However, if you do need to debug your code you can use our debug module for DinkeyChange: +DinkeyChangeDebug.dll. So, you can use DinkeyChange.dll for your release build +and DinkeyChangeDebug.dll for your debug build. \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/ObjTest.dpr b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/ObjTest.dpr new file mode 100644 index 0000000..2f81441 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/ObjTest.dpr @@ -0,0 +1,14 @@ +program ObjTest; + +uses + Forms, + apitest in 'apitest.pas' {Form1}, + dris in 'dris.pas'; + +{$R *.res} + +begin + Application.Initialize; + Application.CreateForm(TForm1, Form1); + Application.Run; +end. diff --git a/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/README.txt b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/README.txt new file mode 100644 index 0000000..8768650 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/README.txt @@ -0,0 +1,97 @@ +Sample code to call Runtime modules in Delphi +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Delphi 6 but will work in more recent versions +(they will upgrade the Project to the latest version. For Delphi XE or earlier +you will need to delete the reference to System.UITypes). + +If you want to create multi-platform or multi-device applications please use +the FireMonkey projects instead. + +The source files in the project are: + +File name Description +apitest.pas main source code file for Delphi +dris.pas contains DRIS structure definition and other definitions. +apitest.dfm +ObjTest.dpr project file + +The idea is to include the dris.pas file in your project and use/modify which ever +functions from apitest.pas you feel are appropriate. + +This sample can also compile to 64-bit code (if your version of Delphi supports 64-bit +code i.e. Delphi XE2 and higher). Just Add the 64-bit Platform to the project. + +In order for the projects to compile without modification we have also installed in +this folder the relevant object modules for Delphi: + +dpwin32_omf.obj for 32-bit builds +dpwin64_delphi.obj for 64-bit builds + +The sample code will detect whether you are building in 32-bit or 64-bit and compile +the appropriate Windows module. + +The sample code contains 11 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. However, you should +still display or log any error codes returned by the protection check otherwise you will not +be able to identify the cause of the error. (You can look up error codes in our knowledge +base: microcosm.com/kb). + +The project currently links with our static protection modules. If you want to link to +our dynamic protection modules instead (dpwin32.dll or dpwin64.dll) then you need +to modify dris.pas as follows: + +1) Modify the declarations of DDProtCheck and DDGetNetUserList so that they refer + to the appropriate runtime DLL. + +2) Delete the code that links the object module. + +We have made these changes and put them in a file called dris_for_dll.pas. +Use this in your project instead of dris.pas. + +It is also recommended that you rename dpwin32.dll to a name of your choice. In +this case you will need to modify the dll name in the dris.pas file. + +Note - if you link the static module dpwin32_omf.obj then you should protect your program. +If you are linking to dpwin32.dll then you need to protect dpwin32.dll and *not* your program. +Because your program is linked to the DLL it is protected. The protected DLL will need to be +in the same folder as your compiled program for it to run correctly. + +Debug Modules +~~~~~~~~~~~~~~ +Note - once your program (or dpwin32.dll) is protected you will not be able to debug +your program - after our API has been called. Our strong anti-debug code will cause +the debugger to throw an exception. You will also not be able to run your program from +the development platform either as Delphi still has the Debugger running. You should run +it instead from My Computer or from the command line. If you do want to debug your code +then you can use our debug module: dpwin32_omf_debug.obj (or dpwin32debug.dll), but these +should not be used for release. + +You could setup your project so that your code links the debug module during your debug build +and the standard module when you produce your release code. + +Note: the debug module has the following restrictions: + +1) It will not correctly start a network user (network dongles only). However, other than that + the protection check will function correctly and return success. +2) You will not be able to encrypt the DRIS. (If you do encrypt the DRIS in your release build + then you should make sure that CryptDRIS does not get called in your debug build). +3) The protection check will take slightly longer than normal. +4) The DDGetNetUserList function will return error 428 (not implemented). +5) A temporary subprocess is created which may be (falsely) detected as malicious by anti-virus + programs. diff --git a/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/apitest.dfm b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/apitest.dfm new file mode 100644 index 0000000..206c931 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/apitest.dfm @@ -0,0 +1,29 @@ +object Form1: TForm1 + Left = 386 + Top = 317 + Width = 372 + Height = 265 + Caption = 'Form1' + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + OldCreateOrder = False + PixelsPerInch = 96 + TextHeight = 13 + object Label1: TLabel + Left = 104 + Top = 88 + Width = 146 + Height = 37 + Caption = 'It Worked!' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -32 + Font.Name = 'MS Sans Serif' + Font.Style = [] + ParentFont = False + end +end diff --git a/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/apitest.pas b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/apitest.pas new file mode 100644 index 0000000..dd6889a --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/apitest.pas @@ -0,0 +1,874 @@ +unit apitest; + +interface + +uses + Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, + Dialogs, StdCtrls, System.UITypes, { !!!! for Delphi XE and earlier remove System.UITypes } + dris; { contains the DRIS structure declaration } + +type + TForm1 = class(TForm) + Label1: TLabel; + private + { Private declarations } + public + { Public declarations } + end; + +var + Form1: TForm1; + +implementation + +{$R *.dfm} + +{ !! We strongly recommend that you read the "readme.txt" file in the sample code folder. + !! It contains important instructions on how to use the sample code } + +{ The sample code contains 11 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. To choose which function +this code uses see the startup code at the bottom of this file. + +this file contains 11 protection-check functions. + longint ProtCheck(); a standard protection check + longint ProtCheckWithAlg(); a protection check & executing an Algorithm + longint WriteBytes(); a protection check & write data to the dongle + longint ReadBytes(); a protection check & read data from the dongle + longint EncryptUserData(); a protection check & encrypting data and then decrypting the data + +these functions are the same as the functions listed above but encrypting all parameters passed to our API + longint ProtCheckEnc(); a standard protection check + longint ProtCheckWithAlgEnc(); a protection check & executing an Algorithm + longint WriteBytesEnc(); a protection check & write data to the dongle + longint ReadBytesEnc(); a protection check & read data from the dongle + longint EncryptUserDataEnc(); a protection check & encrypting data and then decrypting the data + + longint DisplayNetUsers(net_users, model); this function displays the current network users + + If you are using Dinkey Lite then you can only use 4 functions: +ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + } + +const MY_SDSN = 10101; { !!!! change this value to be the value of your SDSN (demo = 10101) } +const MY_PRODCODE = 'DEMO'; + +{ this procedure initialises the DRIS with random bytes } +procedure random_set(data: PByte; length: integer); +var + i : integer; +begin + Randomize(); + for i := 0 to length-1 do + begin + data^ := Random(256); + Inc(data); { increment the pointer so we can access the next byte } + end; +end; + +{ displays messages for the most common errors. You will want to change this for your code } +procedure DisplayError(ret_code, extended_error:integer); +var + display : string; +begin + case ret_code of + 401: display := 'Error! No dongles detected!'; + 403: display := 'Error! The dongle detected has a different type to the one specified in DinkeyAdd.'; + 404: display := 'Error! The dongle detected has a different model to those specified in DinkeyAdd.'; + 409: display := 'Error! The dongle detected has not been programmed by DinkeyAdd.'; + 410: display := 'Error! The dongle detected has a different Product Code to the one specified in DinkeyAdd.'; + 411: display := 'Error! The dongle detected does not contain the licence associated with this program.'; + 413: display := 'Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual.'; + 417: display := 'Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.'; + 423: display := 'Error! The number of network users has been exceeded.'; + 435: display := 'Error! DinkeyServer has not been detected on the network.'; + 922: display := 'Error! The Software Key has expired.'; + else + display := 'An error occurred checking the dongle. Error: ' + IntToStr(ret_code) + '. Extended Error code: ' + IntToStr(extended_error); + end; + messagedlg(display, mtError, [mbok], 0); +end; + +{ ************************* our 11 functions follow *************************** } + +{ *********************** DisplayNetUsers ******************************* } +{ This function displays the current network users (for DinkeyNet only). + The DDProtCheck function must be called before this function is called. + (Normally you would use DinkeyServer to view the network users but this enables you to do it from the client if you want) } +Function DisplayNetUsers (net_users, model : LongInt) : LongInt; +var + display : string; + nu_info: packed array[0..99] of nu_infoType; { !!!! this assumes that you will display max. 100 net users } + i, max_net_users, num_net_users, extended_error : LongInt; + +begin + if (net_users = -1) then + begin + max_net_users := 100; { if unlimited network users are allowed then display up to 100 users (for example) If you want more than 1000 net users you need to change the value above} + end + else + begin + max_net_users := net_users; + end; + + if (net_users = 0) then { no network users are allowed, so nothing to do! } + begin + result := 0; + exit; + end; + + if (model < 3) then + begin + messagedlg('A network dongle has not been detected. Therefore you cannot display the network users.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { now get net users } + result := DDGetNetUserList(NIL, @num_net_users, @nu_info, max_net_users, @extended_error); + + if (result <> 0) then + begin + messagedlg('Error ' + IntToStr(result) + '/' + IntToStr(extended_error) + ' finding network user information.', mtError, [mbok], 0); + end + else + begin + display:= 'number of net users: ' + IntToStr(num_net_users) + #13#10; + for i := 0 to num_net_users-1 do + begin + display := display + IntToStr(i+1) + '. licence: ' + String(nu_info[i].licenceName) + ', user: ' + String(nu_info[i].userName) + + ', computer: ' + String(nu_info[i].computerName) + ', ipaddress: ' + String(nu_info[i].ipAddress) + #13#10; + end; + messagedlg(display, mtInformation, [mbok], 0); + end; +end; + +{ ************************** ProtCheck *************************************** } +Function ProtCheck : LongInt; +var + dris: drisType; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= PROTECTION_CHECK; { standard protection check } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + messagedlg('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.', mtError, [mbok], 0); + result := -1; + exit; + end; + + if (dris.prodcode <> AnsiString(MY_PRODCODE)) then + begin + messagedlg('Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + messagedlg('Dinkey Dongle protection error.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { if you are using a network dongle and you want to list the network users then use this function: } + { DisplayNetUsers(dris.net_users, dris.model); } +end; + +{ ************************** ProtCheckWithAlg ******************************** } +{ !!!! You should replace this function with the one generated by the + "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm). +If you are using Dinkey Lite the copy the source code from DinkeyLook } +Function MyAlgorithm(a,b,c,d,e,f,g,h:LongInt):LongInt; +begin + MyAlgorithm:= a + b + c + d + e + f + g + h; +end; + +{ NB for this to work you must program at least "user algorithm" into the dongle + NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite copy source code from DinkeyLook} +Function ProtCheckWithAlg : LongInt; +var + dris: drisType; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= EXECUTE_ALGORITHM; { standard protection check & execute algorithm } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.alg_number := 1; { execute algorithm 1 (you do not need to specify this field if you are only using Lite models) } + { you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random } + dris.var_a := 1; { sample values } + dris.var_b := 2; + dris.var_c := 3; + dris.var_d := 4; + dris.var_e := 5; + dris.var_f := 6; + dris.var_g := 7; + dris.var_h := 8; + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + messagedlg('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + messagedlg('Dinkey Dongle protection error.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd } + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) <> dris.alg_answer) then + begin + messagedlg('Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine', mtError, [mbok], 0); + result := -1; + exit; + end; +end; + +{ ************************** WriteBytes *************************************** } +{ This writes the Data "Hello, World" to the dongle data area at offset 7 + In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. } + +Function WriteBytes : LongInt; +var + dris: drisType; + DataToWrite : array[0..13] of AnsiChar; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= WRITE_DATA_AREA; { standard protection check & write data} + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.rw_offset := 7; + dris.rw_length := 13; + DataToWrite := 'Hello, World!'; { string to write } + dris.rw_data_ptr := Addr(DataToWrite); + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + messagedlg('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + messagedlg('Dinkey Dongle protection error.', mtError, [mbok], 0); + result := -1; + exit; + end; +end; + +{ ************************** ReadBytes *************************************** } +{ This reads 14 bytes of data from offset 7 in the dongle data area + In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. + In order for the data to be displayed properly by this routine it will need to be text data } +Function ReadBytes : LongInt; +var + dris: drisType; + DataToRead : array[0..13] of AnsiChar; + display : string; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= READ_DATA_AREA; { standard protection check & write data} + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.rw_offset := 7; + dris.rw_length := 13; { we will add null termination after reading } + dris.rw_data_ptr := Addr(DataToRead); + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + messagedlg('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + messagedlg('Dinkey Dongle protection error.', mtError, [mbok], 0); + result := -1; + exit; + end; + + DataToRead[13] := Chr(0); { null end of string } + display := 'Dinkey Dongle data area contains: ' + DataToRead; + messagedlg(display, mtInformation, [mbok], 0); +end; + +{ ************************** EncryptUserData ********************************** } +{ This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 + It will then do another protection check & decrypt the data } +Function EncryptUserData : LongInt; +var + dris: drisType; + display : string; + DataString : array[0..13] of AnsiChar; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= ENCRYPT_USER_DATA; { standard protection check & encrypt data } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.data_crypt_key_num := 1; + dris.rw_length := 13; + DataString := 'Hello, World!'; { string to encrypt } + dris.rw_data_ptr := Addr(DataString); + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... } + + { Now decrypt the same data to get the original values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= DECRYPT_USER_DATA; { standard protection check & decrypt data } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.data_crypt_key_num := 1; + dris.rw_length := 13; + dris.rw_data_ptr := Addr(DataString); + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + messagedlg('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + messagedlg('Dinkey Dongle protection error.', mtError, [mbok], 0); + result := -1; + exit; + end; + + DataString[13] := Chr(0); { null end of string } + display := 'Decrypted data is: ' + DataString; + messagedlg(display, mtInformation, [mbok], 0); +end; + +{!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! + In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" + in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm + but the code can be modified easily to use the 3 encryption parameters. } + +{ !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm } +Function MyRWAlgorithm(a,b,c,d,e,f,g,h:LongInt):LongInt; +begin + MyRWAlgorithm:= a xor b xor c xor d xor e xor f; +end; + +{ !!!! please overwrite this function with the one generated by DinkeyAdd } +procedure CryptDRIS(dris : PByte; seed1,seed2 : Longword); +var + i,j,k : Integer; + bigseed,S : packed array[0..255] of byte; + temp,t : byte; +begin + i := 0; + while (i < 255) do + begin + Move(seed1, bigseed[i], 4); {NB move actually copies data} + Move(seed2, bigseed[i+4], 4); + i := i + 8; + end; + + for i := 0 to 255 do S[i]:= i; + + j := 0; + for i := 0 to 255 do + begin + j := (j + S[i] + bigseed[i] + 123) Mod 256; + temp := S[i]; + S[i] := S[j]; + S[j] := temp; + end; + i := 0; + j := 0; + Inc(dris, 16); {the first part of the DRIS is not encrypted} + for k := 16 to SizeOf(drisType)-1 do + begin + i := (i + 1) Mod 256; + j := (j + S[i] + 212) Mod 256; + temp := S[i]; + S[i] := S[j]; + S[j] := temp; + t := (S[i] + S[j] + 97) Mod 256; + dris^ := dris^ xor S[t]; + Inc(dris); + end; +end; +{ !!!! please overwrite this function with the one generated by DinkeyAdd } +procedure CryptApiData(data : pbyte; length : integer; seed1,seed2 : Longword; alg_answer: LongInt); +var + i,j,k : Integer; + bigseed,S : packed array[0..255] of byte; + temp,t : byte; +begin + i := 0; + while (i < 255) do + begin + Move(seed1, bigseed[i], 4); {NB move actually copies data} + Move(seed2, bigseed[i+4], 4); + i := i + 8; + end; + + for i := 0 to 255 do S[i]:= i; + + j := 0; + for i := 0 to 255 do + begin + j := (j + S[i] + bigseed[i] + (alg_answer And $FF)) Mod 256; + temp := S[i]; + S[i] := S[j]; + S[j] := temp; + end; + i := 0; + j := 0; + for k := 0 to length-1 do + begin + i := (i + 1) Mod 256; + j := (j + S[i] + ((alg_answer shr 8) And $FF)) Mod 256; + temp := S[i]; + S[i] := S[j]; + S[j] := temp; + t := (S[i] + S[j] + ((alg_answer shr 16) And $FF)) Mod 256; + data^ := data^ xor S[t]; + Inc(data); + end; +end; + +{ ************************** ProtCheckEnc ************************************ } +{ We encrypt the DRIS passed to the API. + Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. } +Function ProtCheckEnc : LongInt; +var + dris: drisType; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); { NB this also fills seed1, seed2 with random values } + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= PROTECTION_CHECK; { standard protection check } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!! you should separate from DDProtCheck for greater security } + + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!! you should separate from DDProtCheck for greater security } + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + messagedlg('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.', mtError, [mbok], 0); + result := -1; + exit; + end; + + if (dris.prodcode <> AnsiString(MY_PRODCODE)) then + begin + messagedlg('Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + messagedlg('Dinkey Dongle protection error.', mtError, [mbok], 0); + result := -1; + exit; + end; +end; + +{ ************************** ProtCheckWithAlgEnc ******************************** } +{ NB for this to work you must program at least "user algorithm" into the dongle + NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite copy source code from DinkeyLook. + We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd.} +Function ProtCheckWithAlgEnc : LongInt; +var + dris: drisType; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); { NB this also fills seed1, seed2, var_a...var_h with random values } + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= EXECUTE_ALGORITHM; { standard protection check & execute algorithm } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.alg_number := 1; { execute algorithm 1 - you do not need to specify this field if you are only using Lite models} + { you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random } + dris.var_a := 1; { sample values } + dris.var_b := 2; + dris.var_c := 3; + dris.var_d := 4; + dris.var_e := 5; + dris.var_f := 6; + dris.var_g := 7; + dris.var_h := 8; + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + messagedlg('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + messagedlg('Dinkey Dongle protection error.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd } + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) <> dris.alg_answer) then + begin + messagedlg('Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine', mtError, [mbok], 0); + result := -1; + exit; + end; +end; + +{ ************************** WriteBytesEnc************************************** } +{ This writes the Data 012...9 to the dongle data area at offset 7 + In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd.} +Function WriteBytesEnc : LongInt; +var + dris: drisType; + DataToWrite : packed array[0..9] of byte; + alg_ans, i: longint; + +begin + for i := 0 to 9 do + DataToWrite[i] := i; + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); { NB this also fills seed1, seed2, var_a...var_h with random values } + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= WRITE_DATA_AREA; { standard protection check & write data} + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.rw_offset := 7; + dris.rw_length := SizeOf(DataToWrite); + dris.rw_data_ptr := Addr(DataToWrite); + + { calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm } + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + { encrypt data we want to write } + CryptApiData(@DataToWrite, SizeOf(DataToWrite), dris.seed1, dris.seed2, alg_ans); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + messagedlg('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + messagedlg('Dinkey Dongle protection error.', mtError, [mbok], 0); + result := -1; + exit; + end; +end; + +{ ************************** ReadBytesEnc *************************************** } +{ This reads 10 bytes of data from offset 7 in the dongle data area + In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd.} +Function ReadBytesEnc : LongInt; +var + dris: drisType; + DataToRead : packed array[0..9] of byte; + display : string; + alg_ans, i: longint; + +begin + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); { NB this also fills seed1, seed2, var_a...var_h with random values } + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= READ_DATA_AREA; { standard protection check & write data} + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.rw_offset := 7; + dris.rw_length := SizeOf(DataToRead); + dris.rw_data_ptr := Addr(DataToRead); + + { calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm } + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + messagedlg('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + messagedlg('Dinkey Dongle protection error.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { decrypt data that was read } + CryptApiData(@DataToRead, SizeOf(DataToRead), dris.seed1, dris.seed2, alg_ans); + display := 'Dinkey Dongle data area contains: '; + for i:=0 to 9 do + display := display + IntToStr(DataToRead[i]) + ' '; + messagedlg(display, mtInformation, [mbok], 0); +end; + +{ ************************** EncryptUserDataEnc ******************************* } +{ This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 + It will then do another protection & decrypt the data. + We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd.} +Function EncryptUserDataEnc : LongInt; +var + dris: drisType; + display : string; + DataBytes : packed array[0..9] of byte; + alg_ans,i : LongInt; + +begin + for i := 0 to 9 do + DataBytes[i] := i; { initialise data to 0,1,2,3,4,5,6,7,8,9} + { set the DRIS to have random values } + random_set(@dris, SizeOf(dris)); { NB this also fills seed1, seed2, var_a...var_h with random values } + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= ENCRYPT_USER_DATA; { standard protection check & encrypt data } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.data_crypt_key_num := 1; + dris.rw_length := SizeOf(DataBytes); + dris.rw_data_ptr := Addr(DataBytes); + + { calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm } + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + + { encrypt data we want to write } + CryptApiData(@DataBytes, Sizeof(DataBytes), dris.seed1, dris.seed2, alg_ans); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + if (result <> 0) then + begin + DisplayError(result, dris.ext_err); { display messages for any errors that have occurred } + exit; + end; + + { ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... } + + { Now decrypt the same data to get the original values } + random_set(@dris, SizeOf(dris)); + { then set the values we want to use } + Move(AnsiString('DRIS'), dris.header, 4); + dris.size:= SizeOf(dris); + dris.myfunction:= DECRYPT_USER_DATA; { standard protection check & decrypt data } + dris.flags:= 0; { no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... } + dris.data_crypt_key_num := 1; + dris.rw_length := SizeOf(DataBytes); + dris.rw_data_ptr := Addr(DataBytes); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { encrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + { call dongle-checking code } + result := DDProtCheck(@dris, NIL); + + CryptDRIS(@dris, dris.seed1, dris.seed2); { decrypt DRIS - !!!!you should separate from DDProtCheck for greater security } + + { later in your code you can check other values in the DRIS... } + + if (dris.sdsn <> MY_SDSN) then + begin + messagedlg('Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.', mtError, [mbok], 0); + result := -1; + exit; + end; + + { later on in your program you can check the return code again } + if (dris.ret_code <> 0) then + begin + messagedlg('Dinkey Dongle protection error.', mtError, [mbok], 0); + result := -1; + exit; + end; + + alg_ans := MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h); + { decrypt data that was read } + CryptApiData(@DataBytes, SizeOf(DataBytes), dris.seed1, dris.seed2, alg_ans); + display := 'Data decrypted by dongle is: '; + for i:=0 to 9 do + display := display + IntToStr(DataBytes[i]) + ' '; + messagedlg(display, mtInformation, [mbok], 0); +end; + +{ *************** code that gets executed on startup *********************** } +begin + {call the function(s) of your choice here - in this example I have chosen a standard protection check} + if (ProtCheck() <> 0) then + halt; +end. + diff --git a/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/dpwin32_omf.obj b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/dpwin32_omf.obj new file mode 100644 index 0000000..bbf3f76 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/dpwin32_omf.obj differ diff --git a/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/dpwin64_delphi.obj b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/dpwin64_delphi.obj new file mode 100644 index 0000000..6ff67c1 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/dpwin64_delphi.obj differ diff --git a/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/dris.pas b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/dris.pas new file mode 100644 index 0000000..0eb91b3 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/dris.pas @@ -0,0 +1,102 @@ +{ !! this file should not be modified } +unit dris; + +interface + +uses Windows; + + TYPE + drisType = packed record + { the first 4 fields are never encrypted } + header : array[0..3] of AnsiChar; { should be set to DRIS } + { inputs } + size : longint; { size of this structure } + seed1 : longint; { seed for data/dris encryption } + seed2 : longint; { as above } + { maybe encrypted from now on } + myfunction : longint; { specify only one function. NB can't name it "function" as it is a reserved keyword } + flags : longint; { options for the function selected. To use more than one OR them together: OPTION1 or OPTION2... } + execs_decrement : longword; { amount by which to dec execs if we use flag: DEC_MANY_EXECS } + data_crypt_key_num : longint; { number of the key (1-3) that the dongle uses to encrypt or decrypt user data } + rw_offset : longint; { offset in the dongle data area to read or write data } + rw_length : longint; { length of data are to read/write/encrypt/decrypt } + rw_data_ptr : Pbyte; { pointer to data to write / be read } + alt_licence_name : array[0..255] of AnsiChar; { protection check for different licence instead of the default one, must be null-terminated } + var_a : longint; { variable values for user algorithm } + var_b : longint; + var_c : longint; + var_d : longint; + var_e : longint; + var_f : longint; + var_g : longint; + var_h : longint; + alg_number : longint; { the number of the user algorithm that you want to execute } + { outputs } + ret_code : longint; { return code from the protection check } + ext_err : longint; { extended error } + dongle_type : longint; { type of dongle detected. 1 = Pro, 2 = FD. NB "type" is a reserved word so I use dongle_type } + model : longint; { model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited } + sdsn : longint; { Software Developer's Serial Number } + prodcode : array[0..11] of AnsiChar; { Product Code (null-terminated) } + dongle_number : longword; + update_number : longint; + data_area_size : longword; { size of the data area in the dongle detected } + max_alg_num : longint; { the maximum algorithm number in the dongle detected } + execs : longint; { executions left: -1 indicates 'no limit' } + exp_day : longint; { expiry day: -1 indicates 'no limit' } + exp_month : longint; { expiry month: -1 indicates 'no limit' } + exp_year : longint; { expiry year: -1 indicates 'no limit' } + features : longword; { features value } + net_users : longint; { maximum number of network users for the dongle detected: -1 indicates 'no limit' } + alg_answer : longint; { answer to the user algorithm executed with the given variable values } + fd_capacity : longword; { capacity of the data area in FD dongle. Currently fixed at ~10MB but may change in the future. } + fd_drive : array[0..127] of AnsiChar; { drive letter of FD dongle detected (if any) 'f:\' } + swkey_type : longint; { 0 = no swkey detected, 1 = temporary software key, 2 = demo software key } + swkey_exp_day : longint; { software key expiry date (if software key detected) } + swkey_exp_month : longint; + swkey_exp_year : longint; + end; + + TYPE + nu_infoType = packed record + licenceName : array[0..255] of AnsiChar; + userName : array[0..49] of AnsiChar; + computerName : array[0..255] of AnsiChar; + ipAddress : array[0..15] of AnsiChar; + end; + + { function constants - specify one only } + const PROTECTION_CHECK = 1; { checks for dongle, check program params... } + const EXECUTE_ALGORITHM = 2; { protection check + calculate answer for specified algorithm with specified inputs } + const WRITE_DATA_AREA = 3; { protection check + writes dongle data area } + const READ_DATA_AREA = 4; { protection check + reads dongle data area } + const ENCRYPT_USER_DATA = 5; { protection check + the dongle will encrypt user data } + const DECRYPT_USER_DATA = 6; { protection check + the dongle will decrypt user data } + const FAST_PRESENCE_CHECK = 7; { checks for the presence of the correct dongle only with minimal security, no flags allowed. } + const STOP_NET_USER = 8; { stops a network user (a protection check is NOT performed) } + + { flag constants - can specify more than one } + const DEC_ONE_EXEC = 1; { decrement execs by 1 } + const DEC_MANY_EXECS = 2; { decrement execs by number specified in execs_decrement } + const START_NET_USER = 4; { starts a network user } + const USE_FUNCTION_ARGUMENT = 16; { use the extra argument in the function for pointers } + const CHECK_LOCAL_FIRST = 32; { always look in local ports before looking in network ports } + const CHECK_NETWORK_FIRST = 64; { always look on the network before looking in local ports } + const USE_ALT_LICENCE_NAME = 128; { use name specified in alt_licence_name instead of the default one } + const DONT_SET_MAXDAYS_EXPIRY = 256; { if the max days expiry date has not been calculated then do not do it this time } + const MATCH_DONGLE_NUMBER = 512; { restrict the search to match the dongle number specified in the DRIS } + const DONT_RETURN_FD_DRIVE = 1024; { if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS } + + { runtime api functions} + function DDProtCheck( dris, data:pointer ):LongInt; stdcall; external; + function DDGetNetUserList(licence_name:PAnsiChar; num_net_users:PLongInt; nu_info:pointer; num_info_structs:LongInt; extended_error:PLongInt):LongInt; stdcall; external; + +implementation + +{$IFDEF WIN32} + {$L dpwin32_omf.obj} +{$ELSE} + {$L dpwin64_delphi.obj} +{$ENDIF} + +end. diff --git a/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/dris_for_dll.pas b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/dris_for_dll.pas new file mode 100644 index 0000000..dbf4646 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Delphi/VCL/Runtime/dris_for_dll.pas @@ -0,0 +1,100 @@ +{ !! this file should not be modified } +unit dris; + +interface + +uses Windows; + + TYPE + drisType = packed record + { the first 4 fields are never encrypted } + header : array[0..3] of AnsiChar; { should be set to DRIS } + { inputs } + size : longint; { size of this structure } + seed1 : longint; { seed for data/dris encryption } + seed2 : longint; { as above } + { maybe encrypted from now on } + myfunction : longint; { specify only one function. NB can't name it "function" as it is a reserved keyword } + flags : longint; { options for the function selected. To use more than one OR them together: OPTION1 or OPTION2... } + execs_decrement : longword; { amount by which to dec execs if we use flag: DEC_MANY_EXECS } + data_crypt_key_num : longint; { number of the key (1-3) that the dongle uses to encrypt or decrypt user data } + rw_offset : longint; { offset in the dongle data area to read or write data } + rw_length : longint; { length of data are to read/write/encrypt/decrypt } + rw_data_ptr : Pbyte; { pointer to data to write / be read } + alt_licence_name : array[0..255] of AnsiChar; { protection check for different licence instead of the default one, must be null-terminated } + var_a : longint; { variable values for user algorithm } + var_b : longint; + var_c : longint; + var_d : longint; + var_e : longint; + var_f : longint; + var_g : longint; + var_h : longint; + alg_number : longint; { the number of the user algorithm that you want to execute } + { outputs } + ret_code : longint; { return code from the protection check } + ext_err : longint; { extended error } + dongle_type : longint; { type of dongle detected. 1 = Pro, 2 = FD. NB "type" is a reserved word so I use dongle_type } + model : longint; { model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited } + sdsn : longint; { Software Developer's Serial Number } + prodcode : array[0..11] of AnsiChar; { Product Code (null-terminated) } + dongle_number : longword; + update_number : longint; + data_area_size : longword; { size of the data area in the dongle detected } + max_alg_num : longint; { the maximum algorithm number in the dongle detected } + execs : longint; { executions left: -1 indicates 'no limit' } + exp_day : longint; { expiry day: -1 indicates 'no limit' } + exp_month : longint; { expiry month: -1 indicates 'no limit' } + exp_year : longint; { expiry year: -1 indicates 'no limit' } + features : longword; { features value } + net_users : longint; { maximum number of network users for the dongle detected: -1 indicates 'no limit' } + alg_answer : longint; { answer to the user algorithm executed with the given variable values } + fd_capacity : longword; { capacity of the data area in FD dongle. Currently fixed at ~10MB but may change in the future. } + fd_drive : array[0..127] of AnsiChar; { drive letter of FD dongle detected (if any) 'f:\' } + swkey_type : longint; { 0 = no swkey detected, 1 = temporary software key, 2 = demo software key } + swkey_exp_day : longint; { software key expiry date (if software key detected) } + swkey_exp_month : longint; + swkey_exp_year : longint; + end; + + TYPE + nu_infoType = packed record + licenceName : array[0..255] of AnsiChar; + userName : array[0..49] of AnsiChar; + computerName : array[0..255] of AnsiChar; + ipAddress : array[0..15] of AnsiChar; + end; + + { function constants - specify one only } + const PROTECTION_CHECK = 1; { checks for dongle, check program params... } + const EXECUTE_ALGORITHM = 2; { protection check + calculate answer for specified algorithm with specified inputs } + const WRITE_DATA_AREA = 3; { protection check + writes dongle data area } + const READ_DATA_AREA = 4; { protection check + reads dongle data area } + const ENCRYPT_USER_DATA = 5; { protection check + the dongle will encrypt user data } + const DECRYPT_USER_DATA = 6; { protection check + the dongle will decrypt user data } + const FAST_PRESENCE_CHECK = 7; { checks for the presence of the correct dongle only with minimal security, no flags allowed. } + const STOP_NET_USER = 8; { stops a network user (a protection check is NOT performed) } + + { flag constants - can specify more than one } + const DEC_ONE_EXEC = 1; { decrement execs by 1 } + const DEC_MANY_EXECS = 2; { decrement execs by number specified in execs_decrement } + const START_NET_USER = 4; { starts a network user } + const USE_FUNCTION_ARGUMENT = 16; { use the extra argument in the function for pointers } + const CHECK_LOCAL_FIRST = 32; { always look in local ports before looking in network ports } + const CHECK_NETWORK_FIRST = 64; { always look on the network before looking in local ports } + const USE_ALT_LICENCE_NAME = 128; { use name specified in alt_licence_name instead of the default one } + const DONT_SET_MAXDAYS_EXPIRY = 256; { if the max days expiry date has not been calculated then do not do it this time } + const MATCH_DONGLE_NUMBER = 512; { restrict the search to match the dongle number specified in the DRIS } + const DONT_RETURN_FD_DRIVE = 1024; { if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS } + +{$IFDEF WIN32} + function DDProtCheck( dris, data:pointer ):LongInt; stdcall; external 'dpwin32.dll'; + function DDGetNetUserList(licence_name:PAnsiChar; num_net_users:PLongInt; nu_info:pointer; num_info_structs:LongInt; extended_error:PLongInt):LongInt; stdcall; external 'dpwin32.dll'; +{$ELSE} + function DDProtCheck( dris, data:pointer ):LongInt; stdcall; external 'dpwin64.dll'; + function DDGetNetUserList(licence_name:PAnsiChar; num_net_users:PLongInt; nu_info:pointer; num_info_structs:LongInt; extended_error:PLongInt):LongInt; stdcall; external 'dpwin64.dll'; +{$ENDIF} + +implementation + +end. diff --git a/Dinkey Pro 7.6.1/Samples/Excel/DPSample.xls b/Dinkey Pro 7.6.1/Samples/Excel/DPSample.xls new file mode 100644 index 0000000..11e3985 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/Excel/DPSample.xls differ diff --git a/Dinkey Pro 7.6.1/Samples/Excel/DinkeyPro.bas b/Dinkey Pro 7.6.1/Samples/Excel/DinkeyPro.bas new file mode 100644 index 0000000..8edd116 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Excel/DinkeyPro.bas @@ -0,0 +1,149 @@ +Attribute VB_Name = "DinkeyPro" + +' A VBA Interface to the Dinkey Pro/FD API + +' *********************** +' DO NOT MODIFY THIS FILE +' *********************** + +Option Explicit + +' ------------------------------------------------------------------------------ +' Windows API functions used by this module + +#If VBA7 Then + Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long) +#Else + Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long) +#End If + +' ------------------------------------------------------------------------------ +' Dinkey Runtime Information Structure (DRIS) + +Type DRIS + header As String * 4 ' should be set to "DRIS" + ' Inputs + size As Long ' size of this structure + seed1 As Long ' seed for data/dris encryption + seed2 As Long ' as above + function As Long ' specify only one function + flags As Long ' options for the function selected. To use more than one OR them together: OPTION1 Or OPTION2... + execs_decrement As Long ' amount by which to decrement execs if the DEC_MANY_EXECS flag is used + data_crypt_key_num As Long ' number of the key (1-3) that the dongle uses to encrypt or decrypt user data + rw_offset As Long ' offset in the dongle data area to read or write data + rw_length As Long ' length of data to read/write/encrypt/decrypt +#If VBA7 Then + not_used As LongPtr ' This field is a pointer used in other programming languages. 4 bytes in 32-bit Excel, 8 bytes in 64-bit Excel +#Else + not_used As Long +#End If + alt_licence_name As String * 256 ' protection check for different licence instead of this one, must be null-terminated ASCII + var_a As Long ' variable values for user algorithms + var_b As Long + var_c As Long + var_d As Long + var_e As Long + var_f As Long + var_g As Long + var_h As Long + alg_number As Long ' the number of the user algorithm that you want to execute + + ' Outputs + ret_code As Long ' the return code from the protection check + ext_err As Long ' extended error + type As Long ' type of dongle detected. Possible values shown below + model As Long ' model of dongle detected. Possible values shown below + sdsn As Long ' Software Developer's Serial Number + prodcode As String * 12 ' product code (null-terminated) + dongle_number As Long ' dongle serial number + update_number As Long + data_area_size As Long ' size of the data area in the dongle detected + max_alg_num As Long ' the maximum algorithm number in the dongle detected + execs As Long ' executions left: -1 indicates 'no limit' + exp_day As Long ' expiry day: -1 indicates 'no limit' + exp_month As Long ' expiry month: -1 indicates 'no limit' + exp_year As Long ' expiry year: -1 indicates 'no limit' + features As Long ' features value + net_users As Long ' maximum number of network users for the dongle detected: -1 indicates 'mo limit' + alg_answer As Long ' answer to the user algorithm executed with the given variable values + fd_capacity As Long ' FD dongles only- capacity of the data area. Currently fixed at ~8KB but may change in the future. + fd_drive As String * 128 ' FD dongles only - drive letter of the dongle's flash drive, e.g. "F:\" + swkey_type As Long ' 0 = no software key detected, 1 = temporary software key, 2 = demo software key + swkey_exp_day As Long ' software key expiry date (if software key detected) + swkey_exp_month As Long + swkey_exp_year As Long +End Type + +' ------------------------------------------------------------------------------ +' Useful Constants + +' Possible dris.function values +Public Const PROTECTION_CHECK = 1 ' Standard protection check +Public Const EXECUTE_ALGORITHM = 2 ' Protection check + execute an algorithm stored in the dongle +Public Const WRITE_DATA_AREA = 3 ' Protection check + write to the dongle data area +Public Const READ_DATA_AREA = 4 ' Protection check + read from the dongle data area +Public Const ENCRYPT_USER_DATA = 5 ' Protection check + use the dongle's encryption engine to encrypt your own data +Public Const DECRYPT_USER_DATA = 6 ' Protection check + the dongle will decrypt user data +Public Const FAST_PRESENCE_CHECK = 7 ' Checks for the presence of a valid dongle. Very quick but weaker security +Public Const STOP_NET_USER = 8 ' Stop a network user (a protection check is NOT performed) + +' Possible dris.flags values +Public Const DEC_ONE_EXEC = 1 ' Decrement execs by 1 +Public Const DEC_MANY_EXECS = 2 ' Decrement execs by number specified in execs +Public Const START_NET_USER = 4 ' Start a network user +Public Const USE_FUNCTION_ARGUMENT = 16 ' Use the extra argument in the function for pointers +Public Const CHECK_LOCAL_FIRST = 32 ' Force the API to look for a local dongle before a network dongle +Public Const CHECK_NETWORK_FIRST = 64 ' Force the API to look for a dongle on the network before looking in local ports +Public Const USE_ALT_LICENCE_NAME = 128 ' Use name specified in alt_licence_name instead of the default one +Public Const DONT_SET_MAXDAYS_EXPIRY = 256 ' If the max days expiry date has not been calculated then do not do it this time +Public Const MATCH_DONGLE_NUMBER = 512 ' Restrict the search to match the dongle number specified in the DRIS +Public Const DONT_RETURN_FD_DRIVE = 1024 ' if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + + +' Possible dris.type values +Public Const DONGLE_TYPE_PRO = 1 ' Dinkey Pro dongle +Public Const DONGLE_TYPE_FD = 2 ' Dinkey FD dongle + +' Possible dris.model values +Public Const DONGLE_MODEL_LITE = 1 ' Lite dongle +Public Const DONGLE_MODEL_PLUS = 2 ' Plus dongle +Public Const DONGLE_MODEL_NET5 = 4 ' Net dongle, 5 users +Public Const DONGLE_MODEL_NETU = 7 ' Net dongle, unlimited users + +' ------------------------------------------------------------------------------ +' A function to initialise the DRIS with random values + +Public Sub RandomSetDrisElements(DrisToSet As DRIS) + Dim TempDris(Len(DrisToSet)) As Byte + Dim I As Integer + + Call Randomize + + For I = 0 To Len(DrisToSet) - 1 + TempDris(I) = Int(256 * Rnd()) ' The int part of a random float 0 <= N < 256, i.e. an int between 0 and 255 + Next + + Call CopyMemory(DrisToSet, TempDris(0), Len(DrisToSet)) +End Sub + +' ------------------------------------------------------------------------------ +' This function will convert a C string returned in the DRIS to a VB string + +Function TrimCString(CString As String) As String + Dim I As Integer + I = InStr(CString, vbNullChar) ' Find position of terminating null character + TrimCString = Left(CString, I - 1) ' Return everything before that position +End Function + +' ------------------------------------------------------------------------------ +' Visual Basic for Applications only supports signed integers, +' but some DRIS fields such as dongle_number are stored as unsigned integers. +' Use this function to convert those fields to Double values + +Public Function UnsignedLongToDouble(Number As Long) As Double + If (Number < 0) Then + UnsignedLongToDouble = Number + 4294967296# + Else + UnsignedLongToDouble = Number + End If +End Function diff --git a/Dinkey Pro 7.6.1/Samples/Excel/README.html b/Dinkey Pro 7.6.1/Samples/Excel/README.html new file mode 100644 index 0000000..f536f5f --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Excel/README.html @@ -0,0 +1,267 @@ + + + + + Using Dinkey Pro/FD with Excel + + + +

Using Dinkey Pro/FD with Excel

+
+

+ The Shell protection method supports Windows executables produced by the DoneEx XCell Compiler. +

+

+ API protection checks in Excel are implemented by adding Visual Basic for Applications (VBA) code to your workbook. + The VBA module DinkeyPro.bas is used to communicate with the dongle via the appropriate API DLL + (dpwin32.dll on 32-bit Windows, dpwin64.dll on 64-bit Windows). + You should lock these DLLs with the API method using DinkeyAdd as described in the user manual, and distribute the locked DLLs with your software. +

+
+
+ +

XCell Compiler and the Shell Method

+

+ The DoneEx XCell Compiler converts an Excel workbook into an executable file (a program). + All of your data, formulas and VBA macro code are stored encrypted, which makes this method very secure. + XCell Compiler is a separate tool that must be purchased separately. + A free trial is available to allow you to evaluate its functionality before buying. +

+

+ There are a few things that you should be aware of when protecting your workbook with XCell Compiler and Dinkey Pro/FD: +

+
    +
  • +

    + You must use the XCell Compiler option Save into external storage (XSTG file). + This option means that your protected workbook's data is encrypted and securely stored in a separate file, not in the executable. + This is necessary to allow changes to your workbook to be saved, as Shell-protected executables cannot be modified. +

    +
  • +
  • +

    + If you use the Shell method background check (recommended and enabled by default), + if a background protection check fails then your protected workbook will be immediately closed without any warning messages, and any unsaved changes will be lost. +

    +
  • +
  • +

    + When a user closes your protected workbook, Excel will always ask the user if they want to save changes, even if no changes have been made. +

    +
  • +
+ +

VBA Code and the API Method

+
+

+ For a good level of security, your workbook should rely heavily on VBA code (macros). + See below for more information. +

+

+ Before you distribute your protected workbook, you must protect your VBA code against modification. + To do this: +

+
    +
  1. Open your project in the Visual Basic Editor.
  2. +
  3. Go to Tools > VBAProject Properties in the menu.
  4. +
  5. Select the Protection tab.
  6. +
  7. Enable Lock project for viewing and enter a strong password, then click OK.
  8. +
+

+ Now the workbook's VBA code cannot be viewed or modified without entering the password. +

+
+

+ Even if you have never written code before, you will probably be familiar with macros: sequences of commands and functions that you can use to automate tasks in Excel. + Excel macros are stored in modules that contain sequences of instructions in a code language known as Visual Basic for Applications, or VBA. + The terms macros and VBA are often used interchangeably. +

+

+ VBA code is a powerful and flexible tool with many uses. Unfortunately, the power of VBA means that macros created with malicious intentions can cause harm to your documents or your system. + As a result, Excel makes it possible for users to open and use workbooks with macros disabled, and to only allow the VBA code to be executed if the user trusts the owner of the workbook. + Obviously, this also prevents dongle checking code from running. + To prevent someone using this safety feature to work around the dongle protection, you should ensure that the functionality of your workbook relies heavily on macros. + That way if your workbook is opened with macros disabled, its functionality will be severely limited. +

+

+ Legitimate users of your workbook may be concerned about executing the VBA code in your workbook. + Excel allows you to certify your macros with a digital signature so that users can verify that they are from a trustworthy source (i.e. you), + and that the code has not been modified since you wrote it. See the Excel documentation for more information. +

+ +

Excel Example Files

+
    +
  • DinkeyPro.bas - a module that provides a VBA interface to the Dinkey Pro/FD API.
  • +
  • DPSample.xls - various examples of using DinkeyPro.bas.
  • +
+

+ DinkeyPro.bas should be used, without modification, in your own project. + Use File > Import File in the Visual Basic Editor to add DinkeyPro.bas + to your VBA code. +

+ +

Supported Versions

+

+ The Excel sample workbook and VBA code provided with the Dinkey Pro/FD SDK was created using Excel 2007, + and tested using Excel 2007 (32-bit) and Excel 2013 (64-bit). + All newer versions should be backwards compatible. The sample code should also work with older versions, + but no guarantees can be made, and support for older versions is likely to be very limited. +

+ +

Try It Yourself

+
+

+ The sample code is designed to teach you how to use the Dinkey Pro/FD API in Excel workbooks. + Do not copy the examples verbatim into your own code. Experiment with the sample code to understand how the API works, + and read the chapter Increasing Your Protection in the user manual for many suggestions on how to + make the best use of the API features. +

+
+

+ DPSample.xls gives simple examples of performing a protection check, + as well as using various other features of Dinkey Pro/FD. + To use DPSample.xls you will first need to use DinkeyAdd to produce a locked copy of the DLL for your platform, + and program a dongle (if you are using Plus or Net dongles). Place the locked DLL in the same folder as the example files. +

+

+ Open DPSample.xls in Excel, then open the Visual Basic Editor by pressing ALT+F11. + Browse the examples in the DPSample module to see how different features can be used. + All the examples follow the same basic pattern: +

+
    +
  1. Set up the DRIS structure with the relevant information.
  2. +
  3. Call the API.
  4. +
  5. Use the information returned in the DRIS.
  6. +
+

+ Uncomment the function calls in the RunExampleButton_Click() procedure + in the DPSample module to enable the examples of different features, + then click the Run Example button on Sheet1 of the workbook to run the examples. +

+

+ The DPSample module also demonstrates loading the appropriate DLL for your platform. +

+

+ Parts of the sample code are marked with !!!! must be customised with your own functions or values + for some features to work correctly. Not all features are supported by all dongle models. + See the user manual for more information. +

+ + diff --git a/Dinkey Pro 7.6.1/Samples/FileMaker/DinkeyPro Test.fmp12 b/Dinkey Pro 7.6.1/Samples/FileMaker/DinkeyPro Test.fmp12 new file mode 100644 index 0000000..b8689f0 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/FileMaker/DinkeyPro Test.fmp12 differ diff --git a/Dinkey Pro 7.6.1/Samples/FileMaker/README.txt b/Dinkey Pro 7.6.1/Samples/FileMaker/README.txt new file mode 100644 index 0000000..5bcc48c --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/FileMaker/README.txt @@ -0,0 +1,205 @@ +Filemaker Plug-In +~~~~~~~~~~~~~~~~~ + +We provide a Filemaker plug-in so that you can communicate with the dongle from your +filemaker database. The filemaker plugin in the Filemaker\v7 directory is compatible +with Filemaker 7-13 (and also Filemaker 14 in 32-bit mode). The plug-in in the +Filemaker\v14 directory is compatible with Filemaker 14 (64-bit only for Mac) and +higher. + +The plug-in is called: + +DinkeyPro.fmx (for 32-bit Windows) +DinkeyPro.fmx64 (for 64-bit Windows) +DinkeyPro.fmplugin (for Mac) + +To use the plug-in (as with any plug-in) you must: + +1)a) For versions of Filemaker previous to version 12: + Copy the DinkeyPro plug-in to the Extensions folder (located in the FileMaker folder) + and then launch Filemaker. + + b) For Filemaker 12 (and later) you must install the plug-in by creating a container + and running an installation script. See the DinkeyPro Test.fmp12 solution for an + example of how to do this. You should also read the Filemaker documentation on + installing plug-ins. + +2) From the menu choose Preferences (under Windows it is Edit | Preferences and + under Mac OS X it is FileMaker Pro | Preferences). Then choose the plug-ins tab. + Make sure the box "Dinkey Dongle Pro/FD Plugin" is listed and ticked. If there is a + tock box that says "All solutions to install files" then make sure it is ticked. + +3) You may want to modify the startup script (file | file options | perform script) + to check the dongle or create a field (of type calculation) that displays a value + returned by the protection check. View "external function" to see a list of all the + functions that the plug-in exports. Note - every function returns a text value. + +4) When you first use the plug-in you may get error 413. This is because you + have not protected it. To do this run DinkeyAdd and protect the plug-in file + specifying API Method. + +5) When you have finished make sure that you add FileMaker security so that a + user cannot view or modify the scripts you have added. This step does rely on + the security of the Filemaker password system, however. A better solution would + be to produce a runtime database file (you need FileMaker Advanced (used to be called + Developer Edition) to do this). + +Here is an example of some script you can use to check the protection (Please change the +version number to the current version). It is included in the DinkeyPro Test example +solution. Note: <> signifies 'not equals'. Filemaker has its own symbol for this. +You may want to do more than this so please look at all the functions in the PlugIn, +listed below): + +If [DinkeyProVersion("long") <> "Dinkey Dongle Pro/FD Plug-in 7.2.0"] + Show Custom Dialog ["Dinkey Dongle error"; "Missing or incorrect version of Plug-In."] + Exit Application +Else + #check dongle and look to see if returned values are correct + Set Variable [$ret_code; Value: DDprotCheck(0;0;"")] + If [$ret_code <> "0"] + Show Custom Dialog ["Error Detecting Dongle"; "Error " & $ret_code & " detecting dongle"] + Exit Application + Else If [DDGetSDSN(0) <> "10101"] + Show Custom Dialog ["Incorrect dongle detected"; "Contact your administrator to correct this error."] + Exit Application + Else If [DDGetProdCode(0) <> "DEMO"] + Show Custom Dialog ["Incorrect dongle detected"; "Contact your administrator to correct this error."] + Exit Application + Else + Show Custom Dialog ["Success!"; "Dongle checked successfully!"] + End If +End If + +Note you should make sure that the user cannot abort your scripts: +Allow User Abort[Off] +This is the default value anyway. + +The plug-in exports many functions. Here is a description of each function: + +Note - every function returns a "text" value. +Note - some of the functions expect dummy parameters. This is because there is + a bug with Filemaker 7 so that it will not accept functions with no parameters. +Note - you must call one of the DDProtCheck or DDProtCheckWithAlg or + DDWriteData or DDReadData functions before calling the DDGet... functions. + +DinkeyProVersion +~~~~~~~~~~~~~~~~ +Input: + string - if set to "long" returns the long description of version info + if set to "short" or the string is empty - version info + if set to "platform" - tells you if you are calling "Windows" or "Mac OS X" plug-in + +Returns version information about this plug-in. You must call this function +first to verify the Plug-In is present. This is very important because if the +Plug-In is not present then Filemaker forces the function to return 0 - which +for some functions indicates success. + + +DDProtCheck +~~~~~~~~~~~ +Input: + integer: flags (see DRIS description and flags values listed below) + integer: execs_decrement (optional) (see DRIS description) + text: alt_licence_name (optional) (see DRIS description) +Returns: + text: return code (0 = success, o.w. error number) + +This performs a standard protection check with the flags specified and is the function you +are most likely to use. Although 2 of the parameters are optional, Filemaker 7 (at least) +insists that you enter all 3 parameters. +It will return 0 for success or the dongle error code if there is a failure. + +DDProtCheckWithAlg +~~~~~~~~~~~~~~~~~~ +Input: + integer: flags (see DRIS description and flags values listed below) + integer: alg_number (number of user-defined algorithm to execute) + integers: var_a...var_h (variable values for user defined algorithm) +Returns: + text: return code (0 = success, o.w. error number) + +This performs a basic protection check and executes the specified algorithm with the +specified variable values. It will return 0 for success or the dongle error code if there is a +failure. NB to get the algorithm answer you should call DDGetAlgAnswer. + + +DDWriteData +~~~~~~~~~~~ +Input: + integer: flags (see DRIS description and flags values listed below) + integer: offset (of data area to write to) + integer: length (of data you want to write) + text: data you want to write +Returns: + text: return code (0 is success) + +This allows you to write a string to the dongle data area at the offset specified (for Dinkey 2/DinkeyNet). + + +DDReadData +~~~~~~~~~~ +Input: + integer: flags (see DRIS description and flags values listed below) + integer: offset (of data area you want to read from) + integer: length (of data you want to read) +Returns: + text: The data read (if success), otherwise it is the error code. +return code (0 is success) + +This allows you to read data from the dongle data area (for Dinkey 2/DinkeyNet). + + +After you have called either the DDProtCheck or DDProtCheckWithAlg or DDWriteData or +DDReadData functions you can call one of the following functions to get data from +the DRIS. These functions will all return -1 if a protection check has not been +performed. They will return -2 if a protection check has been performed but failed. +They all take a dummy parameter (integer) which can be any value you like (it is +ignored). They all have text outputs. Refer to the documentation regarding the DRIS +for more information on each of these fields. + +DDGetExtendedError - returns the extended error (only set if one of the protection check function has failed) +DDGetType - returns the type of dongle detected ("Pro" or "FD") +DDGetModel - returns the model of the dongle detected. Numerical value - see documentation on DRIS. +DDGetSDSN - returns the SDSN. +DDGetProdCode - returns the Product Code. +DDGetDongleNumber - returns the donglenumber +DDGetUpdateNumber - returns the update number +DDGetDataAreaSize - returns the size of the data are +DDGetMaxAlgNum - returns the maximum algorithm number in the dongle detected +DDGetExecs - returns the execs left (number or "no limit") +DDGetExpDay - returns the expiry day (number or "no limit") +DDGetExpMonth - returns the expiry month (number or "no limit") +DDGetExpYear - returns the expiry year (number or "no limit") +DDGetFeatures - returns the features value. +DDGetNetUsers - returns the maximum number of simultaneous network user allowed by the dongle (number or "no limit") +DDGetAlgAnswer - returns the answer of the Algorithm (if specified) +DDGetFDCapacity - returns the maximum capacity for the data area if an FD dongle is detected +DDGetFDDrive - returns the drive letter (mount name) of FD dongle detected e.g. f:\ +DDGetSWKeyType - returns whether a software key has been detected and what type it is +DDGetSWKeyExpDay - returns the expiry day of the swkey detected (if one has been detected) +DDGetSWKeyExpMonth - returns the expiry month of the swkey detected (if one has been detected) +DDGetSWKeyExpYear - returns the expiry year of the swkey detected (if one has been detected) + +Note - because of the limitations of the Filemaker scripting language you cannot encrypt +the DRIS or data passed to the API. + +DRIS Flags Values +~~~~~~~~~~~~~~~~~ +In general the flags value will be 0. If you want to use more than one flag then add the values. + +Value Name in Manual Description +1 DEC_ONE_EXEC decrement executions by 1 +2 DEC_MANY_EXECS decrement executions by number specified in execs_decrement +4 START_NET_USER start a network user +8 STOP_NET_USER stops a network user (a protection check is NOT performed) +16 USE_FUNCTION_ARGUMENT use the extra argument in the function to pass data +32 CHECK_LOCAL_FIRST always look for a dongle locally before looking in network ports +64 CHECK_NETWORK_FIRST always look for a network dongle before looking for a dongle locally +128 USE_ALT_LICENCE_NAME use name specified in alt_licence_name instead of the default one +256 DONT_SET_MAXDAYS_EXPIRY if the max days expiry date has not been calculated then do not do it this time +512 MATCH_DONGLE_NUMBER restrict the search to match the dongle number specified in the DRIS +1024 DONT_RETURN_FD_DRIVE if you have protected your solution to a Dinkey FD dongle then this flag + means that the flash disk drive letter or mount name will not be returned + +Filemaker7 plugin tested on filemaker version 7 (Mac and Windows 32-bit). +Filemaker14 plugin tested on Filemaker 15 (Mac and 64-bit Windows) and on Filemaker 14 (Mac 64-bit mode and Windows 32-bit) diff --git a/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/DllTest.lfproj b/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/DllTest.lfproj new file mode 100644 index 0000000..fa2e3fb --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/DllTest.lfproj @@ -0,0 +1,69 @@ + + + + Debug + 2.0 + {76ddb05e-4dea-4d83-98ce-e740d0bc7426} + Exe + DllTest + C:\Program Files (x86)\Lahey-Fujitsu Fortran\v7.2\Visual Studio 2008\Packages + DllTest.exe + False + DllTest + + + bin\Debug\ + O0 + True + False + True + True + True + MSVC + O0 + default + ..\..\C\import_libs + dpwin32.lib + -g|-ndal|-ml MSVC|-o0|-pause|-stchk|-trace|-libpath "..\..\C\import_libs"|"dpwin32.lib" + False + + + False + False + False + + + True + DllTest.exe + LF95 + + + bin\Release\ + False + True + False + MSVC + default + ..\..\C\import_libs + dpwin32.lib + -ndal|-ml MSVC|-nw|-pause|-libpath "..\..\C\import_libs"|dpwin32.lib + + + + Code + .obj + -g|-ndal|-ml MSVC|-o0|-pause|-stchk|-trace + 1 + + + + + + + + + + + + + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/DllTest.sln b/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/DllTest.sln new file mode 100644 index 0000000..d2a7b01 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/DllTest.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{B7CA1DD7-A797-4295-BB4F-1411A8008584}") = "DllTest", "DllTest.lfproj", "{76DDB05E-4DEA-4D83-98CE-E740D0BC7426}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {76DDB05E-4DEA-4D83-98CE-E740D0BC7426}.Debug|Win32.ActiveCfg = Debug|Win32 + {76DDB05E-4DEA-4D83-98CE-E740D0BC7426}.Debug|Win32.Build.0 = Debug|Win32 + {76DDB05E-4DEA-4D83-98CE-E740D0BC7426}.Release|Win32.ActiveCfg = Release|Win32 + {76DDB05E-4DEA-4D83-98CE-E740D0BC7426}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/README.txt b/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/README.txt new file mode 100644 index 0000000..8a25789 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/README.txt @@ -0,0 +1,76 @@ +Fortran Sample Code notes +~~~~~~~~~~~~~~~~~~~~~~~~~ + +We supply separate sample code for different compilers as they all seem to compile Fortran +slightly differently! In general the code is the same. The differences are in defining the +DDProtCheck function in our runtime dll and in using random_set and CryptDris functions. +The Intel compiler is much stricter and so the code is more complicated in this case +(we must use "equivalence" so we can treat the DRIS type as a byte array in some cases). + +Lahey Fortran Sample Code tested using 32-bit Lahey Fortran 7.2 and Visual Studio 2008 +Intel Fortran Sample Code tested using 32-bit and 64-bit Intel Fortran XE 2011 compiler & VS 2008 +(also tested with Intel Fortran 10.1 compiler but see note at the bottom of this file). + +g95 has some unusual restrictions such as 132 characters for a line length. Only tested +with 32-bit code. + +We have not tested with GFortran but the code should be similar to g95. + +Description of files: + +dlltest.f90 Fortran sample code for Lahey Fortran +DllTest.lfproj Visual Studio 2008 Project using Lahey Fortran +Dlltest.sln Visual Studio 2008 Solution for Lahey Fortran + +idlltest.f90 Fortran sample code for Intel Fortran +iDllTest.vfproj Visual Studio 2008 Project using Intel Fortran +iDlltest.sln Visual Studio 2008 Solution for Intel Fortran + +gdlltest.f90 Fortan code using by g95 compiler. + +The sample code contains 10 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. + +Note - you should protect dpwin32.dll and not your program. Because your program +is linked to the DLL it is protected. The protected DLL will need to be in the +same folder as your compiled program for it to run correctly. + +Note - once dpwin32.dll is protected you will not be able to debug your program - +after our API has been called. Our strong anti-debug code will cause the debugger +to throw an exception. If you do want to debug your code then you can use our debug +module: dpwin32debug.dll, but this should not be used for release. See readme.txt +in samples\c for restrictions concerning the debug module. + +Note - if you do not use Lahey/Intel Fortran or you use an earlier version of Visual Studio then +you will have to create the solution & project yourself. (Newer versions of Visual Studio will +update the project for you). It is not difficult. You have to link with the import library +(which is in Microsoft format) dpwin32.lib (so your program knows how our API functions are +formatted and the DLL name). For 64-bit compilations you link with dpwin64.lib. Both of these +files are in the Modules\import_libs folder (also in Samples\C\import_libs). You should list +this files in Project Settings | Linker | Input | Addition Dependencies. + +Note - the Lahey sample only works with 32-bit Fortran (because that is all Lahey supports currently). +The code should work with 64-bit Fortran also. However, you will have to change the "unused" element +in the DRIS to be integer(8). i.e. 8 bytes and change DRIS_SIZE to 548. + +Note - there appears to be a small bug in the 64-bit Intel 10.1 Fortran compiler. If you use this +then you need to remove the word DECORATE in the DDProtCheck function declaration. This keyword is +needed for the 32-bit compiler. + +Note - For g95 you should compile like this (for example): +g95 -Wno=101 gdlltest.f90 -B c:\c95\lib dpwin32.dll -o gDllTest.exe +(the -Wno=101 removes warnings about the EQUIVALENCE statement we have to use in the sample) diff --git a/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/dlltest.f90 b/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/dlltest.f90 new file mode 100644 index 0000000..28031db --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/dlltest.f90 @@ -0,0 +1,797 @@ +! dlltest - sample program to call DinkeyPro/FD runtime module (dpwin32.dll) +! +! this sample code has been compiled and tested using Lahey Fortran v7.2 + +! The sample code contains 10 functions. You will not need to use all these +! functions in your code. Just use which ever functions are most appropriate +! and customise in your own way. The sample code is just a guide. You should +! implement the protection in a stronger way using the techniques described in +! the "Increasing your Protection" chapter of the manual. + +!If you are using Dinkey Lite then you can only use 4 functions: +!ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + +! this file contains 10 protection-check functions. +! ProtCheck a standard protection check +! ProtCheckWithAlg a protection check & executing an algorithm +! WriteBytes a protection check & write data to the dongle +! ReadBytes a protection check & read data from the dongle +! EncryptUserData a protection check & encrypting data and then decrypting the data +! these functions are the same as the functions listed above but encrypting all parameters passed to our API +! ProtCheckEnc a standard protection check +! ProtCheckWithAlgEnc a protection check & executing an Algorithm +! WriteBytesEnc a protection check & write data to the dongle +! ReadBytesEnc a protection check & read data from the dongle +! EncryptUserDataEnc a protection check & encrypting data and then decrypting the data + +PROGRAM main + ! call the function(s) of your choice here + ! by default I have chosen a standard protection check + if (ProtCheck() == 0) then + print *,"It worked!" + end if +END PROGRAM main + +! this module contains the DRIS structure declaration and also declares important constants +MODULE DinkeyPro + + integer,parameter :: MY_SDSN = 10101 !!!! change this value to be the value of your SDSN (demo = 10101) + + ! declare dris data type + TYPE DRIS + sequence + ! the first 4 fields are never encrypted + character(len=4) :: header ! should be set to 'DRIS' + ! inputs + integer(4) :: size ! size of this structure + integer(4) :: seed1 ! seed for data/dris encryption + integer(4) :: seed2 ! as above + ! (maybe encrypted from now on) + integer(4) :: function ! specify only one function + integer(4) :: flags ! options for the function selected. To use more than one OR them together e.g. OR(OPTION1, OPTION2) + integer(4) :: execs_decrement ! amount by which to dec execs if we use flag: DEC_MANY_EXECS + integer(4) :: data_crypt_key_num ! number of the key (1-3) that the dongle uses to encrypt or decrypt user data + integer(4) :: rw_offset ! offset in the dongle data area to read or write data + integer(4) :: rw_length ! length of data are to read/write/encrypt/decrypt + integer(4) :: unused ! pass data by function parameter instead. This field should be 8 bytes long for 64-bit Fortran code + character(len=256) :: alt_licence_name ! protection check for different licence instead of the default one, must be null-terminated + integer(4) :: var_a ! variable values for user algorithm + integer(4) :: var_b + integer(4) :: var_c + integer(4) :: var_d + integer(4) :: var_e + integer(4) :: var_f + integer(4) :: var_g + integer(4) :: var_h + integer(4) :: alg_number ! the number of the user algorithm that you want to execute + + ! outputs + integer(4) :: ret_code ! return code from the protection check + integer(4) :: ext_err ! extended error + integer(4) :: type ! type of dongle detected. 1 = Pro, 2 = FD + integer(4) :: model ! model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + integer(4) :: sdsn ! Software Developer's Serial Number + character(len=12) :: prodcode ! Product Code (null-terminated) + integer(4) :: dongle_number ! NB this should be an unsigned value really + integer(4) :: update_number + integer(4) :: data_area_size ! size of the data area used in the dongle detected + integer(4) :: max_alg_num ! the maximum algorithm number in the dongle detected + integer(4) :: execs ! executions left: -1 indicates 'no limit' + integer(4) :: exp_day ! expiry day: -1 indicates 'no limit' + integer(4) :: exp_month ! expiry month: -1 indicates 'no limit' + integer(4) :: exp_year ! expiry year: -1 indicates 'no limit' + integer(4) :: features ! features value + integer(4) :: net_users ! maximum number of network users for the dongle detected: -1 indicates 'no limit' + integer(4) :: alg_answer ! answer to the user algorithm executed with the given variable values + integer(4) :: fd_capacity ! capacity of the data area in FD dongle. + character(len=128) :: fd_drive ! drive letter of FD dongle detected e.g. 'f:\' (or mount name under Linux) + integer(4) :: swkey_type ! 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + integer(4) :: swkey_exp_day ! software key expiry date (if software key detected) + integer(4) :: swkey_exp_month + integer(4) :: swkey_exp_year + END TYPE DRIS + + integer,parameter :: DRIS_SIZE = 560 ! I am sure there should be a way to get this programatically! + + ! functions - must specify only one + integer,parameter :: PROTECTION_CHECK = 1 ! checks for dongle, check program params... + integer,parameter :: EXECUTE_ALGORITHM = 2 ! protection check + calculate answer for specified algorithm with specified inputs + integer,parameter :: WRITE_DATA_AREA = 3 ! protection check + writes dongle data area + integer,parameter :: READ_DATA_AREA = 4 ! protection check + reads dongle data area + integer,parameter :: ENCRYPT_USER_DATA = 5 ! protection check + the dongle will encrypt user data + integer,parameter :: DECRYPT_USER_DATA = 6 ! protection check + the dongle will decrypt user data + integer,parameter :: FAST_PRESENCE_CHECK = 7 ! checks for the presence of the correct dongle only with minimal security, no flags allowed. + integer,parameter :: STOP_NET_USER = 8 ! stops a network user (a protection check is NOT performed) + + ! flags - can specify as many as you like + integer,parameter :: DEC_ONE_EXEC = 1 ! decrement execs by 1 + integer,parameter :: DEC_MANY_EXECS = 2 ! decrement execs by number specified in execs_decrement + integer,parameter :: START_NET_USER = 4 ! starts a network user + integer,parameter :: STOP_NET_USER = 8 ! stops a network user (a protection check is NOT performed) + integer,parameter :: USE_FUNCTION_ARGUMENT = 16 ! use the extra argument in the function for pointers + integer,parameter :: CHECK_LOCAL_FIRST = 32 ! always look in local ports before looking in network ports + integer,parameter :: CHECK_NETWORK_FIRST = 64 ! always look on the network before looking in local ports + integer,parameter :: USE_ALT_LICENCE_NAME = 128 ! use name specified in alt_licence_name instead of this program name + integer,parameter :: DONT_SET_MAXDAYS_EXPIRY = 256 ! if the max days expiry date has not been calculated then do not do it this time + integer,parameter :: MATCH_DONGLE_NUMBER = 512 ! restrict the search to match the dongle number specified in the DRIS + integer,parameter :: DONT_RETURN_FD_DRIVE = 1024 ! if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + + ! declare the protection check function in the Dinkey Pro/FD runtime module + DLL_IMPORT DDProtCheck + type (DRIS) mydris + integer DDProtCheck + +END MODULE DinkeyPro + +! ************************* our 10 functions ********************************** + +! ************************** ProtCheck *************************************** +FUNCTION ProtCheck() + use DinkeyPro + integer :: ret_code + + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = PROTECTION_CHECK ! standard protection check + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + ret_code = DDProtCheck(mydris, 0) + ProtCheck = ret_code + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn <> MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheck = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code <> 0) then + print *,"Dinkey Dongle protection error." + ProtCheck = -1 + return + end if + + ! sample to show how to display dongle number (this is the only value in the dris that should be an unsigned integer) + integer(8) :: display_dongle_number + display_dongle_number = mydris%dongle_number + call ConvertDongleNumber(display_dongle_number) + print *,"Dongle Check successful. Dongle Number is: ",display_dongle_number +END FUNCTION ProtCheck + +! ************************** ProtCheckWithAlg ****************************** + +! !!!! You should replace this function with the one generated by the +! "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) +! or from DinkeyLook if you are using a Dinkey Lite dongle. +FUNCTION MyAlgorithm(a, b, c, d, e, f, g, h) + integer :: a,b,c,d,e,f,g,h,MyAlgorithm + MyAlgorithm = a + b + c + d + e + f + g + h + return +END FUNCTION MyAlgorithm + +! NB for this to work you must program at least "user algorithm" into the dongle +! NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +! sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +! code from DinkeyLook +FUNCTION ProtCheckWithAlg() + use DinkeyPro + integer :: ret_code + + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = EXECUTE_ALGORITHM ! standard protection check & execute algorithm + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + mydris%alg_number = 1 ! execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + ! you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + mydris%var_a = 1 ! sample values + mydris%var_b = 2 + mydris%var_c = 3 + mydris%var_d = 4 + mydris%var_e = 5 + mydris%var_f = 6 + mydris%var_g = 7 + mydris%var_h = 8 + + ret_code = DDProtCheck(mydris, 0) + ProtCheckWithAlg = ret_code + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn <> MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheckWithAlg = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code <> 0) then + print *,"Dinkey Dongle protection error." + ProtCheckWithAlg = -1 + return + end if + + ! if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + ! !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) <> mydris%alg_answer) then + print *,"Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine" + ProtCheckWithAlg = -1 + return + end if +END FUNCTION ProtCheckWithAlg + +! ************************** WriteBytes *************************************** +! This writes the Data "Hello, World" to the dongle data area at offset 7 +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +FUNCTION WriteBytes() + use DinkeyPro + integer :: ret_code + character(len=*),parameter :: WriteData = "Hello, World!" + + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = WRITE_DATA_AREA ! standard protection check and write data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(WriteData) + + ret_code = DDProtCheck(mydris, WriteData) + WriteBytes = ret_code + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn <> MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + WriteBytes = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code <> 0) then + print *,"Dinkey Dongle protection error." + WriteBytes = -1 + return + end if +END FUNCTION WriteBytes + +! ************************** ReadBytes *************************************** +! This reads 14 bytes of data from offset 7 in the dongle data area +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +! In order for the data to be displayed properly by this routine it will need to be text data +FUNCTION ReadBytes() + use DinkeyPro + integer :: ret_code + character(len=14) :: ReadData + + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = READ_DATA_AREA ! standard protection check and read data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(ReadData) + + ret_code = DDProtCheck(mydris, ReadData) + ReadBytes = ret_code + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn <> MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ReadBytes = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code <> 0) then + print *,"Dinkey Dongle protection error." + ReadBytes = -1 + return + end if + + print *,"Dinkey Dongle Data area, offset 7 is: ",ReadData +END FUNCTION ReadBytes + +! ************************** EncryptUserData *************************************** +! This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +! It will then do another protection check & decrypt the data +FUNCTION EncryptUserData() + use DinkeyPro + integer :: ret_code + character(len=13) :: Data = "Hello, World!" + + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = ENCRYPT_USER_DATA ! standard protection check and encrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(Data) + + ret_code = DDProtCheck(mydris, Data) + EncryptUserData = ret_code + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + ! ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + print *,"Encrypted data is: ",Data + + ! Now decrypt the same data to get the original values + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = DECRYPT_USER_DATA ! standard protection check and decrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(Data) + + ret_code = DDProtCheck(mydris, Data) + EncryptUserData = ret_code + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn <> MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + EncryptUserData = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code <> 0) then + print *,"Dinkey Dongle protection error." + EncryptUserData = -1 + return + end if + + print *,"Decrypted data is: ",Data +END FUNCTION EncryptUserData + +! !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! +! In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" +! in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm +! but the code can be modified easily to use the 3 encryption parameters. + +! !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm +FUNCTION MyRWAlgorithm(a, b, c, d, e, f, g, h) + integer :: a,b,c,d,e,f,g,h,MyAlgorithm + MyRWAlgorithm = IEOR(IEOR(IEOR(IEOR(IEOR(a,b),c),d),e),f) + return +END FUNCTION MyRWAlgorithm + +! !!!! please patch the 3 parameters specified below with the 3 parameters specified in DinkeyAdd +SUBROUTINE CryptDRIS(dris_byte_array) + use DinkeyPro + integer(1), dimension(DRIS_SIZE) :: dris_byte_array + integer :: i,j,k,temp,t + integer, dimension(256) :: bigseed,S + + do i=1,256 + bigseed(i) = dris_byte_array(9 + modulo(i-1,8)) ! this takes the values from seed1, seed2 directly + end do + + do i=1,256 + S(i) = i-1 + end do + + j = 0 + do i=1,256 + j = IAND(j + S(i) + bigseed(i) + 123, 255) ! first parameter patched here + temp = S(i) + S(i) = S(j+1) + S(j+1) = temp + end do + + i = 0 + j = 0 + do k=17,DRIS_SIZE + i = IAND(i + 1, 255) + j = IAND(j + S(i+1) + 212, 255) ! second parameter patched here + temp = S(i+1) + S(i+1) = S(j+1) + S(j+1) = temp + t = IAND(S(i+1) + S(j+1) + 97,255) ! third parameter patched here + dris_byte_array(k) = IEOR(dris_byte_array(k),S(t+1)) + end do + return +END SUBROUTINE CryptDRIS + +! !!!! please patch the 3 parameters specified below with the 3 parameters specified in DinkeyAdd +! if you are using the r/w algorithm then there is no need to change this function +! NB we pass the whole of the DRIS but we only need it for seed1 and seed2 values +SUBROUTINE CryptApiData(data, length, dris_byte_array, alg_answer) + use DinkeyPro + integer :: length, alg_answer, seed1, seed2 + integer(1), dimension(length) :: data + integer(1), dimension(DRIS_SIZE) :: dris_byte_array + integer :: i,j,k,temp,t + integer, dimension(256) :: bigseed,S + + do i=1,256 + bigseed(i) = dris_byte_array(9 + modulo(i-1,8)) ! this takes the values from seed1, seed2 directly + end do + + do i=1,256 + S(i) = i-1 + end do + + j = 0 + do i=1,256 + j = IAND(j + S(i) + bigseed(i) + IAND(alg_answer, 255), 255) ! first parameter patched here + temp = S(i) + S(i) = S(j+1) + S(j+1) = temp + end do + + i = 0 + j = 0 + do k=1,length + i = IAND(i + 1, 255) + j = IAND(j + S(i+1) + IAND(ISHFT(alg_answer, -8),255), 255) ! second parameter patched here + temp = S(i+1) + S(i+1) = S(j+1) + S(j+1) = temp + t = IAND(S(i+1) + S(j+1) + IAND(ISHFT(alg_answer, -16),255),255) ! third parameter patched here + data(k) = IEOR(data(k),S(t+1)) + end do + return +END SUBROUTINE CryptApiData + +! ************************** ProtCheckEnc *************************************** +! We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +FUNCTION ProtCheckEnc() + use DinkeyPro + integer :: ret_code + + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = PROTECTION_CHECK ! standard protection check + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + call CryptDRIS(mydris) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, 0) + ProtCheckEnc = ret_code + + call CryptDRIS(mydris) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn <> MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheckEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code <> 0) then + print *,"Dinkey Dongle protection error." + ProtCheckEnc = -1 + return + end if +END FUNCTION ProtCheckEnc + +! ************************** ProtCheckWithAlgEnc ****************************** +! NB for this to work you must program at least "user algorithm" into the dongle +! NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +! sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +! code from DinkeyLook +! We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +FUNCTION ProtCheckWithAlgEnc() + use DinkeyPro + integer :: ret_code + + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = EXECUTE_ALGORITHM ! standard protection check & execute algorithm + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + mydris%alg_number = 1 ! execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + ! you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + mydris%var_a = 1 ! sample values + mydris%var_b = 2 + mydris%var_c = 3 + mydris%var_d = 4 + mydris%var_e = 5 + mydris%var_f = 6 + mydris%var_g = 7 + mydris%var_h = 8 + + call CryptDRIS(mydris) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, 0) + ProtCheckWithAlgEnc = ret_code + + call CryptDRIS(mydris) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn <> MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheckWithAlgEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code <> 0) then + print *,"Dinkey Dongle protection error." + ProtCheckWithAlgEnc = -1 + return + end if + + ! if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + ! !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) <> mydris%alg_answer) then + print *,"Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine" + ProtCheckWithAlgEnc = -1 + return + end if +END FUNCTION ProtCheckWithAlgEnc + +! ************************** WriteBytesEnc *************************************** +! This writes the Data "Hello, World" to the dongle data area at offset 7 +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +! We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +FUNCTION WriteBytesEnc() + use DinkeyPro + integer :: ret_code,alg_ans + character(len=*),parameter :: WriteData = "Hello, World!" + + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = WRITE_DATA_AREA ! standard protection check and write data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(WriteData) + + ! calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) + + ! encrypt data we want to write. + call CryptApiData(WriteData, len(WriteData), mydris, alg_ans); + + call CryptDRIS(mydris) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, WriteData) + WriteBytesEnc = ret_code + + call CryptDRIS(mydris) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn <> MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + WriteBytesEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code <> 0) then + print *,"Dinkey Dongle protection error." + WriteBytesEnc = -1 + return + end if +END FUNCTION WriteBytesEnc + +! ************************** ReadBytesEnc *************************************** +! This reads 14 bytes of data from offset 7 in the dongle data area +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +! In order for the data to be displayed properly by this routine it will need to be text data +! We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +FUNCTION ReadBytesEnc() + use DinkeyPro + integer :: ret_code,alg_ans + character(len=14) :: ReadData + + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = READ_DATA_AREA ! standard protection check and read data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(ReadData) + + ! calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) + + call CryptDRIS(mydris) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, ReadData) + ReadBytesEnc = ret_code + + call CryptDRIS(mydris) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn <> MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ReadBytesEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code <> 0) then + print *,"Dinkey Dongle protection error." + ReadBytesEnc = -1 + return + end if + + ! decrypt data we have just read. + call CryptApiData(ReadData, len(ReadData), mydris, alg_ans); + print *,"Dinkey Dongle Data area, offset 7 is: ",ReadData +END FUNCTION ReadBytesEnc + +! ************************** EncryptUserDataEnc *************************************** +! This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +! It will then do another protection check & decrypt the data +! We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +FUNCTION EncryptUserDataEnc() + use DinkeyPro + integer :: ret_code,alg_ans + character(len=13) :: Data = "Hello, World!" + + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = ENCRYPT_USER_DATA ! standard protection check and encrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(Data) + + ! calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) + + ! encrypt data we want to pass. + call CryptApiData(Data, len(Data), mydris, alg_ans); + + call CryptDRIS(mydris) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, Data) + EncryptUserDataEnc = ret_code + + call CryptDRIS(mydris) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + ! ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + print *,"Encrypted data is: ",Data + + ! Now decrypt the same data to get the original values + call set_random(mydris) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = DECRYPT_USER_DATA ! standard protection check and decrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(Data) + + call CryptDRIS(mydris) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, Data) + EncryptUserDataEnc = ret_code + + call CryptDRIS(mydris) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code <> 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn <> MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + EncryptUserDataEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code <> 0) then + print *,"Dinkey Dongle protection error." + EncryptUserDataEnc = -1 + return + end if + + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) + ! decrypt data that was passed to us by the API. + call CryptApiData(Data, len(Data), mydris, alg_ans); + print *,"Decrypted data is: ",Data +END FUNCTION EncryptUserDataEnc + + +! ************************** useful subroutines ******************************* +! subroutine to randomise each element of the DRIS +SUBROUTINE set_random(dris_byte_array) + use DinkeyPro + integer(1), dimension(DRIS_SIZE) :: dris_byte_array + real,dimension(DRIS_SIZE) :: temp + + call random_seed() + call random_number(temp) + do i=1,DRIS_SIZE + dris_byte_array(i) = temp(i)*256 + end do + return +END SUBROUTINE set_random + +! subroutine to convert an unsigned integer (stored as a signed integer) to the correct unsigned value (for display purposes) +! e.g. the dongle_number value in the dris - should be an unsigned integer but Fortran 90 does not support them +SUBROUTINE ConvertDongleNumber(value) + integer(8) :: value + + if (value < 0) then + value = value + 4294967296 ! make the -ve value a +ve value + end if + return +END SUBROUTINE ConvertDongleNumber + +! displays messages for the most common errors. You will want to change this for your code +SUBROUTINE DisplayError(ret_code, extended_error) + integer :: ret_code, extended_error + + select case (ret_code) + case (401) + print *,"Error! No dongles detected!" + case (403) + print *,"Error! The dongle detected has a different type to the one specified in DinkeyAdd." + case (404) + print *,"Error! The dongle detected has a different model to those specified in DinkeyAdd." + case (409) + print *,"Error! The dongle detected has not been programmed by DinkeyAdd." + case (410) + print *,"Error! The dongle detected has a different Product Code to the one specified in DinkeyAdd." + case (411) + print *,"Error! The dongle detected does not contain the licence associated with this program." + case (413) + print *,"Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual." + case (417) + print *,"Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa." + case (423) + print *,"Error! The number of network users has been exceeded." + case (435) + print *,"Error! DinkeyServer has not been detected on the network." + case (922) + print *,"Error! The Software Key has expired." + case default + print *,"An error occurred checking the dongle. Error: ", ret_code, " Extended Error: ", extended_error + end select + return +END SUBROUTINE DisplayError \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/gdlltest.f90 b/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/gdlltest.f90 new file mode 100644 index 0000000..96f383a --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/gdlltest.f90 @@ -0,0 +1,862 @@ +! dlltest - sample program to call DinkeyPro/FD runtime module (dpwin32.dll) +! +! this sample code has been compiled and tested using g95. It should also work for GFortran +! but this has not been tested + +! The sample code contains 10 functions. You will not need to use all these +! functions in your code. Just use which ever functions are most appropriate +! and customise in your own way. The sample code is just a guide. You should +! implement the protection in a stronger way using the techniques described in +! the "Increasing your Protection" chapter of the manual. + +!If you are using Dinkey Lite then you can only use 4 functions: +!ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + +! this file contains 10 protection-check functions. +! ProtCheck a standard protection check +! ProtCheckWithAlg a protection check & executing an algorithm +! WriteBytes a protection check & write data to the dongle +! ReadBytes a protection check & read data from the dongle +! EncryptUserData a protection check & encrypting data and then decrypting the data +! these functions are the same as the functions listed above but encrypting all parameters passed to our API +! ProtCheckEnc a standard protection check +! ProtCheckWithAlgEnc a protection check & executing an Algorithm +! WriteBytesEnc a protection check & write data to the dongle +! ReadBytesEnc a protection check & read data from the dongle +! EncryptUserDataEnc a protection check & encrypting data and then decrypting the data + +PROGRAM main + ! call the function(s) of your choice here + ! by default I have chosen a standard protection check + if (ProtCheck() == 0) then + print *,"It worked!" + end if +END PROGRAM main + +! this module contains the DRIS structure declaration and also declares important constants +MODULE DinkeyPro + + integer,parameter :: MY_SDSN = 10101 !!!! change this value to be the value of your SDSN (demo = 10101) + + ! declare dris data type + ! It would be nice if there were a compiler directive ensuring byte alignment for this type. I can't find one but it seems to be byte aligned anyway ;) + TYPE DRIS + sequence + ! the first 4 fields are never encrypted + character(len=4) :: header ! should be set to 'DRIS' + ! inputs + integer(4) :: size ! size of this structure + integer(4) :: seed1 ! seed for data/dris encryption + integer(4) :: seed2 ! as above + ! (maybe encrypted from now on) + integer(4) :: function ! specify only one function + integer(4) :: flags ! options for the function selected. To use more than one OR them together e.g. OR(OPTION1, OPTION2) + integer(4) :: execs_decrement ! amount by which to dec execs if we use flag: DEC_MANY_EXECS + integer(4) :: data_crypt_key_num ! number of the key (1-3) that the dongle uses to encrypt or decrypt user data + integer(4) :: rw_offset ! offset in the dongle data area to read or write data + integer(4) :: rw_length ! length of data are to read/write/encrypt/decrypt + integer(4) :: unused ! pass data by function parameter instead. 4 bytes long for 32-bit Fortran code. + character(len=256) :: alt_licence_name ! protection check for different licence instead of the default one, must be null-terminated + integer(4) :: var_a ! variable values for user algorithm + integer(4) :: var_b + integer(4) :: var_c + integer(4) :: var_d + integer(4) :: var_e + integer(4) :: var_f + integer(4) :: var_g + integer(4) :: var_h + integer(4) :: alg_number ! the number of the user algorithm that you want to execute + + ! outputs + integer(4) :: ret_code ! return code from the protection check + integer(4) :: ext_err ! extended error + integer(4) :: type ! type of dongle detected. 1 = Pro, 2 = FD + integer(4) :: model ! model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + integer(4) :: sdsn ! Software Developer's Serial Number + character(len=12) :: prodcode ! Product Code (null-terminated) + integer(4) :: dongle_number ! NB this should be an unsigned value really + integer(4) :: update_number + integer(4) :: data_area_size ! size of the data area used in the dongle detected + integer(4) :: max_alg_num ! the maximum algorithm number in the dongle detected + integer(4) :: execs ! executions left: -1 indicates 'no limit' + integer(4) :: exp_day ! expiry day: -1 indicates 'no limit' + integer(4) :: exp_month ! expiry month: -1 indicates 'no limit' + integer(4) :: exp_year ! expiry year: -1 indicates 'no limit' + integer(4) :: features ! features value + integer(4) :: net_users ! maximum number of network users for the dongle detected: -1 indicates 'no limit' + integer(4) :: alg_answer ! answer to the user algorithm executed with the given variable values + integer(4) :: fd_capacity ! capacity of the data area in FD dongle. + character(len=128) :: fd_drive ! drive letter of FD dongle detected e.g. 'f:\' (or mount name under Linux) + integer(4) :: swkey_type ! 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + integer(4) :: swkey_exp_day ! software key expiry date (if software key detected) + integer(4) :: swkey_exp_month + integer(4) :: swkey_exp_year + END TYPE DRIS + + integer,parameter :: DRIS_SIZE = 560 ! I am sure there should be a way to get this programatically! + + ! functions - must specify only one + integer,parameter :: PROTECTION_CHECK = 1 ! checks for dongle, check program params... + integer,parameter :: EXECUTE_ALGORITHM = 2 ! protection check + calculate answer for specified algorithm with specified inputs + integer,parameter :: WRITE_DATA_AREA = 3 ! protection check + writes dongle data area + integer,parameter :: READ_DATA_AREA = 4 ! protection check + reads dongle data area + integer,parameter :: ENCRYPT_USER_DATA = 5 ! protection check + the dongle will encrypt user data + integer,parameter :: DECRYPT_USER_DATA = 6 ! protection check + the dongle will decrypt user data + integer,parameter :: FAST_PRESENCE_CHECK = 7 ! checks for the presence of the correct dongle only with minimal security, no flags allowed. + integer,parameter :: STOP_NET_USER = 8 ! stops a network user (a protection check is NOT performed) + + ! flags - can specify as many as you like + integer,parameter :: DEC_ONE_EXEC = 1 ! decrement execs by 1 + integer,parameter :: DEC_MANY_EXECS = 2 ! decrement execs by number specified in execs_decrement + integer,parameter :: START_NET_USER = 4 ! starts a network user + integer,parameter :: USE_FUNCTION_ARGUMENT = 16 ! use the extra argument in the function for pointers + integer,parameter :: CHECK_LOCAL_FIRST = 32 ! always look in local ports before looking in network ports + integer,parameter :: CHECK_NETWORK_FIRST = 64 ! always look on the network before looking in local ports + integer,parameter :: USE_ALT_LICENCE_NAME = 128 ! use name specified in alt_licence_name instead of the default one + integer,parameter :: DONT_SET_MAXDAYS_EXPIRY = 256 ! if the max days expiry date has not been calculated then do not do it this time + integer,parameter :: MATCH_DONGLE_NUMBER = 512 ! restrict the search to match the dongle number specified in the DRIS + integer,parameter :: DONT_RETURN_FD_DRIVE = 1024 ! if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + + ! this is an instance of the dris. We make an equivalence between the derived-type + ! and a byte_array because for encryption we need to access the memory as a byte array + type (DRIS) :: mydris + integer(1), dimension(DRIS_SIZE) :: mydris_byte_array + equivalence(mydris, mydris_byte_array) + +END MODULE DinkeyPro + +! There is just the one function exported by dpwin32.dll +MODULE DDFunctions + use ISO_C_BINDING + implicit none + private + + ! declare the protection check function in the Dinkey Pro/FD runtime module + public DDProtCheck + INTERFACE + FUNCTION DDProtCheck(my_dris, my_data) BIND (C, name="DDProtCheck") + use iso_c_binding + use DinkeyPro +!GCC$ ATTRIBUTES STDCALL :: DDProtCheck + integer(C_INT) DDProtCheck + type (DRIS) my_dris + character(kind=C_CHAR) my_data (*) + END FUNCTION DDProtCheck + END INTERFACE +END MODULE DDFunctions + +! ************************* our 10 functions ********************************** + +! ************************** ProtCheck *************************************** +FUNCTION ProtCheck() + use DinkeyPro + use DDFunctions + integer :: ret_code + integer(8) :: display_dongle_number + + call set_random(mydris_byte_array) ! we have to call this function using the byte array equivalence of the dris type + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = PROTECTION_CHECK ! standard protection check + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + ret_code = DDProtCheck(mydris, "dummy") + ProtCheck = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheck = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ProtCheck = -1 + return + end if + + ! sample to show how to display dongle number (this is the only value in the dris that should be an unsigned integer) + display_dongle_number = mydris%dongle_number + call ConvertDongleNumber(display_dongle_number) + print *,"Dongle Check successful. Dongle Number is: ",display_dongle_number +END FUNCTION ProtCheck + +! ************************** ProtCheckWithAlg ****************************** + +! !!!! You should replace this function with the one generated by the +! "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) +! or from DinkeyLook if you are using a Dinkey Lite dongle. +FUNCTION MyAlgorithm(a, b, c, d, e, f, g, h) + integer :: a,b,c,d,e,f,g,h,MyAlgorithm + MyAlgorithm = a + b + c + d + e + f + g + h + return +END FUNCTION MyAlgorithm + +! NB for this to work you must program at least "user algorithm" into the dongle +! NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +! sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +! code from DinkeyLook +FUNCTION ProtCheckWithAlg() + use DinkeyPro + use DDFunctions + integer :: ret_code, my_alg_answer, a, b, c, d, e, f, g, h + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = EXECUTE_ALGORITHM ! standard protection check & execute algorithm + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + mydris%alg_number = 1 ! execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + ! you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + mydris%var_a = 1 ! sample values + mydris%var_b = 2 + mydris%var_c = 3 + mydris%var_d = 4 + mydris%var_e = 5 + mydris%var_f = 6 + mydris%var_g = 7 + mydris%var_h = 8 + + ret_code = DDProtCheck(mydris, "dummy") + ProtCheckWithAlg = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheckWithAlg = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ProtCheckWithAlg = -1 + return + end if + + ! if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + ! !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + a = mydris%var_a ! for some reason g95 does not execute MyAlgorithm correctly unless it is all on one line so you have to do stupid things like this + b = mydris%var_b + c = mydris%var_c + d = mydris%var_d + e = mydris%var_e + f = mydris%var_f + g = mydris%var_g + h = mydris%var_h + my_alg_answer = MyAlgorithm(a, b, c, d, e, f, g, h) + if (my_alg_answer /= mydris%alg_answer) then + print *,"Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine" + ProtCheckWithAlg = -1 + return + end if +END FUNCTION ProtCheckWithAlg + +! ************************** WriteBytes *************************************** +! This writes the Data "Hello, World" to the dongle data area at offset 7 +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +FUNCTION WriteBytes() + use DinkeyPro + use DDFunctions + integer :: ret_code + character(len=14) :: WriteData = "Hello, World!"//CHAR(0) ! it should be a null-terminated string + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = WRITE_DATA_AREA ! standard protection check and write data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(WriteData) + + ret_code = DDProtCheck(mydris, WriteData) + WriteBytes = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + WriteBytes = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + WriteBytes = -1 + return + end if +END FUNCTION WriteBytes + +! ************************** ReadBytes *************************************** +! This reads 14 bytes of data from offset 7 in the dongle data area +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +! In order for the data to be displayed properly by this routine it will need to be text data +FUNCTION ReadBytes() + use DinkeyPro + use DDFunctions + integer :: ret_code + character(len=14) :: ReadData + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = READ_DATA_AREA ! standard protection check and read data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(ReadData) + + ret_code = DDProtCheck(mydris, ReadData) + ReadBytes = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ReadBytes = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ReadBytes = -1 + return + end if + + print *,"Dinkey Dongle Data area, offset 7 is: ",ReadData +END FUNCTION ReadBytes + +! ************************** EncryptUserData *************************************** +! This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +! It will then do another protection check & decrypt the data +FUNCTION EncryptUserData() + use DinkeyPro + use DDFunctions + integer :: ret_code + character(len=14) :: MyData = "Hello, World!"//CHAR(0) + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = ENCRYPT_USER_DATA ! standard protection check and encrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(MyData) + + ret_code = DDProtCheck(mydris, MyData) + EncryptUserData = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + ! ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + print *,"Encrypted data is: ",MyData + + ! Now decrypt the same data to get the original values + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = DECRYPT_USER_DATA ! standard protection check and decrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(MyData) + + ret_code = DDProtCheck(mydris, MyData) + EncryptUserData = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + EncryptUserData = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + EncryptUserData = -1 + return + end if + + print *,"Decrypted data is: ",MyData +END FUNCTION EncryptUserData + +! !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! +! In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" +! in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm +! but the code can be modified easily to use the 3 encryption parameters. + +! !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm +FUNCTION MyRWAlgorithm(a, b, c, d, e, f, g, h) + integer :: a,b,c,d,e,f,g,h,MyAlgorithm + MyRWAlgorithm = IEOR(IEOR(IEOR(IEOR(IEOR(a,b),c),d),e),f) + return +END FUNCTION MyRWAlgorithm + +! !!!! please patch the 3 parameters specified below with the 3 parameters specified in DinkeyAdd +SUBROUTINE CryptDRIS(dris_byte_array) + use DinkeyPro + integer(1), dimension(DRIS_SIZE) :: dris_byte_array + integer :: i,j,k,temp,t + integer(1) :: temp2 + integer, dimension(256) :: bigseed,S + + do i=1,256 + bigseed(i) = dris_byte_array(9 + modulo(i-1,8)) ! this takes the values from seed1, seed2 directly + end do + + do i=1,256 + S(i) = i-1 + end do + + j = 0 + do i=1,256 + j = IAND(j + S(i) + bigseed(i) + 123, 255) ! first parameter patched here + temp = S(i) + S(i) = S(j+1) + S(j+1) = temp + end do + + i = 0 + j = 0 + do k=17,DRIS_SIZE + i = IAND(i + 1, 255) + j = IAND(j + S(i+1) + 212, 255) ! second parameter patched here + temp = S(i+1) + S(i+1) = S(j+1) + S(j+1) = temp + t = IAND(S(i+1) + S(j+1) + 97,255) ! third parameter patched here + temp2 = S(t+1) + dris_byte_array(k) = IEOR(dris_byte_array(k),temp2) + end do + return +END SUBROUTINE CryptDRIS + +! !!!! please patch the 3 parameters specified below with the 3 parameters specified in DinkeyAdd +! if you are using the r/w algorithm then there is no need to change this function +! NB we pass the whole of the DRIS but we only need it for seed1 and seed2 values +SUBROUTINE CryptApiData(mydata, length, dris_byte_array, alg_answer) + use DinkeyPro + integer :: length, alg_answer, seed1, seed2 + integer(1), dimension(length) :: mydata + integer(1), dimension(DRIS_SIZE) :: dris_byte_array + integer(1) :: temp2 + integer :: i,j,k,temp,t + integer, dimension(256) :: bigseed,S + + do i=1,256 + bigseed(i) = dris_byte_array(9 + modulo(i-1,8)) ! this takes the values from seed1, seed2 directly + end do + + do i=1,256 + S(i) = i-1 + end do + + j = 0 + do i=1,256 + j = IAND(j + S(i) + bigseed(i) + IAND(alg_answer, 255), 255) ! first parameter patched here + temp = S(i) + S(i) = S(j+1) + S(j+1) = temp + end do + + i = 0 + j = 0 + do k=1,length + i = IAND(i + 1, 255) + j = IAND(j + S(i+1) + IAND(ISHFT(alg_answer, -8),255), 255) ! second parameter patched here + temp = S(i+1) + S(i+1) = S(j+1) + S(j+1) = temp + t = IAND(S(i+1) + S(j+1) + IAND(ISHFT(alg_answer, -16),255),255) ! third parameter patched here + temp2 = S(t+1) + mydata(k) = IEOR(mydata(k),temp2) + end do + return +END SUBROUTINE CryptApiData + +! ************************** ProtCheckEnc *************************************** +! We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +FUNCTION ProtCheckEnc() + use DinkeyPro + use DDFunctions + integer :: ret_code + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = PROTECTION_CHECK ! standard protection check + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, "dummy") + ProtCheckEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheckEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ProtCheckEnc = -1 + return + end if +END FUNCTION ProtCheckEnc + +! ************************** ProtCheckWithAlgEnc ****************************** +! NB for this to work you must program at least "user algorithm" into the dongle +! NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +! sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +! code from DinkeyLook +! We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +FUNCTION ProtCheckWithAlgEnc() + use DinkeyPro + use DDFunctions + integer :: ret_code, my_alg_answer, a, b, c, d, e, f, g, h + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = EXECUTE_ALGORITHM ! standard protection check & execute algorithm + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + mydris%alg_number = 1 ! execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + ! you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + mydris%var_a = 1 ! sample values + mydris%var_b = 2 + mydris%var_c = 3 + mydris%var_d = 4 + mydris%var_e = 5 + mydris%var_f = 6 + mydris%var_g = 7 + mydris%var_h = 8 + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, "dummy") + ProtCheckWithAlgEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheckWithAlgEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ProtCheckWithAlgEnc = -1 + return + end if + + ! if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + ! !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + a = mydris%var_a ! for some reason g95 does not execute MyAlgorithm correctly unless it is all on one line so you have to do stupid things like this + b = mydris%var_b + c = mydris%var_c + d = mydris%var_d + e = mydris%var_e + f = mydris%var_f + g = mydris%var_g + h = mydris%var_h + my_alg_answer = MyAlgorithm(a, b, c, d, e, f, g, h) + if (my_alg_answer /= mydris%alg_answer) then + print *,"Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine" + ProtCheckWithAlgEnc = -1 + return + end if +END FUNCTION ProtCheckWithAlgEnc + +! ************************** WriteBytesEnc *************************************** +! This writes the Data "Hello, World" to the dongle data area at offset 7 +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +! We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +FUNCTION WriteBytesEnc() + use DinkeyPro + use DDFunctions + integer :: ret_code,alg_ans + character(len=14) :: WriteData = "Hello, World!"//CHAR(0) + integer(1), dimension(14) :: WriteDataByteArray + equivalence(WriteData, WriteDataByteArray) ! to encrypt it we need to pass it as a byte array + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = WRITE_DATA_AREA ! standard protection check and write data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(WriteData) + + ! calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g,& + mydris%var_h) + + ! encrypt data we want to write. + call CryptApiData(WriteDataByteArray, len(WriteData), mydris_byte_array, alg_ans); + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, WriteData) + WriteBytesEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + WriteBytesEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + WriteBytesEnc = -1 + return + end if +END FUNCTION WriteBytesEnc + +! ************************** ReadBytesEnc *************************************** +! This reads 14 bytes of data from offset 7 in the dongle data area +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +! In order for the data to be displayed properly by this routine it will need to be text data +! We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +FUNCTION ReadBytesEnc() + use DinkeyPro + use DDFunctions + integer :: ret_code,alg_ans + character(len=14) :: ReadData + integer(1), dimension(14) :: ReadDataByteArray + equivalence(ReadData, ReadDataByteArray) ! to encrypt it we need to pass it as a byte array + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = READ_DATA_AREA ! standard protection check and read data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(ReadData) + + ! calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g,& + mydris%var_h) + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, ReadData) + ReadBytesEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ReadBytesEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ReadBytesEnc = -1 + return + end if + + ! decrypt data we have just read. + call CryptApiData(ReadDataByteArray, len(ReadData), mydris_byte_array, alg_ans); + print *,"Dinkey Dongle Data area, offset 7 is: ",ReadData +END FUNCTION ReadBytesEnc + +! ************************** EncryptUserDataEnc *************************************** +! This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +! It will then do another protection check & decrypt the data +! We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +FUNCTION EncryptUserDataEnc() + use DinkeyPro + use DDFunctions + integer :: ret_code,alg_ans + character(len=14) :: MyData = "Hello, World!"//CHAR(0) + integer(1), dimension(14) :: MyDataByteArray + equivalence(MyData, MyDataByteArray) ! to encrypt it we need to pass it as a byte array + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = ENCRYPT_USER_DATA ! standard protection check and encrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(MyData) + + ! calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g,& + mydris%var_h) + + ! encrypt data we want to pass. + call CryptApiData(MyDataByteArray, len(MyData), mydris_byte_array, alg_ans); + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, MyData) + EncryptUserDataEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + ! ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + print *,"Encrypted data is: ",MyData + + ! Now decrypt the same data to get the original values + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = DECRYPT_USER_DATA ! standard protection check and decrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(MyData) + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, MyData) + EncryptUserDataEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + EncryptUserDataEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + EncryptUserDataEnc = -1 + return + end if + + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g,& + mydris%var_h) + ! decrypt data that was passed to us by the API. + call CryptApiData(MyDataByteArray, len(MyData), mydris_byte_array, alg_ans); + print *,"Decrypted data is: ",MyData +END FUNCTION EncryptUserDataEnc + +! ************************** useful subroutines ******************************* +! subroutine to randomise each element of the DRIS (expects you to pass the DRIS as a byte array +SUBROUTINE set_random(dris_byte_array) + use DinkeyPro + integer(1), dimension(DRIS_SIZE) :: dris_byte_array + real,dimension(DRIS_SIZE) :: temp + + call random_seed() + call random_number(temp) + do i=1,DRIS_SIZE + dris_byte_array(i) = temp(i)*256 + end do + return +END SUBROUTINE set_random + +! subroutine to convert an unsigned integer (stored as a signed integer) to the correct unsigned value (for display purposes) +! e.g. the dongle_number value in the dris - should be an unsigned integer but Fortran 90 does not support them +SUBROUTINE ConvertDongleNumber(value) + integer(8) :: value + + if (value < 0) then + value = value + 4294967296 _8 ! make the -ve value a +ve value + end if + return +END SUBROUTINE ConvertDongleNumber + +! displays messages for the most common errors. You will want to change this for your code +SUBROUTINE DisplayError(ret_code, extended_error) + integer :: ret_code, extended_error + + select case (ret_code) + case (401) + print *,"Error! No dongles detected!" + case (403) + print *,"Error! The dongle detected has a different type to the one specified in DinkeyAdd." + case (404) + print *,"Error! The dongle detected has a different model to those specified in DinkeyAdd." + case (409) + print *,"Error! The dongle detected has not been programmed by DinkeyAdd." + case (410) + print *,"Error! The dongle detected has a different Product Code to the one specified in DinkeyAdd." + case (411) + print *,"Error! The dongle detected does not contain the licence associated with this program." + case (413) + print *,"Error! This program has not been protected by DinkeyAdd." + print *,"For guidance please read the DinkeyAdd chapter of the Dinkey manual." + case (417) + print *,"Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the" + print *," DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa." + case (423) + print *,"Error! The number of network users has been exceeded." + case (435) + print *,"Error! DinkeyServer has not been detected on the network." + case (922) + print *,"Error! The Software Key has expired." + case default + print *,"An error occurred checking the dongle. Error: ", ret_code, " Extended Error: ", extended_error + end select + return +END SUBROUTINE DisplayError diff --git a/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/iDllTest.sln b/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/iDllTest.sln new file mode 100644 index 0000000..4976889 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/iDllTest.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = "iDllTest", "iDllTest.vfproj", "{99DA52B5-1568-4A3F-B7D1-CD1813A2CF94}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {99DA52B5-1568-4A3F-B7D1-CD1813A2CF94}.Debug|Win32.ActiveCfg = Debug|Win32 + {99DA52B5-1568-4A3F-B7D1-CD1813A2CF94}.Debug|Win32.Build.0 = Debug|Win32 + {99DA52B5-1568-4A3F-B7D1-CD1813A2CF94}.Debug|x64.ActiveCfg = Debug|x64 + {99DA52B5-1568-4A3F-B7D1-CD1813A2CF94}.Debug|x64.Build.0 = Debug|x64 + {99DA52B5-1568-4A3F-B7D1-CD1813A2CF94}.Release|Win32.ActiveCfg = Release|Win32 + {99DA52B5-1568-4A3F-B7D1-CD1813A2CF94}.Release|Win32.Build.0 = Release|Win32 + {99DA52B5-1568-4A3F-B7D1-CD1813A2CF94}.Release|x64.ActiveCfg = Release|x64 + {99DA52B5-1568-4A3F-B7D1-CD1813A2CF94}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/iDllTest.vfproj b/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/iDllTest.vfproj new file mode 100644 index 0000000..cb277f4 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/iDllTest.vfproj @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/idlltest.f90 b/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/idlltest.f90 new file mode 100644 index 0000000..487d7c3 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Fortran/Runtime/idlltest.f90 @@ -0,0 +1,826 @@ +! dlltest - sample program to call DinkeyPro/FD runtime module (dpwin32.dll) +! +! this sample code has been compiled and tested using Intel Fortran XE 2011 +! but should work with earlier versions. + +! The sample code contains 10 functions. You will not need to use all these +! functions in your code. Just use which ever functions are most appropriate +! and customise in your own way. The sample code is just a guide. You should +! implement the protection in a stronger way using the techniques described in +! the "Increasing your Protection" chapter of the manual. + +!If you are using Dinkey Lite then you can only use 4 functions: +!ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + +! this file contains 10 protection-check functions. +! ProtCheck a standard protection check +! ProtCheckWithAlg a protection check & executing an algorithm +! WriteBytes a protection check & write data to the dongle +! ReadBytes a protection check & read data from the dongle +! EncryptUserData a protection check & encrypting data and then decrypting the data +! these functions are the same as the functions listed above but encrypting all parameters passed to our API +! ProtCheckEnc a standard protection check +! ProtCheckWithAlgEnc a protection check & executing an Algorithm +! WriteBytesEnc a protection check & write data to the dongle +! ReadBytesEnc a protection check & read data from the dongle +! EncryptUserDataEnc a protection check & encrypting data and then decrypting the data + +PROGRAM main + ! call the function(s) of your choice here + ! by default I have chosen a standard protection check + if (ProtCheck() == 0) then + print *,"It worked!" + end if +END PROGRAM main + +! this module contains the DRIS structure declaration and also declares important constants +MODULE DinkeyPro + + integer,parameter :: MY_SDSN = 10101 !!!! change this value to be the value of your SDSN (demo = 10101) + + ! declare dris data type + !DEC$ PACK:1 ! this needs to be byte aligned + TYPE DRIS + sequence + ! the first 4 fields are never encrypted + character(len=4) :: header ! should be set to 'DRIS' + ! inputs + integer(4) :: size ! size of this structure + integer(4) :: seed1 ! seed for data/dris encryption + integer(4) :: seed2 ! as above + ! (maybe encrypted from now on) + integer(4) :: function ! specify only one function + integer(4) :: flags ! options for the function selected. To use more than one OR them together e.g. OR(OPTION1, OPTION2) + integer(4) :: execs_decrement ! amount by which to dec execs if we use flag: DEC_MANY_EXECS + integer(4) :: data_crypt_key_num ! number of the key (1-3) that the dongle uses to encrypt or decrypt user data + integer(4) :: rw_offset ! offset in the dongle data area to read or write data + integer(4) :: rw_length ! length of data are to read/write/encrypt/decrypt +!DEC$ IF DEFINED (_M_X64) + integer(8) :: unused ! pass data by function parameter instead. 8 bytes long for 64-bit Fortran code. +!DEC$ ELSE + integer(4) :: unused ! pass data by function parameter instead. 4 bytes long for 32-bit Fortran code. +!DEC$ ENDIF + character(len=256) :: alt_licence_name ! protection check for different licence instead of the default one, must be null-terminated + integer(4) :: var_a ! variable values for user algorithm + integer(4) :: var_b + integer(4) :: var_c + integer(4) :: var_d + integer(4) :: var_e + integer(4) :: var_f + integer(4) :: var_g + integer(4) :: var_h + integer(4) :: alg_number ! the number of the user algorithm that you want to execute + + ! outputs + integer(4) :: ret_code ! return code from the protection check + integer(4) :: ext_err ! extended error + integer(4) :: type ! type of dongle detected. 1 = Pro, 2 = FD + integer(4) :: model ! model of dongle detected. 1= Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + integer(4) :: sdsn ! Software Developer's Serial Number + character(len=12) :: prodcode ! Product Code (null-terminated) + integer(4) :: dongle_number ! NB this should be an unsigned value really + integer(4) :: update_number + integer(4) :: data_area_size ! size of the data area used in the dongle detected + integer(4) :: max_alg_num ! the maximum algorithm number in the dongle detected + integer(4) :: execs ! executions left: -1 indicates 'no limit' + integer(4) :: exp_day ! expiry day: -1 indicates 'no limit' + integer(4) :: exp_month ! expiry month: -1 indicates 'no limit' + integer(4) :: exp_year ! expiry year: -1 indicates 'no limit' + integer(4) :: features ! features value + integer(4) :: net_users ! maximum number of network users for the dongle detected: -1 indicates 'no limit' + integer(4) :: alg_answer ! answer to the user algorithm executed with the given variable values + integer(4) :: fd_capacity ! capacity of the data area in FD dongle. + character(len=128) :: fd_drive ! drive letter of FD dongle detected e.g. 'f:\' (or mount name under Linux) + integer(4) :: swkey_type ! 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + integer(4) :: swkey_exp_day ! software key expiry date (if software key detected) + integer(4) :: swkey_exp_month + integer(4) :: swkey_exp_year + END TYPE DRIS + !DEC$ PACK + +!DEC$ IF DEFINED (_M_X64) + integer,parameter :: DRIS_SIZE = 564 ! I am sure there should be a way to get this programatically! +!DEC$ ELSE + integer,parameter :: DRIS_SIZE = 560 ! I am sure there should be a way to get this programatically! +!DEC$ ENDIF + + ! functions - must specify only one + integer,parameter :: PROTECTION_CHECK = 1 ! checks for dongle, check program params... + integer,parameter :: EXECUTE_ALGORITHM = 2 ! protection check + calculate answer for specified algorithm with specified inputs + integer,parameter :: WRITE_DATA_AREA = 3 ! protection check + writes dongle data area + integer,parameter :: READ_DATA_AREA = 4 ! protection check + reads dongle data area + integer,parameter :: ENCRYPT_USER_DATA = 5 ! protection check + the dongle will encrypt user data + integer,parameter :: DECRYPT_USER_DATA = 6 ! protection check + the dongle will decrypt user data + integer,parameter :: FAST_PRESENCE_CHECK = 7 ! checks for the presence of the correct dongle only with minimal security, no flags allowed. + integer,parameter :: STOP_NET_USER = 8 ! stops a network user (a protection check is NOT performed) + + ! flags - can specify as many as you like + integer,parameter :: DEC_ONE_EXEC = 1 ! decrement execs by 1 + integer,parameter :: DEC_MANY_EXECS = 2 ! decrement execs by number specified in execs_decrement + integer,parameter :: START_NET_USER = 4 ! starts a network user + integer,parameter :: USE_FUNCTION_ARGUMENT = 16 ! use the extra argument in the function for pointers + integer,parameter :: CHECK_LOCAL_FIRST = 32 ! always look in local ports before looking in network ports + integer,parameter :: CHECK_NETWORK_FIRST = 64 ! always look on the network before looking in local ports + integer,parameter :: USE_ALT_LICENCE_NAME = 128 ! use name specified in alt_licence_name instead of the default one + integer,parameter :: DONT_SET_MAXDAYS_EXPIRY = 256 ! if the max days expiry date has not been calculated then do not do it this time + integer,parameter :: MATCH_DONGLE_NUMBER = 512 ! restrict the search to match the dongle number specified in the DRIS + integer,parameter :: DONT_RETURN_FD_DRIVE = 1024 ! if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + + ! declare the protection check function in the Dinkey Pro/FD runtime module + INTERFACE + FUNCTION DDProtCheck(mydris, mydata) + !DEC$ ATTRIBUTES STDCALL, DECORATE, ALIAS:'DDProtCheck', DLLIMPORT :: DDProtCheck + import + type (DRIS) :: mydris + !DEC$ ATTRIBUTES REFERENCE :: mydris + character(len=*) :: mydata + !DEC$ ATTRIBUTES REFERENCE, ALLOW_NULL :: mydata + integer :: DDProtCheck + END FUNCTION DDProtCheck + END INTERFACE + + ! this is an instance of the dris. We make an equivalence between the derived-type + ! and a byte_array because for encryption we need to access the memory as a byte array + type (DRIS) :: mydris + integer(1), dimension(DRIS_SIZE) :: mydris_byte_array + equivalence(mydris, mydris_byte_array) + +END MODULE DinkeyPro + +! ************************* our 10 functions ********************************** + +! ************************** ProtCheck *************************************** +FUNCTION ProtCheck() + use DinkeyPro + integer :: ret_code + integer(8) :: display_dongle_number + + call set_random(mydris_byte_array) ! we have to call this function using the byte array equivalence of the dris type + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = PROTECTION_CHECK ! standard protection check + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + ret_code = DDProtCheck(mydris, 0) + ProtCheck = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheck = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ProtCheck = -1 + return + end if + + ! sample to show how to display dongle number (this is the only value in the dris that should be an unsigned integer) + display_dongle_number = mydris%dongle_number + call ConvertDongleNumber(display_dongle_number) + print *,"Dongle Check successful. Dongle Number is: ",display_dongle_number +END FUNCTION ProtCheck + +! ************************** ProtCheckWithAlg ****************************** + +! !!!! You should replace this function with the one generated by the +! "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) +! or from DinkeyLook if you are using a Dinkey Lite dongle. +FUNCTION MyAlgorithm(a, b, c, d, e, f, g, h) + integer :: a,b,c,d,e,f,g,h,MyAlgorithm + MyAlgorithm = a + b + c + d + e + f + g + h + return +END FUNCTION MyAlgorithm + +! NB for this to work you must program at least "user algorithm" into the dongle +! NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +! sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +! code from DinkeyLook +FUNCTION ProtCheckWithAlg() + use DinkeyPro + integer :: ret_code + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = EXECUTE_ALGORITHM ! standard protection check & execute algorithm + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + mydris%alg_number = 1 ! execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + ! you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + mydris%var_a = 1 ! sample values + mydris%var_b = 2 + mydris%var_c = 3 + mydris%var_d = 4 + mydris%var_e = 5 + mydris%var_f = 6 + mydris%var_g = 7 + mydris%var_h = 8 + + ret_code = DDProtCheck(mydris, 0) + ProtCheckWithAlg = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheckWithAlg = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ProtCheckWithAlg = -1 + return + end if + + ! if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + ! !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) /= mydris%alg_answer) then + print *,"Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine" + ProtCheckWithAlg = -1 + return + end if +END FUNCTION ProtCheckWithAlg + +! ************************** WriteBytes *************************************** +! This writes the Data "Hello, World" to the dongle data area at offset 7 +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +FUNCTION WriteBytes() + use DinkeyPro + integer :: ret_code + character(len=14) :: WriteData = "Hello, World!"c ! it should be a null-terminated string + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = WRITE_DATA_AREA ! standard protection check and write data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(WriteData) + + ret_code = DDProtCheck(mydris, WriteData) + WriteBytes = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + WriteBytes = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + WriteBytes = -1 + return + end if +END FUNCTION WriteBytes + +! ************************** ReadBytes *************************************** +! This reads 14 bytes of data from offset 7 in the dongle data area +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +! In order for the data to be displayed properly by this routine it will need to be text data +FUNCTION ReadBytes() + use DinkeyPro + integer :: ret_code + character(len=14) :: ReadData + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = READ_DATA_AREA ! standard protection check and read data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(ReadData) + + ret_code = DDProtCheck(mydris, ReadData) + ReadBytes = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ReadBytes = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ReadBytes = -1 + return + end if + + print *,"Dinkey Dongle Data area, offset 7 is: ",ReadData +END FUNCTION ReadBytes + +! ************************** EncryptUserData *************************************** +! This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +! It will then do another protection check & decrypt the data +FUNCTION EncryptUserData() + use DinkeyPro + integer :: ret_code + character(len=14) :: MyData = "Hello, World!"c + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = ENCRYPT_USER_DATA ! standard protection check and encrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(MyData) + + ret_code = DDProtCheck(mydris, MyData) + EncryptUserData = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + ! ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + print *,"Encrypted data is: ",MyData + + ! Now decrypt the same data to get the original values + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = DECRYPT_USER_DATA ! standard protection check and decrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(MyData) + + ret_code = DDProtCheck(mydris, MyData) + EncryptUserData = ret_code + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + EncryptUserData = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + EncryptUserData = -1 + return + end if + + print *,"Decrypted data is: ",MyData +END FUNCTION EncryptUserData + +! !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! +! In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" +! in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm +! but the code can be modified easily to use the 3 encryption parameters. + +! !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm +FUNCTION MyRWAlgorithm(a, b, c, d, e, f, g, h) + integer :: a,b,c,d,e,f,g,h,MyRWAlgorithm + MyRWAlgorithm = IEOR(IEOR(IEOR(IEOR(IEOR(a,b),c),d),e),f) + return +END FUNCTION MyRWAlgorithm + +! !!!! please patch the 3 parameters specified below with the 3 parameters specified in DinkeyAdd +SUBROUTINE CryptDRIS(dris_byte_array) + use DinkeyPro + integer(1), dimension(DRIS_SIZE) :: dris_byte_array + integer :: i,j,k,temp,t + integer, dimension(256) :: bigseed,S + + do i=1,256 + bigseed(i) = dris_byte_array(9 + modulo(i-1,8)) ! this takes the values from seed1, seed2 directly + end do + + do i=1,256 + S(i) = i-1 + end do + + j = 0 + do i=1,256 + j = IAND(j + S(i) + bigseed(i) + 123, 255) ! first parameter patched here + temp = S(i) + S(i) = S(j+1) + S(j+1) = temp + end do + + i = 0 + j = 0 + do k=17,DRIS_SIZE + i = IAND(i + 1, 255) + j = IAND(j + S(i+1) + 212, 255) ! second parameter patched here + temp = S(i+1) + S(i+1) = S(j+1) + S(j+1) = temp + t = IAND(S(i+1) + S(j+1) + 97,255) ! third parameter patched here + dris_byte_array(k) = IEOR(dris_byte_array(k),S(t+1)) + end do + return +END SUBROUTINE CryptDRIS + +! !!!! please patch the 3 parameters specified below with the 3 parameters specified in DinkeyAdd +! if you are using the r/w algorithm then there is no need to change this function +! NB we pass the whole of the DRIS but we only need it for seed1 and seed2 values +SUBROUTINE CryptApiData(mydata, length, dris_byte_array, alg_answer) + use DinkeyPro + integer :: length, alg_answer, seed1, seed2 + integer(1), dimension(length) :: mydata + integer(1), dimension(DRIS_SIZE) :: dris_byte_array + integer :: i,j,k,temp,t + integer, dimension(256) :: bigseed,S + + do i=1,256 + bigseed(i) = dris_byte_array(9 + modulo(i-1,8)) ! this takes the values from seed1, seed2 directly + end do + + do i=1,256 + S(i) = i-1 + end do + + j = 0 + do i=1,256 + j = IAND(j + S(i) + bigseed(i) + IAND(alg_answer, 255), 255) ! first parameter patched here + temp = S(i) + S(i) = S(j+1) + S(j+1) = temp + end do + + i = 0 + j = 0 + do k=1,length + i = IAND(i + 1, 255) + j = IAND(j + S(i+1) + IAND(ISHFT(alg_answer, -8),255), 255) ! second parameter patched here + temp = S(i+1) + S(i+1) = S(j+1) + S(j+1) = temp + t = IAND(S(i+1) + S(j+1) + IAND(ISHFT(alg_answer, -16),255),255) ! third parameter patched here + mydata(k) = IEOR(mydata(k),S(t+1)) + end do + return +END SUBROUTINE CryptApiData + +! ************************** ProtCheckEnc *************************************** +! We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +FUNCTION ProtCheckEnc() + use DinkeyPro + integer :: ret_code + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = PROTECTION_CHECK ! standard protection check + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, 0) + ProtCheckEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheckEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ProtCheckEnc = -1 + return + end if +END FUNCTION ProtCheckEnc + +! ************************** ProtCheckWithAlgEnc ****************************** +! NB for this to work you must program at least "user algorithm" into the dongle +! NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +! sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +! code from DinkeyLook +! We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +FUNCTION ProtCheckWithAlgEnc() + use DinkeyPro + integer :: ret_code + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = EXECUTE_ALGORITHM ! standard protection check & execute algorithm + mydris%flags = 0 ! no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + mydris%alg_number = 1 ! execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + ! you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + mydris%var_a = 1 ! sample values + mydris%var_b = 2 + mydris%var_c = 3 + mydris%var_d = 4 + mydris%var_e = 5 + mydris%var_f = 6 + mydris%var_g = 7 + mydris%var_h = 8 + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, 0) + ProtCheckWithAlgEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ProtCheckWithAlgEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ProtCheckWithAlgEnc = -1 + return + end if + + ! if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + ! !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) /= mydris%alg_answer) then + print *,"Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine" + ProtCheckWithAlgEnc = -1 + return + end if +END FUNCTION ProtCheckWithAlgEnc + +! ************************** WriteBytesEnc *************************************** +! This writes the Data "Hello, World" to the dongle data area at offset 7 +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +! We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +FUNCTION WriteBytesEnc() + use DinkeyPro + integer :: ret_code,alg_ans + character(len=14) :: WriteData = "Hello, World!"c + integer(1), dimension(14) :: WriteDataByteArray + equivalence(WriteData, WriteDataByteArray) ! to encrypt it we need to pass it as a byte array + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = WRITE_DATA_AREA ! standard protection check and write data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(WriteData) + + ! calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) + + ! encrypt data we want to write. + call CryptApiData(WriteDataByteArray, len(WriteData), mydris_byte_array, alg_ans); + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, WriteData) + WriteBytesEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + WriteBytesEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + WriteBytesEnc = -1 + return + end if +END FUNCTION WriteBytesEnc + +! ************************** ReadBytesEnc *************************************** +! This reads 14 bytes of data from offset 7 in the dongle data area +! In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +! In order for the data to be displayed properly by this routine it will need to be text data +! We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +FUNCTION ReadBytesEnc() + use DinkeyPro + integer :: ret_code,alg_ans + character(len=14) :: ReadData + integer(1), dimension(14) :: ReadDataByteArray + equivalence(ReadData, ReadDataByteArray) ! to encrypt it we need to pass it as a byte array + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = READ_DATA_AREA ! standard protection check and read data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%rw_offset = 7 + mydris%rw_length = len(ReadData) + + ! calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, ReadData) + ReadBytesEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + ReadBytesEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + ReadBytesEnc = -1 + return + end if + + ! decrypt data we have just read. + call CryptApiData(ReadDataByteArray, len(ReadData), mydris_byte_array, alg_ans); + print *,"Dinkey Dongle Data area, offset 7 is: ",ReadData +END FUNCTION ReadBytesEnc + +! ************************** EncryptUserDataEnc *************************************** +! This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +! It will then do another protection check & decrypt the data +! We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +FUNCTION EncryptUserDataEnc() + use DinkeyPro + integer :: ret_code,alg_ans + character(len=14) :: MyData = "Hello, World!"c + integer(1), dimension(14) :: MyDataByteArray + equivalence(MyData, MyDataByteArray) ! to encrypt it we need to pass it as a byte array + + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = ENCRYPT_USER_DATA ! standard protection check and encrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(MyData) + + ! calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) + + ! encrypt data we want to pass. + call CryptApiData(MyDataByteArray, len(MyData), mydris_byte_array, alg_ans); + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, MyData) + EncryptUserDataEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + ! ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + print *,"Encrypted data is: ",MyData + + ! Now decrypt the same data to get the original values + call set_random(mydris_byte_array) + mydris%header = 'DRIS' + mydris%size = DRIS_SIZE + mydris%function = DECRYPT_USER_DATA ! standard protection check and decrypt user data + mydris%flags = USE_FUNCTION_ARGUMENT ! this way we don't need to worry about pointers in the DRIS + mydris%data_crypt_key_num = 1 + mydris%rw_length = len(MyData) + + call CryptDRIS(mydris_byte_array) ! encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, MyData) + EncryptUserDataEnc = ret_code + + call CryptDRIS(mydris_byte_array) ! decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code /= 0) then + call DisplayError(ret_code, mydris%ext_err) ! display messages for any errors that have occurred + return + end if + + if (mydris%sdsn /= MY_SDSN) then + print *,"Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + EncryptUserDataEnc = -1 + return + end if + + ! later on in your program you can check the return code again + if (mydris%ret_code /= 0) then + print *,"Dinkey Dongle protection error." + EncryptUserDataEnc = -1 + return + end if + + alg_ans = MyRWAlgorithm(mydris%var_a, mydris%var_b, mydris%var_c, mydris%var_d, mydris%var_e, mydris%var_f, mydris%var_g, mydris%var_h) + ! decrypt data that was passed to us by the API. + call CryptApiData(MyDataByteArray, len(MyData), mydris_byte_array, alg_ans); + print *,"Decrypted data is: ",MyData +END FUNCTION EncryptUserDataEnc + +! ************************** useful subroutines ******************************* +! subroutine to randomise each element of the DRIS (expects you to pass the DRIS as a byte array +SUBROUTINE set_random(dris_byte_array) + use DinkeyPro + integer(1), dimension(DRIS_SIZE) :: dris_byte_array + real,dimension(DRIS_SIZE) :: temp + + call random_seed() + call random_number(temp) + do i=1,DRIS_SIZE + dris_byte_array(i) = temp(i)*256 + end do + return +END SUBROUTINE set_random + +! subroutine to convert an unsigned integer (stored as a signed integer) to the correct unsigned value (for display purposes) +! e.g. the dongle_number value in the dris - should be an unsigned integer but Fortran 90 does not support them +SUBROUTINE ConvertDongleNumber(value) + integer(8) :: value + + if (value < 0) then + value = value + 4294967296 ! make the -ve value a +ve value + end if + return +END SUBROUTINE ConvertDongleNumber + +! displays messages for the most common errors. You will want to change this for your code +SUBROUTINE DisplayError(ret_code, extended_error) + integer :: ret_code, extended_error + + select case (ret_code) + case (401) + print *,"Error! No dongles detected!" + case (403) + print *,"Error! The dongle detected has a different type to the one specified in DinkeyAdd." + case (404) + print *,"Error! The dongle detected has a different model to those specified in DinkeyAdd." + case (409) + print *,"Error! The dongle detected has not been programmed by DinkeyAdd." + case (410) + print *,"Error! The dongle detected has a different Product Code to the one specified in DinkeyAdd." + case (411) + print *,"Error! The dongle detected does not contain the licence associated with this program." + case (413) + print *,"Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual." + case (417) + print *,"Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa." + case (423) + print *,"Error! The number of network users has been exceeded." + case (435) + print *,"Error! DinkeyServer has not been detected on the network." + case (922) + print *,"Error! The Software Key has expired." + case default + print *,"An error occurred checking the dongle. Error: ", ret_code, " Extended Error: ", extended_error + end select + return +END SUBROUTINE DisplayError \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/FoxPro/README.txt b/Dinkey Pro 7.6.1/Samples/FoxPro/README.txt new file mode 100644 index 0000000..5b1a53f --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/FoxPro/README.txt @@ -0,0 +1,45 @@ +FoxPro Sample Code Notes +~~~~~~~~~~~~~~~~~~~~~~~~ + +Runtime.prg was tested in FoxPro6 but will also work with all later versions of PoxPro + +The sample code contains 10 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. + +Note - you should protect dpwin32.dll and not your program. Because your program +is linked to the DLL it is protected. The protected DLL will need to be in the +same folder as your compiled program for it to run correctly. + +Note - you should place dpwin32.dll either in the 32-bit Windows System folder* or in +the project folder (if you do this you should "CD" to this folder in the command window). + +Note - Output text from this program is displayed in the main Visual FoxPro Window. + +Note - You would normally want to QUIT if the protection check failed. We do not do that +in this sample code so you can see error messages being displayed. + +Note - you can debug your code (our anti-debug code sometimes stops this but not for FoxPro) + +Note - For reading data or decrypting data you must initialise the data variable you pass to +contain at least the number of bytes that you want to read. After you have read the data you +must adjust the size of the string to be the size of the data you have read as our API does +not do this. + +* Windows System folder for 32-bit dlls is: +c:\windows\system32 32-bit Windows OS +c:\windows\syswow64 64-bit Windows OS \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/FoxPro/runtime.prg b/Dinkey Pro 7.6.1/Samples/FoxPro/runtime.prg new file mode 100644 index 0000000..3c342ab --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/FoxPro/runtime.prg @@ -0,0 +1,929 @@ +* Sample code for Visual Foxpro +* Compiled and tested with Microsoft Visual Foxpro 6.0 +SET TALK On +CLEAR DLLS + +* declare functions in Dinkey Pro module dpwin32.dll +Declare INTEGER DDProtCheck IN "dpwin32.dll" STRING @dris, STRING @data + +* The sample code contains 10 functions. You will not need to use all these +* functions in your code. Just use which ever functions are most appropriate +* and customise in your own way. The sample code is just a guide. You should +* implement the protection in a stronger way using the techniques described in +* the "Increasing your Protection" chapter of the manual. +* +* Sample Code Functions: +* ProtCheck, ProtCheckWithAlg, WriteBytes, ReadBytes, EncryptUserData +* +* and also these functions but encrypting all parameters passed to our API: +* ProtCheckEnc, ProtCheckWithAlgEnc, WriteBytesEnc, ReadBytesEnc, EncryptUserDataEnc +* +* If you are using Dinkey Lite then you can only use 4 functions: +* ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc +* + +#define MY_SDSN 10101 && !!!! change this value to be the value of your SDSN (demo = 10101) +#define MY_PRODCODE "DEMO" && !!!! change this value to match the Product Code in the dongle + +#define DRIS_SIZE 560 + +* functions constants - must specify only one +#define PROTECTION_CHECK 1 && checks for dongle, check program params... +#define EXECUTE_ALGORITHM 2 && protection check + calculate answer for specified algorithm with specified inputs +#define WRITE_DATA_AREA 3 && protection check + writes dongle data area +#define READ_DATA_AREA 4 && protection check + reads dongle data area +#define ENCRYPT_USER_DATA 5 && protection check + the dongle will encrypt user data +#define DECRYPT_USER_DATA 6 && protection check + the dongle will decrypt user data +#define FAST_PRESENCE_CHECK 7 && checks for the presence of the correct dongle only with minimal security, no flags allowed. +#define STOP_NET_USER 8 && stops a network user (a protection check is NOT performed) + +* flags constants - can specify as many as you like +#define DEC_ONE_EXEC 1 && decrement execs by 1 +#define DEC_MANY_EXECS 2 && decrement execs by number specified in execs_decrement +#define START_NET_USER 4 && starts a network user +#define USE_FUNCTION_ARGUMENT 16 && use the extra argument in the function for pointers +#define CHECK_LOCAL_FIRST 32 && always look in local ports before looking in network ports +#define CHECK_NETWORK_FIRST 64 && always look on the network before looking in local ports +#define USE_ALT_LICENCE_NAME 128 && use name specified in alt_licence_name instead of the default one +#define DONT_SET_MAXDAYS_EXPIRY 256 && if the max days expiry date has not been calculated then do not do it this time +#define MATCH_DONGLE_NUMBER 512 && restrict the search to match the dongle number specified in the DRIS +#define DONT_RETURN_FD_DRIVE 1024 && if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + +********************** entry point ******************************* +* call the function of your choice: + +IF ProtCheck() == 0 + ? "It Worked!" +ELSE + && QUIT && you would probably want to QUIT if the protection check failed. We don't do that here so you can see display error messages +ENDIF + +clear dlls + + +********************* protection check functions ******************* +*** ProtCheck +FUNCTION ProtCheck + * create & initialise DRIS to random values & set header + dris = random_dris() + + * set DRIS values to be what we want to use + SetDrisSize(@dris) + SetDrisFunction(@dris, PROTECTION_CHECK) && standard protection check + SetDrisFlags(@dris, 0) && no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + ret_code = DDProtCheck(@dris, NULL) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * later in your code you can check other values in the DRIS... + IF GetDrisSDSN(dris) != MY_SDSN + ? "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + RETURN -1 + ENDIF + + IF GetDrisProdCode(dris) != MY_PRODCODE + ? "Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle." + RETURN -1 + ENDIF + + * later on in your program you can check the return code again + IF GetDrisRetCode(@dris) != 0 + ? "Dinkey Dongle protection error" + RETURN -1 + ENDIF + + * It worked! + RETURN 0 +ENDFUNC + +*** ProtCheckWithAlg +* !!!! You should replace this function with the one generated by the +* "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) +* or from DinkeyLook if you are using a Dinkey Lite dongle. You will have to translate this from another language e.g. C +FUNCTION MyAlgorithm(a, b, c, d, e, f, g, h) + RETURN a + b + c + d + e + f + g + h +ENDFUNC + +* NB for this to work you must program at least "user algorithm" into the dongle +* NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +* sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +* code from DinkeyLook +FUNCTION ProtCheckWithAlg + * create & initialise DRIS to random values & set header + dris = random_dris() + + * set DRIS values to be what we want to use + SetDrisSize(@dris) + SetDrisFunction(@dris, EXECUTE_ALGORITHM) && standard protection check & execute specified algorithm + SetDrisFlags(@dris, 0) && no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + SetDrisAlgNumber(@dris, 1) && execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + && set variables for algorithm + SetDrisAlgVars(@dris, 1, 2, 3, 4 , 5, 6, 7, 8) && you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + + ret_code = DDProtCheck(@dris, NULL) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * later in your code you can check other values in the DRIS... + IF GetDrisSDSN(dris) != MY_SDSN + ? "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + RETURN -1 + ENDIF + + * later on in your program you can check the return code again + IF GetDrisRetCode(@dris) != 0 + ? "Dinkey Dongle protection error" + RETURN -1 + ENDIF + + * if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + * !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + IF MyAlgorithm(GetDrisVarA(dris), GetDrisVarB(dris), GetDrisVarC(dris), GetDrisVarD(dris), GetDrisVarE(dris), ; + GetDrisVarF(dris), GetDrisVarG(dris), GetDrisVarH(dris)) != GetDrisAlgAnswer(dris) + ? "Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine" + RETURN -1 + ENDIF + + * It worked! + RETURN 0 +ENDFUNC + +*** WriteBytes +* This writes the string "Hello, World" to the dongle data area at offset 7 +* In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +FUNCTION WriteBytes + DataToWrite = "Hello, World!" + + * create & initialise DRIS to random values & set header + dris = random_dris() + + * set DRIS values to be what we want to use + SetDrisSize(@dris) + SetDrisFunction(@dris, WRITE_DATA_AREA) && standard protection check and write the dongle data area + SetDrisFlags(@dris, USE_FUNCTION_ARGUMENT) && we need to set this as we are passing the data to write as an extra parameter to DDProtCheck + SetDrisRWOffset(@dris, 7) + SetDrisRWLength(@dris, LEN(DataToWrite)) + + ret_code = DDProtCheck(@dris, @DataToWrite) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * later in your code you can check other values in the DRIS... + IF GetDrisSDSN(dris) != MY_SDSN + ? "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + RETURN -1 + ENDIF + + * later on in your program you can check the return code again + IF GetDrisRetCode(@dris) != 0 + ? "Dinkey Dongle protection error" + RETURN -1 + ENDIF + + * It worked! + RETURN 0 +ENDFUNC + +*** ReadBytes +* This reads 13 bytes of data from offset 7 in the dongle data area +* In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +* In order for the data to be displayed properly by this routine it will need to be text data +FUNCTION ReadBytes + DataRead = "Data Read goes here" && we must initialise this to something that is at least as long as the data we are reading + data_length = 13 + + * create & initialise DRIS to random values & set header + dris = random_dris() + + * set DRIS values to be what we want to use + SetDrisSize(@dris) + SetDrisFunction(@dris, READ_DATA_AREA) && standard protection check and read the dongle data area + SetDrisFlags(@dris, USE_FUNCTION_ARGUMENT) && we need to set this as we are passing the data to read as an extra parameter to DDProtCheck + SetDrisRWOffset(@dris, 7) + SetDrisRWLength(@dris, data_length) + + ret_code = DDProtCheck(@dris, @DataRead) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * later in your code you can check other values in the DRIS... + IF GetDrisSDSN(dris) != MY_SDSN + ? "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + RETURN -1 + ENDIF + + * later on in your program you can check the return code again + IF GetDrisRetCode(@dris) != 0 + ? "Dinkey Dongle protection error" + RETURN -1 + ENDIF + + DataRead = SUBSTR(DataRead, 1, data_length) && shorten string so it just contains the data read + ? "Dinkey Dongle Data area, offset 7 is: " + DataRead + + * It worked! + RETURN 0 +ENDFUNC + +*** EncryptUserData +* This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +* It will then do another protection check & decrypt the data +FUNCTION EncryptUserData + MyData = "Hello, World!" && this is the data that we are going to encrypt + + * create & initialise DRIS to random values & set header + dris = random_dris() + + * set DRIS values to be what we want to use + SetDrisSize(@dris) + SetDrisFunction(@dris, ENCRYPT_USER_DATA) && standard protection check and encrypt data + SetDrisFlags(@dris, USE_FUNCTION_ARGUMENT) && we need to set this as we are passing the data to encrypt as an extra parameter to DDProtCheck + SetDrisDataCryptKeyNum(@dris, 1) + SetDrisRWLength(@dris, Len(MyData)) + + ret_code = DDProtCheck(@dris, @MyData) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + * Now decrypt this encrypted data to get the original + dris = random_dris() + SetDrisSize(@dris) + SetDrisFunction(@dris, DECRYPT_USER_DATA) && standard protection check and decrypt data + SetDrisFlags(@dris, USE_FUNCTION_ARGUMENT) && we need to set this as we are passing the data to encrypt as an extra parameter to DDProtCheck + SetDrisDataCryptKeyNum(@dris, 1) + SetDrisRWLength(@dris, Len(MyData)) + + ret_code = DDProtCheck(@dris, @MyData) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * later in your code you can check other values in the DRIS... + IF GetDrisSDSN(dris) != MY_SDSN + ? "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + RETURN -1 + ENDIF + + * later on in your program you can check the return code again + IF GetDrisRetCode(@dris) != 0 + ? "Dinkey Dongle protection error" + RETURN -1 + ENDIF + + ? "Decrypted data is: " + MyData + + * It worked! + RETURN 0 +ENDFUNC + +* !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! +* In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" +* in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm +* but the code can be modified easily to use the 3 encryption parameters. + +* !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm +* in this case you will have to translate from C or another programming language +FUNCTION MyRWAlgorithm(a, b, c, d, e, f, g, h) + RETURN BITXOR(BITXOR(BITXOR(BITXOR(BITXOR(a, b), c), d), e), f) +ENDFUNC + +* !!!! please overwrite this function with the one generated by DinkeyAdd +* in this case you will have to just patch the parameter values in the code +FUNCTION CryptDRIS(mydris, seed1, seed2) + DECLARE bigseed[256] As Integer + DECLARE S[256] As Integer + + FOR i=1 TO 256 STEP 8 + SETARRAY4BYTES(@bigseed, i, seed1) + SETARRAY4BYTES(@bigseed, i+4, seed2) + ENDFOR + + FOR i=1 TO 256 + S[i] = i-1 + ENDFOR + + j = 0 + FOR i = 0 TO 255 + j = BITAND(j + S[i+1]+ bigseed[i+1] + 123, 255) && parameter 1 is 123 + temp = S[i+1] + S[i+1] = S[j+1] + S[j+1] = temp + ENDFOR + + i = 0 + j = 0 + FOR k=17 TO DRIS_SIZE + i = BITAND(i + 1, 255) + j = BITAND(j + S[i+1] + 212, 255) && parameter 2 is 212 + temp = S[i+1] + S[i+1] = S[j+1] + S[j+1] = temp + t = BITAND(S[i+1] + S[j+1] + 97, 255) && parameter 3 is 97 + temp = ASC(SUBSTR(mydris, k, 1)) + mydris = STUFF(mydris, k, 1, CHR(BITXOR(temp,S[t+1]))) + ENDFOR +ENDFUNC + +* !!!! please overwrite this function with the one generated by DinkeyAdd +* in this case you will have to just patch the parameter values in the code +FUNCTION CryptApiData(mydata, length, seed1, seed2, alg_answer) + DECLARE bigseed[256] As Integer + DECLARE S[256] As Integer + + FOR i=1 TO 256 STEP 8 + SETARRAY4BYTES(@bigseed, i, seed1) + SETARRAY4BYTES(@bigseed, i+4, seed2) + ENDFOR + + FOR i=1 TO 256 + S[i] = i-1 + ENDFOR + + j = 0 + FOR i = 0 TO 255 + j = BITAND(j + S[i+1]+ bigseed[i+1] + BITAND(alg_answer, 255), 255) && parameter 1 + temp = S[i+1] + S[i+1] = S[j+1] + S[j+1] = temp + ENDFOR + + i = 0 + j = 0 + FOR k=1 TO length + i = BITAND(i + 1, 255) + j = BITAND(j + S[i+1] + BITAND(BITRSHIFT(alg_answer, 8),255), 255) && parameter 2 + temp = S[i+1] + S[i+1] = S[j+1] + S[j+1] = temp + t = BITAND(S[i+1] + S[j+1] + BITAND(BITRSHIFT(alg_answer, 16),255), 255) && parameter 3 + temp = ASC(SUBSTR(mydata, k, 1)) + mydata = STUFF(mydata, k, 1, CHR(BITXOR(temp,S[t+1]))) + ENDFOR +ENDFUNC + +*** ProtCheckEnc +* We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +FUNCTION ProtCheckEnc + * create & initialise DRIS to random values & set header + dris = random_dris() + + * set DRIS values to be what we want to use + SetDrisSize(@dris) + SetDrisFunction(@dris, PROTECTION_CHECK) && standard protection check + SetDrisFlags(@dris, 0) && no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(@dris, NULL) + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * later in your code you can check other values in the DRIS... + IF GetDrisSDSN(dris) != MY_SDSN + ? "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + RETURN -1 + ENDIF + + IF GetDrisProdCode(dris) != MY_PRODCODE + ? "Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle." + RETURN -1 + ENDIF + + * later on in your program you can check the return code again + IF GetDrisRetCode(@dris) != 0 + ? "Dinkey Dongle protection error" + RETURN -1 + ENDIF + + * It worked! + RETURN 0 +ENDFUNC + +*** ProtCheckWithAlgEnc +* NB for this to work you must program at least "user algorithm" into the dongle +* NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +* sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +* code from DinkeyLook +* We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +FUNCTION ProtCheckWithAlgEnc + * create & initialise DRIS to random values & set header + dris = random_dris() + + * set DRIS values to be what we want to use + SetDrisSize(@dris) + SetDrisFunction(@dris, EXECUTE_ALGORITHM) && standard protection check & execute specified algorithm + SetDrisFlags(@dris, 0) && no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + SetDrisAlgNumber(@dris, 1) && execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + && set variables for algorithm + SetDrisAlgVars(@dris, 1, 2, 3, 4 , 5, 6, 7, 8) && you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(@dris, NULL) + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * later in your code you can check other values in the DRIS... + IF GetDrisSDSN(dris) != MY_SDSN + ? "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + RETURN -1 + ENDIF + + * later on in your program you can check the return code again + IF GetDrisRetCode(@dris) != 0 + ? "Dinkey Dongle protection error" + RETURN -1 + ENDIF + + * if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + * !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + IF MyAlgorithm(GetDrisVarA(dris), GetDrisVarB(dris), GetDrisVarC(dris), GetDrisVarD(dris), GetDrisVarE(dris), ; + GetDrisVarF(dris), GetDrisVarG(dris), GetDrisVarH(dris)) != GetDrisAlgAnswer(dris) + ? "Dinkey protection error! You have not patched your algorithm in the MyAlgorithm routine" + RETURN -1 + ENDIF + + * It worked! + RETURN 0 +ENDFUNC + +*** WriteBytes +* This writes the string "Hello, World" to the dongle data area at offset 7 +* In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +* We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +FUNCTION WriteBytesEnc + DataToWrite = "Hello, World!" + + * create & initialise DRIS to random values & set header + dris = random_dris() + + * set DRIS values to be what we want to use + SetDrisSize(@dris) + SetDrisFunction(@dris, WRITE_DATA_AREA) && standard protection check and write the dongle data area + SetDrisFlags(@dris, USE_FUNCTION_ARGUMENT) && we need to set this as we are passing the data to write as an extra parameter to DDProtCheck + SetDrisRWOffset(@dris, 7) + SetDrisRWLength(@dris, LEN(DataToWrite)) + + * calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(GetDrisVarA(dris), GetDrisVarB(dris), GetDrisVarC(dris), GetDrisVarD(dris), GetDrisVarE(dris), GetDrisVarF(dris), GetDrisVarG(dris), GetDrisVarH(dris)) + + * encrypt data we want to write. + CryptApiData(@DataToWrite, LEN(DataToWrite), GetDrisSeed1(dris), GetDrisSeed2(dris), alg_ans) + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(@dris, @DataToWrite) + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * later in your code you can check other values in the DRIS... + IF GetDrisSDSN(dris) != MY_SDSN + ? "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + RETURN -1 + ENDIF + + * later on in your program you can check the return code again + IF GetDrisRetCode(@dris) != 0 + ? "Dinkey Dongle protection error" + RETURN -1 + ENDIF + + * It worked! + RETURN 0 +ENDFUNC + +*** ReadBytesEnc +* This reads 13 bytes of data from offset 7 in the dongle data area +* In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +* In order for the data to be displayed properly by this routine it will need to be text data +FUNCTION ReadBytesEnc + DataRead = "Data Read goes here" && we must initialise this to something that is at least as long as the data we are reading + data_length = 13 + + * create & initialise DRIS to random values & set header + dris = random_dris() + + * set DRIS values to be what we want to use + SetDrisSize(@dris) + SetDrisFunction(@dris, READ_DATA_AREA) && standard protection check and read the dongle data area + SetDrisFlags(@dris, USE_FUNCTION_ARGUMENT) && we need to set this as we are passing the data to read as an extra parameter to DDProtCheck + SetDrisRWOffset(@dris, 7) + SetDrisRWLength(@dris, data_length) + + * calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(GetDrisVarA(dris), GetDrisVarB(dris), GetDrisVarC(dris), GetDrisVarD(dris), GetDrisVarE(dris), GetDrisVarF(dris), GetDrisVarG(dris), GetDrisVarH(dris)) + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(@dris, @DataRead) + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * later in your code you can check other values in the DRIS... + IF GetDrisSDSN(dris) != MY_SDSN + ? "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + RETURN -1 + ENDIF + + * later on in your program you can check the return code again + IF GetDrisRetCode(@dris) != 0 + ? "Dinkey Dongle protection error" + RETURN -1 + ENDIF + + * decrypt data we read + CryptApiData(@DataRead, data_length, GetDrisSeed1(dris), GetDrisSeed2(dris), alg_ans) + DataRead = SUBSTR(DataRead, 1, data_length) && shorten string so it just contains the data read + ? "Dinkey Dongle Data area, offset 7 is: " + DataRead + + * It worked! + RETURN 0 +ENDFUNC + +*** EncryptUserDataEnc +* This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +* It will then do another protection check & decrypt the data +FUNCTION EncryptUserDataEnc + MyData = "Hello, World!" && this is the data that we are going to encrypt + + * create & initialise DRIS to random values & set header + dris = random_dris() + + * set DRIS values to be what we want to use + SetDrisSize(@dris) + SetDrisFunction(@dris, ENCRYPT_USER_DATA) && standard protection check and encrypt data + SetDrisFlags(@dris, USE_FUNCTION_ARGUMENT) && we need to set this as we are passing the data to encrypt as an extra parameter to DDProtCheck + SetDrisDataCryptKeyNum(@dris, 1) + SetDrisRWLength(@dris, Len(MyData)) + + * calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(GetDrisVarA(dris), GetDrisVarB(dris), GetDrisVarC(dris), GetDrisVarD(dris), GetDrisVarE(dris), GetDrisVarF(dris), GetDrisVarG(dris), GetDrisVarH(dris)) + + * encrypt data we want to pass. + CryptApiData(@MyData, LEN(MyData), GetDrisSeed1(dris), GetDrisSeed2(dris), alg_ans) + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(@dris, @MyData) + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + * Now decrypt this encrypted data to get the original + dris = random_dris() + SetDrisSize(@dris) + SetDrisFunction(@dris, DECRYPT_USER_DATA) && standard protection check and decrypt data + SetDrisFlags(@dris, USE_FUNCTION_ARGUMENT) && we need to set this as we are passing the data to encrypt as an extra parameter to DDProtCheck + SetDrisDataCryptKeyNum(@dris, 1) + SetDrisRWLength(@dris, Len(MyData)) + + * calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(GetDrisVarA(dris), GetDrisVarB(dris), GetDrisVarC(dris), GetDrisVarD(dris), GetDrisVarE(dris), GetDrisVarF(dris), GetDrisVarG(dris), GetDrisVarH(dris)) + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(@dris, @MyData) + + CryptDRIS(@dris, GetDrisSeed1(dris), GetDrisSeed2(dris)) && decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + IF ret_code != 0 + DisplayError(dris, ret_code) + RETURN ret_code + ENDIF + + * later in your code you can check other values in the DRIS... + IF GetDrisSDSN(dris) != MY_SDSN + ? "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN." + RETURN -1 + ENDIF + + * later on in your program you can check the return code again + IF GetDrisRetCode(@dris) != 0 + ? "Dinkey Dongle protection error" + RETURN -1 + ENDIF + + * decrypt data passed to us by API + CryptApiData(@MyData, Len(MyData), GetDrisSeed1(dris), GetDrisSeed2(dris), alg_ans) + ? "Decrypted data is: " + MyData + + * It worked! + RETURN 0 +ENDFUNC + + + +******************************** useful functions ********************************* + +* this function extract a 4-byte numeric field from the dris +FUNCTION GET4BYTES(mydris, offset) + value1 = ASC(SUBSTR(mydris, offset + 3)) * 16777216 + ; + ASC(SUBSTR(mydris, offset + 2)) * 65536 + ; + ASC(SUBSTR(mydris, offset + 1)) * 256 + ; + ASC(SUBSTR(mydris, offset)) + RETURN value1 +ENDFUNC + +* this function sets a 4-byte numeric field in the dris, you should pass dris by reference +FUNCTION SET4BYTES(mydris, offset, value1) + string_value = CHR(BITAND(value1, 255)) + CHR(BITAND(BITRSHIFT(value1, 8),255)) + CHR(BITAND(BITRSHIFT(value1, 16),255)) + CHR(BITAND(BITRSHIFT(value1, 24),255)) + mydris = STUFF(mydris, offset, 4, string_value) +ENDFUNC + +* this does the same thing but for an array +FUNCTION SETARRAY4BYTES(myArray, offset, value1) + myArray[offset] = BITAND(value1, 255) + myArray[offset+1] = BITAND(BITRSHIFT(value1, 8),255) + myArray[offset+2] = BITAND(BITRSHIFT(value1, 16),255) + myArray[offset+3] = BITAND(BITRSHIFT(value1, 24),255) +ENDFUNC + +* this function will initialise the DRIS to random values and set the first four bytes to 'DRIS' +FUNCTION random_dris + RAND(-1) && seeds using time + dris = "DRIS" + FOR i = 5 TO DRIS_SIZE + dris = dris + CHR(RAND() * 255) + ENDFOR + RETURN dris +ENDFUNC + +*** these functions let you set values in the DRIS (NB offsets are 1-based) +* NB you should pass dris by reference when you call these functions. e.g. SetDrisSize(@dris) +FUNCTION SetDrisSize(mydris) + SET4BYTES(@mydris, 5, DRIS_SIZE) +ENDFUNC + +FUNCTION SetDrisFunction(mydris, myfunction) + SET4BYTES(@mydris, 17, myfunction) +ENDFUNC + +FUNCTION SetDrisFlags(mydris, myflags) + SET4BYTES(@mydris, 21, myflags) +ENDFUNC + +FUNCTION SetDrisExecsDecrement(mydris, myexecs) + SET4BYTES(@mydris, 25, myexecs) +ENDFUNC + +FUNCTION SetDrisDataCryptKeyNum(mydris, mykey) + SET4BYTES(@mydris, 29, mykey) +ENDFUNC + +FUNCTION SetDrisRWOffset(mydris, myoffset) + SET4BYTES(@mydris, 33, myoffset) +ENDFUNC + +FUNCTION SetDrisRWLength(mydris, mylength) + SET4BYTES(@mydris, 37, mylength) +ENDFUNC + +FUNCTION SetDrisAltLicenceName(mydris, alt_licence_name) + alt_licence_name = alt_licence_name + Chr(0) && null-terminate this string + mydris = STUFF(mydris, 45, 256, alt_licence_name) +ENDFUNC + +FUNCTION SetDrisAlgVars(mydris, var_a, var_b, var_c, var_d, var_e, var_f, var_g, var_h) + SET4BYTES(@mydris, 301, var_a) + SET4BYTES(@mydris, 305, var_b) + SET4BYTES(@mydris, 309, var_c) + SET4BYTES(@mydris, 313, var_d) + SET4BYTES(@mydris, 317, var_e) + SET4BYTES(@mydris, 321, var_f) + SET4BYTES(@mydris, 325, var_g) + SET4BYTES(@mydris, 329, var_h) +ENDFUNC + +FUNCTION SetDrisAlgNumber(mydris, alg_num) + SET4BYTES(@mydris, 333, alg_num) +ENDFUNC + +*** these functions let you get values from the DRIS (NB offsets are 1-based) +FUNCTION GetDrisVarA(mydris) && you may want to use these functions if you set dris vars to be random + RETURN GET4BYTES(mydris, 301) +ENDFUNC + +FUNCTION GetDrisVarB(mydris) + RETURN GET4BYTES(mydris, 305) +ENDFUNC + +FUNCTION GetDrisVarC(mydris) + RETURN GET4BYTES(mydris, 309) +ENDFUNC + +FUNCTION GetDrisVarD(mydris) + RETURN GET4BYTES(mydris, 313) +ENDFUNC + +FUNCTION GetDrisVarE(mydris) + RETURN GET4BYTES(mydris, 317) +ENDFUNC + +FUNCTION GetDrisVarF(mydris) + RETURN GET4BYTES(mydris, 321) +ENDFUNC + +FUNCTION GetDrisVarG(mydris) + RETURN GET4BYTES(mydris, 325) +ENDFUNC + +FUNCTION GetDrisVarH(mydris) + RETURN GET4BYTES(mydris, 329) +ENDFUNC + +FUNCTION GetDrisSeed1(mydris) && you will want to use these functions if you set the seed values to be random + RETURN GET4BYTES(mydris, 9) +ENDFUNC + +FUNCTION GetDrisSeed2(mydris) + RETURN GET4BYTES(mydris, 13) +ENDFUNC + +FUNCTION GetDrisRetCode(mydris) + RETURN GET4BYTES(mydris, 337) +ENDFUNC + +FUNCTION GetDrisExtErr(mydris) + RETURN GET4BYTES(mydris, 341) +ENDFUNC + +FUNCTION GetDrisType(mydris) + RETURN GET4BYTES(mydris, 345) +ENDFUNC + +FUNCTION GetDrisModel(mydris) + RETURN GET4BYTES(mydris, 349) +ENDFUNC + +FUNCTION GetDrisSDSN(mydris) + RETURN GET4BYTES(mydris, 353) +ENDFUNC + +FUNCTION GetDrisProdCode(mydris) + * first find the length of the Product Code + FOR len = 0 TO 11 + c = SUBSTR(mydris, 357+len, 1) + IF c = CHR(0) + EXIT + ENDIF + ENDFOR + RETURN SUBSTR(mydris, 357, len) +ENDFUNC + +FUNCTION GetDrisDongleNumber(mydris) + RETURN GET4BYTES(mydris, 369) +ENDFUNC + +FUNCTION GetDrisUpdateNumber(mydris) + RETURN GET4BYTES(mydris, 373) +ENDFUNC + +FUNCTION GetDrisDataAreaSize(mydris) + RETURN GET4BYTES(mydris, 377) +ENDFUNC + +FUNCTION GetDrisMaxAlgNum(mydris) + RETURN GET4BYTES(mydris, 381) +ENDFUNC + +FUNCTION GetDrisExecs(mydris) + RETURN GET4BYTES(mydris, 385) +ENDFUNC + +FUNCTION GetDrisExpDay(mydris) + RETURN GET4BYTES(mydris, 389) +ENDFUNC + +FUNCTION GetDrisExpMonth(mydris) + RETURN GET4BYTES(mydris, 393) +ENDFUNC + +FUNCTION GetDrisExpYear(mydris) + RETURN GET4BYTES(mydris, 397) +ENDFUNC + +FUNCTION GetDrisFeatures(mydris) + RETURN GET4BYTES(mydris, 401) +ENDFUNC + +FUNCTION GetDrisNetUsers(mydris) + RETURN GET4BYTES(mydris, 405) +ENDFUNC + +FUNCTION GetDrisAlgAnswer(mydris) + RETURN GET4BYTES(mydris, 409) +ENDFUNC + +FUNCTION GetDrisFDCapacity(mydris) + RETURN GET4BYTES(mydris, 413) +ENDFUNC + +FUNCTION GetDrisFDDrive(mydris) + RETURN SUBSTR(mydris, 417, 3) +ENDFUNC + +FUNCTION GetDrisSWKeyType(mydris) + RETURN GET4BYTES(mydris, 545) +ENDFUNC + +FUNCTION GetDrisSWKeyExpDay(mydris) + RETURN GET4BYTES(mydris, 549) +ENDFUNC + +FUNCTION GetDrisSWKeyExpMonth(mydris) + RETURN GET4BYTES(mydris, 553) +ENDFUNC + +FUNCTION GetDrisSWKeyExpYear(mydris) + RETURN GET4BYTES(mydris, 557) +ENDFUNC + + +*** displays messages for the most common errors. You will want to change this for your code +FUNCTION DisplayError(mydris, ret_code) + DO CASE + CASE ret_code = 401 + ? "Error! No dongles detected!" + + CASE ret_code = 403 + ? "Error! The dongle detected has a different type to the one specified in DinkeyAdd." + + CASE ret_code = 404 + ? "Error! The dongle detected has a different model to those specified in DinkeyAdd." + + CASE ret_code = 409 + ? "Error! The dongle detected has not been programmed by DinkeyAdd." + + CASE ret_code = 410 + ? "Error! The dongle detected has a different Product Code to the one specified in DinkeyAdd." + + CASE ret_code = 411 + ? "Error! The dongle detected does not contain the licence associated with this program." + + CASE ret_code = 413 + ? "Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual." + + CASE ret_code = 417 + ? "Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa." + + CASE ret_code = 423 + ? "Error! The number of network users has been exceeded." + + CASE ret_code = 435 + ? "Error! DinkeyServer has not been detected on the network." + + CASE ret_code = 922 + ? "Error! The Software Key has expired." + + OTHERWISE + ? "An error occurred checking the dongle. Error: " + STR(ret_code) + " Extended Error: " + STR(GetDrisExtErr(mydris)) + + ENDCASE + RETURN +ENDFUNC diff --git a/Dinkey Pro 7.6.1/Samples/Java/DinkeyChange/DCSample.java b/Dinkey Pro 7.6.1/Samples/Java/DinkeyChange/DCSample.java new file mode 100644 index 0000000..cbd86f9 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Java/DinkeyChange/DCSample.java @@ -0,0 +1,322 @@ +// A simple program illustrating how to use the DinkeyChange API in Java. +// Copyright 2018 Microcosm Ltd. + +import uk.microcosm.dinkeydongle.DinkeyChange; +import uk.microcosm.dinkeydongle.DinkeyChangeException; +import uk.microcosm.dinkeydongle.DongleToChange; + +import java.io.*; + +public class DCSample +{ + public static void main(String[] args) + { + String userChoice = ""; + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + + // Prompt the user for the DinkeyChange operation to perform + System.out.println(); + System.out.println("1) Display information about dongles attached to this computer"); + System.out.println("2) Save diagnostic information to a file"); + System.out.println("3) Apply an update code from a file"); + System.out.println("4) Apply a short update code"); + System.out.println("5) Restore a Dinkey FD Lite dongle"); + System.out.println("6) Display this computer's machine ID"); + System.out.println("7) Download and install a temporary software key"); + System.out.println("8) Download and install a demo software key"); + System.out.print("Enter an option 1 to 8. Enter anything else to exit: "); + try + { + userChoice = br.readLine(); + } + catch (IOException e) + { + System.err.println(e.getMessage()); + System.exit(1); + } + System.out.println(); + + if (userChoice.equals("1")) + { + /* DinkeyChange.getDongles() - get information about dongles attached to this computer. + This method returns an array of DongleToChange objects. You can use this method's arguments + to control which dongles it searches for - see README.html for more information. */ + + int i; + DongleToChange[] dongles; + + try + { // Search for all types and models of dongle, with any product code + dongles = DinkeyChange.getDongles(DinkeyChange.TYPE_MASK_ALL, DinkeyChange.MODEL_MASK_ALL, ""); + + for (i = 0; i < dongles.length; i++) + { + /* Display information about each dongle found that matched the search criteria. + This information is needed by DinkeyRemote to create update codes for these dongles. */ + + System.out.println((i+1) + ": Dinkey " + dongles[i].typeAsString + " " + dongles[i].modelAsString); + System.out.println("\tDongle Number: " + dongles[i].dongleNumber); + System.out.println("\tProduct Code: " + dongles[i].productCode); + System.out.println("\tUpdate Number: " + dongles[i].updateNumber); + } + } + catch (DinkeyChangeException e) + { + displayError(e); + } + } + + else if (userChoice.equals("2")) + { + /* DinkeyChange.writeDiagnosticsToFile() - this method creates an encrypted DLPF file containing diagnostics + and the parameters stored in each dongle currently attached to this computer. This file can be opened with DinkeyLook. + This method can take a String or File argument, i.e. DinkeyChange.writeDiagnosticsToFile("out.dlpf") + is exactly equivalent to DinkeyChange.writeDiagnosticsToFile(new File("out.dlpf")) */ + + String filename = null; + + // Prompt for the name of the DLPF file to create. + // This file's path can be absolute, or relative to the current working directory. + // If the name does not include a ".dlpf" extension, it will automatically be added. + System.out.print("Enter output filename: "); + try + { + filename = br.readLine(); + } + catch (IOException e) + { + System.err.println(e.getMessage()); + } + + try + { // If successful, DinkeyChange.writeDiagnosticsToFile() returns the full path to the file it created + System.out.println("Diagnostics written to " + DinkeyChange.writeDiagnosticsToFile(new File(filename))); + } + catch (DinkeyChangeException e) + { + displayError(e); + } + } + + else if (userChoice.equals("3")) + { + /* DinkeyChange.applyUpdate(File) - this method takes a File object representing + a secure update code file (DUCF file) and applies the code to the relevant dongle + attached to this computer, updating the parameters stored in that dongle. */ + + File f; + String filename = null; + String confirmationCode; + + // Prompt user for location of DUCF file. + // The path to the file can be absolute, or relative to the current working directory + System.out.print("Enter secure update code filename: "); + try + { + filename = br.readLine(); + } + catch (IOException e) + { + System.err.println(e.getMessage()); + } + + f = new File(filename); // Create a File object representing the DUCF file + try + { // If successful, DinkeyChange.applyUpdate() returns the confirmation code for this update + confirmationCode = Integer.toHexString(DinkeyChange.applyUpdate(f)); + System.out.println("Update code successfully applied. Confirmation code is " + confirmationCode); + } + catch (DinkeyChangeException e) + { + displayError(e); + } + } + + else if (userChoice.equals("4")) + { + /* DinkeyChange.applyUpdate(String) - this method takes a short secure update code + and applies it to the relevant dongle attached to this computer, updating the parameters + stored in that dongle. */ + + String updateCode = null; + String confirmationCode; + + // Prompt the user for the short update code + System.out.print("Enter update code: "); + try + { + updateCode = br.readLine(); + } + catch (IOException e) + { + System.err.println(e.getMessage()); + } + + try + { // If successful, DinkeyChange.applyUpdate() returns the confirmation code for this update + confirmationCode = Integer.toHexString(DinkeyChange.applyUpdate(updateCode)); + System.out.println("Update code successfully applied. Confirmation code is " + confirmationCode); + } + catch (DinkeyChangeException e) + { + displayError(e); + } + } + + else if (userChoice.equals("5")) + { + // DinkeyChange.restoreDinkeyFDLite() - restore a Dinkey FD Lite dongle + + try + { + DinkeyChange.restoreDinkeyFDLite(); + System.out.println("Dinkey FD Lite restored successfully."); + } + catch (DinkeyChangeException e) + { + displayError(e); + } + } + + else if (userChoice.equals("6")) + { + // DinkeyChange.getMachineID() - get this computer's machine ID + + String machineIDString; + + try + { + machineIDString = Long.toHexString(DinkeyChange.getMachineID()); + System.out.println("The Machine ID is " + machineIDString); + } + catch (DinkeyChangeException e) + { + displayError(e); + } + } + + else if (userChoice.equals("7")) + { + // DinkeyChange.downloadTempSoftwareKey() - download and install a temporary software key + + try + { + DinkeyChange.downloadTempSoftwareKey(); + System.out.println("The temporary software key has been downloaded successfully."); + } + catch (DinkeyChangeException e) + { + displayError(e); + } + } + + else if (userChoice.equals("8")) + { + // DinkeyChange.downloadDemoSoftwareKey() - download and install a demo software key + + String productCode = null; + + // Prompt for the product code to use + System.out.print("Enter product code of demo software key: "); + try + { + productCode = br.readLine(); + } + catch (IOException e) + { + System.err.println(e.getMessage()); + } + + try + { + // This examples assumes that exactly one dongle model is set in the demo template + // If multiple models are set in the template you will need to use the second parameter to specify which model to download and install + DinkeyChange.downloadDemoSoftwareKey(productCode, DinkeyChange.SWKEY_MODEL_DEFAULT); + System.out.println("The demo software key has been downloaded successfully."); + } + catch (DinkeyChangeException e) + { + displayError(e); + } + } + + System.exit(0); + + } // End of main() + + + // An example of error reporting + // Displays descriptions for some common error codes + static void displayError(DinkeyChangeException e) + { + switch (e.getError()) + { + case 401: + System.out.println("Error! No dongles detected that meet the search criteria!"); + break; + + case 409: + System.out.println("Error! The dongle detected has not been programmed by DinkeyAdd."); + break; + + case 758: + System.out.println("Error! Cannot open the update code file specified."); + break; + + case 759: + System.out.println("Error! The file specified is not a valid update code file."); + break; + + case 762: + case 763: + case 764: + System.out.println("Error! Update code is not in a correct format / update code file is corrupt."); + break; + + case 765: + System.out.println("Error! The update code does not match any dongle attached to your machine."); + break; + + case 766: + System.out.println("Error! The update number for this update code is too high. You need to first enter an update code that was previously sent to you."); + break; + + case 767: + System.out.println("Error! You have already entered this update code."); + break; + + case 1905: + System.out.println("Error! There is no software key available for download."); + break; + + case 1907: + System.out.println("Error! The temporary software key has expired. Cannot download it."); + break; + + case 1910: + System.out.println("Error! The software key has already been downloaded."); + break; + + case 1921: + System.out.println("Error! You specified the 'default model' but there is more than one model available. You need to specify a specific dongle model."); + break; + + case 1922: + System.out.println("Error! The model you requested is not available."); + break; + + case 1923: + System.out.println("Error! The demo software key template has been disabled."); + break; + + case 1924: + System.out.println("Error! You have run out of demo software key activations. You need to order some more."); + break; + + default: + System.err.println("DinkeyChange error " + e.getError() + ":" + e.getExtendedError()); + System.err.println(e.getMessage()); + } + } + +} // End of class DCSample diff --git a/Dinkey Pro 7.6.1/Samples/Java/DinkeyChange/README.html b/Dinkey Pro 7.6.1/Samples/Java/DinkeyChange/README.html new file mode 100644 index 0000000..6f47dee --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Java/DinkeyChange/README.html @@ -0,0 +1,335 @@ + + + + + Using the DinkeyChange API with Java + + + +

Using the DinkeyChange API with Java

+

+ The DinkeyChange API allows you apply secure update codes to modify the information + stored in Dinkey Pro and FD dongles directly from your Java application. + The API also allows you to view the information needed to create these codes, and produce + encrypted diagnostic files to help you troubleshoot any dongle-related problems your users might have. +

+

+ The DinkeyChange class provides a Java wrapper around the API, which is implemented by native libraries. + If you are not familiar with calling native libraries, it is recommended that you read the Java documentation on the subject, + especially the documentation for System.loadLibrary(), + and how Java uses the system property java.library.path to locate native libraries. +

+

+ The native libraries and the classes described below are part of the uk.microcosm.dinkeydongle package. + See the documentation for your development environment for details of how to include and reference this package in your project. + dinkeydongle.jar provides all of the Java classes in the uk.microcosm.dinkeydongle package in a single JAR file. + This allows you to import the package much more easily in many Java IDEs. Note that the native libraries are not included in the JAR file. + You will need to distribute with your software the native libraries for every platform that your software supports. +

+ +

The DinkeyChange Class

+

+ This class exposes the DinkeyChange API to Java programs. + It contains only static methods and fields, and cannot be instantiated. +

+ +

Fields

+

+ Useful constants you can use in your code: +

+
    +
  • static final int MAX_USB_DEVICES - maximum number of dongles that the API can return information about.
  • +
  • static final int MAX_PRODCODE_LEN - maximum length of a product code string.
  • +
+

+ Possible values to use as the typeMask parameter of DinkeyChange.getDongles(): +

+
    +
  • static final int TYPE_MASK_PRO - search for Dinkey Pro dongles only.
  • +
  • static final int TYPE_MASK_FD - search for Dinkey FD dongles only.
  • +
  • static final int TYPE_MASK_ALL - search for both Dinkey Pro and FD dongles.
  • +
+

+ Possible values to use as the modelMask parameter of DinkeyChange.getDongles(): +

+
    +
  • static final int MODEL_MASK_LITE - search for Lite dongles only.
  • +
  • static final int MODEL_MASK_PLUS - search for Plus dongles only.
  • +
  • static final int MODEL_MASK_NET - search for Net dongles only.
  • +
  • static final int MODEL_MASK_ALL - search for all models of dongle.
  • +
  • static final int MODEL_MASK_DEFAULT - search only for models that can be modified using update codes (i.e. ignore Lite dongles.)
  • +
+

+ Possible values to use as the model parameter of DinkeyChange.downloadDemoSoftwareKey(): +

+
    +
  • static final int SWKEY_MODEL_DEFAULT - download the default model (valid only if exactly one model is set in the demo key template).
  • +
  • static final int SWKEY_MODEL_PRO_LITE - download a Pro Lite demo software key.
  • +
  • static final int SWKEY_MODEL_PRO_PLUS - download a Pro Plus demo software key.
  • +
  • static final int SWKEY_MODEL_PRO_NET - download a Pro Net demo software key.
  • +
  • static final int SWKEY_MODEL_FD_LITE - download an FD Lite demo software key.
  • +
  • static final int SWKEY_MODEL_FD_PLUS - download an FD Plus demo software key.
  • +
  • static final int SWKEY_MODEL_FD_NET - download an FD Net demo software key.
  • +
+ +

Methods

+

+ All methods in this class throw a DinkeyChangeException if the underlying native API call fails. + The DinkeyChangeException contains the error code and extended error code returned by the native API function. +

+ +

static DongleToChange[] getDongles(int typeMask, int modelMask, String productCodeMask)

+

+ Returns a list of the dongles attached to this computer that match the search criteria specified by the method's arguments. + typeMask and modelMask should be set to one of the possible values listed above. + If productCodeMask is specified, only dongles with a product code that exactly matches (case is not important) this string will be returned. + In most cases this string will be the product code of your protected application. + Use null or the empty string as this parameter to search for dongles with any product code. +

+ +

static String writeDiagnosticsToFile(String filename)

+

+ Writes diagnostic information about all dongles connnected to this computer to the file specified by filename. + The output file is encrypted, and its contents can only be viewed using DinkeyLook. + The path to the file can be absolute, or relative to the current working directory. + If the filename does not end in ".dlpf" this extension will be added automatically. + This method returns the absolute path to the file created. +

+ +

static String writeDiagnosticsToFile(java.io.File file)

+

+ Writes diagnostic information about all dongles connnected to this computer to the file represented by file. + The output file is encrypted, and its contents can only be viewed using DinkeyLook. + The path to the file can be absolute, or relative to the current working directory. + If the filename does not end in ".dlpf" this extension will be added automatically. + This method returns the absolute path to the file created. +

+ +

static int applyUpdate(String updateCode)

+

+ Applies a short secure update code to a dongle connected to this computer. + Returns the confirmation code for this update. +

+ +

static int applyUpdate(java.io.File updateFile)

+

+ Applies the secure update code in the file represented by updateFile to a dongle connected to this computer. + Returns the confirmation code for this update. +

+ +

static void restoreDinkeyFDLite()

+

+ Restores the hidden .DO NOT DELETE.dat on a Dinkey FD Lite dongle. +

+ +

static long getmachineID()

+

+ Returns the machine ID required to generate a temporary software key for this computer. +

+ +

static void downloadTempSoftwareKey()

+

+ Downloads and installs a temporary software key that was created by DinkeyAdd. +

+ +

static void downloadDemoSoftwareKey(String productCode, int model)

+

+ Downloads and installs a demo software key from a demo template that was created by DinkeyAdd. + productCode specifies the product code of the demo template to download the key from. + model specifies the model of demo key to download, and should be set to one of the values listed above. +

+ +

The DongleToChange Class

+

+ An instance of DongleToChange represents one dongle found by DinkeyChange.getDongles(). +

+ +

Fields

+

+ Possible values for type: +

+
    +
  • static final int TYPE_PRO - a Dinkey Pro dongle.
  • +
  • static final int TYPE_FD - a Dinkey FD dongle.
  • +
+

+ Possible values for mask: +

+
    +
  • static final int MODEL_LITE - a Lite dongle.
  • +
  • static final int MODEL_PLUS - a Plus dongle.
  • +
  • static final int MODEL_NET5 - a Net dongle (5 users).
  • +
  • static final int MODEL_NETU - a Net dongle (unlimited users).
  • +
+

+ Fields that provide information needed to create an update code for this dongle: +

+
    +
  • final int type - integer representation of the dongle type.
  • +
  • final String typeAsString - string representation of the dongle type.
  • +
  • final int model - integer representation of the dongle model.
  • +
  • final String modelAsString - string representation of the dongle model.
  • +
  • final String productCode - the dongle's product code.
  • +
  • final long dongleNumber - the dongle's dongle number (sometimes called dongle serial number).
  • +
  • final int updateNumber - the dongle's update number.
  • +
+ +

The DinkeyChangeException Class

+

+ An instance of this Exception subclass is thrown if a call to the DinkeyChange API fails. + The usual getMessage() method returns a string providing general information about the error. + If the problem occurred in Java code, getCause() will return the Java exception that caused the DinkeyChangeException. +

+ +

Methods

+

+ DinkeyChangeException's methods provide further details about the error that occurred. + It is strongly recommended that you display this information in the event of an error, + to help both you and us troubleshoot a recurring problem. + More information about Dinkey Pro/FD error numbers can be found in the user manual chapter Error Codes + and online in our knowledge base. +

+

int getError()

+

+ Returns an error code indicating the cause of the error. +

+

int getExtendedError()

+

+ Returns an extended error code providing additional information about the error. +

+ +

Java Example Files

+
    +
  • DCSample.java - various examples of using the DinkeyChange classes.
  • +
+ +

Supported Versions

+

+ All parts of the uk.microcosm.dinkeydongle package support Java platforms version 5 and newer. +

+ +

Try It Yourself

+

+ DCSample.java gives a simple example of calling each of the API functions. + To run the DCSample program you will need a copy of the appropriate shared library for your platform + (DinkeyChange.dll for 32-bit Windows, DinkeyChange64.so for 64-bit Linux etc.). + Place the library in one of the paths specified by your Java environment's java.library.path system property. + Browse the examples in DCSample.java to see how different features can be used. +

+ + + diff --git a/Dinkey Pro 7.6.1/Samples/Java/Runtime/DPSample.java b/Dinkey Pro 7.6.1/Samples/Java/Runtime/DPSample.java new file mode 100644 index 0000000..3c93108 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Java/Runtime/DPSample.java @@ -0,0 +1,612 @@ +// Example use of the Dinkey Pro/FD API in Java. +// Copyright 2018 Microcosm Ltd. + +import uk.microcosm.dinkeydongle.DinkeyPro; +import java.util.Arrays; // For Arrays.toString() + +class DPSample +{ + static final String MY_PRODCODE = "DEMO"; // !!!! Replace "DEMO" with the product code that you specify when adding protection with DinkeyAdd. + static final int MY_SDSN = 10101; // !!!! "10101" is the SDSN used by the demo SDK and demo dongles. + // If not using a demo, replace "10101" with your own SDSN here. + + static final int DRIS_ENCRYPTION_PARAMETER_1 = 123; // !!!! If you enable DRIS encryption when adding protection with DinkeyAdd, + static final int DRIS_ENCRYPTION_PARAMETER_2 = 212; // replace these values with the encryption parameters that you specify. + static final int DRIS_ENCRYPTION_PARAMETER_3 = 97; + + public static void main(String[] args) + { + // Each of the methods below demonstrates different API functionality. + // Uncomment the appropriate methods to execute the examples. + // See the comments in each method for more details about the features that they demonstrate. + + protCheck(); + // protCheckWithAlg(); + // writeDataArea(); + // readDataArea(); + // encryptUserData(); + // protCheckEnc(); + // writeDataAreaEnc(); + // readDataAreaEnc(); + // encryptUserDataEnc(); + // displayNetUsers(); + } + + // An example of a basic protection check + static void protCheck() + { + int retCode; + + // Create a DinkeyPro instance that uses the default library name, DPJava. + // All DRIS fields are initialised to random values. + DinkeyPro ddpro = new DinkeyPro(); + + // You can use an alternative library name like this: + // DinkeyPro ddpro = new DinkeyPro("MyName"); + // The manner in which the library name is mapped to the actual system library is system dependent, + // but common behaviour is that Java will attempt to locate and load MyName.dll on Windows, libMyName.dylib on macOS, + // or libMyName.so on Linux. + + // You can also specify the full path to the library, if it is not located in one of the paths specified by java.library.path, + // or uses a non-standard filename: + // Dinkey ddpro = new DinkeyPro("~/Unusual Folder For Libraries/nonstandardname.jnilib"); + + // Initialise the DRIS + ddpro.function = DinkeyPro.PROTECTION_CHECK; + ddpro.flags = DinkeyPro.DEC_ONE_EXEC | DinkeyPro.START_NET_USER; + + // Call the API + retCode = ddpro.checkProtection(); + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + // ... + + // You can check other values from the DRIS in other parts of your program to improve security. + // For example: + + // Check the SDSN + if (ddpro.sdsn != MY_SDSN) + { + System.out.println("Incorrect SDSN! Have you replaced '10101' with your SDSN in the sample code?"); + return; + } + + // Check the product code + if (!(ddpro.getProdCode().equals(MY_PRODCODE))) + { + System.out.println("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle."); + return; + } + + System.out.println("Protection check successful."); + return; + } + + // An example of a protection check that also executes an algorithm stored in the dongle. + // The best way to use this feature is to identify lines of code in your program + // that can be represented by algorithms stored in the dongle, + // and replace these lines with calls to the API. + // Lite dongle users cannot change the algorithm stored in the dongles, + // so should calculate the algorithm in their own code and compare the result with the one returned by the API, + // as in this example. + static void protCheckWithAlg() + { + int retCode; + DinkeyPro ddpro = new DinkeyPro(); + + // Initialise the DRIS + ddpro.function = DinkeyPro.EXECUTE_ALGORITHM; + ddpro.flags = 0; + ddpro.alg_number = 1; // The algorithm to execute. Lite dongles ignore this field, as they contain only 1 algorithm + ddpro.var_a = 1; // The input variables to use in the algorithm + ddpro.var_b = 2; + ddpro.var_c = 3; + ddpro.var_d = 4; + ddpro.var_e = 5; + ddpro.var_f = 6; + ddpro.var_g = 7; + ddpro.var_h = 8; + + // Call the API + retCode = ddpro.checkProtection(); + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + // ... + + // Check the algorithm result in another part of your program to improve security. + // !!!! Ensure the myAlgorithm() method matches the algorithm that was executed by the protection check! + if (myAlgorithm(ddpro.var_a, ddpro.var_b, ddpro.var_c, ddpro.var_d, ddpro.var_e, ddpro.var_f, ddpro.var_g, ddpro.var_h) != ddpro.alg_answer) + { + System.out.println("Error! The algorithm result was not as expected."); + return; + } + + System.out.println("Protection check with algorithm successful."); + return; + } + + // An example of a protection check that also writes data to the dongle's secure data area. + // This feature is not supported by Lite dongles. + // Make sure you specify a large enough data area size when adding protection with DinkeyAdd! + static void writeDataArea() + { + int retCode; + DinkeyPro ddpro = new DinkeyPro(); + byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // Data to write + + // Initialise the DRIS + ddpro.function = DinkeyPro.WRITE_DATA_AREA; + ddpro.flags = DinkeyPro.USE_FUNCTION_ARGUMENT; // Java uses DDProtCheck()'s data parameter, so this flag must be set + ddpro.rw_offset = 0; // Index to start writing at. Indices start at zero + ddpro.rw_length = data.length; // The number of bytes to be written + + // Call the API + retCode = ddpro.checkProtection(data); + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + // You can inspect the dongle with DinkeyLook to see that the data has been written to the dongle + + System.out.println("Writing data successful."); + return; + } + + // An example of a protection check that also reads data from the dongle's secure data area. + // This feature is not supported by Lite dongles. + // Make sure you specify a large enough data area size when adding protection with DinkeyAdd! + static void readDataArea() + { + int retCode; + DinkeyPro ddpro = new DinkeyPro(); + byte[] data = new byte[10]; + + // Initialise the DRIS + ddpro.function = DinkeyPro.READ_DATA_AREA; + ddpro.flags = DinkeyPro.USE_FUNCTION_ARGUMENT; // Java uses DDProtCheck()'s data parameter, so this flag must be set + ddpro.rw_offset = 0; // Index to start reading from. Indices start at zero + ddpro.rw_length = data.length; // The number of bytes to read + + // Call the API + retCode = ddpro.checkProtection(data); + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + System.out.println("Reading data successful: " + Arrays.toString(data)); + return; + } + + // An example of protection checks that encrypt/decrypt your data. + // This feature is not supported by Lite dongles. + static void encryptUserData() + { + int retCode; + DinkeyPro ddpro = new DinkeyPro(); + byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // The data to be encrypted + byte[] originalData = data.clone(); // A copy of the data for displaying later + byte[] encryptedData; + + // Initialise the DRIS + ddpro.function = DinkeyPro.ENCRYPT_USER_DATA; + ddpro.flags = DinkeyPro.USE_FUNCTION_ARGUMENT; // Java uses DDProtCheck()'s data parameter, so this flag must be set + ddpro.rw_length = data.length; // The number of bytes to be encrypted + ddpro.data_crypt_key_num = 1; // The encryption key to use + + // Call the API + retCode = ddpro.checkProtection(data); + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + encryptedData = data.clone(); // A copy of the encrypted data for displaying later + + // Initialise the DRIS + ddpro.reset(); // Reset the DRIS fields with random values + ddpro.function = DinkeyPro.DECRYPT_USER_DATA; + ddpro.flags = DinkeyPro.USE_FUNCTION_ARGUMENT; // Java uses DDProtCheck()'s data parameter, so this flag must be set + ddpro.rw_length = data.length; + ddpro.data_crypt_key_num = 1; // This must be the same key used to encrypt the data + + // Call the API + retCode = ddpro.checkProtection(data); + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + System.out.println("Data encryption successful."); + System.out.println("Original data: " + Arrays.toString(originalData)); + System.out.println("Encrypted data: " + Arrays.toString(encryptedData)); + System.out.println("Decrypted data: " + Arrays.toString(data)); + return; + } + + // An example of a protection check that uses DRIS encryption for extra security. + static void protCheckEnc() + { + int retCode; + DinkeyPro ddpro = new DinkeyPro(); + + // Initialise the DRIS + ddpro.function = DinkeyPro.PROTECTION_CHECK; + ddpro.flags = 0; + + // Encrypt the DRIS + ddpro.cryptDris(DRIS_ENCRYPTION_PARAMETER_1, DRIS_ENCRYPTION_PARAMETER_2, DRIS_ENCRYPTION_PARAMETER_3); + + // Call the API + retCode = ddpro.checkProtection(); + + // Decrypt the DRIS + ddpro.cryptDris(DRIS_ENCRYPTION_PARAMETER_1, DRIS_ENCRYPTION_PARAMETER_2, DRIS_ENCRYPTION_PARAMETER_3); + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + // ... + + // You can check other values from the DRIS in other parts of your program to improve security. + // For example: + + // Check the SDSN + if (ddpro.sdsn != MY_SDSN) + { + System.out.println("Incorrect SDSN! Have you replaced '10101' with your SDSN in the sample code?"); + return; + } + + // Check the product code + if (!(ddpro.getProdCode().equals(MY_PRODCODE))) + { + System.out.println("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle."); + return; + } + + System.out.println("Protection check successful."); + return; + } + + // An example of a protection check that also writes data to the dongle's secure data area. + // This feature is not supported by Lite dongles. + // Make sure you specify a large enough data area size when adding protection with DinkeyAdd! + // This method also uses DRIS encryption and data encryption for extra security. + // You must select these options on the Extra Security tab of DinkeyAdd for this method to work correctly! + static void writeDataAreaEnc() + { + int retCode, algAnswer; + DinkeyPro ddpro = new DinkeyPro(); + byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // The data to be written + + // Initialise the DRIS + ddpro.function = DinkeyPro.WRITE_DATA_AREA; + ddpro.flags = DinkeyPro.USE_FUNCTION_ARGUMENT; // Java uses DDProtCheck()'s data parameter, so this flag must be set + ddpro.rw_offset = 0; // Index to start writing at. Indices start at zero + ddpro.rw_length = data.length; // The number of bytes to write + + // If taking data encryption parameters from the R/W algorithm: + // Calculate the R/W algorithm result + // The input variables were initialised to random values when ddpro was created + algAnswer = myRwAlgorithm(ddpro.var_a, ddpro.var_b, ddpro.var_c, ddpro.var_d, ddpro.var_e, ddpro.var_f, ddpro.var_g, ddpro.var_h); + + // Use the algorithm result to encrypt the data to be written to the dongle + ddpro.cryptApiData(data, algAnswer); + + // If using constant data encryption parameters: + // ddpro.cryptApiData(data, DATA_ENCRYPTION_PARAMETER_1, DATA_ENCRYPTION_PARAMETER_2, DATA_ENCRYPTION_PARAMETER_3); + + // Encrypt the DRIS + ddpro.cryptDris(DRIS_ENCRYPTION_PARAMETER_1, DRIS_ENCRYPTION_PARAMETER_2, DRIS_ENCRYPTION_PARAMETER_3); + + // Call the API + retCode = ddpro.checkProtection(data); + + // Decrypt the DRIS + ddpro.cryptDris(DRIS_ENCRYPTION_PARAMETER_1, DRIS_ENCRYPTION_PARAMETER_2, DRIS_ENCRYPTION_PARAMETER_3); + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + System.out.println("Writing data successful."); + return; + } + + // An example of a protection check that also reads data from the dongle's secure data area. + // This feature is not supported by Lite dongles. + // Make sure you specify a large enough data area size when adding protection with DinkeyAdd! + // This method also uses DRIS encryption and data encryption for extra security. + // You must select these options on the Extra Security tab of DinkeyAdd for this method to work correctly! + static void readDataAreaEnc() + { + int retCode, algAnswer; + DinkeyPro ddpro = new DinkeyPro(); + byte[] data = new byte[10]; + + // Initialise the DRIS + ddpro.function = DinkeyPro.READ_DATA_AREA; + ddpro.flags = DinkeyPro.USE_FUNCTION_ARGUMENT; // Java uses DDProtCheck()'s data parameter, so this flag must be set + ddpro.rw_offset = 0; // Index to start reading from. Indices start at zero + ddpro.rw_length = data.length; // The number of bytes to read + + // Encrypt the DRIS + ddpro.cryptDris(DRIS_ENCRYPTION_PARAMETER_1, DRIS_ENCRYPTION_PARAMETER_2, DRIS_ENCRYPTION_PARAMETER_3); + + // Call the API + retCode = ddpro.checkProtection(data); + + // Decrypt the DRIS + ddpro.cryptDris(DRIS_ENCRYPTION_PARAMETER_1, DRIS_ENCRYPTION_PARAMETER_2, DRIS_ENCRYPTION_PARAMETER_3); + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + // If taking data encryption parameters from the R/W algorithm: + // Calculate the R/W algorithm result + // The input variables were initialised to random values when ddpro was created + algAnswer = myRwAlgorithm(ddpro.var_a, ddpro.var_b, ddpro.var_c, ddpro.var_d, ddpro.var_e, ddpro.var_f, ddpro.var_g, ddpro.var_h); + + // Use the algorithm result to decrypt the data read from the dongle + ddpro.cryptApiData(data, algAnswer); + + // If using constant data encryption parameters: + // ddpro.cryptApiData(data, DATA_ENCRYPTION_PARAMETER_1, DATA_ENCRYPTION_PARAMETER_2, DATA_ENCRYPTION_PARAMETER_3); + + System.out.println("Reading data successful: " + Arrays.toString(data)); + return; + } + + // An example of protection checks that encrypt/decrypt your data. + // This feature is not supported by Lite dongles. + // This method also uses DRIS encryption and data encryption for extra security. + // You must select these options on the Extra Security tab of DinkeyAdd for this method to work correctly! + static void encryptUserDataEnc() + { + int retCode, algAnswer; + DinkeyPro ddpro = new DinkeyPro(); + byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // The data to be encrypted + byte[] originalData = data.clone(); // A copy of the data for displaying later + byte[] encryptedData; + + // Initialise the DRIS + ddpro.function = DinkeyPro.ENCRYPT_USER_DATA; + ddpro.flags = DinkeyPro.USE_FUNCTION_ARGUMENT; // Java uses DDProtCheck()'s data parameter, so this flag must be set + ddpro.rw_length = data.length; // The number of bytes to be encrypted + ddpro.data_crypt_key_num = 1; // The encryption key to use + + // If taking data encryption parameters from the R/W algorithm: + // Calculate the R/W algorithm result + // The input variables were initialised to random values when ddpro was created + algAnswer = myRwAlgorithm(ddpro.var_a, ddpro.var_b, ddpro.var_c, ddpro.var_d, ddpro.var_e, ddpro.var_f, ddpro.var_g, ddpro.var_h); + + // Use the algorithm result to encrypt the data passed to the API + ddpro.cryptApiData(data, algAnswer); + + // If using constant data encryption parameters: + // ddpro.cryptApiData(data, DATA_ENCRYPTION_PARAMETER_1, DATA_ENCRYPTION_PARAMETER_2, DATA_ENCRYPTION_PARAMETER_3); + + // Encrypt the DRIS + ddpro.cryptDris(DRIS_ENCRYPTION_PARAMETER_1, DRIS_ENCRYPTION_PARAMETER_2, DRIS_ENCRYPTION_PARAMETER_3); + + // Call the API + retCode = ddpro.checkProtection(data); + + // Decrypt the DRIS + ddpro.cryptDris(DRIS_ENCRYPTION_PARAMETER_1, DRIS_ENCRYPTION_PARAMETER_2, DRIS_ENCRYPTION_PARAMETER_3); + + // Do not call cryptApiData() here to decrypt the data received from the API! + // The data has been encrypted by the dongle hardware, so the API will not apply an unnecessary second layer of encryption + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + encryptedData = data.clone(); // A copy of the encrypted data for displaying later + + // Initialise the DRIS + ddpro.reset(); // Reset the DRIS fields with random values + ddpro.function = DinkeyPro.DECRYPT_USER_DATA; + ddpro.flags = DinkeyPro.USE_FUNCTION_ARGUMENT; // Java uses DDProtCheck()'s data parameter, so this flag must be set + ddpro.rw_length = data.length; + ddpro.data_crypt_key_num = 1; // This must be the same key used to encrypt the data + + // Encrypt the DRIS + ddpro.cryptDris(DRIS_ENCRYPTION_PARAMETER_1, DRIS_ENCRYPTION_PARAMETER_2, DRIS_ENCRYPTION_PARAMETER_3); + + // Do not call cryptApiData() here to encrypt the data passed to the API! + // The data is already encrypted, so the API does not expect an unnecessary second layer of encryption + + // Call the API + retCode = ddpro.checkProtection(data); + + // Decrypt the DRIS + ddpro.cryptDris(DRIS_ENCRYPTION_PARAMETER_1, DRIS_ENCRYPTION_PARAMETER_2, DRIS_ENCRYPTION_PARAMETER_3); + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + // If taking data encryption parameters from the R/W algorithm: + // Calculate the R/W algorithm result + // The input variables were initialised to random values when ddpro was created + algAnswer = myRwAlgorithm(ddpro.var_a, ddpro.var_b, ddpro.var_c, ddpro.var_d, ddpro.var_e, ddpro.var_f, ddpro.var_g, ddpro.var_h); + + // Use the algorithm result to decrypt the data received from the API + ddpro.cryptApiData(data, algAnswer); + + // If using constant data encryption parameters: + // ddpro.cryptApiData(data, DATA_ENCRYPTION_PARAMETER_1, DATA_ENCRYPTION_PARAMETER_2, DATA_ENCRYPTION_PARAMETER_3); + + System.out.println("Data encryption successful."); + System.out.println("Original data: " + Arrays.toString(originalData)); + System.out.println("Encrypted data: " + Arrays.toString(encryptedData)); + System.out.println("Decrypted data: " + Arrays.toString(data)); + return; + } + + // An example of a simple protection check and displaying information about the current users of a network dongle. + // This feature is supported by Dinkey Pro Net and Dinkey FD Net dongles only. + // queryNetUsers() will only work following a call to checkProtection() that established a connection to DinkeyServer. + static void displayNetUsers() + { + int retCode, maxNetUsersToQuery; + + DinkeyPro ddpro = new DinkeyPro(); // Create a DinkeyPro instance. All DRIS fields are initialised to random values + + // Initialise the DRIS + ddpro.function = DinkeyPro.PROTECTION_CHECK; + ddpro.flags = DinkeyPro.START_NET_USER; + + // Call the API + retCode = ddpro.checkProtection(); + + // Check the return value + if (retCode != 0) + { + displayError(retCode, ddpro.ext_err); + return; + } + + // If you lock your software to multiple dongle models, + // you might want to check that a network dongle was found before trying to get network user information + if ((ddpro.model == DinkeyPro.MODEL_LITE) || (ddpro.model == DinkeyPro.MODEL_PLUS)) + { + System.out.println("Local dongle found. No network user information to display."); + return; + } + + // Set maxNetUsersToQuery to a sensible value! + // This example requests information about 10 users if there is no limit to the number of users supported by the dongle + if (ddpro.net_users == DinkeyPro.UNLIMITED_NET_USERS) + maxNetUsersToQuery = 10; + else + maxNetUsersToQuery = ddpro.net_users; + + // Call the API + retCode = ddpro.queryNetUsers(maxNetUsersToQuery); + + // Check the return value + if (retCode != 0) + { + System.out.println("An error occurred getting network user information."); + System.out.println("Error: " + retCode + "\nExtended Error: " + ddpro.queryNetUsersExtErr); + return; + } + + System.out.println(ddpro.numNetUsers + " current network users:\n"); + for (int i = 0; i < ddpro.num_net_users; i++) + { + System.out.println((i+1) + ") " + ddpro.userNames[i] + " @ " + ddpro.computerNames[i] + " (" + ddpro.ipAddresses[i] + ") using licence '" + ddpro.licenceNames[i] + "'"); + } + return; + } + + + // !!!! This method must match one stored in the dongle for protCheckWithAlg() to work correctly. + // For Lite dongles, use DinkeyLook to see the algorithm pre-programmed into the dongle. + // For Plus and Net dongles, ensure this algorithm matches one you specified in DinkeyAdd when adding protection. + static int myAlgorithm(int a, int b, int c, int d, int e, int f, int g, int h) + { + return a + b + c + d + e + f + g + h; + } + + // !!!! This method must match the R/W algorithm stored in the dongle for + // writeDataAreaEnc() and readDataAreaEnc() to work correctly. + static int myRwAlgorithm(int a, int b, int c, int d, int e, int f, int g, int h) + { + return a ^ b ^ c ^ d ^ e ^ f; + } + + + // An example of error reporting. Displays descriptions for some common error codes. + // IMPORTANT - THE MESSAGES DISPLAYED ARE TO HELP DEVELOPERS IMPLEMENT THE DINKEY PRO/FD API. + // THEY ARE NOT SUITABLE FOR DISPLAYING TO USERS! + static void displayError(int retCode, int extErr) + { + switch (retCode) + { + case 401: + System.out.println("Error! No dongles detected!"); + break; + case 403: + System.out.println("Error! The dongle is a different type to the one specified in DinkeyAdd."); + break; + case 404: + System.out.println("Error! The dongle is a different model to those specified in DinkeyAdd."); + break; + case 409: + System.out.println("Error! The dongle has not been programmed by DinkeyAdd."); + break; + case 410: + System.out.println("Error! The dongle has a different product code to the one specified in DinkeyAdd."); + break; + case 411: + System.out.println("Error! This software's licence was not found in the dongle."); + break; + case 413: + System.out.println("Error! This software has not been locked by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the user manual."); + break; + case 417: + System.out.println("Error! One or more of the parameters set in the DRIS is incorrect.\nCheck if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa."); + break; + case 423: + System.out.println("Error! The number of network users has been exceeded."); + break; + case 435: + System.out.println("Error! DinkeyServer has not been detected on the network."); + break; + case 922: + System.out.println("Error! The Software Key has expired."); + break; + default: + System.out.println("An error occurred checking the dongle.\nError: " + retCode + "\nExtended Error: " + extErr); + break; + } + return; + } + +} diff --git a/Dinkey Pro 7.6.1/Samples/Java/Runtime/README.html b/Dinkey Pro 7.6.1/Samples/Java/Runtime/README.html new file mode 100644 index 0000000..f207a27 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Java/Runtime/README.html @@ -0,0 +1,438 @@ + + + + + Using Dinkey Pro/FD with Java + + + +

Using Dinkey Pro/FD with Java

+
+

+ Protection checks in Java are implemented using DinkeyPro.class to communicate with the dongle via the appropriate native library + (DPJava.dll on 32-bit Windows, libDPJava64.so on 64-bit Linux, etc.). + You should lock these native libraries with the API method using DinkeyAdd as described in the user manual, and distribute the locked libraries with your software. +

+
+

+ The DinkeyPro class provides a Java wrapper around the Dinkey Pro/FD API, which is implemented by native libraries. + If you are not familiar with calling native libraries, it is recommended that you read the Java documentation on the subject, + especially the documentation for System.loadLibrary() and System.load(), + and how Java uses the system property java.library.path to locate native libraries. +

+

+ The native libraries and the DinkeyPro class are part of the uk.microcosm.dinkeydongle package. + See the documentation for your development environment for details of how to include and reference this package in your project. + dinkeydongle.jar provides all of the Java classes in the uk.microcosm.dinkeydongle package in a single JAR file. + This allows you to import the package much more easily in many Java IDEs. Note that the native libraries are not included in the JAR file. + You will need to distribute with your software locked copies of the native libraries for every platform that your software supports. +

+

+ Do not specify a calling program when locking the native libraries. + The calling program for Java software is the user's JVM, which will be different for different users. +

+

+ Java bytecode is more easily decompiled than native code. + For maximum security, it is recommended that you obfuscate your Java code using a third-party tool. +

+ +

The DinkeyPro Class

+

+ Instances of DinkeyPro contain an internal DRIS. + Most of this structure's members are exposed as public fields that can be directly accessed. + Others must be accessed via get...() and set...() methods: see below for details. + As Java does not have unsigned types, DRIS members that are documented as unsigned integers in the user manual + are represented by long fields in the DinkeyPro class. +

+
+

+ The header and size DRIS members are set automatically. + You do not need to set these fields in your code. +

+

+ rw_data_ptr is not used in Java. To use an API function that passes data to/from the dongle, + you must use the checkProtection(byte[] data) method and also set the USE_FUNCTION_ARGUMENT flag. +

+
+ +

Fields

+

+ Possible values for the function DRIS field, as documented in the user manual: +

+
    +
  • static final int PROTECTION_CHECK
  • +
  • static final int EXECUTE_ALGORITHM
  • +
  • static final int WRITE_DATA_AREA
  • +
  • static final int READ_DATA_AREA
  • +
  • static final int ENCRYPT_USER_DATA
  • +
  • static final int DECRYPT_USER_DATA
  • +
  • static final int FAST_PRESENCE_CHECK
  • +
  • static final int STOP_NET_USER
  • +
+

+ Possible values for the flags DRIS field, as documented in the user manual: +

+
    +
  • static final int DEC_ONE_EXEC
  • +
  • static final int DEC_MANY_EXECS
  • +
  • static final int START_NET_USER
  • +
  • static final int USE_FUNCTION_ARGUMENT
  • +
  • static final int CHECK_LOCAL_FIRST
  • +
  • static final int CHECK_NETWORK_FIRST
  • +
  • static final int USE_ALT_LICENCE_NAME
  • +
  • static final int DONT_SET_MAXDAYS_EXPIRY
  • +
  • static final int MATCH_DONGLE_NUMBER
  • +
  • static final int DONT_RETURN_FD_DRIVE
  • +
+

+ Possible values for the type DRIS field, as documented in the user manual: +

+
    +
  • static final int TYPE_PRO
  • +
  • static final int TYPE_FD
  • +
+

+ Possible values for the model DRIS field, as documented in the user manual: +

+
    +
  • static final int MODEL_LITE
  • +
  • static final int MODEL_PLUS
  • +
  • static final int MODEL_NET5
  • +
  • static final int MODEL_NETU
  • +
+

+ Possible values for the net_users DRIS field, as documented in the user manual: +

+
    +
  • static final int UNLIMITED_NET_USERS
  • +
+

+ Directly accessible DRIS fields, as documented in the user manual: +

+
    +
  • int seed1
  • +
  • int seed2
  • +
  • int function
  • +
  • int flags
  • +
  • long execs_decrement
  • +
  • int data_crypt_key_num
  • +
  • int rw_offset
  • +
  • int rw_length
  • +
  • int var_a
  • +
  • int var_b
  • +
  • int var_c
  • +
  • int var_d
  • +
  • int var_e
  • +
  • int var_f
  • +
  • int var_g
  • +
  • int var_h
  • +
  • int alg_number
  • +
  • int ret_code
  • +
  • int ext_err
  • +
  • int type
  • +
  • int model
  • +
  • int sdsn
  • +
  • long dongle_number
  • +
  • int update_number
  • +
  • long data_area_size
  • +
  • int max_alg_num
  • +
  • int execs
  • +
  • int exp_day
  • +
  • int exp_month
  • +
  • int exp_year
  • +
  • long features
  • +
  • int net_users
  • +
  • int alg_answer
  • +
  • long fd_capacity
  • +
  • int swkey_type
  • +
  • int swkey_exp_day
  • +
  • int swkey_exp_month
  • +
  • int swkey_exp_year
  • +
+

+ Fields used to access information returned by DDGetNetUserList(): +

+
    +
  • int numNetUsers - the current number of network users when DDGetNetUserList() was called.
  • +
  • int queryNetUsersExtErr - contains additional error information if DDGetNetUserList() returns failure.
  • +
  • String[] licenceNames - the names of the licences currently used by network users.
  • +
  • String[] userNames - the usernames of the current network users.
  • +
  • String[] computerNames - the computer names of the current network users.
  • +
  • String[] ipAddresses - the IP addresses of the current network users.
  • +
+

+ The string arrays should be used in combination, i.e. licenceNames[0], userNames[0], + computerNames[0] and ipAddresses[0] together describe a single network user. +

+ +

Constructors

+

+ These constructors can throw any exception thrown by System.loadLibrary() and System.load(). + See the documentation for those methods for details. +

+ +

DinkeyPro()

+

+ Creates a new DinkeyPro instance and calls System.loadLibrary() + to load the native library using the default filename. + The library must be located in one of the paths specified in the java.library.path system property. + The exact filename is implementation-dependent, but the most common names are: +

+
    +
  • 32-bit Windows - DPJava.dll
  • +
  • 64-bit Windows - DPJava64.dll
  • +
  • 32-bit Linux - libDPJava.so
  • +
  • 64-bit Linux - libDPJava64.so
  • +
  • 64-bit macOS - libDPJava64.dylib
  • +
+

+ The members of the instance's internal DRIS are initialised to random values. +

+ +

DinkeyPro(String libName)

+

+ Creates a new DinkeyPro instance and calls System.loadLibrary(libName) to load the native library. + The library must be located in one of the paths specified in the java.library.path system property. + If System.loadLibrary(libName) fails, it then calls System.load(libName). + Use this version of the constructor if you rename the native libraries (recommended), or if you need to specify the absolute + path to the library. +

+

+ The members of the instance's internal DRIS are initialised to random values. +

+ +

Methods

+ +

int checkProtection()

+

+ Calls DDProtCheck() in the native library using the internal DRIS. + Returns zero on success, or a value indicating the cause of the error on failure. +

+ +

int checkProtection(byte[] data)

+

+ Calls DDProtCheck() in the native library using the internal DRIS. + data is passed to the API (e.g. when writing to the dongle data area), + or acts as a buffer filled by the API (e.g. when reading from the dongle data area). + When using this method you must also set the USE_FUNCTION_ARGUMENT flag. + Returns zero on success, or a value indicating the cause of the error on failure. +

+ +

int queryNetUsers(int maxUsersToQuery)

+

+ Calls DDGetNetUserList() in the native library. + maxNetUsersToQuery specifies the maximum number of current network users to return information about. + Use this version of this method to get information about the current network users for the protected software's licence + (if protected with the per licence network users option), or all licences in the dongle + (if protected with the per product network users option). + Returns zero on success, or a value indicating the cause of the error on failure. +

+ +

int queryNetUsers(String licenceName, int maxUsersToQuery)

+

+ Calls DDGetNetUserList() in the native library. + maxNetUsersToQuery specifies the maximum number of current network users to return information about. + Use this version of this method to get information about the current network users for the licence specified by licenceName. + Returns zero on success, or a value indicating the cause of the error on failure. +

+ +

void reset()

+

+ Set all members of the internal DRIS to random values. +

+ +

String getProdCode()

+

+ Return the prodcode member of the internal DRIS as a Java string. +

+ +

String getFdDrive()

+

+ Return the fd_drive member of the internal DRIS as a Java string. +

+ +

void setAltLicenceName(String altLicenceName)

+

+ Assign the value of altLicenceName to the alt_licence_name member of the internal DRIS. +

+ +

void cryptDris(int encryptionParameter1, int encryptionParameter2, int encryptionParameter3)

+

+ Encrypt/decrypt the internal DRIS. + encryptionParameter1, encryptionParameter2 and encryptionParameter3 + must match the parameters specified for DRIS encryption in DinkeyAdd. +

+ +

void cryptApiData(byte[] data, int algAnswer)

+

+ Encrypt/decrypt checkProtection()'s data parameter using the result of the R/W algorithm. + The option to take data encryption parameters from the R/W algorithm must also be selected in DinkeyAdd when adding protection, + and algAnswer must be the result of an algorithm that matches the R/W algorithm specified there. +

+ +

void cryptApiData(byte[] data, int encryptionParameter1, int encryptionParameter2, int encryptionParameter3)

+

+ Encrypt/decrypt checkProtection()'s data parameter using constant parameters. + The option to use constant data encryption parameters must be selected in DinkeyAdd when adding protection, and + encryptionParameter1, encryptionParameter2 and encryptionParameter3 + must match the parameters specified there. +

+ +

Java Example Files

+
    +
  • DPSample.java - various examples of using the DinkeyPro class.
  • +
+ +

Supported Versions

+

+ All parts of the uk.microcosm.dinkeydongle package support Java platforms version 5 and newer. +

+ +

Try It Yourself

+
+

+ The sample code is designed to teach you how to use the Dinkey Pro/FD API in Java programs. + Do not copy the examples verbatim into your own code. Experiment with the sample code to understand how the API works, + and read the chapter Increasing Your Protection in the user manual for many suggestions on how to + make the best use of the API features. +

+
+

+ DPSample.java gives simple examples of performing a protection check, + as well as using various other features of Dinkey Pro/FD. + To run the DPSample program you will first need to use DinkeyAdd to produce a locked copy of the native library for your platform, + and program a dongle (if you are using Plus or Net dongles). + Place the locked library in one of the paths specified by your Java environment's java.library.path system property. + Browse the examples in DPSample.java to see how different features can be used. + All the examples follow the same basic pattern: +

+
    +
  1. Create a DinkeyPro instance and set up its internal DRIS with the relevant information.
  2. +
  3. Call the API.
  4. +
  5. Use the information returned in the internal DRIS.
  6. +
+

+ Uncomment the calls at the top of the main() method in DPSample.java + to enable the examples of different features, then recompile and run DPSample to run the examples. +

+

+ Parts of the sample code marked with !!!! must be customised with your own functions or values + for some features to work correctly. Not all features are supported by all dongle models. + See the user manual for more information. +

+ + diff --git a/Dinkey Pro 7.6.1/Samples/LabVIEW/README.html b/Dinkey Pro 7.6.1/Samples/LabVIEW/README.html new file mode 100644 index 0000000..93f94ac --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/LabVIEW/README.html @@ -0,0 +1,295 @@ + + + + + Using Dinkey Pro/FD with LabVIEW + + + +

Using Dinkey Pro/FD with LabVIEW

+
+

+ The Shell protection method supports Windows executables (stand-alone applications) produced by the LabVIEW Application Builder. +

+

+ API protection checks in LabVIEW are implemented using the Virtual Instruments dp32.vi and dp64.vi + to communicate with the dongle via the appropriate shared library + (dpwin32.dll on 32-bit Windows, dplin64.so on 64-bit Linux, etc.). + You should lock these shared libraries with the API method using DinkeyAdd as described in the user manual, and distribute the locked libraries with your software. +

+
+

+ Using the Dinkey Pro/FD API in LabVIEW is very similar to using the API with text-based programming languages. + See Modifying Your Code in the user manual for information on using the API. +

+

+ In LabVIEW, the DRIS is a cluster with some slight differences to the DRIS + documented in Structures > DRIS Structure in the user manual. + These differences are: +

+
    +
  • + The fields header and size are set automatically by the dp32 and dp64 VIs. + You do not need to set these fields in your code. +
  • +
  • + rw_data_ptr is replaced by rw_data. + This field is an array of bytes representing the actual data passed to/received from the dongle (rather than a pointer to it). + Internally, the array is converted to a cluster. Because LabVIEW limits the number of elements in cluster to 256, + the maximum size of data that can be passed to/from the dongle in a single protection check is 256 bytes. + You must set the USE_FUNCTION_ARGUMENT flag when using this field. +
  • +
+

+ In the user manual, possible values for the function and flags fields are referred to by the + symbolic names used in other programming languages. Their literal values are provided here for your reference: +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FunctionValue
PROTECTION_CHECK1
EXECUTE_ALGORITHM2
WRITE_DATA_AREA3
READ_DATA_AREA4
ENCRYPT_USER_DATA5
DECRYPT_USER_DATA6
FAST_PRESENCE_CHECK7
STOP_NET_USER8
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FlagValue
DEC_ONE_EXEC1
DEC_MANY_EXECS2
START_NET_USER4
USE_FUNCTION_ARGUMENT16
CHECK_LOCAL_FIRST32
CHECK_NETWORK_FIRST64
USE_ALT_LICENCE_NAME128
DONT_SET_MAXDAYS_EXPIRY256
MATCH_DONGLE_NUMBER512
DONT_RETURN_FD_DRIVE1024
+
+
+

+ The VIs also have a Path input that must be used to specify the path to the locked API library. + See the LabVIEW documentation for the Call Library Function Node for more information on specifying paths to shared libraries. +

+

+ The dp32 and dp64 VIs do not support DRIS encryption or user data encryption/decryption. +

+ +
+

+ Before you distribute your application, you must protect it from modification. + In general, it is best to use the LabVIEW Application Builder to create a standalone application that can be run outside of LabVIEW. + If you are distributing your LabVIEW code as a module to be used in other LabVIEW VIs, + don't forget to remove the block diagram from the VI so that end users cannot modify the code! + For more information on this, see the LabVIEW documentation. +

+
+ +

LabVIEW Example Files

+
    +
  • dp32.vi - a VI that provides a 32-bit LabVIEW interface to the Dinkey Pro/FD API.
  • +
  • dp64.vi - a VI that provides a 64-bit LabVIEW interface to the Dinkey Pro/FD API.
  • +
  • sample.vi - a simple example of using dp32.vi.
  • +
+ +

Supported Versions

+

+ The LabVIEW sample code provided with the Dinkey Pro/FD SDK was written using LabVIEW 8.5 for Windows, + and tested using LabVIEW 8.5 on 32-bit Windows and LabVIEW 2018 on 64-bit Windows. + All newer versions should be backwards compatible. The sample code may also work with older versions, + but no guarantees can be made, and support for older versions is likely to be very limited. +

+

+ The sample code should also work without modification on macOS and Linux. + If you have problems calling our API from LabVIEW on macOS or Linux, + please contact us with full details of the platform and LabVIEW version that you are using. +

+ +

Try It Yourself

+
+

+ The sample code is designed to teach you how to use the Dinkey Pro/FD API in LabVIEW programs. + Experiment with the sample code to understand how the API works, + and read the chapter Increasing Your Protection in the user manual for many suggestions on how to + make the best use of the API features. +

+
+

+ sample.vi gives a simple example of using the dp32 VI to perform a protection check. + If you are using 64-bit LabVIEW, replace dp32 with the dp64 VI. + The VI calls the API and checks that the return code is 0 and that the SDSN of the dongle is 10101 (i.e. a demo dongle), + turning on the LED indicator if both are correct. +

+

+ Controls and indicators for the other input and output variables are included to allow you to experiment with other dongle features. + It is strongly recommended that you use these other features to improve the security of the dongle protection. + See the chapter Increasing Your Protection in the user manual for many suggestions on how to do this. +

+

+ To run sample.vi you will first need to use DinkeyAdd to produce a locked copy of the shared library for your platform, + and program a dongle (if you are using Plus or Net dongles). + Set the value of the Path control to the location of the locked library. +

+ + diff --git a/Dinkey Pro 7.6.1/Samples/LabVIEW/dp32.vi b/Dinkey Pro 7.6.1/Samples/LabVIEW/dp32.vi new file mode 100644 index 0000000..b07827c Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/LabVIEW/dp32.vi differ diff --git a/Dinkey Pro 7.6.1/Samples/LabVIEW/dp64.vi b/Dinkey Pro 7.6.1/Samples/LabVIEW/dp64.vi new file mode 100644 index 0000000..635e423 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/LabVIEW/dp64.vi differ diff --git a/Dinkey Pro 7.6.1/Samples/LabVIEW/sample.vi b/Dinkey Pro 7.6.1/Samples/LabVIEW/sample.vi new file mode 100644 index 0000000..3690f46 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/LabVIEW/sample.vi differ diff --git a/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/DinkeyChange64_thunk_pcwin64.dll b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/DinkeyChange64_thunk_pcwin64.dll new file mode 100644 index 0000000..0ca8e9c Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/DinkeyChange64_thunk_pcwin64.dll differ diff --git a/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/README.html b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/README.html new file mode 100644 index 0000000..bef676e --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/README.html @@ -0,0 +1,273 @@ + + + + + Using the DinkeyChange API with MATLAB + + + +

Using the DinkeyChange API with MATLAB

+

+ If you are not already familiar with calling shared libraries from MATLAB code, + it is strongly recommended that you read the MATLAB documentation on this topic. + Depending on your version of MATLAB, you may need to install a C compiler and configure MATLAB to use it with the command mex -setup. + Again, refer to the MATLAB documentation for further information. +

+

+ See Remote Parameter Changing > DinkeyChange > DinkeyChange.dll in the user manual for information on using the DinkeyChange API. + Use the help command to see overviews of how each M-file interface to the DinkeyChange API is used in MATLAB. + Most of the DinkeyChange M-files are simple MATLAB wrappers for the shared library functions. + dcgetinfo.m however is quite different to the DCGetInfo() function described in the user manual: +

+
[retCode, dongleArray] = dcgetinfo(libName, typeMask, modelMask, prodcodeMask)
+

+ The inputs typeMask, modelMask and prodcodeMask + are used in the same way as the inputs of DCGetInfo(), as dcsample.m illustrates. + The outputs however are grouped together as dongleArray, a 1-by-N vector of MATLAB structures. + Each structure represents a dongle found by dcgetinfo's search, and each structure has the following fields: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldData TypeDescription
typeint32 + The dongle's type as a numeric value. Possible values: +
    +
  • 1 for Dinkey Pro dongles
  • +
  • 2 for Dinkey FD dongles
  • +
+
type_as_stringchar + The dongle's type as a string. Possible values: +
    +
  • "Pro"
  • +
  • "FD"
  • +
+
modelint32 + The dongle's model as a numeric value. Possible values: +
    +
  • 1 for Lite dongles
  • +
  • 2 for Plus dongles
  • +
  • 4 for Net dongles (5 users)
  • +
  • 7 for Net dongles (unlimited users)
  • +
+
model_as_stringchar + The dongle's model as a string. Possible values: +
    +
  • "Lite"
  • +
  • "Plus"
  • +
  • "Net (5 users)"
  • +
  • "Net (unlimited users)"
  • +
+
product_codecharThe dongle's product code
dongle_numberuint32The dongle's serial number (dongle number)
update_numberint32The dongle's update number
+ +

MATLAB Example Files

+
    +
  • dcgetinfo.m - an M-file that provides a MATLAB interface to the DCGetInfo() API function.
  • +
  • dcgetdiagnosticinfo.m - a MATLAB interface to the DCGetDiagnosticInfo() API function.
  • +
  • dcdoupdatecodestring.m - a MATLAB interface to the DCDoUpdateCodeString() API function.
  • +
  • dcdoupdatecodefromfile.m - a MATLAB interface to the DCDoUpdateCodeFromFile() API function.
  • +
  • dcrestoredinkeyfdlite.m - a MATLAB interface to the DCRestoreDinkeyFDLite() API function.
  • +
  • dcgetmachineid.m - a MATLAB interface to the DCGetMachineID() API function.
  • +
  • dcdownloadtempsoftwarekey.m - a MATLAB interface to the DCDownloadTempSoftwareKey() API function.
  • +
  • dcdownloaddemosoftwarekey.m - a MATLAB interface to the DCDownloadDemoSoftwareKey() API function.
  • +
  • dcsample.m - examples of using these M-files.
  • +
  • dinkeychangewin32proto.p - a prototype P-file that defines the signatures of the API functions for 32-bit MATLAB on Windows.
  • +
  • dinkeychange32proto.p - a prototype P-file that defines the signatures of the API functions for 32-bit MATLAB on all other supported platforms.
  • +
  • dinkeychange64proto.p - a prototype P-file that defines the signatures of the API functions for 64-bit MATLAB on all supported platforms.
  • +
  • DinkeyChange64_thunk_pcwin64.dll - a compatibility layer required by 64-bit MATLAB to use DinkeyChange64.dll.
  • +
+

+ The appropriate prototype P-file and any M-files that you call should be included, without modification, in your own project. + If you are using 64-bit MATLAB on Windows, you should also include DinkeyChange64_thunk_pcwin64.dll. + If you rename DinkeyChange64.dll, + you must change the DinkeyChange64 part of the thunking DLL's filename accordingly. +

+

+ Our M-files and P-files are compatible with MATLAB on macOS and Linux. + However, we do not currently provide the thunk files required by 64-bit MATLAB on these platforms. + If you want to use the DinkeyChange API on 64-bit macOS and/or 64-bit Linux, + please contact us with full details of the platform(s) and MATLAB versions that you want to use, + and we can provide compatible thunk files or instruct you on how to produce these files yourself. +

+ +

Supported Versions

+

+ The MATLAB sample code provided with the Dinkey Pro/FD SDK was written and tested using MATLAB R2013a. + All newer versions should be backwards compatible. The sample code may also work with older versions, + but no guarantees can be made, and support for older versions is likely to be very limited. +

+ +

Try It Yourself

+

+ dcsample.m gives a simple example of calling each of the API functions. + To run dcsample.m you will need a copy of the appropriate shared library for your platform + (DinkeyChange.dll for 32-bit Windows, DinkeyChange64.so for 64-bit Linux etc.). + Place the library in the same folder as the example files and change MATLAB's current directory to this folder. + Browse the examples in dcsample.m to see how different features can be used. +

+

+ Uncomment the function calls at the top of dcsample.m + to enable the examples of different features, then enter dcsample in the Command Window to run the examples. +

+

+ dcsample.m also demonstrates loading and unloading the appropriate shared library for your platform. +

+

+ Parts of the sample code marked with !!!! must be customised with your own functions or values + for some features to work correctly. Not all features are supported by all dongle models. + See the user manual for more information. +

+ + + diff --git a/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcdoupdatecodefromfile.m b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcdoupdatecodefromfile.m new file mode 100644 index 0000000..54ead05 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcdoupdatecodefromfile.m @@ -0,0 +1,17 @@ +function [retCode, confirmationCode, extErr] = dcdoupdatecodefromfile(libName, filename) +%DCDOUPDATECODEFROMFILE Update a dongle attached to this computer using a +%strongly encrypted update code. +% [RETCODE,CONFIRMATIONCODE,EXTERR] = +% DCDOUPDATECODEFROMFILE(LIBNAME,FILENAME) calls the API via the external +% library LIBNAME. FILENAME is a file containing the update code to be +% applied. RETCODE is the return code of the API call. If the update +% succeeded, CONFIRMATIONCODE contains the update's confirmation code. If +% the update failed, EXTERR contains an additional error code that +% provides more information. + +% Copyright Microcosm Ltd. DO NOT MODIFY THIS FILE. + + confirmationCode = int32(0); + extErr = int32(0); + [retCode, filename, confirmationCode, extErr] = calllib(libName, 'DCDoUpdateCodeFromFile', filename, confirmationCode, extErr); +end diff --git a/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcdoupdatecodestring.m b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcdoupdatecodestring.m new file mode 100644 index 0000000..e838ff6 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcdoupdatecodestring.m @@ -0,0 +1,17 @@ +function [retCode, confirmationCode, extErr] = dcdoupdatecodestring(libName, updateCode) +%%DCDOUPDATECODESTRING Update a dongle attached to this computer using a +%short update code. +% [RETCODE,CONFIRMATIONCODE,EXTERR] = +% DCDOUPDATECODESTRING(LIBNAME,UPDATECODE) calls the API via the external +% library LIBNAME. UPDATECODE is the short update code to be applied. +% RETCODE is the return code of the API call. If the update succeeded, +% CONFIRMATIONCODE contains the update's confirmation code. If the update +% failed, EXTERR contains an additional error code that provides more +% information. + +% Copyright Microcosm Ltd. DO NOT MODIFY THIS FILE. + + confirmationCode = int32(0); + extErr = int32(0); + [retCode, updateCode, confirmationCode, extErr] = calllib(libName, 'DCDoUpdateCodeString', updateCode, confirmationCode, extErr); +end diff --git a/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcdownloaddemosoftwarekey.m b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcdownloaddemosoftwarekey.m new file mode 100644 index 0000000..7a87a40 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcdownloaddemosoftwarekey.m @@ -0,0 +1,15 @@ +function [retCode, extErr] = dcdownloaddemosoftwarekey(libName, machineId, productCode, model) +%DCDOWNLOADDEMOSOFTWAREKEY Download and install a demo software key. +% [RETCODE,EXTERR] = DCDOWNLOADDEMOSOFTWAREKEY(LIBNAME,MACHINEID,PRODUCTCODE,MODEL) +% calls the API via the external library LIBNAME. MACHINEID is the machine +% ID of this computer (you can obtain this by calling the API function +% DCGETMACHINEID). PRODUCTCODE and MODEL specify the product code and dongle +% model of the demo software key to be installed. RETCODE is the return code +% of the API call. If the update failed, EXTERR contains an additional error +% code that provides more information. + +% Copyright Microcosm Ltd. DO NOT MODIFY THIS FILE. + + extErr = int32(0); + [retCode, productCode, extErr] = calllib(libName, 'DCDownloadDemoSoftwareKey', machineId, productCode, model, extErr); +end diff --git a/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcdownloadtempsoftwarekey.m b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcdownloadtempsoftwarekey.m new file mode 100644 index 0000000..e8b0758 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcdownloadtempsoftwarekey.m @@ -0,0 +1,14 @@ +function [retCode, extErr] = dcdownloadtempsoftwarekey(libName, machineId) +%DCDOWNLOADTEMPSOFTWAREKEY Download and install a temporary software key. +% [RETCODE,EXTERR] = DCDOWNLOADTEMPSOFTWAREKEY(LIBNAME,MACHINEID) calls the +% API via the external library LIBNAME. MACHINEID is the machine ID of +% this computer (you can obtain this by calling the API function +% DCGETMACHINEID). RETCODE is the return code of the API call. If the +% update failed, EXTERR contains an additional error code that provides +% more information. + +% Copyright Microcosm Ltd. DO NOT MODIFY THIS FILE. + + extErr = int32(0); + [retCode, extErr] = calllib(libName, 'DCDownloadTempSoftwareKey', machineId, extErr); +end diff --git a/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcgetdiagnosticinfo.m b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcgetdiagnosticinfo.m new file mode 100644 index 0000000..9d35894 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcgetdiagnosticinfo.m @@ -0,0 +1,13 @@ +function retCode = dcgetdiagnosticinfo(libName, filename) +%DCGETDIAGNOSTICINFO Call the DinkeyChange API to write diagnostic +%information to a file. +% RETCODE = DCGETDIAGNOSTICINFO(LIBNAME,FILENAME) calls the API via the +% external library LIBNAME, writing diagnostic information to the file +% specified in FILENAME. FILENAME can be an absolute or relative path. If +% FILENAME does not end in '.dlpf', it will be appended automatically. +% RETCODE is the return code of the API call. + +% Copyright Microcosm Ltd. DO NOT MODIFY THIS FILE. + + retCode = calllib(libName, 'DCGetDiagnosticInfo', filename); +end diff --git a/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcgetinfo.m b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcgetinfo.m new file mode 100644 index 0000000..bdbbd87 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcgetinfo.m @@ -0,0 +1,72 @@ +function [retCode, dongleArray] = dcgetinfo(libName, typeMask, modelMask, prodcodeMask) +%DCGETINFO Get information about Dinkey Pro/FD dongles attached to this +%computer. +% [RETCODE,DONGLEARRAY] = +% DCGETINFO(LIBNAME,TYPEMASK,MODELMASK,PRODCODEMASK) calls the API via +% the external library LIBNAME. TYPEMASK, MODELMASK and PRODCODEMASK can +% be used to restrict the search to dongles with specific +% characteristics. DONGLEARRAY is a vector of structures; each structure +% contains information about a dongle attached to this computer. RETCODE +% is the return code of the API call. + +% Copyright Microcosm Ltd. DO NOT MODIFY THIS FILE. + + MAX_USB_DEVICES = 128; + MAX_PRODCODE_LEN = 9; + + dongleArray = []; + numberFound = int32(0); + typeArray = zeros(1, MAX_USB_DEVICES, 'int32'); + modelArray = zeros(1, MAX_USB_DEVICES, 'int32'); + productCodeArray = zeros(1, MAX_USB_DEVICES * MAX_PRODCODE_LEN, 'uint8'); + dongleNumberArray = zeros(1, MAX_USB_DEVICES, 'uint32'); + updateNumberArray = zeros(1, MAX_USB_DEVICES, 'int32'); + + [retCode, prodcodeMask, numberFound, typeArray, modelArray, productCodeArray, dongleNumberArray, updateNumberArray] = ... + calllib(libName, 'DCGetInfo', typeMask, modelMask, prodcodeMask, MAX_USB_DEVICES, numberFound, typeArray, modelArray, productCodeArray, dongleNumberArray, updateNumberArray); + + for (i = 1:numberFound) + productCode = productCodeArray(((i-1)*MAX_PRODCODE_LEN)+1 : i*MAX_PRODCODE_LEN); % Get product codes out of array of bytes, 9 bytes at a time + productCode = deblank(char(productCode)); % Convert to string and remove any trailing NULLs + newDongle = createdonglestructure(typeArray(i), modelArray(i), productCode, dongleNumberArray(i), updateNumberArray(i)); + dongleArray = [dongleArray newDongle]; + end +end + +function dongle = createdonglestructure(type, model, productCode, dongleNumber, updateNumber) +% Create a structure representing a dongle detected by dcgetinfo() + + dongle.type = type; + switch type + case 1 + dongle.type_as_string = 'Pro'; + case 2 + dongle.type_as_string = 'FD'; + otherwise + dongle.type_as_string = ''; % Should never happen! + end + + dongle.model = model; + switch model + case 1 + dongle.model_as_string = 'Lite'; + case 2 + dongle.model_as_string = 'Plus'; + case 3 + dongle.model_as_string = 'Net (1 user)'; + case 4 + dongle.model_as_string = 'Net (5 users)'; + case 5 + dongle.model_as_string = 'Net (10 users)'; + case 6 + dongle.model_as_string = 'Net (50 users)'; + case 7 + dongle.model_as_string = 'Net (unlimited users)'; + otherwise + dongle.model_as_string = ''; % Should never happen! + end + + dongle.product_code = char(productCode); + dongle.dongle_number = uint32(dongleNumber); + dongle.update_number = int32(updateNumber); +end diff --git a/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcgetmachineid.m b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcgetmachineid.m new file mode 100644 index 0000000..b998b81 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcgetmachineid.m @@ -0,0 +1,14 @@ +function [retCode, machineId, extErr] = dcgetmachineid(libName) +%DCGETMACHINEID Get the machine ID for this computer +% [RETCODE,MACHINEID,EXTERR] = DCGETMACHINEID(LIBNAME) calls the API via +% the external library LIBNAME. RETCODE is the return code of the API +% call. If the update succeeded, MACHINEID is the machine ID of the +% computer. If this call failed, EXTERR contains an additional error code +% that provides more information. + +% Copyright Microcosm Ltd. DO NOT MODIFY THIS FILE. + + machineId = uint32(0); + extErr = int32(0); + [retCode, machineId, extErr] = calllib(libName, 'DCGetMachineID', machineId, extErr); +end diff --git a/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcrestorefdlite.m b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcrestorefdlite.m new file mode 100644 index 0000000..9db050d --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcrestorefdlite.m @@ -0,0 +1,10 @@ +function retCode = dcrestorefdlite(libName) +%DCRESTOREFDLITE Restore the required hidden file on all Dinkey FD Lite +%dongles attached to this computer. +% RETCODE = DCRESTOREFDLITE(LIBNAME) calls the API via the external +% library LIBNAME. RETCODE is the return code of the API call. + +% Copyright Microcosm Ltd. DO NOT MODIFY THIS FILE. + + retCode = calllib(libName, 'DCRestoreDinkeyFDLite'); +end \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcsample.m b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcsample.m new file mode 100644 index 0000000..9dc00cf --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dcsample.m @@ -0,0 +1,249 @@ +function dcsample +%DCSAMPLE Example use of the DinkeyChange API in MATLAB. + +% Copyright Microcosm Ltd. + + % Load the correct library for this platform + switch computer() + case 'PCWIN64' % 64-bit Windows + loadlibrary('DinkeyChange64.dll', @dinkeychange64proto, 'alias', 'dinkeychange'); + case 'PCWIN' % 32-bit Windows + loadlibrary('DinkeyChange.dll', @dinkeychangewin32proto, 'alias', 'dinkeychange'); + case 'GLNXA64' % 64-bit Linux + loadlibrary('DinkeyChange64.so', @dinkeychange64proto, 'alias', 'dinkeychange'); + case 'GLNX86' % 32-bit Linux + loadlibrary('DinkeyChange.so', @dinkeychange32proto, 'alias', 'dinkeychange'); + case 'MACI64' % 64-bit Mac OS X + loadlibrary('DinkeyChange64.dylib', @dinkeychange64proto, 'alias', 'dinkeychange'); + case 'MAC' % 32-bit Mac OS X + loadlibrary('DinkeyChange32.dylib', @dinkeychange32proto, 'alias', 'dinkeychange'); + otherwise + disp('Error! Platform not supported!'); + return + end + + % Each of the functions below demonstrates different API functionality. + % Uncomment the appropriate functions to execute the examples. + % See the comments in each function for more details about the features + % that they demonstrate. + + getdongleinfo('dinkeychange'); + %writediagnosticfile('dinkeychange'); + %applyshortupdatecode('dinkeychange'); + %applystronglyencryptedupdatecode('dinkeychange'); + %restorefdlite('dinkeychange'); + %getmachineid('dinkeychange'); + %downloadtempsoftwarekey('dinkeychange'); + %downloaddemosoftwarekey('dinkeychange'); + + unloadlibrary('dinkeychange'); +end + +function getdongleinfo(libName) +% Display information about the dongles attached to this computer + + % Possible values for dcgetinfo's typeMask parameter + TYPE_MASK_PRO = 1; + TYPE_MASK_FD = 2; + TYPE_MASK_ALL = bitor(TYPE_MASK_PRO, TYPE_MASK_FD); + + % Possible values for dcgetinfo's modelMask parameter + MODEL_MASK_LITE = 1; + MODEL_MASK_PLUS = 2; + MODEL_MASK_NET = 4; + MODEL_MASK_ALL = bitor(bitor(MODEL_MASK_LITE, MODEL_MASK_PLUS), MODEL_MASK_NET); + MODEL_MASK_DEFAULT = bitor(MODEL_MASK_PLUS, MODEL_MASK_NET); + + % Call the DinkeyChange API + [retCode, dongleArray] = dcgetinfo(libName, TYPE_MASK_ALL, MODEL_MASK_ALL, ''); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, 0); + return + end + + for (i = 1:length(dongleArray)) + disp(sprintf('%3d) Dinkey %s %s', i, dongleArray(i).type_as_string, dongleArray(i).model_as_string)); + disp(sprintf(' Product code : %s', dongleArray(i).product_code)); + disp(sprintf(' Dongle number: %u', dongleArray(i).dongle_number)); + disp(sprintf(' Update number: %u', dongleArray(i).update_number)); + disp(sprintf('\n')); + end +end + +function writediagnosticfile(libName) +% Write diagnostic information about the dongles attached to this computer +% to an encrypted file. + + filename = '!!!! REPLACE THIS WITH THE NAME OF THE FILE TO WRITE TO'; + + % Call the DinkeyChange API + retCode = dcgetdiagnosticinfo(libName, filename); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, 0); + return + end + + disp(['Successfully wrote diagnostic information to ' filename]); +end + +function applyshortupdatecode(libName) +% Update a dongle attached to this computer using a short update code + + % Call the DinkeyChange API + [retCode, confirmationCode, extErr] = dcdoupdatecodestring(libName, '!!!! REPLACE THIS WITH A VALID UPDATE CODE STRING'); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, extErr); + return + end + + disp('Successfully updated dongle'); + disp(['Confirmation code: ' sprintf('%X', confirmationCode)]); +end + +function applystronglyencryptedupdatecode(libName) +% Update a dongle attached to this computer using a strongly encrypted +% update code file + + % Call the DinkeyChange API + [retCode, confirmationCode, extErr] = dcdoupdatecodefromfile(libName, '!!!! REPLACE THIS WITH A VALID UPDATE CODE FILENAME'); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, extErr); + return + end + + disp('Successfully updated dongle'); + disp(['Confirmation code: ' sprintf('%X', confirmationCode)]); +end + +function restorefdlite(libName) +% Restore the required hidden file on a Dinkey FD Lite dongle. + + % Call the DinkeyChange API + retCode = dcrestorefdlite(libName); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, 0); + return + end + + disp('Successfully restored FD Lite dongle'); +end + +function getmachineid(libName) +% Display this computer's machine ID + + % Call the DinkeyChange API + [retCode, machineId, extErr] = dcgetmachineid(libName); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, extErr); + return + end + + disp(['The machine ID for this computer is: ' sprintf('%X', machineId)]); +end + +function downloadtempsoftwarekey(libName) +% Download and install a temporary software key on this computer + + % First call the DinkeyChange API to get the machine ID + [retCode, machineId, extErr] = dcgetmachineid(libName); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, extErr); + return + end + + % Then call the API again to install the software key + [retCode, extErr] = dcdownloadtempsoftwarekey(libName, machineId); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, extErr); + return + end + + disp('The temporary software key has been succesfully installed.'); +end + +function downloaddemosoftwarekey(libName) +% Download and install a demo software key on this computer + + % Possible values for dcdownloaddemosoftwarekey's model parameter + SWKEY_MODEL_DEFAULT = -1; + SWKEY_MODEL_PRO_LITE = 0; + SWKEY_MODEL_PRO_PLUS = 1; + SWKEY_MODEL_PRO_NET = 2; + SWKEY_MODEL_FD_LITE = 3; + SWKEY_MODEL_FD_PLUS = 4; + SWKEY_MODEL_FD_NET = 5; + + % First call the DinkeyChange API to get the machine ID + [retCode, machineId, extErr] = dcgetmachineid(libName); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, extErr); + return + end + + % Then call the API again to install the software key + [retCode, extErr] = dcdownloaddemosoftwarekey(libName, machineId, '!!!! REPLACE THIS WITH THE PRODUCT CODE OF THE KEY', SWKEY_MODEL_DEFAULT); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, extErr); + return + end + + disp('The demo software key has been succesfully installed.'); +end + +% An example of error reporting +% Displays descriptions for some common error codes +function displayerror(retCode, extErr) + switch retCode + case 401 + disp('Error! No dongles detected that meet the search criteria.'); + case 409 + disp('Error! The dongle detected has not been programmed by DinkeyAdd.'); + case 754 + disp('Error! The specified output file could not be written to.'); + case 758 + disp('Error! Cannot open the file specified.'); + case 759 + disp('Error! The file specified is not a valid update code file.'); + case 762 + disp('Error! The update code contains invalid characters.'); + case 763 + disp('Error! Invalid update code.'); + case 764 + disp('Error! The update code was entered incorrectly, or the update code file is corrupt.'); + case 765 + disp('Error! The update code does not match any dongle attached to your computer.'); + case 766 + disp('Error! The update number for this update code is too high. If you have more than one update code, ensure that you apply them in the correct order.'); + case 767 + disp('Error! You have already entered this update code.'); + case 1905 + disp('Error! There is no temporary software key available for download.'); + case 1907 + disp('Error! The temporary software key has expired. Cannot download it.'); + case 1910 + disp('Error! The temporary software key has already been downloaded.'); + otherwise + str = sprintf('An error occurred checking the dongle. Error: %d, Extended Error: %d', retCode, extErr); + disp(str); + end +end diff --git a/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dinkeychange32proto.p b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dinkeychange32proto.p new file mode 100644 index 0000000..3746269 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dinkeychange32proto.p differ diff --git a/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dinkeychange64proto.p b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dinkeychange64proto.p new file mode 100644 index 0000000..b89378f Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dinkeychange64proto.p differ diff --git a/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dinkeychangewin32proto.p b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dinkeychangewin32proto.p new file mode 100644 index 0000000..fa7dc34 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/MATLAB/DinkeyChange/dinkeychangewin32proto.p differ diff --git a/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/README.html b/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/README.html new file mode 100644 index 0000000..05c1104 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/README.html @@ -0,0 +1,343 @@ + + + + + Using Dinkey Pro/FD with MATLAB + + + +

Using Dinkey Pro/FD with MATLAB

+
+

+ The Shell protection method supports Windows executables produced by the MATLAB Compiler. +

+

+ API protection checks in MATLAB are implemented using the M-file ddprotcheck.p to communicate with the dongle via the appropriate shared library + (dpwin32.dll on 32-bit Windows, dplin64.so on 64-bit Linux, etc.). + You should lock these shared libraries with the API method using DinkeyAdd as described in the user manual, and distribute the locked libraries with your software. +

+
+

+ If you are not already familiar with calling shared libraries from MATLAB code, + it is strongly recommended that you read the MATLAB documentation on this topic. + Depending on your version of MATLAB, you may need to install a C compiler and configure MATLAB to use it with the command mex -setup. + Again, refer to the MATLAB documentation for more information. +

+

+ See Modifying Your Code in the user manual for information on using the API. + Below is an overview of how the ddprotcheck function is used in MATLAB. +

+
ddprotcheck Call the Dinkey Pro/FD API.
+    [RETCODE,DRIS] = ddprotcheck(LIBNAME,DRIS) calls the API via the
+    external library LIBNAME. DRIS is a struct used to pass inputs to the
+    API and receive outputs. RETCODE is the return code of the API call.
+
+    [RETCODE,DRIS] = ddprotcheck(LIBNAME,DRIS,@CRYPTFUNCTION) additionally
+    provides an extra layer of security. The function CRYPTFUNCTION
+    is used to encrypt the DRIS before it is passed between MATLAB and the
+    external library.
+ +

+ In MATLAB, the DRIS is a MATLAB structure with some slight differences to the DRIS + documented in Structures > DRIS Structure in the user manual. + These differences are: +

+
    +
  • + The fields header and size are set automatically by ddprotcheck.p. + You do not need to set these fields in your code. +
  • +
  • + The seed1 and seed2 fields must be 1-by-4 vectors of type uint8, not integers. +
  • +
  • + rw_data_ptr is replaced by rw_data. + This field is the actual data read from/to be written to the dongle (rather than a pointer to it). + It should be a 1-by-N vector of type uint8. +
  • +
  • + When using the functions WRITE_DATA_AREA, ENCRYPT_USER_DATA and DECRYPT_USER_DATA, + rw_length is automatically set to be the length of the vector rw_data. +
  • +
  • + The fields var_a to var_h are replaced by alg_vars. + alg_vars must be a 1-by-N vector. The first 8 elements will be used for var_a to var_h. + If alg_vars has fewer than 8 elements, it will be padded with zeros. +
  • +
+

+ DRIS fields are automatically converted to the data types specified in Structures > DRIS Structure. + When casting, MATLAB truncates values that cannot fit into a variable of the new data type. + This can lead to loss of data. +

+

+ Indices for the secure data area of Plus and Net dongles start at zero. + To read the first ten bytes for example, set rw_length = 10 and rw_offset = 0. +

+

+ In the user manual, possible values for the function and flags fields are referred to by the + symbolic names used in other programming languages. Their literal values are provided here for your reference: +

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FunctionValue
PROTECTION_CHECK1
EXECUTE_ALGORITHM2
WRITE_DATA_AREA3
READ_DATA_AREA4
ENCRYPT_USER_DATA5
DECRYPT_USER_DATA6
FAST_PRESENCE_CHECK7
STOP_NET_USER8
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FlagValue
DEC_ONE_EXEC1
DEC_MANY_EXECS2
START_NET_USER4
USE_FUNCTION_ARGUMENT16
CHECK_LOCAL_FIRST32
CHECK_NETWORK_FIRST64
USE_ALT_LICENCE_NAME128
DONT_SET_MAXDAYS_EXPIRY256
MATCH_DONGLE_NUMBER512
DONT_RETURN_FD_DRIVE1024
+
+
+
+

+ Before you distribute your application, you must protect it from modification. + In general, it is best to use the MATLAB Compiler to create a standalone application that can be run outside of MATLAB. + It is also possible to convert your source files to P-code, which protects the code from modification, + but still allows it to be run inside the MATLAB environment. + However, MathWorks do not recommend P-coding files to protect your intellectual property, + as P-code files are obfuscated, not encrypted. + See the MATLAB documentation for more information. +

+
+

MATLAB Example Files

+
    +
  • ddprotcheck.p - a P-file that provides a MATLAB interface to the Dinkey Pro/FD API.
  • +
  • dpsample.m - various examples of using ddprotcheck.p.
  • +
  • dinkeyprowin32proto.p - a prototype P-file that defines the signatures of the API functions for 32-bit MATLAB on Windows.
  • +
  • dinkeypro32proto.p - a prototype P-file that defines the signatures of the API functions for 32-bit MATLAB on all other supported platforms.
  • +
  • dinkeypro64proto.p - a prototype P-file that defines the signatures of the API functions for 64-bit MATLAB on all supported platforms.
  • +
  • dp64_thunk.dll - a compatibility layer required by 64-bit MATLAB to use dpwin64.dll.
  • +
  • dp64_thunk.dylib - a compatibility layer required by 64-bit MATLAB to use dpmac64.dylib.
  • +
  • dp64_thunk.so - a compatibility layer required by 64-bit MATLAB to use dplin64.so.
  • +
+

+ ddprotcheck.p and the appropriate prototype P-file(s) should be used in your own project. + If you are using 64-bit MATLAB, you should also include the appropriate thunk file(s) for the platform(s) that you support. +

+ +

Supported Versions

+

+ The MATLAB sample code provided with the Dinkey Pro/FD SDK was written using MATLAB 7 (R14) for Windows, + and tested using MATLAB 7 on 32-bit Windows and MATLAB R2013a on 64-bit Windows. + All newer versions should be backwards compatible. The sample code may also work with older versions, + but no guarantees can be made, and support for older versions is likely to be very limited. +

+

+ dp64_thunk.dylib and dp64_thunk.so may not be compatible with all versions of MATLAB + on all versions of macOS and/or all Linux distributions. If you have problems calling our API on 64-bit macOS or 64-bit Linux, + please contact us with full details of the platform and MATLAB version that you are using. +

+ +

Try It Yourself

+
+

+ The sample code is designed to teach you how to use the Dinkey Pro/FD API in MATLAB programs. + Do not copy the examples verbatim into your own code. Experiment with the sample code to understand how the API works, + and read the chapter Increasing Your Protection in the user manual for many suggestions on how to + make the best use of the API features. +

+
+

+ dpsample.m gives simple examples of performing a protection check, + as well as using various other features of Dinkey Pro/FD. + To run dpsample.m you will first need to use DinkeyAdd to produce a locked copy of the shared library for your platform, + and program a dongle (if you are using Plus or Net dongles). + Place the locked library in the same folder as the example files and change MATLAB's current directory to this folder. + Browse the examples in dpsample.m to see how different features can be used. + All the examples follow the same basic pattern: +

+
    +
  1. Set up the DRIS structure with the relevant information.
  2. +
  3. Call the API.
  4. +
  5. Use the information returned in the DRIS.
  6. +
+

+ Uncomment the function calls at the top of dpsample.m + to enable the examples of different features, then enter dpsample in the Command Window to run the examples. +

+

+ dpsample.m also demonstrates loading and unloading the appropriate shared library for your platform. +

+

+ Parts of the sample code marked with !!!! must be customised with your own functions or values + for some features to work correctly. Not all features are supported by all dongle models. + See the user manual for more information. +

+ + + diff --git a/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/ddprotcheck.p b/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/ddprotcheck.p new file mode 100644 index 0000000..787295f Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/ddprotcheck.p differ diff --git a/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/dinkeypro32proto.p b/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/dinkeypro32proto.p new file mode 100644 index 0000000..eab23ed Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/dinkeypro32proto.p differ diff --git a/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/dinkeypro64proto.p b/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/dinkeypro64proto.p new file mode 100644 index 0000000..84cd52c Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/dinkeypro64proto.p differ diff --git a/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/dinkeyprowin32proto.p b/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/dinkeyprowin32proto.p new file mode 100644 index 0000000..0876cac Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/dinkeyprowin32proto.p differ diff --git a/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/dp64_thunk.dll b/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/dp64_thunk.dll new file mode 100644 index 0000000..58bb549 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/dp64_thunk.dll differ diff --git a/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/dp64_thunk.dylib b/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/dp64_thunk.dylib new file mode 100644 index 0000000..56abdb1 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/dp64_thunk.dylib differ diff --git a/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/dpsample.m b/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/dpsample.m new file mode 100644 index 0000000..5de3b88 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/MATLAB/Runtime/dpsample.m @@ -0,0 +1,502 @@ +function dpsample +%DPSAMPLE Example use of the Dinkey Pro/FD API in MATLAB. + +% Copyright 2015 Microcosm Ltd. + + % Load the correct library for this platform + % !!!! If you rename the libraries as recommended in the user manual, + % !!!! you need to modify the lines below to use the new names. + switch computer() + case 'PCWIN64' % 64-bit Windows + loadlibrary('dpwin64.dll', @dinkeypro64proto, 'alias', 'dinkeypro'); + case 'PCWIN' % 32-bit Windows + loadlibrary('dpwin32.dll', @dinkeyprowin32proto, 'alias', 'dinkeypro'); + case 'GLNXA64' % 64-bit Linux + loadlibrary('dplin64.so', @dinkeypro64proto, 'alias', 'dinkeypro'); + case 'GLNX86' % 32-bit Linux + loadlibrary('dplin32.so', @dinkeypro32proto, 'alias', 'dinkeypro'); + case 'MACI64' % 64-bit Mac OS X + loadlibrary('dpmac64.dylib', @dinkeypro64proto, 'alias', 'dinkeypro'); + case 'MAC' % 32-bit Mac OS X + loadlibrary('dpmac32.dylib', @dinkeypro32proto, 'alias', 'dinkeypro'); + otherwise + disp('Error! Platform not supported!'); + return + end + + % Each of the functions below demonstrates different API functionality. + % Uncomment the appropriate functions to execute the examples. + % See the comments in each function for more details about the features + % that they demonstrate. + + protcheck('dinkeypro'); + %protcheckwithalg('dinkeypro'); + %writedataarea('dinkeypro'); + %readdataarea('dinkeypro'); + %encryptuserdata('dinkeypro'); + %protcheckenc('dinkeypro'); + %writedataareaenc('dinkeypro'); + %readdataareaenc('dinkeypro'); + + % Unload the library + unloadlibrary('dinkeypro'); +end + + +function protcheck(libName) +% An example of a basic protection check + + PROTECTION_CHECK = 1; + DEC_ONE_EXEC = 1; + START_NET_USER = 4; + + % Initialise the DRIS + dris.function = PROTECTION_CHECK; + dris.flags = bitor(DEC_ONE_EXEC, START_NET_USER); + + % Call the API + [retCode, dris] = ddprotcheck(libName, dris); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, dris.ext_err); + return + end + + % ... + + % You can check other values from the DRIS in other parts of your + % program to improve security. For example: + + % Check the SDSN + % !!!! "10101" is the SDSN used by the demo SDK and demo dongles + % !!!! If not using a demo, replace "10101" with your own SDSN here + if (dris.sdsn ~= 10101) + disp('Incorrect SDSN! Have you replaced "10101" with your SDSN in the sample code?'); + return + end + + % Check the product code + % !!!! Replace "DEMO" with the product code you specify when adding + % protection with DinkeyAdd + if (~strcmp(dris.prodcode, 'DEMO')) + disp('Incorrect product code! Have you replaced "DEMO" with your product code in the sample code?'); + return + end + + disp('Protection check successful'); +end + + +function protcheckwithalg(libName) +% An example of a protection check that also executes an algorithm stored +% in the dongle. +% The best way to use this feature is to identify lines of code in your +% program that can be represented by algorithms stored in the dongle, and +% replace these lines with calls to the API. Lite dongle users cannot +% change the algorithm stored in the dongles, so should calculate the +% algorithm in their own code and compare the result with the one returned +% by the API, as in this example. + + EXECUTE_ALGORITHM = 2; + + % Initialise the DRIS + dris.function = EXECUTE_ALGORITHM; + dris.alg_vars = [1 2 3 4 5 6 7 8]; % The input variables to use in the algorithm + dris.alg_number = 1; % The algorithm to execute. Lite dongles ignore this field, as they contain only 1 algorithm + + % Call the API + [retCode, dris] = ddprotcheck(libName, dris); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, dris.ext_err); + return + end + + + % Check the algorithm result in another part of your program to improve + % security. !!!! Ensure the myalgorithm() function matches the + % algorithm that was executed by the protection check! + if (dris.alg_answer ~= myalgorithm(dris.alg_vars)) + disp('Error! The algorithm result was not as expected.'); + return + end + + disp('Protection check with algorithm successful'); +end + + +function writedataarea(libName) +% An example of a protection check that also writes data to the dongle's +% secure data area. +% This feature is not supported by Lite dongles. +% Make sure you specify a large enough data area size when adding +% protection with DinkeyAdd! + + WRITE_DATA_AREA = 3; + + % Initialise the DRIS + dris.function = WRITE_DATA_AREA; + dris.rw_data = 'Hello, World!'; % Data to write + dris.rw_offset = 0; % Index to start writing at. Note indices start at zero! + + % Call the API + [retCode, dris] = ddprotcheck(libName, dris); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, dris.ext_err); + return + end + + disp('Writing data successful'); +end + + +function readdataarea(libName) +% An example of a protection check that also reads data from the dongle's +% secure data area. +% This feature is not supported by Lite dongles. +% Make sure you specify a large enough data area size when adding +% protection with DinkeyAdd! + + READ_DATA_AREA = 4; + + % Initialise the DRIS + dris.function = READ_DATA_AREA; + dris.rw_offset = 0; % Index to start reading at. Note indices start at zero! + dris.rw_length = 13; % How many bytes to read + + % Call the API + [retCode, dris] = ddprotcheck(libName, dris); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, dris.ext_err); + return + end + + disp(['Reading data successful: ' char(dris.rw_data)]); +end + + +function encryptuserdata(libName) +% An example of protection checks that encrypt/decrypt your data. +% This feature is not supported by Lite dongles. + + ENCRYPT_USER_DATA = 5; + DECRYPT_USER_DATA = 6; + + originalData = uint8(255 * rand(1, 10)); + + % Initialise the DRIS + dris.function = ENCRYPT_USER_DATA; + dris.rw_data = originalData; + dris.data_crypt_key_num = 1; + + % Call the API + [retCode, dris] = ddprotcheck(libName, dris); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, dris.ext_err); + return + end + + encryptedData = dris.rw_data; + + % Initialise the DRIS + dris.function = DECRYPT_USER_DATA; + + % Call the API + [retCode, dris] = ddprotcheck(libName, dris); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, dris.ext_err); + return + end + + decryptedData = dris.rw_data; + + disp('Data encryption successful'); + disp('Original data:'); + disp(originalData); + disp('Encrypted data:'); + disp(encryptedData); + disp('Decrypted data:'); + disp(decryptedData); +end + + +function protcheckenc(libName) +% An example of a protection check that uses DRIS encryption for extra +% security. + + PROTECTION_CHECK = 1; + + % Initialise the DRIS + dris.function = PROTECTION_CHECK; + dris.seed1 = uint8(255 * rand(1, 4)); % 4 random bytes + dris.seed2 = uint8(255 * rand(1, 4)); % 4 random bytes + + % Call the API + [retCode, dris] = ddprotcheck(libName, dris, @cryptdris); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, dris.ext_err); + return + end + + + % You can check other values from the DRIS in other parts of your + % program to improve security. For example: + + % Check the SDSN + % !!!! "10101" is the SDSN used by the demo SDK and demo dongles + % !!!! If not using a demo, replace "10101" with your own SDSN here + if (dris.sdsn ~= 10101) + disp('Incorrect SDSN! Have you replaced "10101" with your SDSN in the sample code?'); + return + end + + % Check the product code + % !!!! Replace "DEMO" with the product code you specify when adding + % protection with DinkeyAdd + if (~strcmp(dris.prodcode, 'DEMO')) + disp('Incorrect product code! Have you replaced "DEMO" with your product code in the sample code?'); + return + end + + disp('Protection check successful'); +end + + +function writedataareaenc(libName) +% An example of a protection check that also writes data to the dongle's +% secure data area. +% This feature is not supported by Lite dongles. +% Make sure you specify a large enough data area size when adding +% protection with DinkeyAdd! This function also uses DRIS encryption and +% encrypts the rw_data field for extra security. You must select these +% options in DinkeyAdd for this function to work correctly! + + WRITE_DATA_AREA = 3; + + % Initialise the DRIS + dris.function = WRITE_DATA_AREA; + dris.rw_offset = 0; + dris.seed1 = uint8(255 * rand(1, 4)); % 4 random bytes + dris.seed2 = uint8(255 * rand(1, 4)); % 4 random bytes + dris.alg_vars = randint(1 , 8, double([intmin intmax])); % 8 random signed 32-bit integers + + rwAlgAnswer = myrwalgorithm(dris.alg_vars); + + % Encrypt the data to be written to the dongle + dataToWrite = uint8('ABCDEFGHIJKLMNOPQRSTUVWXYZ'); + dris.rw_data = cryptapidata(dataToWrite, dris.seed1, dris.seed2, rwAlgAnswer); + + % Call the API + [retCode, dris] = ddprotcheck(libName, dris, @cryptdris); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, dris.ext_err); + return + end + + disp('Writing data successful'); +end + + +function readdataareaenc(libName) +% An example of a protection check that also reads data from the dongle's +% secure data area. +% This feature is not supported by Lite dongles. +% Make sure you specify a large enough data area size when adding +% protection with DinkeyAdd! This function also uses DRIS encryption and +% encrypts the rw_data field for extra security. You must select these +% options in DinkeyAdd for this function to work correctly! + + READ_DATA_AREA = 4; + + % Initialise the DRIS + dris.function = READ_DATA_AREA; + dris.rw_offset = 0; + dris.rw_length = 10; + dris.seed1 = uint8(255 * rand(1, 4)); % 4 random bytes + dris.seed2 = uint8(255 * rand(1, 4)); % 4 random bytes + dris.alg_vars = randint(1 , 8, double([intmin intmax])); % 8 random signed 32-bit integers + + % Call the API + [retCode, dris] = ddprotcheck(libName, dris, @cryptdris); + + % Check the return value + if (retCode ~= 0) + displayerror(retCode, dris.ext_err); + return + end + + % Decrypt the data read from the dongle + rwAlgAnswer = myrwalgorithm(dris.alg_vars); + dataRead = cryptapidata(dris.rw_data, dris.seed1, dris.seed2, rwAlgAnswer); + + disp(['Reading data successful: ' char(dataRead)]); +end + + +function ret = myalgorithm(algVars) +% !!!! This function must match one stored in the dongle for +% protcheckwithalg() to work correctly. +% For Lite dongles, use DinkeyLook to see the algorithm pre-programmed +% into the dongle. For Plus and Net dongles, ensure this algorithm matches +% one you specified in DinkeyAdd when adding protection. + ret = algVars(1) - algVars(2) - algVars(3) - algVars(4) - algVars(5) - algVars(6) - algVars(7); +end + + +function ret = myrwalgorithm(algVars) +% !!!! This function must match the R/W algorithm stored in the dongle for +% writedataareaenc() and readdataareaenc() to work correctly. + ret = algVars(1) - algVars(2) - algVars(3) - algVars(4) - algVars(5) - algVars(6); +end + + +function dris = cryptdris(dris) +% This function can be used to encrypt/decrypt the DRIS. If using DRIS +% encryption in your own program, copy this function exactly. Modify only +% the parts indicated by !!!! + + % !!!! Overwrite the encryption parameters with those chosen in + % DinkeyAdd. This example uses 123, 212, 97. + DRIS_ENCRYPTION_PARAMETERS = [123 212 97]; + + S = 0:255; + bigseed = zeros(256, 1); + + for i = 1:8:256 + for j = 0:3 + bigseed(i+j) = dris(9+j); + bigseed(i+j+4) = dris(13+j); + end + end + + j = 0; + for i = 0:255 + j = bitand((j + S(i+1) + bigseed(i+1) + DRIS_ENCRYPTION_PARAMETERS(1)), 255); + temp = S(i+1); + S(i+1) = S(j+1); + S(j+1) = temp; + end + + i = 0; + j = 0; + for k = 17:length(dris) + i = bitand((i + 1), 255); + j = bitand((j + S(i+1) + DRIS_ENCRYPTION_PARAMETERS(2)), 255); + temp = S(i+1); + S(i+1) = S(j+1); + S(j+1) = temp; + t = bitand((S(i+1) + S(j+1) + DRIS_ENCRYPTION_PARAMETERS(3)), 255); + dris(k) = bitxor(dris(k), S(t+1)); + end +end + + +function data = cryptapidata(data, seed1, seed2, algAnswer) +% This function is used to encrypt/decrypt data passed in the rw_data DRIS +% field (applies to Plus and Net dongles only). If using this feature in +% your own program, copy this function exactly. Modify only the parts +% indicated by !!!! + + % !!!! If you are using constant encryption parameters, define them + % like this: + % DATA_ENCRYPTION_PARAMETERS = [X Y Z]; + + + % !!!! If you are using the R/W algorithm, derive the encryption + % parameters from the algorithm result like this: + + % 1. Convert algAnswer to uint32 without changing underlying data + if (algAnswer < 0) + algAnswer = uint32(double(algAnswer) + hex2dec('FFFFFFFF') + 1); + else + algAnswer = uint32(algAnswer); + end + + % 2. Now algAnswer is a uint32 we can use bitwise operations to derive + % the encryption parameters + DATA_ENCRYPTION_PARAMETERS = [bitand(algAnswer, 255), bitand(bitshift(algAnswer,-8), 255), bitand(bitshift(algAnswer,-16), 255)]; + + + % The rest of the function should not be modified! + + S = 0:255; + bigseed = zeros(256, 1); + + for i = 1:8:256 + for j = 0:3 + bigseed(i+j) = seed1(j+1); + bigseed(i+j+4) = seed2(j+1); + end + end + + j = 0; + for i = 0:255 + j = bitand((j + S(i+1) + bigseed(i+1) + DATA_ENCRYPTION_PARAMETERS(1)), 255); + temp = S(i+1); + S(i+1) = S(j+1); + S(j+1) = temp; + end + + i = 0; + j = 0; + for k = 1:length(data) + i = bitand((i + 1), 255); + j = bitand((j + S(i+1) + DATA_ENCRYPTION_PARAMETERS(2)), 255); + temp = S(i+1); + S(i+1) = S(j+1); + S(j+1) = temp; + t = bitand((S(i+1) + S(j+1) + DATA_ENCRYPTION_PARAMETERS(3)), 255); + data(k) = bitxor(data(k), S(t+1)); + end +end + + +% An example of error reporting +% Displays descriptions for some common error codes +% IMPORTANT - THE MESSAGES DISPLAYED ARE TO HELP DEVELOPERS IMPLEMENT THE +% DINKEY PRO/FD API. THEY ARE NOT SUITABLE FOR DISPLAYING TO USERS! +function displayerror(retCode, extErr) + switch retCode + case 401 + disp('Error! No dongles detected!'); + case 403 + disp('Error! The dongle is a different type to the one specified in DinkeyAdd.'); + case 404 + disp('Error! The dongle is a different model to those specified in DinkeyAdd.'); + case 409 + disp('Error! The dongle has not been programmed by DinkeyAdd.'); + case 410 + disp('Error! The dongle has a different product code to the one specified in DinkeyAdd.'); + case 411 + disp('Error! This program''s licence was not found in the dongle.'); + case 413 + disp('Error! This program has not been locked by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the user manual.'); + case 417 + disp('Error! One or more of the parameters set in the DRIS is incorrect.'); + disp('Check that you have defined the necessary input fields in the DRIS struct.'); + disp('Also check if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.'); + case 423 + disp('Error! The number of network users has been exceeded.'); + case 435 + disp('Error! DinkeyServer has not been detected on the network.'); + case 922 + disp('Error! The Software Key has expired.'); + otherwise + str = sprintf('An error occurred checking the dongle. Error: %d, Extended Error: %d', retCode, extErr); + disp(str); + end +end diff --git a/Dinkey Pro 7.6.1/Samples/PHP/README.html b/Dinkey Pro 7.6.1/Samples/PHP/README.html new file mode 100644 index 0000000..accecb1 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/PHP/README.html @@ -0,0 +1,293 @@ + + + + + Using Dinkey Pro/FD with PHP + + + +

Using Dinkey Pro/FD with PHP

+
+

+ Protection checks in PHP are implemented using a PHP extension to communicate with the dongle. + You should use DinkeyAdd to lock this extension with the API protection method as described in the user manual, and distribute the locked file(s) with your software. +

+
+

+ If you are not already familiar with using PHP extensions, it is strongly recommended that you read the PHP documentation on the subject. + The Dinkey Pro/FD SDK includes a large number of different PHP extension files. Which one(s) you need to use depends on several factors, + including operating system, PHP version, architecture (e.g. x86 or x64) and thread safety. + This sample code includes a script, extensionhelper.php, that detects these factors, + indicates which extension is appropriate, and provides basic installation instructions. +

+

+ It is important that you consider which system configuration(s) your protected software will support, + and distribute the corresponding PHP extension(s). + You may wish to distribute extensionhelper.php along with your software + to help your users to install the correct extension for their system. + See Supported Versions below for full information on the platforms supported by Dinkey Pro/FD. +

+

+ Do not specify a calling program when locking the PHP extensions. + The calling program for PHP code is the user's web server (or PHP CLI), which will be different for different users. +

+
+

+ Before you distribute your PHP code, you must protect it from modification using a third-party tool such as + SourceGuardian. +

+
+ +

API Reference

+

+ See Modifying Your Code in the user manual for general information about the Dinkey Pro/FD API. + In PHP, DDProtCheck() and the DRIS structure are not directly accessible. + Instead, the PHP API provides two sets of functions: wrappers to DDProtCheck() that also take parameters that set DRIS input fields; + and functions that access DRIS output fields. +

+ +

Protection Check Functions

+

+ These functions each provide a wrapper to DDProtCheck() using a different function value. + Each function's return value is the return value of DDProtCheck() - zero on success, or a value indicating the cause of the error on failure. +

+ +

DDSimpleCheck ( int $flags ) : int

+

+ Sets the flags DRIS field and calls DDProtCheck() with the PROTECTION_CHECK function. +

+ +

DDSimpleCheckEx ( int $flags , int $execs_decrement, string $alt_licence_name ) : int

+

+ Sets the flags, execs_decrement and alt_licence_name DRIS fields + and calls DDProtCheck() with the PROTECTION_CHECK function. +

+ +

DDSimpleCheckAlg ( int $flags , int $alg_num , int $var_a , int $var_b , int $var_c , int $var_d , int $var_e , int $var_f , int $var_g , int $var_h ) : int

+

+ Sets the flags, alg_num and var_a to var_h DRIS fields + and calls DDProtCheck() with the EXECUTE_ALGORITHM function. +

+ +

DDSimpleCheckAlgEx ( int $flags , int $execs_dec, string $alt_licence_name , int $alg_number , int $var_a , int $var_b , int $var_c , int $var_d , int $var_e , int $var_f , int $var_g , int $var_h ) : int

+

+ Sets the flags, execs_decrement, alt_licence_name, alg_num and var_a to var_h DRIS fields + and calls DDProtCheck() with the EXECUTE_ALGORITHM function. +

+ +

DDWriteString ( int $flags , int $rw_offset , string $rw_data ) : int

+

+ Sets the flags, rw_offset and rw_data DRIS fields + and calls DDProtCheck() with the WRITE_DATA_AREA function. +

+

+ $rw_data must be an ASCII string. To write binary data, first encode it using base64_encode(). + The rw_length DRIS field is automatically set to the length of $rw_data. +

+ +

DDReadString ( int $flags , int $rw_offset , int $rw_length , string &$rw_data) : int

+

+ Sets the flags, rw_offset and rw_length DRIS fields + and calls DDProtCheck() with the READ_DATA_AREA function. + The data read is returned in $rw_data. +

+

+ Only use this function to read data that represents an ASCII string. + If you read bytes that do not represent ASCII characters, the string value returned in $rw_data may be unpredictable. + To read binary data, store it in the dongle data area as a base64-encoded sequence and use base64_decode() on the string returned in $rw_data. +

+ +

DDGet...() Functions

+

+ Each DDGet...() function takes one parameter by reference sets it to the value of the relevant DRIS element. + See Structures > DRIS Structure in the user manual for more information about the DRIS and its fields. + These functions return TRUE on success, or FALSE if the internal DRIS has not been populated by a call to one of the + DDProtCheck() wrapper functions above. +

+
    +
  • DDGetExtendedError ( int &$ext_err ) : bool
  • +
  • DDGetType ( int &$type ) : bool
  • +
  • DDGetModel ( int &$model ) : bool
  • +
  • DDGetSDSN ( int &$sdsn ) : bool
  • +
  • DDGetProdCode ( string &$prodcode ) : bool
  • +
  • DDGetDongleNumber ( int &$dongle_number ) : bool
  • +
  • DDGetUpdateNumber ( int &$update_number ) : bool
  • +
  • DDGetDataAreaSize ( int &$data_area_size ) : bool
  • +
  • DDGetMaxAlgNum ( int &$max_alg_num ) : bool
  • +
  • DDGetExecs ( int &$execs ) : bool
  • +
  • DDGetExpDay ( int &$exp_day ) : bool
  • +
  • DDGetExpMonth ( int &$exp_month ) : bool
  • +
  • DDGetExpYear ( int &$exp_year ) : bool
  • +
  • DDGetFeatures ( int &$features ) : bool
  • +
  • DDGetNetUsers ( int &$net_users ) : bool
  • +
  • DDGetAlgAnswer ( int &$alg_answer ) : bool
  • +
  • DDGetFDCapacity ( int &$fd_capacity ) : bool
  • +
  • DDGetFDDrive ( string &$fd_drive ) : bool
  • +
  • DDGetSWKeyType ( int &$swkey_type ) : bool
  • +
  • DDGetSWKeyExpDay ( int &$swkey_exp_day ) : bool
  • +
  • DDGetSWKeyExpMonth ( int &$swkey_exp_month ) : bool
  • +
  • DDGetSWKeyExpYear ( int &$swkey_exp_year ) : bool
  • +
+ +

PHP Example Files

+
    +
  • + dpsample.php - various examples of using the Dinkey Pro/FD PHP API. + This script outputs HTML and so is best used in a web server, but it can also be run using the PHP CLI. +
  • +
  • + extensionhelper.php - a script that detects system configuration to determine + the appropriate PHP extension to use, and where it should be located. + This script outputs HTML when used in a web server and plain text when executed by the PHP CLI. +
  • +
+ +

Supported Versions

+

+ The Dinkey Pro/FD SDK includes extensions for PHP versions 5.1 and newer on Windows and Linux. + The x86 and x64 architectures are both supported, and extensions are provided for both Thread Safe (TS) and Non-Thread Safe (NTS) builds of PHP. + Due to the large number of combinations of PHP version, OS, architecture and TS/NTS PHP builds, + the exact extension for your system may not be included in the SDK. + In this case, please contact us with full details of your platform. +

+ +

Try It Yourself

+
+

+ The sample code is designed to teach you how to use the Dinkey Pro/FD API in PHP programs. + Do not copy the examples verbatim into your own code. Experiment with the sample code to understand how the API works, + and read the chapter Increasing Your Protection in the user manual for many suggestions on how to + make the best use of the API features. +

+
+

+ To execute the sample code you will first need to use DinkeyAdd to produce a locked copy of the PHP extension for your system, + and program a dongle (if you are using Plus or Net dongles). Place the locked extension in your PHP extensions directory. + Use extensionhelper.php to determine the correct extension and the location of the extensions directory for your system. +

+

+ dpsample.php gives simple examples of performing a protection check, + as well as using various other features of Dinkey Pro/FD. + Browse the examples at the top of dpsample.php to see how different features can be used, + and uncomment the relevant lines to enable them. +

+

+ Not all features are supported by all dongle models. + See the user manual for more information. +

+ + diff --git a/Dinkey Pro 7.6.1/Samples/PHP/dpsample.php b/Dinkey Pro 7.6.1/Samples/PHP/dpsample.php new file mode 100644 index 0000000..a673a8a --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/PHP/dpsample.php @@ -0,0 +1,181 @@ + + + + + + + Dinkey Pro/FD PHP API Sample Code + + + +

+ Protection check failed +

+

+ Error Code:
+ Extended Error Code:
+

+ +

+ Protection check succeeded +

+

+ + Algorithm result:
+ + + + Data read:
+ + + SDSN:
+ Product Code:
+ Dongle Number:
+ + Dongle Type:
+ + + Flash Drive Path:
+ + + Dongle Model:
+ + DONGLE_MODEL_LITE): ?> + Update Number:
+ Data Area Size:
+ Max Algorithm Number:
+ Executions:
+ Expiry Day:
+ Expiry Month:
+ Expiry Year:
+ Features:
+ + + DONGLE_MODEL_PLUS): ?> + Maximum Simultaneous Network Users:
+ + + + Software Key Type:
+ Software Key Expiry Day:
+ Software Key Expiry Month:
+ Software Key Expiry Year:
+ + + + + diff --git a/Dinkey Pro 7.6.1/Samples/PHP/extensionhelper.php b/Dinkey Pro 7.6.1/Samples/PHP/extensionhelper.php new file mode 100644 index 0000000..e7d5648 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/PHP/extensionhelper.php @@ -0,0 +1,146 @@ + + + + Dinkey Pro/FD PHP Extension Helper + + +

System Configuration

+ + + + ". ( ($os == "win") ? "" : "" ) ." + + + + +
Operating System:$osFriendlyName
PHP Version:{$info['server-config']['php-ver']}
Compiler:{$info['server-config']['compiler']}
Thread Safety:".(($info['server-config']['thread-safety'] == "ts") ? "Enabled" : "Disabled")."
Architecture:{$info['server-config']['arch']}-bit
PHP Extensions Directory:{$info['server-config']['ext-dir']}
PHP Configuration File:{$info['server-config']['php-ini-filename']}
+

Use the following PHP extension on this system: {$info['dp-ext-filename']}.

+

Installation

+
    +
  1. Lock {$info['dp-ext-filename']} with DinkeyAdd and copy the locked file to {$info['server-config']['ext-dir']}.

  2. +
  3. Edit the {$info['server-config']['php-ini-filename']} file to include the following line:
      extension={$info['dp-ext-filename']}

  4. + ". (($info['server-config']['webserver'] != "") ? "
  5. Restart {$info['server-config']['webserver']}.

  6. " : "") ." +
+ + + "; +} + + +$os = ""; +$version = ""; +$threadsafe = ""; +$compiler = ""; +$arch = ""; + +if (stristr(php_uname("s"), "linux") !== false) + $os = "lin"; +else if (stristr(php_uname("s"), "win") !== false) // Windows can be given as "Windows NT", or "WINNT"... just search for "win" + $os = "win"; + +$v = explode(".", PHP_VERSION); +$version = $v[0] . "." . $v[1]; + +$matches = array(); +$match = (bool) preg_match("/php extension build[^,]+,([NTS]{2,3}),?(VC[0-9]+)?/i", PHPINFO, $matches); +if ($match) +{ + $threadsafe = strtolower($matches[1]); + + if ($os == "win") + $compiler = strtolower($matches[2]); +} + +$i = intval("9223372036854775807"); +$s = strval($i); +if ($s == "9223372036854775807") + $arch = "64"; +else + $arch = "32"; + +if ($os == "") + die("Error, could not detect operating system."); +if ($threadsafe == "") + die("Error, could not detect thread-safety setting."); +if (($os == "win") && ($version >= 5.3) && ($compiler == "")) + die("Error, could not detect compiler version."); + +$filename = (($os=="lin") ? "lib" : "") . "dpphp-$os$arch-$version-$threadsafe" . (($os=="win" && $version>=5.3) ? "-$compiler" : "") . "." . (($os=="win") ? "dll" : "so"); + +$phpIniFilename = get_cfg_var('cfg_file_path'); +$extDir = ini_get("extension_dir"); + +$webserver = ""; +if (isset($_SERVER['SERVER_SOFTWARE'])) +{ + if (stripos($_SERVER['SERVER_SOFTWARE'], "iis") !== FALSE) + $webserver = "Microsoft IIS"; + else if (stripos($_SERVER['SERVER_SOFTWARE'], "apache") !== FALSE) + $webserver = "Apache"; + else + $webserver = "your HTTP server software"; +} + +$info = array( + 'server-config' => array( + 'os' => $os, + 'php-ver' => $version, + 'webserver' => $webserver, + 'compiler' => $compiler, + 'thread-safety' => (bool)($threadsafe == "ts"), + 'arch' => $arch, + 'ext-dir' => $extDir, + 'php-ini-filename' => $phpIniFilename + ), + + 'dp-ext-filename' => $filename, +); + +pretty_output($info); + +?> diff --git a/Dinkey Pro 7.6.1/Samples/Python/Cython/README.txt b/Dinkey Pro 7.6.1/Samples/Python/Cython/README.txt new file mode 100644 index 0000000..467a086 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Python/Cython/README.txt @@ -0,0 +1,50 @@ +Cython Sample Code +~~~~~~~~~~~~~~~~~~ + +NB - tested under Python 2.7 and Python 3.6 with Cython 0.29 with Visual Studio C compiler +but it should work for all versions of Python, Cython and C compiler. (We also tested the +32-bit code using MinGW). + +If you are coding in Cython then you can link the Dinkey Pro/FD Runtime module directly to +your code (rather than having to call an external Python extension). See the notes for +Python sample code as to why this is preferable. Use: + +dpwin32_coff.obj for 32-bit code +dpwin64.obj for 64-bit code + +The source files in the project are: + +File name Description +objtest.pyx main source code file for Cython containing protection functions +objtest.pxd implements the DRIS structure and function definitions +ddpro.h Used by the pxd file so we can call DDProtCheck (a hack because it is + difficult to declare a stdcall function in a pxd file) +setup.py python file to compile the Cython sample code + +The sample code is just a guide. You should implement the protection in a stronger way +using the techniques described in the "Increasing your Protection" chapter of the manual. + +NB - our sample code assumes that you are using 64-bit Python 3. If not then you will have +to make some small modifications to setup.py: + +32-bit Python: modify extra_objects to list "dpwin32_coff.obj" instead of "dpwin64.obj" + +Python 2: modify 'language_level' to be "2" (If you are using an old version of Python/Cython + you may have to modify the objtest.pyx code. e.g. "DEMO" instead of b'DEMO' and use + print instead of print() + +To compile run the following command: + +python setup.py build_ext --inplace --compiler=msvc + +(for mingw32 use --compiler=mingw32) + +So a makefile could look like this: + +all: + python setup.py build_ext -c mingw32 --inplace + rm -rf ./build + rm -f *.c + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: diff --git a/Dinkey Pro 7.6.1/Samples/Python/Cython/ddpro.h b/Dinkey Pro 7.6.1/Samples/Python/Cython/ddpro.h new file mode 100644 index 0000000..9e01a29 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Python/Cython/ddpro.h @@ -0,0 +1,2 @@ +int __stdcall DDProtCheck(void*, unsigned char*); +int __stdcall DDGetNetUserList(char*, int*, void*, int, int*); diff --git a/Dinkey Pro 7.6.1/Samples/Python/Cython/objtest.pxd b/Dinkey Pro 7.6.1/Samples/Python/Cython/objtest.pxd new file mode 100644 index 0000000..e15ff5a --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Python/Cython/objtest.pxd @@ -0,0 +1,62 @@ +#DRIS struture +cdef packed struct DRIS: + # the first 4 fields are never encrypted + char header[4] # should be set to DRIS + # inputs + int size # size of this structure + int seed1 # seed for data/dris encryption + int seed2 # as above + # (maybe encrypted from now on) + int function # specify only one function + int flags # options for the function selected. To use more than one OR them together: OPTION1 | OPTION2... + unsigned int execs_decrement # amount by which to dec execs if we use flag: DEC_MANY_EXECS + int data_crypt_key_num # number of the key (1-3) that the dongle uses to encrypt or decrypt user data + int rw_offset # offset in the dongle data area to read or write data + int rw_length # length of data are to read/write/encrypt/decrypt + char *rw_data_ptr # pointer to data to write / be read + char alt_prog_name[256] # protection check for different program instead of this one, must be null-terminated + int var_a # variable values for user algorithm + int var_b + int var_c + int var_d + int var_e + int var_f + int var_g + int var_h + int alg_number # the number of the user algorithm that you want to execute + # outputs + int ret_code # return code from the protection check + int ext_err # extended error + int type # type of dongle detected. 1 = Pro, 2 = FD + int model # model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + int sdsn # Software Developer's Serial Number + char prodcode[12] # Product Code (null-terminated) + unsigned int dongle_number + int update_number + unsigned int data_area_size # size of the data area used in the dongle detected + int max_alg_num # the maximum algorithm number in the dongle detected + int execs # executions left: -1 indicates 'no limit' + int exp_day # expiry day: -1 indicates 'no limit' + int exp_month # expiry month: -1 indicates 'no limit' + int exp_year # expiry year: -1 indicates 'no limit' + unsigned int features # features value + int net_users # maximum number of network users for the dongle detected: -1 indicates 'no limit' + int alg_answer # answer to the user algorithm executed with the given variable values + unsigned int fd_capacity # capacity of the data area in FD dongle. + char fd_drive[128] # drive letter of FD dongle detected e.g. 'f:\' (or mount name under Linux) + int swkey_type # 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + int swkey_exp_day # software key expiry date (if software key detected) + int swkey_exp_month + int swkey_exp_year + +#NU_INFO struture +cdef packed struct NU_INFO: + char licenceName[256] + char userName[50] + char computerName[256] + char ipAddress[16] + +# declare DDProtCheck (we do it like this because it is stdcall - the default for Cython is cdecl) +cdef extern from "ddpro.h": + int __stdcall DDProtCheck(void*, unsigned char*) + int __stdcall DDGetNetUserList(char*, int*, void*, int, int*) diff --git a/Dinkey Pro 7.6.1/Samples/Python/Cython/objtest.pyx b/Dinkey Pro 7.6.1/Samples/Python/Cython/objtest.pyx new file mode 100644 index 0000000..b44a721 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Python/Cython/objtest.pyx @@ -0,0 +1,647 @@ +from libc.string cimport memcpy +from libc.string cimport strlen +import random + +# The sample code contains 10 functions. You will not need to use all these +# functions in your code. Just use which ever functions are most appropriate +# and customise in your own way. The sample code is just a guide. You should +# implement the protection in a stronger way using the techniques described in +# the "Increasing your Protection" chapter of the manual. +# +# If you are using Dinkey Lite then you can only use 4 functions: +# ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + +# this file contains 10 protection-check functions. +# ProtCheck a standard protection check +# ProtCheckWithAlg a protection check & executing an Algorithm +# WriteBytes a protection check & write data to the dongle +# ReadBytes a protection check & read data from the dongle +# EncryptUserData a protection check & encrypting data and then decrypting the data + +# these functions are the same as the functions listed above but encrypting all parameters passed to our API +# ProtCheckEnc a standard protection check +# ProtCheckWithAlgEnc a protection check & executing an Algorithm +# WriteBytesEnc a protection check & write data to the dongle +# ReadBytesEnc a protection check & read data from the dongle +# EncryptUserDataEnc a protection check & encrypting data and then decrypting the data + +DEF MY_SDSN = 10101 # !!!! modify this value to your SDSN +DEF MY_PRODCODE = b'DEMO' # !!!! change this value to match the Product Code in the dongle + +# for some reason these constants have to be declared here rather than the pxd file +# functions - must specify only one +DEF PROTECTION_CHECK=1 # checks for dongle, check program params... +DEF EXECUTE_ALGORITHM=2 # protection check + calculate answer for specified algorithm with specified inputs +DEF WRITE_DATA_AREA=3 # protection check + writes dongle data area +DEF READ_DATA_AREA=4 # protection check + reads dongle data area +DEF ENCRYPT_USER_DATA=5 # protection check + the dongle will encrypt user data +DEF DECRYPT_USER_DATA=6 # protection check + the dongle will decrypt user data +DEF FAST_PRESENCE_CHECK=7 # checks for the presence of the correct dongle only with minimal security, no flags allowed. +DEF STOP_NET_USER=8 # stops a network user (a protection check is NOT performed) + +# flags - can specify as many as you like +DEF DEC_ONE_EXEC=1 # decrement execs by 1 +DEF DEC_MANY_EXECS=2 # decrement execs by number specified in execs_decrement +DEF START_NET_USER=4 # starts a network user +DEF USE_FUNCTION_ARGUMENT=16 # use the extra argument in the function for pointers +DEF CHECK_LOCAL_FIRST=32 # always look in local ports before looking in network ports +DEF CHECK_NETWORK_FIRST=64 # always look on the network before looking in local ports +DEF USE_ALT_PROG_NAME=128 # use name specified in prog_name instead of this program name +DEF DONT_SET_MAXDAYS_EXPIRY=256 # if the max days expiry date has not been calculated then do not do it this time +DEF MATCH_DONGLE_NUMBER=512 # restrict the search to match the dongle number specified in the DRIS +DEF DONT_RETURN_FD_DRIVE=1024 # if an FD dongle has been detected then don't return the flash drive/mount name + +# ************************* our 10 functions ********************************** + +# ************************** ProtCheck *************************************** +cpdef int ProtCheck(): + cdef DRIS dris + cdef int ret_code + + # set the DRIS to have random values + cdef unsigned char *drisbuf = &dris + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + # then set the values we want to use + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = PROTECTION_CHECK # standard protection check + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + ret_code = DDProtCheck(&dris, NULL) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + # later in your code you can check other values in the DRIS... + + if (dris.sdsn != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return -1 + + if (dris.prodcode != MY_PRODCODE): + print("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.") + return -1 + + # later on in your program you can check the return code again + if (dris.ret_code != 0): + print("Dinkey Dongle protection error") + return -1 + + print("It worked!") + return 0 + + +# ************************** ProtCheckWithAlg ****************************** + +# !!!! You should replace this function with the one generated by the +# "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) +# or from DinkeyLook if you are using a Dinkey Lite dongle. +# (If it does not generate source code for Python you have translate it from C) +cdef int MyAlgorithm(int a, int b, int c, int d, int e, int f, int g, int h): + return a + b + c + d + e + f + g + h + +# NB for this to work you must program at least "user algorithm" into the dongle +# NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +# sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +# code from DinkeyLook +cpdef int ProtCheckWithAlg(): + cdef DRIS dris + cdef int ret_code + + # set the DRIS to have random values + cdef unsigned char *drisbuf = &dris + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + # then set the values we want to use + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = EXECUTE_ALGORITHM # standard protection check and execute algorithm + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number = 1 # execute algorithm 1 (you do not need to specify this field if you are only using Lite models) + + ret_code = DDProtCheck(&dris, NULL) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + if (dris.sdsn != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return -1 + + # later on in your program you can check the return code again + if (dris.ret_code != 0): + print("Dinkey Dongle protection error") + return -1 + + # if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + # !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) != dris.alg_answer): + print("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine") + return -1 + + print("It worked!") + return 0 + + +# ************************** WriteBytes ****************************** +# This writes the string "Hello, World!" to the dongle data area at offset 7 +# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +cpdef int WriteBytes(): + cdef DRIS dris + cdef int ret_code + cdef char *datatowrite = "Hello, World!" + + # set the DRIS to have random values + cdef unsigned char *drisbuf = &dris + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + # then set the values we want to use + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = WRITE_DATA_AREA # standard protection check and write data + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset = 7 + dris.rw_length = strlen(datatowrite)+1 # include the null + dris.rw_data_ptr = datatowrite + + ret_code = DDProtCheck(&dris, NULL) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + if (dris.sdsn != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return -1 + + # later on in your program you can check the return code again + if (dris.ret_code != 0): + print("Dinkey Dongle protection error") + return -1 + + print("It worked!") + return 0 + +# ************************ ReadBytes ************************************ +# This reads 13 bytes of data from offset 7 in the dongle data area +# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +# In order for the data to be displayed properly by this routine it will need to be text data +cpdef ReadBytes(): + cdef DRIS dris + cdef int ret_code + cdef char datatoread[14] + + # set the DRIS to have random values + cdef unsigned char *drisbuf = &dris + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + # then set the values we want to use + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = READ_DATA_AREA # standard protection check and read data + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset = 7 + dris.rw_length = sizeof(datatoread) + dris.rw_data_ptr = datatoread + + ret_code = DDProtCheck(&dris, NULL) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + if (dris.sdsn != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return -1 + + # later on in your program you can check the return code again + if (dris.ret_code != 0): + print("Dinkey Dongle protection error") + return -1 + + print("It worked! Dinkey Dongle Data area, offset 7 is: " + str(datatoread)) + return 0 + +# ************************** EncryptUserData **************************** +# This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +# It will then do another protection check & decrypt the data +cpdef EncryptUserData(): + cdef DRIS dris + cdef int ret_code + cdef char *mydata = "Hello, World!" + cdef int data_length = strlen(mydata)+1 # include the NULL + + # set the DRIS to have random values + cdef unsigned char *drisbuf = &dris + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + # then set the values we want to use + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = ENCRYPT_USER_DATA # standard protection check and encrypt data + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num = 1 + dris.rw_length = data_length + dris.rw_data_ptr = mydata + + ret_code = DDProtCheck(&dris, NULL) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + # ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + # Now decrypt this (encrypted) data to get the original values + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = DECRYPT_USER_DATA # standard protection check and decrypt data + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num = 1 + dris.rw_length = data_length + dris.rw_data_ptr = mydata + + ret_code = DDProtCheck(&dris, NULL) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + print("It worked! Data decrypted is " + str(mydata)) + return 0 + +# !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! +# In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" +# in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm +# but the code can be modified easily to use the 3 encryption parameters. + +# !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm +# NB DinkeyAdd currently does not generate code for Python so you will have to translate it from C +cdef int MyRWAlgorithm(int a, int b, int c, int d, int e, int f, int g, int h): + return a ^ b ^ c ^ d ^ e ^ f + +# !!!! modify parameters 1,2 and 3 to match those specified in DinkeyAdd +cdef void CryptDRIS(DRIS *dris, unsigned int seed1, unsigned int seed2): + cdef int i, j, k, t + cdef unsigned char bigseed[256] + cdef unsigned char S[256] + cdef unsigned char temp + + for i in range(0, 256, 8): + memcpy(bigseed+i, &seed1, 4) + memcpy(bigseed+i+4, &seed2, 4) + for i in range(256): + S[i] = i + j = 0 + for i in range(256): + j = (j + S[i] + bigseed[i] + 123) % 256 # parameter 1 + temp = S[i] + S[i] = S[j] + S[j] = temp + i = 0 + j = 0 + for k in range(16, sizeof(DRIS)): + i = (i + 1) % 256 + j = (j + S[i] + 212) % 256 # parameter 2 + temp = S[i] + S[i] = S[j] + S[j] = temp + t = (S[i] + S[j] + 97) % 256 # parameter 3 + (dris)[k] ^= S[t] + return + +# !!!! modify parameters 1,2 and 3 to match those specified in DinkeyAdd (if you specified r/w algorithm then no need to modify anything) +cdef void CryptApiData(unsigned char *mydata, int length, unsigned int seed1, unsigned int seed2, int alg_answer): + cdef int i, j, k, t + cdef unsigned char bigseed[256] + cdef unsigned char S[256] + cdef unsigned char temp + + for i in range(0, 256, 8): + memcpy(bigseed+i, &seed1, 4) + memcpy(bigseed+i+4, &seed2, 4) + for i in range(256): + S[i] = i + j = 0 + for i in range(256): + j = (j + S[i] + bigseed[i] + (alg_answer & 0xff)) % 256 # parameter1 + temp = S[i] + S[i] = S[j] + S[j] = temp + i = 0 + j = 0 + for k in range(length): + i = (i + 1) % 256 + j = (j + S[i] + ((alg_answer >> 8) & 0xff)) % 256 # parameter 2 + temp = S[i] + S[i] = S[j] + S[j] = temp + t = (S[i] + S[j] + ((alg_answer >> 16) & 0xff)) % 256 # parameter 3 + (mydata)[k] ^= S[t] + return + +# ************************** ProtCheckEnc *************************************** +# We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file with parameters specified in DinkeyAdd +# NB if you are using the debug module then do not call CryptDRIS as DRIS encryption is not supported. See notes in C readme.txt +cpdef int ProtCheckEnc(): + cdef DRIS dris + cdef int ret_code + + # set the DRIS to have random values + cdef unsigned char *drisbuf = &dris + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + # then set the values we want to use + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = PROTECTION_CHECK # standard protection check + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + CryptDRIS(&dris, dris.seed1, dris.seed2) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL) + + CryptDRIS(&dris, dris.seed1, dris.seed2) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + # later in your code you can check other values in the DRIS... + + if (dris.sdsn != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return -1 + + if (dris.prodcode != MY_PRODCODE): + print("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.") + return -1 + + # later on in your program you can check the return code again + if (dris.ret_code != 0): + print("Dinkey Dongle protection error") + return -1 + + print("It worked!") + return 0 + + +# ************************** ProtCheckWithAlgEnc ****************************** + +# NB for this to work you must program at least "user algorithm" into the dongle +# NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +# sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +# code from DinkeyLook +# We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file with parameters specified in DinkeyAdd +cpdef int ProtCheckWithAlgEnc(): + cdef DRIS dris + cdef int ret_code + + # set the DRIS to have random values + cdef unsigned char *drisbuf = &dris + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + # then set the values we want to use + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = EXECUTE_ALGORITHM # standard protection check and execute algorithm + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number = 1 # execute algorithm 1 (you do not need to specify this field if you are only using Lite models) + + CryptDRIS(&dris, dris.seed1, dris.seed2) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL) + + CryptDRIS(&dris, dris.seed1, dris.seed2) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + if (dris.sdsn != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return -1 + + # later on in your program you can check the return code again + if (dris.ret_code != 0): + print("Dinkey Dongle protection error") + return -1 + + # if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + # !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) != dris.alg_answer): + print("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine") + return -1 + + print("It worked!") + return 0 + + +# ************************** WriteBytesEnc ****************************** +# This writes the string "Hello, World!" to the dongle data area at offset 7 +# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +# We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file with parameters specified in DinkeyAdd. +cpdef int WriteBytesEnc(): + cdef DRIS dris + cdef int ret_code, alg_answer + cdef char *datatowrite = "Hello, World!" + cdef string_length = strlen(datatowrite)+1 # include the null + + # set the DRIS to have random values + cdef unsigned char *drisbuf = &dris + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + # then set the values we want to use + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = WRITE_DATA_AREA # standard protection check and write data + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset = 7 + dris.rw_length = string_length + dris.rw_data_ptr = datatowrite + + # calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm specified in DinkeyAdd + alg_answer = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) + + # encrypt data we want to write. + CryptApiData(datatowrite, string_length, dris.seed1, dris.seed2, alg_answer) + + CryptDRIS(&dris, dris.seed1, dris.seed2) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL) + + CryptDRIS(&dris, dris.seed1, dris.seed2) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + if (dris.sdsn != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return -1 + + # later on in your program you can check the return code again + if (dris.ret_code != 0): + print("Dinkey Dongle protection error") + return -1 + + print("It worked!") + return 0 + +# ************************ ReadBytesEnc ************************************ +# This reads 13 bytes of data from offset 7 in the dongle data area +# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +# In order for the data to be displayed properly by this routine it will need to be text data +# We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file with parameters specified in DinkeyAdd. +cpdef ReadBytesEnc(): + cdef DRIS dris + cdef int ret_code, alg_answer + cdef char datatoread[14] + + # set the DRIS to have random values + cdef unsigned char *drisbuf = &dris + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + # then set the values we want to use + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = READ_DATA_AREA # standard protection check and read data + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.rw_offset = 7 + dris.rw_length = sizeof(datatoread) + dris.rw_data_ptr = datatoread + + # calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm specified in DinkeyAdd + alg_answer = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) + + CryptDRIS(&dris, dris.seed1, dris.seed2) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL) + + CryptDRIS(&dris, dris.seed1, dris.seed2) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + if (dris.sdsn != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return -1 + + # later on in your program you can check the return code again + if (dris.ret_code != 0): + print("Dinkey Dongle protection error") + return -1 + + # decrypt data that was read + CryptApiData(datatoread, sizeof(datatoread), dris.seed1, dris.seed2, alg_answer) + + print("It worked! Dinkey Dongle Data area, offset 7 is: " + str(datatoread)) + return 0 + +# ************************** EncryptUserDataEnc **************************** +# This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +# It will then do another protection check & decrypt the data +# We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +cpdef EncryptUserDataEnc(): + cdef DRIS dris + cdef int ret_code, alg_answer + cdef char *mydata = "Hello, World!" + cdef int data_length = strlen(mydata)+1 # include the NULL + + # set the DRIS to have random values + cdef unsigned char *drisbuf = &dris + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + # then set the values we want to use + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = ENCRYPT_USER_DATA # standard protection check and encrypt data + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num = 1 + dris.rw_length = data_length + dris.rw_data_ptr = mydata + + # calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm specified in DinkeyAdd + alg_answer = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) + + # encrypt data we want to write. + CryptApiData(mydata, data_length, dris.seed1, dris.seed2, alg_answer) + + CryptDRIS(&dris, dris.seed1, dris.seed2) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL) + + CryptDRIS(&dris, dris.seed1, dris.seed2) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + # ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + # Now decrypt this (encrypted) data to get the original values + for i in range(sizeof(DRIS)): + drisbuf[i]= random.randint(0,255) + memcpy(dris.header, b'DRIS', 4) + dris.size = sizeof(DRIS) + dris.function = DECRYPT_USER_DATA # standard protection check and decrypt data + dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.data_crypt_key_num = 1 + dris.rw_length = data_length + dris.rw_data_ptr = mydata + + # calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm specified in DinkeyAdd + alg_answer = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) + + CryptDRIS(&dris, dris.seed1, dris.seed2) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(&dris, NULL) + + CryptDRIS(&dris, dris.seed1, dris.seed2) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + DisplayError(ret_code, dris.ext_err) + return ret_code + + # decrypt data that was pass to us by the API + CryptApiData(mydata, data_length, dris.seed1, dris.seed2, alg_answer) + + print("It worked! Data decrypted is " + str(mydata)) + return 0 + + +#displays messages for the most common errors. You will want to change this for your code +cdef void DisplayError(int ret_code, int extended_error): + cdef char szBuffer[200] + + if (ret_code == 401): + print("Error! No dongles detected!") + elif (ret_code == 403): + print("Error! The dongle detected has a different type to the one specified in DinkeyAdd.") + elif (ret_code == 404): + print("Error! The dongle detected has a different model to those specified in DinkeyAdd.") + elif (ret_code == 409): + print("Error! The dongle detected has not been programmed by DinkeyAdd.") + elif (ret_code == 410): + print("Error! The dongle detected has a different Product Code to the one specified in DinkeyAdd.") + elif (ret_code == 411): + print("Error! The dongle detected does not contain the licence associated with this program.") + elif (ret_code == 413): + print("Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual.") + elif (ret_code == 417): + print("Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.") + elif (ret_code == 423): + print("Error! The number of network users has been exceeded.") + elif (ret_code == 435): + print("Error! DinkeyServer has not been detected on the network.") + elif (ret_code == 922): + print("Error! The Software Key has expired.") + else: + print("An error occurred checking the dongle.\nError: " + str(ret_code) + ", Extended Error: " + str(extended_error)) + return diff --git a/Dinkey Pro 7.6.1/Samples/Python/Cython/setup.py b/Dinkey Pro 7.6.1/Samples/Python/Cython/setup.py new file mode 100644 index 0000000..6112e48 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Python/Cython/setup.py @@ -0,0 +1,16 @@ +from distutils.core import setup +from distutils.extension import Extension +from Cython.Distutils import build_ext + +my_modules = [ + Extension("objtest", ["objtest.pyx"], extra_objects=["dpwin64.obj", "advapi32.lib", "user32.lib"]), +] + +for e in my_modules: + e.cython_directives = {'language_level': "3"} #all are Python-3 + +setup( + name = 'objtest', + cmdclass = {'build_ext': build_ext}, + ext_modules = my_modules +) diff --git a/Dinkey Pro 7.6.1/Samples/Python/README.txt b/Dinkey Pro 7.6.1/Samples/Python/README.txt new file mode 100644 index 0000000..ef743bd --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Python/README.txt @@ -0,0 +1,155 @@ +DllTest - sample code for Python +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This sample code will work with versions of Python 2.6 and higher. + +Note - for Cython Sample code please look in the Cython sub-folder. + +The source files in the project are: + +File name Description +dlltest.py main source code file for Python containing protection functions +dris.py contains useful constants and functions that implement the DRIS structure. + +The sample code works by calling a Python extension that communicates with the dongle. +The Python extension is located in the Modules/Python directory of the SDK. You need to +use the extension that matches the version of Python you are using. For each version of +Python we have extensions for each supported Operating System: + +dpwin32py.pyd - Windows 32-bit +dpwin64py.pyd - Windows 64-bit +dplin32py.so - Linux 32-bit +dplin64py.so - Linux 64-bit +dpmac64py.so - MacOS 64-bit + +Please contact Microcosm if you require a Python module for a different version to those we +provide and we will generate it for you. + +The sample code (dris.py) will automatically work out the OS and bitness and load the +appropriate extension for you. + +The sample code contains 10 functions which demonstrate some of the functionality offered by +the Dinkey Pro/FD system. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You should use DinkeyAdd to protect the Python extension(s) (e.g. dpmac64py.pyd etc...) and +not your Python code directly. Because your program is linked to the protected extension +then it is protected. + +How To Protect The Python Sample Code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use DinkeyAdd (using the API Method of protection) to protect the Dinkey Pro/FD Python +extensions we provide for the version of Python you want to support. (If you know which +Operating Systems you will support then you can just protect these extensions. If you are +not sure then just protect them all). + +For example, if you were just distributing on Windows with 64-bit python 3.x then you should +specify the extension: Modules/Python/x86-amd64/3.x/dpwin64py.pyd as the input pathname and +the location of your python code as the output pathname. Do this for each extension you want +to protect. In our example you will have the following in your sample code folder: + +dlltest.py +dris.py +dpwin64py.pyd [output from DinkeyAdd] + +To test everything is working run the sample code with and without the dongle attached. + +Note - the version of the extension you provide must match the version of Python that is +being run. If not you will get an error. In our experience this is different for each OS: +Windows: gives a sensible error message saying that the version of the extension is different. +Linux: We actually found that any 2.x extension could run on any 2.y Python (similar for 3.x). + Otherwise you get an error about PyInit_dpxxxx or init_dpxxx not being found in the + extension. +Mac: you get the very unhelpful error "PyThreadState_Get: no current thread" + + +How To Add Protection to your Python Code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +1) Modify your python code to check the dongle - you can base your protection check function + on those from dlltest.py in the sample code. The sample code in dlltest.py contains 10 + functions. You will not need to use all these functions in your code. Just use which ever + functions are most appropriate and customise in your own way. The sample code is just a + guide. You can implement the protection in a stronger way using the techniques described in + the "Increasing your Protection" chapter of the manual. + +2) You should import dris.py into your python code. + +3) You will probably want to modify some of the error messages in dris.py with your own. + However, you should still display or log any error codes returned by the protection check + otherwise you will not be able to identify the cause of the error. You can look up error + codes in our knowledge base: www.microcosm.com/kb. + +4) Protect the relevant Python extensions just like in the step above for the sample code. + +5) The protected Python extensions (for your version of Python) should be in the same + directory as the dris module. + +6) Compile your Python code (py files) to pyc files for distribution (see instructions below). + +Algorithms in Python +~~~~~~~~~~~~~~~~~~~~ + +Python implements modulo and integer division differently to other programming languages +like C, when it is applied to negative integers. Also, when you perform arithmetic in Python +it can expand the size of the variable to accommodate the size of the result. When the +algorithms are executed in the dongle they assume the output and all the inputs are signed +integers. To ensure that the algorithms are implemented in Python so that they match the +output of the dongle you need to be aware of the following: + +* use the mod function defined in dlltest.py instead of the operator % +* use the div function defined in dlltest.py instead of the integer operator // +* apply the function dris.make_signed32bit to the value of the algorithm to ensure the output + is a 32-bit signed value + +Level of Security +~~~~~~~~~~~~~~~~~ +You should not distribute your py code as this editable and therefore not secure (an end +user could edit the file and remove all the protection checks). You should distribute the +compiled pyc or pyo files and the protected extensions. These files contain byte-code. +You can do this by compiling your python code like this: + +python -m compile_all -b ./ [.\ for windows] + +This will generate the pyc files in the same directory as the py files (rather than the +__pycache__ directory) and ensure that they will work in a pyc-only distribution. + +However, although byte-code is not readable like source code, it is still possible to use +tools to decompile it back to source code. This will not be as easy to read as your source +code but a hacker might be able to work out what your code is doing, remove the protection +checks and re-compile. Also - it is possible to use tools that modify the byte-code directly. + +One way around this is to write your code (or the most sensitive parts of your code) in Cython +(see Cython sample code) or in pure C (see C/C++ sample code). This is recommended if you have +the skills to do it. Another technique is to use a Python obfuscator so that the bytecode is +much more difficult to understand. + +Another tool you could look at is Nuitka (nuitka.net) which converts Python code to C and then +compiles it. + +Another possible hack is to use the Python interpreter to replace the protection check function +with a function that the hacker has written himself. You can combat this hack by using a user +algorithm or (not quite so good) reading data from the dongle data area. This works because it +means that the hacker would have to work out the algorithm (data) to defeat the protection. +Another solution is write some of your code in pure C and call it from Python. + +Note - you may be tempted to not modify your source code and instead use py2exe and the Shell +Method to protect the resulting executable. However, this is not secure as the "compiled" +executable file is just a loader. Your compiled Python code is also included in the library.zip +file, so someone could just extract these files and use them. Therefore you should not use this +method but to use the API method with the source code instead. You can then use py2exe +(without the Shell method) if you prefer to distribute your software this way. + +This is also the case for any other Python-to-executable software unless it specifically says +that your compiled Python code is encrypted. We have not seen this feature in any Python-to-exe +converter. diff --git a/Dinkey Pro 7.6.1/Samples/Python/dlltest.py b/Dinkey Pro 7.6.1/Samples/Python/dlltest.py new file mode 100644 index 0000000..68c2f4f --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Python/dlltest.py @@ -0,0 +1,574 @@ +import dris # code that communicates with the Dinkey Pro/FD runtime extension +import sys # so we can load the correct extension dependent on OS & bitness + +# The sample code contains 10 functions. You will not need to use all these +# functions in your code. Just use which ever functions are most appropriate +# and customise in your own way. The sample code is just a guide. You should +# implement the protection in a stronger way using the techniques described in +# the "Increasing your Protection" chapter of the manual. +# +# If you are using Dinkey Lite then you can only use 4 functions: +# ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + + +# this file contains 10 protection-check functions. +# ProtCheck a standard protection check +# ProtCheckWithAlg a protection check & executing an Algorithm +# WriteBytes a protection check & write data to the dongle +# ReadBytes a protection check & read data from the dongle +# EncryptUserData a protection check & encrypting data and then decrypting the data + +# these functions are the same as the functions listed above but encrypting all parameters passed to our API +# ProtCheckEnc a standard protection check +# ProtCheckWithAlgEnc a protection check & executing an Algorithm +# WriteBytesEnc a protection check & write data to the dongle +# ReadBytesEnc a protection check & read data from the dongle +# EncryptUserDataEnc a protection check & encrypting data and then decrypting the data + +MY_SDSN = 10101 # !!!! change this value to be the value of your SDSN (demo = 10101) +MY_PRODCODE = "DEMO" # !!!! change this value to be the value of the Product Code in the dongle + +# ************************* our 10 functions ********************************** + +# ************************** ProtCheck *************************************** +def ProtCheck(): + # create the DRIS and allocate the values we want to use + mydris = dris.create() + dris.set_function(mydris, dris.PROTECTION_CHECK) # standard protection check + dris.set_flags(mydris, 0) # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + ret_code = DDProtCheck(mydris) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris)) + return + + # later in your code you can check other values in the DRIS... + if (dris.get_sdsn(mydris) != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return + + if (dris.get_prodcode(mydris) != MY_PRODCODE): + print("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.") + return + + # later on in your program you can check the return code again + if (dris.get_ret_code(mydris) != 0): + print("Dinkey Dongle protection error") + return + + print("It worked!") + return ret_code + +# ************************** ProtCheckWithAlg ****************************** + +# this function should be used instead of % for modulo as python calculates this differently to C for negative numbers +def mod(x, y): + return abs(x)%abs(y)*(1,-1)[x<0] + +# this function should be used instead of // for integer division as python calculates this differently to C for negative numbers +def div(x, y): + if (x >= 0) != (y >= 0) and x % y: + return x // y + 1 + else: + return x // y + +# !!!! You should replace this function with the one generated by the +# "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) +# or from DinkeyLook if you are using a Dinkey Lite dongle. +# (If it does not generate source code for Python you have translate it from C but use the mod function instead of % and div instead of //) +def MyAlgorithm(a, b, c, d, e, f, g, h): + value = a + b + c + d + e + f + g + h # place your algorithm here using mod instead of % and div instead of // + return dris.make_signed32bit(value) # this line always needs to be here to convert the value to a signed 32bit integer + +# NB for this to work you must program at least "user algorithm" into the dongle +# NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +# sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +# code from DinkeyLook +def ProtCheckWithAlg(): + # create the DRIS and allocate the values we want to use + mydris = dris.create() + dris.set_function(mydris, dris.EXECUTE_ALGORITHM) # standard protection check & execute algorithm + dris.set_flags(mydris, 0) # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.set_alg_number(mydris, 1) # execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + # you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.set_var_a(mydris, 1) # sample values + dris.set_var_b(mydris, 2) + dris.set_var_c(mydris, 3) + dris.set_var_d(mydris, 4) + dris.set_var_e(mydris, 5) + dris.set_var_f(mydris, 6) + dris.set_var_g(mydris, 7) + dris.set_var_h(mydris, 8) + + ret_code = DDProtCheck(mydris) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris)) + return + + # later in your code you can check other values in the DRIS... + if (dris.get_sdsn(mydris) != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return + + # later on in your program you can check the return code again + if (dris.get_ret_code(mydris) != 0): + print("Dinkey Dongle protection error") + return + + # if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + # !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if MyAlgorithm(dris.get_var_a(mydris), dris.get_var_b(mydris), dris.get_var_c(mydris), dris.get_var_d(mydris), dris.get_var_e(mydris), \ + dris.get_var_f(mydris), dris.get_var_g(mydris), dris.get_var_h(mydris)) != dris.get_alg_answer(mydris): + print("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine") + return + + print("It worked!") + return ret_code + +# ************************** WriteBytes ****************************** +# This writes the string "Hello, World!" to the dongle data area at offset 7 +# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +def WriteBytes(): + datatowrite = bytearray("Hello, World!", "ascii") + # create the DRIS and allocate the values we want to use + mydris = dris.create() + dris.set_function(mydris, dris.WRITE_DATA_AREA) # standard protection check and write data + dris.set_flags(mydris, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python + dris.set_rw_offset(mydris, 7) + dris.set_rw_length(mydris, len(datatowrite)) + + ret_code = DDProtCheck(mydris, datatowrite) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris)) + return + + # later in your code you can check other values in the DRIS... + if (dris.get_sdsn(mydris) != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return + + # later on in your program you can check the return code again + if (dris.get_ret_code(mydris) != 0): + print("Dinkey Dongle protection error") + return + + print("It worked!") + return ret_code + +# ************************ ReadBytes ************************************ +# This reads 13 bytes of data from offset 7 in the dongle data area +# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +# In order for the data to be displayed properly by this routine it will need to be text data +def ReadBytes(): + datatoread = bytearray(13) + # create the DRIS and allocate the values we want to use + mydris = dris.create() + dris.set_function(mydris, dris.READ_DATA_AREA) # standard protection check and read data + dris.set_flags(mydris, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python + dris.set_rw_offset(mydris, 7) + dris.set_rw_length(mydris, len(datatoread)) + + ret_code = DDProtCheck(mydris, datatoread) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris)) + return + + # later in your code you can check other values in the DRIS... + if (dris.get_sdsn(mydris) != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return + + # later on in your program you can check the return code again + if (dris.get_ret_code(mydris) != 0): + print("Dinkey Dongle protection error") + return + + print("It worked! Dinkey Dongle Data area, offset 7 is " + datatoread.decode("ascii")) + return ret_code + +# ************************** EncryptUserData **************************** +# This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +# It will then do another protection check & decrypt the data +def EncryptUserData(): + data = bytearray("Hello, World!", "ascii") + # create the DRIS and allocate the values we want to use + mydris = dris.create() + dris.set_function(mydris, dris.ENCRYPT_USER_DATA) # standard protection check and encrypt data + dris.set_flags(mydris, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python + dris.set_data_crypt_key_num(mydris, 1) + dris.set_rw_length(mydris, len(data)) + + ret_code = DDProtCheck(mydris, data) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris)) + return + + # ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + # Now decrypt this (encrypted) data to get the original values + mydris2 = dris.create() + dris.set_function(mydris2, dris.DECRYPT_USER_DATA) # standard protection check and decrypt data + dris.set_flags(mydris2, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python + dris.set_data_crypt_key_num(mydris2, 1) + dris.set_rw_length(mydris2, len(data)) + + ret_code = DDProtCheck(mydris2, data) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris2)) + return + + # later in your code you can check other values in the DRIS... + if (dris.get_sdsn(mydris2) != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return + + # later on in your program you can check the return code again + if (dris.get_ret_code(mydris2) != 0): + print("Dinkey Dongle protection error") + return + + print("It worked! Data decrypted is " + data.decode("ascii")) + return ret_code + +# !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! +# In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" +# in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm +# but the code can be modified easily to use the 3 encryption parameters. + +# !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm +# NB DinkeyAdd currently does not generate code for Python so you will have to translate it from C +def MyRWAlgorithm(a, b, c, d, e, f, g, h): + value = a ^ b ^ c ^ d ^ e ^ f + return dris.make_signed32bit(value) + +# !!!! please overwrite this function with the one generated by DinkeyAdd +# It is not generated by DinkeyAdd for Python currently so just modify parameters 1,2 and 3 accordingly +def CryptDRIS(mydris): + bigseed = bytearray(256) + S = bytearray(256) + + for i in range(0, 256, 8): + bigseed[i:i+4] = mydris[8:12] # seed1 + bigseed[i+4:i+8] = mydris[12:16] # seed2 + + for i in range(256): + S[i] = i + + j = 0 + for i in range(256): + j = (j + S[i] + bigseed[i] + 123) % 256 # !!!! parameter 1 + temp = S[i] + S[i] = S[j] + S[j] = temp + + i = 0 + j = 0 + for k in range(16,dris.DRIS_SIZE): + i = (i + 1) % 256 + j = (j + S[i] + 212) % 256 # !!!! parameter 2 + temp = S[i] + S[i] = S[j] + S[j] = temp + t = (S[i] + S[j] + 97) % 256 # !!!! parameter 3 + mydris[k] = mydris[k] ^ S[t] + return + +# !!!! please overwrite this function with the one generated by DinkeyAdd +# It is not generated by DinkeyAdd for Python currently. This is set-up for using r/w parameters +def CryptApiData(data, mydris, length, alg_answer): + bigseed = bytearray(256) + S = bytearray(256) + + for i in range(0, 256, 8): + bigseed[i:i+4] = mydris[8:12] # seed1 + bigseed[i+4:i+8] = mydris[12:16] # seed2 + + for i in range(256): + S[i] = i + + j = 0 + for i in range(256): + j = (j + S[i] + bigseed[i] + (alg_answer & 0xff)) % 256 # parameter 1 + temp = S[i] + S[i] = S[j] + S[j] = temp + + i = 0 + j = 0 + for k in range(length): + i = (i + 1) % 256 + j = (j + S[i] + ((alg_answer >> 8) & 0xff)) % 256 # parameter 2 + temp = S[i] + S[i] = S[j] + S[j] = temp + t = (S[i] + S[j] + ((alg_answer >> 16) & 0xff)) % 256 # parameter 3 + data[k] = data[k] ^ S[t] + return + +# ************************* ProtCheckEnc ******************************* +def ProtCheckEnc(): + # We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. + mydris = dris.create() + dris.set_function(mydris, dris.PROTECTION_CHECK) # standard protection check + dris.set_flags(mydris, 0) # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + CryptDRIS(mydris) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris) + + CryptDRIS(mydris) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris)) + return + + # later in your code you can check other values in the DRIS... + if (dris.get_sdsn(mydris) != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return + + if (dris.get_prodcode(mydris) != MY_PRODCODE): + print("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.") + return + + # later on in your program you can check the return code again + if (dris.get_ret_code(mydris) != 0): + print("Dinkey Dongle protection error") + return + + print("It worked!") + return ret_code + +# ************************ ProtCheckWithAlgEnc *********************** +# NB for this to work you must program at least "user algorithm" into the dongle +# NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +# sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +# code from DinkeyLook +# We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +def ProtCheckWithAlgEnc(): + # create the DRIS and allocate the values we want to use + mydris = dris.create() + dris.set_function(mydris, dris.EXECUTE_ALGORITHM) # standard protection check & execute algorithm + dris.set_flags(mydris, 0) # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.set_alg_number(mydris, 1) # execute algorithm 1 (you do not need to specify this field if you are only using Lite models). + # you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.set_var_a(mydris, 1) # sample values + dris.set_var_b(mydris, 2) + dris.set_var_c(mydris, 3) + dris.set_var_d(mydris, 4) + dris.set_var_e(mydris, 5) + dris.set_var_f(mydris, 6) + dris.set_var_g(mydris, 7) + dris.set_var_h(mydris, 8) + + CryptDRIS(mydris) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris) + + CryptDRIS(mydris) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris)) + return + + # later in your code you can check other values in the DRIS... + if (dris.get_sdsn(mydris) != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return + + # later on in your program you can check the return code again + if (dris.get_ret_code(mydris) != 0): + print("Dinkey Dongle protection error") + return + + # if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + # !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + if MyAlgorithm(dris.get_var_a(mydris), dris.get_var_b(mydris), dris.get_var_c(mydris), dris.get_var_d(mydris), dris.get_var_e(mydris), \ + dris.get_var_f(mydris), dris.get_var_g(mydris), dris.get_var_h(mydris)) != dris.get_alg_answer(mydris): + print("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine") + return + + print("It worked!") + return ret_code + +# ************************** WriteBytesEnc ****************************** +# This writes the string "Hello, World!" to the dongle data area at offset 7 +# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +# We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +def WriteBytesEnc(): + datatowrite = bytearray("Hello, World!", "ascii") + # create the DRIS and allocate the values we want to use + mydris = dris.create() + dris.set_function(mydris, dris.WRITE_DATA_AREA) # standard protection check and write data + dris.set_flags(mydris, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python + dris.set_rw_offset(mydris, 7) + dris.set_rw_length(mydris, len(datatowrite)) + + # calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.get_var_a(mydris), dris.get_var_b(mydris), dris.get_var_c(mydris), dris.get_var_d(mydris), \ + dris.get_var_e(mydris), dris.get_var_f(mydris), dris.get_var_g(mydris), dris.get_var_h(mydris)) + + # encrypt data we want to write. + CryptApiData(datatowrite, mydris, len(datatowrite), alg_ans) + + CryptDRIS(mydris) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, datatowrite) + + CryptDRIS(mydris) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris)) + return + + # later in your code you can check other values in the DRIS... + if (dris.get_sdsn(mydris) != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return + + # later on in your program you can check the return code again + if (dris.get_ret_code(mydris) != 0): + print("Dinkey Dongle protection error") + return + + print("It worked!") + return ret_code + +# ************************ ReadBytesEnc ************************************ +# This reads 13 bytes of data from offset 7 in the dongle data area +# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +# In order for the data to be displayed properly by this routine it will need to be text data +# We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +def ReadBytesEnc(): + datatoread = bytearray(13) + # create the DRIS and allocate the values we want to use + mydris = dris.create() + dris.set_function(mydris, dris.READ_DATA_AREA) # standard protection check and read data + dris.set_flags(mydris, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python + dris.set_rw_offset(mydris, 7) + dris.set_rw_length(mydris, len(datatoread)) + + # calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.get_var_a(mydris), dris.get_var_b(mydris), dris.get_var_c(mydris), dris.get_var_d(mydris), \ + dris.get_var_e(mydris), dris.get_var_f(mydris), dris.get_var_g(mydris), dris.get_var_h(mydris)) + + CryptDRIS(mydris) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, datatoread) + + CryptDRIS(mydris) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris)) + return + + # later in your code you can check other values in the DRIS... + if (dris.get_sdsn(mydris) != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return + + # later on in your program you can check the return code again + if (dris.get_ret_code(mydris) != 0): + print("Dinkey Dongle protection error") + return + + # decrypt data that was read + CryptApiData(datatoread, mydris, len(datatoread), alg_ans) + print("It worked! Dinkey Dongle Data area, offset 7 is " + datatoread.decode("ascii")) + return ret_code + +# ************************** EncryptUserDataEnc **************************** +# This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +# It will then do another protection check & decrypt the data +# We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +def EncryptUserDataEnc(): + data = bytearray("Hello, World!", "ascii") + # create the DRIS and allocate the values we want to use + mydris = dris.create() + dris.set_function(mydris, dris.ENCRYPT_USER_DATA) # standard protection check and encrypt data + dris.set_flags(mydris, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python + dris.set_data_crypt_key_num(mydris, 1) + dris.set_rw_length(mydris, len(data)) + + # calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.get_var_a(mydris), dris.get_var_b(mydris), dris.get_var_c(mydris), dris.get_var_d(mydris), \ + dris.get_var_e(mydris), dris.get_var_f(mydris), dris.get_var_g(mydris), dris.get_var_h(mydris)) + + # encrypt data we want to pass. + CryptApiData(data, mydris, len(data), alg_ans) + + CryptDRIS(mydris) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris, data) + + CryptDRIS(mydris) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris)) + return + + # ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + # Now decrypt this (encrypted) data to get the original values + mydris2 = dris.create() + dris.set_function(mydris2, dris.DECRYPT_USER_DATA) # standard protection check and decrypt data + dris.set_flags(mydris2, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python + dris.set_data_crypt_key_num(mydris2, 1) + dris.set_rw_length(mydris2, len(data)) + + CryptDRIS(mydris2) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(mydris2, data) + + CryptDRIS(mydris2) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + if (ret_code != 0): + dris.DisplayError(ret_code, dris.get_ext_err(mydris2)) + return + + # later in your code you can check other values in the DRIS... + if (dris.get_sdsn(mydris2) != MY_SDSN): + print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + return + + # later on in your program you can check the return code again + if (dris.get_ret_code(mydris2) != 0): + print("Dinkey Dongle protection error") + return + + alg_ans = MyRWAlgorithm(dris.get_var_a(mydris2), dris.get_var_b(mydris2), dris.get_var_c(mydris2), dris.get_var_d(mydris2), \ + dris.get_var_e(mydris2), dris.get_var_f(mydris2), dris.get_var_g(mydris2), dris.get_var_h(mydris2)) + + # decrypt data passed to us by the API + CryptApiData(data, mydris2, len(data), alg_ans) + + print("It worked! Data decrypted is " + data.decode("ascii")) + return ret_code + +# entry point +if __name__ == "__main__": + # load the correct extension dependent on the OS and bitness of Python + if sys.platform == 'win32': + if sys.maxsize > 2**32: + from dpwin64py import DDProtCheck + else: + from dpwin32py import DDProtCheck + elif 'linux' in sys.platform: + if sys.maxsize > 2**32: + from dplin64py import DDProtCheck + else: + from dplin32py import DDProtCheck + elif sys.platform == 'darwin': + if sys.maxsize > 2**32: + from dpmac64py import DDProtCheck + else: + from dpmac32py import DDProtCheck + + # choose the protection check function of your choice here. We have chosen the basic protection check. + ProtCheck() diff --git a/Dinkey Pro 7.6.1/Samples/Python/dris.py b/Dinkey Pro 7.6.1/Samples/Python/dris.py new file mode 100644 index 0000000..a904565 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Python/dris.py @@ -0,0 +1,254 @@ +import random +import sys + +#define constants + +#these constants depend on the bitness of the OS - the DRIS is 4 bytes bigger for 64-bit code +if sys.maxsize > 2**32: + DRIS_SIZE = 564 # DRIS size is bigger for 64-bit (it has an 8-byte pointer) + python64 = 4 # so we can adjust structure offsets for 64-bit python +else: + DRIS_SIZE = 560 + python64 = 0 + +#function values +PROTECTION_CHECK = 1 # checks for dongle, check program params... +EXECUTE_ALGORITHM = 2 # protection check + calculate answer for specified algorithm with specified inputs +WRITE_DATA_AREA = 3 # protection check + writes dongle data area +READ_DATA_AREA = 4 # protection check + reads dongle data area +ENCRYPT_USER_DATA = 5 # protection check + the dongle will encrypt user data +DECRYPT_USER_DATA = 6 # protection check + the dongle will decrypt user data +FAST_PRESENCE_CHECK = 7 # checks for the presence of the correct dongle only with minimal security, no flags allowed. +STOP_NET_USER = 8 # stops a network user (a protection check is NOT performed) + +# flags - can specify as many as you like +DEC_ONE_EXEC = 1 # decrement execs by 1 +DEC_MANY_EXECS = 2 # decrement execs by number specified in execs_decrement +START_NET_USER = 4 # starts a network user +USE_FUNCTION_ARGUMENT = 16 # use the extra argument in the function for pointers +CHECK_LOCAL_FIRST = 32 # always look in local ports before looking in network ports +CHECK_NETWORK_FIRST = 64 # always look on the network before looking in local ports +USE_ALT_LICENCE_NAME = 128 # use name specified in alt_licence_name instead of the default one +DONT_SET_MAXDAYS_EXPIRY = 256 # if the max days expiry date has not been calculated then do not do it this time +MATCH_DONGLE_NUMBER = 512 # restrict the search to match the dongle number specified in the DRIS +DONT_RETURN_FD_DRIVE = 1024 # if an FD dongle has been detected then don't return the flash drive/mount name + +# set 4 bytes in our DRIS byte array from an integer +def set4bytes(data, offset, value): + data[offset] = value & 0xff + data[offset+1] = (value >> 8) & 0xff + data[offset+2] = (value >> 16) & 0xff + data[offset+3] = (value >> 24) & 0xff + return + +# trunctates a value to 32-bit and converts to a signed integer +def make_signed32bit(value): + value = value & 0xffffffff + if (value > (2**31)): + value = value - (2**32) + return value + +# get 4 bytes in our DRIS byte array and convert to an unsigned integer +# this returns an unsigned value, which is useful for dongle number, features, etc... +def get4bytes(data, offset): + return (data[offset] + data[offset+1]*0x100 + data[offset+2]*0x10000 + data[offset+3]*0x1000000) + +# this returns a signed value, which is useful for alg_answer, expiry day... +def get4bytes_signed(data, offset): + value = data[offset] + data[offset+1]*0x100 + data[offset+2]*0x10000 + data[offset+3]*0x1000000 + if (value > (2**31)): + value = value - (2**32) + return value + +# create the DRIS structure as a byte array, populate it with random values, initialise the header and size fields +def create(): + dris = bytearray(DRIS_SIZE) + random.seed() + for n in range(DRIS_SIZE): + dris[n] = random.randint(0, 255) + dris[0] = ord('D') + dris[1] = ord('R') + dris[2] = ord('I') + dris[3] = ord('S') + set4bytes(dris, 4, DRIS_SIZE) + return dris + +# these functions set various values in the DRIS +def set_function(dris, value): + set4bytes(dris, 16, value) + +def set_flags(dris, value): + set4bytes(dris, 20, value) + +def set_execs_decrement(dris, value): + set4bytes(dris, 24, value) + +def set_data_crypt_key_num(dris, value): + set4bytes(dris, 28, value) + +def set_rw_offset(dris, value): + set4bytes(dris, 32, value) + +def set_rw_length(dris, value): + set4bytes(dris, 36, value) + +def set_alt_licence_name(dris, licence_name): + dris[44+python64:44+python64+len(licence_name)] = licence_name + dris[44+python64+len(licence_name)] = 0 # null-terminate the string + +def set_var_a(dris, value): + set4bytes(dris, 300+python64, value) + +def set_var_b(dris, value): + set4bytes(dris, 304+python64, value) + +def set_var_c(dris, value): + set4bytes(dris, 308+python64, value) + +def set_var_d(dris, value): + set4bytes(dris, 312+python64, value) + +def set_var_e(dris, value): + set4bytes(dris, 316+python64, value) + +def set_var_f(dris, value): + set4bytes(dris, 320+python64, value) + +def set_var_g(dris, value): + set4bytes(dris, 324+python64, value) + +def set_var_h(dris, value): + set4bytes(dris, 328+python64, value) + +def set_alg_number(dris, value): + set4bytes(dris, 332+python64, value) + +# these functions get values from the DRIS +def get_ret_code(dris): + return get4bytes(dris, 336+python64) + +def get_ext_err(dris): + return get4bytes(dris, 340+python64) + +def get_type(dris): + return get4bytes(dris, 344+python64) + +def get_model(dris): + return get4bytes(dris, 348+python64) + +def get_sdsn(dris): + return get4bytes(dris, 352+python64) + +def get_prodcode(dris): + for n in range(356+python64,368+python64): + if dris[n] == 0: + break + return dris[356+python64:n].decode("utf-8") + +def get_dongle_number(dris): + return get4bytes(dris, 368+python64) + +def get_update_number(dris): + return get4bytes(dris, 372+python64) + +def get_data_area_size(dris): + return get4bytes(dris, 376+python64) + +def get_max_alg_num(dris): + return get4bytes(dris, 380+python64) + +def get_execs(dris): + return get4bytes(dris, 384+python64) + +def get_exp_day(dris): + return get4bytes_signed(dris, 388+python64) + +def get_exp_month(dris): + return get4bytes_signed(dris, 392+python64) + +def get_exp_year(dris): + return get4bytes_signed(dris, 396+python64) + +def get_features(dris): + return get4bytes(dris, 400+python64) + +def get_net_users(dris): + return get4bytes(dris, 404+python64) + +def get_alg_answer(dris): + return get4bytes_signed(dris, 408+python64) + +def get_fd_capacity(dris): + return get4bytes(dris, 412+python64) + +def get_fd_drive(dris): + for n in range(416+python64,544+python64): + if dris[n] == 0: + break + return dris[416+python64:n].decode("utf-8") + +def get_swkey_type(dris): + return get4bytes(dris, 544+python64) + +def get_swkey_exp_day(dris): + return get4bytes(dris, 548+python64) + +def get_swkey_exp_month(dris): + return get4bytes(dris, 552+python64) + +def get_swkey_exp_year(dris): + return get4bytes(dris, 556+python64) + +# you may also want to retrieve var_a values that you already entered into the dris! +def get_var_a(dris): + return get4bytes_signed(dris, 300+python64) + +def get_var_b(dris): + return get4bytes_signed(dris, 304+python64) + +def get_var_c(dris): + return get4bytes_signed(dris, 308+python64) + +def get_var_d(dris): + return get4bytes_signed(dris, 312+python64) + +def get_var_e(dris): + return get4bytes_signed(dris, 316+python64) + +def get_var_f(dris): + return get4bytes_signed(dris, 320+python64) + +def get_var_g(dris): + return get4bytes_signed(dris, 324+python64) + +def get_var_h(dris): + return get4bytes_signed(dris, 328+python64) + +# function to display the most common error codes. +# You will want to change this with your own error messages +def DisplayError(ret_code, extended_error): + if (ret_code == 401): + print("Error! No dongles detected!") + elif (ret_code == 403): + print("Error! The dongle detected has a different type to the one specified in DinkeyAdd.") + elif (ret_code == 404): + print("Error! The dongle detected has a different model to those specified in DinkeyAdd.") + elif (ret_code == 409): + print("Error! The dongle detected has not been programmed by DinkeyAdd.") + elif (ret_code == 410): + print("Error! The dongle detected has a different Product Code to the one specified in DinkeyAdd.") + elif (ret_code == 411): + print("Error! The dongle detected does not contain the licence associated with this program.") + elif (ret_code == 413): + print("Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual.") + elif (ret_code == 417): + print("Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.") + elif (ret_code == 423): + print("Error! The number of network users has been exceeded.") + elif (ret_code == 435): + print("Error! DinkeyServer has not been detected on the network.") + elif (ret_code == 922): + print("Error! The Software Key has expired.") + else: + print("An error occurred checking the dongle.\nError: " + str(ret_code) + ", Extended Error: " + str(extended_error)) + return diff --git a/Dinkey Pro 7.6.1/Samples/RealBasic/DllTest.rbp b/Dinkey Pro 7.6.1/Samples/RealBasic/DllTest.rbp new file mode 100644 index 0000000..ee09198 Binary files /dev/null and b/Dinkey Pro 7.6.1/Samples/RealBasic/DllTest.rbp differ diff --git a/Dinkey Pro 7.6.1/Samples/RealBasic/README.txt b/Dinkey Pro 7.6.1/Samples/RealBasic/README.txt new file mode 100644 index 0000000..c7fbf58 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/RealBasic/README.txt @@ -0,0 +1,64 @@ +DllTest - Runtime sample code in RealBasic +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in RealBasic 2011 but will also work in later versions +and also in Xojo (tested on Xojo 2013r4.1). It can also work on previous versions +of RealBasic (but if using versions previous to 2005 then see note about use of Nil). +It is a console program so for a Windows application you would need to change "Print" +statements for "MsgBox". + +The Module1 module contains the DRIS structure definition and some useful functions. +The main sample code contains the functions: + +DDProtCheck +DDProtCheckWithAlg +WriteBytes +ReadBytes +EncryptUserData + +There are also encrypted versions of these functions (where the parameters passed +to and from our API are encrypted for greater security): + +DDProtCheckEnc, DDProtCheckWithAlgEnc, WriteBytesEnc, ReadBytesEnc, EncryptUserDataEnc + +These functions also use some smaller functions: +CryptDRIS, CryptAPIData, MyAlgorithm, MyRWAlgorithm + +You will not need to use all these functions in your code. Just use which ever functions +are most appropriate and customise in your own way. The sample code is just a guide. +You should implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN constant to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. + +Note - you should protect dpwin32.dll and not your program. Because your program +is linked to the DLL it is protected. This protected dll should be placed in the +sample folder as the compiled program. + +You can rename the runtime module (e.g. dpwin32.dll) if you want but you must also +change this name for every occurance in the MyDDProtCheck function in Module1. + +You can also use the protected program on MacOS X and Linux by protecting the +appropriate runtime modules (i.e. dpmac32.dylib and dplin32.so). If you do this +you will probably want to protect all the runtime modules to a single licence. + +Due to our anti-debug code it may be impossible to debug your code once it has been +protected (we found that the debugger often crashed anyway even without our anti-debug +code)! + +Note for version of RealBasic previous to 2005 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The "Nil" value is not defined for these earlier versions and so you should define a +MemoryBlock object, initialise it to something and pass that instead (it doesn't get used +so as long as it compiles it is OK). diff --git a/Dinkey Pro 7.6.1/Samples/VERY IMPORTANT README.txt b/Dinkey Pro 7.6.1/Samples/VERY IMPORTANT README.txt new file mode 100644 index 0000000..ad1899e --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/VERY IMPORTANT README.txt @@ -0,0 +1,13 @@ +Notes on How to use the Sample Code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Always read the "readme" file in the project you use. It contains important +information about the programming language you are using and how to integrate +the sample project with the Dinkey Pro SDK. + +Instead of creating projects for every single version of an IDE, we only create +a new project when an older project can no longer be updated by the IDE. For +example, for Windows C we have a Visual Studio 5 project and a Visual Studio 2008 +project. The VS 5 project will work for VS 5 up to VS 2005 and the Visual Studio +2008 project will work for VS2008 and higher. In these cases VS will update the +project to the latest version. diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyAdd/AssemblyInfo.vb b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyAdd/AssemblyInfo.vb new file mode 100644 index 0000000..41bb2c5 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyAdd/AssemblyInfo.vb @@ -0,0 +1,31 @@ +Imports System.Reflection +Imports System.Runtime.InteropServices + +' General Information about an assembly is controlled through the following +' set of attributes. Change these attribute values to modify the information +' associated with an assembly. + +' Review the values of the assembly attributes + + + + + + + + + +'The following GUID is for the ID of the typelib if this project is exposed to COM + + +' Version information for an assembly consists of the following four values: +' +' Major Version +' Minor Version +' Build Number +' Revision +' +' You can specify all the values or you can default the Build and Revision Numbers +' by using the '*' as shown below: + + diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyAdd/Form1.resx b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyAdd/Form1.resx new file mode 100644 index 0000000..feb5499 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyAdd/Form1.resx @@ -0,0 +1,283 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Assembly + + + 8, 8 + + + True + + + False + + + True + + + Assembly + + + Assembly + + + False + + + Assembly + + + False + + + Assembly + + + Assembly + + + Assembly + + + False + + + Assembly + + + False + + + Assembly + + + Assembly + + + Assembly + + + False + + + Assembly + + + False + + + Assembly + + + Assembly + + + False + + + Assembly + + + Assembly + + + Assembly + + + False + + + Assembly + + + False + + + Assembly + + + Assembly + + + False + + + Assembly + + + Assembly + + + False + + + Assembly + + + Assembly + + + False + + + Assembly + + + Assembly + + + False + + + Assembly + + + Assembly + + + Assembly + + + Assembly + + + False + + + False + + + Assembly + + + Assembly + + + False + + + (Default) + + + False + + + False + + + 8, 8 + + + True + + + 80 + + + True + + + Assembly + + + Form1 + + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyAdd/Form1.vb b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyAdd/Form1.vb new file mode 100644 index 0000000..c70a0ff --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyAdd/Form1.vb @@ -0,0 +1,485 @@ +' !! We strongly recommend that you read the "readme.txt" file in the sample code folder. +' !! It contains important instructions on how to use the sample code + +Imports System.Runtime.InteropServices ' so we can marshall our structures + +Public Class Form1 + Inherits System.Windows.Forms.Form + + Public Const AppName As String = "dapfTest" +#Region " Windows Form Designer generated code " + + Public Sub New() + MyBase.New() + + 'This call is required by the Windows Form Designer. + InitializeComponent() + + 'Add any initialization after the InitializeComponent() call + + End Sub + + 'Form overrides dispose to clean up the component list. + Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) + If disposing Then + If Not (components Is Nothing) Then + components.Dispose() + End If + End If + MyBase.Dispose(disposing) + End Sub + + 'Required by the Windows Form Designer + Private components As System.ComponentModel.IContainer + + 'NOTE: The following procedure is required by the Windows Form Designer + 'It can be modified using the Windows Form Designer. + 'Do not modify it using the code editor. + Friend WithEvents groupBox2 As System.Windows.Forms.GroupBox + Friend WithEvents label6 As System.Windows.Forms.Label + Friend WithEvents maxDaysText As System.Windows.Forms.TextBox + Friend WithEvents demoSoftwareKey As System.Windows.Forms.Button + Friend WithEvents groupBox1 As System.Windows.Forms.GroupBox + Friend WithEvents expyearText As System.Windows.Forms.TextBox + Friend WithEvents label5 As System.Windows.Forms.Label + Friend WithEvents expmonthText As System.Windows.Forms.TextBox + Friend WithEvents label4 As System.Windows.Forms.Label + Friend WithEvents expdayText As System.Windows.Forms.TextBox + Friend WithEvents label3 As System.Windows.Forms.Label + Friend WithEvents label2 As System.Windows.Forms.Label + Friend WithEvents machineIDText As System.Windows.Forms.TextBox + Friend WithEvents tempSoftwareKey As System.Windows.Forms.Button + Friend WithEvents encryptShellData As System.Windows.Forms.Button + Friend WithEvents lockSoftware As System.Windows.Forms.Button + Friend WithEvents programDongleMod As System.Windows.Forms.Button + Friend WithEvents programDongle As System.Windows.Forms.Button + Friend WithEvents dapfFile As System.Windows.Forms.TextBox + Friend WithEvents label1 As System.Windows.Forms.Label + Private Sub InitializeComponent() + Me.groupBox2 = New System.Windows.Forms.GroupBox + Me.label6 = New System.Windows.Forms.Label + Me.maxDaysText = New System.Windows.Forms.TextBox + Me.demoSoftwareKey = New System.Windows.Forms.Button + Me.groupBox1 = New System.Windows.Forms.GroupBox + Me.expyearText = New System.Windows.Forms.TextBox + Me.label5 = New System.Windows.Forms.Label + Me.expmonthText = New System.Windows.Forms.TextBox + Me.label4 = New System.Windows.Forms.Label + Me.expdayText = New System.Windows.Forms.TextBox + Me.label3 = New System.Windows.Forms.Label + Me.label2 = New System.Windows.Forms.Label + Me.machineIDText = New System.Windows.Forms.TextBox + Me.tempSoftwareKey = New System.Windows.Forms.Button + Me.encryptShellData = New System.Windows.Forms.Button + Me.lockSoftware = New System.Windows.Forms.Button + Me.programDongleMod = New System.Windows.Forms.Button + Me.programDongle = New System.Windows.Forms.Button + Me.dapfFile = New System.Windows.Forms.TextBox + Me.label1 = New System.Windows.Forms.Label + Me.groupBox1.SuspendLayout() + Me.SuspendLayout() + ' + 'groupBox2 + ' + Me.groupBox2.Controls.Add(Me.label6) + Me.groupBox2.Controls.Add(Me.maxDaysText) + Me.groupBox2.Controls.Add(Me.demoSoftwareKey) + Me.groupBox2.Location = New System.Drawing.Point(16, 390) + Me.groupBox2.Name = "groupBox2" + Me.groupBox2.Size = New System.Drawing.Size(336, 96) + Me.groupBox2.TabIndex = 17 + Me.groupBox2.TabStop = False + Me.groupBox2.Text = "Demo Software Key" + ' + 'demoSoftwareKey + ' + Me.demoSoftwareKey.Location = New System.Drawing.Point(64, 56) + Me.demoSoftwareKey.Name = "demoSoftwareKey" + Me.demoSoftwareKey.Size = New System.Drawing.Size(208, 23) + Me.demoSoftwareKey.TabIndex = 15 + Me.demoSoftwareKey.Text = "Create Demo Template" + ' + 'label6 + ' + Me.label6.Location = New System.Drawing.Point(24, 24) + Me.label6.Name = "label6" + Me.label6.Size = New System.Drawing.Size(100, 20) + Me.label6.TabIndex = 18 + Me.label6.Text = "Max Days:" + Me.label6.TextAlign = System.Drawing.ContentAlignment.MiddleLeft + ' + 'maxDaysText + ' + Me.maxDaysText.Location = New System.Drawing.Point(128, 24) + Me.maxDaysText.Name = "maxDaysText" + Me.maxDaysText.Size = New System.Drawing.Size(184, 20) + Me.maxDaysText.TabIndex = 19 + Me.maxDaysText.Text = "" + ' + 'groupBox1 + ' + Me.groupBox1.Controls.Add(Me.expyearText) + Me.groupBox1.Controls.Add(Me.label5) + Me.groupBox1.Controls.Add(Me.expmonthText) + Me.groupBox1.Controls.Add(Me.label4) + Me.groupBox1.Controls.Add(Me.expdayText) + Me.groupBox1.Controls.Add(Me.label3) + Me.groupBox1.Controls.Add(Me.label2) + Me.groupBox1.Controls.Add(Me.machineIDText) + Me.groupBox1.Controls.Add(Me.tempSoftwareKey) + Me.groupBox1.Location = New System.Drawing.Point(16, 251) + Me.groupBox1.Name = "groupBox1" + Me.groupBox1.Size = New System.Drawing.Size(336, 128) + Me.groupBox1.TabIndex = 7 + Me.groupBox1.TabStop = False + Me.groupBox1.Text = "Temporary Software Key" + ' + 'tempSoftwareKey + ' + Me.tempSoftwareKey.Location = New System.Drawing.Point(64, 88) + Me.tempSoftwareKey.Name = "tempSoftwareKey" + Me.tempSoftwareKey.Size = New System.Drawing.Size(208, 23) + Me.tempSoftwareKey.TabIndex = 16 + Me.tempSoftwareKey.Text = "Create Software Key" + ' + 'expyearText + ' + Me.expyearText.Location = New System.Drawing.Point(240, 56) + Me.expyearText.Name = "expyearText" + Me.expyearText.Size = New System.Drawing.Size(32, 20) + Me.expyearText.TabIndex = 15 + Me.expyearText.Text = "yyyy" + ' + 'label5 + ' + Me.label5.Location = New System.Drawing.Point(224, 56) + Me.label5.Name = "label5" + Me.label5.Size = New System.Drawing.Size(8, 20) + Me.label5.TabIndex = 14 + Me.label5.Text = "/" + Me.label5.TextAlign = System.Drawing.ContentAlignment.MiddleLeft + ' + 'expmonthText + ' + Me.expmonthText.Location = New System.Drawing.Point(184, 56) + Me.expmonthText.Name = "expmonthText" + Me.expmonthText.Size = New System.Drawing.Size(32, 20) + Me.expmonthText.TabIndex = 13 + Me.expmonthText.Text = "mm" + ' + 'label4 + ' + Me.label4.Location = New System.Drawing.Point(168, 56) + Me.label4.Name = "label4" + Me.label4.Size = New System.Drawing.Size(8, 20) + Me.label4.TabIndex = 12 + Me.label4.Text = "/" + Me.label4.TextAlign = System.Drawing.ContentAlignment.MiddleLeft + ' + 'expdayText + ' + Me.expdayText.Location = New System.Drawing.Point(128, 56) + Me.expdayText.Name = "expdayText" + Me.expdayText.Size = New System.Drawing.Size(32, 20) + Me.expdayText.TabIndex = 11 + Me.expdayText.Text = "dd" + ' + 'label3 + ' + Me.label3.Location = New System.Drawing.Point(24, 56) + Me.label3.Name = "label3" + Me.label3.Size = New System.Drawing.Size(100, 20) + Me.label3.TabIndex = 10 + Me.label3.Text = "Expiry Date:" + Me.label3.TextAlign = System.Drawing.ContentAlignment.MiddleLeft + ' + 'label2 + ' + Me.label2.Location = New System.Drawing.Point(24, 24) + Me.label2.Name = "label2" + Me.label2.Size = New System.Drawing.Size(100, 20) + Me.label2.TabIndex = 8 + Me.label2.Text = "Machine ID:" + Me.label2.TextAlign = System.Drawing.ContentAlignment.MiddleLeft + ' + 'machineIDText + ' + Me.machineIDText.Location = New System.Drawing.Point(128, 24) + Me.machineIDText.Name = "machineIDText" + Me.machineIDText.Size = New System.Drawing.Size(184, 20) + Me.machineIDText.TabIndex = 9 + Me.machineIDText.Text = "" + ' + 'encryptShellData + ' + Me.encryptShellData.Location = New System.Drawing.Point(80, 203) + Me.encryptShellData.Name = "encryptShellData" + Me.encryptShellData.Size = New System.Drawing.Size(208, 23) + Me.encryptShellData.TabIndex = 6 + Me.encryptShellData.Text = "Encrypt Shell Data Files" + ' + 'lockSoftware + ' + Me.lockSoftware.Location = New System.Drawing.Point(80, 163) + Me.lockSoftware.Name = "lockSoftware" + Me.lockSoftware.Size = New System.Drawing.Size(208, 23) + Me.lockSoftware.TabIndex = 5 + Me.lockSoftware.Text = "Lock Software" + ' + 'programDongleMod + ' + Me.programDongleMod.Location = New System.Drawing.Point(80, 123) + Me.programDongleMod.Name = "programDongleMod" + Me.programDongleMod.Size = New System.Drawing.Size(208, 23) + Me.programDongleMod.TabIndex = 4 + Me.programDongleMod.Text = "Program Dongle with modification" + ' + 'programDongle + ' + Me.programDongle.Location = New System.Drawing.Point(80, 83) + Me.programDongle.Name = "programDongle" + Me.programDongle.Size = New System.Drawing.Size(208, 23) + Me.programDongle.TabIndex = 3 + Me.programDongle.Text = "Program Dongle" + ' + 'dapfFile + ' + Me.dapfFile.Location = New System.Drawing.Point(16, 35) + Me.dapfFile.Name = "dapfFile" + Me.dapfFile.Size = New System.Drawing.Size(344, 20) + Me.dapfFile.TabIndex = 2 + Me.dapfFile.Text = "" + ' + 'label1 + ' + Me.label1.Location = New System.Drawing.Point(16, 19) + Me.label1.Name = "label1" + Me.label1.Size = New System.Drawing.Size(416, 16) + Me.label1.TabIndex = 1 + Me.label1.Text = "Full path of dapf file:" + ' + 'Form1 + ' + Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13) + Me.ClientSize = New System.Drawing.Size(376, 496) + Me.Controls.Add(Me.groupBox2) + Me.Controls.Add(Me.groupBox1) + Me.Controls.Add(Me.encryptShellData) + Me.Controls.Add(Me.lockSoftware) + Me.Controls.Add(Me.programDongleMod) + Me.Controls.Add(Me.programDongle) + Me.Controls.Add(Me.dapfFile) + Me.Controls.Add(Me.label1) + Me.Name = "Form1" + Me.Text = "Form1" + Me.groupBox1.ResumeLayout(False) + Me.ResumeLayout(False) + + End Sub + +#End Region + + ' The sample code contains 5 functions. You will not need to use all these functions in your code. + ' Just use which ever functions are most appropriate and customise in your own way. The sample code + ' is just a guide. + ' + ' There are two methods to loading a DAPF file. These are shown in the first two functions + ' programDongle_Click and programDongleMod_Click: + ' + ' programDongle_Click: we load the DAPF file from disk and get a handle and use it "as is" using the API + ' call LoadDAPFFromFile. You can make some limited changes to overwrite the default + ' behaviour by using API flags. + ' + ' programDongleMod_Click: we load the DAPF file from disk and load into structures. We can then modify the + ' DAPF settings by modifying this structure. This method uses the API calls + ' ReadDAPFEx and LoadDAPF. + ' + ' The other functions use the first method (as it is simpler) but you can use the second method instead if + ' you prefer. + ' + ' Note - an alternative to using the programDongleMod_Click technique is to modify the DAPF file on disk + ' and then use the programDongle_Click technique. To modify a binary DAPF you would use the binary structures + ' that are defined in dapf.h. To modify JSON DAPF you would need to use a JSON parser. + ' + ' lockSoftware_Click : locks software (protect it) to a dongle as specified by the DAPF file. + ' + ' encryptShellData_Click: encrypts the shell data files specified in the DAPF file (this is used with encrypting + ' data file if you use the Shell Method with "Data File Encryption" enabled). + ' + ' tempSoftwareKey_Click: creates a Temporary Software Key based on the DAPF file and settings the user has entered. + ' + ' demoSoftwareKey_Click: creates a Demo Software Key Template based on the DAPF file and settings the user has entered. + + Private Sub programDongle_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles programDongle.Click + Dim dapfHandle As IntPtr + Dim err_code As Integer + Dim dongle_number As UInt32 + + ' load DAPF from File into memory + dapfHandle = LoadDAPFFromFile(dapfFile.Text, err_code) + If IntPtr.Zero.Equals(dapfHandle) Then + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, AppName) + Exit Sub + End If + + ' program dongle as specified by the DAPF file + err_code = AddProtection(dapfHandle, ACTION_PROGRAM_DONGLE, 0, 0, dongle_number) + + ' Unload DAPF from memory + UnloadDAPF(dapfHandle) + + ' display message (error or success) + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Information, AppName) + End Sub +#If VBC_VER >= 14 Then + #Disable Warning BC42108, BC42030 'This line is used in Visual Studio 2015 (and newer) to remove warnings in this function +#End If + Private Sub programDongleMod_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles programDongleMod.Click + Dim dapfHandle As IntPtr + Dim err_code, dummy1, dummy2 As Integer + Dim dongle_number As UInt32 + Dim MyDinkeyInfo As DINKEYINFO + Dim LicenceInfoArray() As LICENCEINFO + Dim FileInfoArray() As FILEINFO + Dim AlgorithmArray() As ALGORITHM + Dim DataFileEncArray() As DATAFILEENC + + ' in this case we need to read the DAPF into our structures, so that the DAPF values can be modified + err_code = ReadDAPFEx(dapfFile.Text, MyDinkeyInfo, LicenceInfoArray, FileInfoArray, AlgorithmArray, DataFileEncArray, dummy1, dummy2) + If err_code <> 0 Then + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, AppName) + Exit Sub + End If + + ' patch new values + LicenceInfoArray(0).Features = Convert.ToUInt32(12345) + LicenceInfoArray(0).Execs = 100 + LicenceInfoArray(0).LicenceName = "fred" + + ' get DAPF handle + dapfHandle = LoadDAPF(MyDinkeyInfo, LicenceInfoArray, FileInfoArray, AlgorithmArray, DataFileEncArray, err_code) + If IntPtr.Zero.Equals(dapfHandle) Then + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, AppName) + Exit Sub + End If + + ' program dongle + err_code = AddProtection(dapfHandle, ACTION_PROGRAM_DONGLE, 0, 0, dongle_number) + + ' Unload DAPF from memory + UnloadDAPF(dapfHandle) + + ' display message (error or success) + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Information, AppName) + End Sub +#If VBC_VER >= 14 Then + #Enable Warning BC42108, BC42030 'This line is used in Visual Studio 2015 (and higher) to remove warnings +#End If + ' load a DAPF file from disk and protect the files specified + ' (in practice it is better to protect the files one at a time and output messages as you go along, similar to DinkeyAdd.exe) + ' In this example we specify the flag to overwrite any existing output file that might exist. + Private Sub lockSoftware_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lockSoftware.Click + Dim dapfHandle As IntPtr + Dim err_code As Integer + Dim dummy As UInt32 + + ' load DAPF from File into memory + dapfHandle = LoadDAPFFromFile(dapfFile.Text, err_code) + If IntPtr.Zero.Equals(dapfHandle) Then + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, AppName) + Exit Sub + End If + + ' protect all the files listed in the DAPF file + err_code = AddProtection(dapfHandle, ACTION_PROTECT_SOFTWARE, -1, FLAGS_OVERWRITE_OUTPUT, dummy) + + ' Unload DAPF from memory + UnloadDAPF(dapfHandle) + + ' display message (error or success) + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Information, AppName) + End Sub + + Private Sub encryptShellData_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles encryptShellData.Click + Dim dapfHandle As IntPtr + Dim err_code As Integer + + ' load DAPF from File into memory + dapfHandle = LoadDAPFFromFile(dapfFile.Text, err_code) + If IntPtr.Zero.Equals(dapfHandle) Then + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, AppName) + Exit Sub + End If + + ' encrypt all the shell data files listed in the DAPF file + err_code = EncryptShellDataFiles(dapfHandle, -1, FLAGS_OVERWRITE_OUTPUT) + + ' Unload DAPF from memory + UnloadDAPF(dapfHandle) + + ' display message (error or success) + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Information, AppName) + End Sub + + Private Sub tempSoftwareKey_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tempSoftwareKey.Click + Dim dapfHandle As IntPtr + Dim err_code As Integer + Dim swkey_info As TEMP_SWKEY_INFO + + ' load DAPF from File into memory + dapfHandle = LoadDAPFFromFile(dapfFile.Text, err_code) + If IntPtr.Zero.Equals(dapfHandle) Then + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, AppName) + Exit Sub + End If + + ' fill out the SWKEY structure from the values the user entered + swkey_info.Size = Marshal.SizeOf(swkey_info.GetType) + swkey_info.MachineID = Convert.ToUInt32(machineIDText.Text, 16) + swkey_info.ExpiryDay = Convert.ToInt32(expdayText.Text, 10) + swkey_info.ExpiryMonth = Convert.ToInt32(expmonthText.Text, 10) + swkey_info.ExpiryYear = Convert.ToInt32(expyearText.Text, 10) + ' !!!! in this case we just choose Pro Plus. You could load the DAPF file into structures and see which model is selected. + ' If there is more than one model selected you can ask the customer to choose which model they want. + swkey_info.DongleModel = SWKEY_MODEL_PRO_PLUS + swkey_info.DongleNumber = Convert.ToUInt32(0) + + ' attempt to create the Temporary Software Key + err_code = CreateTempSoftwareKey(dapfHandle, swkey_info, 0) + + ' Unload DAPF from memory + UnloadDAPF(dapfHandle) + + ' display message (error or success) + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Information, AppName) + End Sub + + Private Sub demoSoftwareKey_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles demoSoftwareKey.Click + Dim dapfHandle As IntPtr + Dim err_code As Integer + Dim swkey_info As DEMO_SWKEY_INFO + + ' load DAPF from File into memory + dapfHandle = LoadDAPFFromFile(dapfFile.Text, err_code) + If IntPtr.Zero.Equals(dapfHandle) Then + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, AppName) + Exit Sub + End If + + ' fill out the SWKEY structure from the values the user entered + swkey_info.Size = Marshal.SizeOf(swkey_info.GetType) + swkey_info.MaxDays = Convert.ToInt32(maxDaysText.Text, 10) + ' !!!! in this case we just choose the default model (assuming you only selected one in the DAPF file). + ' If you want to specify more than one model then OR the flags together. e.g. SWKEY_BITMAP_PRO_LITE Or SWKEY_BITMAP_PRO_PLUS + swkey_info.Models = SWKEY_BITMAP_DEFAULT + + ' attempt to create the Demo Software Key Template + err_code = CreateDemoSoftwareKeyTemplate(dapfHandle, swkey_info, 0) + + ' Unload DAPF from memory + UnloadDAPF(dapfHandle) + + ' display message (error or success) + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Information, AppName) + End Sub +End Class diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyAdd/README.txt b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyAdd/README.txt new file mode 100644 index 0000000..d77ce0b --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyAdd/README.txt @@ -0,0 +1,50 @@ +dapfTest - sample code to call DinkeyAdd Module in VB.NET +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 2002 but will work in more recent +versions of Visual Studio (they will upgrade the Project to the latest version. +If prompted you should also upgrade the .NET framework the project requires). + +For users of Visual Studio 2005 or higher, the default setting to projects is to +compile for the Target Platform "Any". This means that on 32-bit Windows, your +code will run as 32-bit code (and needs to call DinkeyAdd32.dll) and under 64-bit +Windows your code will run as 64-bit code (and needs to call DinkeyAdd64.dll). +The sample code works this out automatically. If you select the target platform as "x86" +then it will always be 32-bit and so you only need to use DinkeyAdd32.dll. If you +select "x64" then your code will be 64-bit and you only need to use DinkeyAdd64.dll. + +The main source files in the project are: + +dapf.vb - the source file contains declarations of our API. We automatically + work out whether your code is running in 32-bit or 64-bit and load + the appropriate DinkeyAdd module. + +Form1.vb - this is the sample code giving an example on how you can call our API. + It contains 5 functions. Just use which ever functions are most appropriate + and customise in your own way. + +The best approach is to compile the sample code and see how it works and then to take +the appropriate code and apply it to your own project. You should include the dapf.vb +file in your project and use/modify which ever functions from Form1.vb you feel are +appropriate. The dapf.vb file should not be modified. + +The sample code is just a guide. As none of the parameters are security sensitive then +there is no need to implement strong security in calling DinkeyAdd. + +Make sure you remember to do the following when creating your own project: + +1) Insert the following namespaces in your code file: +using System.Runtime.InteropServices; + +2) Insert the dapf.vb file in your project. + +3) You need to put DinkeyAdd32.dll and/or DinkeyAdd64.dll into the folder that +contains dapfTest. Otherwise the message "Unable to open DLL (DinkeyAdd32.dll)" or +the System.DllNotFoundException error will appear when you run dapfTest. + +Notes on Debugging 64-bit Code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +When you use the 64-bit module (DinkeyAdd64.dll) the anti-debug code is so strong +that if you are debugging your code, after calling our API then it will crash with +an SEH exception. There are no debug modules for DinkeyAdd so you will have to find +other ways of debugging your code (for example taking out the call altogether). diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyAdd/dapf.vb b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyAdd/dapf.vb new file mode 100644 index 0000000..350cffc --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyAdd/dapf.vb @@ -0,0 +1,467 @@ +' !! this file should not be modified + +' DAPF file is in the following format: +' DINKEYINFO +' LICENCEINFO (however many are needed) +' FILEINFO (however many are needed) +' ALGORITHM (however many are needed) +' DATAFILEENC (however many are needed) + +Imports System +Imports System.Runtime.InteropServices ' so we can marshal the structures as a block of memory +Imports System.Text ' for StringBuilder + +' *********** define structures that make up the DAPF file ******************* + +Module dapf_code + + _ + Structure DINKEYINFO + Dim Header1 As Byte ' should be set to "DAPF" + Dim Header2 As Byte + Dim Header3 As Byte + Dim Header4 As Byte + Dim Version As Integer ' version of this structure. Currently 9. + Dim SelectedModels As Integer ' BIT0 = Dinkey Pro Lite, BIT1 = Dinkey Pro Plus, BIT2 = Dinkey Pro Net etc... + _ + Dim ProdCode As String + Dim PerLicence As Integer ' 1 = per licence, 0 = per product (default) + Dim MaxNetUsers As Integer ' product net users, unlimited = -1, no entry = -2 + Dim RangeSettings As Integer ' 0 = any number, 1 = dongle in computer, 2 = range + Dim RangeMin As UInt32 + Dim RangeMax As UInt32 + Dim NumLicences As Integer ' number of LICENCEINFO structures in this DAPF file + Dim NumProgs As Integer ' number of FILEINFO structures in this DAPF file + Dim NumAlgs As Integer + Dim DataSizeType As Integer ' 1 = set the zero data size, 0 = use file to initialise data area + Dim ZeroDataSize As Integer ' size of the data area area in bytes + ' NB some of these entries were for an older (deprecated) FD model. Now marked as deprecated. These fields are ignored. + _ + Dim DataFile As String ' path to data file (0 = no data file) + Dim DataAreaSize As Integer ' file size in bytes, -1 = file not found + _ + Dim ShellSuccessMsg As String ' Shell Method messages... + _ + Dim ShellNoDongleMsg As String + _ + Dim ShellExpiryDateMsg As String + _ + Dim ShellExpiryExecsMsg As String + _ + Dim ShellWarnDateMsg As String + _ + Dim ShellWarnExecsMsg As String + _ + Dim ShellNetUserLimitMsg As String + _ + Dim ShellOtherErrorMsg As String + _ + Dim ShellBackgroundMsg As String + _ + Dim NetNoServerMsg As String + _ + Dim rwalg As Byte() ' coded form of rw algorithm (0 = no algorithm) + Dim SecOptions As Integer ' BIT0: DRIS encryption, BIT1: Data encryption, BIT2: Data enc with alg, BIT3: only secure update codes + Dim SecDRISEncKey1 As Byte ' DRIS encryption parameters + Dim SecDRISEncKey2 As Byte + Dim SecDRISEncKey3 As Byte + Dim Ignored1 As Byte ' this byte is ignored + Dim SecDataEncKey1 As Byte ' API Data encryption parameters + Dim SecDataEncKey2 As Byte + Dim SecDataEncKey3 As Byte + Dim Ignored2 As Byte ' this byte is ignored + Dim ProtectionType As Integer ' 0 = software + dongle, 1 = dongle only, 2 = program only + _ + Dim DataEncKeyProdCode As String ' Alternative Product Code used to generate internal encryption keys. Normally set to 0. + _ + Dim Notes As String ' user-defined notes + Dim LockDongle As Integer ' 0 = don't lock (default), 1 = lock dongle to user's computer + Dim Reserved1 As Integer ' must be 0 + Dim Reserved2 As Integer ' must be 0 + Dim AdvancedOptions As Integer ' BIT0 = do not allow usb-over-network for non-Net dongles, BIT1 = do not check for Software Key at Runtime. + Dim NumDataFileEnc As Integer ' Number of data files in our encryption list + End Structure + + _ + Structure LICENCEINFO + _ + Dim LicenceName As String ' licence name + Dim MaxDays As Integer ' -1 = no limit + Dim ExpiryDay As Integer ' -1 = no limit, 0 = no change + Dim ExpiryMonth As Integer + Dim ExpiryYear As Integer + Dim Execs As Integer ' -1 = no limit + Dim ExecsWarn As Integer ' 0 = no warning (just for Shell method) + Dim DaysWarn As Integer ' 0 = no warning (just for Shell method) + Dim Features As Uint32 + Dim LicenceNetUsers As Integer ' unlimited = -1 (-2 = not needed (this is for display only)) + End Structure + + _ + Structure FILEINFO + _ + Dim InputName As String ' input file (full path) + _ + Dim OutputName As String ' output file/folder + _ + Dim CallingProg As String ' calling program name + Dim LicenceIndex As Integer ' index (of licence) in the LicenceInfo structure (1-based index. 0 = no selection) + Dim Method As Integer ' 0-api, 1-shell, 2-shell & api + Dim ShellFlags As Integer ' same bit flag values as in dris. i.e. 1 = DEC_ONE_EXEC, 4 = START_NET_USER + Dim BackGround As Integer ' 0=no background, 1=1min, 2=5min, 3=10min, 4=30min, 5=60min + Dim OtherShellOptions As Integer ' BIT0 = Shell Data Encryption Enabled, BIT1: Extra Anti-Debug is disabled, BIT2: Extra Anti-Piracy is disabled + _ + Dim EncFileList As String ' files (or file types) that the Shell-protected program will treat as encrypted (separated by ':') + _ + Dim ExceptList As String ' files (or file types) that are exceptions to the above list (separated by ':') + Dim ExtraAntiPiracy As Integer ' 0 = off, 1=min, 10=max + End Structure + + _ + Structure ALGORITHM + _ + Dim alg As Byte() ' coded form of algorithm + End Structure + + _ + Structure DATAFILEENC + _ + Dim InputName As String ' file name, wild cards are allowed + _ + Dim OutputName As String ' file name (or folder name if input is a wildcard) + End Structure + + ' this structure is used for creating Temporary Software Keys + _ + Structure TEMP_SWKEY_INFO + Dim Size As Integer + Dim MachineID As UInt32 + Dim ExpiryDay As Integer + Dim ExpiryMonth As Integer + Dim ExpiryYear As Integer + Dim DongleModel As Integer + Dim DongleNumber As UInt32 + End Structure + + ' this structure is used for creating Demo Software Key Templates + _ + Structure DEMO_SWKEY_INFO + Dim Size As Integer + Dim MaxDays As Int32 ' max days demo swkey installation is valid (0-60) + Dim Models As Int32 ' bitmap of valid dongle models. See constant values below. 0 = default (only use if only one model is selected in DINKEYINFO) + End Structure + +' ********************** DinkeyAdd Module Imports ************************ + + ' Loads DAPF from disk and returns handle + Declare Ansi Function LoadDAPFFromFile32 Lib "DinkeyAdd32.dll" Alias "LoadDAPFFromFile" (ByVal dapf_file As String, ByRef err_code As Integer) As IntPtr + Declare Ansi Function LoadDAPFFromFile64 Lib "DinkeyAdd64.dll" Alias "LoadDAPFFromFile" (ByVal dapf_file As String, ByRef err_code As Integer) As IntPtr + + ' Loads DAPF from disk into structures supplied (so we can modify DAPF in memory) + Declare Ansi Function ReadDAPFEx32 Lib "DinkeyAdd32.dll" Alias "ReadDAPFEx" (ByVal dapf_file As String, ByRef MyDinkeyInfo As DINKEYINFO, ByVal licence_bytes() As Byte, _ + ByVal fileinfo_bytes() As Byte, ByVal alg_bytes() As Byte, ByVal datafile_bytes() As Byte, ByRef dapf_version As Integer, ByRef dapf_format As Integer) As Integer + Declare Ansi Function ReadDAPFEx64 Lib "DinkeyAdd64.dll" Alias "ReadDAPFEx" (ByVal dapf_file As String, ByRef MyDinkeyInfo As DINKEYINFO, ByVal licence_bytes() As Byte, _ + ByVal fileinfo_bytes() As Byte, ByVal alg_bytes() As Byte, ByVal datafile_bytes() As Byte, ByRef dapf_version As Integer, ByRef dapf_format As Integer) As Integer + + ' Loads DAPF from structures and returns a handle + Declare Ansi Function LoadDAPF32 Lib "DinkeyAdd32.dll" Alias "LoadDAPF" (ByRef MyDinkeyInfo As DINKEYINFO, ByVal licence_bytes() As Byte, ByVal fileinfo_bytes() As Byte, _ + ByVal alg_bytes() As Byte, ByVal datafile_bytes() As Byte, ByRef ret_code As Integer) As IntPtr + Declare Ansi Function LoadDAPF64 Lib "DinkeyAdd64.dll" Alias "LoadDAPF" (ByRef MyDinkeyInfo As DINKEYINFO, ByVal licence_bytes() As Byte, ByVal fileinfo_bytes() As Byte, _ + ByVal alg_bytes() As Byte, ByVal datafile_bytes() As Byte, ByRef ret_code As Integer) As IntPtr + + ' saves the DAPF file to disk + Declare Ansi Function WriteDAPFEx32 Lib "DinkeyAdd32.dll" Alias "WriteDAPFEx" (ByVal dapf_handle As IntPtr, ByVal dapf_file As String, ByVal dapf_format As Integer, _ + ByVal dapf_version As Integer, ByVal flags As Integer) As Integer + Declare Ansi Function WriteDAPFEx64 Lib "DinkeyAdd64.dll" Alias "WriteDAPFEx" (ByVal dapf_handle As IntPtr, ByVal dapf_file As String, ByVal dapf_format As Integer, _ + ByVal dapf_version As Integer, ByVal flags As Integer) As Integer + + ' unloads the DAPF file + Declare Ansi Sub UnloadDAPF32 Lib "DinkeyAdd32.dll" Alias "UnloadDAPF" (ByRef dapf_handle As IntPtr) + Declare Ansi Sub UnloadDAPF64 Lib "DinkeyAdd64.dll" Alias "UnloadDAPF" (ByRef dapf_handle As IntPtr) + + 'main functions + Declare Ansi Function AddProtection32 Lib "DinkeyAdd32.dll" Alias "AddProtection" (ByVal dapf_handle As IntPtr, ByVal action As Integer, ByVal file_num As Integer, _ + ByVal flags As Integer, ByRef dongle_number As UInt32) As Integer + Declare Ansi Function AddProtection64 Lib "DinkeyAdd64.dll" Alias "AddProtection" (ByVal dapf_handle As IntPtr, ByVal action As Integer, ByVal file_num As Integer, _ + ByVal flags As Integer, ByRef dongle_number As UInt32) As Integer + + Declare Ansi Function CreateTempSoftwareKey32 Lib "DinkeyAdd32.dll" Alias "CreateTempSoftwareKey" (ByVal dapf_handle As IntPtr, ByRef my_swkey_info As TEMP_SWKEY_INFO, _ + ByVal flags As Integer) As Integer + Declare Ansi Function CreateTempSoftwareKey64 Lib "DinkeyAdd64.dll" Alias "CreateTempSoftwareKey" (ByVal dapf_handle As IntPtr, ByRef my_swkey_info As TEMP_SWKEY_INFO, _ + ByVal flags As Integer) As Integer + + Declare Ansi Function CreateDemoSoftwareKeyTemplate32 Lib "DinkeyAdd32.dll" Alias "CreateDemoSoftwareKeyTemplate" (ByVal dapf_handle As IntPtr, ByRef my_swkey_info As DEMO_SWKEY_INFO, _ + ByVal flags As Integer) As Integer + Declare Ansi Function CreateDemoSoftwareKeyTemplate64 Lib "DinkeyAdd64.dll" Alias "CreateDemoSoftwareKeyTemplate" (ByVal dapf_handle As IntPtr, ByRef my_swkey_info As DEMO_SWKEY_INFO, _ + ByVal flags As Integer) As Integer + + Declare Ansi Function EncryptShellDataFiles32 Lib "DinkeyAdd32.dll" Alias "EncryptShellDataFiles" (ByVal dapf_handle As IntPtr, ByVal file_num As Integer, _ + ByVal flags As Integer) As Integer + Declare Ansi Function EncryptShellDataFiles64 Lib "DinkeyAdd64.dll" Alias "EncryptShellDataFiles" (ByVal dapf_handle As IntPtr, ByVal file_num As Integer, _ + ByVal flags As Integer) As Integer + + ' get the message output by DinkeyAdd + Declare Ansi Sub GetLastMessage32 Lib "DinkeyAdd32.dll" Alias "GetLastMessage" (ByVal message As StringBuilder, ByVal buffer_size As Integer, ByRef message_length As Integer) + Declare Ansi Sub GetLastMessage64 Lib "DinkeyAdd64.dll" Alias "GetLastMessage" (ByVal message As StringBuilder, ByVal buffer_size As Integer, ByRef message_length As Integer) + + ' get the extended error (set if an error occurs) + Declare Ansi Function GetLastExtendedError32 Lib "DinkeyAdd32.dll" Alias "GetLastExtendedError" () As Integer + Declare Ansi Function GetLastExtendedError64 Lib "DinkeyAdd64.dll" Alias "GetLastExtendedError" () As Integer + + ' ********************** Constants ************************ + Public Const DAPF_VERSION As Integer = 9 ' current DAPF version + + ' WriteDAPFEx API flags + Public Const FLAGS_LOSE_FEATURES As Integer = 1 ' means that you can save the DAPF file to an earlier version even if it means losing some new features that have been currently set + + ' AddProtection API action values + Public Const ACTION_USE_DAPF_SETTINGS As Integer = 0 ' means you just ignore the action value and use the default dapf settings + Public Const ACTION_PROGRAM_DONGLE As Integer = 1 ' program the dongle only + Public Const ACTION_PROTECT_SOFTWARE As Integer = 2 ' protect a software file (index indicated by separate parameter) + Public Const ACTION_PROGRAM_AND_PROTECT As Integer = 3 ' program the dongle and protect software + + ' AddProtection API flags values + Public Const FLAGS_OVERWRITE_OUTPUT As Integer = 1 ' overwrite the output file if it already exists (default is to give an error) + + ' CreateSoftwareKey API flags + Public Const FLAGS_OVERWRITE_SWKEY As Integer = 1 ' ovewrite an existing swkey with the new one + Public Const FLAGS_EXPIRY_DONTCARE As Integer = 2 ' create the Software Key even though the expiry date (or max days) is less than the expiry date of the key itself. + + ' constants for dapf_format in ReadDAPFEx and WriteDAPFEx functions + Public Const DAPF_FORMAT_BINARY As Integer = 1 + Public Const DAPF_FORMAT_JSON As Integer = 2 + Public Const DAPF_FORMAT_JSON_MIN As Integer = 3 ' this value is only used with WriteDAPEx. ReadDAPFEx cannot return this value. + + ' constants for values for model in the TEMP_SWKEY_INFO structure + Public Const SWKEY_MODEL_PRO_LITE As Integer = 0 + Public Const SWKEY_MODEL_PRO_PLUS As Integer = 1 + Public Const SWKEY_MODEL_PRO_NET As Integer = 2 + Public Const SWKEY_MODEL_FD_LITE As Integer = 3 + Public Const SWKEY_MODEL_FD_PLUS As Integer = 4 + Public Const SWKEY_MODEL_FD_NET As Integer = 5 + + ' constants for models bitmap in the DEMO_SWKEY_INFO structure + Public Const SWKEY_BITMAP_DEFAULT As Integer = 0 ' use default value set in DINKEYINFO.SelectedModels + Public Const SWKEY_BITMAP_PRO_LITE As Integer = 1 ' BIT0 + Public Const SWKEY_BITMAP_PRO_PLUS As Integer = 2 ' BIT1 + Public Const SWKEY_BITMAP_PRO_NET As Integer = 4 ' BIT2 + Public Const SWKEY_BITMAP_FD_LITE As Integer = 8 ' BIT3 + Public Const SWKEY_BITMAP_FD_PLUS As Integer = 16 ' BIT4 + Public Const SWKEY_BITMAP_FD_NET As Integer = 32 ' BIT5 + + ' private constants + Private Const MAX_LICENCES As Integer = 255 ' max number of licences in a DAPF file + Private Const MAX_FILE_INFO As Integer = 1000 ' theoretically unlimited but in practice it is easier if we limit it + Private Const MAX_USER_ALGS As Integer = 20 'max number of user algs in DAPF file + Private Const MAX_DATA_ENCS As Integer = 255 ' max number of Shell data encryption files in DAPF file + +' ********************** API Functions ************************ +' We only want to load the correct DLL for the bit-ness of the computer. The other DLL may not exist. +' if the appropriate DLL does not exist in the same directory as this test program you will receive a DllNotFoundException + + ' call the correct dll depending on whether we are running 32-bit or 64-bit code + Function LoadDAPFFromFile(ByVal dapf_file As String, ByRef err_code As Integer) As IntPtr + If (IntPtr.Size = 4) Then + LoadDAPFFromFile = LoadDAPFFromFile32(dapf_file, err_code) + Else + LoadDAPFFromFile = LoadDAPFFromFile64(dapf_file, err_code) + End If + End Function + + ' we have to do some marshalling of arrays of bytes into arrays of structures + Function ReadDAPFEx(ByVal dapf_file As String, ByRef MyDinkeyInfo As DINKEYINFO, ByRef LicenceInfoArray() As LICENCEINFO, ByRef FileInfoArray() As FILEINFO, _ + ByRef AlgorithmArray() As ALGORITHM, ByRef DataFileEncArray() As DATAFILEENC, ByRef dapf_version As Integer, ByRef dapf_format As Integer) As Integer + Dim i As Integer + Dim MyLicenceInfo As New LICENCEINFO + Dim licence_bytes(MAX_LICENCES * Marshal.SizeOf(MyLicenceInfo)) As Byte + Dim licence_bytes_one_struct(Marshal.SizeOf(MyLicenceInfo)) As Byte + Dim MyFileInfo As New FILEINFO + Dim fileinfo_bytes(MAX_FILE_INFO * Marshal.SizeOf(MyFileInfo)) As Byte + Dim fileinfo_bytes_one_struct(Marshal.SizeOf(MyFileInfo)) As Byte + Dim MyAlgorithm As New ALGORITHM + Dim alg_bytes(MAX_USER_ALGS * Marshal.SizeOf(MyAlgorithm)) As Byte + Dim alg_bytes_one_struct(Marshal.SizeOf(MyAlgorithm)) As Byte + Dim MyDataFileEnc As New DATAFILEENC + Dim datafile_bytes(MAX_DATA_ENCS * Marshal.SizeOf(MyDataFileEnc)) As Byte + Dim datafile_bytes_one_struct(Marshal.SizeOf(MyDataFileEnc)) As Byte + Dim MyGC As GCHandle + MyDinkeyInfo = New DINKEYINFO + + If (IntPtr.Size = 4) Then + ReadDAPFEx = ReadDAPFEx32(dapf_file, MyDinkeyInfo, licence_bytes, fileinfo_bytes, alg_bytes, datafile_bytes, dapf_version, dapf_format) + Else + ReadDAPFEx = ReadDAPFEx64(dapf_file, MyDinkeyInfo, licence_bytes, fileinfo_bytes, alg_bytes, datafile_bytes, dapf_version, dapf_format) + End If + + If ReadDAPFEx <> 0 Then + Exit Function + End If + + ' convert byte array to an array of structs + ReDim LicenceInfoArray(MyDinkeyInfo.NumLicences) + For i = 0 To MyDinkeyInfo.NumLicences - 1 + LicenceInfoArray(i) = New LICENCEINFO + Array.Copy(licence_bytes, i * Marshal.SizeOf(MyLicenceInfo.GetType), licence_bytes_one_struct, 0, Marshal.SizeOf(MyLicenceInfo.GetType)) + MyGC = GCHandle.Alloc(licence_bytes_one_struct, GCHandleType.Pinned) + LicenceInfoArray(i) = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, MyLicenceInfo.GetType) + MyGC.Free() + Next + + ReDim FileInfoArray(MyDinkeyInfo.NumProgs) + For i = 0 To MyDinkeyInfo.NumProgs - 1 + FileInfoArray(i) = New FILEINFO + Array.Copy(fileinfo_bytes, i * Marshal.SizeOf(MyFileInfo.GetType), fileinfo_bytes_one_struct, 0, Marshal.SizeOf(MyFileInfo.GetType)) + MyGC = GCHandle.Alloc(fileinfo_bytes_one_struct, GCHandleType.Pinned) + FileInfoArray(i) = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, MyFileInfo.GetType) + MyGC.Free() + Next + + ReDim AlgorithmArray(MyDinkeyInfo.NumAlgs) + For i = 0 To MyDinkeyInfo.NumAlgs - 1 + AlgorithmArray(i) = New ALGORITHM + Array.Copy(alg_bytes, i * Marshal.SizeOf(MyAlgorithm.GetType), alg_bytes_one_struct, 0, Marshal.SizeOf(MyAlgorithm.GetType)) + MyGC = GCHandle.Alloc(alg_bytes_one_struct, GCHandleType.Pinned) + AlgorithmArray(i) = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, MyAlgorithm.GetType) + MyGC.Free() + Next + + ReDim DataFileEncArray(MyDinkeyInfo.NumDataFileEnc) + For i = 0 To MyDinkeyInfo.NumDataFileEnc - 1 + DataFileEncArray(i) = New DATAFILEENC + Array.Copy(datafile_bytes, i * Marshal.SizeOf(MyDataFileEnc.GetType), datafile_bytes_one_struct, 0, Marshal.SizeOf(MyDataFileEnc.GetType)) + MyGC = GCHandle.Alloc(datafile_bytes_one_struct, GCHandleType.Pinned) + DataFileEncArray(i) = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, MyDataFileEnc.GetType) + MyGC.Free() + Next + + End Function + + Function LoadDAPF(ByRef MyDinkeyInfo As DINKEYINFO, ByRef LicenceInfoArray() As LICENCEINFO, ByRef FileInfoArray() As FILEINFO, _ + ByRef AlgorithmArray() As ALGORITHM, ByRef DataFileEncArray() As DATAFILEENC, ByRef ret_code As Integer) As IntPtr + Dim i As Integer + Dim MyLicenceInfo As New LICENCEINFO + Dim licence_bytes(MAX_LICENCES * Marshal.SizeOf(MyLicenceInfo)) As Byte + Dim licence_bytes_one_struct(Marshal.SizeOf(MyLicenceInfo)) As Byte + Dim MyFileInfo As New FILEINFO + Dim fileinfo_bytes(MAX_FILE_INFO * Marshal.SizeOf(MyFileInfo)) As Byte + Dim fileinfo_bytes_one_struct(Marshal.SizeOf(MyFileInfo)) As Byte + Dim MyAlgorithm As New ALGORITHM + Dim alg_bytes(MAX_USER_ALGS * Marshal.SizeOf(MyAlgorithm)) As Byte + Dim alg_bytes_one_struct(Marshal.SizeOf(MyAlgorithm)) As Byte + Dim MyDataFileEnc As New DATAFILEENC + Dim datafile_bytes(MAX_DATA_ENCS * Marshal.SizeOf(MyDataFileEnc)) As Byte + Dim datafile_bytes_one_struct(Marshal.SizeOf(MyDataFileEnc)) As Byte + Dim MyGC As GCHandle + + ' convert array of structs to byte arrays + For i = 0 To MyDinkeyInfo.NumLicences - 1 + MyGC = GCHandle.Alloc(licence_bytes_one_struct, GCHandleType.Pinned) + Marshal.StructureToPtr(LicenceInfoArray(i), MyGC.AddrOfPinnedObject, False) + MyGC.Free() + Array.Copy(licence_bytes_one_struct, 0, licence_bytes, i * Marshal.SizeOf(MyLicenceInfo.GetType), Marshal.SizeOf(MyLicenceInfo.GetType)) + Next + + For i = 0 To MyDinkeyInfo.NumProgs - 1 + MyGC = GCHandle.Alloc(fileinfo_bytes_one_struct, GCHandleType.Pinned) + Marshal.StructureToPtr(FileInfoArray(i), MyGC.AddrOfPinnedObject, False) + MyGC.Free() + Array.Copy(fileinfo_bytes_one_struct, 0, fileinfo_bytes, i * Marshal.SizeOf(MyFileInfo.GetType), Marshal.SizeOf(MyFileInfo.GetType)) + Next + + For i = 0 To MyDinkeyInfo.NumAlgs - 1 + MyGC = GCHandle.Alloc(alg_bytes_one_struct, GCHandleType.Pinned) + Marshal.StructureToPtr(AlgorithmArray(i), MyGC.AddrOfPinnedObject, False) + MyGC.Free() + Array.Copy(alg_bytes_one_struct, 0, alg_bytes, i * Marshal.SizeOf(MyAlgorithm.GetType), Marshal.SizeOf(MyAlgorithm.GetType)) + Next + + For i = 0 To MyDinkeyInfo.NumDataFileEnc - 1 + MyGC = GCHandle.Alloc(datafile_bytes_one_struct, GCHandleType.Pinned) + Marshal.StructureToPtr(DataFileEncArray(i), MyGC.AddrOfPinnedObject, False) + MyGC.Free() + Array.Copy(datafile_bytes_one_struct, 0, datafile_bytes, i * Marshal.SizeOf(MyDataFileEnc.GetType), Marshal.SizeOf(MyDataFileEnc.GetType)) + Next + + If (IntPtr.Size = 4) Then + LoadDAPF = LoadDAPF32(MyDinkeyInfo, licence_bytes, fileinfo_bytes, alg_bytes, datafile_bytes, ret_code) + Else + LoadDAPF = LoadDAPF64(MyDinkeyInfo, licence_bytes, fileinfo_bytes, alg_bytes, datafile_bytes, ret_code) + End If + + End Function + + Function WriteDAPFEx(ByVal dapf_handle As IntPtr, ByVal dapf_file As String, ByVal dapf_format As Integer, ByVal dapf_version As Integer, ByVal flags As Integer) As Integer + If (IntPtr.Size = 4) Then + WriteDAPFEx = WriteDAPFEx32(dapf_handle, dapf_file, dapf_format, dapf_version, flags) + Else + WriteDAPFEx = WriteDAPFEx64(dapf_handle, dapf_file, dapf_format, dapf_version, flags) + End If + End Function + + Sub UnloadDAPF(ByRef dapf_handle As IntPtr) + If (IntPtr.Size = 4) Then + UnloadDAPF32(dapf_handle) + Else + UnloadDAPF64(dapf_handle) + End If + End Sub + + Function AddProtection(ByVal dapf_handle As IntPtr, ByVal action As Integer, ByVal file_num As Integer, ByVal flags As Integer, ByRef dongle_number As UInt32) As Integer + If (IntPtr.Size = 4) Then + AddProtection = AddProtection32(dapf_handle, action, file_num, flags, dongle_number) + Else + AddProtection = AddProtection64(dapf_handle, action, file_num, flags, dongle_number) + End If + End Function + + Function CreateTempSoftwareKey(ByVal dapf_handle As IntPtr, ByRef swkey_info As TEMP_SWKEY_INFO, ByVal flags As Integer) As Integer + If (IntPtr.Size = 4) Then + CreateTempSoftwareKey = CreateTempSoftwareKey32(dapf_handle, swkey_info, flags) + Else + CreateTempSoftwareKey = CreateTempSoftwareKey64(dapf_handle, swkey_info, flags) + End If + End Function + + Function CreateDemoSoftwareKeyTemplate(ByVal dapf_handle As IntPtr, ByRef swkey_info As DEMO_SWKEY_INFO, ByVal flags As Integer) As Integer + If (IntPtr.Size = 4) Then + CreateDemoSoftwareKeyTemplate = CreateDemoSoftwareKeyTemplate32(dapf_handle, swkey_info, flags) + Else + CreateDemoSoftwareKeyTemplate = CreateDemoSoftwareKeyTemplate64(dapf_handle, swkey_info, flags) + End If + End Function + + Function EncryptShellDataFiles(ByVal dapf_handle As IntPtr, ByVal file_num As Integer, ByVal flags As Integer) As Integer + If (IntPtr.Size = 4) Then + EncryptShellDataFiles = EncryptShellDataFiles32(dapf_handle, file_num, flags) + Else + EncryptShellDataFiles = EncryptShellDataFiles64(dapf_handle, file_num, flags) + End If + End Function + + ' do a bit of work here to make the function easier to use for VB.NET + Function GetLastMessage() As String + Dim length, dummy As Integer + Dim message As StringBuilder + + If (IntPtr.Size = 4) Then + GetLastMessage32(Nothing, 0, length) + message = New StringBuilder(length) + GetLastMessage32(message, length, dummy) + Else + GetLastMessage64(Nothing, 0, length) + message = New StringBuilder(length) + GetLastMessage64(message, length, dummy) + End If + + Return message.ToString() + End Function + + Function GetLastExtendedError() As Integer + If (IntPtr.Size = 4) Then + GetLastExtendedError = GetLastExtendedError32() + Else + GetLastExtendedError = GetLastExtendedError64() + End If + End Function + +End Module diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyAdd/dapfTest.sln b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyAdd/dapfTest.sln new file mode 100644 index 0000000..376658e --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyAdd/dapfTest.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "dapfTest", "dapfTest.vbproj", "{35022C29-459B-4D19-BC69-5133B03CD7FF}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {35022C29-459B-4D19-BC69-5133B03CD7FF}.Debug.ActiveCfg = Debug|.NET + {35022C29-459B-4D19-BC69-5133B03CD7FF}.Debug.Build.0 = Debug|.NET + {35022C29-459B-4D19-BC69-5133B03CD7FF}.Release.ActiveCfg = Release|.NET + {35022C29-459B-4D19-BC69-5133B03CD7FF}.Release.Build.0 = Release|.NET + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyAdd/dapfTest.vbproj b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyAdd/dapfTest.vbproj new file mode 100644 index 0000000..d72e0d2 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyAdd/dapfTest.vbproj @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyChange/AssemblyInfo.vb b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyChange/AssemblyInfo.vb new file mode 100644 index 0000000..2635a9c --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyChange/AssemblyInfo.vb @@ -0,0 +1,31 @@ +Imports System.Reflection +Imports System.Runtime.InteropServices + +' General Information about an assembly is controlled through the following +' set of attributes. Change these attribute values to modify the information +' associated with an assembly. + +' Review the values of the assembly attributes + + + + + + + + + +'The following GUID is for the ID of the typelib if this project is exposed to COM + + +' Version information for an assembly consists of the following four values: +' +' Major Version +' Minor Version +' Build Number +' Revision +' +' You can specify all the values or you can default the Build and Revision Numbers +' by using the '*' as shown below: + + diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyChange/ChangeTest.sln b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyChange/ChangeTest.sln new file mode 100644 index 0000000..03ad53d --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyChange/ChangeTest.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "ChangeTest", "ChangeTest.vbproj", "{5F1FF5B9-0F39-4DF7-B37A-CD1A84027EDB}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {5F1FF5B9-0F39-4DF7-B37A-CD1A84027EDB}.Debug.ActiveCfg = Debug|.NET + {5F1FF5B9-0F39-4DF7-B37A-CD1A84027EDB}.Debug.Build.0 = Debug|.NET + {5F1FF5B9-0F39-4DF7-B37A-CD1A84027EDB}.Release.ActiveCfg = Release|.NET + {5F1FF5B9-0F39-4DF7-B37A-CD1A84027EDB}.Release.Build.0 = Release|.NET + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyChange/ChangeTest.vbproj b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyChange/ChangeTest.vbproj new file mode 100644 index 0000000..615886b --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyChange/ChangeTest.vbproj @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyChange/DinkeyChange.vb b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyChange/DinkeyChange.vb new file mode 100644 index 0000000..ca08fcc --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyChange/DinkeyChange.vb @@ -0,0 +1,144 @@ +' !! this file should not be modified + +Imports System.Runtime.InteropServices +Imports System.Text + +Module DinkeyChange_code + + ' declarations for functions exported by DinkeyChange.dll + Declare Ansi Function DCGetInfo32 Lib "DinkeyChange.dll" Alias "DCGetInfo" (ByVal type_mask As Integer, ByVal model_mask As Integer, ByVal prodcode_mask As String, ByVal array_length As Integer, _ + ByRef num_found As Integer, ByVal type_array() As Integer, ByVal model_array() As Integer, ByVal prodcode_array() As Byte, ByVal dongle_number() As UInt32, ByVal update_number() As Integer) As Integer + Declare Ansi Function DCGetDiagnosticInfo32 Lib "DinkeyChange.dll" Alias "DCGetDiagnosticInfo" (ByVal filename As String) As Integer + Declare Ansi Function DCDoUpdateCodeString32 Lib "DinkeyChange.dll" Alias "DCDoUpdateCodeString" (ByVal update_code_string As String, ByRef confirmation_code As Integer, ByRef extended_error As Integer) As Integer + Declare Ansi Function DCDoUpdateCodeFromFile32 Lib "DinkeyChange.dll" Alias "DCDoUpdateCodeFromFile" (ByVal filename As String, ByRef confirmation_code As Integer, ByRef extended_error As Integer) As Integer + Declare Ansi Function DCRestoreDinkeyFDLite32 Lib "DinkeyChange.dll" Alias "DCRestoreDinkeyFDLite" () As Integer + Declare Ansi Function DCGetMachineID32 Lib "DinkeyChange.dll" Alias "DCGetMachineID" (ByRef machineID As UInt32, ByRef extended_error As Integer) As Integer + Declare Ansi Function DCDownloadTempSoftwareKey32 Lib "DinkeyChange.dll" Alias "DCDownloadTempSoftwareKey" (ByVal machineID As UInt32, ByRef extended_error As Integer) As Integer + Declare Ansi Function DCDownloadDemoSoftwareKey32 Lib "DinkeyChange.dll" Alias "DCDownloadDemoSoftwareKey" (ByVal machineID As UInt32, ByVal prodcode As String, ByVal model As Integer, ByRef extended_error As Integer) As Integer + + ' declarations for functions exported by DinkeyChange64.dll + Declare Ansi Function DCGetInfo64 Lib "DinkeyChange64.dll" Alias "DCGetInfo" (ByVal type_mask As Integer, ByVal model_mask As Integer, ByVal prodcode_mask As String, ByVal array_length As Integer, _ + ByRef num_found As Integer, ByVal type_array() As Integer, ByVal model_array() As Integer, ByVal prodcode_array() As Byte, ByVal dongle_number() As UInt32, ByVal update_number() As Integer) As Integer + Declare Ansi Function DCGetDiagnosticInfo64 Lib "DinkeyChange64.dll" Alias "DCGetDiagnosticInfo" (ByVal filename As String) As Integer + Declare Ansi Function DCDoUpdateCodeString64 Lib "DinkeyChange64.dll" Alias "DCDoUpdateCodeString" (ByVal update_code_string As String, ByRef confirmation_code As Integer, ByRef extended_error As Integer) As Integer + Declare Ansi Function DCDoUpdateCodeFromFile64 Lib "DinkeyChange64.dll" Alias "DCDoUpdateCodeFromFile" (ByVal filename As String, ByRef confirmation_code As Integer, ByRef extended_error As Integer) As Integer + Declare Ansi Function DCRestoreDinkeyFDLite64 Lib "DinkeyChange64.dll" Alias "DCRestoreDinkeyFDLite" () As Integer + Declare Ansi Function DCGetMachineID64 Lib "DinkeyChange64.dll" Alias "DCGetMachineID" (ByRef machineID As UInt32, ByRef extended_error As Integer) As Integer + Declare Ansi Function DCDownloadTempSoftwareKey64 Lib "DinkeyChange64.dll" Alias "DCDownloadTempSoftwareKey" (ByVal machineID As UInt32, ByRef extended_error As Integer) As Integer + Declare Ansi Function DCDownloadDemoSoftwareKey64 Lib "DinkeyChange64.dll" Alias "DCDownloadDemoSoftwareKey" (ByVal machineID As UInt32, ByVal prodcode As String, ByVal model As Integer, ByRef extended_error As Integer) As Integer + + 'routines that ensure the relevant dll is called depending on whether we are running on 32-bit or 64-bit Windows + Function DCGetInfo(ByVal type_mask As Integer, ByVal model_mask As Integer, ByVal prodcode_mask As String, ByVal array_length As Integer, _ + ByRef num_found As Integer, ByVal type_array() As Integer, ByVal model_array() As Integer, ByVal prodcode_array() As Byte, ByVal dongle_number() As UInt32, ByVal update_number() As Integer) As Integer + If (IntPtr.Size = 4) Then + DCGetInfo = DCGetInfo32(type_mask, model_mask, prodcode_mask, array_length, num_found, type_array, model_array, prodcode_array, dongle_number, update_number) + Else + DCGetInfo = DCGetInfo64(type_mask, model_mask, prodcode_mask, array_length, num_found, type_array, model_array, prodcode_array, dongle_number, update_number) + End If + End Function + + Function DCGetDiagnosticInfo(ByVal filename As String) As Integer + If (IntPtr.Size = 4) Then + DCGetDiagnosticInfo = DCGetDiagnosticInfo32(filename) + Else + DCGetDiagnosticInfo = DCGetDiagnosticInfo64(filename) + End If + End Function + + Function DCDoUpdateCodeString(ByVal update_code_string As String, ByRef confirmation_code As Integer, ByRef extended_error As Integer) As Integer + If (IntPtr.Size = 4) Then + DCDoUpdateCodeString = DCDoUpdateCodeString32(update_code_string, confirmation_code, extended_error) + Else + DCDoUpdateCodeString = DCDoUpdateCodeString64(update_code_string, confirmation_code, extended_error) + End If + End Function + + Function DCDoUpdateCodeFromFile(ByVal filename As String, ByRef confirmation_code As Integer, ByRef extended_error As Integer) As Integer + If (IntPtr.Size = 4) Then + DCDoUpdateCodeFromFile = DCDoUpdateCodeFromFile32(filename, confirmation_code, extended_error) + Else + DCDoUpdateCodeFromFile = DCDoUpdateCodeFromFile64(filename, confirmation_code, extended_error) + End If + End Function + + Function DCRestoreDinkeyFDLite() As Integer + If (IntPtr.Size = 4) Then + DCRestoreDinkeyFDLite = DCRestoreDinkeyFDLite32() + Else + DCRestoreDinkeyFDLite = DCRestoreDinkeyFDLite64() + End If + End Function + + Function DCGetMachineID(ByRef machineID As UInt32, ByRef extended_error As Integer) As Integer + If (IntPtr.Size = 4) Then + DCGetMachineID = DCGetMachineID32(machineID, extended_error) + Else + DCGetMachineID = DCGetMachineID64(machineID, extended_error) + End If + End Function + + Function DCDownloadTempSoftwareKey(ByVal machineID As UInt32, ByRef extended_error As Integer) As Integer + If (IntPtr.Size = 4) Then + DCDownloadTempSoftwareKey = DCDownloadTempSoftwareKey32(machineID, extended_error) + Else + DCDownloadTempSoftwareKey = DCDownloadTempSoftwareKey64(machineID, extended_error) + End If + End Function + + Function DCDownloadDemoSoftwareKey(ByVal machineID As UInt32, ByVal prodcode As String, ByVal model As Integer, ByRef extended_error As Integer) As Integer + If (IntPtr.Size = 4) Then + DCDownloadDemoSoftwareKey = DCDownloadDemoSoftwareKey32(machineID, prodcode, model, extended_error) + Else + DCDownloadDemoSoftwareKey = DCDownloadDemoSoftwareKey64(machineID, prodcode, model, extended_error) + End If + End Function + + ' routine to extract product code string from array of product codes + Function GetProductCode(ByRef prodcode() As Byte, ByVal index As Integer) As String + Dim i As Integer + Dim ascii As New ASCIIEncoding() + + For i = 0 To 8 + If prodcode((index * 9) + i) = 0 Then + Exit For + End If + Next + Return ascii.GetString(prodcode, index * 9, i) + End Function + + ' maximum number of USB devices that can be attached to a machine at any time + Public Const MAX_USB_DEVICES As Integer = 128 + Public Const MAX_PRODCODE_LEN As Integer = 9 + + ' mask values + Public Const TYPE_MASK_PRO As Integer = 1 + Public Const TYPE_MASK_FD As Integer = 2 + Public Const TYPE_MASK_ALL As Integer = TYPE_MASK_PRO Or TYPE_MASK_FD + + Public Const MODEL_MASK_LITE As Integer = 1 + Public Const MODEL_MASK_PLUS As Integer = 2 + Public Const MODEL_MASK_NET As Integer = 4 + Public Const MODEL_MASK_ALL As Integer = MODEL_MASK_LITE Or MODEL_MASK_PLUS Or MODEL_MASK_NET + Public Const MODEL_MASK_DEFAULT As Integer = MODEL_MASK_PLUS Or MODEL_MASK_NET + + ' type values for DCGetInfo (returned in the array) + Public Const TYPE_PRO As Integer = 1 + Public Const TYPE_FD As Integer = 2 + + ' model values for DCGetInfo (returned in the array) + Public Const MODEL_LITE As Integer = 1 + Public Const MODEL_PLUS As Integer = 2 + Public Const MODEL_NET5 As Integer = 4 + Public Const MODEL_NETU As Integer = 7 + + ' model values for DCDownloadDemoSoftwareKey + Public Const SWKEY_MODEL_DEFAULT As Integer = &HFFFFFFFF ' NB this assumes that the Demo Software Key Template was created with only one valid dongle model + Public Const SWKEY_MODEL_PRO_LITE As Integer = 0 + Public Const SWKEY_MODEL_PRO_PLUS As Integer = 1 + Public Const SWKEY_MODEL_PRO_NET As Integer = 2 + Public Const SWKEY_MODEL_FD_LITE As Integer = 3 + Public Const SWKEY_MODEL_FD_PLUS As Integer = 4 + Public Const SWKEY_MODEL_FD_NET As Integer = 5 + +End Module + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyChange/Form1.resx b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyChange/Form1.resx new file mode 100644 index 0000000..3c1fe23 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyChange/Form1.resx @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + False + + + Assembly + + + Assembly + + + False + + + Assembly + + + Assembly + + + Assembly + + + False + + + Assembly + + + False + + + Assembly + + + Assembly + + + False + + + Assembly + + + Assembly + + + Assembly + + + False + + + Assembly + + + False + + + Assembly + + + Assembly + + + False + + + Assembly + + + Assembly + + + Assembly + + + False + + + Assembly + + + False + + + Assembly + + + Assembly + + + False + + + Assembly + + + Assembly + + + False + + + Assembly + + + Assembly + + + False + + + Assembly + + + Assembly + + + Assembly + + + False + + + Assembly + + + False + + + (Default) + + + False + + + Form1 + + + False + + + 8, 8 + + + True + + + 80 + + + True + + + Assembly + + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyChange/Form1.vb b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyChange/Form1.vb new file mode 100644 index 0000000..11f2263 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyChange/Form1.vb @@ -0,0 +1,458 @@ +' !! We strongly recommend that you read the "readme.txt" file in the sample code folder. +' !! It contains important instructions on how to use the sample code + +Imports System.Text + +Public Class Form1 + Inherits System.Windows.Forms.Form + +#Region " Windows Form Designer generated code " + + Public Sub New() + MyBase.New() + + 'This call is required by the Windows Form Designer. + InitializeComponent() + + 'Add any initialization after the InitializeComponent() call + + End Sub + + 'Form overrides dispose to clean up the component list. + Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) + If disposing Then + If Not (components Is Nothing) Then + components.Dispose() + End If + End If + MyBase.Dispose(disposing) + End Sub + + 'Required by the Windows Form Designer + Private components As System.ComponentModel.IContainer + + 'NOTE: The following procedure is required by the Windows Form Designer + 'It can be modified using the Windows Form Designer. + 'Do not modify it using the code editor. + Friend WithEvents GetDongleInfo As System.Windows.Forms.Button + Friend WithEvents label1 As System.Windows.Forms.Label + Friend WithEvents DiagFilename As System.Windows.Forms.TextBox + Friend WithEvents WriteDiags As System.Windows.Forms.Button + Friend WithEvents DoUpdateCodeString As System.Windows.Forms.Button + Friend WithEvents UpdateCodeString As System.Windows.Forms.TextBox + Friend WithEvents Label2 As System.Windows.Forms.Label + Friend WithEvents DoUpdateCodeFile As System.Windows.Forms.Button + Friend WithEvents Label3 As System.Windows.Forms.Label + Friend WithEvents UpdateCodeFile As System.Windows.Forms.TextBox + Friend WithEvents RestoreFDLite As System.Windows.Forms.Button + Friend WithEvents GetMachineID As System.Windows.Forms.Button + Friend WithEvents DownloadTempSoftwareKey As System.Windows.Forms.Button + Friend WithEvents ShowMachineID As System.Windows.Forms.TextBox + Friend WithEvents label4 As System.Windows.Forms.Label + Friend WithEvents ProdCode As System.Windows.Forms.TextBox + Friend WithEvents DownloadDemoSoftwareKey As System.Windows.Forms.Button + Private Sub InitializeComponent() + Me.GetDongleInfo = New System.Windows.Forms.Button + Me.label1 = New System.Windows.Forms.Label + Me.DiagFilename = New System.Windows.Forms.TextBox + Me.WriteDiags = New System.Windows.Forms.Button + Me.DoUpdateCodeString = New System.Windows.Forms.Button + Me.UpdateCodeString = New System.Windows.Forms.TextBox + Me.Label2 = New System.Windows.Forms.Label + Me.DoUpdateCodeFile = New System.Windows.Forms.Button + Me.UpdateCodeFile = New System.Windows.Forms.TextBox + Me.Label3 = New System.Windows.Forms.Label + Me.RestoreFDLite = New System.Windows.Forms.Button + Me.GetMachineID = New System.Windows.Forms.Button + Me.DownloadTempSoftwareKey = New System.Windows.Forms.Button + Me.ShowMachineID = New System.Windows.Forms.TextBox + Me.label4 = New System.Windows.Forms.Label + Me.ProdCode = New System.Windows.Forms.TextBox + Me.DownloadDemoSoftwareKey = New System.Windows.Forms.Button + Me.SuspendLayout() + ' + 'GetDongleInfo + ' + Me.GetDongleInfo.Location = New System.Drawing.Point(48, 24) + Me.GetDongleInfo.Name = "GetDongleInfo" + Me.GetDongleInfo.Size = New System.Drawing.Size(216, 24) + Me.GetDongleInfo.TabIndex = 0 + Me.GetDongleInfo.Text = "Get Dongle Information" + ' + 'label1 + ' + Me.label1.Location = New System.Drawing.Point(16, 72) + Me.label1.Name = "label1" + Me.label1.Size = New System.Drawing.Size(296, 16) + Me.label1.TabIndex = 1 + Me.label1.Text = "Enter diagnostic filename:" + ' + 'DiagFilename + ' + Me.DiagFilename.Location = New System.Drawing.Point(16, 88) + Me.DiagFilename.Name = "DiagFilename" + Me.DiagFilename.Size = New System.Drawing.Size(288, 20) + Me.DiagFilename.TabIndex = 2 + Me.DiagFilename.Text = "" + ' + 'WriteDiags + ' + Me.WriteDiags.Location = New System.Drawing.Point(56, 120) + Me.WriteDiags.Name = "WriteDiags" + Me.WriteDiags.Size = New System.Drawing.Size(192, 23) + Me.WriteDiags.TabIndex = 3 + Me.WriteDiags.Text = "Write Diagnostics to File" + ' + 'Label2 + ' + Me.Label2.Location = New System.Drawing.Point(16, 171) + Me.Label2.Name = "Label2" + Me.Label2.Size = New System.Drawing.Size(296, 16) + Me.Label2.TabIndex = 4 + Me.Label2.Text = "Enter short Update Code here:" + ' + 'UpdateCodeString + ' + Me.UpdateCodeString.Location = New System.Drawing.Point(16, 187) + Me.UpdateCodeString.Name = "UpdateCodeString" + Me.UpdateCodeString.Size = New System.Drawing.Size(288, 20) + Me.UpdateCodeString.TabIndex = 5 + Me.UpdateCodeString.Text = "" + ' + 'DoUpdateCodeString + ' + Me.DoUpdateCodeString.Location = New System.Drawing.Point(56, 219) + Me.DoUpdateCodeString.Name = "DoUpdateCodeString" + Me.DoUpdateCodeString.Size = New System.Drawing.Size(192, 23) + Me.DoUpdateCodeString.TabIndex = 6 + Me.DoUpdateCodeString.Text = "Make Changes" + ' + 'Label3 + ' + Me.Label3.Location = New System.Drawing.Point(16, 272) + Me.Label3.Name = "Label3" + Me.Label3.Size = New System.Drawing.Size(296, 16) + Me.Label3.TabIndex = 7 + Me.Label3.Text = "Enter path to Update Code file:" + ' + 'UpdateCodeFile + ' + Me.UpdateCodeFile.Location = New System.Drawing.Point(16, 288) + Me.UpdateCodeFile.Name = "UpdateCodeFile" + Me.UpdateCodeFile.Size = New System.Drawing.Size(288, 20) + Me.UpdateCodeFile.TabIndex = 8 + Me.UpdateCodeFile.Text = "" + ' + 'DoUpdateCodeFile + ' + Me.DoUpdateCodeFile.Location = New System.Drawing.Point(56, 320) + Me.DoUpdateCodeFile.Name = "DoUpdateCodeFile" + Me.DoUpdateCodeFile.Size = New System.Drawing.Size(192, 23) + Me.DoUpdateCodeFile.TabIndex = 9 + Me.DoUpdateCodeFile.Text = "Make Changes" + ' + 'RestoreFDLite + ' + Me.RestoreFDLite.Location = New System.Drawing.Point(56, 376) + Me.RestoreFDLite.Name = "RestoreFDLite" + Me.RestoreFDLite.Size = New System.Drawing.Size(192, 23) + Me.RestoreFDLite.TabIndex = 10 + Me.RestoreFDLite.Text = "Restore FD Lite" + ' + 'GetMachineID + ' + Me.GetMachineID.Location = New System.Drawing.Point(24, 432) + Me.GetMachineID.Name = "GetMachineID" + Me.GetMachineID.Size = New System.Drawing.Size(128, 23) + Me.GetMachineID.TabIndex = 11 + Me.GetMachineID.Text = "Get Machine ID" + ' + 'ShowMachineID + ' + Me.ShowMachineID.Location = New System.Drawing.Point(168, 432) + Me.ShowMachineID.Name = "ShowMachineID" + Me.ShowMachineID.Size = New System.Drawing.Size(136, 20) + Me.ShowMachineID.TabIndex = 12 + Me.ShowMachineID.Text = "" + ' + 'DownloadTempSoftwareKey + ' + Me.DownloadTempSoftwareKey.Location = New System.Drawing.Point(56, 488) + Me.DownloadTempSoftwareKey.Name = "DownloadTempSoftwareKey" + Me.DownloadTempSoftwareKey.Size = New System.Drawing.Size(192, 23) + Me.DownloadTempSoftwareKey.TabIndex = 13 + Me.DownloadTempSoftwareKey.Text = "Download Temporary Software Key" + ' + 'label4 + ' + Me.label4.Location = New System.Drawing.Point(16, 541) + Me.label4.Name = "label4" + Me.label4.Size = New System.Drawing.Size(296, 16) + Me.label4.TabIndex = 14 + Me.label4.Text = "Demo Software Key Product Code:" + ' + 'ProdCode + ' + Me.ProdCode.Location = New System.Drawing.Point(16, 557) + Me.ProdCode.Name = "ProdCode" + Me.ProdCode.Size = New System.Drawing.Size(288, 20) + Me.ProdCode.TabIndex = 15 + Me.ProdCode.Text = "" + ' + 'DownloadTempSoftwareKey + ' + Me.DownloadDemoSoftwareKey.Location = New System.Drawing.Point(56, 590) + Me.DownloadDemoSoftwareKey.Name = "DownloadDemoSoftwareKey" + Me.DownloadDemoSoftwareKey.Size = New System.Drawing.Size(192, 23) + Me.DownloadDemoSoftwareKey.TabIndex = 16 + Me.DownloadDemoSoftwareKey.Text = "Download Demo Software Key" + ' + 'Form1 + ' + Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13) + Me.ClientSize = New System.Drawing.Size(320, 636) + Me.Controls.Add(Me.DownloadDemoSoftwareKey) + Me.Controls.Add(Me.ProdCode) + Me.Controls.Add(Me.label4) + Me.Controls.Add(Me.ShowMachineID) + Me.Controls.Add(Me.DownloadTempSoftwareKey) + Me.Controls.Add(Me.GetMachineID) + Me.Controls.Add(Me.RestoreFDLite) + Me.Controls.Add(Me.DoUpdateCodeFile) + Me.Controls.Add(Me.UpdateCodeFile) + Me.Controls.Add(Me.Label3) + Me.Controls.Add(Me.DoUpdateCodeString) + Me.Controls.Add(Me.UpdateCodeString) + Me.Controls.Add(Me.Label2) + Me.Controls.Add(Me.WriteDiags) + Me.Controls.Add(Me.DiagFilename) + Me.Controls.Add(Me.label1) + Me.Controls.Add(Me.GetDongleInfo) + Me.Name = "Form1" + Me.Text = "ChangeTest" + Me.ResumeLayout(False) + + End Sub + +#End Region + + ' Get Dongle Information + Private Sub GetDongleInfo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles GetDongleInfo.Click + Dim sType, sModel, sProdCode, sDisplay As String + Dim ret_code, i, num_found As Integer + ' our arrays + Dim type(MAX_USB_DEVICES), model(MAX_USB_DEVICES), update_number(MAX_USB_DEVICES) As Integer + Dim prodcode(MAX_USB_DEVICES * MAX_PRODCODE_LEN) As Byte + Dim dongle_number(MAX_USB_DEVICES) As UInt32 + + ' find dongle information for all dongle types, Plus & Net models, for all product codes + ' NB In practice you will probably want to set the prodcode_mask to the value of your product code + ret_code = DCGetInfo(TYPE_MASK_ALL, MODEL_MASK_DEFAULT, Nothing, MAX_USB_DEVICES, num_found, type, model, prodcode, dongle_number, update_number) + + ' check error code and display error if an error occurs + If ret_code = 401 Then + MsgBox("No dongles detected matching the search criteria specified", MsgBoxStyle.OkOnly, "Error") + Exit Sub + ElseIf ret_code <> 0 Then + MsgBox("Error " + Str(ret_code) + " getting dongle information", MsgBoxStyle.OkOnly, "Error") + Exit Sub + End If + + ' display info from the dongles detected + sDisplay = "" + For i = 0 To num_found - 1 + ' get type of dongle + If type(i) = TYPE_PRO Then + sType = "Pro" + Else + sType = "FD" + End If + ' get model of dongle + If model(i) = MODEL_LITE Then + sModel = "Lite" + ElseIf model(i) = MODEL_PLUS Then + sModel = "Plus" + Else + sModel = "Net" + End If + ' get product code + sProdCode = GetProductCode(prodcode, i) + sDisplay = sDisplay + Str(i + 1) + ". Dinkey " + sType + " " + sModel + " with dongle number: " + dongle_number(i).ToString + ", product code: " + sProdCode + ", update number: " + Str(update_number(i)) + vbNewLine + Next + MsgBox(sDisplay, MsgBoxStyle.OkOnly, "Dongle Information") + End Sub + + + ' Write Dongle Diagnostics to file + Private Sub WriteDiags_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles WriteDiags.Click + Dim ret_code As Integer + + ret_code = DCGetDiagnosticInfo(DiagFilename.Text) + + ' check error code and display error if an error occurs + If ret_code = 754 Then + MsgBox("Could not create the diagnostic file. Please check that the path exists: " + DiagFilename.Text, MsgBoxStyle.OkOnly, "Error") + Exit Sub + ElseIf ret_code <> 0 Then + MsgBox("Error " + Str(ret_code) + " writing diagnostic information", MsgBoxStyle.OkOnly, "Error") + Exit Sub + End If + + ' display success + MsgBox("Diagnostic file written successfully.", MsgBoxStyle.OkOnly, "Dongle Information") + End Sub + + + ' Apply short update code entered manually + Private Sub DoUpdateCodeString_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DoUpdateCodeString.Click + Dim ret_code, confirmation_code, extended_error As Integer + + ret_code = DCDoUpdateCodeString(UpdateCodeString.Text, confirmation_code, extended_error) + + ' check error code and display error if an error occurs + If ret_code <> 0 Then + DisplayError(ret_code, extended_error) + Exit Sub + End If + + ' display success + MsgBox("Dongle updated successfully!" + vbNewLine + "Confirmation code is : " + Hex(confirmation_code), MsgBoxStyle.OkOnly, "Dongle Information") + End Sub + + Private Sub DoUpdateCodeFile_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DoUpdateCodeFile.Click + Dim ret_code, confirmation_code, extended_error As Integer + + ret_code = DCDoUpdateCodeFromFile(UpdateCodeFile.Text, confirmation_code, extended_error) + + ' check error code and display error if an error occurs + If ret_code <> 0 Then + DisplayError(ret_code, extended_error) + Exit Sub + End If + + ' display success + MsgBox("Dongle updated successfully!" + vbNewLine + "Confirmation code is : " + Hex(confirmation_code), MsgBoxStyle.OkOnly, "Dongle Information") + End Sub + + Private Sub RestoreFDLite_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RestoreFDLite.Click + Dim ret_code As Integer + + ret_code = DCRestoreDinkeyFDLite() + + ' check error code and display error if an error occurs + If ret_code <> 0 Then + DisplayError(ret_code, 0) + Exit Sub + End If + + ' display success + MsgBox("Dinkey FD Lite updated successfully!", MsgBoxStyle.OKOnly, "Dongle Information") + End Sub + + Private Sub GetMachineID_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles GetMachineID.Click + Dim ret_code, extended_error As Integer + Dim machineID As UInt32 + + ret_code = DCGetMachineID(machineID, extended_error) + + ' check error code and display error if an error occurs + If ret_code <> 0 Then + DisplayError(ret_code, extended_error) + Exit Sub + End If + + ' success - display the machineID + ShowMachineID.Text = String.Format("{0:X8}", machineID) + End Sub + + Private Sub DownloadTempSoftwareKey_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DownloadTempSoftwareKey.Click + Dim ret_code, extended_error As Integer + Dim machineID As UInt32 + + ' first get the machine ID + ret_code = DCGetMachineID(machineID, extended_error) + + ' check error code and display error if an error occurs + If ret_code <> 0 Then + DisplayError(ret_code, extended_error) + Exit Sub + End If + + ' ...then try to download the temporary software key + ret_code = DCDownloadTempSoftwareKey(machineID, extended_error) + + ' check error code and display error if an error occurs + If ret_code <> 0 Then + DisplayError(ret_code, extended_error) + Exit Sub + End If + + MsgBox("The Temporary Software Key has been downloaded successfully!", MsgBoxStyle.OKOnly, "Dongle Information") + End Sub + + Private Sub DownloadDemoSoftwareKey_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DownloadDemoSoftwareKey.Click + Dim ret_code, extended_error As Integer + Dim machineID As UInt32 + + ' first get the machine ID + ret_code = DCGetMachineID(machineID, extended_error) + + ' check error code and display error if an error occurs + If ret_code <> 0 Then + DisplayError(ret_code, extended_error) + Exit Sub + End If + + ' ...then try to download the demo software key + ' (NB we are assuming only one dongle model is set in the Demo Software Template. + ' If multiple models are set you will also need to specify the exact model) + ret_code = DCDownloadDemoSoftwareKey(machineID, ProdCode.Text, SWKEY_MODEL_DEFAULT, extended_error) + + ' check error code and display error if an error occurs + If ret_code <> 0 Then + DisplayError(ret_code, extended_error) + Exit Sub + End If + + MsgBox("The Demo Software Key has been downloaded successfully!", MsgBoxStyle.OKOnly, "Dongle Information") + End Sub + + ' look at the error code and try to display an appropriate message + Private Sub DisplayError(ByVal ret_code As Integer, ByVal extended_error As Integer) + Select Case ret_code + Case 401 + MsgBox("Error! No dongles detected that meet the search criteria", MsgBoxStyle.OkOnly, "Error") + Case 409 + MsgBox("Error! The dongle detected has not been programmed by DinkeyAdd.", MsgBoxStyle.OkOnly, "Error") + Case 758 + MsgBox("Error! Cannot open the Update Code file specified.", MsgBoxStyle.OkOnly, "Error") + Case 759 + MsgBox("Error! The file specified is not a valid Update Code file.", MsgBoxStyle.OkOnly, "Error") + Case 762, 763, 764 + MsgBox("Error! Update Code is not in a correct format / update code file is corrupt.", MsgBoxStyle.OkOnly, "Error") + Case 765 + MsgBox("Error! The Update Code does not match any dongle attached to your machine.", MsgBoxStyle.OkOnly, "Error") + Case 766 + MsgBox("Error! The update number for this Update Code is too high. You need to first enter an update code that was previously sent to you.", MsgBoxStyle.OkOnly, "Error") + Case 767 + MsgBox("Error! You have already entered this Update Code.", MsgBoxStyle.OkOnly, "Error") + Case 1905 + MsgBox("Error! There is no Software Key available for download.", MsgBoxStyle.OkOnly, "Error") + Case 1907 + MsgBox("Error! The Temporary Software Key has expired. Cannot download it.", MsgBoxStyle.OkOnly, "Error") + Case 1910 + MsgBox("Error! The Software Key has already been downloaded.", MsgBoxStyle.OkOnly, "Error") + Case 1921 + MsgBox("Error! You specified the 'default model' but there is more than one model available. You need to specify a specific dongle model.", MsgBoxStyle.OkOnly, "Error") + Case 1922: + MsgBox("Error! The model you requested is not available.", MsgBoxStyle.OkOnly, "Error") + Case 1923: + MsgBox("Error! The Demo Software Key Template has been disabled.", MsgBoxStyle.OkOnly, "Error") + Case 1924: + MsgBox("Error! You have run out of Demo Software Key activations. You need to order some more.", MsgBoxStyle.OkOnly, "Error") + Case Else + MsgBox("An error occurred checking the dongle. Error: " + Str(ret_code) + ". Extended Error: " + Str(extended_error) + ".", MsgBoxStyle.OkOnly, "Error") + End Select + End Sub + +End Class diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyChange/README.txt b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyChange/README.txt new file mode 100644 index 0000000..9ccdf8f --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyChange/README.txt @@ -0,0 +1,61 @@ +ChangeTest - sample code to call DinkeyChange.dll (DinkeyChange64.dll) in VB.NET +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 2003 but will work in more recent versions of +Visual Studio (they will upgrade the Project to the latest version. If prompted you +should also upgrade the .NET framework the project requires). + +For users of Visual Studio 2005 or higher, the default setting to projects is to compile +for the Target Platform "Any". This means that on 32-bit Windows, your code will run as +32-bit code (and needs to call DinkeyChange.dll) and under 64-bit Windows your code will +run as 64-bit code (and needs to call DinkeyChange64.dll). The sample code works this out +automatically. If you select the target platform as "x86" then it will always be 32-bit +and so you only need to use DinkeyChange.dll. If you select "x64" then your code will be +64-bit and you only need to use DinkeyChange64.dll. + +The main source files in the project are: + +DinkeyChange.vb - the source file contains declarations of our API. We automatically + work out whether your code is running in 32-bit or 64-bit and load the + appropriate DinkeyChange module. + +Form1.vb - this is the sample code giving an example on how you can call our API. + It contains 7 functions. Just use which ever functions are most appropriate + and customise in your own way. + +The best approach is to compile the sample code and see how it works and then to take the +appropriate code and apply it to your own project. You should include the DinkeyChange.vb +file in your project and use/modify which ever functions from Form1.vb you feel are +appropriate. The DinkeyChange.vb file should not be modified. + +The sample code is just a guide. As none of the parameters are security sensitive then +there is no need to implement strong security in calling DinkeyChange. + +Make sure you remember to do the following when creating your own project: + +1) Insert the DinkeyChange.vb file in your project. + +2) You need to put DinkeyChange.dll and/or DinkeyChange64.dll into the folder that +contains your EXE file. Otherwise the message "Unable to open DLL (DinkeyChange.dll)" or +the System.DllNotFoundException error will appear when you run ChangeTest. + +You can rename DinkeyChange.dll (DinkeyChange64.dll) to a name of your choice. In this +case you will need to modify the dll name in the DinkeyChange.vb file. + +Notes on Debugging 64-bit Code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +When you use the 64-bit module (DinkeyChange64.dll) the anti-debug code is so strong that +if you are debugging your code, after calling our API then it will crash with an SEH +exception. If you want to be able to debug your code then you can setup your project so +that your code calls the debug module (DinkeyChange64Debug.dll) in your "debug" build and +the standard module (DinkeyChange64.dll) in your release build. In this case you will +need to modify the declarations of our API in DinkeyChange.vb. This is an example for +DCDoUpdateCodeFromFile64: + +#if DEBUG ' debug module + Declare Ansi Function DCDoUpdateCodeFromFile64 Lib "DinkeyChange64Debug.dll" Alias "DCDoUpdateCodeFromFile" _ + (ByVal filename As String, ByRef confirmation_code As Integer, ByRef extended_error As Integer) As Integer +#else ' standard module + Declare Ansi Function DCDoUpdateCodeFromFile64 Lib "DinkeyChange64.dll" Alias "DCDoUpdateCodeFromFile" _ + (ByVal filename As String, ByRef confirmation_code As Integer, ByRef extended_error As Integer) As Integer +#endif diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyRemote/AssemblyInfo.vb b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyRemote/AssemblyInfo.vb new file mode 100644 index 0000000..28d946b --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyRemote/AssemblyInfo.vb @@ -0,0 +1,31 @@ +Imports System.Reflection +Imports System.Runtime.InteropServices + +' General Information about an assembly is controlled through the following +' set of attributes. Change these attribute values to modify the information +' associated with an assembly. + +' Review the values of the assembly attributes + + + + + + + + + +'The following GUID is for the ID of the typelib if this project is exposed to COM + + +' Version information for an assembly consists of the following four values: +' +' Major Version +' Minor Version +' Build Number +' Revision +' +' You can specify all the values or you can default the Build and Revision Numbers +' by using the '*' as shown below: + + diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyRemote/Form1.resx b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyRemote/Form1.resx new file mode 100644 index 0000000..ed1cd0f --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyRemote/Form1.resx @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Assembly + + + Form1 + + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyRemote/Form1.vb b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyRemote/Form1.vb new file mode 100644 index 0000000..a479e8e --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyRemote/Form1.vb @@ -0,0 +1,179 @@ +' !! We strongly recommend that you read the "readme.txt" file in the sample code folder. +' !! It contains important instructions on how to use the sample code + +Imports System.Runtime.InteropServices ' so we can marshal our structures in drpf.vb + + +Public Class Form1 + Inherits System.Windows.Forms.Form + + Public Const AppName As String = "drpfTest" + +#Region " Windows Form Designer generated code " + + Public Sub New() + MyBase.New() + + 'This call is required by the Windows Form Designer. + InitializeComponent() + + 'Add any initialization after the InitializeComponent() call + + End Sub + + 'Form overrides dispose to clean up the component list. + Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) + If disposing Then + If Not (components Is Nothing) Then + components.Dispose() + End If + End If + MyBase.Dispose(disposing) + End Sub + + 'Required by the Windows Form Designer + Private components As System.ComponentModel.IContainer + + 'NOTE: The following procedure is required by the Windows Form Designer + 'It can be modified using the Windows Form Designer. + 'Do not modify it using the code editor. + Friend WithEvents updatecodeMod As System.Windows.Forms.Button + Friend WithEvents updatecode As System.Windows.Forms.Button + Friend WithEvents drpfFile As System.Windows.Forms.TextBox + Friend WithEvents label1 As System.Windows.Forms.Label + Private Sub InitializeComponent() + Me.updatecodeMod = New System.Windows.Forms.Button + Me.updatecode = New System.Windows.Forms.Button + Me.drpfFile = New System.Windows.Forms.TextBox + Me.label1 = New System.Windows.Forms.Label + Me.SuspendLayout() + ' + 'updatecodeMod + ' + Me.updatecodeMod.Location = New System.Drawing.Point(88, 128) + Me.updatecodeMod.Name = "updatecodeMod" + Me.updatecodeMod.Size = New System.Drawing.Size(264, 23) + Me.updatecodeMod.TabIndex = 7 + Me.updatecodeMod.Text = "Generate Update Code with modifications " + ' + 'updatecode + ' + Me.updatecode.Location = New System.Drawing.Point(88, 88) + Me.updatecode.Name = "updatecode" + Me.updatecode.Size = New System.Drawing.Size(264, 23) + Me.updatecode.TabIndex = 6 + Me.updatecode.Text = "Generate Update Code" + ' + 'drpfFile + ' + Me.drpfFile.Location = New System.Drawing.Point(8, 40) + Me.drpfFile.Name = "drpfFile" + Me.drpfFile.Size = New System.Drawing.Size(424, 20) + Me.drpfFile.TabIndex = 5 + Me.drpfFile.Text = "" + ' + 'label1 + ' + Me.label1.Location = New System.Drawing.Point(8, 24) + Me.label1.Name = "label1" + Me.label1.Size = New System.Drawing.Size(440, 16) + Me.label1.TabIndex = 4 + Me.label1.Text = "Full path of drpf file:" + ' + 'Form1 + ' + Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13) + Me.ClientSize = New System.Drawing.Size(456, 174) + Me.Controls.Add(Me.updatecodeMod) + Me.Controls.Add(Me.updatecode) + Me.Controls.Add(Me.drpfFile) + Me.Controls.Add(Me.label1) + Me.Name = "Form1" + Me.Text = "Form1" + Me.ResumeLayout(False) + + End Sub + +#End Region + + ' The sample code contains 2 functions. Use which ever functions are most appropriate and customise + ' in your own way. The sample code is just a guide. + ' + ' There are two methods to loading a DRPF file. These are shown in the these two functions + ' updatecode_Click and updatecodeMod_Click: + ' + ' updatecode_Click: we load the DRPF file from disk and get a handle and use it "as is" using the API + ' call LoadDRPFFromFile. You can make some limited changes to overwrite the default + ' behaviour by using API flags. + ' + ' updatecodeMod_Click: we load the DRPF file from disk and load into structures. We can then modify the + ' DRPF settings by modifying this structure. This method uses the API calls + ' ReadDRPFEx and LoadDRPF. + + + Private Sub updatecode_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles updatecode.Click + Dim drpfHandle As IntPtr + Dim err_code As Integer + Dim Outputs As New UPDATE_CODE_OUTPUTS + + ' load DRPF from File into memory + drpfHandle = LoadDRPFFromFile(drpfFile.Text, err_code) + If IntPtr.Zero.Equals(drpfHandle) Then + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, AppName) + Exit Sub + End If + + ' generate update code as specified by the DRPF file + err_code = GenerateUpdateCode(drpfHandle, Convert.ToUInt32(0), 0, Nothing, Nothing, Outputs) + + ' Unload DRPF from memory + UnloadDRPF(drpfHandle) + + ' display message (error or success) + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Information, AppName) + End Sub +#If VBC_VER >= 14 Then + #Disable Warning BC42108, BC42030 'This line is used in Visual Studio 2015 (and newer) to remove warnings in this function +#End If + Private Sub updatecodeMod_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles updatecodeMod.Click + Dim drpfHandle As IntPtr + Dim err_code, dummy1, dummy2 As Integer + Dim MyRemoteInfo As REMOTEINFO + Dim LicenceInfoArray() As LICENCEINFO + Dim AlgChangesArray() As ALGCHANGE + Dim DataChangesArray() As DATACHANGE + Dim Outputs As New UPDATE_CODE_OUTPUTS + + ' in this case we need to read the DRPF into our structures, so that the DRPF values can be modified + err_code = ReadDRPFEx(drpfFile.Text, MyRemoteInfo, LicenceInfoArray, AlgChangesArray, DataChangesArray, dummy1, dummy2) + If err_code <> 0 Then + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, AppName) + Exit Sub + End If + + ' patch new values + LicenceInfoArray(0).FeaturesFlag = 1 ' so that the features value below will be recognised + LicenceInfoArray(0).Features = Convert.ToUInt32(12345) + LicenceInfoArray(0).AddSetExecs = 1 ' so the executions will be added to existing + LicenceInfoArray(0).Execs = 100 + + ' get DRPF handle + drpfHandle = LoadDRPF(MyRemoteInfo, LicenceInfoArray, AlgChangesArray, DataChangesArray, err_code) + If IntPtr.Zero.Equals(drpfHandle) Then + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, AppName) + Exit Sub + End If + + ' generate update code as specified by the modified DRPF file + err_code = GenerateUpdateCode(drpfHandle, Convert.ToUInt32(0), 0, Nothing, Nothing, Outputs) + + ' Unload DRPF from memory + UnloadDRPF(drpfHandle) + + ' display message (error or success) + MsgBox(GetLastMessage(), MsgBoxStyle.OKOnly Or MsgBoxStyle.Information, AppName) + End Sub +#If VBC_VER >= 14 Then + #Enable Warning BC42108, BC42030 'This line is used in Visual Studio 2015 (and higher) to restore warnings +#End If +End Class diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyRemote/README.txt b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyRemote/README.txt new file mode 100644 index 0000000..3872cf7 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyRemote/README.txt @@ -0,0 +1,50 @@ +drpfTest - sample code to call DinkeyRemote Modules in VB.NET +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 2002 but will work in more recent +versions of Visual Studio (they will upgrade the Project to the latest version. +If prompted you should also upgrade the .NET framework the project requires). + +For users of Visual Studio 2005 or higher, the default setting to projects is to +compile for the Target Platform "Any". This means that on 32-bit Windows, your +code will run as 32-bit code (and needs to call DinkeyRemote32.dll) and under 64-bit +Windows your code will run as 64-bit code (and needs to call DinkeyRemote64.dll). +The sample code works this out automatically. If you select the target platform as "x86" +then it will always be 32-bit and so you only need to use DinkeyRemote32.dll. If you +select "x64" then your code will be 64-bit and you only need to use DinkeyRemote64.dll. + +The main source files in the project are: + +drpf.vb - the source file contains declarations of our API. We automatically + work out whether your code is running in 32-bit or 64-bit and load + the appropriate DinkeyRemote module. + +Form1.vb - this is the sample code giving an example on how you can call our API. + It contains 2 functions. Just use the function most appropriate for you + and customise in your own way. + +The best approach is to compile the sample code and see how it works and then to take +the appropriate code and apply it to your own project. You should include the drpf.vb +file in your project and use/modify which ever functions from Form1.vb you feel are +appropriate. The drpf.vb file should not be modified. + +The sample code is just a guide. As none of the parameters are security sensitive then +there is no need to implement strong security in calling DinkeyRemote. + +Make sure you remember to do the following when creating your own project: + +1) Insert the following namespaces in your code file: +using System.Runtime.InteropServices; + +2) Insert the drpf.cs file in your project. + +3) You need to put DinkeyRemote32.dll and/or DinkeyRemote64.dll into the folder that +contains drpfTest. Otherwise the message "Unable to open DLL (DinkeyRemote32.dll)" or +the System.DllNotFoundException error will appear when you run drpfTest. + +Notes on Debugging 64-bit Code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +When you use the 64-bit module (DinkeyRemote64.dll) the anti-debug code is so strong +that if you are debugging your code, after calling our API then it will crash with +an SEH exception. There are no debug modules for DinkeyRemote so you will have to +find other ways of debugging your code (for example taking out the call altogether). diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyRemote/drpf.vb b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyRemote/drpf.vb new file mode 100644 index 0000000..be6befd --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyRemote/drpf.vb @@ -0,0 +1,321 @@ +' !! this file should not be modified + +' DRPF file is in the following format: +' REMOTEINFO +' LICENCEINFO (however many are needed) +' ALGCHANGE (however many are needed) +' DATACHANGE blocks (however many are needed) - may refer to external files. + +' Remember: you only need to specify a value if you want to change it. Otherwise you +' specify the default "no change" setting. For most entries this is indicated by 0. +' However, for MaxNetUsers and LicenceNetUsers it is "-2" because 0 is a valid value to change to. + +Imports System +Imports System.Runtime.InteropServices ' so we can marshal our structures as a block of memory +Imports System.Text ' for StringBuilder + +' *********** define structures that make up the DRPF file ******************* + +Module drpf_code + + _ + Structure REMOTEINFO + Dim Header1 As Byte ' Should be set to "DRPF" = DinkeyRemote Parameter File + Dim Header2 As Byte + Dim Header3 As Byte + Dim Header4 As Byte + Dim Version As Integer ' version of this structure - currently 2 + _ + Dim ProdCode As String ' Product Code + Dim DongleNumber As UInt32 + Dim UpdateNumber As Integer + _ + Dim Notes As String ' user-defined notes + Dim NumLicences As Integer + Dim NumAlgs As Integer ' number of algs to set (incl r/w alg) + Dim NumDataChanges As Integer ' number of data change blocks specified + Dim DataAreaSize As Integer ' -1 = increase as necessary. specifies the new size of the data area + Dim PerLicence As Integer ' 0 = no change, 1 = per licence net users, 2 = per product net users + Dim MaxNetUsers As Integer ' product net users, unlimited = -1, no change = -2 + Dim LastUsedDay As Integer ' Day = 0 (only) -> no change + Dim LastUsedMonth As Integer + Dim LastUsedYear As Integer + _ + Dim DataEncKeyProdCode As String + Dim ChangeCodeType As Integer ' 0 = no change, bit0 = only accept secure codes, bit1 = accept secure & short codes + Dim CodeType As Integer ' type of code to generate. 0 = secure code, 1 = short code + _ + Dim OutputFileName As String ' name of file to output code to. Null (default) -> UpdateCode.ducf + Dim LockDongle As Integer ' 1 = lock dongle to user's computer + Dim ResetDongleLock As Integer ' 1 = reset the dongle lock so that the dongle can be locked to a new machine + End Structure + + _ + Structure LICENCEINFO + _ + Dim LicenceName As String ' licence name + Dim Action As Integer ' 0 = change, 1 = delete, 2 = add + Dim AddSetExecs As Integer ' 0 = no change to execs, 1 = add, 2 = set + Dim Execs As Integer ' -1 = no limit + Dim ExecsWarn As Integer ' 0 = remove warning, -1 = no change + Dim ExpiryDay As Integer ' -1 = no limit, 0 = no change + Dim ExpiryMonth As Integer + Dim ExpiryYear As Integer + Dim AddSetMaxDays As Integer ' 0 = no change, 1 = add, 2 = set + Dim MaxDays As Integer ' -1 = no limit + Dim DaysWarn As Integer ' 0 = remove warning, -1 = no change + Dim FeaturesFlag As Integer ' 0 = don't change features, 1 = change features + Dim Features As UInt32 ' all values OK + Dim LicenceNetUsers As Integer ' unlimited = -1, no change = -2 + End Structure + + _ + Structure ALGCHANGE + Dim alg_number As Integer ' number of algorithm to set (0 = r/w algorithm) + _ + Dim alg As Byte() ' coded form of algorithm + End Structure + + _ + Structure DATACHANGE + Dim type As Integer ' 1 = file, 2 = hex data, 3 = ascii, 4 = ascii null-term string + Dim offset As Integer ' offset in dongle data memory to write data + Dim length As Integer ' length of data to change + _ + Dim data As Byte() ' data to write OR name of data file depending on which method set + End Structure + + _ + Structure UPDATE_CODE_OUTPUTS + _ + Dim ShortCode As String ' the update code (for short update codes only) + _ + Dim UpdateCodeFile As String ' the output ducf that contains the update code + _ + Dim ConfirmationCode As String ' the confirmation code + End Structure + +' ********************** DinkeyRemote Module Imports ************************ + + ' Loads DRPF from disk and returns handle + Declare Ansi Function LoadDRPFFromFile32 Lib "DinkeyRemote32.dll" Alias "LoadDRPFFromFile" (ByVal drpf_file As String, ByRef err_code As Integer) As IntPtr + Declare Ansi Function LoadDRPFFromFile64 Lib "DinkeyRemote64.dll" Alias "LoadDRPFFromFile" (ByVal drpf_file As String, ByRef err_code As Integer) As IntPtr + + ' Loads DRPF from disk into structures supplied (so we can modify DRPF in memory) + Declare Ansi Function ReadDRPFEx32 Lib "DinkeyRemote32.dll" Alias "ReadDRPFEx" (ByVal drpf_file As String, ByRef MyRemoteInfo As REMOTEINFO, ByVal licence_bytes() As Byte, _ + ByVal algchange_bytes() As Byte, ByVal datachange_bytes() As Byte, ByRef drpf_version As Integer, ByRef drpf_format As Integer) As Integer + Declare Ansi Function ReadDRPFEx64 Lib "DinkeyRemote64.dll" Alias "ReadDRPFEx" (ByVal drpf_file As String, ByRef MyRemoteInfo As REMOTEINFO, ByVal licence_bytes() As Byte, _ + ByVal algchange_bytes() As Byte, ByVal datachange_bytes() As Byte, ByRef drpf_version As Integer, ByRef drpf_format As Integer) As Integer + + ' Loads DRPF from structures and returns a handle + Declare Ansi Function LoadDRPF32 Lib "DinkeyRemote32.dll" Alias "LoadDRPF" (ByRef MyRemoteInfo As REMOTEINFO, ByVal licence_bytes() As Byte, ByVal algchange_bytes() As Byte, _ + ByVal datachange_bytes() As Byte, ByRef ret_code As Integer) As IntPtr + Declare Ansi Function LoadDRPF64 Lib "DinkeyRemote64.dll" Alias "LoadDRPF" (ByRef MyRemoteInfo As REMOTEINFO, ByVal licence_bytes() As Byte, ByVal algchange_bytes() As Byte, _ + ByVal datachange_bytes() As Byte, ByRef ret_code As Integer) As IntPtr + + ' saves the DRPF file to disk + Declare Ansi Function WriteDRPFEx32 Lib "DinkeyRemote32.dll" Alias "WriteDRPFEx" (ByVal drpf_handle As IntPtr, ByVal drpf_file As String, ByVal drpf_format As Integer, _ + ByVal drpf_version As Integer, ByVal flags As Integer) As Integer + Declare Ansi Function WriteDRPFEx64 Lib "DinkeyRemote64.dll" Alias "WriteDRPFEx" (ByVal drpf_handle As IntPtr, ByVal drpf_file As String, ByVal drpf_format As Integer, _ + ByVal drpf_version As Integer, ByVal flags As Integer) As Integer + + ' unloads the DRPF file + Declare Ansi Sub UnloadDRPF32 Lib "DinkeyRemote32.dll" Alias "UnloadDRPF" (ByRef drpf_handle As IntPtr) + Declare Ansi Sub UnloadDRPF64 Lib "DinkeyRemote64.dll" Alias "UnloadDRPF" (ByRef drpf_handle As IntPtr) + + 'main functions + Declare Ansi Function GenerateUpdateCode32 Lib "DinkeyRemote32.dll" Alias "GenerateUpdateCode" (ByVal drpf_handle As IntPtr, ByVal dongle_number As UInt32, _ + ByVal update_number As Integer, ByVal ducf_file As String, ByVal logfile As String, ByRef Outputs As UPDATE_CODE_OUTPUTS) As Integer + Declare Ansi Function GenerateUpdateCode64 Lib "DinkeyRemote64.dll" Alias "GenerateUpdateCode" (ByVal drpf_handle As IntPtr, ByVal dongle_number As UInt32, _ + ByVal update_number As Integer, ByVal ducf_file As String, ByVal logfile As String, ByRef Outputs As UPDATE_CODE_OUTPUTS) As Integer + + ' get the message output by DinkeyRemote + Declare Ansi Sub GetLastMessage32 Lib "DinkeyRemote32.dll" Alias "GetLastMessage" (ByVal message As StringBuilder, ByVal buffer_size As Integer, ByRef message_length As Integer) + Declare Ansi Sub GetLastMessage64 Lib "DinkeyRemote64.dll" Alias "GetLastMessage" (ByVal message As StringBuilder, ByVal buffer_size As Integer, ByRef message_length As Integer) + + ' get the extended error (set if an error occurs) + Declare Ansi Function GetLastExtendedError32 Lib "DinkeyRemote32.dll" Alias "GetLastExtendedError" () As Integer + Declare Ansi Function GetLastExtendedError64 Lib "DinkeyRemote64.dll" Alias "GetLastExtendedError" () As Integer + + ' ********************** Constants ************************ + Public Const DRPF_VERSION As Integer = 2 ' current DRPF version + + ' WriteDRPFEx API flags + Public Const FLAGS_LOSE_FEATURES As Integer = 1 ' means that you can save the DRPF file to an earlier version even if it means losing some new features that have been currently set + + ' constants for drpf_format in ReadDRPFEx and WriteDRPFEx functions + Public Const DRPF_FORMAT_BINARY As Integer = 1 + Public Const DRPF_FORMAT_JSON As Integer = 2 + Public Const DRPF_FORMAT_JSON_MIN As Integer = 3 ' this value is only used with WriteDRPEx. ReadDRPFEx cannot return this value. + + ' private constants + Private const MAX_LICENCES As Integer = 255 ' max number of licence changes in a DRPF file (theoretically unlimited but easier if we limit it) + Private Const MAX_ALG_CHANGES As Integer = 21 ' max number of alg changes in DRPF file + Private Const MAX_DATA_CHANGES As Integer = 127 ' max number of data area changes in DRPF file + + ' ********************** API Functions ************************ + ' We only want to load the correct DLL for the bit-ness of the computer. The other DLL may not exist. + ' if the appropriate DLL does not exist in the same directory as this test program you will receive a DllNotFoundException + + ' call the correct dll depending on whether we are running 32-bit or 64-bit code + Function LoadDRPFFromFile(ByVal drpf_file As String, ByRef err_code As Integer) As IntPtr + If (IntPtr.Size = 4) Then + LoadDRPFFromFile = LoadDRPFFromFile32(drpf_file, err_code) + Else + LoadDRPFFromFile = LoadDRPFFromFile64(drpf_file, err_code) + End If + End Function + + ' we have to do some marshalling of arrays of bytes into arrays of structures + Function ReadDRPFEx(ByVal drpf_file As String, ByRef MyRemoteInfo As REMOTEINFO, ByRef LicenceInfoArray() As LICENCEINFO, ByRef AlgChangesArray() As ALGCHANGE, _ + ByRef DataChangesArray() As DATACHANGE, ByRef drpf_version As Integer, ByRef drpf_format As Integer) As Integer + Dim i As Integer + Dim MyLicenceInfo As New LICENCEINFO + Dim licence_bytes(MAX_LICENCES * Marshal.SizeOf(MyLicenceInfo)) As Byte + Dim licence_bytes_one_struct(Marshal.SizeOf(MyLicenceInfo)) As Byte + Dim MyAlgChanges As New ALGCHANGE + Dim algchange_bytes(MAX_ALG_CHANGES * Marshal.SizeOf(MyAlgChanges)) As Byte + Dim algchange_bytes_one_struct(Marshal.SizeOf(MyAlgChanges)) As Byte + Dim MyDataChanges As New DATACHANGE + Dim datachange_bytes(MAX_DATA_CHANGES * Marshal.SizeOf(MyDataChanges)) As Byte + Dim datachange_bytes_one_struct(Marshal.SizeOf(MyDataChanges)) As Byte + Dim MyGC As GCHandle + MyRemoteInfo = New REMOTEINFO + + If (IntPtr.Size = 4) Then + ReadDRPFEx = ReadDRPFEx32(drpf_file, MyRemoteInfo, licence_bytes, algchange_bytes, datachange_bytes, drpf_version, drpf_format) + Else + ReadDRPFEx = ReadDRPFEx64(drpf_file, MyRemoteInfo, licence_bytes, algchange_bytes, datachange_bytes, drpf_version, drpf_format) + End If + + If ReadDRPFEx <> 0 Then + Exit Function + End If + + ' convert byte array to an array of structs + ReDim LicenceInfoArray(MyRemoteInfo.NumLicences) + For i = 0 To MyRemoteInfo.NumLicences - 1 + LicenceInfoArray(i) = New LICENCEINFO + Array.Copy(licence_bytes, i * Marshal.SizeOf(MyLicenceInfo.GetType), licence_bytes_one_struct, 0, Marshal.SizeOf(MyLicenceInfo.GetType)) + MyGC = GCHandle.Alloc(licence_bytes_one_struct, GCHandleType.Pinned) + LicenceInfoArray(i) = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, MyLicenceInfo.GetType) + MyGC.Free() + Next + + ReDim AlgChangesArray(MyRemoteInfo.NumAlgs) + For i = 0 To MyRemoteInfo.NumAlgs - 1 + AlgChangesArray(i) = New ALGCHANGE + Array.Copy(algchange_bytes, i * Marshal.SizeOf(MyAlgChanges.GetType), algchange_bytes_one_struct, 0, Marshal.SizeOf(MyAlgChanges.GetType)) + MyGC = GCHandle.Alloc(algchange_bytes_one_struct, GCHandleType.Pinned) + AlgChangesArray(i) = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, MyAlgChanges.GetType) + MyGC.Free() + Next + + ReDim DataChangesArray(MyRemoteInfo.NumDataChanges) + For i = 0 To MyRemoteInfo.NumDataChanges - 1 + DataChangesArray(i) = New DATACHANGE + Array.Copy(datachange_bytes, i * Marshal.SizeOf(MyDataChanges.GetType), datachange_bytes_one_struct, 0, Marshal.SizeOf(MyDataChanges.GetType)) + MyGC = GCHandle.Alloc(datachange_bytes_one_struct, GCHandleType.Pinned) + DataChangesArray(i) = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, MyDataChanges.GetType) + MyGC.Free() + Next + + End Function + + Function LoadDRPF(ByRef MyRemoteInfo As REMOTEINFO, ByRef LicenceInfoArray() As LICENCEINFO, ByRef AlgChangesArray() As ALGCHANGE, ByRef DataChangesArray() As DATACHANGE, _ + ByRef ret_code As Integer) As IntPtr + Dim i As Integer + Dim MyLicenceInfo As New LICENCEINFO + Dim licence_bytes(MAX_LICENCES * Marshal.SizeOf(MyLicenceInfo)) As Byte + Dim licence_bytes_one_struct(Marshal.SizeOf(MyLicenceInfo)) As Byte + Dim MyAlgChanges As New ALGCHANGE + Dim algchange_bytes(MAX_ALG_CHANGES * Marshal.SizeOf(MyAlgChanges)) As Byte + Dim algchange_bytes_one_struct(Marshal.SizeOf(MyAlgChanges)) As Byte + Dim MyDataChanges As New DATACHANGE + Dim datachange_bytes(MAX_DATA_CHANGES * Marshal.SizeOf(MyDataChanges)) As Byte + Dim datachange_bytes_one_struct(Marshal.SizeOf(MyDataChanges)) As Byte + Dim MyGC As GCHandle + + ' convert array of structs to byte arrays + For i = 0 To MyRemoteInfo.NumLicences - 1 + MyGC = GCHandle.Alloc(licence_bytes_one_struct, GCHandleType.Pinned) + Marshal.StructureToPtr(LicenceInfoArray(i), MyGC.AddrOfPinnedObject, False) + MyGC.Free() + Array.Copy(licence_bytes_one_struct, 0, licence_bytes, i * Marshal.SizeOf(MyLicenceInfo.GetType), Marshal.SizeOf(MyLicenceInfo.GetType)) + Next + + For i = 0 To MyRemoteInfo.NumAlgs - 1 + MyGC = GCHandle.Alloc(algchange_bytes_one_struct, GCHandleType.Pinned) + Marshal.StructureToPtr(AlgChangesArray(i), MyGC.AddrOfPinnedObject, False) + MyGC.Free() + Array.Copy(algchange_bytes_one_struct, 0, algchange_bytes, i * Marshal.SizeOf(MyAlgChanges.GetType), Marshal.SizeOf(MyAlgChanges.GetType)) + Next + + For i = 0 To MyRemoteInfo.NumDataChanges - 1 + MyGC = GCHandle.Alloc(datachange_bytes_one_struct, GCHandleType.Pinned) + Marshal.StructureToPtr(DataChangesArray(i), MyGC.AddrOfPinnedObject, False) + MyGC.Free() + Array.Copy(datachange_bytes_one_struct, 0, datachange_bytes, i * Marshal.SizeOf(MyDataChanges.GetType), Marshal.SizeOf(MyDataChanges.GetType)) + Next + + If (IntPtr.Size = 4) Then + LoadDRPF = LoadDRPF32(MyRemoteInfo, licence_bytes, algchange_bytes, datachange_bytes, ret_code) + Else + LoadDRPF = LoadDRPF64(MyRemoteInfo, licence_bytes, algchange_bytes, datachange_bytes, ret_code) + End If + + End Function + + Function WriteDRPFEx(ByVal drpf_handle As IntPtr, ByVal drpf_file As String, ByVal drpf_format As Integer, ByVal drpf_version As Integer, ByVal flags As Integer) As Integer + If (IntPtr.Size = 4) Then + WriteDRPFEx = WriteDRPFEx32(drpf_handle, drpf_file, drpf_format, drpf_version, flags) + Else + WriteDRPFEx = WriteDRPFEx64(drpf_handle, drpf_file, drpf_format, drpf_version, flags) + End If + End Function + + Sub UnloadDRPF(ByRef drpf_handle As IntPtr) + If (IntPtr.Size = 4) Then + UnloadDRPF32(drpf_handle) + Else + UnloadDRPF64(drpf_handle) + End If + End Sub + + Function GenerateUpdateCode(ByVal drpf_handle As IntPtr, ByVal dongle_number As UInt32, ByVal update_number As Integer, ByVal ducf_file As String, _ + ByVal logfile As String, ByRef Outputs As UPDATE_CODE_OUTPUTS) As Integer + If (IntPtr.Size = 4) Then + GenerateUpdateCode = GenerateUpdateCode32(drpf_handle, dongle_number, update_number, ducf_file, logfile, Outputs) + Else + GenerateUpdateCode = GenerateUpdateCode64(drpf_handle, dongle_number, update_number, ducf_file, logfile, Outputs) + End If + End Function + + ' do a bit of work here to make the function easier to use for VB.NET + Function GetLastMessage() As String + Dim length, dummy As Integer + Dim message As StringBuilder + + If (IntPtr.Size = 4) Then + GetLastMessage32(Nothing, 0, length) + message = New StringBuilder(length) + GetLastMessage32(message, length, dummy) + Else + GetLastMessage64(Nothing, 0, length) + message = New StringBuilder(length) + GetLastMessage64(message, length, dummy) + End If + + Return message.ToString() + End Function + + Function GetLastExtendedError() As Integer + If (IntPtr.Size = 4) Then + GetLastExtendedError = GetLastExtendedError32() + Else + GetLastExtendedError = GetLastExtendedError64() + End If + End Function + + +End Module diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyRemote/drpfTest.sln b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyRemote/drpfTest.sln new file mode 100644 index 0000000..4c7c9af --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyRemote/drpfTest.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "drpfTest", "drpfTest.vbproj", "{35F04638-E647-4D07-A165-876D21B435B1}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {35F04638-E647-4D07-A165-876D21B435B1}.Debug.ActiveCfg = Debug|.NET + {35F04638-E647-4D07-A165-876D21B435B1}.Debug.Build.0 = Debug|.NET + {35F04638-E647-4D07-A165-876D21B435B1}.Release.ActiveCfg = Release|.NET + {35F04638-E647-4D07-A165-876D21B435B1}.Release.Build.0 = Release|.NET + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyRemote/drpfTest.vbproj b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyRemote/drpfTest.vbproj new file mode 100644 index 0000000..31aafaf --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/DinkeyRemote/drpfTest.vbproj @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/AssemblyInfo.vb b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/AssemblyInfo.vb new file mode 100644 index 0000000..9315c48 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/AssemblyInfo.vb @@ -0,0 +1,31 @@ +Imports System.Reflection +Imports System.Runtime.InteropServices + +' General Information about an assembly is controlled through the following +' set of attributes. Change these attribute values to modify the information +' associated with an assembly. + +' Review the values of the assembly attributes + + + + + + + + + +'The following GUID is for the ID of the typelib if this project is exposed to COM + + +' Version information for an assembly consists of the following four values: +' +' Major Version +' Minor Version +' Build Number +' Revision +' +' You can specify all the values or you can default the Build and Revision Numbers +' by using the '*' as shown below: + + diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/DllTest.sln b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/DllTest.sln new file mode 100644 index 0000000..f0f93c0 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/DllTest.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "DllTest", "DllTest.vbproj", "{7C92E3C8-2E6D-4347-B8B3-579231D8E24D}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {7C92E3C8-2E6D-4347-B8B3-579231D8E24D}.Debug.ActiveCfg = Debug|.NET + {7C92E3C8-2E6D-4347-B8B3-579231D8E24D}.Debug.Build.0 = Debug|.NET + {7C92E3C8-2E6D-4347-B8B3-579231D8E24D}.Release.ActiveCfg = Release|.NET + {7C92E3C8-2E6D-4347-B8B3-579231D8E24D}.Release.Build.0 = Release|.NET + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/DllTest.vbproj b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/DllTest.vbproj new file mode 100644 index 0000000..4da9a7f --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/DllTest.vbproj @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/Form1.resx b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/Form1.resx new file mode 100644 index 0000000..ed1cd0f --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/Form1.resx @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Assembly + + + Form1 + + \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/Form1.vb b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/Form1.vb new file mode 100644 index 0000000..49f69d2 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/Form1.vb @@ -0,0 +1,988 @@ +' !! We strongly recommend that you read the "readme.txt" file in the sample code folder. +' !! It contains important instructions on how to use the sample code + +Imports System.Runtime.InteropServices + +Public Class Form1 + Inherits System.Windows.Forms.Form + +#Region " Windows Form Designer generated code " + + Public Sub New() + MyBase.New() + + 'This call is required by the Windows Form Designer. + InitializeComponent() + + 'Add any initialization after the InitializeComponent() call + + End Sub + + 'Form overrides dispose to clean up the component list. + Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) + If disposing Then + If Not (components Is Nothing) Then + components.Dispose() + End If + End If + MyBase.Dispose(disposing) + End Sub + + 'Required by the Windows Form Designer + Private components As System.ComponentModel.IContainer + + 'NOTE: The following procedure is required by the Windows Form Designer + 'It can be modified using the Windows Form Designer. + 'Do not modify it using the code editor. + Friend WithEvents Label1 As System.Windows.Forms.Label + Private Sub InitializeComponent() + Me.Label1 = New System.Windows.Forms.Label() + Me.SuspendLayout() + ' + 'Label1 + ' + Me.Label1.Font = New System.Drawing.Font("Microsoft Sans Serif", 24.0!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte)) + Me.Label1.Location = New System.Drawing.Point(72, 80) + Me.Label1.Name = "Label1" + Me.Label1.Size = New System.Drawing.Size(168, 40) + Me.Label1.TabIndex = 0 + Me.Label1.Text = "It Worked!" + ' + 'Form1 + ' + Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13) + Me.ClientSize = New System.Drawing.Size(304, 213) + Me.Controls.AddRange(New System.Windows.Forms.Control() {Me.Label1}) + Me.Name = "Form1" + Me.Text = "Form1" + Me.ResumeLayout(False) + + End Sub + +#End Region + + ' The sample code contains 11 functions. You will not need to use all these + ' functions in your code. Just use which ever functions are most appropriate + ' and customise in your own way. The sample code is just a guide. You should + ' implement the protection in a stronger way using the techniques described in + ' the "Increasing your Protection" chapter of the manual. + ' + ' The 11 functions are: + ' ProtCheck a standard protection check + ' ProtCheckWithAlg a protection check & executing an Algorithm + ' WriteBytes a protection check & write data to the dongle + ' ReadBytes a protection check & read data from the dongle + ' EncryptUserData a protection check,& encrypting data and then decrypting the data + ' + ' these functions are the same as the functions listed above but encrypting all parameters passed to our API + ' ProtCheckEnc a standard protection check + ' ProtCheckWithAlgEnc a protection check & executing an Algorithm + ' WriteBytesEnc a protection check & write data to the dongle + ' ReadBytesEnc a protection check & read data from the dongle + ' EncryptUserDataEnc a protection check & encrypting data and then decrypting the data + + ' this function displays the current network users + ' DisplayNetUsers + + ' !!!! + Public Const MY_SDSN As Integer = 10101 ' !!!! change this value to be the value of your SDSN (demo = 10101) + Public Const MY_PRODCODE As String = "DEMO" ' !!!! change this value to match the Product Code in the dongle + + ' If you are using Dinkey Lite then you can only use 4 functions: + ' ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + + Private Sub Form1_Load(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles MyBase.Load + + ' call the function(s) of your choice here + ' here I have chosen a standard protection check + If ProtCheck() <> 0 Then + End 'terminate + End If + + End Sub + + ' ************************* our 10 functions ********************************** + + ' ************************** ProtCheck *************************************** + Function ProtCheck() As Integer + Dim dris As DRIS = New DRIS + Dim ret_code As Integer + On Error GoTo Protection_Err + + ' set the DRIS to have random values + Call RandomSet(dris) + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = PROTECTION_CHECK ' standard protection check + dris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + ret_code = DDProtCheck(dris, Nothing) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + ProtCheck = ret_code + Exit Function + End If + + ' later in your code you can check other values in the DRIS... + If (dris.sdsn <> MY_SDSN) Then + MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error") + ProtCheck = -1 + Exit Function + End If + + If (GetProductCode(dris) <> MY_PRODCODE) Then + MsgBox("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", MsgBoxStyle.OkOnly, "Error") + ProtCheck = -1 + Exit Function + End If + + ' later on in your program you can check the return code again + If (dris.ret_code <> 0) Then + MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error") + ProtCheck = -1 + Exit Function + End If + + + ' NB if you are using a network dongle and you want to list the network users then use this function: + ' DisplayNetUsers(dris.net_users, dris.model) + + ProtCheck = 0 + Exit Function + +Protection_Err: ' see readme.txt for explanation of this exception handler + Protection_Exception() + ProtCheck = -1 + End Function + + + ' ************************** ProtCheckWithAlg ****************************** + + ' !!!! You should replace this function with the one generated by the + ' "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) + ' or from DinkeyLook if you are using Dinkey Lite dongles. + ' see readme.txt notes concerning using the algorithm in vb.net + Private Function MyAlgorithm(ByVal a As Integer, ByVal b As Integer, ByVal c As Integer, ByVal d As Integer, ByVal e As Integer, ByVal f As Integer, ByVal g As Integer, ByVal h As Integer) As Integer + MyAlgorithm = a + b + c + d + e + f + g + h + End Function + + ' NB for this to work you must program at least "user algorithm" into the dongle + ' NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + ' sample code generated by DinkeyAdd for the algorithm that you are using. + Function ProtCheckWithAlg() As Integer + Dim dris As DRIS = New DRIS + Dim ret_code As Integer + On Error GoTo Protection_Err + + ' set the DRIS to have random values + Call RandomSet(dris) + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = EXECUTE_ALGORITHM ' standard protection check & execute algorithm + dris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number = 1 ' execute first algorithm (you do not need to specify this field for Dinkey Lite dongles) + ' you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.var_a = 1 ' sample values + dris.var_b = 2 + dris.var_c = 3 + dris.var_d = 4 + dris.var_e = 5 + dris.var_f = 6 + dris.var_g = 7 + dris.var_h = 8 + + ret_code = DDProtCheck(dris, Nothing) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + ProtCheckWithAlg = ret_code + Exit Function + End If + + ' later in your code you can check other values in the DRIS... + If (dris.sdsn <> MY_SDSN) Then + MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error") + ProtCheckWithAlg = -1 + Exit Function + End If + + ' later on in your program you can check the return code again + If (dris.ret_code <> 0) Then + MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error") + ProtCheckWithAlg = -1 + Exit Function + End If + + ' if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + ' NB read the note in the "readme.txt" about possible overflow errors in VB.NET + ' !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + If (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) <> dris.alg_answer) Then + MsgBox("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine", MsgBoxStyle.OkOnly, "Error") + ProtCheckWithAlg = -1 + Exit Function + End If + + ProtCheckWithAlg = 0 + Exit Function +Protection_Err: ' see readme.txt for explanation of this exception handler + Protection_Exception() + ProtCheckWithAlg = -1 + End Function + + ' ************************** WriteBytes ****************************** + ' This writes the data array 0,1,2,3,4,5,6,7,8,9 to the dongle data area at offset 7 + ' In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + ' if you want to write a string then you need to convert it to a byte array first: + ' encoding.GetBytes(your_string, 0, your_string.Length, data, 0) where encoding is declared: Dim encoding As New ASCIIEncoding() You also need to include System.Text + Function WriteBytes() As Integer + Dim dris As DRIS = New DRIS + Dim ret_code As Integer + Dim data() As Byte = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + On Error GoTo Protection_Err + + ' set the DRIS to have random values + Call RandomSet(dris) + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = WRITE_DATA_AREA ' standard protection check & write data + dris.flags = USE_FUNCTION_ARGUMENT ' you have to do it this way in vb.net + dris.rw_offset = 7 + dris.rw_length = data.Length + + ret_code = DDProtCheck(dris, data) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + WriteBytes = ret_code + Exit Function + End If + + ' later in your code you can check other values in the DRIS... + If (dris.sdsn <> MY_SDSN) Then + MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error") + WriteBytes = -1 + Exit Function + End If + + ' later on in your program you can check the return code again + If (dris.ret_code <> 0) Then + MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error") + WriteBytes = -1 + Exit Function + End If + + WriteBytes = 0 + Exit Function +Protection_Err: ' see readme.txt for explanation of this exception handler + Protection_Exception() + WriteBytes = -1 + End Function + + ' ************************ ReadBytes ************************************ + ' This reads 10 bytes of data from offset 7 in the dongle data area + ' In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + ' if you want to read a string then you need to convert it from a byte array (via an array of char). You also need to include System.Text + ' CharArray = encoding.GetChars(data); where CharArray is of type char[] and encoding is of type ASCIIEncoding + ' your_string = new String(CharArray, 0, your_string_length); + Function ReadBytes() As Integer + Dim dris As DRIS = New DRIS + Dim ret_code As Integer + Dim data(10) As Byte + On Error GoTo Protection_Err + + ' set the DRIS to have random values + Call RandomSet(dris) + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = READ_DATA_AREA ' standard protection check & read data + dris.flags = USE_FUNCTION_ARGUMENT ' you have to do it this way in vb.net + dris.rw_offset = 7 + dris.rw_length = data.Length + + ret_code = DDProtCheck(dris, data) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + ReadBytes = ret_code + Exit Function + End If + + ' later in your code you can check other values in the DRIS... + If (dris.sdsn <> MY_SDSN) Then + MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error") + ReadBytes = -1 + Exit Function + End If + + ' later on in your program you can check the return code again + If (dris.ret_code <> 0) Then + MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error") + ReadBytes = -1 + Exit Function + End If + + MsgBox("Dinkey Dongle Data Area, offset 7 is : " + Str(data(0)) + "," + Str(data(1)) + "," + Str(data(2)) + "," + Str(data(3)) + "," + _ + Str(data(4)) + "," + Str(data(5)) + "," + Str(data(6)) + "," + Str(data(7)) + "," + Str(data(8)) + "," + Str(data(9)), MsgBoxStyle.OkOnly) + ReadBytes = 0 + Exit Function +Protection_Err: ' see readme.txt for explanation of this exception handler + Protection_Exception() + ReadBytes = -1 + End Function + + ' ************************** EncryptUserData ************************************ + ' This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 + ' It will then do another protection check & decrypt the data + ' to encrypt or decrypt strings please read notes for WriteBytes and ReadBytes functions + Function EncryptUserData() As Integer + Dim dris As DRIS = New DRIS + Dim ret_code As Integer + Dim data() As Byte = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + On Error GoTo Protection_Err + + ' set the DRIS to have random values + Call RandomSet(dris) + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = ENCRYPT_USER_DATA ' standard protection check & encrypt data + dris.flags = USE_FUNCTION_ARGUMENT ' you have to do it this way in vb.net + dris.rw_length = data.Length + dris.data_crypt_key_num = 1 + + ret_code = DDProtCheck(dris, data) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + EncryptUserData = ret_code + Exit Function + End If + + ' ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + ' Now decrypt the same data to get the original values + Call RandomSet(dris) + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = DECRYPT_USER_DATA ' standard protection check & decrypt data + dris.flags = USE_FUNCTION_ARGUMENT ' you have to do it this way in vb.net + dris.rw_length = data.Length + dris.data_crypt_key_num = 1 + + ret_code = DDProtCheck(dris, data) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + EncryptUserData = ret_code + Exit Function + End If + + ' later in your code you can check other values in the DRIS... + If (dris.sdsn <> MY_SDSN) Then + MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error") + EncryptUserData = -1 + Exit Function + End If + + ' later on in your program you can check the return code again + If (dris.ret_code <> 0) Then + MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error") + EncryptUserData = -1 + Exit Function + End If + + MsgBox("Decrypted data is : " + Str(data(0)) + "," + Str(data(1)) + "," + Str(data(2)) + "," + Str(data(3)) + "," + _ + Str(data(4)) + "," + Str(data(5)) + "," + Str(data(6)) + "," + Str(data(7)) + "," + Str(data(8)) + "," + Str(data(9)), MsgBoxStyle.OkOnly) + EncryptUserData = 0 + Exit Function +Protection_Err: ' see readme.txt for explanation of this exception handler + Protection_Exception() + EncryptUserData = -1 + End Function + + ' !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! + ' In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" + ' in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm + ' but the code can be modified easily to use the 3 encryption parameters. + + ' !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm + Private Function MyRWAlgorithm(ByVal a As Integer, ByVal b As Integer, ByVal c As Integer, ByVal d As Integer, ByVal e As Integer, ByVal f As Integer, ByVal g As Integer, ByVal h As Integer) As Integer + MyRWAlgorithm = a Xor b Xor c Xor d Xor e Xor f + MyRWAlgorithm = MyRWAlgorithm And &HFFFFFF ' we only use bottom 3 bytes. -ve numbers can cause problems for CryptApiData + End Function + + ' !!!! please overwrite this function with the one generated by DinkeyAdd + Private Sub CryptDRIS(ByRef dris As DRIS) + Dim i, j, k, t As Integer + Dim bigseed(255) As Byte + Dim S(255) As Byte + Dim temp As Byte + Dim temp_dris(Marshal.SizeOf(dris) - 1) As Byte + + DrisToByteArray(dris, temp_dris) ' convert DRIS to byte array so we can encrypt it + + For i = 0 To 255 Step 8 + Call Set4Bytes(bigseed, i, dris.seed1) + Call Set4Bytes(bigseed, i + 4, dris.seed2) + Next + For i = 0 To 255 + S(i) = i + Next + j = 0 + For i = 0 To 255 + j = (j + CInt(S(i)) + CInt(bigseed(i)) + 123) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + Next + i = 0 + j = 0 + For k = 16 To Marshal.SizeOf(dris) - 1 + i = (i + 1) Mod 256 + j = (j + CInt(S(i)) + 212) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + t = (CInt(S(i)) + CInt(S(j)) + 97) Mod 256 + temp_dris(k) = temp_dris(k) Xor S(t) + Next + + ByteArrayToDris(temp_dris, dris) ' convert it back again + End Sub + + + ' !!!! please overwrite this function with the one generated by DinkeyAdd + Private Sub CryptApiData(ByVal dris As DRIS, ByVal data() As Byte, ByVal length As Integer, ByVal alg_answer As Integer) + Dim i, j, k, t As Integer + Dim bigseed(255) As Byte + Dim S(255) As Byte + Dim temp As Byte + + For i = 0 To 255 Step 8 + Call Set4Bytes(bigseed, i, dris.seed1) + Call Set4Bytes(bigseed, i + 4, dris.seed2) + Next + For i = 0 To 255 + S(i) = i + Next + j = 0 + For i = 0 To 255 + j = (j + CInt(S(i)) + CInt(bigseed(i)) + (alg_answer And &HFF)) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + Next + i = 0 + j = 0 + For k = 0 To length - 1 + i = (i + 1) Mod 256 + j = (j + CInt(S(i)) + ((alg_answer \ &H100) And &HFF)) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + t = (CInt(S(i)) + CInt(S(j)) + ((alg_answer \ &H10000) And &HFF)) Mod 256 + data(k) = data(k) Xor S(t) + Next + End Sub + + ' ************************** ProtCheckEnc ************************************ + ' We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. + Function ProtCheckEnc() As Integer + Dim dris As DRIS = New DRIS + Dim ret_code As Integer + On Error GoTo Protection_Err + + ' set the DRIS to have random values + Call RandomSet(dris) + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = PROTECTION_CHECK ' standard protection check + dris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + + Call CryptDRIS(dris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(dris, Nothing) + + Call CryptDRIS(dris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + ProtCheckEnc = ret_code + Exit Function + End If + + ' later in your code you can check other values in the DRIS... + If (dris.sdsn <> MY_SDSN) Then + MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error") + ProtCheckEnc = -1 + Exit Function + End If + + If (GetProductCode(dris) <> MY_PRODCODE) Then + MsgBox("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", MsgBoxStyle.OkOnly, "Error") + ProtCheckEnc = -1 + Exit Function + End If + + ' later on in your program you can check the return code again + If (dris.ret_code <> 0) Then + MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error") + ProtCheckEnc = -1 + Exit Function + End If + + ProtCheckEnc = 0 + Exit Function + +Protection_Err: ' see readme.txt for explanation of this exception handler + Protection_Exception() + ProtCheckEnc = -1 + End Function + + + ' ************************** ProtCheckWithAlgEnc **************************** + ' NB for this to work you must program at least "user algorithm" into the dongle + ' NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the + ' sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite get source from DinkeyLook. + ' We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. + Function ProtCheckWithAlgEnc() As Integer + Dim dris As DRIS = New DRIS + Dim ret_code As Integer + On Error GoTo Protection_Err + + ' set the DRIS to have random values + Call RandomSet(dris) + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = EXECUTE_ALGORITHM ' standard protection check & execute algorithm + dris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + dris.alg_number = 1 ' execute first algorithm (you do not need to specify this field for Dinkey Lite dongles) + ' you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random + dris.var_a = 1 ' sample values + dris.var_b = 2 + dris.var_c = 3 + dris.var_d = 4 + dris.var_e = 5 + dris.var_f = 6 + dris.var_g = 7 + dris.var_h = 8 + + Call CryptDRIS(dris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(dris, Nothing) + + Call CryptDRIS(dris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + ProtCheckWithAlgEnc = ret_code + Exit Function + End If + + ' later in your code you can check other values in the DRIS... + If (dris.sdsn <> MY_SDSN) Then + MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error") + ProtCheckWithAlgEnc = -1 + Exit Function + End If + + ' later on in your program you can check the return code again + If (dris.ret_code <> 0) Then + MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error") + ProtCheckWithAlgEnc = -1 + Exit Function + End If + + ' if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code + ' !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd + If (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) <> dris.alg_answer) Then + MsgBox("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine", MsgBoxStyle.OkOnly, "Error") + ProtCheckWithAlgEnc = -1 + Exit Function + End If + + ProtCheckWithAlgEnc = 0 + Exit Function +Protection_Err: ' see readme.txt for explanation of this exception handler + Protection_Exception() + ProtCheckWithAlgEnc = -1 + End Function + + ' ************************** WriteBytesEnc ****************************** + ' This writes the data array 0,1,2,3,4,5,6,7,8,9 to the dongle data area at offset 7 + ' In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + ' We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + ' to write string data please read notes for WriteBytes + Function WriteBytesEnc() As Integer + Dim dris As DRIS = New DRIS + Dim ret_code, alg_ans As Integer + Dim data() As Byte = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + On Error GoTo Protection_Err + + ' set the DRIS to have random values + Call RandomSet(dris) ' sets DRIS to have random values including seed1, seed2 and var_a..var_h + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = WRITE_DATA_AREA ' standard protection check & write data + dris.flags = USE_FUNCTION_ARGUMENT ' you have to do it this way in vb.net + dris.rw_offset = 7 + dris.rw_length = data.Length + dris.var_a = dris.var_a And &HFFFFFF ' restrict to 24-bit to prevent potential overflow in algorithm + dris.var_b = dris.var_b And &HFFFFFF + dris.var_c = dris.var_c And &HFFFFFF + dris.var_d = dris.var_d And &HFFFFFF + dris.var_e = dris.var_e And &HFFFFFF + dris.var_f = dris.var_f And &HFFFFFF + dris.var_g = dris.var_g And &HFFFFFF + dris.var_h = dris.var_h And &HFFFFFF + + ' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) + + ' encrypt data we want to write. + CryptApiData(dris, data, data.Length, alg_ans) + + Call CryptDRIS(dris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(dris, data) + + Call CryptDRIS(dris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + WriteBytesEnc = ret_code + Exit Function + End If + + ' later in your code you can check other values in the DRIS... + If (dris.sdsn <> MY_SDSN) Then + MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error") + WriteBytesEnc = -1 + Exit Function + End If + + ' later on in your program you can check the return code again + If (dris.ret_code <> 0) Then + MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error") + WriteBytesEnc = -1 + Exit Function + End If + + WriteBytesEnc = 0 + Exit Function +Protection_Err: ' see readme.txt for explanation of this exception handler + Protection_Exception() + WriteBytesEnc = -1 + End Function + + ' ************************ ReadBytesEnc ************************************ + ' This reads 10 bytes of data from offset 7 in the dongle data area + ' In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long. + ' We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + ' to read string data please notes for ReadBytes function + Function ReadBytesEnc() As Integer + Dim dris As DRIS = New DRIS + Dim ret_code, alg_ans As Integer + Dim data(10) As Byte + On Error GoTo Protection_Err + + ' set the DRIS to have random values + Call RandomSet(dris) ' sets DRIS to have random values including seed1, seed2 and var_a..var_h + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = READ_DATA_AREA ' standard protection check & read data + dris.flags = USE_FUNCTION_ARGUMENT ' you have to do it this way in vb.net + dris.rw_offset = 7 + dris.rw_length = data.Length + dris.var_a = dris.var_a And &HFFFFFF ' restrict to 24-bit to prevent potential overflow in algorithm + dris.var_b = dris.var_b And &HFFFFFF + dris.var_c = dris.var_c And &HFFFFFF + dris.var_d = dris.var_d And &HFFFFFF + dris.var_e = dris.var_e And &HFFFFFF + dris.var_f = dris.var_f And &HFFFFFF + dris.var_g = dris.var_g And &HFFFFFF + dris.var_h = dris.var_h And &HFFFFFF + + ' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) + + Call CryptDRIS(dris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(dris, data) + + Call CryptDRIS(dris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + ReadBytesEnc = ret_code + Exit Function + End If + + ' later in your code you can check other values in the DRIS... + If (dris.sdsn <> MY_SDSN) Then + MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error") + ReadBytesEnc = -1 + Exit Function + End If + + ' later on in your program you can check the return code again + If (dris.ret_code <> 0) Then + MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error") + ReadBytesEnc = -1 + Exit Function + End If + + ' decrypt data just read. + CryptApiData(dris, data, data.Length, alg_ans) + MsgBox("Dinkey Dongle Data Area, offset 7 is : " + Str(data(0)) + "," + Str(data(1)) + "," + Str(data(2)) + "," + Str(data(3)) + "," + _ + Str(data(4)) + "," + Str(data(5)) + "," + Str(data(6)) + "," + Str(data(7)) + "," + Str(data(8)) + "," + Str(data(9)), MsgBoxStyle.OkOnly) + ReadBytesEnc = 0 + Exit Function +Protection_Err: ' see readme.txt for explanation of this exception handler + Protection_Exception() + ReadBytesEnc = -1 + End Function + + ' ************************** EncryptUserDataEnc ********************************* + ' This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 + ' It will then do another protection check & decrypt the data + ' We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. + ' to encrypt or decrypt strings please read notes for WriteBytes and ReadBytes functions + Function EncryptUserDataEnc() As Integer + Dim dris As DRIS = New DRIS + Dim ret_code, alg_ans As Integer + Dim data() As Byte = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + On Error GoTo Protection_Err + + ' set the DRIS to have random values + Call RandomSet(dris) ' sets DRIS to have random values including seed1, seed2 and var_a..var_h + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = ENCRYPT_USER_DATA ' standard protection check & encrypt data + dris.flags = USE_FUNCTION_ARGUMENT ' you have to do it this way in vb.net + dris.rw_length = data.Length + dris.data_crypt_key_num = 1 + dris.var_a = dris.var_a And &HFFFFFF ' restrict to 24-bit to prevent potential overflow in algorithm + dris.var_b = dris.var_b And &HFFFFFF + dris.var_c = dris.var_c And &HFFFFFF + dris.var_d = dris.var_d And &HFFFFFF + dris.var_e = dris.var_e And &HFFFFFF + dris.var_f = dris.var_f And &HFFFFFF + dris.var_g = dris.var_g And &HFFFFFF + dris.var_h = dris.var_h And &HFFFFFF + + ' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) + + ' encrypt data we pass to our API + CryptApiData(dris, data, data.Length, alg_ans) + + Call CryptDRIS(dris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(dris, data) + + Call CryptDRIS(dris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + EncryptUserDataEnc = ret_code + Exit Function + End If + + ' ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ... + + ' Now decrypt the same data to get the original values + Call RandomSet(dris) ' sets DRIS to have random values including seed1, seed2 and var_a..var_h + ' then set the values we want to use + dris.header1 = Asc("D") + dris.header2 = Asc("R") + dris.header3 = Asc("I") + dris.header4 = Asc("S") + dris.size = Marshal.SizeOf(dris) + dris.myfunction = DECRYPT_USER_DATA ' standard protection check & decrypt data + dris.flags = USE_FUNCTION_ARGUMENT ' you have to do it this way in vb.net + dris.rw_length = data.Length + dris.data_crypt_key_num = 1 + dris.var_a = dris.var_a And &HFFFFFF ' restrict to 24-bit to prevent potential overflow in algorithm + dris.var_b = dris.var_b And &HFFFFFF + dris.var_c = dris.var_c And &HFFFFFF + dris.var_d = dris.var_d And &HFFFFFF + dris.var_e = dris.var_e And &HFFFFFF + dris.var_f = dris.var_f And &HFFFFFF + dris.var_g = dris.var_g And &HFFFFFF + dris.var_h = dris.var_h And &HFFFFFF + + Call CryptDRIS(dris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + ret_code = DDProtCheck(dris, data) + + Call CryptDRIS(dris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + + If (ret_code <> 0) Then + Call DisplayError(ret_code, dris.ext_err) + EncryptUserDataEnc = ret_code + Exit Function + End If + + ' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm + alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) + + ' later in your code you can check other values in the DRIS... + If (dris.sdsn <> MY_SDSN) Then + MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error") + EncryptUserDataEnc = -1 + Exit Function + End If + + ' later on in your program you can check the return code again + If (dris.ret_code <> 0) Then + MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error") + EncryptUserDataEnc = -1 + Exit Function + End If + + ' decrypt data just returned by API. + CryptApiData(dris, data, data.Length, alg_ans) + MsgBox("Decrypted data is : " + Str(data(0)) + "," + Str(data(1)) + "," + Str(data(2)) + "," + Str(data(3)) + "," + _ + Str(data(4)) + "," + Str(data(5)) + "," + Str(data(6)) + "," + Str(data(7)) + "," + Str(data(8)) + "," + Str(data(9)), MsgBoxStyle.OkOnly) + EncryptUserDataEnc = 0 + Exit Function +Protection_Err: ' see readme.txt for explanation of this exception handler + Protection_Exception() + EncryptUserDataEnc = -1 + End Function + + + ' *********************** DisplayNetUsers ******************************* + ' This function displays the current network users (for DinkeyNet only). + ' The DDProtCheck function must be called before this function is called. + ' (Normally you would use DinkeyServer to view the network users but this enables you to do it from the client if you want) + Function DisplayNetUsers(net_users As Integer, model As Integer) As Integer + Dim num_net_users, extended_error, ret_code, i, max_net_users As Integer + Dim DisplayString As String + + If net_users = -1 Then + max_net_users = 100 ' if unlimited network users are allowed then display up to 100 users (for example) + Else + max_net_users = net_users + End If + + If max_net_users = 0 Then ' no network users are allowed, so nothing to do! + DisplayNetUsers = 0 + Exit Function + End If + + If model < 3 Then + MsgBox("A network dongle has not been detected. Therefore you cannot display the network users.", MsgBoxStyle.OKOnly) + DisplayNetUsers = -1 + Exit Function + End If + + Dim nu_info_array(max_net_users) As NU_INFO + + ' now get net users + ret_code = DDGetNetUserList(Nothing, num_net_users, nu_info_array, max_net_users, extended_error) + + If ret_code <> 0 Then + MsgBox("Error " + Str(ret_code) + "/" + Str(extended_error) + " finding network user information.", MsgBoxStyle.OKOnly) + Else + DisplayString = "number of net users: " + Str(num_net_users) + Environment.NewLine + For i = 0 To num_net_users - 1 + DisplayString = DisplayString + Str(i + 1) + ". licence: " + nu_info_array(i).LicenceName + ", user: " + nu_info_array(i).UserName + ", computer: " + nu_info_array(i).ComputerName + ", ip address: " + nu_info_array(i).IPAddress + Environment.NewLine + Next + MsgBox(DisplayString, MsgBoxStyle.OKOnly, "Net Users") + End If + DisplayNetUsers = ret_code + + End Function + + ' look at the error code and try to display an appropriate message + ' you may want to change these messages and specify your own + Public Sub DisplayError(ByVal ret_code As Integer, ByVal extended_error As Integer) + Select Case ret_code + Case 401 + MsgBox("Error! No dongles detected!", MsgBoxStyle.OKOnly, "Error") + Case 403 + MsgBox("Error! A dongle was detected but it was a different type to the one specified in DinkeyAdd.", MsgBoxStyle.OKOnly, "Error") + Case 404 + MsgBox("Error! A dongle was detected but it was a different model to those specified in DinkeyAdd.", MsgBoxStyle.OKOnly, "Error") + Case 409 + MsgBox("Error! The dongle detected has not been programmed by DinkeyAdd.", MsgBoxStyle.OKOnly, "Error") + Case 410 + MsgBox("Error! A dongle was detected but it has a different Product Code to the one specified in DinkeyAdd.", MsgBoxStyle.OKOnly, "Error") + Case 411 + MsgBox("Error! The dongle detected does not contain the licence associated with this program.", MsgBoxStyle.OKOnly, "Error") + Case 413 + MsgBox("Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual.", MsgBoxStyle.OKOnly, "Error") + Case 417 + MsgBox("Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.", MsgBoxStyle.OKOnly, "Error") + Case 423 + MsgBox("Error! The number of network users has been exceeded.", MsgBoxStyle.OKOnly, "Error") + Case 435 + MsgBox("Error! DinkeyServer has not been detected on the network.", MsgBoxStyle.OKOnly, "Error") + Case 922 + MsgBox("Error! The Software Key has expired.", MsgBoxStyle.OKOnly, "Error") + Case Else + MsgBox("An error occurred checking the dongle. Error: " + Str(ret_code) + ". Extended Error: " + Str(extended_error) + ".", MsgBoxStyle.OKOnly, "Error") + End Select + End Sub + + ' if an error exception occurs during a protection check function then display an appropiate message + ' see readme.txt for an explaination + Sub Protection_Exception() + If (TypeOf Err.GetException() Is DllNotFoundException) Then + If (IntPtr.Size = 4) Then + MsgBox("Error! Cannot find dpwin32.dll. This should be in the same folder that DLLTest.exe is in.", MsgBoxStyle.OKOnly, "Error") + Else + MsgBox("Error! Cannot find dpwin64.dll. This should be in the same folder that DLLTest.exe is in.", MsgBoxStyle.OKOnly, "Error") + End If + Else + MsgBox("Error! An exception occurred: " + Err.GetException.Message, MsgBoxStyle.OKOnly, "Error") + End If + End Sub + +End Class diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/README.txt b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/README.txt new file mode 100644 index 0000000..7a594ac --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/README.txt @@ -0,0 +1,180 @@ +DllTest - sample code to call the Runtime Module in VB.NET +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Studio 2002 but will work in more recent versions of Visual Studio +(it will upgrade the Project to the latest version. If prompted you should also upgrade the .NET +framework the project requires). + +The main source files in the project are: + +File name Description +Form1.vb main source code file for VB.NET +dris.vb contains the DRIS structure and low-level functions to manipulate it. + +The best approach is to compile the sample code and see how it works and then to take the appropriate code +and apply it to your own project. You should include the dris.vb file in your project and use/modify which +ever functions from form1.vb you feel are appropriate. The dris.vb file should not be modified. + +The sample code contains 11 functions. You will not need to use all these functions in your code. Just use +which ever functions are most appropriate and customise in your own way. The sample code is just a guide. +You should implement the protection in a stronger way using the techniques described in the +"Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. However, you should still +display or log any error codes returned by the protection check otherwise you will not be able to +identify the cause of the error. (You can look up error codes in our knowledge base: microcosm.com/kb). + +For users of Visual Studio 2005 or higher, the default setting for projects is to compile for the Target +Platform "Any". This means that on 32-bit Windows, your code will run as 32-bit code (and needs to call +dpwin32.dll) and under 64-bit Windows your code will run as 64-bit code (and needs to call dpwin64.dll). +The sample code works this out automatically. If you select the target platform as "x86" then it will +always be 32-bit and so you only need to use dpwin32.dll. If you select "x64" then your code will be +64-bit and you only need to use dpwin64.dll. + +Note - as you are using the API method in this sample you should protect dpwin32.dll and/or dpwin64.dll +and not your program. Because your program is linked to the DLL it is protected. You can also protect +your program with the Shell Method should you wish. + +Note - if you are compiling for the Platform target "Any" (and therefore need to protect both dpwin32.dll +and dpwin64.dll) then you will probably want to protect these modules to the same licence so that they share +a common set of protection parameters. + +Make sure you remember to do the following: + +1) Insert the following namespaces in your code file: +Imports System.Runtime.InteropServices + +2) Insert the dris.vb file in your project. + +3) The protected dpwin32.dll (dpwin64.dll) should be output to the folder that contains your EXE file. +Otherwise the message "Unable to open DLL (dpwin32.dll)" or System.DllNotFoundException error will appear +when you run DllTest. Unfortunately, when the system displays these exceptions, it gives the choice of +"Continue" which will return from the program assuming it returned success - and thereby bypassing the +protection check. To combat this we have added the Protection_Err exception handler to handle exceptions. +This behaviour appears to be unique to VB.NET. + +If you wish you can rename dpwin32.dll (dpwin64.dll) to a name of your choice. In this case you will need to +modify the dll name in the dris.vb file. + +Note - VB.NET is an interpreted language and so it is easier to decompile than other languages. You can +improve security if you use an obfuscator to obfuscate your code. Or - even better - you could use the +Shell Method to protect your executable. This encrypts your code (making it impossible to decompile). + +Note for using strings in DRIS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +To set the alt_licence_name field and read the prodcode field in the DRIS you need to use the +SetAltLicenceName and GetProductCode functions. You can use other fields directly, e.g. dris.sdsn + +Notes on Debugging 64-bit Code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +When you use the 64-bit runtime module (dpwin64.dll) to protect your software the anti-debug code is so +strong that if you are debugging your code, after the call DDProtCheck then it will crash with an SEH +exception. If you want to be able to debug your code then you can setup your project so that your code +calls the debug module (dpwin64debug.dll) in your "debug" build and the standard module (dpwin64.dll) +in your release build. You can do this by modifying the declaration of DDProtCheck64 in dris.vb like this: + +#if DEBUG ' debug module + Declare Function DDProtCheck64 Lib "dpwin64debug.dll" Alias "DDProtCheck" (ByRef mydris As DRIS, ByVal data() As Byte) As Integer +#else ' standard module + Declare Function DDProtCheck64 Lib "dpwin64.dll" Alias "DDProtCheck" (ByRef mydris As DRIS, ByVal data() As Byte) As Integer +#endif + +Note - the debug module has the following restrictions: + +1) It will not correctly start a network user (network dongles only). However, other than that the protection + check will function correctly and return success. +2) You will not be able to encrypt the DRIS. (If you do encrypt the DRIS in your release build then you + should make sure that CryptDRIS does not get called in your debug build). +3) The protection check will take slightly longer than normal. +4) The DDGetNetUserList function will return error 428 (not implemented). +5) A temporary subprocess is created which may be (falsely) detected as malicious by anti-virus programs. + +This behaviour does not occur in 32-bit code, so if you are using dpwin32.dll then you can debug your code. + +Special Note for using Algorithms in VB.NET +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The algorithms are calculated using 32-bit integers (Integer in vb.net). It is quite possible for the +MyAlgorithm and MyRWAlgorithm functions to overflow if the values provided are too big. In the dongle the +algorithms can never overflow - if the answer is too big then the high part of the answer is ignored. +In practical terms: + +When you are using the r/w algorithm it is best not to pass random 32-bit integers. It is better to restrict +the variables to 24-bit to avoid the possibility of overflows. You can see this implemented in the MyRWAlgorithm +and WriteBytesEnc function, for example. + +You can also use this technique with the user algorithms. Another option in MyAlgorithm is to convert each input +to 64-bit, apply the algorithm and then convert back to 32-bit to return the answer. + +When using a user algorithm it will behave exactly as the corresponding MyAlgorithm function will in VB +except it will not give overflow errors. + +Important Note for UWP app Developers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Universal Windows Platform (UWP) application (previously called Windows Store Apps or Metro Apps) are not +compatible with Lite or Plus dongles because the restrictions imposed by these applications. However, you +can protect these Apps with network dongles (because the restrictive access is performed by the non-UWP +DinkeyServer process). If you do this you will need to enable the "Private Networks (Client and Server)" +Capability in your package manifest. + +.NET Core / .NET 5+ +~~~~~~~~~~~~~~~~~~~ + +The sample code provided also works with .NET Core. However, .NET Core also supports Linux and macOS as well +as other platforms. If you want to support these OS then please replace dris.vb with dris_dotnetcore.vb. +The files are very similar but dris_dotnetcore.vb will load the relevant native runtime module (dpwin32.dll +under 32-bit Windows; dpwin64.dll under 64-bit Windows; dplin64.so under Linux OS; dpmac64debug.dylib under +macOS - unfortunately the release module is not compatible with the .NET Core framework so you have to use +the debug one. This also means that our solution is not compatible with ARM-based macOS - because the debug +modules do not exist). + +If you are using .NET Core version earlier than 3.0 then Windows.Forms are not supported and you will have to +replace the MessageBox.Show lines with Console.WriteLine. + +The Shell Method is compatible with .NET Core Console, Windows.Forms and WPF applications. It is supported +under Windows and Linux but not macOS. It is only supported for .NET Core version 3.0 or higher. If you are +using the Shell Method then you should protect your compiled dll and not the "appHost" (this is a native +executable which is just a stub program that loads the assemblies in your dll). Also do not use "dotnet run" +to launch your application - it will run the unprotected version. Either launch the executable or run using +"dotnet ". + +If you publish a "single-file executable" file then although this file can be protected we do not recommend +it because it is not secure. (The single-file executable just comprises a stub loader with your compiled +assemblies and configuration files appended to the end of the executable. These files are just considered as +data appended to the executable file in a custom format and therefore are not protected. When you shell +protect your executable you are just protecting the loader but not your assemblies). Instead you need to +build your code and then add protection before publishing. You should protect your assemblies in the obj +directory (and in the platform type you specified) e.g. obj/Release/net5.0/win-x64, because the publish +process takes your assemblies from this location when it builds the single-file executable. You will also +need to distribute all the extra files that DinkeyAdd generates. e.g. .dp64.dll. + +If you publish using the ReadytoRun compilation this will not work because it includes mixtures of .NET +assemblies and native code and the .NET Shell Method does not support that. + +Visual Studio Installer Projects Extension +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can use this extension to create a project in your solution that will create an installation program / msi +file. Please note that after your application has been built you need to protect it with DinkeyAdd before you +can invoke the installer project. You can do this manually by building your application project (not the entire +solution); then adding protection to your application using DinkeyAdd; then building your installer project. +Or you can automate this by executing DinkeyAddCmd as a post-build step. For example: +"c:\program files (x86)\Dinkey Pro 7.6.0\DinkeyAdd\DinkeyAddCmd.exe" c:\adir\mydapf.dapfj /a2 + +Note - if you specify "primary output" in your installer project then it will take the files from +obj\Release\net5.0 (for example), rather than bin\Release\net5.0. So, you need to add protection to your files +in this folder. + +Note - if you use the API Method you will also need to include the protected runtime modules that you use +(e.g. dpwin64.dll). If you use the Shell Method you will also need to include in your installer project all +of the output files mentioned by DinkeyAdd. e.g. .dp64.dll diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/dris.vb b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/dris.vb new file mode 100644 index 0000000..afd2fa5 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/dris.vb @@ -0,0 +1,218 @@ +' !! this file should not be modified + +Imports System.Runtime.InteropServices +Imports System.Text + +Module dris_code + + _ + Structure DRIS + ' the first 4 fields are never encrypted + Dim header1 As Byte ' should be set to 'DRIS' + Dim header2 As Byte + Dim header3 As Byte + Dim header4 As Byte + ' inputs + Dim size As Integer ' size of this structure + Dim seed1 As Integer ' seed for data/dris encryption + Dim seed2 As Integer ' as above + ' (maybe encrypted from now on) + Dim myfunction As Integer ' specify only one function + Dim flags As Integer ' options for the function selected. To use more than one OR them together: OPTION1 Or OPTION2... + Dim execs_decrement As UInt32 ' amount by which to dec execs if we use flag: DEC_MANY_EXECS + Dim data_crypt_key_num As Integer ' number of the key (1-3) that the dongle uses to encrypt or decrypt user data + Dim rw_offset As Integer ' offset in the dongle data area to read or write data + Dim rw_length As Integer ' length of data are to read/write/encrypt/decrypt + Dim DoNotUse As IntPtr ' do not use the rw_data_ptr element use the "Data" argument of the DDProtCheck function + ' to set this field use the function SetAltLicenceName instead + Dim _alt_licence_name As Byte() + Dim var_a As Integer ' variable values for user algorithm + Dim var_b As Integer + Dim var_c As Integer + Dim var_d As Integer + Dim var_e As Integer + Dim var_f As Integer + Dim var_g As Integer + Dim var_h As Integer + Dim alg_number As Integer ' the number of the user algorithm that you want to execute + ' outputs + Dim ret_code As Integer ' return code from the protection check + Dim ext_err As Integer ' extended error + Dim type As Integer ' type of dongle detected. 1 = Pro, 2 = FD + Dim model As Integer ' model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + Dim sdsn As Integer ' Software Developer's Serial Number + 'to read this field use the function GetProductCode instead + Dim _prodcode As Byte() + Dim dongle_number As UInt32 + Dim update_number As Integer + Dim data_area_size As UInt32 ' size of the data area in the dongle detected + Dim max_alg_num As Integer ' the maximum algorithm number in the dongle detected + Dim execs As Integer ' executions left: -1 indicates 'no limit' + Dim exp_day As Integer ' expiry day: -1 indicates 'no limit' + Dim exp_month As Integer ' expiry month: -1 indicates 'no limit' + Dim exp_year As Integer ' expiry year: -1 indicates 'no limit' + Dim features As UInt32 ' features value + Dim net_users As Integer ' maximum number of network users for the dongle detected: -1 indicates 'mo limit' + Dim alg_answer As Integer ' answer to the user algorithm executed with the given variable values + Dim fd_capacity As UInt32 ' capacity of the data area in FD dongle. Currently fixed at ~10MB but may change in the future. + 'to read this field use the function GetFDDrive instead + Dim _fd_drive As Byte() + Dim swkey_type As Integer ' 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + Dim swkey_exp_day As Integer ' software key expiry date (if software key detected) + Dim swkey_exp_month As Integer + Dim swkey_exp_year As Integer + End Structure + + _ + Structure NU_INFO + _ + Dim LicenceName As String + _ + Dim UserName As String + _ + Dim ComputerName As String + _ + Dim IPAddress As String + End Structure + + ' functions exported from dpwin32.dll / dpwin32.dll - do 32-bit and 64-bit separately + + ' DDProtCheck + Declare Function DDProtCheck32 Lib "dpwin32.dll" Alias "DDProtCheck" (ByRef mydris As DRIS, ByVal data() As Byte) As Integer + Declare Function DDProtCheck64 Lib "dpwin64.dll" Alias "DDProtCheck" (ByRef mydris As DRIS, ByVal data() As Byte) As Integer + + ' DDGetNetUserList + Declare Ansi Function DDGetNetUserList32 Lib "dpwin32.dll" Alias "DDGetNetUserList" (ByVal licence_name As String, ByRef num_net_users As Integer, _ + ByVal nu_info_bytes() As Byte, ByVal num_info_structs As Integer, ByRef extended_error As Integer) As Integer + Declare Ansi Function DDGetNetUserList64 Lib "dpwin64.dll" Alias "DDGetNetUserList" (ByVal licence_name As String, ByRef num_net_users As Integer, _ + ByVal nu_info_bytes() As Byte, ByVal num_info_structs As Integer, ByRef extended_error As Integer) As Integer + + ' call the correct dll depending on whether we are running 32-bit or 64-bit code + Function DDProtCheck(ByRef mydris As DRIS, ByVal data() As Byte) As Integer + If (IntPtr.Size = 4) Then + DDProtCheck = DDProtCheck32(mydris, data) + Else + DDProtCheck = DDProtCheck64(mydris, data) + End If + End Function + + Function DDGetNetUserList(ByVal licence_name As String, ByRef num_net_users As Integer, ByRef nu_info_array() As NU_INFO, ByVal num_info_structs As Integer, ByRef extended_error As Integer) As Integer + Dim i As Integer + Dim my_nu_info As New NU_INFO ' NB this only exists so we can get the size of the NU_INFO stucture + Dim nu_info_bytes(num_info_structs * Marshal.SizeOf(my_nu_info)) As Byte + Dim nu_info_one_struct(Marshal.SizeOf(my_nu_info)) As Byte + Dim MyGC As GCHandle + + ' call the function and get info as a byte array + If (IntPtr.Size = 4) Then + DDGetNetUserList = DDGetNetUserList32(licence_name, num_net_users, nu_info_bytes, num_info_structs, extended_error) + Else + DDGetNetUserList = DDGetNetUserList64(licence_name, num_net_users, nu_info_bytes, num_info_structs, extended_error) + End If + + ' convert byte array to an array of structs + For i = 0 To num_net_users - 1 + nu_info_array(i) = New NU_INFO + Array.Copy(nu_info_bytes, i * Marshal.SizeOf(my_nu_info.GetType), nu_info_one_struct, 0, Marshal.SizeOf(my_nu_info.GetType)) + MyGC = GCHandle.Alloc(nu_info_one_struct, GCHandleType.Pinned) + nu_info_array(i) = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, my_nu_info.GetType) + MyGC.Free() + Next + + End Function + + ' Functions + Public Const PROTECTION_CHECK As Integer = 1 ' checks for dongle, check program params... + Public Const EXECUTE_ALGORITHM As Integer = 2 ' protection check + calculate answer for specified algorithm with specified inputs + Public Const WRITE_DATA_AREA As Integer = 3 ' protection check + writes dongle data area + Public Const READ_DATA_AREA As Integer = 4 ' protection check + reads dongle data area + Public Const ENCRYPT_USER_DATA As Integer = 5 ' protection check + the dongle will encrypt user data + Public Const DECRYPT_USER_DATA As Integer = 6 ' protection check + the dongle will decrypt user data + Public Const FAST_PRESENCE_CHECK As Integer = 7 ' checks for the presence of the correct dongle only with minimal security, no flags allowed + Public Const STOP_NET_USER As Integer = 8 ' stops a network user (a protection check is NOT performed) + + ' Flags + Public Const DEC_ONE_EXEC As Integer = 1 ' decrement execs by 1 + Public Const DEC_MANY_EXECS As Integer = 2 ' decrement execs by number specified in execs + Public Const START_NET_USER As Integer = 4 ' starts a network user + Public Const USE_FUNCTION_ARGUMENT As Integer = 16 ' use the extra argument in the function for pointers + Public Const CHECK_LOCAL_FIRST As Integer = 32 ' always look in local ports before looking in network ports + Public Const CHECK_NETWORK_FIRST As Integer = 64 ' always look on the network before looking in local ports + Public Const USE_ALT_LICENCE_NAME As Integer = 128 ' use name specified in alt_licence_name instead of the default one + Public Const DONT_SET_MAXDAYS_EXPIRY As Integer = 256 ' if the max days expiry date has not been calculated then do not do it this time + Public Const MATCH_DONGLE_NUMBER As Integer = 512 ' restrict the search to match the dongle number specified in the DRIS + Public Const DONT_RETURN_FD_DRIVE As Integer = 1024 ' if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + + Public Const NU_INFO_SIZE As Integer = (256 + 50 + 256 + 16) ' size of NU_INFO structure (for listing network users) + + ' ********************** useful functions for use in sample code *************************** + ' use this function to set the alt_licence_name field of the DRIS + Public Sub SetAltLicenceName(ByVal mydris As DRIS, ByVal altlicencename As String) + Dim i, num_bytes As Integer + Dim ascii As New ASCIIEncoding + Dim temp As Byte() + + temp = ascii.GetBytes(altlicencename) + num_bytes = ascii.GetByteCount(altlicencename) + For i = 0 To num_bytes - 1 + mydris._alt_licence_name(i) = temp(i) + Next + mydris._alt_licence_name(num_bytes) = 0 'null-terminate string + End Sub + + ' use this function to read the prodcode field of the DRIS + Public Function GetProductCode(ByVal mydris As DRIS) As String + Dim ascii As New ASCIIEncoding + Dim i As Integer + For i = 0 To 11 + If mydris._prodcode(i) = 0 Then + Exit For + End If + Next + Return ascii.GetString(mydris._prodcode, 0, i) + End Function + + ' use this function to read the fd_drive field of the DRIS + Public Function GetFDDrive(ByVal mydris As DRIS) As String + Dim ascii As New ASCIIEncoding + Dim i As Integer + For i = 0 To 127 + If mydris._fd_drive(i) = 0 Then + Exit For + End If + Next + Return ascii.GetString(mydris._fd_drive, 0, i) + End Function + + ' copies an integer to offset "index" in trhe specified byte array + Public Sub Set4Bytes(ByVal data() As Byte, ByVal index As Integer, ByVal value As Integer) + Dim MyGC As GCHandle = GCHandle.Alloc(value, GCHandleType.Pinned) + Dim AddressOfValue As IntPtr = MyGC.AddrOfPinnedObject() + Marshal.Copy(AddressOfValue, data, index, 4) + MyGC.Free() + End Sub + + ' converts to DRIS structure to a byte array (so we can do encryption) + Public Sub DrisToByteArray(ByVal mydris As DRIS, ByVal data() As Byte) + Dim MyGC As GCHandle = GCHandle.Alloc(data, GCHandleType.Pinned) + Marshal.StructureToPtr(mydris, MyGC.AddrOfPinnedObject, False) + MyGC.Free() + End Sub + + ' converts a byte array to the DRIS structure (so we can do encryption) + Public Sub ByteArrayToDris(ByVal data() As Byte, ByRef mydris As DRIS) + Dim MyGC As GCHandle = GCHandle.Alloc(data, GCHandleType.Pinned) + mydris = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, mydris.GetType) + MyGC.Free() + End Sub + + ' initialise the DRIS with random values + Public Sub RandomSet(ByRef mydris As DRIS) + Dim temp_dris(Marshal.SizeOf(mydris) - 1) As Byte + Dim rnd As New Random + + rnd.NextBytes(temp_dris) + ByteArrayToDris(temp_dris, mydris) + End Sub + +End Module diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/dris_dotnetcore.vb b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/dris_dotnetcore.vb new file mode 100644 index 0000000..7b7fe4f --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic .NET/Runtime/dris_dotnetcore.vb @@ -0,0 +1,236 @@ +' !! this file should not be modified + +Imports System.Runtime.InteropServices +Imports System.Text + +Module dris_code + + _ + Structure DRIS + ' the first 4 fields are never encrypted + Dim header1 As Byte ' should be set to 'DRIS' + Dim header2 As Byte + Dim header3 As Byte + Dim header4 As Byte + ' inputs + Dim size As Integer ' size of this structure + Dim seed1 As Integer ' seed for data/dris encryption + Dim seed2 As Integer ' as above + ' (maybe encrypted from now on) + Dim myfunction As Integer ' specify only one function + Dim flags As Integer ' options for the function selected. To use more than one OR them together: OPTION1 Or OPTION2... + Dim execs_decrement As UInt32 ' amount by which to dec execs if we use flag: DEC_MANY_EXECS + Dim data_crypt_key_num As Integer ' number of the key (1-3) that the dongle uses to encrypt or decrypt user data + Dim rw_offset As Integer ' offset in the dongle data area to read or write data + Dim rw_length As Integer ' length of data are to read/write/encrypt/decrypt + Dim DoNotUse As IntPtr ' do not use the rw_data_ptr element use the "Data" argument of the DDProtCheck function + ' to set this field use the function SetAltLicenceName instead + Dim _alt_licence_name As Byte() + Dim var_a As Integer ' variable values for user algorithm + Dim var_b As Integer + Dim var_c As Integer + Dim var_d As Integer + Dim var_e As Integer + Dim var_f As Integer + Dim var_g As Integer + Dim var_h As Integer + Dim alg_number As Integer ' the number of the user algorithm that you want to execute + ' outputs + Dim ret_code As Integer ' return code from the protection check + Dim ext_err As Integer ' extended error + Dim type As Integer ' type of dongle detected. 1 = Pro, 2 = FD + Dim model As Integer ' model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + Dim sdsn As Integer ' Software Developer's Serial Number + 'to read this field use the function GetProductCode instead + Dim _prodcode As Byte() + Dim dongle_number As UInt32 + Dim update_number As Integer + Dim data_area_size As UInt32 ' size of the data area in the dongle detected + Dim max_alg_num As Integer ' the maximum algorithm number in the dongle detected + Dim execs As Integer ' executions left: -1 indicates 'no limit' + Dim exp_day As Integer ' expiry day: -1 indicates 'no limit' + Dim exp_month As Integer ' expiry month: -1 indicates 'no limit' + Dim exp_year As Integer ' expiry year: -1 indicates 'no limit' + Dim features As UInt32 ' features value + Dim net_users As Integer ' maximum number of network users for the dongle detected: -1 indicates 'mo limit' + Dim alg_answer As Integer ' answer to the user algorithm executed with the given variable values + Dim fd_capacity As UInt32 ' capacity of the data area in FD dongle. Currently fixed at ~10MB but may change in the future. + 'to read this field use the function GetFDDrive instead + Dim _fd_drive As Byte() + Dim swkey_type As Integer ' 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + Dim swkey_exp_day As Integer ' software key expiry date (if software key detected) + Dim swkey_exp_month As Integer + Dim swkey_exp_year As Integer + End Structure + + _ + Structure NU_INFO + _ + Dim LicenceName As String + _ + Dim UserName As String + _ + Dim ComputerName As String + _ + Dim IPAddress As String + End Structure + + ' functions exported from runtime module e.g. dpwin64.dll etc + + ' DDProtCheck + Declare Function DDProtCheckWin32 Lib "dpwin32.dll" Alias "DDProtCheck" (ByRef mydris As DRIS, ByVal data() As Byte) As Integer + Declare Function DDProtCheckWin64 Lib "dpwin64.dll" Alias "DDProtCheck" (ByRef mydris As DRIS, ByVal data() As Byte) As Integer + Declare Function DDProtCheckLin64 Lib "dplin64.so" Alias "DDProtCheck" (ByRef mydris As DRIS, ByVal data() As Byte) As Integer + Declare Function DDProtCheckMac64 Lib "dpmac64debug.dylib" Alias "DDProtCheck" (ByRef mydris As DRIS, ByVal data() As Byte) As Integer + + ' DDGetNetUserList - NB not supported for macOS as this function does not exist in the debug module + Declare Ansi Function DDGetNetUserListWin32 Lib "dpwin32.dll" Alias "DDGetNetUserList" (ByVal licence_name As String, ByRef num_net_users As Integer, + ByVal nu_info_bytes() As Byte, ByVal num_info_structs As Integer, ByRef extended_error As Integer) As Integer + Declare Ansi Function DDGetNetUserListWin64 Lib "dpwin64.dll" Alias "DDGetNetUserList" (ByVal licence_name As String, ByRef num_net_users As Integer, + ByVal nu_info_bytes() As Byte, ByVal num_info_structs As Integer, ByRef extended_error As Integer) As Integer + Declare Ansi Function DDGetNetUserListLin64 Lib "dplin64.so" Alias "DDGetNetUserList" (ByVal licence_name As String, ByRef num_net_users As Integer, + ByVal nu_info_bytes() As Byte, ByVal num_info_structs As Integer, ByRef extended_error As Integer) As Integer + + ' call the correct dll depending on whether we are running 32-bit or 64-bit code + Function DDProtCheck(ByRef mydris As DRIS, ByVal data() As Byte) As Integer + If (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) Then + If (Environment.Is64BitProcess) Then + DDProtCheck = DDProtCheckWin64(mydris, data) + Else + DDProtCheck = DDProtCheckWin32(mydris, data) + End If + ElseIf (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) Then + DDProtCheck = DDProtCheckLin64(mydris, data) + ElseIf (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) Then + DDProtCheck = DDProtCheckMac64(mydris, data) + Else + DDProtCheck = -1 ' OS not supported + End If + End Function + + Function DDGetNetUserList(ByVal licence_name As String, ByRef num_net_users As Integer, ByRef nu_info_array() As NU_INFO, ByVal num_info_structs As Integer, ByRef extended_error As Integer) As Integer + Dim i As Integer + Dim my_nu_info As New NU_INFO ' NB this only exists so we can get the size of the NU_INFO stucture + Dim nu_info_bytes(num_info_structs * Marshal.SizeOf(my_nu_info)) As Byte + Dim nu_info_one_struct(Marshal.SizeOf(my_nu_info)) As Byte + Dim MyGC As GCHandle + + ' call the function and get info as a byte array + If (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) Then + If (Environment.Is64BitProcess) Then + DDGetNetUserList = DDGetNetUserListWin64(licence_name, num_net_users, nu_info_bytes, num_info_structs, extended_error) + Else + DDGetNetUserList = DDGetNetUserListWin32(licence_name, num_net_users, nu_info_bytes, num_info_structs, extended_error) + End If + ElseIf (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) Then + DDGetNetUserList = DDGetNetUserListLin64(licence_name, num_net_users, nu_info_bytes, num_info_structs, extended_error) + Else + DDGetNetUserList = -1 ' OS not supported (this includes macOS) + End If + + ' convert byte array to an array of structs + For i = 0 To num_net_users - 1 + nu_info_array(i) = New NU_INFO + Array.Copy(nu_info_bytes, i * Marshal.SizeOf(my_nu_info.GetType), nu_info_one_struct, 0, Marshal.SizeOf(my_nu_info.GetType)) + MyGC = GCHandle.Alloc(nu_info_one_struct, GCHandleType.Pinned) + nu_info_array(i) = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, my_nu_info.GetType) + MyGC.Free() + Next + + End Function + + ' Functions + Public Const PROTECTION_CHECK As Integer = 1 ' checks for dongle, check program params... + Public Const EXECUTE_ALGORITHM As Integer = 2 ' protection check + calculate answer for specified algorithm with specified inputs + Public Const WRITE_DATA_AREA As Integer = 3 ' protection check + writes dongle data area + Public Const READ_DATA_AREA As Integer = 4 ' protection check + reads dongle data area + Public Const ENCRYPT_USER_DATA As Integer = 5 ' protection check + the dongle will encrypt user data + Public Const DECRYPT_USER_DATA As Integer = 6 ' protection check + the dongle will decrypt user data + Public Const FAST_PRESENCE_CHECK As Integer = 7 ' checks for the presence of the correct dongle only with minimal security, no flags allowed + Public Const STOP_NET_USER As Integer = 8 ' stops a network user (a protection check is NOT performed) + + ' Flags + Public Const DEC_ONE_EXEC As Integer = 1 ' decrement execs by 1 + Public Const DEC_MANY_EXECS As Integer = 2 ' decrement execs by number specified in execs + Public Const START_NET_USER As Integer = 4 ' starts a network user + Public Const USE_FUNCTION_ARGUMENT As Integer = 16 ' use the extra argument in the function for pointers + Public Const CHECK_LOCAL_FIRST As Integer = 32 ' always look in local ports before looking in network ports + Public Const CHECK_NETWORK_FIRST As Integer = 64 ' always look on the network before looking in local ports + Public Const USE_ALT_LICENCE_NAME As Integer = 128 ' use name specified in alt_licence_name instead of the default one + Public Const DONT_SET_MAXDAYS_EXPIRY As Integer = 256 ' if the max days expiry date has not been calculated then do not do it this time + Public Const MATCH_DONGLE_NUMBER As Integer = 512 ' restrict the search to match the dongle number specified in the DRIS + Public Const DONT_RETURN_FD_DRIVE As Integer = 1024 ' if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + + Public Const NU_INFO_SIZE As Integer = (256 + 50 + 256 + 16) ' size of NU_INFO structure (for listing network users) + + ' ********************** useful functions for use in sample code *************************** + ' use this function to set the alt_licence_name field of the DRIS + Public Sub SetAltLicenceName(ByVal mydris As DRIS, ByVal altlicencename As String) + Dim i, num_bytes As Integer + Dim ascii As New ASCIIEncoding + Dim temp As Byte() + + temp = ascii.GetBytes(altlicencename) + num_bytes = ascii.GetByteCount(altlicencename) + For i = 0 To num_bytes - 1 + mydris._alt_licence_name(i) = temp(i) + Next + mydris._alt_licence_name(num_bytes) = 0 'null-terminate string + End Sub + + ' use this function to read the prodcode field of the DRIS + Public Function GetProductCode(ByVal mydris As DRIS) As String + Dim ascii As New ASCIIEncoding + Dim i As Integer + For i = 0 To 11 + If mydris._prodcode(i) = 0 Then + Exit For + End If + Next + Return ascii.GetString(mydris._prodcode, 0, i) + End Function + + ' use this function to read the fd_drive field of the DRIS + Public Function GetFDDrive(ByVal mydris As DRIS) As String + Dim ascii As New ASCIIEncoding + Dim i As Integer + For i = 0 To 127 + If mydris._fd_drive(i) = 0 Then + Exit For + End If + Next + Return ascii.GetString(mydris._fd_drive, 0, i) + End Function + + ' copies an integer to offset "index" in trhe specified byte array + Public Sub Set4Bytes(ByVal data() As Byte, ByVal index As Integer, ByVal value As Integer) + Dim MyGC As GCHandle = GCHandle.Alloc(value, GCHandleType.Pinned) + Dim AddressOfValue As IntPtr = MyGC.AddrOfPinnedObject() + Marshal.Copy(AddressOfValue, data, index, 4) + MyGC.Free() + End Sub + + ' converts to DRIS structure to a byte array (so we can do encryption) + Public Sub DrisToByteArray(ByVal mydris As DRIS, ByVal data() As Byte) + Dim MyGC As GCHandle = GCHandle.Alloc(data, GCHandleType.Pinned) + Marshal.StructureToPtr(mydris, MyGC.AddrOfPinnedObject, False) + MyGC.Free() + End Sub + + ' converts a byte array to the DRIS structure (so we can do encryption) + Public Sub ByteArrayToDris(ByVal data() As Byte, ByRef mydris As DRIS) + Dim MyGC As GCHandle = GCHandle.Alloc(data, GCHandleType.Pinned) + mydris = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, mydris.GetType) + MyGC.Free() + End Sub + + ' initialise the DRIS with random values + Public Sub RandomSet(ByRef mydris As DRIS) + Dim temp_dris(Marshal.SizeOf(mydris) - 1) As Byte + Dim rnd As New Random + + rnd.NextBytes(temp_dris) + ByteArrayToDris(temp_dris, mydris) + End Sub + +End Module diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic/DinkeyChange/ChangeTest.bas b/Dinkey Pro 7.6.1/Samples/Visual Basic/DinkeyChange/ChangeTest.bas new file mode 100644 index 0000000..a03b903 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic/DinkeyChange/ChangeTest.bas @@ -0,0 +1,98 @@ +' !! this file should not be modified + +Attribute VB_Name = "Module1" +' API functions +Declare Function DCGetInfo Lib "DinkeyChange.dll" (ByVal type_mask As Long, ByVal model_mask As Long, ByVal prodcode_mask As Any, ByVal array_length As Long, _ + num_found As Long, type_array As FixedIntegerArray, model_array As FixedIntegerArray, prodcode_array As FixedByteArray, dongle_number_array As FixedIntegerArray, update_number_array As FixedIntegerArray) As Long +Declare Function DCGetDiagnosticInfo Lib "DinkeyChange.dll" (ByVal DiagFileName As Any) As Long +Declare Function DCDoUpdateCodeString Lib "DinkeyChange.dll" (ByVal UpdateCode As Any, confirmation_code As Long, extended_error As Long) As Long +Declare Function DCDoUpdateCodeFromFile Lib "DinkeyChange.dll" (ByVal UpdateCodeFile As Any, confirmation_code As Long, extended_error As Long) As Long +Declare Function DCRestoreDinkeyFDLite Lib "DinkeyChange.dll" () As Long +Declare Function DCGetMachineID Lib "DinkeyChange.dll" (machineID As Long, extended_error As Long) As Long +Declare Function DCDownloadTempSoftwareKey Lib "DinkeyChange.dll" (ByVal machineID As Long, extended_error As Long) As Long +Declare Function DCDownloadDemoSoftwareKey Lib "DinkeyChange.dll" (ByVal machineID As Long, ByVal ProdCode As Any, ByVal model As Long, extended_error As Long) As Long + +' maximum number of USB dongles that can be attached to a machine at any one time +Public Const MAX_USB_DEVICES = 128 + +' mask values +Public Const TYPE_MASK_PRO = 1 +Public Const TYPE_MASK_FD = 2 +Public Const TYPE_MASK_ALL = (TYPE_MASK_PRO Or TYPE_MASK_FD) + +Public Const MODEL_MASK_LITE = 1 +Public Const MODEL_MASK_PLUS = 2 +Public Const MODEL_MASK_NET = 4 +Public Const MODEL_MASK_ALL = (MODEL_MASK_LITE Or MODEL_MASK_PLUS Or MODEL_MASK_NET) +Public Const MODEL_MASK_DEFAULT = (MODEL_MASK_PLUS Or MODEL_MASK_NET) + +' type values for DCGetInfo (returned in the array) +Public Const TYPE_PRO = 1 +Public Const TYPE_FD = 2 + +' model values for DCGetInfo (returned in the array) +Public Const MODEL_LITE = 1 +Public Const MODEL_PLUS = 2 +Public Const MODEL_NET5 = 4 +Public Const MODEL_NETU = 7 + +' model values for DCDownloadDemoSoftwareKey +Public Const SWKEY_MODEL_DEFAULT = &HFFFFFFFF ' NB this assumes that the Demo Software Key Template was created with only one valid dongle model +Public Const SWKEY_MODEL_PRO_LITE = 0 +Public Const SWKEY_MODEL_PRO_PLUS = 1 +Public Const SWKEY_MODEL_PRO_NET = 2 +Public Const SWKEY_MODEL_FD_LITE = 3 +Public Const SWKEY_MODEL_FD_PLUS = 4 +Public Const SWKEY_MODEL_FD_NET = 5 + +'we need a structure for an array of bytes because otherwise the VB runtime can move the data in-between function calls +Type FixedByteArray + data(0 To MAX_USB_DEVICES * 9) As Byte ' 9 is the prodcode length (including terminating null) +End Type + +' and ints +Type FixedIntegerArray + data(1 To MAX_USB_DEVICES) As Long +End Type + +' this function converts an unsigned integer to a double for display purposes (otherwise it may display the dongle number as a negative number!) +Public Function UIntToDouble(ByVal number As Long) As Double + UIntToDouble = CDbl(number) + If UIntToDouble < 0 Then + UIntToDouble = UIntToDouble + 2 ^ 32 + End If +End Function + +' this function gets the index-th prodcode from the array +Public Function GetProdCodeFromArray(prodcode As FixedByteArray, ByVal index As Long) As String + Dim data As Byte ' this will be a byte of data from array + + index = index - 1 ' so it is 0-based + GetProdCodeFromArray = "" + For i = 0 To 8 + data = prodcode.data((index * 9) + i) + If data = 0 Then ' stop when we get to the null + Exit For + Else ' otherwise append character to string + GetProdCodeFromArray = GetProdCodeFromArray & Chr(data) + End If + Next +End Function + +' this function will convert the C string returned in the DCIS to a VB string +' e.g. to access the product code use TrimCString(mydcis.prodcode) +Function TrimCString(Str As String) As String + Dim i As Integer + Dim length As Integer + + length = Len(Str) + + For i = 1 To length + If Mid(Str, i, 1) = Chr$(0) Then + TrimCString = Left$(Str, i - 1) 'take off null and rest of string + Exit For + End If + Next + +End Function + diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic/DinkeyChange/ChangeTest.frm b/Dinkey Pro 7.6.1/Samples/Visual Basic/DinkeyChange/ChangeTest.frm new file mode 100644 index 0000000..2a3f294 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic/DinkeyChange/ChangeTest.frm @@ -0,0 +1,361 @@ +VERSION 5.00 +Begin VB.Form ChangeTest + Caption = "ChangeTest" + ClientHeight = 9705 + ClientLeft = 60 + ClientTop = 345 + ClientWidth = 5235 + LinkTopic = "Form1" + ScaleHeight = 9705 + ScaleWidth = 5235 + StartUpPosition = 3 'Windows Default + Begin VB.CommandButton DownloadDemoSoftwareKey + Caption = "Download Demo Software Key" + Height = 315 + Left = 960 + TabIndex = 16 + Top = 9120 + Width = 3015 + End + Begin VB.TextBox SwKeyProdCode + Height = 375 + Left = 240 + TabIndex = 15 + Top = 8640 + Width = 4695 + End + Begin VB.TextBox ShowMachineID + Height = 375 + Left = 2640 + TabIndex = 13 + Top = 6720 + Width = 2295 + End + Begin VB.CommandButton DownloadTempSoftwareKey + Caption = "Download Temporary Software Key" + Height = 375 + Left = 1080 + TabIndex = 12 + Top = 7560 + Width = 2895 + End + Begin VB.CommandButton GetMachineID + Caption = "Get Machine ID" + Height = 375 + Left = 240 + TabIndex = 11 + Top = 6720 + Width = 2175 + End + Begin VB.CommandButton RestoreFDLite + Caption = "Restore FD Lite" + Height = 375 + Left = 1080 + TabIndex = 10 + Top = 5760 + Width = 2895 + End + Begin VB.CommandButton DoUpdateCodeFile + Caption = "Make Changes" + Height = 375 + Left = 1080 + TabIndex = 9 + Top = 4920 + Width = 2895 + End + Begin VB.TextBox UpdateCodeFile + Height = 405 + Left = 240 + TabIndex = 8 + Top = 4440 + Width = 4695 + End + Begin VB.CommandButton DoUpdateCodeString + Caption = "Make Changes" + Height = 375 + Left = 1080 + TabIndex = 6 + Top = 3360 + Width = 2895 + End + Begin VB.TextBox UpdateCodeString + Height = 405 + Left = 240 + TabIndex = 5 + Top = 2880 + Width = 4695 + End + Begin VB.CommandButton WriteDiags + Caption = "Write Diagnostics to File" + Height = 375 + Left = 1080 + TabIndex = 3 + Top = 1800 + Width = 2895 + End + Begin VB.TextBox DiagFileName + Height = 405 + Left = 240 + TabIndex = 2 + Top = 1320 + Width = 4695 + End + Begin VB.CommandButton GetInfo + Caption = "Get Dongle Information" + Height = 375 + Left = 1080 + TabIndex = 0 + Top = 360 + Width = 2895 + End + Begin VB.Label Label4 + Caption = "Demo Software Key Product Code:" + Height = 255 + Left = 240 + TabIndex = 14 + Top = 8400 + Width = 4695 + End + Begin VB.Label Label3 + Caption = "Enter path of Update Code file:" + Height = 255 + Left = 240 + TabIndex = 7 + Top = 4200 + Width = 4695 + End + Begin VB.Label Label2 + Caption = "Enter short Update Code here:" + Height = 255 + Left = 240 + TabIndex = 4 + Top = 2640 + Width = 4695 + End + Begin VB.Label Label1 + Caption = "Enter Diagnostic filename:" + Height = 255 + Left = 240 + TabIndex = 1 + Top = 1080 + Width = 4695 + End +End +Attribute VB_Name = "ChangeTest" +Attribute VB_GlobalNameSpace = False +Attribute VB_Creatable = False +Attribute VB_PredeclaredId = True +Attribute VB_Exposed = False + + +' !! We strongly recommend that you read the "readme.txt" file for this sample. +' !! It contains important instructions on how to use the sample code + +' Display Dongle Information +Private Sub GetInfo_Click() + Dim ret_code As Long + Dim num_found As Long + Dim DisplayString, DongleType, DongleModel, ProdCodeString As String + ' these are the arrays of dongle information filled-in by DCGetInfo + Dim type_array As FixedIntegerArray + Dim model_array As FixedIntegerArray + Dim prodcode_array As FixedByteArray + Dim dongle_number_array As FixedIntegerArray + Dim update_number_array As FixedIntegerArray + + ' find dongle information for all dongle types, Plus & Net models, for all product codes + ' NB In practice you will probably want to set the prodcode_mask to the value of your product code + ret_code = DCGetInfo(TYPE_MASK_ALL, MODEL_MASK_DEFAULT, "", MAX_USB_DEVICES, num_found, type_array, model_array, prodcode_array, dongle_number_array, update_number_array) + + ' check for errors + If ret_code = 401 Then + MsgBox "No dongles detected matching the search criteria specified", vbOKOnly, "Error" + Exit Sub + End If + + If ret_code <> 0 Then + MsgBox "Error " + Str$(ret_code) + " getting dongle information", vbOKOnly, "Error" + Exit Sub + End If + + 'display dongle details + DisplayString = "" ' initialise + For i = 1 To num_found + If type_array.data(i) = 1 Then ' dongle type + DongleType = "Pro" + Else + DongleType = "FD" + End If + If model_array.data(i) = 1 Then ' dongle model + DongleModel = "Lite" + ElseIf model_array.data(i) = 2 Then + DongleModel = "Plus" + Else + DongleModel = "Net" + End If + ProdCodeString = GetProdCodeFromArray(prodcode_array, i) ' product code + ' add details for this dongle to list + DisplayString = DisplayString + Str$(i) + ". Dinkey " + DongleType + " " + DongleModel + ", product code " + ProdCodeString + " with dongle number " + Str$(UIntToDouble(dongle_number_array.data(i))) + ", update number " + Str$(update_number_array.data(i)) + vbNewLine + Next + + MsgBox DisplayString, vbOKOnly + +End Sub + +' Write dongle diagnostics to file +Private Sub WriteDiags_Click() + Dim ret_code As Long + + ret_code = DCGetDiagnosticInfo(DiagFileName.Text) + + If ret_code = 754 Then + MsgBox "Could not create the diagnostic file. Please check that the path exists:" + DiagFileName.Text, vbOKOnly, "Error" + Exit Sub + ElseIf ret_code <> 0 Then + MsgBox "Error " + Str$(ret_code) + " writing diagnostic file.", vbOKOnly, "Error" + Exit Sub + End If + + ' display success + MsgBox "Diagnostic file written successfully.", vbOKOnly +End Sub + +' update dongle with short code entered +Private Sub DoUpdateCodeString_Click() + Dim ret_code, confirmation_code, extended_error As Long + + ret_code = DCDoUpdateCodeString(UpdateCodeString.Text, confirmation_code, extended_error) + + If ret_code <> 0 Then + Call DisplayError(ret_code, extended_eror) + Exit Sub + End If + + MsgBox "Dongle updated successfully!" + vbNewLine + "Confirmation code is: " + Hex(confirmation_code), vbOnly +End Sub + +' update dongle using update code in specified file +Private Sub DoUpdateCodeFile_Click() + Dim ret_code, confirmation_code, extended_error As Long + + ret_code = DCDoUpdateCodeFromFile(UpdateCodeFile.Text, confirmation_code, extended_error) + + If ret_code <> 0 Then + Call DisplayError(ret_code, extended_eror) + Exit Sub + End If + + MsgBox "Dongle updated successfully!" + vbNewLine + "Confirmation code is: " + Hex(confirmation_code), vbOnly +End Sub + +Private Sub RestoreFDLite_Click() + Dim ret_code As Long + + ret_code = DCRestoreDinkeyFDLite() + + If ret_code <> 0 Then + Call DisplayError(ret_code, 0) + Exit Sub + End If + + ' display success + MsgBox "Dinkey FD Lite dongle restored successfully.", vbOKOnly +End Sub + +Private Sub GetMachineID_Click() + Dim ret_code, machineID, extended_error As Long + + ret_code = DCGetMachineID(machineID, extended_error) + + If ret_code <> 0 Then + Call DisplayError(ret_code, 0) + Exit Sub + End If + + ' display machine ID in text box + ShowMachineID.Text = Hex(machineID) +End Sub + +Private Sub DownloadTempSoftwareKey_Click() + Dim ret_code, machineID, extended_error As Long + + ' first get the machine ID... + ret_code = DCGetMachineID(machineID, extended_error) + + If ret_code <> 0 Then + Call DisplayError(ret_code, 0) + Exit Sub + End If + + ' ...then try to download the temporary software key + ret_code = DCDownloadTempSoftwareKey(machineID, extended_error) + + If ret_code <> 0 Then + Call DisplayError(ret_code, 0) + Exit Sub + End If + + MsgBox "The Temporary Software Key has been downloaded successfully!", vbOnly +End Sub + +Private Sub DownloadDemoSoftwareKey_Click() + Dim ret_code, machineID, extended_error As Long + + ' first get the machine ID... + ret_code = DCGetMachineID(machineID, extended_error) + + If ret_code <> 0 Then + Call DisplayError(ret_code, 0) + Exit Sub + End If + + ' ...then try to download the demo software key + '(NB we are assuming only one dongle model is set in the Demo Software Template. + ' If multiple models are set you will also need to specify the exact model) + ret_code = DCDownloadDemoSoftwareKey(machineID, SwKeyProdCode.Text, SWKEY_MODEL_DEFAULT, extended_error) + + If ret_code <> 0 Then + Call DisplayError(ret_code, 0) + Exit Sub + End If + + MsgBox "The Demo Software Key has been downloaded successfully!", vbOnly +End Sub + +' look at the error code and try to display an appropriate message +Public Sub DisplayError(ByVal ret_code As Long, ByVal extended_error As Long) + Select Case ret_code + Case 401 + MsgBox "Error! No dongles detected that meet the search criteria!", vbOKOnly, "Error" + Case 409 + MsgBox "Error! The dongle detected has not been programmed by DinkeyAdd.", vbOKOnly, "Error" + Case 758: + MsgBox "Error! Cannot open the Update Code file specified.", vbOKOnly, "Error" + Case 759: + MsgBox "Error! The file specified is not a valid Update Code file.", vbOKOnly, "Error" + Case 762, 763, 764 + MsgBox "Error! Update Code is not in a correct format / update code file is corrupt.", vbOKOnly, "Error" + Case 765 + MsgBox "Error! The Update Code does not match any dongle attached to your machine.", vbOKOnly, "Error" + Case 766 + MsgBox "Error! The update number for this Update Code is too high. You need to first enter an update code that was previously sent to you.", vbOKOnly, "Error" + Case 767: + MsgBox "Error! You have already entered this Update Code.", vbOKOnly, "Error" + Case 1905: + MsgBox "Error! There is no Software Key available for download.", vbOKOnly, "Error" + Case 1907: + MsgBox "Error! The Temporary Software Key has expired. Cannot download it.", vbOKOnly, "Error" + Case 1910: + MsgBox "Error! The Software Key has already been downloaded.", vbOKOnly, "Error" + Case 1921 + MsgBox "Error! You specified the 'default model' but there is more than one model available. You need to specify a specific dongle model.", vbOKOnly, "Error" + Case 1922: + MsgBox "Error! The model you requested is not available.", vbOKOnly, "Error" + Case 1923: + MsgBox "Error! The Demo Software Key Template has been disabled.", vbOKOnly, "Error" + Case 1924: + MsgBox "Error! You have run out of Demo Software Key activations. You need to order some more.", vbOKOnly, "Error" + Case Else + MsgBox "An error occurred checking the dongle. Error: " + Str$(ret_code) + ". Extended Error: " + Str$(extended_error) + ".", vbOKOnly, "Error" + End Select +End Sub diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic/DinkeyChange/ChangeTest.vbp b/Dinkey Pro 7.6.1/Samples/Visual Basic/DinkeyChange/ChangeTest.vbp new file mode 100644 index 0000000..5eb7ece --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic/DinkeyChange/ChangeTest.vbp @@ -0,0 +1,35 @@ +Type=Exe +Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#..\..\..\..\..\Windows\SysWOW64\stdole2.tlb#OLE Automation +Module=Module1; ChangeTest.bas +Form=ChangeTest.frm +Startup="ChangeTest" +HelpFile="" +ExeName32="ChangeTest.exe" +Command32="" +Name="Project1" +HelpContextID="0" +CompatibleMode="0" +MajorVer=1 +MinorVer=0 +RevisionVer=0 +AutoIncrementVer=0 +ServerSupportFiles=0 +VersionCompanyName="Microcosm Ltd" +CompilationType=0 +OptimizationType=0 +FavorPentiumPro(tm)=0 +CodeViewDebugInfo=0 +NoAliasing=0 +BoundsCheck=0 +OverflowCheck=0 +FlPointCheck=0 +FDIVCheck=0 +UnroundedFP=0 +StartMode=0 +Unattended=0 +Retained=0 +ThreadPerObject=0 +MaxNumberOfThreads=1 + +[MS Transaction Server] +AutoRefresh=1 diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic/DinkeyChange/ChangeTest.vbw b/Dinkey Pro 7.6.1/Samples/Visual Basic/DinkeyChange/ChangeTest.vbw new file mode 100644 index 0000000..475402b --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic/DinkeyChange/ChangeTest.vbw @@ -0,0 +1,2 @@ +Module1 = 525, 283, 1161, 899, +ChangeTest = 244, 99, 880, 715, , 66, 66, 702, 841, C diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic/DinkeyChange/README.txt b/Dinkey Pro 7.6.1/Samples/Visual Basic/DinkeyChange/README.txt new file mode 100644 index 0000000..01ac826 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic/DinkeyChange/README.txt @@ -0,0 +1,22 @@ +ChangeTest - sample code to call DinkeyChange.dll in Visual Basic +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Note: For VB.net code please look in the vb.net folder. + +The sample code contains 7 functions. Just use which ever functions are most +appropriate and customise in your own way. The sample code is just a guide. +As none of the parameters are sensitive then there is no need to implement +strong security in calling DinkeyChange. + +Note - to run the project from the IDE you will need to place the protected +DinkeyChange.dll in the 32-bit Windows System folder*. For release you can place +DinkeyChange.dll in the folder of the compiled executable or in the Windows System +directory. The former is generally considered better as it is easier to install. + +It is also recommended that you rename DinkeyChange.dll to a name of your choice. In +this case you will need to modify the dll name in the ChangeTest.bas file. + +~~~~~~~~~~~~~~~~~ +* Windows System folder for 32-bit dlls is: +c:\windows\system32 32-bit Windows +c:\windows\sysWOW64 64-bit Windows \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic/Runtime/DllTest.vbp b/Dinkey Pro 7.6.1/Samples/Visual Basic/Runtime/DllTest.vbp new file mode 100644 index 0000000..683c4be --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic/Runtime/DllTest.vbp @@ -0,0 +1,35 @@ +Type=Exe +Form=Form1.frm +Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#C:\WINNT\system32\stdole2.tlb#OLE Automation +Module=Module1; dris.bas +IconForm="Form1" +Startup="Form1" +ExeName32="DllTest.exe" +Command32="" +Name="DllTest" +HelpContextID="0" +CompatibleMode="0" +MajorVer=1 +MinorVer=0 +RevisionVer=0 +AutoIncrementVer=0 +ServerSupportFiles=0 +VersionCompanyName="Microcosm Ltd" +CompilationType=0 +OptimizationType=0 +FavorPentiumPro(tm)=0 +CodeViewDebugInfo=0 +NoAliasing=0 +BoundsCheck=0 +OverflowCheck=0 +FlPointCheck=0 +FDIVCheck=0 +UnroundedFP=0 +StartMode=0 +Unattended=0 +Retained=0 +ThreadPerObject=0 +MaxNumberOfThreads=1 + +[MS Transaction Server] +AutoRefresh=1 diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic/Runtime/DllTest.vbw b/Dinkey Pro 7.6.1/Samples/Visual Basic/Runtime/DllTest.vbw new file mode 100644 index 0000000..ec4079a --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic/Runtime/DllTest.vbw @@ -0,0 +1,2 @@ +Form1 = 243, 27, 938, 801, , 22, 22, 577, 462, C +Module1 = 22, 69, 888, 858, diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic/Runtime/Form1.frm b/Dinkey Pro 7.6.1/Samples/Visual Basic/Runtime/Form1.frm new file mode 100644 index 0000000..b0124f6 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic/Runtime/Form1.frm @@ -0,0 +1,980 @@ +VERSION 5.00 +Begin VB.Form Form1 + Caption = "DllTest" + ClientHeight = 2940 + ClientLeft = 60 + ClientTop = 345 + ClientWidth = 4605 + LinkTopic = "Form1" + ScaleHeight = 2940 + ScaleWidth = 4605 + StartUpPosition = 3 'Windows Default + Begin VB.Label Label1 + Caption = "It Worked!" + BeginProperty Font + Name = "MS Sans Serif" + Size = 24 + Charset = 0 + Weight = 400 + Underline = 0 'False + Italic = 0 'False + Strikethrough = 0 'False + EndProperty + Height = 735 + Left = 1080 + TabIndex = 0 + Top = 840 + Width = 2535 + End +End +Attribute VB_Name = "Form1" +Attribute VB_GlobalNameSpace = False +Attribute VB_Creatable = False +Attribute VB_PredeclaredId = True +Attribute VB_Exposed = False + +' !! We strongly recommend that you read the "readme.txt" file for this sample. +' !! It contains important instructions on how to use the sample code + +' The sample code contains 13 functions. You will not need to use all these +' functions in your code. Just use which ever functions are most appropriate +' and customise in your own way. The sample code is just a guide. You should +' implement the protection in a stronger way using the techniques described in +' the "Increasing your Protection" chapter of the manual. +' +' The 13 functions are: +' ProtCheck a standard protection check +' ProtCheckWithAlg a protection check & executing an Algorithm +' WriteString a protection check & write data to the dongle +' ReadString a protection check & read data from the dongle +' WriteBytes a protection check & write data to the dongle +' ReadBytes a protection check & read data from the dongle +' EncryptUserData a protection check,& encrypting data and then decrypting the data +' +' these functions are the same as some of the functions listed above but encrypting all parameters passed to our API +' ProtCheckEnc a standard protection check +' ProtCheckWithAlgEnc a protection check & executing an Algorithm +' WriteBytesEnc a protection check & write data to the dongle +' ReadBytesEnc a protection check & read data from the dongle +' EncryptUserDataEnc a protection check & encrypting data and then decrypting the data +' +' DisplayNetUsers this function displays the current network users (network dongle only) + +' If you are using Dinkey Lite then you can only use 4 functions: +' ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc + +' !!!! +Const MY_SDSN = 10101 ' !!!! change this value to be the value of your SDSN (demo = 10101) +Const MY_PRODCODE = "DEMO" ' !!!! change this value to match the Product Code in the dongle + + +Private Sub Form_Load() + +' call the function(s) of your choice here +' here I have chosen a standard protection check +If ProtCheck() <> 0 Then + End 'terminate +End If + +End Sub + +Function ProtCheck() As Long +Dim mydris As DRIS +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = PROTECTION_CHECK ' standard protection check +mydris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + +ret_code = DDProtCheck(mydris, 0) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ProtCheck = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ProtCheck = -1 + Exit Function +End If + +' NB to access product code you will need to use the TrimCString +If (TrimCString(mydris.prodcode) <> MY_PRODCODE) Then + MsgBox "Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", vbOKOnly, "Error" + ProtCheck = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ProtCheck = -1 + Exit Function +End If + +'to access product code you will need to use the TrimCString function like this: +'TrimCString(mydris.prodcode) + +'to access the dongle number you will need to use the ConvertToUnsigned function like this: +'ConvertToUnsigned(mydris.dongle_number) + +' NB if you are using a network dongle and you want to list the network users then use this function: +' DisplayNetUsers (mydris.net_users, mydris.model) + +ProtCheck = 0 +End Function + +' !!!! You should replace this function with the one generated by the +' "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) +' or from DinkeyLook if you are using Dinkey Lite dongles. +' see readme.txt notes concerning using the algorithm in VB +Private Function MyAlgorithm(ByVal a As Long, ByVal b As Long, ByVal c As Long, ByVal d As Long, ByVal e As Long, ByVal f As Long, ByVal g As Long, ByVal h As Long) As Long + MyAlgorithm = a + b + c + d + e + f + g + h +End Function + +' NB for this to work you must program at least "user algorithm" into the dongle +' NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +' sample code generated by DinkeyAdd for the algorithm that you are using. +Function ProtCheckWithAlg() As Long +Dim mydris As DRIS +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = EXECUTE_ALGORITHM ' standard protection check & execute an algorithm +mydris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... +mydris.alg_number = 1 ' execute first algorithm (you do not need to specify this field for Dinkey Lite dongles) +' you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random +mydris.var_a = 1 ' sample values +mydris.var_b = 2 +mydris.var_c = 3 +mydris.var_d = 4 +mydris.var_e = 5 +mydris.var_f = 6 +mydris.var_g = 7 +mydris.var_h = 8 + +ret_code = DDProtCheck(mydris, 0) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ProtCheckWithAlg = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ProtCheckWithAlg = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ProtCheckWithAlg = -1 + Exit Function +End If + +' if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code +' !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd +If MyAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) <> mydris.alg_answer Then + MsgBox "Dinkey Dongle protection error / You have not patched your algorithm in the MyAlgorithm routine", vbOKOnly, "Error" + ProtCheckWithAlg = -1 + Exit Function +End If + +ProtCheckWithAlg = 0 +End Function + + +' This writes the String "Hello, World" to the dongle data area at offset 7 +' In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +' If you want to write data that isn't a string use the WriteBytes function +Function WriteString() As Long +Dim mydris As DRIS +Dim StringToWrite As String * 13 +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = WRITE_DATA_AREA ' standard protection check and write data provided +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 13 + +StringToWrite = "Hello, World!" + +ret_code = DDProtCheckString(mydris, StringToWrite) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + WriteString = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + WriteString = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + WriteString = -1 + Exit Function +End If + +WriteString = 0 +End Function + + +' This writes the data 0,1,2,...19 to the dongle data area at offset 7 +' In order for this function to work you will need to have a data area in your dongle that is at least 28 bytes long. +' If you want to write strings it is easier to use the WriteString function +Function WriteData() As Long +Dim mydris As DRIS +Dim DataToWrite As FixedByteArray +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = WRITE_DATA_AREA ' standard protection check and write data provided +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 20 + +For i = 0 To 19 + DataToWrite.data(i) = i +Next + +ret_code = DDProtCheckData(mydris, DataToWrite) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + WriteData = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + WriteData = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + WriteData = -1 + Exit Function +End If + +WriteData = 0 +End Function + + +' This reads 13 bytes of data from offset 7 in the dongle data area +' In order for this function to work you will need to have a data area in your dongle that is at least 20 bytes long. +' In order for the data to be displayed properly by this routine it will need to be text data +Function ReadString() As Long +Dim mydris As DRIS +Dim StringToRead As String * 13 +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = READ_DATA_AREA ' standard protection check and read data +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 13 + +ret_code = DDProtCheckString(mydris, StringToRead) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ReadString = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ReadString = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ReadString = -1 + Exit Function +End If + +MsgBox "Dinkey Data Area at offset 7 contains: " + StringToRead, vbOKOnly + +ReadString = 0 +End Function + + +' This reads 20 bytes of data from offset 7 in the dongle data area +' In order for this function to work you will need to have a data area in your dongle that is at least 27 bytes long. +Function ReadData() As Long +Dim mydris As DRIS +Dim DataToRead As FixedByteArray +Dim ret_code As Long +Dim DisplayString As String + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = READ_DATA_AREA ' standard protection check and write data provided +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 20 + +ret_code = DDProtCheckData(mydris, DataToRead) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ReadData = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ReadData = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ReadData = -1 + Exit Function +End If + +DisplayString = "Dinkey Data Area at offset 7 contains: " +For i = 0 To 19 + DisplayString = DisplayString + Str(DataToRead.data(i)) +Next + +MsgBox DisplayString, vbOKOnly +ReadData = 0 +End Function + +' This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +' It will then do another protection check & decrypt the data +' The data used in this example is 0,1,2...19. If you wanted to encrypt and/or decrypt Strings +' then you could use a technique similar to that employed in WriteString & ReadString +Function EncryptUserData() As Long +Dim mydris As DRIS +Dim MyData As FixedByteArray +Dim DisplayString As String +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = ENCRYPT_USER_DATA ' standard protection check & encrypt data +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.data_crypt_key_num = 1 +mydris.rw_length = 20 + +For i = 0 To 19 ' initialise data + MyData.data(i) = i +Next + +ret_code = DDProtCheckData(mydris, MyData) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + EncryptUserData = ret_code + Exit Function +End If + +' ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn as per previous example functions + +' Now decrypt the same data to get the original values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = DECRYPT_USER_DATA ' standard protection check & decrypt data +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.data_crypt_key_num = 1 +mydris.rw_length = 20 + +ret_code = DDProtCheckData(mydris, MyData) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + EncryptUserData = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + EncryptUserData = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + EncryptUserData = -1 + Exit Function +End If + +DisplayString = "Decrypted Data is : " +For i = 0 To 19 + DisplayString = DisplayString + Str(MyData.data(i)) +Next + +MsgBox DisplayString, vbOKOnly +EncryptUserData = 0 +End Function + +' !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! +' In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" +' in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm +' but the code can be modified easily to use the 3 encryption parameters. + +' !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm +Private Function MyRWAlgorithm(ByVal a As Long, ByVal b As Long, ByVal c As Long, ByVal d As Long, ByVal e As Long, ByVal f As Long, ByVal g As Long, ByVal h As Long) As Long + MyRWAlgorithm = a Xor b Xor c Xor d Xor e Xor f + MyRWAlgorithm = MyRWAlgorithm And &HFFFFFF ' we only use bottom 3 bytes and -ve numbers can cause problems with CryptApiData +End Function + +' !!!! please overwrite this function with the one generated by DinkeyAdd +Private Sub CryptDRIS(mydris As DRIS) + Dim i, j, k, t As Integer + Dim bigseed(256) As Byte + Dim S(256) As Byte + Dim temp As Byte + Dim temp_dris(Len(mydris)) As Byte + + Call CopyMemory(temp_dris(0), mydris, Len(mydris)) + For i = 0 To 255 Step 8 + Call CopyMemory(bigseed(i), mydris.seed1, 4) + Call CopyMemory(bigseed(i + 4), mydris.seed2, 4) + Next + For i = 0 To 255 + S(i) = i + Next + j = 0 + For i = 0 To 255 + j = (j + CInt(S(i)) + CInt(bigseed(i)) + 123) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + Next + i = 0 + j = 0 + For k = 16 To Len(mydris) - 1 + i = (i + 1) Mod 256 + j = (j + CInt(S(i)) + 212) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + t = (CInt(S(i)) + CInt(S(j)) + 97) Mod 256 + temp_dris(k) = temp_dris(k) Xor S(t) + Next + + Call CopyMemory(mydris, temp_dris(0), Len(mydris)) +End Sub + +' !!!! please overwrite this function with the one generated by DinkeyAdd +Private Sub CryptApiData(ByRef data() As Byte, ByVal length As Long, ByVal seed1 As Long, ByVal seed2 As Long, ByVal AlgAnswer As Long) + Dim i, j, k, t As Integer + Dim bigseed(256) As Byte + Dim S(256) As Byte + Dim temp As Byte + + For i = 0 To 255 Step 8 + Call CopyMemory(bigseed(i), seed1, 4) + Call CopyMemory(bigseed(i + 4), seed2, 4) + Next + For i = 0 To 255 + S(i) = i + Next + j = 0 + For i = 0 To 255 + j = (j + CInt(S(i)) + CInt(bigseed(i)) + (AlgAnswer And &HFF)) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + Next + i = 0 + j = 0 + For k = 0 To length - 1 + i = (i + 1) Mod 256 + j = (j + CInt(S(i)) + ((AlgAnswer \ &H100) And &HFF)) Mod 256 + temp = S(i) + S(i) = S(j) + S(j) = temp + t = (CInt(S(i)) + CInt(S(j)) + ((AlgAnswer \ &H10000) And &HFF)) Mod 256 + data(k) = data(k) Xor S(t) + Next +End Sub + +' We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +Function ProtCheckEnc() As Long +Dim mydris As DRIS +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = PROTECTION_CHECK ' standard protection check +mydris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheck(mydris, 0) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ProtCheckEnc = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ProtCheckEnc = -1 + Exit Function +End If + +' NB to access product code you will need to use the TrimCString +If (TrimCString(mydris.prodcode) <> MY_PRODCODE) Then + MsgBox "Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", vbOKOnly, "Error" + ProtCheckEnc = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ProtCheckEnc = -1 + Exit Function +End If + +ProtCheckEnc = 0 +End Function + + +' NB for this to work you must program at least "user algorithm" into the dongle +' NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +' sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite copy source from DinkeyLook. +' We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +Function ProtCheckWithAlgEnc() As Long +Dim mydris As DRIS +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = EXECUTE_ALGORITHM ' standard protection check & execute an algorithm +mydris.flags = 0 ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,... +mydris.alg_number = 1 ' execute first algorithm - you do not need to specify this field if you are only using Lite models +' you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random +mydris.var_a = 1 ' sample values +mydris.var_b = 2 +mydris.var_c = 3 +mydris.var_d = 4 +mydris.var_e = 5 +mydris.var_f = 6 +mydris.var_g = 7 +mydris.var_h = 8 + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheck(mydris, 0) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ProtCheckWithAlgEnc = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ProtCheckWithAlgEnc = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ProtCheckWithAlgEnc = -1 + Exit Function +End If + +' if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code +' !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd +If MyAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) <> mydris.alg_answer Then + MsgBox "Dinkey Dongle protection error / You have not patched your algorithm in the MyAlgorithm routine", vbOKOnly, "Error" + ProtCheckWithAlgEnc = -1 + Exit Function +End If + +ProtCheckWithAlgEnc = 0 +End Function + + +' This writes the data 0,1,2,...19 to the dongle data area at offset 7 +' In order for this function to work you will need to have a data area in your dongle that is at least 28 bytes long. +' We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +Function WriteDataEnc() As Long +Dim mydris As DRIS +Dim DataToWrite As FixedByteArray +Dim ret_code As Long +Dim alg_ans As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = WRITE_DATA_AREA ' standard protection check and write data provided +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 20 +' NB we restrict the algorithm variables to be 24-bit values to avoid any possible overruns in the algorithm +mydris.var_a = Rand(&HFFFFFF) ' random values +mydris.var_b = Rand(&HFFFFFF) +mydris.var_c = Rand(&HFFFFFF) +mydris.var_d = Rand(&HFFFFFF) +mydris.var_e = Rand(&HFFFFFF) +mydris.var_f = Rand(&HFFFFFF) +mydris.var_g = Rand(&HFFFFFF) +mydris.var_h = Rand(&HFFFFFF) + +For i = 0 To 19 ' initialise data to write + DataToWrite.data(i) = i +Next + +' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm +alg_ans = MyRWAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) + +' encrypt data we want to write. +Call CryptApiData(DataToWrite.data, 20, mydris.seed1, mydris.seed2, alg_ans) + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheckData(mydris, DataToWrite) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + WriteDataEnc = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + WriteDataEnc = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + WriteDataEnc = -1 + Exit Function +End If + +WriteDataEnc = 0 +End Function + + +' This reads 20 bytes of data from offset 7 in the dongle data area +' In order for this function to work you will need to have a data area in your dongle that is at least 27 bytes long. +' We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +Function ReadDataEnc() As Long +Dim mydris As DRIS +Dim DataToRead As FixedByteArray +Dim ret_code As Long +Dim DisplayString As String + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = READ_DATA_AREA ' standard protection check and write data provided +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.rw_offset = 7 +mydris.rw_length = 20 +' NB we restrict the algorithm variables to be 24-bit values to avoid any possible overruns in the algorithm +mydris.var_a = Rand(&HFFFFFF) ' random values +mydris.var_b = Rand(&HFFFFFF) +mydris.var_c = Rand(&HFFFFFF) +mydris.var_d = Rand(&HFFFFFF) +mydris.var_e = Rand(&HFFFFFF) +mydris.var_f = Rand(&HFFFFFF) +mydris.var_g = Rand(&HFFFFFF) +mydris.var_h = Rand(&HFFFFFF) + +' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm +alg_ans = MyRWAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheckData(mydris, DataToRead) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + ReadDataEnc = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + ReadDataEnc = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + ReadDataEnc = -1 + Exit Function +End If + +' decrypt data we have just read +Call CryptApiData(DataToRead.data, 20, mydris.seed1, mydris.seed2, alg_ans) + +DisplayString = "Dinkey Data Area at offset 7 contains: " +For i = 0 To 19 + DisplayString = DisplayString + Str(DataToRead.data(i)) +Next + +MsgBox DisplayString, vbOKOnly +ReadDataEnc = 0 +End Function + +' This function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +' It will then do another protection & decrypt the data +' We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd. +Function EncryptUserDataEnc() As Long +Dim mydris As DRIS +Dim MyData As FixedByteArray +Dim DisplayString As String +Dim ret_code As Long + +' set the DRIS to have random values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = ENCRYPT_USER_DATA ' standard protection check & encrypt data +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.data_crypt_key_num = 1 +mydris.rw_length = 20 +' NB we restrict the algorithm variables to be 24-bit values to avoid any possible overruns in the algorithm +mydris.var_a = Rand(&HFFFFFF) ' random values +mydris.var_b = Rand(&HFFFFFF) +mydris.var_c = Rand(&HFFFFFF) +mydris.var_d = Rand(&HFFFFFF) +mydris.var_e = Rand(&HFFFFFF) +mydris.var_f = Rand(&HFFFFFF) +mydris.var_g = Rand(&HFFFFFF) +mydris.var_h = Rand(&HFFFFFF) + +For i = 0 To 19 ' initialise data + MyData.data(i) = i +Next + +' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm +alg_ans = MyRWAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) + +' encrypt data we want to pass. +Call CryptApiData(MyData.data, 20, mydris.seed1, mydris.seed2, alg_ans) + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheckData(mydris, MyData) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + EncryptUserDataEnc = ret_code + Exit Function +End If + +' ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn as per previous example functions + +' Now decrypt the same data to get the original values +Call RandomSet(mydris) +' then set the values we want to use +mydris.header = "DRIS" +mydris.size = Len(mydris) +mydris.function = DECRYPT_USER_DATA ' standard protection check & decrypt data +mydris.flags = USE_FUNCTION_ARGUMENT ' indicates we want to pass the data directly to our function. This is the only way to do it in VB. +mydris.data_crypt_key_num = 1 +mydris.rw_length = 20 +' NB we restrict the algorithm variables to be 24-bit values to avoid any possible overruns in the algorithm +mydris.var_a = Rand(&HFFFFFF) ' random values +mydris.var_b = Rand(&HFFFFFF) +mydris.var_c = Rand(&HFFFFFF) +mydris.var_d = Rand(&HFFFFFF) +mydris.var_e = Rand(&HFFFFFF) +mydris.var_f = Rand(&HFFFFFF) +mydris.var_g = Rand(&HFFFFFF) +mydris.var_h = Rand(&HFFFFFF) + +Call CryptDRIS(mydris) ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = DDProtCheckData(mydris, MyData) + +Call CryptDRIS(mydris) ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +If (ret_code <> 0) Then + Call DisplayError(ret_code, mydris.ext_err) + EncryptUserDataEnc = ret_code + Exit Function +End If + +' later in your code you can check other values in the DRIS... +If (mydris.sdsn <> MY_SDSN) Then + MsgBox "Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", vbOKOnly, "Error" + EncryptUserDataEnc = -1 + Exit Function +End If + +' later on in your program you can check the return code again +If (mydris.ret_code <> 0) Then + MsgBox "Dinkey Dongle protection error", vbOKOnly, "Error" + EncryptUserDataEnc = -1 + Exit Function +End If + +' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm +alg_ans = MyRWAlgorithm(mydris.var_a, mydris.var_b, mydris.var_c, mydris.var_d, mydris.var_e, mydris.var_f, mydris.var_g, mydris.var_h) + +' decrypt data passed to us from the API. +Call CryptApiData(MyData.data, 20, mydris.seed1, mydris.seed2, alg_ans) + +DisplayString = "Decrypted Data is : " +For i = 0 To 19 + DisplayString = DisplayString + Str(MyData.data(i)) +Next + +MsgBox DisplayString, vbOKOnly +EncryptUserDataEnc = 0 +End Function + +' This function displays the current network users (for DinkeyNet only). +' The DDProtCheck function must be called before this function is called. +' (Normally you would use DinkeyServer to view the network users but this enables you to do it from the client if you want) +Function DisplayNetUsers(net_users As Integer, model As Integer) As Integer + Dim num_net_users, extended_error, ret_code, i, max_net_users As Long + Dim DisplayString As String + Dim nu_info_bytes As LargeFixedByteArray ' !!!! only contains space for info for up to 20 net users. If you want more then you must change the type definition + + If net_users = -1 Then + max_net_users = 20 ' if unlimited network users are allowed then display up to 20 users (for example, to change this limit see note above) + Else + max_net_users = net_users + End If + + If max_net_users = 0 Then ' no network users are allowed, so nothing to do! + DisplayNetUsers = 0 + Exit Function + End If + + If model < 3 Then + MsgBox "A network dongle has not been detected. Therefore you cannot display the network users.", vbOKOnly + DisplayNetUsers = -1 + Exit Function + End If + + ' now get net users + ret_code = DDGetNetUserList("", num_net_users, nu_info_bytes, max_net_users, extended_error) + + If ret_code <> 0 Then + MsgBox "Error " + Str$(ret_code) + "/" + Str$(extended_error) + " finding network user information.", vbOKOnly + Else + DisplayString = "number of net users: " + Str(num_net_users) + vbNewLine + For i = 0 To num_net_users - 1 + DisplayString = DisplayString + Str$(i + 1) + ". licence: " + GetLicenceName(nu_info_bytes, i) + ", user: " + GetUserName(nu_info_bytes, i) + ", computer: " + GetComputerName(nu_info_bytes, i) + ", ip address: " + GetIpAddress(nu_info_bytes, i) + vbNewLine + Next + MsgBox DisplayString, vbOKOnly, "Net Users" + End If + DisplayNetUsers = ret_code + +End Function + +' look at the error code and try to display an appropriate message +Public Sub DisplayError(ret_code As Long, extended_error As Long) + Select Case ret_code + Case 401 + MsgBox "Error! No dongles detected!", vbOKOnly, "Error" + Case 403 + MsgBox "Error! A dongle was detected but it was a different type to the one specified in DinkeyAdd.", vbOKOnly, "Error" + Case 404 + MsgBox "Error! A dongle was detected but it was a different model to those specified in DinkeyAdd.", vbOKOnly, "Error" + Case 409 + MsgBox "Error! The dongle detected has not been programmed by DinkeyAdd.", vbOKOnly, "Error" + Case 410 + MsgBox "Error! A dongle was detected but it has a different Product Code to the one specified in DinkeyAdd.", vbOKOnly, "Error" + Case 411 + MsgBox "Error! The dongle detected does not contain the licence associated with this program.", vbOKOnly, "Error" + Case 413 + MsgBox "Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual.", vbOKOnly, "Error" + Case 417 + MsgBox "Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.", vbOKOnly, "Error" + Case 423 + MsgBox "Error! The number of network users has been exceeded.", vbOKOnly, "Error" + Case 435 + MsgBox "Error! DinkeyServer has not been detected on the network.", vbOKOnly, "Error" + Case 922 + MsgBox "Error! The Software Key has expired.", vbOKOnly, "Error" + Case Else + MsgBox "An error occurred checking the dongle. Error: " + Str$(ret_code) + ". Extended Error: " + Str$(extended_error) + ".", vbOKOnly, "Error" + End Select +End Sub diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic/Runtime/README.txt b/Dinkey Pro 7.6.1/Samples/Visual Basic/Runtime/README.txt new file mode 100644 index 0000000..3e58f76 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic/Runtime/README.txt @@ -0,0 +1,64 @@ +DllTest - sample code to call dpwin32.dll in Visual Basic +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This project is written in Visual Basic 6.0 but will the code will also +work in version 5.0 (but you will have to create your own project). + +For VB.net code please look in the vb.net folder. + +The source files in the project are: + +File name Folder Description +Form1.frm Samples\vb main source code file for VB +dris.bas Samples\vb contains the DRIS structure & function declarations + +The idea is to include the dris.bas file in your project and use/modify which ever +functions from form1.frm you feel are appropriate. + +The sample code contains 13 functions. You will not need to use all these +functions in your code. Just use which ever functions are most appropriate +and customise in your own way. The sample code is just a guide. You should +implement the protection in a stronger way using the techniques described in +the "Increasing your Protection" chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the Product Code in the dongle +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. + +Note - you should protect dpwin32.dll and not your program. Because your program +is linked to the DLL it is protected. + +Note - to run the project from the IDE you will need to place the protected +dpwin32.dll in the 32-bit Windows System folder*. For release you can place +dpwin32.dll in the folder of the compiled executable or in the Windows System folder. +The former is generally considered better as it is easier to install. + +It is also recommended that you rename dpwin32.dll to a name of your choice. In +this case you will need to modify the dll name in the dris.bas file. + +Special Note for using Algorithms in Visual Basic +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The algorithms are calculated on 32-bit integers (Long in VB). It is quite possible for +the MyAlgorithm and MyRWAlgorithm functions to overflow if the values provided are too big. +In the dongle the algorithms can never overflow - if the answer is too big then the high part +of the answer is ignored. In practical terms: + +When you are using the r/w algorithm it is best not to pass random 32-bit integers. It is +better to restrict the variables to 24-bit to avoid the possibility of overflows. + +When using a user algorithm it will behave exactly as the corresponding MyAlgorithm function +will in VB except it will not give overflow errors. + +~~~~~~~~~~~~~~~~~ +* Windows System folder for 32-bit dlls is: +c:\windows\system32 32-bit Windows +c:\windows\sysWOW64 64-bit Windows \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/Samples/Visual Basic/Runtime/dris.bas b/Dinkey Pro 7.6.1/Samples/Visual Basic/Runtime/dris.bas new file mode 100644 index 0000000..10d6a64 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Visual Basic/Runtime/dris.bas @@ -0,0 +1,214 @@ +' !! this file should not be modified + +Attribute VB_Name = "Module1" +' API functions +' DDProtCheck - so we can ignore the second argument +Declare Function DDProtCheck Lib "dpwin32.dll" (mydris As DRIS, data As String) As Long +' DDProtCheckString - so we can pass data as a String +Declare Function DDProtCheckString Lib "dpwin32.dll" Alias "DDProtCheck" (mydris As DRIS, ByVal String1 As Any) As Long +' DDProtCheckData - so we can pass data in any format +Declare Function DDProtCheckData Lib "dpwin32.dll" Alias "DDProtCheck" (mydris As DRIS, data As FixedByteArray) As Long +' DDGetNetUserList +Declare Function DDGetNetUserList Lib "dpwin32.dll" (ByVal licence_name As Any, num_net_users As Long, nu_info_bytes As LargeFixedByteArray, ByVal num_info_structs As Long, extended_error As Long) As Long + +'Dinkey Runtime Information Structure (DRIS) +Type DRIS + ' the first 4 fields are never encrypted + header As String * 4 ' should be set to DRIS + ' inputs + size As Long ' size of this structure + seed1 As Long ' seed for data/dris encryption + seed2 As Long ' as above + ' (maybe encrypted from now on) + function As Long ' specify only one function + flags As Long ' options for the function selected. To use more than one OR them together: OPTION1 Or OPTION2... + execs_decrement As Long ' amount by which to dec execs if we use flag: DEC_MANY_EXECS + data_crypt_key_num As Long ' number of the key (1-3) that the dongle uses to encrypt or decrypt user data + rw_offset As Long ' offset in the dongle data area to read or write data + rw_length As Long ' length of data are to read/write/encrypt/decrypt + not_used As Long ' pass the data as a parameter instead for VB + alt_licence_name As String * 256 ' protection check for different licence instead of the default one, must be null-terminated ascii + var_a As Long ' variable values for user algorithms + var_b As Long + var_c As Long + var_d As Long + var_e As Long + var_f As Long + var_g As Long + var_h As Long + alg_number As Long ' the number of the user algorithm that you want to execute + + ' outputs + ret_code As Long ' the return code from the protection check + ext_err As Long ' extended error + type As Long ' type of dongle detected. 1 = Pro, 2 = FD + model As Long ' model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + sdsn As Long ' Software Developer's Serial Number + prodcode As String * 12 ' product code (null-terminated) + dongle_number As Long ' dongle number. This number should be converted to a positive value using ConvertToUnsigned before being displayed otherwise it my appear as a negative number. + update_number As Long + data_area_size As Long ' size of the data area in the dongle detected + max_alg_num As Long ' the maximum algorithm number in the dongle detected + execs As Long ' executions left: -1 indicates 'no limit' + exp_day As Long ' expiry day: -1 indicates 'no limit' + exp_month As Long ' expiry month: -1 indicates 'no limit' + exp_year As Long ' expiry year: -1 indicates 'no limit' + features As Long ' features value + net_users As Long ' maximum number of network users for the dongle detected: -1 indicates 'mo limit' + alg_answer As Long ' answer to the user algorithm executed with the given variable values + fd_capacity As Long ' capacity of the data area in FD dongle. + fd_drive As String * 128 ' drive letter of FD dongle detected e.g. 'f:\' + swkey_type As Long ' 0 = no swkey detected, 1 = temporary software key, 2 = demo software key + swkey_exp_day As Long ' software key expiry date (if software key detected) + swkey_exp_month As Long + swkey_exp_year As Long +End Type + +'we need a structure for an array of bytes because otherwise the VB runtime can move the data in-between function calls +Type FixedByteArray + data(0 To 1023) As Byte +End Type + +'this is a similar structure that can be used for the DDGetNetUserList call. +'!!!! this structure will acommodate info for upto 20 net users. If you want to alow for more then increase the array size +Public Const NU_INFO_SIZE = (256 + 50 + 256 + 16) +Type LargeFixedByteArray + data(0 To NU_INFO_SIZE * 20) As Byte +End Type + +' Functions +Public Const PROTECTION_CHECK = 1 ' checks for dongle, check program params... +Public Const EXECUTE_ALGORITHM = 2 ' protection check + calculate answer for specified algorithm with specified inputs +Public Const WRITE_DATA_AREA = 3 ' protection check + writes dongle data area +Public Const READ_DATA_AREA = 4 ' protection check + reads dongle data area +Public Const ENCRYPT_USER_DATA = 5 ' protection check + the dongle will encrypt user data +Public Const DECRYPT_USER_DATA = 6 ' protection check + the dongle will decrypt user data +Public Const FAST_PRESENCE_CHECK = 7 ' checks for the presence of the correct dongle only with minimal security, no flags allowed +Public Const STOP_NET_USER = 8 ' stops a network user (a protection check is NOT performed) + +' Flags +Public Const DEC_ONE_EXEC = 1 ' decrement execs by 1 +Public Const DEC_MANY_EXECS = 2 ' decrement execs by number specified in execs +Public Const START_NET_USER = 4 ' starts a network user +Public Const USE_FUNCTION_ARGUMENT = 16 ' use the extra argument in the function for pointers +Public Const CHECK_LOCAL_FIRST = 32 ' always look in local ports before looking in network ports +Public Const CHECK_NETWORK_FIRST = 64 ' always look on the network before looking in local ports +Public Const USE_ALT_LICENCE_NAME = 128 ' use name specified in alt_licence_name instead of the default one +Public Const DONT_SET_MAXDAYS_EXPIRY = 256 ' if the max days expiry date has not been calculated then do not do it this time +Public Const MATCH_DONGLE_NUMBER = 512 ' restrict the search to match the dongle number specified in the DRIS +Public Const DONT_RETURN_FD_DRIVE = 1024 ' if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS + +' Useful functions +Declare Sub CopyMemory Lib "KERNEL32" Alias "RtlMoveMemory" (lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long) + +' given the maximum possible value generate a random number between 0 and the maximum +Public Function Rand(ByVal High As Long) As Long + Rand = Int((High + 1) * Rnd) +End Function + +' initialise the DRIS with random values +Public Sub RandomSet(mydris As DRIS) + Dim temp_dris(Len(mydris)) As Byte + + Randomize + + Call CopyMemory(temp_dris(0), mydris, Len(mydris)) + For i = 0 To Len(mydris) - 1 + temp_dris(i) = Rand(255) + Next + Call CopyMemory(mydris, temp_dris(0), Len(mydris)) +End Sub + +' this function will convert the C string returned in the DRIS to a VB string +' e.g. to access the product code use TrimCString(mydris.prodcode) +Public Function TrimCString(Str As String) As String + Dim i As Integer + Dim length As Integer + + length = Len(Str) + + For i = 1 To length + If Mid(Str, i, 1) = Chr$(0) Then + TrimCString = Left$(Str, i - 1) 'take off null and rest of string + Exit For + End If + Next + +End Function + +' this function should be used if you want to display the dongle_number. It will always display as a positive value +Public Function ConvertToUnsigned(number As Long) As Double +If (number >= 0) Then + ConvertToUnsigned = number +Else + ConvertToUnsigned = number + 4294967296# +End If +End Function + +' routine to extract Licence Name from array of NU_INFO structures (implemented as a LargeFixedByteArray) +Public Function GetLicenceName(nu_info_bytes As LargeFixedByteArray, ByVal index As Long) As String + Dim data As Byte ' this will be a byte of data from array + Dim start As Long + + start = (index * NU_INFO_SIZE) + 0 + GetLicenceName = "" + For i = 0 To 255 + data = nu_info_bytes.data(start + i) + If data = 0 Then ' stop when we get to the null + Exit For + Else ' otherwise append character to string + GetLicenceName = GetLicenceName & Chr(data) + End If + Next +End Function + +' routine to extract User Name from array of NU_INFO structures (implemented as a LargeFixedByteArray) +Public Function GetUserName(nu_info_bytes As LargeFixedByteArray, ByVal index As Long) As String + Dim data As Byte ' this will be a byte of data from array + Dim start As Long + + start = (index * NU_INFO_SIZE) + 256 + GetUserName = "" + For i = 0 To 49 + data = nu_info_bytes.data(start + i) + If data = 0 Then ' stop when we get to the null + Exit For + Else ' otherwise append character to string + GetUserName = GetUserName & Chr(data) + End If + Next +End Function + +' routine to extract Computer Name from array of NU_INFO structures (implemented as a LargeFixedByteArray) +Public Function GetComputerName(nu_info_bytes As LargeFixedByteArray, ByVal index As Long) As String + Dim data As Byte ' this will be a byte of data from array + Dim start As Long + + start = (index * NU_INFO_SIZE) + 256 + 50 + GetComputerName = "" + For i = 0 To 255 + data = nu_info_bytes.data(start + i) + If data = 0 Then ' stop when we get to the null + Exit For + Else ' otherwise append character to string + GetComputerName = GetComputerName & Chr(data) + End If + Next +End Function + +' routine to extract ipAddress from array of NU_INFO structures (implemented as a LargeFixedByteArray) +Public Function GetIpAddress(nu_info_bytes As LargeFixedByteArray, ByVal index As Long) As String + Dim data As Byte ' this will be a byte of data from array + Dim start As Long + + start = (index * NU_INFO_SIZE) + 256 + 50 + 256 + GetIpAddress = "" + For i = 0 To 15 + data = nu_info_bytes.data(start + i) + If data = 0 Then ' stop when we get to the null + Exit For + Else ' otherwise append character to string + GetIpAddress = GetIpAddress & Chr(data) + End If + Next +End Function diff --git a/Dinkey Pro 7.6.1/Samples/WinDev/DinkeyChange/DinkeyChange functions.txt b/Dinkey Pro 7.6.1/Samples/WinDev/DinkeyChange/DinkeyChange functions.txt new file mode 100644 index 0000000..a866ea8 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/WinDev/DinkeyChange/DinkeyChange functions.txt @@ -0,0 +1,299 @@ +// sample functions for calling DinkeyChange.dll. + + +// Summary: Displays the error code with a helpful error message. You may want to change the messages. +// Syntax: +//DisplayChangeError ( is int, is int) +PROCEDURE DisplayChangeError(ret_code is int, ext_err is int) +SWITCH ret_code + CASE 401: Info("Error! No dongles detected that meet the search criteria!") + CASE 409: Info("Error! The dongle detected has not been programmed by DinkeyAdd.") + CASE 758: Info("Error! Cannot open the Update Code file specified.") + CASE 759: Info("Error! The file specified is not a valid Update Code file.") + CASE 762 TO 764: Info("Error! Update Code is not in a correct format / update code file is corrupt.") + CASE 765: Info("Error! The Update Code does not match any dongle attached to your machine.") + CASE 766: Info("Error! The update number for this Update Code is too high. You need to first enter an update code that was previously sent to you.") + CASE 767: Info("Error! You have already entered this Update Code.") + CASE 1905: Info("Error! There is no Software Key available for download.") + CASE 1907: Info("Error! The Temporary Software Key has expired. Cannot download it.") + CASE 1910: Info("Error! The Software Key has already been downloaded.") + CASE 1921: Info("Error! You specified the 'default model' but there is more than one model available. You need to specify a specific dongle model.") + CASE 1922: Info("Error! The model you requested is not available.") + CASE 1923: Info("Error! The Demo Software Key Template has been disabled.") + CASE 1924: Info("Error! You have run out of Demo Software Key activations. You need to order some more.") + OTHER CASE: Info("An error occurred updating the dongle.","Error: " + ret_code, "Extended Error: " + ext_err) +END + + +// Summary: gets the product code, dongle number and update number for all dongles attached that meet the specify search criteria +// Syntax: +//[ = ] GetDongleInfo () +PROCEDURE GetDongleInfo() +hLib, ret_code are system int +type, model, update_number are fixed array of MAX_USB_DEVICES int +dongle_number is a fixed array of MAX_USB_DEVICES unsigned int +prodcode is a fixed array of MAX_USB_DEVICES fixed strings on MAX_PRODCODE_LEN +num_found is int +sDisplayMsg, sType, sModel are strings + +// Load the DinkeyChange.dll +hLib = LoadDLL(changedllname) +IF hLib = 0 THEN + Info("Cannot load " + changedllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +// get dongle information +ret_code = CallDLL32(changedllname, "DCGetInfo", TYPE_MASK_ALL, MODEL_MASK_DEFAULT, Null, MAX_USB_DEVICES, &num_found, &type, &model, &prodcode, &dongle_number, &update_number) +FreeDLL(hLib) + +IF ret_code <> 0 THEN + DisplayChangeError(ret_code, 0) + RESULT ret_code +END + +// display details on the dongles detected +sDisplayMsg = "Dongle Information:" + CR +FOR i = 1 TO num_found + // get type of dongle + IF type[i] = TYPE_PRO THEN + sType = "Pro" + ELSE + sType = "FD" + END + // get model of dongle + IF model[i] = MODEL_LITE THEN + sModel = "Lite" + ELSE IF model[i] = MODEL_PLUS THEN + sModel = "Plus" + ELSE + sModel = "Net" + END + sDisplayMsg += i + ". Dinkey " + sType + " " + sModel + " with dongle number " + dongle_number[i] + " product code " + ExtractString(prodcode[i], 1, Charact(0)) + " update number " + update_number[i] + CR +END + +Info(sDisplayMsg) + + +// Summary: collect diagnostic information from the system and write to a file +// Syntax: +//[ = ] GetDiagnosticInfo ( is string) +PROCEDURE GetDiagnosticInfo(sDiagPath is string) +hLib, ret_code are system int + +// Load the DinkeyChange.dll +hLib = LoadDLL(changedllname) +IF hLib = 0 THEN + Info("Cannot load " + changedllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +// get diagnostic info +ret_code = CallDLL32(changedllname, "DCGetDiagnosticInfo", sDiagPath) +FreeDLL(hLib) + +IF ret_code = 754 THEN + Info("Could not create the diagnostic file. Please check that the path exists:" + sDiagPath) + RESULT ret_code +END + +IF ret_code <> 0 THEN + Info("Error " + ret_code + " writing diagnostic information") + RESULT ret_code +END + +Info("Diagnostic file written successfully") + + +// Summary: updates the dongle attached using the update code passed +// Syntax: +//[ = ] UpdateCodeString ( is string) +// +// Parameters: +// sUpdateString (string): + +PROCEDURE UpdateCodeString(sUpdateString is string) +hLib, ret_code are system int +extended_error, confirmation_code are int + +// Load the DinkeyChange.dll +hLib = LoadDLL(changedllname) +IF hLib = 0 THEN + Info("Cannot load " + changedllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +// update dongle +ret_code = CallDLL32(changedllname, "DCDoUpdateCodeString", sUpdateString, &confirmation_code, &extended_error) +FreeDLL(hLib) + +IF ret_code <> 0 THEN + DisplayChangeError(ret_code, extended_error) + RESULT ret_code +END + +Info("Dongle updated successfully.", "Confirmation Code is " + NumToString(confirmation_code, "04x")) + + +// Summary: updates the dongle attached using the update code passed +// Syntax: +//[ = ] UpdateCodeFromFile ( is string) +// +// Parameters: +// sUpdateCodeFile (string) + +PROCEDURE UpdateCodeFromFile(sUpdateCodeFile is string) +hLib, ret_code are system int +extended_error, confirmation_code are int + +// Load the DinkeyChange.dll +hLib = LoadDLL(changedllname) +IF hLib = 0 THEN + Info("Cannot load " + changedllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +// update dongle +ret_code = CallDLL32(changedllname, "DCDoUpdateCodeFromFile", sUpdateCodeFile, &confirmation_code, &extended_error) +FreeDLL(hLib) + +IF ret_code <> 0 THEN + DisplayChangeError(ret_code, extended_error) + RESULT ret_code +END + +Info("Dongle updated successfully.", "Confirmation Code is " + NumToString(confirmation_code, "04x")) + + +// Summary: attempts to restore a corrupt Dinkey FD Lite dongle +// Syntax: +//[ = ] RestoreDinkeyFDLite () +// +// Parameters: none + +PROCEDURE RestoreDinkeyFDLite() +hLib, ret_code are system int + +// Load the DinkeyChange.dll +hLib = LoadDLL(changedllname) +IF hLib = 0 THEN + Info("Cannot load " + changedllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +ret_code = CallDLL32(changedllname, "DCRetoreDinkeyFDLite") +FreeDLL(hLib) + +IF ret_code <> 0 THEN + DisplayChangeError(ret_code, extended_error) + RESULT ret_code +END + +Info("Dinkey FD has been restored successfully.") + + +// Summary: displays the machine ID of the current computer +// Syntax: +//[ = ] GetMachineID () +// + +PROCEDURE GetMachineID() +hLib, ret_code are system int +extended_error is int +machineID is unsigned int + +// Load the DinkeyChange.dll +hLib = LoadDLL(changedllname) +IF hLib = 0 THEN + Info("Cannot load " + changedllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +ret_code = CallDLL32(changedllname, "DCGetMachineID", &machineID, &extended_error) +FreeDLL(hLib) + +IF ret_code <> 0 THEN + DisplayChangeError(ret_code, extended_error) + RESULT ret_code +END + +Info("Machine ID is: " + NumToString(machineID, "08x")) + + +// Summary: tries to download an available temporary software key for this machine +// Syntax: +//[ = ] DownloadTempSoftwareKey () +// + +PROCEDURE DownloadTempSoftwareKey() +hLib, ret_code are system int +extended_error is int +machineID is unsigned int + +// Load the DinkeyChange module +hLib = LoadDLL(changedllname) +IF hLib = 0 THEN + Info("Cannot load " + changedllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +// first call GetMachineID to get the machine ID value +ret_code = CallDLL32(changedllname, "DCGetMachineID", &machineID, &extended_error) + +IF ret_code <> 0 THEN + DisplayChangeError(ret_code, extended_error) + RESULT ret_code +END + +// then try to download a temporary software key for that machine ID +ret_code = CallDLL32(changedllname, "DCDownloadTempSoftwareKey", machineID, &extended_error) +FreeDLL(hLib) + +IF ret_code <> 0 THEN + DisplayChangeError(ret_code, extended_error) + RESULT ret_code +END + +Info("The Temporary Software Key has been downloaded successfully.") + + +// Summary: tries to download a demo software key for this machine +// Syntax: +//[ = ] DownloadDemoSoftwareKey ( is string) +// +// Parameters: +// sProdCode (string) +// + +PROCEDURE DownloadDemoSoftwareKey(sProdCode is string) +hLib, ret_code are system int +extended_error is int +machineID is unsigned int + +// Load the DinkeyChange module +hLib = LoadDLL(changedllname) +IF hLib = 0 THEN + Info("Cannot load " + changedllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +// first call GetMachineID to get the machine ID value +ret_code = CallDLL32(changedllname, "DCGetMachineID", &machineID, &extended_error) + +IF ret_code <> 0 THEN + DisplayChangeError(ret_code, extended_error) + RESULT ret_code +END + +// then try to download a demo software key +// (NB we are assuming only one dongle model is set in the Demo Software Template. +// If multiple models are set you will also need to specify the exact model) +ret_code = CallDLL32(changedllname, "DCDownloadDemoSoftwareKey", machineID, sProdCode, SWKEY_MODEL_DEFAULT, &extended_error) +FreeDLL(hLib) + +IF ret_code <> 0 THEN + DisplayChangeError(ret_code, extended_error) + RESULT ret_code +END + +Info("The Demo Software Key has been downloaded successfully.") diff --git a/Dinkey Pro 7.6.1/Samples/WinDev/DinkeyChange/README.txt b/Dinkey Pro 7.6.1/Samples/WinDev/DinkeyChange/README.txt new file mode 100644 index 0000000..97abcb7 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/WinDev/DinkeyChange/README.txt @@ -0,0 +1,15 @@ +Calling DinkeyChange.dll from WinDev +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You should copy all the code in the file "global variables.txt". These data +structures and functions are used by the API sample code. Then copy the +appropraite function(s) from the "protection check functions.txt" file. These +functions implement all the various routines in DinkeyChange.dll + +Note - if you are producing a 64-bit Windows executable you need to use DinkeyChange64.dll +(instead of DinkeyChange.dll) and change the "changedllname" to be "DinkeyChange64.dll" +(this is found in the global variables and functions.txt). +Similarly for Linux you will need to use DinkeyChange.so (32-bit Linux) or +DinkeyChange64.so (64-bit Linux). + +Tested under Windev Express v12 diff --git a/Dinkey Pro 7.6.1/Samples/WinDev/DinkeyChange/global variables.txt b/Dinkey Pro 7.6.1/Samples/WinDev/DinkeyChange/global variables.txt new file mode 100644 index 0000000..3ceced4 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/WinDev/DinkeyChange/global variables.txt @@ -0,0 +1,50 @@ +// DinkeyChange constants + +// maximum number of USB devices that can be attached to a machine at any time +CONSTANT + MAX_USB_DEVICES = 128 // max number of USB devices that can be attached to the system + MAX_PRODCODE_LEN = 9 // one extra character for null-terminated strings +END + +// mask values +CONSTANT + TYPE_MASK_PRO = 1 + TYPE_MASK_FD = 2 + TYPE_MASK_ALL = 3 + + MODEL_MASK_LITE = 1 + MODEL_MASK_PLUS = 2 + MODEL_MASK_NET = 4 + MODEL_MASK_ALL = 7 + MODEL_MASK_DEFAULT = 6 // Plus and Net +END + +// type values for DCGetInfo (returned in the array) +CONSTANT + TYPE_PRO = 1 + TYPE_FD = 2 +END + +// model values for DCGetInfo (returned in the array) +CONSTANT + MODEL_LITE = 1 + MODEL_PLUS = 2 + MODEL_NET5 = 4 + MODEL_NETU = 7 +END + +// model values for DCDownloadDemoSoftwareKey + +CONSTANT + SWKEY_MODEL_DEFAULT = -1 // NB this assumes that the Demo Software Key Template was created with only one valid dongle model + SWKEY_MODEL_PRO_LITE = 0 + SWKEY_MODEL_PRO_PLUS = 1 + SWKEY_MODEL_PRO_NET = 2 + SWKEY_MODEL_FD_LITE = 3 + SWKEY_MODEL_FD_PLUS = 4 + SWKEY_MODEL_FD_NET = 5 +END + + +// name for DinkeyChange.dll (you can rename it if you like) +changedllname is a string = "DinkeyChange.dll" diff --git a/Dinkey Pro 7.6.1/Samples/WinDev/Runtime/README.txt b/Dinkey Pro 7.6.1/Samples/WinDev/Runtime/README.txt new file mode 100644 index 0000000..0ce4a34 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/WinDev/Runtime/README.txt @@ -0,0 +1,43 @@ +Protecting Windev applications with Dinkey Dongle +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You should copy all the code in the file "global variables and functions.txt". +These data structures and functions are used by the API sample code. Then copy +the appropriate function(s) from the "protection check functions.txt" file. These +functions implement all the various features of the DInkey Dongle SDK. + +Note that the sample code is just a guide. You should implement the protection in +a stronger way using the techniques described in the "Increasing your Protection" +chapter of the manual. + +Code marked with !!!! are places where you should customise the sample code so +that it will work properly: + +* Change the MY_SDSN value to the value of your SDSN +* Change the MY_PRODCODE value to the value of your Product Code +* Change the MyAlgorithm code (if you call a user algorithm) +* Change the CryptDRIS code (if you encrypt the DRIS) +* Change the CryptApiData (if you encrypt Data you send to our API) +* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) + +You will also probably want to replace our error messages with your own. However, you should +still display or log any error codes returned by the protection check otherwise you will not +be able to identify the cause of the error. (You can look up error codes in our knowledge +base: microcosm.com/kb). + +Note - you should protect dpwin32.dll and not your program. Because your program +is linked to the DLL it is protected. The protected DLL will need to be in the +same folder as your compiled program for it to run correctly. + +Note - if you are producing a 64-bit Windows executable you need to protect dpwin64.dll +(instead of dpwin32.dll) and change the "protectdllname" to be "dpwin64.dll" +(this is found in the global variables and functions.txt). +Similarly for Linux you will need to use dplin32.so (32-bit Linux) or dplin64.so (64-bit Linux). + +Note - you can also use the Shell Method of protection on WinDev executables. + +Note - we have had reports of a bug in early releases of Windev 19 which causes the "Length" ("Taille") +function to return in incorrect value. This bug has been fixed in the February 2014 release of Windev 19. + +Tested under Windev Express v12 + diff --git a/Dinkey Pro 7.6.1/Samples/WinDev/Runtime/global variables and functions.txt b/Dinkey Pro 7.6.1/Samples/WinDev/Runtime/global variables and functions.txt new file mode 100644 index 0000000..061886f --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/WinDev/Runtime/global variables and functions.txt @@ -0,0 +1,135 @@ +//******************************************************************* +// Dinkey Runtime Information structure (DRIS) + +GLOBAL + DRIS is composed of + // the first 4 fields are never encrypted + header is a fixed string on 4 // should be set to DRIS + + // inputs + size is an int on 4 // size of this structure + seed1 is an int on 4 // seed for data/dris encryption + seed2 is an int on 4 // seed for data/dris encryption + // (maybe encrypted from now on) + dpfunction is an int on 4 // specify only one function + flags is an int on 4 // options for the function selected. To use more than one OR them together: OPTION1 | OPTION2... + execs_decrement is an unsigned int on 4 // amount by which to dec execs if we use flag: DEC_MANY_EXECS + data_crypt_key_num is an int on 4 // number of the key (1-3) that the dongle uses to encrypt or decrypt user data + rw_offset is an unsigned int on 4 // offset in the dongle data area to read or write data + rw_length is an unsigned int on 4 // length of data are to read/write/encrypt/decrypt + rw_data_ptr is a system int // pointer to data to write / be read + alt_licence_name is a fixed string on 256 // protection check for different licence instead of the default one, must be null-terminated + var_a is an int on 4 // variable values for user algorithm + var_b is an int on 4 + var_c is an int on 4 + var_d is an int on 4 + var_e is an int on 4 + var_f is an int on 4 + var_g is an int on 4 + var_h is an int on 4 + alg_number is an unsigned int on 4 // the number of the user algorithm that you want to execute + + // outputs + ret_code is an int on 4 // return code from the protection check + ext_err is an unsigned int on 4 // extended error + type is an int on 4 // type of dongle detected. 1 = Pro, 2 = FD + model is an int on 4 // model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited + sdsn is an int on 4 // Software Developer's Serial Number + prodcode is a fixed string on 12 // Product Code (null-terminated) + dongle_number is an unsigned int on 4 + update_number is an unsigned int on 4 + data_area_size is an unsigned int on 4 // size of the data area used in the dongle detected + num_algs is an int on 4 // the maximum algorithm number in the dongle detected + execs is an int on 4 // executions left: -1 indicates 'no limit' + exp_day is an int on 4 // expiry day: -1 indicates 'no limit' + exp_month is an int on 4 // expiry month: -1 indicates 'no limit' + exp_year is an int on 4 // expiry year: -1 indicates 'no limit' + features is an unsigned int on 4 // features value + net_users is an int on 4 // maximum number of network users for the dongle detected: -1 indicates 'mo limit' + alg_answer is an int on 4 // answer to the user algorithm executed with the given variable values + fd_capacity is an unsigned int on 4 + fd_drive is a fixed string on 128 // drive letter of FD dongle detected e.g. 'f:\' + swkey_type is an int on 4 // 0 = no swkey detected, 1 = temporary software key, 2 = demo software + swkey_exp_day is an int on 4 // software key expiry date (if software key detected) + swkey_exp_month is an int on 4 + swkey_exp_year is an int on 4 + END + + // dpwin32.dll - 32-bit Windows protection module !!!! change this module for 64-bit Windows or Linux or Mac + protectdllname is a string = "dpwin32.dll" + +// functions - must specify only one +CONSTANT + PROTECTION_CHECK = 1 // checks for dongle, check program parameters + EXECUTE_ALGORITHM = 2 // protection check + calculate answer for specified algorithm with specified inputs + WRITE_DATA_AREA =3 // protection check + writes dongle data area + READ_DATA_AREA = 4 // protection check + reads dongle data area + ENCRYPT_USER_DATA = 5 // protection check + the dongle will encrypt user data + DECRYPT_USER_DATA = 6 // protection check + the dongle will decrypt user data + FAST_PRESENCE_CHECK = 7 // checks for the presence of the correct dongle only with minimal security, no flags allowed. + STOP_NET_USER = 8 // stops a network user (and doesn't do a protection check) +END + +// flags - can specify as many as you like +CONSTANT + DEC_ONE_EXEC = 1 // decrement execs by 1 + DEC_MANY_EXECS = 2 // decrement execs by number specified in execs_decrement + START_NET_USER = 4 // starts a network user + USE_FUNCTION_ARGUMENT = 16 // use the extra argument in the function for pointers + CHECK_LOCAL_FIRST = 32 // always look in local ports before looking in network ports + CHECK_NETWORK_FIRST = 64 // always look on the network before looking in local ports + USE_ALT_LICENCE_NAME = 128 // use name specified in alt_licence_name instead of the default one + DONT_SET_MAXDAYS_EXPIRY = 256 // if the max days expiry date has not been calculated then do not do it this time + MATCH_DONGLE_NUMBER = 512 // restrict the search to match the dongle number specified in the DRIS + DONT_RETURN_FD_DRIVE = 1024 // if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS +END + +// SDSN (software developer's serial number) +CONSTANT + MY_SDSN = 10101 // !!!! change this value to be the value of your SDSN (demo = 10101) + MY_PRODCODE = "DEMO" // !!!! change thus value to be the value of your Product Code +END + + +// Summary: Sets each element of the DRIS to be a random value. Improves security +// Syntax: +//RandomSet () +// +PROCEDURE RandomSet() +DRIS_bytes is array of Length(DRIS) 1-byte unsigned int + +Transfer(&DRIS_bytes, &DRIS, Length(DRIS)) // copy DRIS to a byte array so we can look at each byte +InitRandom() +FOR i = 1 _TO_ Length(DRIS) + DRIS_bytes[i] = Random(0,255) // set each element to a random number +END +Transfer(&DRIS, &DRIS_bytes, Length(DRIS)) // copy back to DRIS + + +// Summary: Displays the error code with a helpful error message. You may want to change the messages. +// Syntax: +//DisplayError ( is int, is 4-byte unsigned int) +// +// Parameters: +// ret_code (int): +// ext_err (4-byte unsigned int): +// Return Value: +// None +// +// +PROCEDURE DisplayError(ret_code is int, ext_err is unsigned int) +SWITCH ret_code + CASE 401: Info("Error! No dongles detected!") + CASE 403: Info("Error! The dongle detected has a different type to the one specified in DinkeyAdd.") + CASE 404: Info("Error! The dongle detected has a different model to those specified in DinkeyAdd.") + CASE 409: Info("Error! The dongle detected has not been programmed by DinkeyAdd.") + CASE 410: Info("Error! The dongle detected has a different Product Code to the one specified in DinkeyAdd.") + CASE 411: Info("Error! The dongle detected does not contain the licence associated with this program.") + CASE 413: Info("Error! This program has not been protected by DinkeyAdd.","For guidance please read the DinkeyAdd chapter of the Dinkey manual.") + CASE 417: Info("Error! One or more of the parameters set in the DRIS is incorrect.","This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.") + CASE 423: Info("Error! The number of network users has been exceeded.") + CASE 435: Info("Error! DinkeyServer has not been detected on the network.") + CASE 922: Info("Error! The Software Key has expired.") + OTHER CASE: Info("An error occurred checking the dongle.","Error: " + ret_code, "Extended Error: " + ext_err) +END + diff --git a/Dinkey Pro 7.6.1/Samples/WinDev/Runtime/protection check functions.txt b/Dinkey Pro 7.6.1/Samples/WinDev/Runtime/protection check functions.txt new file mode 100644 index 0000000..13b748e --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/WinDev/Runtime/protection check functions.txt @@ -0,0 +1,784 @@ +// This code contains the following functions. Please choose the one that matches your needs: +// ProtCheck +// ProtCheckWithAlg (the function also depends on the function MyAlgorithm) +// WriteString +// ReadString +// EncryptUserData +// or the same functions but using DRIS and API data encryption +// (these functions also require the functions CryptDRIS and possibly CryptApiData and MyRWAlgorithm) +// ProtCheckEnc +// ProtCheckWithAlgEnc +// WriteStringEnc +// ReadStringEnc +// EncryptUserDataEnc + + +// Summary: does a standard protection check +// Syntax: +//[ = ] ProtCheck () +// return value is 0 (success) or an error code +PROCEDURE ProtCheck() +hLib, ret_code are system int + +// set the DRIS to have random values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = PROTECTION_CHECK // standard protection check +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... + +// Load the protection DLL. +hLib = LoadDLL(protectdllname) +IF hLib = 0 THEN + Info("Cannot load " + protectdllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +//do a protection check +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) +FreeDLL(hLib) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + RESULT ret_code +END + +// later in your code you can check other values in the DRIS... +IF (DRIS.sdsn <> MY_SDSN) THEN + Info("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + RESULT -1 +END + +IF (ExtractString(DRIS.prodcode, 1, Charact(0)) <> MY_PRODCODE) THEN + Info("Incorrect Product Code. Please modify your source code so that MY_PRODCODE is set to be your Product Code.") + RESULT -1 +END + +// later on in your program you can check the return code again +IF (DRIS.ret_code <> 0) THEN + Info("Dinkey Dongle protection error") + RESULT -1 +END + +Info("It worked!") + +// Summary: does a standard protection check and executes an algorithm +// NB for this to work you must program at least "user algorithm" into the dongle +// NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +// sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +// code from DinkeyLook +// Syntax: +//[ = ] ProtCheckWithAlg () +// return value is 0 (success) or an error code +PROCEDURE ProtCheckWithAlg() +hLib, ret_code are system int + +// set the DRIS to have random values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = EXECUTE_ALGORITHM // protection check and execute specified algorithm +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... +DRIS.alg_number = 1 +// !!!! you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random +DRIS.var_a = 1 // sample values +DRIS.var_b = 2 +DRIS.var_c = 3 +DRIS.var_d = 4 +DRIS.var_e = 5 +DRIS.var_f = 6 +DRIS.var_g = 7 +DRIS.var_h = 8 + +// Load the protection DLL. +hLib = LoadDLL(protectdllname) +IF hLib = 0 THEN + DelayBeforeClosing(1000) + Info("Cannot load " + protectdllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +//do a protection check +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) +FreeDLL(hLib) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + RESULT ret_code +END + +// later in your code you can check other values in the DRIS... +IF (DRIS.sdsn <> MY_SDSN) THEN + Info("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + RESULT -1 +END + +IF (ExtractString(DRIS.prodcode, 1, Charact(0)) <> MY_PRODCODE) THEN + Info("Incorrect Product Code. Please modify your source code so that MY_PRODCODE is set to be your Product Code.") + RESULT -1 +END + +// later on in your program you can check the return code again +IF (DRIS.ret_code <> 0) THEN + Info("Dinkey Dongle protection error") + RESULT -1 +END + +// if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code +// !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd +IF (MyAlgorithm(DRIS.var_a, DRIS.var_b, DRIS.var_c, DRIS.var_d, DRIS.var_e, DRIS.var_f, DRIS.var_g, DRIS.var_h) <> DRIS.alg_answer) THEN + Info("Dinkey protection error!", "You have not patched your algorithm in the MyAlgorithm routine") + RESULT -1 +END + +Info("It worked!") + +// Summary: +// !!!! You should replace this function with the one generated by the +// "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm) +// or from DinkeyLook if you are using a Dinkey Lite dongle. You can modify the C code to make it compatiable with Windev. +// Syntax: +//[ = ] MyAlgorithm ( is int, is int, is int, is int, is int, is int, is int, is int) +// +PROCEDURE MyAlgorithm(var_a is int, var_b is int, var_c is int, var_d is int, var_e is int, var_f is int, var_g is int, var_h is int) +RESULT var_a + var_b + var_c + var_d + var_e + var_f + var_g + var_h + + +// Summary: This function does a protection check and writes the string "Hello, World!" to the data area at offset 7 +// In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +// NB you can easily modify the code to write a byte array instead of a string +// Syntax: +//[ = ] WriteString () +// return value is 0 (success) or an error code +// +PROCEDURE WriteString() +hLib, ret_code are system int +OurString is fixed string on 1024 = "Hello, World!" // NB max. data write is 1K + +// set the DRIS to have random values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = WRITE_DATA_AREA // protection check and write specified data +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... +DRIS.rw_offset = 7 +DRIS.rw_length = Length(Left(OurString)) // the length of the string (in this case 13 bytes) +DRIS.rw_data_ptr = &OurString + +// Load the protection DLL. +hLib = LoadDLL(protectdllname) +IF hLib = 0 THEN + Info("Cannot load " + protectdllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +//do a protection check +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) +FreeDLL(hLib) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + RESULT ret_code +END + +// later in your code you can check other values in the DRIS... +IF (DRIS.sdsn <> MY_SDSN) THEN + Info("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + RESULT -1 +END + +IF (ExtractString(DRIS.prodcode, 1, Charact(0)) <> MY_PRODCODE) THEN + Info("Incorrect Product Code. Please modify your source code so that MY_PRODCODE is set to be your Product Code.") + RESULT -1 +END + +// later on in your program you can check the return code again +IF (DRIS.ret_code <> 0) THEN + Info("Dinkey Dongle protection error") + RESULT -1 +END + +Info("It worked!") + + +// Summary: This function does a protection check and reads 13 bytes of data from the data area at offset 7 +// In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +// NB you can amend this code to read a byte array instead of a string if you prefer. +// Syntax: +//[ = ] ReadString () +// return value is 0 (success) or an error code +// +PROCEDURE ReadString() +hLib, ret_code are system int +OurString is fixed string on 1024 // NB max. data read is 1K + +// set the DRIS to have random values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = READ_DATA_AREA // protection check and read data +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... +DRIS.rw_offset = 7 +DRIS.rw_length = 13 +DRIS.rw_data_ptr = &OurString + +// Load the protection DLL. +hLib = LoadDLL(protectdllname) +IF hLib = 0 THEN + Info("Cannot load " + protectdllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +//do a protection check +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) +FreeDLL(hLib) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + RESULT ret_code +END + +// later in your code you can check other values in the DRIS... +IF (DRIS.sdsn <> MY_SDSN) THEN + Info("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + RESULT -1 +END + +IF (ExtractString(DRIS.prodcode, 1, Charact(0)) <> MY_PRODCODE) THEN + Info("Incorrect Product Code. Please modify your source code so that MY_PRODCODE is set to be your Product Code.") + RESULT -1 +END + +// later on in your program you can check the return code again +IF (DRIS.ret_code <> 0) THEN + Info("Dinkey Dongle protection error") + RESULT -1 +END + +Info("It worked! Dinkey Dongle data area at offset 7 is:", OurString) + + +// Summary: this function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +// It will then do another protection check & decrypt the data. NB you can modify the code to encrypt byte arrays instead of strings +// NB you can amend this code to read a byte array instead of a string if you prefer. +// Syntax: +//[ = ] EncryptUserData () +// return value is 0 (success) or an error code +// +PROCEDURE EncryptUserData() +hLib, ret_code are system int +OurString is fixed string on 1024 = "Hello, World!" // NB max. data we can encrypt is 1K + +// set the DRIS to have random values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = ENCRYPT_USER_DATA // protection check and encrypt specified data +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... +DRIS.data_crypt_key_num = 1 +DRIS.rw_length = Length(Left(OurString)) // the length of the string (in this case 13 bytes) +DRIS.rw_data_ptr = &OurString + +// Load the protection DLL. +hLib = LoadDLL(protectdllname) +IF hLib = 0 THEN + Info("Cannot load " + protectdllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +//do a protection check +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + FreeDLL(hLib) + RESULT ret_code +END + +// NB can add code to check other elements of the DRIS e.g. SDSN, ProductCode (see ProtCheck function) + +// Now decrypt the same data to get the original values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = DECRYPT_USER_DATA // protection check and decrypt specified data +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... +DRIS.data_crypt_key_num = 1 +DRIS.rw_length = 13 // the length of the string (in this case 13 bytes) +DRIS.rw_data_ptr = &OurString // NB the data is encrypted at this point + +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) +FreeDLL(hLib) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + RESULT ret_code +END + +// NB can add code to check other elements of the DRIS e.g. SDSN, ProductCode (see ProtCheck function) + +Info("It worked! Dinkey Dongle data area at offset 7 is:", OurString) + + +// !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!! +// In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API" +// in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm +// but the code can be modified easily to use the 3 encryption parameters. + +// !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm (you will have to adapt the C code generated by DinkeyAdd) +PROCEDURE MyRWAlgorithm(var_a is int, var_b is int, var_c is int, var_d is int, var_e is int, var_f is int, nVar_g is int, nVar_h is int) +RESULT BinaryXOR(BinaryXOR(BinaryXOR(BinaryXOR(BinaryXOR(var_a, var_b), var_c), var_d), var_e), var_f) + +// !!!! please overwrite this function with the one generated by DinkeyAdd +// (just modify the parameters specified in DinkeyAdd in the positiions indicated below): +// Note arrays in Windev are 1-base which makes it a real pain +PROCEDURE CryptDRIS() +i, j, k are int +bigseed, S are array of 256 1-byte unsigned int +DRIS_bytes is an array of Length(DRIS) 1-byte unsigned int +temp, t are 1-byte unsigned int + +FOR i = 1 _TO_ 256 STEP 8 + Transfer(&bigseed[i], &DRIS.seed1, 4) + Transfer(&bigseed[i+4], &DRIS.seed2, 4) +END + +FOR i = 0 _TO_ 255 + S[i+1] = i +END + +j = 0 +FOR i = 0 _TO_ 255 + j = (j + S[i+1] + bigseed[i+1] + 123) modulo 256 // parameter 1, modify 123 + temp = S[i+1] + S[i+1] = S[j+1] + S[j+1] = temp +END + +Transfer(&DRIS_bytes, &DRIS, Length(DRIS)) // convert DRIS to bytes + +i = 0 +j = 0 +FOR k = 17 _TO_ Length(DRIS) + i = (i + 1) modulo 256 + j = (j + S[i+1] + 212) modulo 256 // parameter 2, modify 212 + temp = S[i+1] + S[i+1] = S[j+1] + S[j+1] = temp + t = (S[i+1] + S[j+1] + 97) modulo 256 // parameter 3, modify 97 + DRIS_bytes[k] = BinaryXOR(DRIS_bytes[k], S[t+1]) +END + +Transfer(&DRIS, &DRIS_bytes, Length(DRIS)) // convert back again + + + +// Note arrays in Windev are 1-base which makes it a real pain +// Summary: +// Syntax: +//CryptApiData (, is 4-byte unsigned int, is int) +PROCEDURE CryptApiData(data, enc_length is unsigned int, alg_ans is int) +i, j, k are int +bigseed, S are array of 256 1-byte unsigned int +temp, t are 1-byte unsigned int + +FOR i = 1 _TO_ 256 STEP 8 + Transfer(&bigseed[i], &DRIS.seed1, 4) + Transfer(&bigseed[i+4], &DRIS.seed2, 4) +END + +FOR i = 0 _TO_ 255 + S[i+1] = i +END + +j = 0 +FOR i = 0 _TO_ 255 + j = (j + S[i+1] + bigseed[i+1] + BinaryAND(alg_ans, 0xff)) modulo 256 + temp = S[i+1] + S[i+1] = S[j+1] + S[j+1] = temp +END + +i = 0 +j = 0 +FOR k = 1 _TO_ enc_length + i = (i + 1) modulo 256 + j = (j + S[i+1] + (BinaryAND(alg_ans, 0xff00))/256) modulo 256 + temp = S[i+1] + S[i+1] = S[j+1] + S[j+1] = temp + t = (S[i+1] + S[j+1] + (BinaryAND(alg_ans, 0xff0000))/65536) modulo 256 + data[k] = BinaryXOR(data[k], S[t+1]) +END + + +// Summary: does a standard protection check and encrypt the DRIS we pass and from the API. +// We encrypt the DRIS passed to the API. !!!! Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +// Syntax: +//[ = ] ProtCheckEnc () +// return value is 0 (success) or an error code +PROCEDURE ProtCheckEnc() +hLib, ret_code are system int + +// set the DRIS to have random values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = PROTECTION_CHECK // standard protection check +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... + +// Load the protection DLL. +hLib = LoadDLL(protectdllname) +IF hLib = 0 THEN + Info("Cannot load " + protectdllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +CryptDRIS() // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +//do a protection check +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) +FreeDLL(hLib) + +CryptDRIS() // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + RESULT ret_code +END + +// later in your code you can check other values in the DRIS... +IF (DRIS.sdsn <> MY_SDSN) THEN + Info("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + RESULT -1 +END + +IF (ExtractString(DRIS.prodcode, 1, Charact(0)) <> MY_PRODCODE) THEN + Info("Incorrect Product Code. Please modify your source code so that MY_PRODCODE is set to be your Product Code.") + RESULT -1 +END + +// later on in your program you can check the return code again +IF (DRIS.ret_code <> 0) THEN + Info("Dinkey Dongle protection error") + RESULT -1 +END + +Info("It worked!") + + +// Summary: does a standard protection check and executes an algorithm and encrypts the DRIS +// NB for this to work you must program at least one "user algorithm" into the dongle +// NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the +// sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample +// code from DinkeyLook. +// We encrypt the DRIS passed to the API. !!!! Patch the CryptDRIS function in this file from source code generated by DinkeyAdd. +// Syntax: +//[ = ] ProtCheckWithAlgEnc () +// return value is 0 (success) or an error code +PROCEDURE ProtCheckWithAlgEnc() +hLib, ret_code are system int + +// set the DRIS to have random values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = EXECUTE_ALGORITHM // protection check and execute specified algorithm +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... +DRIS.alg_number = 1 +// !!!! you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random +DRIS.var_a = 1 // sample values +DRIS.var_b = 2 +DRIS.var_c = 3 +DRIS.var_d = 4 +DRIS.var_e = 5 +DRIS.var_f = 6 +DRIS.var_g = 7 +DRIS.var_h = 8 + +// Load the protection DLL. +hLib = LoadDLL(protectdllname) +IF hLib = 0 THEN + DelayBeforeClosing(1000) + Info("Cannot load " + protectdllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +CryptDRIS() // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +//do a protection check +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) +FreeDLL(hLib) + +CryptDRIS() // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + RESULT ret_code +END + +// later in your code you can check other values in the DRIS... +IF (DRIS.sdsn <> MY_SDSN) THEN + Info("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + RESULT -1 +END + +IF (ExtractString(DRIS.prodcode, 1, Charact(0)) <> MY_PRODCODE) THEN + Info("Incorrect Product Code. Please modify your source code so that MY_PRODCODE is set to be your Product Code.") + RESULT -1 +END + +// later on in your program you can check the return code again +IF (DRIS.ret_code <> 0) THEN + Info("Dinkey Dongle protection error") + RESULT -1 +END + +// if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code +// !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd +IF (MyAlgorithm(DRIS.var_a, DRIS.var_b, DRIS.var_c, DRIS.var_d, DRIS.var_e, DRIS.var_f, DRIS.var_g, DRIS.var_h) <> DRIS.alg_answer) THEN + Info("Dinkey protection error!", "You have not patched your algorithm in the MyAlgorithm routine") + RESULT -1 +END + +Info("It worked!") + + +// Summary: This function does a protection check and writes the string "Hello, World!" to the data area at offset 7 +// In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +// NB you can easily modify the code to write a byte array instead of a string +// We encrypt the DRIS and Data passed to the API. !!!! Patch the CryptDRIS, CryptApiData and MyRWAlgorithm functions in this file from source code generated by DinkeyAdd. +// Syntax: +//[ = ] WriteStringEnc () +// return value is 0 (success) or an error code +// +PROCEDURE WriteStringEnc() +hLib, ret_code are system int +alg_ans are int +OurString is fixed string on 1024 = "Hello, World!" // NB max. data write is 1K +OurString_bytes is array of 1024 1-byte unsigned int // byte-array of the encrypted string + +// set the DRIS to have random values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = WRITE_DATA_AREA // protection check and write specified data +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... +DRIS.rw_offset = 7 +DRIS.rw_length = Length(Left(OurString)) // the length of the string (in this case 13 bytes) +DRIS.rw_data_ptr = &OurString_bytes // we convert the string to write to a byte array (so we can encrypt it) and then we pass that value to our API + +// Load the protection DLL. +hLib = LoadDLL(protectdllname) +IF hLib = 0 THEN + Info("Cannot load " + protectdllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +// calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code generated by DinkeyAdd +alg_ans = MyRWAlgorithm(DRIS.var_a, DRIS.var_b, DRIS.var_c, DRIS.var_d, DRIS.var_e, DRIS.var_f, DRIS.var_g, DRIS.var_h) + +// encrypt data we want to write (we must first convert it to a byte array so we can encrypt) +Transfer(&OurString_bytes, &OurString, DRIS.rw_length) +CryptApiData(OurString_bytes, DRIS.rw_length, alg_ans) + +CryptDRIS() // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +//do a protection check +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) +FreeDLL(hLib) + +CryptDRIS() // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + RESULT ret_code +END + +// later in your code you can check other values in the DRIS... +IF (DRIS.sdsn <> MY_SDSN) THEN + Info("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + RESULT -1 +END + +IF (ExtractString(DRIS.prodcode, 1, Charact(0)) <> MY_PRODCODE) THEN + Info("Incorrect Product Code. Please modify your source code so that MY_PRODCODE is set to be your Product Code.") + RESULT -1 +END + +// later on in your program you can check the return code again +IF (DRIS.ret_code <> 0) THEN + Info("Dinkey Dongle protection error") + RESULT -1 +END + +Info("It worked!") + + +// Summary: This function does a protection check and reads 13 bytes of data from the data area at offset 7 +// In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long. +// NB you can amend this code to read a byte array instead of a string if you prefer. +// We encrypt the DRIS and Data passed to the API. !!!! Patch the CryptDRIS, CryptApiData and MyRWAlgorithm functions in this file from source code generated by DinkeyAdd. +// Syntax: +//[ = ] ReadStringEnc () +// return value is 0 (success) or an error code +// +PROCEDURE ReadStringEnc() +hLib, ret_code are system int +alg_ans are int +OurString is fixed string on 1024 // NB max. data read is 1K +OurString_bytes is array of 1024 1-byte unsigned int // byte-array of the encrypted string + +// set the DRIS to have random values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = READ_DATA_AREA // protection check and read data +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... +DRIS.rw_offset = 7 +DRIS.rw_length = 13 +DRIS.rw_data_ptr = &OurString_bytes // read it to our byte array first and then convert to a string + +// Load the protection DLL. +hLib = LoadDLL(protectdllname) +IF hLib = 0 THEN + Info("Cannot load " + protectdllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +// calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code generated by DinkeyAdd +alg_ans = MyRWAlgorithm(DRIS.var_a, DRIS.var_b, DRIS.var_c, DRIS.var_d, DRIS.var_e, DRIS.var_f, DRIS.var_g, DRIS.var_h) + +CryptDRIS() // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +//do a protection check +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) +FreeDLL(hLib) + +CryptDRIS() // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + RESULT ret_code +END + +// later in your code you can check other values in the DRIS... +IF (DRIS.sdsn <> MY_SDSN) THEN + Info("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.") + RESULT -1 +END + +IF (ExtractString(DRIS.prodcode, 1, Charact(0)) <> MY_PRODCODE) THEN + Info("Incorrect Product Code. Please modify your source code so that MY_PRODCODE is set to be your Product Code.") + RESULT -1 +END + +// later on in your program you can check the return code again +IF (DRIS.ret_code <> 0) THEN + Info("Dinkey Dongle protection error") + RESULT -1 +END + +// decrypt data we have just read (then convert to string) +CryptApiData(OurString_bytes, DRIS.rw_length, alg_ans) +Transfer(&OurString, &OurString_bytes, DRIS.rw_length) + +Info("It worked! Dinkey Dongle data area at offset 7 is:", OurString) + + +// Summary: this function will do a protection check and ask the dongle to encrypt some data using encryption key 1 +// It will then do another protection check & decrypt the data. NB you can modify the code to encrypt byte arrays instead of strings +// NB you can amend this code to read a byte array instead of a string if you prefer. +// We encrypt the DRIS and Data passed to the API. !!!! Patch the CryptDRIS, CryptApiData and MyRWAlgorithm functions in this file from source code generated by DinkeyAdd. +// Syntax: +//[ = ] EncryptUserDataEnc () +// return value is 0 (success) or an error code +// +PROCEDURE EncryptUserDataEnc() +hLib, ret_code are system int +alg_ans is int +OurString is fixed string on 1024 = "Hello, World!" // NB max. data we can encrypt is 1K +OurString_bytes is array of 1024 1-byte unsigned int // byte-array of the encrypted string + +// set the DRIS to have random values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = ENCRYPT_USER_DATA // protection check and encrypt specified data +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... +DRIS.data_crypt_key_num = 1 +DRIS.rw_length = Length(Left(OurString)) // the length of the string (in this case 13 bytes) +DRIS.rw_data_ptr = &OurString_bytes // we convert the string to encrypt to a byte array (so we can encrypt it) and then we pass that to the API + +// Load the protection DLL. +hLib = LoadDLL(protectdllname) +IF hLib = 0 THEN + Info("Cannot load " + protectdllname, "This DLL should be in the same folder as this executable") + RESULT -1 +END + +// calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code generated by DinkeyAdd +alg_ans = MyRWAlgorithm(DRIS.var_a, DRIS.var_b, DRIS.var_c, DRIS.var_d, DRIS.var_e, DRIS.var_f, DRIS.var_g, DRIS.var_h) + +// encrypt data we want to write (we must first convert it to a byte array so we can encrypt) +Transfer(&OurString_bytes, &OurString, DRIS.rw_length) +CryptApiData(OurString_bytes, DRIS.rw_length, alg_ans) + +CryptDRIS() // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +//do a protection check +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) + +CryptDRIS() // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + FreeDLL(hLib) + RESULT ret_code +END + +// NB can add code to check other elements of the DRIS e.g. SDSN, ProductCode (see ProtCheck function) + +// Now decrypt the same data to get the original values +RandomSet() +// then set the values we want to use +DRIS.header = "DRIS" +DRIS.size = Length(DRIS) +DRIS.dpfunction = DECRYPT_USER_DATA // protection check and decrypt specified data +DRIS.flags = 0 // no extra flags, but you may want to specify some if you want to start a network user or decrement execs... +DRIS.data_crypt_key_num = 1 +DRIS.rw_length = 13 // the length of the string (in this case 13 bytes) +DRIS.rw_data_ptr = &OurString_bytes // NB this wil still be the encrypted data at this point + +alg_ans = MyRWAlgorithm(DRIS.var_a, DRIS.var_b, DRIS.var_c, DRIS.var_d, DRIS.var_e, DRIS.var_f, DRIS.var_g, DRIS.var_h) + +CryptDRIS() // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +ret_code = CallDLL32(protectdllname, "DDProtCheck", &DRIS, 0) +FreeDLL(hLib) + +CryptDRIS() // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security) + +IF ret_code <> 0 THEN // an error occured so display an appropriate error message + DisplayError(ret_code, DRIS.ext_err) + RESULT ret_code +END + +// NB can add code to check other elements of the DRIS e.g. SDSN, ProductCode (see ProtCheck function) + +// decrypt the returned value and convert to a string +CryptApiData(OurString_bytes, DRIS.rw_length, alg_ans) +Transfer(&OurString, &OurString_bytes, DRIS.rw_length) +Info("It worked! Dinkey Dongle data area at offset 7 is:", OurString) + diff --git a/Dinkey Pro 7.6.1/Samples/Xojo/README.txt b/Dinkey Pro 7.6.1/Samples/Xojo/README.txt new file mode 100644 index 0000000..767ad11 --- /dev/null +++ b/Dinkey Pro 7.6.1/Samples/Xojo/README.txt @@ -0,0 +1,4 @@ +Xojo Sample Code +~~~~~~~~~~~~~~~~ + +See RealBasic sample code. \ No newline at end of file diff --git a/Dinkey Pro 7.6.1/uninstall.exe.nsis b/Dinkey Pro 7.6.1/uninstall.exe.nsis new file mode 100644 index 0000000..2e721a2 Binary files /dev/null and b/Dinkey Pro 7.6.1/uninstall.exe.nsis differ

+ Using the DoneEx XCell Compiler and the Shell method is the preferred option for most Excel users, + as it does not require you to write any VBA macro code, and so is easier to implement. +