Index: client/pkgd.eagle
==================================================================
--- client/pkgd.eagle
+++ client/pkgd.eagle
@@ -18,10 +18,15 @@
# NOTE: Use our own namespace here because even though we do not directly
# support namespaces ourselves, we do not want to pollute the global
# namespace if this script actually ends up being evaluated in Tcl.
#
namespace eval ::PackageDownloader {
+ #
+ # NOTE: This procedure sets up the default values for all configuration
+ # parameters used by the package downloader client. There are no
+ # arguments.
+ #
proc setupDownloadVars {} {
#
# NOTE: Prevent progress messages from being displayed while downloading
# from the repository, etc? By default, this is enabled.
#
@@ -58,18 +63,31 @@
if {![info exists persistentDirectory]} then {
set persistentDirectory [getPersistentRootDirectory]
}
}
+ #
+ # NOTE: This procedure returns the root directory where any packages that
+ # are downloaded should be saved to permanent storage for subsequent
+ # use. There are no arguments.
+ #
proc getPersistentRootDirectory {} {
#
# NOTE: Return a directory parallel to the one containing the library
# directory.
#
return [file join [file dirname [info library]] pkgr]
}
+ #
+ # NOTE: This procedure adds a directory to the auto-path of the specified
+ # language (i.e. native Tcl or Eagle). The directory will not be
+ # added if it is already present. The language argument must be the
+ # literal string "eagle" or the literal string "tcl". The directory
+ # argument is the fully qualified path for the directory to add to
+ # the auto-path.
+ #
proc addToAutoPath { language directory } {
#
# NOTE: Add the specified directory to the auto-path if not already
# present.
#
@@ -106,15 +124,40 @@
} else {
error "unsupported language, no idea how to modify auto-path"
}
}
+ #
+ # NOTE: This procedure attempts to download a list of files, optionally
+ # persistening them for subsequent uses by the target language.
+ # The language argument must be the literal string "eagle" or the
+ # literal string "tcl". The version argument must be the literal
+ # string "8.4", "8.5", or "8.6" when the language is "tcl" -OR-
+ # the literal string "1.0" when the language is "eagle". The
+ # fileNames argument must be a well-formed list of file names to
+ # download, each one relative to the language/version-specific
+ # directory on the package file server. The persistent argument
+ # should be non-zero if the downloaded files should be saved to
+ # permanent storage for subsequent use.
+ #
proc downloadFiles { language version fileNames persistent } {
variable baseUri
variable downloadUri
variable persistentDirectory
variable quiet
+
+ if {[string length $language] == 0 || $language eq "eagle"} then {
+ if {$version ne "1.0"} then {
+ error "unsupported Eagle version"
+ }
+ } elseif {$language eq "tcl"} then {
+ if {$version ne "8.4" && $version ne "8.5" && $version ne "8.6"} then {
+ error "unsupported Tcl version"
+ }
+ } else {
+ error "unsupported language"
+ }
if {$persistent} then {
set downloadRootDirectory [file join $persistentDirectory]
} else {
global env
Index: client/pkgd.eagle.harpy
==================================================================
--- client/pkgd.eagle.harpy
+++ client/pkgd.eagle.harpy
@@ -19,32 +19,32 @@
None
Mistachkin Systems
- 36e6e8e4-39ac-4f29-928e-5c10e32cb1eb
+ 2c09ab50-08d8-47a0-8d50-96529e4cf6fd
SHA512
Script
- 2016-08-16T23:11:46.2517109Z
+ 2016-08-17T22:38:23.1247578Z
-1.00:00:00
0x2c322765603b5278
- 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
+ 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
Index: client/pkgr.eagle
==================================================================
--- client/pkgr.eagle
+++ client/pkgr.eagle
@@ -27,15 +27,25 @@
# be modified to include the "Eagle1.0" directory (i.e. the one
# containing the Eagle core script library file "init.eagle").
#
package require Eagle.Library
+ #
+ # NOTE: This procedure returns a formatted, possibly version-specific,
+ # package name, for use in logging.
+ #
proc formatPackageName { package version } {
return [string trim [appendArgs \
$package " " [getLookupVersion $version]]]
}
+ #
+ # NOTE: This procedure returns a formatted script result. If the string
+ # result is empty, only the return code is used. The code argument
+ # must be an integer Tcl return code (e.g. from [catch]) and the
+ # result argument is the script result or error message.
+ #
proc formatResult { code result } {
switch -exact -- $code {
0 {set codeString ok}
1 {set codeString error}
2 {set codeString return}
@@ -49,16 +59,26 @@
} else {
return $codeString
}
}
+ #
+ # NOTE: This procedure emits a message to the package repository client
+ # log. The string argument is the content of the message to emit.
+ #
+ #
proc pkgLog { string } {
catch {
tclLog [appendArgs [pid] " : " [clock seconds] " : pkgr : " $string]
}
}
+ #
+ # NOTE: This procedure attempts to determine if a string is a valid list
+ # and returns non-zero when that is true. The value argument is
+ # the string to check.
+ #
proc stringIsList { value } {
if {[isEagle]} then {
return [string is list $value]
} else {
global tcl_version
@@ -71,10 +91,16 @@
return false
}
}
}
+ #
+ # NOTE: This procedure returns non-zero if the specified string value
+ # looks like a Harpy (script) certificate. The value argument
+ # is the string to check.
+ #
+ #
proc isHarpyCertificate { value } {
if {[string length $value] == 0 || [string first [string trim {
proc isPgpSignature { value } {
if {[string length $value] == 0 || [string first [string trim {
-----BEGIN PGP SIGNATURE-----
}] $value] != -1} then {
return true
@@ -91,10 +123,15 @@
} else {
return false
}
}
+ #
+ # NOTE: This procedure returns a unique temporary file name. A script
+ # error is raised if this task cannot be accomplished. There are
+ # no arguments.
+ #
proc getFileTempName {} {
if {[isEagle]} then {
return [file tempname]
} else {
global env
@@ -122,10 +159,18 @@
incr counter
}
}
}
+ #
+ # NOTE: This procedure attempts to verify the PGP signature contained in
+ # the specified (named) file. Non-zero is only returned if the PGP
+ # signature is verified successfully. A script error should not be
+ # raised by this procedure. The fileName argument must be the fully
+ # qualified path and file name of the PGP signature file to verify.
+ #
+ #
proc verifyPgpSignature { fileName } {
variable pgpCommand
if {[isEagle]} then {
set fileName [appendArgs \" $fileName \"]
@@ -144,20 +189,38 @@
}
return false
}
+ #
+ # NOTE: This procedure returns the prefix for fully qualified variable
+ # names that MAY be present in the global namespace. There are
+ # no arguments.
+ #
proc getLookupVarNamePrefix {} {
return ::pkgr_; # TODO: Make non-global?
}
+ #
+ # NOTE: This procedure returns a unique suffix for a fully qualified
+ # variable name that MAY be present in the global namespace.
+ # It is used (internally) to avoid any name collisions with
+ # variables and commands in the global namespace. There are
+ # no arguments.
+ #
proc getLookupVarNameSuffix {} {
return [appendArgs \
[string trim [pid] -] _ [string trim [clock seconds] -] _ \
[string trim [clock clicks -milliseconds] -]]; # TODO: Bad?
}
+ #
+ # NOTE: This procedure returns the list of API keys to use when looking
+ # up packages via the package repository server. An empty list
+ # is returned if no API keys are currently configured. There are
+ # no arguments.
+ #
proc getLookupApiKeys {} {
set varName [appendArgs [getLookupVarNamePrefix] api_keys]
if {[info exists $varName]} then {
return [set $varName]
@@ -188,10 +251,20 @@
}
return https://urn.to/r/pkg; # NOTE: System default.
}
+ #
+ # NOTE: This procedure returns the full URI to use when looking up a
+ # specific package via the package repository server. The apiKey
+ # argument is the API key to use -OR- an empty string if a public
+ # package is being looked up. The package argument is the name
+ # of the package being looked up, it cannot be an empty string.
+ # The version argument is the specific version being looked up
+ # -OR- an empty string for any available version. No HTTP request
+ # is issued by this procedure; it just returns the URI to use.
+ #
proc getLookupUri { apiKey package version } {
set baseUri [getLookupBaseUri]
if {[string length $baseUri] == 0} then {
return ""
@@ -214,18 +287,33 @@
$baseUri ? [http::formatQuery raw 1 method lookup apiKey $apiKey \
package $package version $version]]
}
}
+ #
+ # NOTE: This procedure returns the version of the package that should be
+ # used to lookup the associated [package ifneeded] script -OR- an
+ # empty string if no such version exists. The package argument is
+ # the name of the package, it cannot be an empty string. The
+ # version argument is the specific version being looked up -OR- an
+ # empty string for any available version.
+ #
proc getIfNeededVersion { package version } {
if {[string length $version] > 0} then {
return $version
}
return [lindex [package versions $package] 0]
}
+ #
+ # NOTE: This procedure accepts a package requirement (spec) and returns
+ # a simple package version, if possible. An empty string will be
+ # returned, if appropriate (i.e. any version should be allowed).
+ # The requirement argument must be a package specification that
+ # conforms to TIP #268.
+ #
proc getLookupVersion { requirement } {
if {[set index [string first - $requirement]] != -1} then {
incr index -1; set requirement [string range $requirement 0 $index]
}
@@ -241,10 +329,20 @@
}
return $requirement
}
+ #
+ # NOTE: This procedure issues an HTTP request that should return metadata
+ # that can be used to load and/or provide the specified package.
+ # The apiKey argument is the API key to use -OR- an empty string if
+ # a public package is being looked up. The package argument is the
+ # name of the package, it cannot be an empty string. The version
+ # argument is the specific version being looked up -OR- an empty
+ # string for any available version. This procedure may raise script
+ # errors.
+ #
proc getLookupData { apiKey package version } {
variable verboseUriDownload
set uri [getLookupUri $apiKey $package $version]
@@ -258,12 +356,11 @@
}
if {[isEagle]} then {
set data [uri download -inline $uri]
} else {
- variable quiet
-
+ set quiet [expr {!$verboseUriDownload}]
set data [getFileViaHttp $uri 10 stdout $quiet]
}
if {$verboseUriDownload} then {
pkgLog [appendArgs \
@@ -276,34 +373,57 @@
set data [string trim $data]
return $data
}
+ #
+ # NOTE: This procedure attempts to extract the lookup code from the raw
+ # HTTP response data. The data argument is the raw HTTP response
+ # data. An empty string is returned if no lookup code is available.
+ #
proc getLookupCodeFromData { data } {
if {![stringIsList $data] || [llength $data] < 1} then {
return ""
}
return [lindex $data 0]
}
+ #
+ # NOTE: This procedure attempts to extract the lookup result from the raw
+ # HTTP response data. The data argument is the raw HTTP response
+ # data. An empty string is returned if no lookup result is available.
+ #
proc getLookupResultFromData { data } {
if {![stringIsList $data] || [llength $data] < 2} then {
return ""
}
return [lindex $data 1]
}
+ #
+ # NOTE: This procedure returns non-zero if the specified lookup response
+ # code indicates success. The code argument is the extracted HTTP
+ # lookup response code.
+ #
proc isLookupCodeOk { code } {
#
# NOTE: The code must be the literal string "OK" for the package lookup
# request to be considered successful.
#
return [expr {$code eq "OK"}]
}
+ #
+ # NOTE: This procedure attempts to extract the package lookup metadata from
+ # the lookup result. The result argument is the lookup result. The
+ # varName argument is the name of an array variable, in the call frame
+ # of the immediate caller, that should receive the extracted package
+ # lookup metadata. The caller argument must be an empty string -OR-
+ # the literal string "handler".
+ #
proc extractAndVerifyLookupMetadata { result varName caller } {
variable strictUnknownLanguage
#
# NOTE: Grab the language for the package script. It must be an empty
@@ -358,12 +478,12 @@
}
}
}
#
- # NOTE: If the caller wants the package metadata, use their array
- # variable name.
+ # NOTE: If the caller wants the package lookup metadata, use their
+ # array variable name.
#
if {[string length $varName] > 0} then {
upvar 1 $varName metadata
set metadata(language) $language
@@ -370,10 +490,15 @@
set metadata(script) $script
set metadata(certificate) $certificate
}
}
+ #
+ # NOTE: This procedure, which may only be used from an Eagle script, checks
+ # if a native Tcl library is loaded and ready. If not, a script error
+ # is raised.
+ #
proc tclMustBeReady {} {
#
# NOTE: This procedure is not allowed to actually load a native Tcl
# library; therefore, one must already be loaded.
#
@@ -384,10 +509,15 @@
if {![tcl ready]} then {
error "cannot use Tcl language, supporting library is not loaded"
}
}
+ #
+ # NOTE: This procedure, which may only be used from a native Tcl script,
+ # checks if Garuda and Eagle are loaded and ready. If not, a script
+ # error is raised.
+ #
proc eagleMustBeReady {} {
#
# NOTE: This procedure is not allowed to actually load Garuda (and
# Eagle); therefore, they must already be loaded.
#
@@ -398,10 +528,15 @@
if {[llength [info commands eagle]] == 0} then {
error "cannot use Eagle language, supporting package is not loaded"
}
}
+ #
+ # NOTE: This procedure returns non-zero if the current script is being
+ # evaluated in Eagle with signed-only script security enabled.
+ # There are no arguments.
+ #
proc eagleHasSecurity {} {
#
# NOTE: If possible, check if the current interpreter has security
# enabled.
#
@@ -414,10 +549,26 @@
}
return false
}
+ #
+ # NOTE: This procedure uses the package lookup metadata. If the package
+ # script is properly signed, an attempt will be made to evaluate it
+ # in the target language. If the script was signed using PGP, then
+ # a conforming implementation of the OpenPGP specification (e.g.
+ # gpg2) must be installed locally. If the script was signed using
+ # Harpy then Garuda, Eagle, and Harpy must be installed locally.
+ # This procedure is designed to work for both native Tcl and Eagle
+ # packages. Additionally, it is designed to work when evaluated
+ # using either native Tcl or Eagle; however, it is up to the package
+ # script itself to either add the package or provide the package to
+ # the language(s) supported by that package. The varName argument
+ # is the name of an array variable in the call frame of the
+ # immediate caller, that contains the package lookup metadata. This
+ # procedure may raise script errors.
+ #
proc processLookupMetadata { varName } {
#
# NOTE: If the metadata variable name appears to be invalid, fail.
#
if {[string length $varName] == 0} then {
@@ -738,10 +889,17 @@
} else {
error "unsupported script certificate"
}
}
+ #
+ # NOTE: This procedure performs initial setup of the package repository
+ # client, using the current configuration parameters. There are
+ # no arguments. It may load the Garuda package when evaluated in
+ # native Tcl. It may load a native Tcl library when evaluated in
+ # Eagle. It may install the [package unknown] hook.
+ #
proc setupPackageUnknownHandler {} {
variable autoHook
variable autoLoadTcl
variable autoRequireGaruda
@@ -768,15 +926,27 @@
#
hookPackageUnknownHandler
}
}
+ #
+ # NOTE: This procedure returns non-zero if the [package unknown] handler
+ # has already been hooked by the package repository client. There
+ # are no arguments.
+ #
proc isPackageUnknownHandlerHooked {} {
return [info exists [appendArgs \
[getLookupVarNamePrefix] saved_package_unknown]]
}
+ #
+ # NOTE: This procedure attempts to hook the [package unknown] handler. It
+ # will raise a script error if this has already been done. The old
+ # [package unknown] handler is saved and will be used by the new one
+ # as part of the overall package loading process. There are no
+ # arguments.
+ #
proc hookPackageUnknownHandler {} {
set varName [appendArgs [getLookupVarNamePrefix] saved_package_unknown]
if {[info exists $varName]} then {
error "package unknown handler already hooked"
@@ -784,10 +954,17 @@
set $varName [package unknown]
package unknown [appendArgs [namespace current] ::packageUnknownHandler]
}
+ #
+ # NOTE: This procedure attempts to unhook the [package unknown] handler.
+ # It will raise a script error if the [package unknown] handler is
+ # not hooked. The old [package unknown] handler is restored and
+ # the saved [package unknown] handler is cleared. There are no
+ # arguments.
+ #
proc unhookPackageUnknownHandler {} {
set varName [appendArgs [getLookupVarNamePrefix] saved_package_unknown]
if {![info exists $varName]} then {
error "package unknown handler is not hooked"
@@ -795,10 +972,15 @@
package unknown [set $varName]
unset $varName
}
+ #
+ # NOTE: The procedure runs the saved [package unknown] handler. Any script
+ # errors are raised to the caller. The package and version arguments
+ # are passed in from the current [package unknown] handler verbatim.
+ #
proc runSavedPackageUnknownHandler { package version } {
#
# NOTE: See if there is a saved [package unknown] handler. If so, then
# attempt to use it.
#
@@ -809,13 +991,17 @@
lappend oldHandler $package $version; uplevel #0 $oldHandler
}
}
#
- # NOTE: This version argument to this procedure must be optional, because
- # Eagle does not add a version argument when one is not supplied to
- # the [package require] sub-command itself.
+ # NOTE: This procedure is the [package unknown] handler entry point called
+ # by native Tcl and Eagle. The package argument is the name of the
+ # package being sought, it cannot be an empty string. The version
+ # argument must be a specific version -OR- a package specification
+ # that conforms to TIP #268. This version argument must be optional
+ # here, because Eagle does not add a version argument when one is
+ # not explicitly supplied to the [package require] sub-command.
#
proc packageUnknownHandler { package {version ""} } {
variable verboseUnknownResult
#
@@ -881,10 +1067,17 @@
"\" was not loaded"]
}
}
}
+ #
+ # NOTE: This procedure evaluates the package repository client settings
+ # script file, if it exists. Any script errors raised are not
+ # masked. The script argument must be the fully qualified path
+ # and file name for the primary package repository client script
+ # file.
+ #
proc maybeReadSettingsFile { script } {
if {[string length $script] == 0 || \
![file exists $script] || ![file isfile $script]} then {
return
}
@@ -895,21 +1088,16 @@
if {[file exists $fileName] && [file isfile $fileName]} then {
uplevel 1 [list source $fileName]
}
}
+ #
+ # NOTE: This procedure sets up the default values for all configuration
+ # parameters used by the package repository client. There are no
+ # arguments.
+ #
proc setupPackageUnknownVars {} {
- #
- # NOTE: Prevent progress messages from being displayed while downloading
- # from the repository, etc? By default, this is enabled.
- #
- variable quiet; # DEFAULT: true
-
- if {![info exists quiet]} then {
- set quiet true
- }
-
#
# NOTE: Automatically install our [package unknown] handler when this
# package is loaded?
#
variable autoHook; # DEFAULT: true
@@ -976,10 +1164,20 @@
if {![info exists verboseUriDownload]} then {
set verboseUriDownload false
}
}
+ #
+ # NOTE: This procedure is the primary entry point to the package repository
+ # client. It attempts to lookup the specified package using the
+ # currently configured package repository server. The package
+ # argument is the name of the package being sought, it cannot be an
+ # empty string. The version argument must be a specific version -OR-
+ # a package specification that conforms to TIP #268. The caller
+ # argument must be an empty string -OR- the literal string "handler".
+ #
+ #
proc main { package version caller } {
#
# NOTE: Get the list of API keys and try each one, in order, until
# the package is found.
#
@@ -1050,31 +1248,58 @@
###########################################################################
############################# BEGIN Tcl ONLY ##############################
###########################################################################
#
- # NOTE: This procedure was stolen from the "getEagle.tcl" script.
+ # NOTE: This procedure was stolen from the "getEagle.tcl" script. It is
+ # designed to emit a progress indicator while an HTTP request is
+ # being processed. The channel argument is the Tcl channel where
+ # the progress indicator should be emitted. The type argument is
+ # the single-character progress indicator. The milliseconds
+ # argument is the number of milliseconds to wait until the next
+ # periodic progress indicator should be emitted. This procedure
+ # reschedules its own execution.
#
proc pageProgress { channel type milliseconds } {
+ #
+ # NOTE: This variable is used to keep track of the currently scheduled
+ # (i.e. pending) [after] event.
+ #
+ variable afterForPageProgress
+
#
# NOTE: Show that something is happening...
#
catch {puts -nonewline $channel $type; flush $channel}
#
- # NOTE: Make sure that we are scheduled to run again.
+ # NOTE: Make sure that we are scheduled to run again, if requested.
#
if {$milliseconds > 0} then {
- after $milliseconds [namespace code [list pageProgress \
- $channel $type $milliseconds]]
+ set afterForPageProgress [after $milliseconds \
+ [namespace code [list pageProgress $channel $type \
+ $milliseconds]]]
+ } else {
+ unset afterForPageProgress
}
}
#
- # NOTE: This procedure was stolen from the "getEagle.tcl" script.
+ # NOTE: This procedure was stolen from the "getEagle.tcl" script. It is
+ # designed to process a single HTTP request, including any HTTP
+ # 3XX redirects (up to the specified limit), and return the raw
+ # HTTP response data. It does not contain special code to handle
+ # HTTP status codes other than 3XX (e.g. 4XX, 5XX, etc).
#
+ #
proc getFileViaHttp { uri redirectLimit channel quiet args } {
+ #
+ # NOTE: This variable is used to keep track of the currently scheduled
+ # (i.e. pending) [after] event.
+ #
+ variable afterForPageProgress
+
#
# NOTE: This procedure requires the modern version of the HTTP package,
# which is typically included with the Tcl core distribution.
#
package require http 2.0
@@ -1204,10 +1429,17 @@
set data [::http::data $token]
::http::cleanup $token; break
}
}
}
+
+ #
+ # NOTE: If there is a currently scheduled [after] event, cancel it.
+ #
+ if {[info exists afterForPageProgress]} then {
+ catch {after cancel $afterForPageProgress}
+ }
#
# NOTE: If progress messages were emitted, start a fresh line.
#
if {!$quiet} then {
Index: client/pkgr.eagle.harpy
==================================================================
--- client/pkgr.eagle.harpy
+++ client/pkgr.eagle.harpy
@@ -19,32 +19,32 @@
None
Mistachkin Systems
- 3568d473-0bb6-4f90-be5f-8b450f8736d7
+ 46bd3e67-77bb-4fa4-a28a-7c83625d9f52
SHA512
Script
- 2016-08-17T20:05:49.0964375Z
+ 2016-08-17T22:22:41.5866719Z
-1.00:00:00
0x2c322765603b5278
- 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
+ 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
Index: client/pkgr.settings.eagle
==================================================================
--- client/pkgr.settings.eagle
+++ client/pkgr.settings.eagle
@@ -12,8 +12,11 @@
#
# RCS: @(#) $Id: $
#
###############################################################################
+# TODO: Set this to your list of API keys.
+# set ::pkgr_api_keys [list 0000000000000000000000000000000000000000]
+
variable strictUnknownLanguage false
variable verboseUnknownResult true
variable verboseUriDownload true
Index: client/pkgr.settings.eagle.harpy
==================================================================
--- client/pkgr.settings.eagle.harpy
+++ client/pkgr.settings.eagle.harpy
@@ -19,32 +19,32 @@
None
Mistachkin Systems
- 32fce62e-9899-4d81-b1d8-2fac61bb26fb
+ b44b4ef2-76ad-4786-b4b7-e1d604e15e8b
SHA512
Script
- 2016-08-17T19:24:49.1950703Z
+ 2016-08-17T22:22:56.6608906Z
-1.00:00:00
0x2c322765603b5278
- Y39+6r8dzwDCn6Ze2DrONO0bDIzV2h+QXR2QlUN7iA5UK0PvN3TjvvhHhJOSxcEAuxthZySu2dkP
- bieKV0gFN51x2Q9bJajyzKVJW1L79b8DdTE0jTX/Lr3R92w3DZVX6bi8nZreuKhN37PEJ1IkQhVw
- /2YqRDFOAH6vC5ig7ujOsL74jaUTiyA6dBz7WFuu4IUDcSnkMJxnf50DuH0U40/1BICc525HFrA+
- U6OhoYEthUl/fUzZ9xXBc76hfTkdkgF+r8C1JNPuX6Gz5EcBLu1SEWumszq7zTnN5Rk1/rf6KJb5
- 3XXGyqncpOK8chlJdGW13ck929P/lJxzjM2GvwzTlSEQeKZXIET67P3al8U0yTLeQlgG/DGKz8WO
- 06Iktkp4FQPvOIFB07Po6ADZw8MNK/A3sTei2md9RVVJzWrMY34S3BfMHYhDUQQUzGRF4OjLhuWU
- giyNTXIvqa0Kx+JBnQ4uQP0Z7lhoLM+0rI1yDYFVfpKERud+KDDfBqoxfTVMIdJw1NX9uVe23SLK
- vw0FPHRF+bDjM2AhLxF4APG3pmPW6fJAkTJaLoKq38JoAleVeKyGa4ygdSkMqmI+Q8PSlqlhxL87
- pB9g0N9Ffq/UuZbeXycdw3VeBEEhtAAgozm22Gxhjc0HIywnBLWyF+PhKOoNJFLw3L4BfaSQmnSu
- yWTXZhHWvUU6dyyWORLqpwwo94AHxGmMUqIZrp1EhC2Zmb4wouw0RUjEbbjBwkFYC38w0kikrzhZ
- i/+CG9XC6HoCQM0FUu+28zvm+CNP7W+b8YfxV/k8HH4HehY3w/xwYYWGC3uSwKhg4rofvct8tFmL
- PfMsWjRkefmi5YJMXaaUva/WyUmU6s3NbgcTxMgH2TwACHCLvhLTjufuUsoew3o6uYvsThOEam4Y
- YpZ3/ssOlwduavNYqhjfFVOtp531LGzikNOAwcnQ7tb8NbMmN0JD/GsAPUrpgQK+F3enWI/X9pmf
- LN4ZRseSiIMJA4DvQYQ1NAw2q/WrrVNWYCpRjEhfB3AsXJB9OXZvlvA2+UnA5SDuaTGyb9R7N1sg
- BRYfGccH2NcH6fjghLNlhXIgAQiHPHLw8xAMXaqxC5VL6D3srSiELztXcSN2yQoj1FURDGJcQ0Po
- NZINy+XLrHHeGY3GW7jZNEXk+lHIWJv1oiKGsvxSxeQ9dLPgn8NyVomlM7SOunUfTfNaCVMZJ1jH
- Z4dc17ubAEQfMR7B0wBuuTnbzgtc/3m21dqN9uXovD/bYPqszZGoye23q7ArhI0Axtz0yb+R7/7f
- AL1ypFUQG/JTxceySoL0j1RwxlBsbUuNk92yUkt5dymUATV7LkTHBIyyt/JIxbTTyJGJ4uving==
+ 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