From cf2ab0a7e7c8b9285ba213d0f954ace6b5450c72 Mon Sep 17 00:00:00 2001 From: yabwon Date: Sat, 3 Oct 2020 22:54:35 +0200 Subject: [PATCH] BasePlus, version 0.7 BasePlus, version 0.7: - documentation updated - new macro `%symdelGlobal()` added --- README.md | 5 +- packages/README.md | 14 +- packages/SHA256_for_packages.txt | 3 + packages/baseplus.md | 2156 ++++++++++++++++++++++++++++++ packages/baseplus.zip | Bin 34378 -> 43636 bytes 5 files changed, 2171 insertions(+), 7 deletions(-) create mode 100644 packages/baseplus.md diff --git a/README.md b/README.md index 0d3e84c..5058ef5 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ SHA256 digest for macroArray: 53C248E1DE3268946C9CEC7E77BC222F652FBB006D9317BE36 [Documentation for macroArray](https://github.com/yabwon/SAS_PACKAGES/blob/master/packages/macroarray.md "Documentation for macroArray") -- **BasePlus**\[0.62\] adds a bunch of functionalities I am missing in BASE SAS, such as: +- **BasePlus**\[0.7\] adds a bunch of functionalities I am missing in BASE SAS, such as: ``` call arrMissToRight(myArray); call arrFillMiss(17, myArray); @@ -118,8 +118,9 @@ format x bool.; %put %getVars(sashelp.class, pattern = ght$, sep = +, varRange = _numeric_); ``` -SHA256 digest for BasePlus: 278621A6D8BBBB791DEA4C215D4261F2CB8F8B76B1397F7FA9B2E4219E77CB5A +SHA256 digest for BasePlus: 66E966489F4C183CA75FC32D3AF581FEC20FC9C5FF0C36E4DDC5A14BBDA82EAB +[Documentation for BasePlus](https://github.com/yabwon/SAS_PACKAGES/blob/master/packages/baseplus.md "Documentation for BasePlus") - **dynMacroArray**\[0.2\], set of macros (wrappers for a hash table) emulating dynamic array in the data step (macro predecessor of DFA) diff --git a/packages/README.md b/packages/README.md index 5ace517..48f6b7b 100644 --- a/packages/README.md +++ b/packages/README.md @@ -3,6 +3,7 @@ To get started with SAS Packages try this [**`Getting Started with SAS Packages` ## Available packages: Currently the following packages are available: +--- - **SQLinDS**\[2.2\], based on Mike Rhoads' article *Use the Full Power of SAS in Your Function-Style Macros*. The package allows to write SQL queries in the data step, e.g. ``` @@ -19,7 +20,7 @@ run; SHA256 digest for SQLinDS: B280D0B72DB77001ADAAE9C1612B67AD30C2C672371B27F1ACB12016C7A1363D [Documentation for SQLinDS](https://github.com/yabwon/SAS_PACKAGES/blob/master/packages/sqlinds.md "Documentation for SQLinDS") - +--- - **DFA** (Dynamic Function Arrays)\[0.2\], contains set of macros and FCMP functions which implement: a dynamically allocated array, a stack, a fifo queue, an ordered stack, and a priority queue, run `%helpPackage(DFA,createDFArray)` to find examples. ``` @@ -49,7 +50,7 @@ data _null_; run; ``` SHA256 digest for DFA: BB8768E977D62429368CFF2E5338A6553C35C998AEC09AF24088BA713BB54DDA - +--- - **macroArray**\[0.5\], implementation of an array concept in a macro language, e.g. ``` @@ -73,8 +74,9 @@ SHA256 digest for DFA: BB8768E977D62429368CFF2E5338A6553C35C998AEC09AF24088BA713 SHA256 digest for macroArray: 53C248E1DE3268946C9CEC7E77BC222F652FBB006D9317BE36B86410DA31AE35 [Documentation for macroArray](https://github.com/yabwon/SAS_PACKAGES/blob/master/packages/macroarray.md "Documentation for macroArray") +--- -- **BasePlus**\[0.62\] adds a bunch of functionalities I am missing in BASE SAS, such as: +- **BasePlus**\[0.7\] adds a bunch of functionalities I am missing in BASE SAS, such as: ``` call arrMissToRight(myArray); call arrFillMiss(17, myArray); @@ -88,9 +90,11 @@ format x bool.; %put %getVars(sashelp.class, pattern = ght$, sep = +, varRange = _numeric_); ``` -SHA256 digest for BasePlus: 278621A6D8BBBB791DEA4C215D4261F2CB8F8B76B1397F7FA9B2E4219E77CB5A +SHA256 digest for BasePlus: 66E966489F4C183CA75FC32D3AF581FEC20FC9C5FF0C36E4DDC5A14BBDA82EAB +[Documentation for BasePlus](https://github.com/yabwon/SAS_PACKAGES/blob/master/packages/baseplus.md "Documentation for BasePlus") +--- - **dynMacroArray**\[0.2\], set of macros (wrappers for a hash table) emulating dynamic array in the data step (macro predecessor of DFA) SHA256 digest for dynMacroArray: 066186B94B2976167C797C6A6E6217E361E8DEB10F2AB81906E0A325E5243084 - +--- diff --git a/packages/SHA256_for_packages.txt b/packages/SHA256_for_packages.txt index c74278c..2ec79a7 100644 --- a/packages/SHA256_for_packages.txt +++ b/packages/SHA256_for_packages.txt @@ -1,3 +1,6 @@ +/* 20201003 */ +BasePlus: 66E966489F4C183CA75FC32D3AF581FEC20FC9C5FF0C36E4DDC5A14BBDA82EAB + /* 20200914 */ macroArray: 53C248E1DE3268946C9CEC7E77BC222F652FBB006D9317BE36B86410DA31AE35 SQLinDS: B280D0B72DB77001ADAAE9C1612B67AD30C2C672371B27F1ACB12016C7A1363D diff --git a/packages/baseplus.md b/packages/baseplus.md new file mode 100644 index 0000000..fe94646 --- /dev/null +++ b/packages/baseplus.md @@ -0,0 +1,2156 @@ +- [The BasePlus package [ver. 0.7]](#baseplus-package) +- [Content description](#content-description) + * [`%getVars()` macro](#getvars-macro) + * [`%QgetVars()` macro](#qgetvars-macro) + * [`%symdelGlobal()` macro](#symdelglobal-macro) + * [`bool.` format](#bool-format) + * [`boolz.` format](#boolz-format) + * [`ceil.` format](#ceil-format) + * [`floor.` format](#floor-format) + * [`int.` format](#int-format) + * [`arrFill()` subroutine](#arrfill-subroutine) + * [`arrFillC()` subroutine](#arrfillc-subroutine) + * [`arrMissFill()` subroutine](#arrmissfill-subroutine) + * [`arrMissFillC()` subroutine](#arrmissfillc-subroutine) + * [`arrMissToLeft()` subroutine](#arrmisstoleft-subroutine) + * [`arrMissToLeftC()` subroutine](#arrmisstoleftc-subroutine) + * [`arrMissToRight()` subroutine](#arrmisstoright-subroutine) + * [`arrMissToRightC()` subroutine](#arrmisstorightc-subroutine) + * [`catXFc()` function](#catxfc-function) + * [`catXFi()` function](#catxfi-function) + * [`catXFj()` function](#catxfj-function) + * [`catXFn()` function](#catxfn-function) + * [`delDataset()` function](#deldataset-function) + * [`qsortInCbyProcProto()` proto function](#qsortincbyprocproto-proto-function) + * [`fromMissingToNumberBS()` function](#frommissingtonumberbs-function) + * [`fromNumberToMissing()` function](#fromnumbertomissing-function) + * [`quickSort4NotMiss()` subroutine](#quicksort4notmiss-subroutine) + * [`quickSortHash()` subroutine](#quicksorthash-subroutine) + * [`quickSortHashSDDV()` subroutine](#quicksorthashsddv-subroutine) + * [`quickSortLight()` subroutine](#quicksortlight-subroutine) + * [License](#license) + +--- + +# The BasePlus package [ver. 0.7] ############################################### + +The **BasePlus** package implements useful +functions and functionalities I miss in the BASE SAS. + +It is inspired by various people, e.g. +- at the SAS-L discussion list +- at the communities.sas.com (SASware Ballot Ideas) +- etc. + +Kudos to all who inspired me to generate this package: +*Mark Keintz*, +*Paul Dorfman*, +*Richard DeVenezia*, +*Christian Graffeuille*. + +--- + +### BASIC EXAMPLES AND USECASES: #################################################### + +**Example 1**: One-dimensional array functions. + Array parameters to subroutine + calls must be 1-based. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + data _null_; + array X[4] _temporary_ (. 1 . 2); + + call arrMissToRight(X); + do i = 1 to 4; + put X[i]= @; + end; + put; + + call arrFillMiss(17, X); + do i = 1 to 4; + put X[i]= @; + end; + put; + + call arrFill(42, X); + do i = 1 to 4; + put X[i]= @; + end; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**Example 2**: Delete dataset by name. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + data toDrop; + x = 17; + run; + data _null_; + p = delDataset("toDrop"); + put p=; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**Example 3**: Strings concatenation with format. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + data test; + x = 1 ; y = . ; z = 3 ; + t = "t"; u = " "; v = "v"; + + array a[*] x y z; + array b[*] t u v; + + length s1 s2 s3 s4 $ 17; + s1 = catXFn("z5.", "#", A); + s2 = catXFi("z5.", "#", A); + s3 = catXFc("upcase.", "*", B); + s4 = catXFj("upcase.", "*", B); + + put (_all_) (=); + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Example 4**: Useful formats. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + data _null_; + input x @@; + put @1 x= @11 x= bool. @21 x= int. @31 x= ceil. @41 x= floor.; + cards; + . ._ .A -10 -3.14 0 3.14 10 + ; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Example 5**: Getting variables names from datasets. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %put *%getVars(sashelp.class + ,pattern = ght$ + ,sep = + + ,varRange = _numeric_)*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Example 6**: Quick sort as an alternative to call sortn() +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + data _null_; + array test[25000000] _temporary_ ; + + t = time(); + call streaminit(123); + do _N_ = 25000000 to 1 by -1; + test[_N_] = rand("uniform"); + end; + t = time() - t; + put "Array population time: " t; + + t = time(); + call quickSortLight (test); + t = time()-t; + put "Sorting time: " / t=; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +### Content ################################################################### + +--- + +Package contains: +1. macro getvars +2. macro qgetvars +3. macro symdelglobal +4. format bool +5. format boolz +6. format ceil +7. format floor +8. format int +9. function arrfill +10. function arrfillc +11. function arrmissfill +12. function arrmissfillc +13. function arrmisstoleft +14. function arrmisstoleftc +15. function arrmisstoright +16. function arrmisstorightc +17. function catxfc +18. function catxfi +19. function catxfj +20. function catxfn +21. function deldataset +22. proto qsortincbyprocproto +23. function frommissingtonumberbs +24. function fromnumbertomissing +25. function quicksort4notmiss +26. function quicksorthash +27. function quicksorthashsddv +28. function quicksortlight + +*SAS package generated by generatePackage, version 20201001* + +The SHA256 hash digest for package BasePlus: +`66E966489F4C183CA75FC32D3AF581FEC20FC9C5FF0C36E4DDC5A14BBDA82EAB` + +--- +# Content description ############################################################################################ + +## >>> `%getVars()` macro: <<< ####################### + +The getVars() and QgetVars() macro functions +allow to extract variables names form a dataset +according to a given pattern into a list. + +The getVars() returns unquoted value [by %unquote()]. +The QgetVars() returns quoted value [by %superq()]. + +See examples below for the details. + +The `%getVars()` macro executes like a pure macro code. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +%getVars( + ds + <,sep=> + <,pattern=> + <,varRange=> + <,quote=> +) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `ds` - *Required*, the name of the dataset from + which variables are to be taken. + +* `sep = %str( )` - *Optional*, default value `%str( )`, + a variables separator on the created list. + +* `pattern = .*` - *Optional*, default value `.*` (i.e. any text), + a variable name regexp pattern, case INSENSITIVE! + +* `varRange = _all_` - *Optional*, default value `_all_`, + a named range list of variables. + +* `quote =` - *Optional*, default value is blank, a quotation + symbol to be used around values. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** A list of all variables from the + sashelp.class dataset: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %put *%getVars(sashelp.class)*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** A list of all variables from the + sashelp.class dataset separated + by backslash: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %let x = %getVars(sashelp.class, sep=\); + %put &=x; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 3.** Use of regular expressions: + a) A list of variables which name contains "i" or "a" +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %put *%getVars(sashelp.class, pattern=i|a)*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + b) A list of variables which name starts with "w" +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %put *%getVars(sashelp.class, pattern=^w)*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + c) A list of variables which name ends with "ght" +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %put *%getVars(sashelp.class, pattern=ght$)*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 4.** A list of numeric variables which name + starts with "w" or "h" or ends with "x" +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %put *%getVars(sashelp.class, sep=+, pattern=^(w|h)|x$, varRange=_numeric_)*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 5.** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + data test; + array x[30]; + array y[30] $ ; + array z[30]; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + a) A list of variables separated by a comma: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %put *%getVars(test, sep=%str(,))*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + b) A list of variables separated by a comma + with suffix 5 or 7: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %put *%getVars(test, sep=%str(,), pattern=(5|7)$)*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + c) A list of variables separated by a comma + with suffix 5 or 7 from a given variables range: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %put *%getVars(test, sep=%str(,), varRange=x10-numeric-z22 y6-y26, pattern=(5|7)$)*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 6.** Case of quotes and special characters + when the quote= parameter is _not_ used: + + a) one single or double qiote: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %put *%bquote(%getVars(sashelp.class, sep=%str(%")))*; + %put *%bquote(%getVars(sashelp.class, sep=%str(%')))*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + b) two single or double qiotes: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %put *"%bquote(%getVars(sashelp.class,sep=""))"*; + %put *%str(%')%bquote(%getVars(sashelp.class,sep=''))%str(%')*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + c) coma separated double quote list: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %put *"%getVars(sashelp.class,sep=%str(", "))"*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + d) coma separated single quote list: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %put *%str(%')%getVars(sashelp.class,sep=', ')%str(%')*; + %let x = %str(%')%getVars(sashelp.class,sep=', ')%str(%'); + + %put *%str(%')%QgetVars(sashelp.class,sep=', ')%str(%')*; + %let y = %str(%')%QgetVars(sashelp.class,sep=', ')%str(%'); + %let z = %unquote(&y.); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + e) ampersand (&) as a separator [compare behaviour]: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %put *%getVars(sashelp.class,sep=&)*; + %let x = %getVars(sashelp.class,sep=&); + + %put *%getVars(sashelp.class,sep=%str( & ))*; + %let x = %getVars(sashelp.class,sep=%str( & )); + + %put *%QgetVars(sashelp.class,sep=&)*; + %let y = %QgetVars(sashelp.class,sep=&); + %let z = %unquote(&y.); + + %put *%QgetVars(sashelp.class,sep=%str( & ))*; + %let y = %QgetVars(sashelp.class,sep=%str( & )); + %let z = %unquote(&y.); + + %put *%getVars(sashelp.class,sep=&)*; + %let x = %getVars(sashelp.class,sep=&); + + %put *%getVars(sashelp.class,sep=%str( & ))*; + %let x = %getVars(sashelp.class,sep=%str( & )); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + f) percent (%) as a separator [compare behaviour]: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %put *%QgetVars(sashelp.class,sep=%)*; + %let y = %QgetVars(sashelp.class,sep=%); + %let z = %unquote(&y.); + + %put *%QgetVars(sashelp.class,sep=%str( % ))*; + %let y = %QgetVars(sashelp.class,sep=%str( % )); + %let z = %unquote(&y.); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 7.** Case of quotes and special characters + when the quote= parameter is used: + +a) one single or double qiote: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %put *%getVars(sashelp.class, quote=%str(%"))*; + %put *%getVars(sashelp.class, quote=%str(%'))*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + b) two single or double quotes: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %* this gives an error: ; + %* %put *%getVars(sashelp.class,quote="")*; + %* %put *%getVars(sashelp.class,quote='')*; + + %* this does not give an error: ; + %put *%QgetVars(sashelp.class,quote="")*; + %put *%QgetVars(sashelp.class,quote='')*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + c) coma separated double quote list: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %put *%getVars(sashelp.class,sep=%str(,),quote=%str(%"))*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + d) coma separated single quote list: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %let x = %getVars(sashelp.class,sep=%str(,),quote=%str(%')); + %put &=x.; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 8.** Variables that start with `A` and do not end with `GHT`: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +data class; + set sashelp.class; + Aeight = height; +run; + +%put *%getVars(class, pattern = ^A(.*)(?>> `%QgetVars()` macro: <<< ####################### + +The getVars() and QgetVars() macro functions +allow to extract variables names form a dataset +according to a given pattern into a list. + +The getVars() returns unquoted value [by %unquote()]. +The QgetVars() returns quoted value [by %superq()]. + +The `%QgetVars()` macro executes like a pure macro code. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +%QgetVars( + ds + <,sep=> + <,pattern=> + <,varRange=> + <,quote=> +) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `ds` - *Required*, the name of the dataset from + which variables are to be taken. + +* `sep = %str( )` - *Optional*, default value `%str( )`, + a variables separator on the created list. + +* `pattern = .*` - *Optional*, default value `.*` (i.e. any text), + a variable name regexp pattern, case INSENSITIVE! + +* `varRange = _all_` - *Optional*, default value `_all_`, + a named range list of variables. + +* `quote =` - *Optional*, default value is blank, a quotation + symbol to be used around values. + +### EXAMPLES AND USECASES: #################################################### + +See examples in `%getVars()` help for the details. + +--- + +## >>> `%symdelGlobal()` macro: <<< ####################### + +The `%symdelGlobal()` macro deletes all global macrovariables +created by the user. The only exceptions are read only variables +and variables the one which starts with SYS, AF, or FSP. +In that case a warning is printed in the log. + +One temporary global macrovariable `________________98_76_54_32_10_` +and a dataset, in `work` library, named `_%sysfunc(datetime(),hex7.)` +are created and deleted during the process. + +The `%symdelGlobal()` macro executes like a pure macro code. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +%symdelGlobal( + info +) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `info` - *Optional*, default value should be empty, + if set to `NOINFO` or `QUIET` then infos and + warnings about variables deletion are suspended. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Basic use-case one. + Delete global macrovariables, info notes + and warnings are printed in the log. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %let a = 1; + %let b = 2; + %let c = 3; + %let sys_my_var = 11; + %let af_my_var = 22; + %let fsp_my_var = 33; + %global / readonly read_only_x = 1234567890; + + %put _user_; + + %symdelGlobal(); + + %put _user_; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**EXAMPLE 2.** Basic use-case two. + Delete global macrovariables in quite mode + No info notes and warnings are printed in the log. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %let a = 1; + %let b = 2; + %let c = 3; + %let sys_my_var = 11; + %let af_my_var = 22; + %let fsp_my_var = 33; + %global / readonly read_only_x = 1234567890; + + %put _user_; + %put *%symdelGlobal(NOINFO)*; + %put _user_; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +--- + +## >>> `bool.` format: <<< ####################### + +The **bool** format returns: +*zero* for 0 or missing, +*one* for other values. + +### EXAMPLES AND USECASES: #################################################### + +It allows for a %sysevalf()'ish +conversion-type [i.e. `%sysevalf(1.7 & 4.2, boolean)`] +inside the `%sysfunc()` [e.g. `%sysfunc(aFunction(), bool.)`] + +--- + +## >>> `boolz.` format: <<< ####################### + +The **boolz** format returns: +*zero* for 0 or missing, +*one* for other values. + +*Fuzz* value is 0. + +### EXAMPLES AND USECASES: #################################################### + +It allows for a %sysevalf()'ish +conversion-type [i.e. `%sysevalf(1.7 & 4.2, boolean)`] +inside the `%sysfunc()` [e.g. `%sysfunc(aFunction(), boolz.)`] + +--- + +## >>> `ceil.` format: <<< ####################### + +The **ceil** format is a "wrapper" for the `ceil()` function. + +### EXAMPLES AND USECASES: #################################################### + +It allows for a %sysevalf()'ish +conversion-type [i.e. `%sysevalf(1.7 + 4.2, ceil)`] +inside the `%sysfunc()` [e.g. `%sysfunc(aFunction(), ceil.)`] + +--- + +## >>> `floor.` format: <<< ####################### + +The **floor** format is a "wrapper" for the `floor()` function. + +### EXAMPLES AND USECASES: #################################################### + +It allows for a %sysevalf()'ish +conversion-type [i.e. `%sysevalf(1.7 + 4.2, floor)`] +inside the `%sysfunc()` [e.g. `%sysfunc(aFunction(), floor.)`] + +--- + +## >>> `int.` format: <<< ####################### + +The **int** format is a "wrapper" for the `int()` function. + +### EXAMPLES AND USECASES: #################################################### + +It allows for a %sysevalf()'ish +conversion-type [i.e. `%sysevalf(1.7 + 4.2, integer)`] +inside the `%sysfunc()` [e.g. `%sysfunc(aFunction(), int.)`] + +--- + +## >>> `arrFill()` subroutine: <<< ####################### + +The **arrFill()** subroutine is a wrapper +for the Call Fillmatrix() [a special FCMP subroutine]. + +A numeric array is filled with selected numeric value, e.g. + +for array `A = [. . . .]` the subroutine +`call arrFill(42, A)` returns `A = [42 42 42 42]` + +*Caution!* Array parameters to subroutine calls *must* be 1-based. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +call arrFill(N ,A) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `N` - Numeric value. + +2. `A` - Numeric array. + + +### EXAMPLES AND USECASES: #################################################### + +**Example 1.** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +data _null_; + array X[*] a b c; + + put "before: " (_all_) (=); + call arrFill(42, X); + put "after: " (_all_) (=); + +run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `arrFillC()` subroutine: <<< ####################### + +The **arrFillC()** subroutine fills +a character array with selected character value, e.g. + +for array `A = [" ", " ", " "]` the subroutine +`call arrFillC("B", A)` returns `A = ["B", "B", "B"]` + +*Caution!* Array parameters to subroutine calls *must* be 1-based. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +call arrFillC(C ,A) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `C` - Character value. + +2. `A` - Character array. + + +### EXAMPLES AND USECASES: #################################################### + +**Example 1.** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +data _null_; + array X[*] $ a b c; + + put "before: " (_all_) (=); + call arrFillC("ABC", X); + put "after: " (_all_) (=); + +run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `arrMissFill()` subroutine: <<< ####################### + +The **arrMissFill()** subroutine fills +all missing values (i.e. less or equal than `.Z`) +of a numeric array with selected numeric value, e.g. + +for array `A = [1 . . 4]` the subroutine +`call arrMissFill(42, A)` returns `A = [1 42 42 4]` + +*Caution!* Array parameters to subroutine calls *must* be 1-based. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +call arrMissFill(N ,A) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `N` - Numeric value. + +2. `A` - Numeric array. + + +### EXAMPLES AND USECASES: #################################################### + +**Example 1.** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +data have; + input a b c; +cards4; +1 . 3 +. 2 . +. . 3 +;;;; +run; + +data _null_; + set have ; + array X[*] a b c; + + put "before: " (_all_) (=); + call arrMissFill(42, X); + put "after: " (_all_) (=); + +run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `arrMissFillC()` subroutine: <<< ####################### + +The **arrMissFillC()** subroutine fills +all missing values of a character array +with selected character value, e.g. + +for array `A = ["A", " ", "C"]` the subroutine +`call arrMissFillC("B", A)` returns `A = ["A", "B", "C"]` + +*Caution!* Array parameters to subroutine calls *must* be 1-based. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +call arrMissFillC(C, A) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `C` - Character value. + +2. `A` - Character array. + + +### EXAMPLES AND USECASES: #################################################### + +**Example 1.** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +data have; + infile cards dsd dlm="," missover; + input (a b c) (: $ 1.); +cards4; +A, ,C + ,B, + , ,C +;;;; +run; + +data _null_; + set have ; + array X[*] $ a b c; + + put "before: " (_all_) (=); + call arrMissFillC("X", X); + put "after: " (_all_) (=); + +run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `arrMissToLeft()` subroutine: <<< ####################### + +The **arrMissToLeft()** subroutine shifts +all non-missing (i.e. greater than `.Z`) +numeric elements to the right side of an array +and missing values to the left, e.g. + +for array `A = [1 . 2 . 3]` the subroutine +`call arrMissToLeft(A)` returns `A = [. . 1 2 3]` + +All missing values are replaced with the dot (`.`) + +*Caution!* Array parameters to subroutine calls *must* be 1-based. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +call arrMissToLeft(A) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `A` - Numeric array. + + +### EXAMPLES AND USECASES: #################################################### + +**Example 1.** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +data have; + input a b c; +cards4; +1 . 3 +. 2 . +. . 3 +;;;; +run; + +data _null_; + set have ; + array X[*] a b c; + + put "before: " (_all_) (=); + call arrMissToLeft(X); + put "after: " (_all_) (=); + +run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `arrMissToLeftC()` subroutine: <<< ####################### + +The **arrMissToLeftC()** subroutine shifts +all non-missing (i.e. different than empty string) +character elements to the right side of an array +and all missing values to the left, e.g. + +for array `A = ["A", " ", "B", " ", "C"]` the subroutine +`call arrMissToLeftC(A)` returns `A = [" ", " ", "A", "B", "C"]` + +*Caution!* Array parameters to subroutine calls *must* be 1-based. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +call arrMissToLeftC(A) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `A` - Character array. + + +### EXAMPLES AND USECASES: #################################################### + +**Example 1.** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +data have; + infile cards dsd dlm="," missover; + input (a b c) (: $ 1.); +cards4; +A, ,C + ,B, + , ,C +;;;; +run; + +data _null_; + set have ; + array X[*] $ a b c; + + put "before: " (_all_) (=); + call arrMissToLeftC(X); + put "after: " (_all_) (=); + +run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `arrMissToRight()` subroutine: <<< ####################### + +The **arrMissToRight()** subroutine shifts +all non-missing (i.e. greater than `.Z`) +numeric elements to the left side of an array +and missing values to the right, e.g. + +for array `A = [1 . 2 . 3]` the subroutine +`call arrMissToRight(A)` returns `A = [1 2 3 . .]` + +All missing values are replaced with the dot (`.`) + +*Caution!* Array parameters to subroutine calls *must* be 1-based. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +call arrMissToRight(A) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `A` - Numeric array. + + +### EXAMPLES AND USECASES: #################################################### + +**Example 1.** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +data have; + input a b c; +cards4; +1 . 3 +. 2 . +. . 3 +;;;; +run; + +data _null_; + set have ; + array X[*] a b c; + + put "before: " (_all_) (=); + call arrMissToRight(X); + put "after: " (_all_) (=); + +run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `arrMissToRightC()` subroutine: <<< ####################### + +The **arrMissToRightC()** subroutine shifts +all non-missing (i.e. different than empty string) +character elements to the left side of an array +and missing values to the right, e.g. + +for array `A = ["A", " ", "B", " ", "C"]` the subroutine +`call arrMissToRightC(A)` returns `A = ["A", "B", "C", " ", " "]` + +*Caution!* Array parameters to subroutine calls *must* be 1-based. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +call arrMissToRightC(A) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `A` - Character array. + + +### EXAMPLES AND USECASES: #################################################### + +**Example 1.** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +data have; + infile cards dsd dlm="," missover; + input (a b c) (: $ 1.); +cards4; +A, ,C + ,B, + , ,C +;;;; +run; + +data _null_; + set have ; + array X[*] $ a b c; + + put "before: " (_all_) (=); + call arrMissToRightC(X); + put "after: " (_all_) (=); + +run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `catXFc()` function: <<< ####################### + +The **catXFc()** function is a wrapper +of the `catX()` function but with ability +to format character values. + +For array `A = ["a", " ", "c"]` the +`catXFc("upcase.", "*", A)` returns `"A*C"`. + +If format does not handle nulls they are ignored. + +*Caution!* Array parameters to function calls *must* be 1-based. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +catXFc(format, delimiter, A) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `format` - A name of the *character* format to be used. + +2. `delimiter` - A delimiter string to be used. + +3. `A` - Character array + + +### EXAMPLES AND USECASES: #################################################### + +**Example 1.** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +data _null_; + t = "t"; + u = " "; + v = "v"; + + array b[*] t u v; + + length s $ 17; + s = catXFc("upcase.", "*", B); + put (_all_) (=); +run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `catXFi()` function: <<< ####################### + +The **catXFi()** function is a wrapper +of the `catX()` function but with ability +to format numeric values but +IGNORES missing values (i.e. `._`, `.`, `.a`, ..., `.z`). + +For array `A = [0, ., 2]` the +`catXFi("date9.", "#", A)` returns +`"01JAN1960#03JAN1960"` + +*Caution!* Array parameters to function calls *must* be 1-based. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +catXFi(format, delimiter, A) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `format` - A name of the *numeric* format to be used. + +2. `delimiter` - A delimiter string to be used. + +3. `A` - Numeric array + + +### EXAMPLES AND USECASES: #################################################### + +**Example 1.** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +data _null_; + x = 1; + y = .; + z = 3; + + array a[*] x y z; + + length s $ 17; + s = catXFi("z5.", "#", A); + put (_all_) (=); +run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `catXFj()` function: <<< ####################### + +The **catXFj()** function is a wrapper +of the catX() function but with ability +to format character values. + +For array `A = ["a", " ", "c"]` the +`catXFj("upcase.", "*", A)` returns `"A**C"` + +If format does not handle nulls they are +printed as an empty string. + +*Caution!* Array parameters to function calls *must* be 1-based. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +catXFj(format, delimiter, A) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `format` - A name of the *character* format to be used. + +2. `delimiter` - A delimiter string to be used. + +3. `A` - Character array + + +### EXAMPLES AND USECASES: #################################################### + +**Example 1.** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +data _null_; + t = "t"; + u = " "; + v = "v"; + + array b[*] t u v; + + length s $ 17; + s = catXFj("upcase.", "*", B); + put (_all_) (=); +run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `catXFn()` function: <<< ####################### + +The **catXFn()** function is a wrapper +of the `catX()` function but with ability +to format numeric values. + +For array `A = [0, 1, 2]` the +`catXFn("date9.", "#", A)` returns +`"01JAN1960#02JAN1960#03JAN1960"` + +*Caution!* Array parameters to function calls *must* be 1-based. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +catXFn(format, delimiter, A) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `format` - A name of the *numeric* format to be used. + +2. `delimiter` - A delimiter string to be used. + +3. `A` - Numeric array + + +### EXAMPLES AND USECASES: #################################################### + +**Example 1.** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +data _null_; + x = 1; + y = .; + z = 3; + + array a[*] x y z; + + length s $ 17; + s = catXFn("z5.", "#", A); + put (_all_) (=); +run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `delDataset()` function: <<< ####################### + +The **delDataset()** function is a "wrapper" +for the `Fdelete()` function. +`delDataset()` function uses a text string with +a dataset name as an argument. + +Function checks for `*.sas7bdat`, `*.sas7bndx`, +and `*.sas7bvew` files and delete them. +Return code of 0 means dataset was deleted. + +For compound library files are +deleted from _ALL_ locations! + + +*Note:* +Currently only the BASE SAS engine datasets/views are deleted. + +Tested on Windows and Linux. Not tested on Z/OS. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +delDataset(lbds_) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `lbds_` - *Required*, character argument containing + name of the dataset/view to be deleted. + The `_last_` special name is honored. + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + data TEST1 TEST2(index=(x)); + x = 17; + run; + + data TEST3 / view=TEST3; + set test1; + run; + + data _null_; + p = delDataset("WORK.TEST1"); + put p=; + + p = delDataset("TEST2"); + put p=; + + p = delDataset("WORK.TEST3"); + put p=; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**Example 2.** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + data TEST4; + x=42; + run; + data _null_; + p = delDataset("_LAST_"); + put p=; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**Example 3.** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + options dlcreatedir; + libname user "%sysfunc(pathname(work))/user"; + + data TEST5; + x=42; + run; + + data _null_; + p = delDataset("test5"); + put p=; + run; + + libname user clear; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**Example 4.** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + data TEST6; + x=42; + run; + + %put *%sysfunc(delDataset(test6))*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**Example 5.** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + options dlcreatedir; + libname L1 "%sysfunc(pathname(work))/L)1"; + libname L2 "%sysfunc(pathname(work))/L(2"; + libname L3 "%sysfunc(pathname(work))/L'3"; + + data L1.TEST7 L2.TEST7 L3.TEST7; + x=42; + run; + + libname L12 ("%sysfunc(pathname(work))/L(1" "%sysfunc(pathname(work))/L)2"); + libname L1L2 (L2 L3); + + %put *%sysfunc(delDataset(L12.test7))*; + %put *%sysfunc(delDataset(L1L2.test7))*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `qsortInCbyProcProto()` proto function: <<< ####################### + +The **qsortInCbyProcProto()** is external *C* function, +this is the implementation of the *Quick Sort* algorithm. + +The function is used **internally** by +functions in the *BasePlus* package. + +Asumptions: +- smaller subarray is sorted first, +- subarrays of *size < 11* are sorted by *insertion sort*, +- pivot is selected as median of low index value, + high index value, and (low+high)/2 index value. + +`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`
+`!CAUTION! Sorted array CANNOT contains SAS missing values !`
+`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`
+ +### SYNTAX: ################################################################### + +The basic syntax is the following: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +qsortInCbyProcProto(arr, low, high) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `arr` - An array of double type to be sorted. + +2. `low` - An integer low index of starting position (from which the sorting is done). + +3. `high` - An integer high index of ending position (up to which the sorting is done). + + +### REFERENCES: #################################################### + +*Reference 1.* + +Insertion sort for arrays smaller then 11 elements: + +Based on the code from the following WikiBooks page [2020.08.14]: + +[https://pl.wikibooks.org/wiki/Kody_%C5%BAr%C3%B3d%C5%82owe/Sortowanie_przez_wstawianie](https://pl.wikibooks.org/wiki/Kody_%C5%BAr%C3%B3d%C5%82owe/Sortowanie_przez_wstawianie) + + +*Reference 2.* + +Iterative Quick Sort: + +Based on the code from the following pages [2020.08.14]: + +[https://www.geeksforgeeks.org/iterative-quick-sort/](https://www.geeksforgeeks.org/iterative-quick-sort/) + +[https://www.geeksforgeeks.org/c-program-for-iterative-quick-sort/](https://www.geeksforgeeks.org/c-program-for-iterative-quick-sort/) + +--- + +## >>> `fromMissingToNumberBS()` function: <<< ####################### + +The **fromMissingToNumberBS()** function +gets numeric missing value or a number +as an argument and returns an integer +from 1 to 29. + +For a numeric missing argument +the returned values are: +- 1 for `._` +- 2 for `.` +- 3 for `.a` +- ... +- 28 for `.z` and +- 29 for *all other*. + +The function is used **internally** by +functions in the *BasePlus* package. + +For *missing value arguments* the function +is an inverse of the `fromNumberToMissing()` function. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +fromMissingToNumberBS(x) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `x` - A numeric missing value or a number. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + data _null_; + do x = ._, ., .a, .b, .c, 42; + y = fromMissingToNumberBS(x); + put x= y=; + end; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `fromNumberToMissing()` function: <<< ####################### + +The **fromNumberToMissing()** function +gets a number as an argument and returns +a numeric missing value or zero. + +For a numeric argument +the returned values are: +- `._` for 1 +- `.` for 2 +- `.a` for 3 +- ... +- `.z` for 28 and +- `0` for *all other*. + +The function is used **internally** by +functions in the *BasePlus* package. + +For arguments 1,2,3, ..., and 28 the function +is an inverse of the `fromMissingToNumberBS()` function. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +fromNumberToMissing(x) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `x` - A numeric value. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + data _null_; + do x = 1 to 29; + y = fromNumberToMissing(x); + put x= y=; + end; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `quickSort4NotMiss()` subroutine: <<< ####################### + +The **quickSort4NotMiss()** subroutine is an alternative to the +`CALL SORTN()` subroutine for 1-based big arrays (i.e. `> 10'000'000` elements) +when memory used by `call sortn()` may be an issue. +For smaller arrays the memory footprint is not significant. + +The subroutine is based on an iterative quick sort algorithm +implemented in the `qsortInCbyProcProto()` *C* prototype function. + + +**Caution 1!** Array _CANNOT_ contains missing values! + +**Caution 2!** Array parameters to subroutine calls must be 1-based. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +call quickSort4NotMiss(A) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `A` - Argument is a 1-based array of NOT missing numeric values. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** For session with 8GB of RAM, + array of size 250'000'000 with values in range + from 0 to 99'999'999 and _NO_ missing values. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %let size = 250000000; + options fullstimer; + + data _null_; + array test[&size.] _temporary_ ; + + t = time(); + call streaminit(123); + do _N_ = &size. to 1 by -1; + test[_N_] = int(100000000*rand("uniform")); + end; + t = time() - t; + put "Array population time: " t; + + put "First 50 elements before sorting:"; + do _N_ = 1 to 20; + put test[_N_] = @; + end; + + t = time(); + call quickSort4NotMiss (test); + t = time()-t; + put "Sorting time: " / t=; + + put; put "First 50 elements after sorting:"; + do _N_ = 1 to 20; + put test[_N_] = @; + end; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**Example 2.** Resources comparison for + session with 8GB of RAM. + + Array of size 250'000'000 with random values + from 0 to 999'999'999 and _NO_ missing values. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + Array: + Population time 8.82s + memory 1'953'470.62k + OS Memory 1'977'436.00k + + Call quickSort4NotMiss: + Sorting time 66.92s + Memory 1'954'683.06k + OS Memory 1'977'436.00k + + Call quickSortLight: + Sorting time 70.98s + Memory 1'955'479.71k + OS Memory 1'977'436.00k +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `quickSortHash()` subroutine: <<< ####################### + +The **quickSortHash()** subroutine is an alternative to the +`CALL SORTN()` subroutine for 1-based big arrays (i.e. `> 10'000'000` elements) +when memory used by `call sortn()` may be an issue. +For smaller arrays the memory footprint is not significant. + +The subroutine is based on an iterative quick sort algorithm +implemented in the `qsortInCbyProcProto()` *C* prototype function. + +The number of "sparse distinct data values" is set to `100'000` to +use the hash sort instead of the quick sort. + E.g. when number of unique values for sorting is less then + 100'000 then an ordered hash table is used to store the data + and their count and sort them. + +*Caution!* Array parameters to subroutine calls *must* be 1-based. + +*Note!* Due to improper memory reporting/releasing for hash + tables in FCMP procedure the reported memory used after running + the function may not be in line with the RAM memory required + for processing. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +call quickSortHash(A) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `A` - Argument is a 1-based array of numeric values. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** For session with 8GB of RAM + Array of size 250'000'000 with values in range + from 0 to 99'999'999 and around 10% of various + missing values. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %let size = 250000000; + options fullstimer; + + data _null_; + array test[&size.] _temporary_ ; + + array m[0:27] _temporary_ + (._ . .A .B .C .D .E .F .G .H .I .J .K .L + .M .N .O .P .Q .R .S .T .U .V .W .X .Y .Z); + + t = time(); + call streaminit(123); + do _N_ = &size. to 1 by -1; + _I_ + 1; + if rand("uniform") > 0.1 then test[_I_] = int(100000000*rand("uniform")); + else test[_I_] = m[mod(_N_,28)]; + end; + t = time() - t; + put "Array population time: " t; + + put "First 50 elements before sorting:"; + do _N_ = 1 to 20; + put test[_N_] = @; + end; + + t = time(); + call quickSortHash (test); + t = time()-t; + put "Sorting time: " / t=; + + put; put "First 50 elements after sorting:"; + do _N_ = 1 to 20; + put test[_N_] = @; + end; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**Example 2.** For session with 8GB of RAM + Array of size 250'000'000 with values in range + from 0 to 9'999 and around 10% of various + missing values. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %let size = 250000000; + options fullstimer; + + data _null_; + array test[&size.] _temporary_ ; + + array m[0:27] _temporary_ + (._ . .A .B .C .D .E .F .G .H .I .J .K .L + .M .N .O .P .Q .R .S .T .U .V .W .X .Y .Z); + + t = time(); + call streaminit(123); + do _N_ = &size. to 1 by -1; + _I_ + 1; + if rand("uniform") > 0.1 then test[_I_] = int(10000*rand("uniform")); + else test[_I_] = m[mod(_N_,28)]; + end; + t = time() - t; + put "Array population time: " t; + + put "First 50 elements before sorting:"; + do _N_ = 1 to 20; + put test[_N_] = @; + end; + + t = time(); + call quickSortHash (test); + t = time()-t; + put "Sorting time: " / t=; + + put; put "First 50 elements after sorting:"; + do _N_ = 1 to 20; + put test[_N_] = @; + end; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**Example 3.** Resources comparison for + session with 8GB of RAM + + A) Array of size 10'000'000 with + random values from 0 to 9'999 range (sparse) + and around 10% of missing data. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + Array: + Population time 0.61s + Memory 78'468.50k + OS Memory 101'668.00k + + Call sortn: + Sorting time 0.87s + Memory 1'120'261.53k + OS Memory 1'244'968.00k + + Call quickSortHash: + Sorting time 6.76s + Memory 1'222'242.75k(*) + OS Memory 1'402'920.00k(*) + + Call quickSortLight: + Sorting time 23.45s + Memory 80'527.75k + OS Memory 101'924.00k +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + B) Array of size 10'000'000 with + random values from 0 to 99'999'999 range (dense) + and around 10% of missing data. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + Array: + Population time 0.6s + Memory 78'463.65k + OS Memory 101'924.00k + + Call sortn: + Sorting time 1.51s + Memory 1'120'253.53k + OS Memory 1'244'968.00k + + Call quickSortHash: + Sorting time 6.28s + Memory 1'222'241.93k(*) + OS Memory 1'402'920.00k(*) + + Call quickSortLight: + Sorting time 0.78s + Memory 80'669.28k + OS Memory 102'436.00k +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + C) Array of size 250'000'000 with + random values from 0 to 999'999'999 range (dense) + and around 10% of missing data. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + Array: + Population time 15.34s + memory 1'953'471.81k + OS Memory 1'977'436.00k + + Call sortn: + FATAL: Insufficient memory to execute DATA step program. + Aborted during the COMPILATION phase. + ERROR: The SAS System stopped processing this step + because of insufficient memory. + + Call quickSortHash: + Sorting time 124.68s + Memory 7'573'720.34k(*) + OS Memory 8'388'448.00k(*) + + Call quickSortLight: + Sorting time 72.41s + Memory 1'955'520.78k + OS Memory 1'977'180.00k +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + D) Array of size 250'000'000 with + random values from 0 to 99'999 range (sparse) + and around 10% of missing data. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + Array: + Population time 16.07 + Memory 1'953'469.78k + OS Memory 1'977'180.00k + + Call sortn: + FATAL: Insufficient memory to execute DATA step program. + Aborted during the COMPILATION phase. + ERROR: The SAS System stopped processing this step + because of insufficient memory. + + Call quickSortHash: + Sorting time 123.5s + Memory 7'573'722.03k + OS Memory 8'388'448.00k + + Call quickSortLight: + Sorting time 1'338.25s + Memory 1'955'529.90k + OS Memory 1'977'436.00k +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +(*) When using hash tables in `Proc FCMP` the RAM + usage is not indicated properly. The memory + allocation is reported up to the session limit + and then reused if needed. The really required + memory is in fact much less then reported. + +--- + +## >>> `quickSortHashSDDV()` subroutine: <<< ####################### + +The **quickSortHashSDDV()** subroutine is an alternative to the +`CALL SORTN()` subroutine for 1-based big arrays (i.e. `> 10'000'000` elements) +when memory used by `call sortn()` may be an issue. +For smaller arrays the memory footprint is not significant. + +The subroutine is based on an iterative quick sort algorithm +implemented in the `qsortInCbyProcProto()` *C* prototype function. + +The number of "sparse distinct data values" (argument `SDDV`) may +be adjusted to use the hash sort instead of the quick sort. + E.g. when number of unique values for sorting is less then + some *N* then an ordered hash table is used to store the data + and their count and sort them. + +*Caution!* Array parameters to subroutine calls *must* be 1-based. + +*Note!* Due to improper memory reporting/releasing for hash + tables in FCMP procedure the report memory used after running + the function may not be in line with the RAM memory required + for processing. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +call quickSortHashSDDV(A, SDDV) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `A` - Argument is a 1-based array of numeric values. + +2. `SDDV` - A number of distinct data values, e.g. 100'000. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** For session with 8GB of RAM + Array of size 250'000'000 with values in range + from 0 to 99'999'999 and around 10% of various + missing values. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %let size = 250000000; + options fullstimer; + + data _null_; + array test[&size.] _temporary_ ; + + array m[0:27] _temporary_ + (._ . .A .B .C .D .E .F .G .H .I .J .K .L + .M .N .O .P .Q .R .S .T .U .V .W .X .Y .Z); + + t = time(); + call streaminit(123); + do _N_ = &size. to 1 by -1; + _I_ + 1; + if rand("uniform") > 0.1 then test[_I_] = int(100000000*rand("uniform")); + else test[_I_] = m[mod(_N_,28)]; + end; + t = time() - t; + put "Array population time: " t; + + put "First 50 elements before sorting:"; + do _N_ = 1 to 20; + put test[_N_] = @; + end; + + t = time(); + call quickSortHashSDDV (test, 2e4); + t = time()-t; + put "Sorting time: " / t=; + + put; put "First 50 elements after sorting:"; + do _N_ = 1 to 20; + put test[_N_] = @; + end; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**Example 2.** For session with 8GB of RAM + Array of size 250'000'000 with values in range + from 0 to 9'999 and around 10% of various + missing values. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %let size = 250000000; + options fullstimer; + + data _null_; + array test[&size.] _temporary_ ; + + array m[0:27] _temporary_ + (._ . .A .B .C .D .E .F .G .H .I .J .K .L + .M .N .O .P .Q .R .S .T .U .V .W .X .Y .Z); + + t = time(); + call streaminit(123); + do _N_ = &size. to 1 by -1; + _I_ + 1; + if rand("uniform") > 0.1 then test[_I_] = int(10000*rand("uniform")); + else test[_I_] = m[mod(_N_,28)]; + end; + t = time() - t; + put "Array population time: " t; + + put "First 50 elements before sorting:"; + do _N_ = 1 to 20; + put test[_N_] = @; + end; + + t = time(); + call quickSortHashSDDV (test, 2e4); + t = time()-t; + put "Sorting time: " / t=; + + put; put "First 50 elements after sorting:"; + do _N_ = 1 to 20; + put test[_N_] = @; + end; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `quickSortLight()` subroutine: <<< ####################### + +The **quickSortLight()** subroutine is an alternative to the +`CALL SORTN()` subroutine for 1-based big arrays (i.e. `> 10'000'000` elements) +when memory used by `call sortn()` may be an issue. +For smaller arrays the memory footprint is not significant. + +The subroutine is based on an iterative quick sort algorithm +implemented in the `qsortInCbyProcProto()` *C* prototype function. + +*Caution!* Array parameters to subroutine calls *must* be 1-based. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +call quickSortLight(A) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `A` - Argument is a 1-based array of numeric values. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** For session with 8GB of RAM + Array of size 250'000'000 with values in range + from 0 to 99'999'999 and around 10% of various + missing values. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %let size = 250000000; + options fullstimer; + + data _null_; + array test[&size.] _temporary_ ; + + array m[0:27] _temporary_ + (._ . .A .B .C .D .E .F .G .H .I .J .K .L + .M .N .O .P .Q .R .S .T .U .V .W .X .Y .Z); + + t = time(); + call streaminit(123); + do _N_ = &size. to 1 by -1; + _I_ + 1; + if rand("uniform") > 0.1 then test[_I_] = int(100000000*rand("uniform")); + else test[_I_] = m[mod(_N_,28)]; + end; + t = time() - t; + put "Array population time: " t; + + put "First 50 elements before sorting:"; + do _N_ = 1 to 20; + put test[_N_] = @; + end; + + t = time(); + call quickSortLight (test); + t = time()-t; + put "Sorting time: " / t=; + + put; put "First 50 elements after sorting:"; + do _N_ = 1 to 20; + put test[_N_] = @; + end; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**Example 2.** Resources comparison for + session with 8GB of RAM. + + Array of size 250'000'000 with random values + from 0 to 999'999'999 and _NO_ missing values. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + Array: + Population time 8.82s + memory 1'953'470.62k + OS Memory 1'977'436.00k + + Call quickSort4NotMiss: + Sorting time 66.92s + Memory 1'954'683.06k + OS Memory 1'977'436.00k + + Call quickSortLight: + Sorting time 70.98s + Memory 1'955'479.71k + OS Memory 1'977'436.00k +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Example 3.** Resources comparison for + session with 8GB of RAM + + A) Array of size 10'000'000 with + random values from 0 to 9'999 range (sparse) + and around 10% of missing data. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + Array: + Population time 0.61s + Memory 78'468.50k + OS Memory 101'668.00k + + Call sortn: + Sorting time 0.87s + Memory 1'120'261.53k + OS Memory 1'244'968.00k + + Call quickSortHash: + Sorting time 6.76s + Memory 1'222'242.75k(*) + OS Memory 1'402'920.00k(*) + + Call quickSortLight: + Sorting time 23.45s + Memory 80'527.75k + OS Memory 101'924.00k +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + B) Array of size 10'000'000 with + random values from 0 to 99'999'999 range (dense) + and around 10% of missing data. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + Array: + Population time 0.6s + Memory 78'463.65k + OS Memory 101'924.00k + + Call sortn: + Sorting time 1.51s + Memory 1'120'253.53k + OS Memory 1'244'968.00k + + Call quickSortHash: + Sorting time 6.28s + Memory 1'222'241.93k(*) + OS Memory 1'402'920.00k(*) + + Call quickSortLight: + Sorting time 0.78s + Memory 80'669.28k + OS Memory 102'436.00k +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + C) Array of size 250'000'000 with + random values from 0 to 999'999'999 range (dense) + and around 10% of missing data. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + Array: + Population time 15.34s + memory 1'953'471.81k + OS Memory 1'977'436.00k + + Call sortn: + FATAL: Insufficient memory to execute DATA step program. + Aborted during the COMPILATION phase. + ERROR: The SAS System stopped processing this step + because of insufficient memory. + + Call quickSortHash: + Sorting time 124.68s + Memory 7'573'720.34k(*) + OS Memory 8'388'448.00k(*) + + Call quickSortLight: + Sorting time 72.41s + Memory 1'955'520.78k + OS Memory 1'977'180.00k +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + D) Array of size 250'000'000 with + random values from 0 to 99'999 range (sparse) + and around 10% of missing data. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + Array: + Population time 16.07 + Memory 1'953'469.78k + OS Memory 1'977'180.00k + + Call sortn: + FATAL: Insufficient memory to execute DATA step program. + Aborted during the COMPILATION phase. + ERROR: The SAS System stopped processing this step + because of insufficient memory. + + Call quickSortHash: + Sorting time 123.5s + Memory 7'573'722.03k + OS Memory 8'388'448.00k + + Call quickSortLight: + Sorting time 1'338.25s + Memory 1'955'529.90k + OS Memory 1'977'436.00k +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +(*) When using hash tables in `Proc FCMP` the RAM + usage is not indicated properly. The memory + allocation is reported up to the session limit + and then reused if needed. The really required + memory is in fact much less then reported. + +--- + +## License #################################################################### + +Copyright (c) 2020 Bartosz Jablonski + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +--- diff --git a/packages/baseplus.zip b/packages/baseplus.zip index 17b771b077db23f1add2808fada327fa82bdb93e..5c7ba5ea8685c249a0186fea7ee0f7f70af31b42 100644 GIT binary patch delta 39985 zcma&tV{oNyn=atk=8Dm=)p63X?T&5RE4FRh9ox2T+v=o~?0&zQshV$Q@2dT4Rjr@v zIqE#`>$$Hr9tHNe2nJA)28X}^0Re#liEa{BJP`zTpFx0t&?CnKsDWMTHg+5AD4({y zUwe6tepRBDe-d2kE=c7rF?18zBC|;aPymf08`fk>->504LqDFk#_pw;5wtp%;0$xe z4hVkpj&v;8$KO+E*Wc#IdbFv)$a0#7=nbb+r-t+ob24Q)a9$&LGMyq258>!DO&fE9 zfA@!lQ==L)G=Suog$AYwkVc_8!U@%2r%30vv6rm|1@79kEskBvSlpLXv&i4l;*CgU zc!6FAL=z?PW>Cls3YH~EwK-1*HNMV#Jw>phI$GGjoO~FxEhgqi*o(`y66Sm=G0f?; zaB#Mr>mj}8GUzj1Y9nUue8qKjkt;xY#xdLlZE&rCX8%UoW(LO5?b(<`NkJ6pQE}bu zbQ##jw0k5JG3F@ATtZ5Sk-t6XJO94Wzbw>$UF2#eOqGfkihB;SALPbbOD+AWxtCfC|AWK+x8H z>}4YXjEoEY*auFkn4`8BbVtYjEJDzLECWGiZCX?8w{Rb4=1&v#pjdwW_I;ac;pH~o z2!_w&-48sKE;7IJk<7r6%aObvX93muw^`#o*{b8Kaf!o8faGi5nsGlX>c}R%U-QAc zuiX1KVgAw&|83cmKlfD}e$%4ZHPBt?gZ8t3)YMiMJ#~RM@u-msPn{Ir37fGHES8S* zeil<$R#=Fn5Hq=QHE}G_BxZNls3H`2R>?m*C2o^_!|HG)Sd0v!_R5@@C#4IyknRAKVeEKtRUnk9eZ7rK?z3_6=` zWsc87i2#6Pv%{F~&tl9_7N&DGtyTky%!4K>5}YsU1Er%}IBu18FMGh2OLog0J5{s# zr$FBS5mSZCjFCp;v(jDb(1GiLUnP z`2gj$Sx^hF6{=;}A^#9K-g6Coz2P9>PHar#?1Ql<* zLa5>PKH~^C{ip;8#xdDswkj{STk@8to4GZpeD&2HGoqF@uinLow%lD~30w(O2~r7Y zty&ZqV#{63YNqlTw|uC71M)PXud~|bUV)I{pJ*YUVw85dln?-DTS6$&h*j~h)Y-&@ zR3=csLEPO)9MgUySx01&LKhcb@6txCjKSUFV+HlGyQ^JlGH3au@u0)?}C?IIgan?76<#MQ6m;8!;@*X=j@lI zlZO7ORL!6hJC)cfbvxQpHm_&F7QC03iL30*;qO6Ks4+C#whCYA3Sac-dwhUmdZu&v zUn7Oz3@o!wx^#3|EHvAbb@cp9a0`Pxw0L+&b5HojxYZR(8dnS3D)E&UJ&nGbh4%tu zR;riJGbQO>3L{Y&G}np?)yiw$mXvVto=6&Y5=#4>&Jp7@lXTE5p`qFn=k3zO(U;7fF?TPD7Gh#fej_ zcE*6ZX!bd_Pk3Nr6ZwFSA^yy0x%3BTj=OqB`^m^1Jz7VdF*?o&Hr-@StNHuL9U|NOe^=DJ}VAqBE#Pf)Hjq2+0eb z6caROP&B+~*=T%Y9oS;t*!nFeaW_OLw6o`oTUGY2+`3_HoM!QWG1v#>0r_AtC02t+ z=d`cqkDfojq1jG)OeaG3Iyttt?K;LY91ecND@eotx58*Rhsg#5{PPnDWPNs7LV|#Z zkpI&q7$DYm2F8i;&Nzv!@Cd*)RWbsjUe6Ugm@|Nhj@^d<_?atrc3dJSd8HBShQ-R~ zlNlw11bQAh#1?X7kO;AF&d5!w9_5{P05u#Ff@jb3_REC}ad+HRDx+?^SaK5A37^aOdF+-mDv^-vOB2C!f@28m!smPVv;)fG=6CIOF_b6c2W{aO z6@hL`c;7FkJS*3%2?&}pMq+DkLLB>BsjE^lU{hsydvixAq9X8!CcTVznBPWR{JfQ% zH1zohef_;@mZ0sB=YVp#pF=+3dwz~2Z65aevP|hnhFY27)%3Rj=yK~*!##UoMfH*{ zd}TC0zDrLOT49&B!>)2@5JQLuNE&M?lm;obqzbx(Ll@*Y1bkayW`jRSTjTotZDZs9 zcsF*^bC-zCKEFM48^xrUv6fFPGn~1~9X9cAjiRa5hM^Dsm|vD-yHzw;LoF5HsRN&> ziX#w=abVwSDny~L0X^kwG|bMJ>0|Zlw59WJCkI33t2e%9K5y7agI%*j!zwY6l9ODG zCRgL6$iXuA3c!d`{7bu=a^u@+RgWO%?xw2Wr`Z=u-+irA8-9thO{ECmX<+SZ`}{l^ zp*BNumt%s&lG@)$_f`ZhnTqPIJa3kF63t*PrckM$Shz8r>g71gKz0W>*#tZ@K%JNo zIX1A0dAnNLGUYvJpB!rpQqPUGKdtSamX2zNQ2(@0j0Be0OD)pi^ldjd@rYl7l{q(c z)Lo$|m3y`U`PQO6P9%;lwxa#96-=mH!>5zb>HC`R8L$Dg<6=PUen%&0r z?K+v5+_T962sTtt3f2O3G|1?HPd+k)avfc%AD2_JR$6cFPmZ36-1WKjeIk;?UWyhf-Ns? zUchxC+!V;Pb^>xP^*b~z^NWrfoLH6oy9|#UH05B^u9^?0NQtl(W`X_^jH^BuSS|KH zJbB!r2Dr6RG!ijo#1e+eltXM*AeC@)!BBv^74IENYkrrzSgHnYdsmP7FH1DnlQI{6 z?6!Lv3((2&^|XuuFY1uD5|y=Uji4d^dZ2Z%>8TC#ew<+Gki-yvxH&sqX4oNu;+ zrhSVP$E0wMR7odBBX*N-ChXAVOCp=lmJV+j>SvB-Mp-p5wX)Wpux$Hg(PGyk@Lmq# zvPU=kDYan{Fxm_YEO?iE+o@{%NHEZfPA()ll%E$NGz5q`e9PF;2pb^?tp~P*c0g?a zwp8`^wOiIy;ISkBhA-Afn#~W@Zw4Dc+Kh-1DGCvqbQPr^S+-@Eu+1^uQusa|zfy;N z_8VV_K!xhhy1mh^uAiN&);?^Xa+Kg?dzcn_c*Av5=S1v~1>f~5ZHxh6htl2{8z!bg#hfQ{1RAZqI@C?8>F^n8f zh(8QITu_&i02t8zCb-^;<#3}4nhz_u7j7U9j%=Fu0NMeu_^0m4 zM^6>BYZDu(o$`&oer85#u+q^Q^7C8Cm@UTq!9U{#|zjT89=R-mL&k3t1@H(RQZ%;xKCGMe70RLma z(#`wYtDp-@@~GLcL1Z5Q#}^-qT6Zw*(CRRNF%GX^QYsKqlI+s!`9}Vm+&A243~-Fx zOqcM&>mAcsDCa96c^Cv?tNEkZx8CY|o`2laKP|}_gATjWmH)x&9Y*EUNsKFe*{YYt z?C&HVhnEosw~5XGh9y|-2~_LrV+e=vxAoG{tGgx0%E{^1U%fse7M&j;I8(%a~s=5-7WMahkX&}T2>S9t+>&**+nl@bi3s}_ermu{aAOZFu zh!Z;Nz!k_G4kI3+8$m`1;f;YA#T@^Fgsr*<15OAgWgyZkJiO}m6Tez~sI@+{hvOZ5 z^^rNEuFZ=*dnadCIV>hEB#f`b`fzrO8j;_H@p4+V)NT9HIuAm>oRRYWUK9k8seMYV z$LtW14Pe1hiPf}v3>*OLxG}#*g~n|1?x7mZq@8-ywzvj#SoFZB0&~QVX9D9LBySN6 zG+p2Q`d^cnyLr+lEM|KPGiy3Cvo6|}rEHn8#t8ZgfYR9EY7J`Y}K14@G>`!QYe*yE8WZJ%T8 zF-wr*C?s+VsWtpcu~iBeFtreF+BS7N(dSZIMtLn`&dpS;5Z~o4WBo0)DT1~z`m2*!x%V}-0<>1wKaMwSDl4enhzi(VWP6yDQeE5~7~Hp3)X-N8Y7d9FmE)v_=&~!B zghw8qYC1u_0MumM5_XwFvkEB{wdPGQHR9mwK{b5_uzI!gPBFpfr=vLmuqvZydXbBX zk=!U($9UxmI)X?le?F&dh7-1il02o=Lt{tJY%q}*t4*e(PV^5cafyXbez(4b$jhYb z^6B zLEtW>Cl+&2b0{}NSRH70rb}oej+s7UD$E)cHMW!k+f!@yLD$k3??44{Z35xqS-ozRvi7|}na-c3O;N)ogeeOyU#5Q@>LcwHG^cbZ< zWABwc$cfJSk`Mttun^>^ubqtkGvugY&*UhWlztRT9w74LUU6y2400kLsuMh6!wI62 zoTT23PCpI(7c_Z}W~HkoQ_^=5H^0#imG4RJ06z+1LVk$I&{TS%X#G+otq%W2Axc$# zN4|iXhohVA^(8Ov?jTNL$c#+NRZBZ*5*UmIzSxo?59hrI z&O;6;q+ohwQ*d$K-zu6x0_*m_*~#hRp#|68gWxxGzKXr-n`Kj*MS$;m5L>aTORXqy z1+u@)W5&yJR^U1@^`+Qjo%6fi%yWa7$0TCK+iS_eL|4AF``VmiLm(=*(orCOqvyrb z6jbf7pnBr&Iu7=6Sg`K0(_I4xUttLEgi5Hk898(w}3TeECW9FiGVHnR8{jCs;26zb*aW^YdsY~0%oO2oj1voo0B0Ax0ZQfYH zeimm%*1M3&#y|QsUZpxyRfrDn>%VTzJmX`(3fbw`pq9%EsQn2>DgL{%$r|b$Yr62W zQ5Dlfd@)P9dzg1TtD@6{mVWYd0K-(+>z5ZARcwL6GB1h;&{ z&`+9OP?Qsxp>taUw`PE%N}t#4SLw7ll$7R&C10}J%Bj(=9>dbx=%C3$Q0H~*($NVL z&~LYAz-N+?{3Xl20epY;1CprP;W`nvRVE$CY5Y?JQ;prx(PzGERHznxM*ThJW60QD zNLUmuMB>UTJ2K+@sqhVGZ|>Tg8Y0hZ-O`DxXH1c=|2b2=l5Y(ihS74NJ zYzi>4V1%FgT5)1(f9!1k*xZiR=WIW-8UWG@XQ`8ki1Gx|HJoCLhAbTWV3X!7Id2QI za*=SjTp+QrHlF1_N3eb4XUIS}nPP?#ST!U5f#~PerO%_n@Dt&k>M@m_7rJnRZ8n8~ z39A`h38M4HrB49*%QO^05`A2k_SK>i<9Aw$cMY>1L5~ikr=$m{$tdSq6>bG~pV-9V&ad%Cw+(i9+N4CzPTuOIG zwC-h6CaI??F&A^Kn*rz37~RIh_0R7La*MxhRZjV)o$9w$M2>=VlKSy8ztWD%c5F+Z z>lcr{F_!ljn<@S7l|Cny*5SY8%pL?Xj7TgCbh$64k{pexn6MqTrpv9YUY_R8*WLT) z20P~qGs^`o8A|nA*t$@;fq<$3bHFx>}{Jm{;AN0 zXDl%3(qrO(M2HIh5!HYTn85KQu`N$iXB>`I?1Woz(VnAqK~s!GY2G+Ao3JnK10w8>&7YX=eZuZnq${k@ z4e-Yg{Fn+u+EgTzRR42ytxyXzQ2H1>iF0&+h273ly%CZSaZfSOZ=}ft!D%JYDcNJZ z23yx>$p`~c|4CXsezbgOhQj)4&(qFK*;0tyLKK>~z!s^DklH#25mi+m^($41kh?(| z`9XBH0cR5DNhfMqF=!NbSsHA9Xb^f}F_)w7@&M*(dXBk)wqF-1j)@aUM_snENXAJ_ za_P)K!E)VPXI!3uG(RK-NUk0ZXGotCV?L)w^pdid@9;a5&Ub_ zh*ne@ulxNl72>z(w;mN?C|H)+QGH65u~0JZa?R+Xs#fO?^mI_*PmOw&a^fFKv^%C9 zOH}5IQC=2L?OjQp!9SBUl_Gq9;Ra774<6oEYe>}SgpYo|#;A)=re;0Tnv?ila$Y40 zmtsPzsYECGWO6AY)-tBlc)S|%_xlg`bF)k(nZF;%w~EX!@v&uYA&{!dY*B);4haO5 zma>@H;j=O(I2}Mzd}=G_mkW)o0}B0g^h(}l&}uz>5ffsndUiP0cDPM;-XJSZ)M{?* zn3y;5=YXtc1$4NYk(BN(C_Ije5M%5!)mq6Z5fp6lMAFnwoEu9*`a4_iu@7v#lRSU4ORR^d>c8JExIxS;lm{n2twrFmI zDtu<7p*H4d&+Gq(csc@o;Z>d@WDXx=)bdas5%+fH2lvJtlzBwTa5E3a2OAtYpn%-1 z=}zxSY+TCgOVJw`S@mrTPc>Q9*Q4PCJ$ny>KXtZlaO(1AAogWHM@oBIGrGT{0^G~x z^+V0&=NB*&@&Nu?7SGkq)ls@O#u-^%Foieh`yf!-hlrs?WtrI)ymE|t+rcrO?vXRs zH1B)^xNdPl zmg{=CA)f6x+RxC=1#(a`;+KgDdN62W=%1Dv)_GP*RfRL90pdB@;(MAHJ(2{>au_}X zLDBYTPjr~N#W1WliJeM}6OBvKh78u*e+7&#eqOY$#VWQD7zUm4k%*Qj*3t?Rs?liX`F_j>H`2xqQP!(N=YMJKps{Nxh=Q zz;&~GK4EKWwCrj@?Oxb9o^dnrHa6^CU7@ZlV=LY0l3Xeg!HpK5&7xp>x$%<6P}L9K1AZM9#xidg(189LLqEvaXt!NfgC<1+CkUxr|kK={>2 zoG|iOVqLr$ntWk(P?7xnComGV4WLI*^DiLz&Ij{Ow(dYeWT*+Db|K&LZzN5yZD89X z`UQkAyu*U_8P4y&A>HtxmkrOHFW&&0&z?(GYgeVkgb96_ve`LmI7bZX`r@i?>~R5_ z$Z*AN+RQVl<%*)KzbM^EgZX@JQVxhi6h{x#W9-|mrHJ)DTs^klp3HO52_4Coozoui z;}QjaF}o{iZDJnc47QcqZBRDbn()}oFtBakBgbPqwitlqnM2Hd-)8HB*-}6dKrXw)ec~(44L1w<9K5~U z?YT^WUe8A~KPcP75S9#fsapsBx(AMc6gsB5{XDGXyj+(YIQAZ*E5s-+jKm1ZhiSZ$ z8^sa*HH{i(BXNI%aVds(-Qk#246>rU24ekGV{7tCq3U~C?5{Amtz=0>t81PkJ59-$f$g2co*6*LGW?Mh=L$c1c? zO_JxsY09(<%0l4oj|C@5Fh_zH#TaZf1oYcG_ivu0{uu0xwlIbv$&?A!UbpHsVb;hD z>wq=KlTbr<^v8DdR!6|M<}^luH%Rwo<$M)n*y=;gh{7LzL)LiUa1iexG8kbrd6(pRWzIu}(?KCIqbY%y@5 z2%TqXdu@}mM5FwzUyxgEgu=Okzdmt(J6j?_M|~TFlH+1E2vuMcG}>KONC#QF$hUpv zS0GRi>U_0PB1s5u*^0KsiX9h=2fagb^r1b_zXDdvGI9Q7RM{s^ zG1S*grvz0-B}!TqW8N}8V)%J zpFm*L0h@ZGX;*8wL@36QKpVzGIBouYC~A&iBF16K-E26_r_6z_`*@9NQ=jlfc)}^V zP%v98z{bd8RTvovPv7q;%#fQspSq?K!o%af^tr5&XP1E2l|_O~n)->^U|xdPe*fhQ#(i#3XwdSWrL8i-N7zz@ZPtIpd>gOzQ|qIE&Ho!LMPuDqH1 zwf=Tjx^etW&C_nr!4V(~dDH;R&&fY47apj)W#EcCqMI3E5sV?;6?rg zIK!7di|!8A7D}{WYJgFNp6D^jogHa^ZZKLC2&&aLsO*^>iYjPUAZ|y^R{aDu!rM;| z-tSJMYwOyv4aiX(?|SVAkxi`nyj*~{`tA%=^`zgw3$IA{>rArN7<=yu%}R5HLRkepr2 ztR0ky4LbE^V?#@(AoHsk!i^5m68IKVFD~{CF&UC%J}6r|%2+)Q`7*~E@5H6YqxD`= z?RWi0>DCXW7v}-f0=L>_ux3KW7C%H_$mqr3^Aqki$(>pESl5UGVBW0{>8624US#hk zmM0R+p%Rm~tITG*`sEONvDee@(IU4q1yZgSlhnlEV94NC*7$tQ?QQFn-;3r^c^6fSW5<@so6wjE|s$z^=? zSvTGMMjdiff}Pyfh7!6t_mi(;?;g8t3(cv7s-KZMdeS64mr10Kj=nFHSdVfgqq6}oa3?AuCp@O95 z?q$EVXr&(J)((h6zqjA^(Wptt=L#?EdPzCPe_aMa%tW6I)!%Rci;sqHO2;gjr^Wo-!(Dy72_;bzxmGK6b(g z36wDf#2>;>G>YDYklBYU*&*`y4YK25x-SsZPBvf)nu?&+u@Gpbv%Wz8{VkNF0+UA{ zD-I{5 zVnuxxf9NQDu#)tsYK8elD>~UF+$u0%yYG?o#A*78Nq8rI{^j%1`f*GX2rXqOBT|$? z(-Pr*GMf&tw5IecXhF`Imq>wYN2B)d1gX+r56pa+~A#bg*@ zQcTkox!-T7tGpn~2ujPAi$AuYEVSD(gt-Ef0706$822Ie=XbNG^&g=`1Gf-FU^Ocs z#LRUcyVo8Qw@ackANS%%>h9|+GSjVk?Ff307309Z!cz<*!1EKGmZJqC+2)`o=hwh( z)OL;-liZ~HMlO5M${%+03`&C>P*U8o^7ktbDCO#uT`=y)suR*2^|J9>fp`z}KNDEm z?dXUGQHleQ^@HaW5Jt$K9WzV;l-}d@i=JZ9@O{e%y;Wcl%Xd*#^La%Ne9Kv=f&?FZ z?+U=AVMviZK=%bW?03<@Z&jO!8dc-Fp_^lgWxu0#Y9k!21*6)6Cicvk@O8GeeF;0M zI%%c}w%$VMcQ;-wY8}%l2}u4xG_p#;=7G~YshSR;A~4V-xx-<@n+3;5EVlQg>7clL=Ja-{i<%<(nhm6vSM?er+;i)s1N{_ zVWv(M4vI`cjvPCy9MTAN>yffK3lXQ+f2#`44jiL+>=>sfri2fB4@B{j@qjA;x-{8o z%j{91qCW0I;A&hz!sCUXrvwc`Dnyl16%cL;n3~@o@LTrXI(>N_=0l=Ey+fAq)VL`; zRC0_wH~Z-7bki~yAi;V)h?5E(cuWJk2tB*Wv*&17Z|ll5%JdS{CWisL(zY>sh`o1#=;^hnqtq*QC0X0LUd-T#QM%BLdoA1ydnvlDGlL2_fx&%9M&~JZtSv9lW!JKHSQ1jtD%*S+mD?%Wt6TvtKCgfuE}ZX5e+`UO_Jy4ze*zG=VdlE=lGZ?eQ6uUK?!`TmiEZ23S~a7KM~;teiuv22<%WN*0* zv8bHfxy5Vd=~TvEO^b?S4qc(Fm4Cj8@ll>RSKa4kkfZ0Fc@CYx>l_0bF(6I{r7EwM zAuJu1p7SpB z<5xEKGfvN@#kNkb)PWOl8lbQu2WHd9U!YPjzxJVfv$ODO?fuXDhL&B=yCNtM5I1xX z5WK(3R(ecK9C|heMvit2P98SKCe~)wc7|XE*8ePE0X4Lo_SrH1X#x9ln+StGGUHm5 zG!wTm3LC8XxNO_pC?+soX0+r>6mFi6D?V`+<|49un>V!|AoWG^C->QrWhqkRoM&0t z!e8}14zQe6$4*O1{4bX{jhgg;%d;cv!9w|X{Q6OPB>iD9@(X)sX9#fwh|IeZqZOIS zjEJAW-Nu-TD#)4UAHTKv-MEfk^1-|JnOAxXVCX8cTTN+<2f{AA85FXHydeh22g8!g zYj}xes0+w%GyP@`6yOFG@a?Zg<*G=Sn8!n)MBtDjEdVltBQis{SO&bopS2$>jj4>@FgNt6eyNyl?rh{m3$_@_$>D#D`bBo{!HniMaN1prrR4{ zyPelsz2A&_uc6<+^mmB-lGFOahTLtnON61|%WI%ef`x?`@Z6$M;IAr1!eO+vClBn0 zw+ubT?R33{K>PDV)sDYOSlRrM!zdRFm`O%xUEVf|+2`Pu7*$qu7cEJn46`W(T)S?#h0R_~02_B>RH;Ia@v<)xCEau|D}dC?V0FerrA;~>TG&RFGFWs#s3kwD=3 zPGe+HA4{z~wEbxQkwGHNo;-aryKj^}gL$(hTAwUs^Ig(Zn;0mj4Nb##k|O1j!FQ`K zKm}eVP@XEKLUSA*HuUW}+LXm+CqCstKTfDS#5Zfa8 zembtV;l~~KOH@R=akP|Z50&T3?0^5nL(5~M&~+|2(T;i@1usk(gRPXAJM)!!7|eNk z3`v&2XH&pb4W+;sRd#D_u!kaa`)yjt_#_@{})IRG5sbYJ&S z$z&X}XHHP42}Q!*9D4)_3*4K=pe6l(LYomn_D9p8mJ^y|PR1vZj>&25-afbr^NVxA zP`$W!;Dh^(%Q7Y7BKCw1XoA-OIde0ArHi*0fVwL1FW|-HP08JGZrS;OD$vKX%T*rv z*(rWNIV_1pKb%#)bo(3&H2CsZ9SlhnW-=o~bz_(wK9r$0Q?^sT)ivp6~r>vV7+2o3HNU9TMpDA{Rp{Vj!u z!;3(Hxa9Yy3j(-xSVlmg(9NkWu`<`oUP;^ToO^jdTvFw7JXKS#lYJr=rY?3o1+OcC z=M_d|D@jShDK|T1!GVm>U^xaTtdXzc_23`=qq)rvcCL|5T^X+8Zh>i!2K{g)CLEQR zk;Y=!cT=5=A99`gLXhBR zW?%hGMJgq^ozg-76HI#PFCjn>liJVBu7&_Ybkv?k#`e-Jc^Biyj$tuXVolBLXZpCG z!1!^w2@WfX=UW&&;)Zs+r0$MonJo)vd^{^8FEA4fl`}F!YFuAr~@3<-yQ9q{8 zfPmpuMpv1m;pz6o_9zc#dOaMEj=rc#UvwGF`#pr7M9uM_mJ|^lM>H~6He^j(k*#xM zKuo_;kwn&1qqa0Nn`1Sk{GsXN_n)eTP+8` zb_9F(G(={=$J)F&f%(chyZ(W7K{FK7@`Lq0Q?S&P;uL9y?`w(fHj3lb?a+jJ?M`RY z5x^}iLyA7K$FpG#(njaSZmRL@d>u=D1ime@atzo*P9ir0tcz~B=y2Tn`ttInoGCq+ zFL|*Erb)s5f`p_=9{-^4@OX!4sZ(wCj4*?I5}Zz@$&xW5tBxrCB=8ksF{JgyOc4wP z)4J6~nIKVD*r>hoLKfgFSNSIQG68WTJg)Hma7MoE2F}1%GPS@=XA+Q4Y}h$JCr@XM zVTbZ}LAvY(c>2%nsTuEwoj+nzRNWzQbx@JJQdq;FTF{W@z15q%QHRReFVMooG!4T< zb|Z8-zCf{8cd4dYp;CIGDr*fBhc>V_6n%yaU8tu@8Mqbq++z(v>Vn^=Jf3C&+;hjV z(Ew=?s5~K`Bb(%N5eA7d;geE0ijU%>qAvilxDAy|WB!hHOdRWU)0Z zt*v5^R%v!^i96fB{}(vSM~&q1yd4|8HTHj?{P&?IGRC{f5)1@n1Trz4mH}9;4E$%0 z?PF*6=61QB9rjm3N?)FA|NK-Tfep1ZcXRSDsu;9LPNld*+?RzLV~z`$Evj$OSj$^y zTeWW4YL&qculG=ecef7!=c^#WQcS4#cK`xZnoQI5Duk1b+Gcj%%0>Q2{;SmEODBB= zy;q=aD01CbXOJKuN?Gvs69^kzMbrnAif1B^0#yxd;A|p*?OavVq(r~IU6fo#zh2zG zn`72iHyMb=zF#{~nK|JewD$zP8MFT~pvcSpTZ`rk0}kqq0pC64tY1x#OLt=)E`r;R z4Y^o$fOzg)7eLz-q1}ennkd60lk+ELRSSO?k;isGovzhV&Ns+k1*kR+Q5Lc8kyBYT zm$fTb2l*~M^ke=ErhBdmRO5*kp@8ZhvD~yVU0cRv#R)#JX>P2ftvf|VZcaRZDuJNN zqy7-yLAKDSNg9x)rmGi{+TwsYvIFwWYPhq(7Ruk=RAS33NhGf8gbPKXUdm5Ke*dF- zJ3)Ng0K4Abvv#F89vHc}7ll`P1| zzciEvl?-DNE`sfp#4X;JEUfZDp-s~AIQ)ygtYI@AD_j>gQm7rn+tMY4Cq7vrLm-MI z3r%!9dntgkL+29eoY}hHhpa|w@-<>~pJNWKQ`!QXnkYhT6i7Fq;_jw7Dr7MIFj?B{ z|5oxa;3dc)^cx{5t?QoK{#zMRtT2@(A1J^g^>VFh+GQ`%R(SbrN<`@@*4G-wRFi;P z{x#TMw+n5&7Sa7$NeA=2Lwy57pzv@(sM0MGGZm+hf?bcZFFW4AEb`%h-1CstTOs87 z{q#%IgR5uFC=U7qp>59)} z2)I@T&S&D#kD5|e#Tgue;+o;-A{`U~eBC(S|12*2@czr-z#k`Yo|I+elo3WsSYWk|Y!3NC_g>^Cn!)n6dUrLoJv}$0; z39un|PMfG+vEaZ?qY>Fxc9@#;10nEJJEk$#Zul2P*JNT!P4L?C`F2`*#5|L-evqsw4*XnqodU z+B@Q^q>HADC%UEAA0Y2*hC7*TrG(tcrML(`k;S+FQUy{dm-2HdzU7wKttGPjg5MCx zzECwdM3KPSEH<6TA zXT{(ao=z67{1eqCWO^23q@`e%{*BSF3j?do8TNJXoXv@pK99{GAj}DQAH-7$Ip)@} zinyq}o(6oE(Z)=>Cm$QOs~~qzovlG58c&&E8xnc7*Id;$7;acp-VpFvSlcViL&@g_ zCoi$q#y`S%v`!`?k`uJy$P;m!KDZsndAH1uDPX(HNWeGpE?>XU?p3uk!)#A^|` zYMWXO-sR3b^vgqi3nMSycKA*KKsRcUpA>=sCKZ;cWvd$6Ypj%hxOvTN4P~64`Nklj z0s=5SFEzFydoW!W@S8FH58G7u1YglFxuHyF9CiAV1uV*StetFad&qR@E9a^PhC7i- z-n;8@5hYVA_->@TpcJtVb^$N$(Qbn8C~|H-jyGOHxXcG8%nb9G`*7_Cz&_H~g9sg4 znyRIV%RGsfF4G3d{c!_paSWxgBR_AuYSqRo(j|Wp8HWg&Gm~4(sRDAXTdNF3g^<^6 zNz|t%j!r~)!bOJuiR~+U@3&?hH~HS%2M)G5BJWG|c^$3*uNUWiFYaW@n3Tak@|AAW z!^W#4YeLzTE;U1>&74N-K$-{i+*LNkdAcEzs5n&d_c9+0UU19Wic!eJdzESTv#ZL! zv=B@Oi&4=)F2`h2qj{x^t(`E*q7X;xI&hbi`ECsn%OOM-1EacfMM+DK1YsJmxeR+p zW9Gl3D$AAaFRd~}n?Zc^L@rZn(GXC2KN5F5_%>p`!IW^azN8L&AY!uQ=YSxbc zEw`@y`D!E$OCwc`zj4`tB|vYsATx#>iCIWqNU@yD)z_77VE4b`a?6P6)aWn5c2LN~ zd`8B<3UB_UkdXRo0B=c6f5_Q-z9^+&j-5cJu@Y(vSvA=*05nqn+lEEb#}f}_om^RF z1uRf%+U=&R!^?L0!sW4`?|Vq$bt>v<3l7wjC*blbf8lJ`H^ba!m9J!-u8l{iV@oVk z_^z0<93wUQzGB{j!voq&K9>n5a84TqD5xl0WrA4*DNfGn-Go-MUud7Cey?UFl2x%P zS)CS2OeV6^k-8FS9(KLNWg9a0(+z+a`ziKk20V7nZCA2@RV&V^v#|{mnKxa{>V1BC zfOz>_5Fm|<%b*9lDMbOeCVJSe`v+l_i=U9|)h7c&QN1JSxT$x=&A^Kj?J6+p19cz! z0;;mfg^TulAaBk*uGf(y^SkJxQ(F;}1`dJUFaSz`bc9o|WGbLb^Ul4`Y(HXoa6E~L zlcB!b6`Dg)GU(jHd9Dj5N^ZN^@)HT*{TTw~`4P(((5}O{H@!m;>MyzUi;{xti}k9y zp&8fJfnCAOGZ~L7lPAmZpb_{HF7KUXZi0OeqE?}i=d#LeJma@sPQwC*!>5X_xc*-M zqrhcI=%=F+FhaX@wAGQ#>kG#zcu^_(ZxWVL^WlVQFb0cKY~g!byCiVOAO1&a5+6bB2#GwbTQ#7KBqt))`4llX~us~LNp2b(SH!uLMA>l z(f@xKWa@+b-v%!`UbeToto~mH_34t0j5e(r4zFRZT=8s>hEn&7gyf^|^Z#8SrwI^6 zFCE;XPjL)EuR5swRf{v?K57Y9v4qA|i54nXo++%`jjG$FM-2AeI)xh$ggDGx&yqv1? zuCE(IZ@yX|$of2j*`u+dQH=>wHHs7{RwxKIA!&V#t~hn%+^=uq+<9gQ01409g-Bi6v=^FdN?icVg+P(+ARHnXL|jEi1_$M?7s-)vB~hRl!BC2`pG;c{mTWP&f;W{!x0&tJj3hCRG2}tk zLEIcGO-UgCGGUQqLgn8S0Gh$Q{5OMe|1$X2zvGW5=;DqqGvcce;JhhYcSv+gIFin|86kXAKYL1 zuR$G1a1apOLwyN0f9=>5!7%!78!+x+m_Uu7 zzBQbX0TLFI$<$7&^=yRZpJ^2i9_9Z`IRL68%gS17$2X#e(a?CR z%xd=EXc$s_4Q6s`wYO;<&>A|Y#f1xmPs*6l*Fxf%VN+c9(@cr2!#)sSlPtM2B$@zY zX*pZHnIlo`1PRvl?HM|eh$EhbLN~m}dc~VLyv-`oM^=QtA^P6TH zgC7?x^7$xhjtLrT`S@=o-wFaI7kLTaumF8W^ees@v^23 z<0ig7gc$US2S|Uwx17Wp7}-5Wh$jE82kVM6)-|=z?IPft5hbfQ7tJyc03ZpoXII#r zHzue~TCh%n!6Z(!i5Al*?$0Iec{SAC&ieWTg6db7T^Om4m_gB9;eha!krj!yqh$u0 zs)Y3JLVq=Gi;l_78@L1qU}}^8O1Pe8ziTn~B-zh6*bZV9d(o0Cr~YOxv=^@%W#L;n z&_hjD-AS#=u29lP>)PU9PE;856DA(thX>_+Lr_y;_(Kua&Sx)Usbu6`WD_1cXx4}f zkfErtx0Y^XiFRy}?ane#xpvejV=j?0Eie0x5igZ`=BsO={g!~yQRp3OQFGyg>_S~W zcVEzfye3Vky77MZt|GFw+~y(>?&owDs2p==vvOEpj*jwYpN5?pJKM%>pX8o2W;cIk zd1;py=hk zet$Vq^2}SYwc9o1|8I($U&n}w`+?c{56lRDV1}Li$d2~|vkiwIX7g`31aOfv)`E~y zDGDW2EvnO!Yp9ir;S&4y!D`j7xUEbdmF#S26> zNRwB%=^DBELEuSMx*AMVGCVMK?Vg^dcjGkfIbJ2Fl+U38kzi>=(`#MY%S8(v8;>~c zew)MBWv_lB!nU7C_)&0MwQ_j;5eERT(}9?|<`EyI5z0td)`A3yVC3{c{9PlwO~2qwSnYi!znHgO4A zvb5ss8pglw>P?exlT2rB!tB{ne^nHNb`M*aNXU@;h%p}5c6;I@ih3Ozd!p*p6wz3p z)p8|P)lbS4h+8Wgb2RD6lI|mCb!W*{Hx&?qe!lBiNwW1SLte?!E@le`m9Vb~bu*N( zG7newnu>qR#tEN4`J6z${~u*;B)t&L{DCdu&n%7bzhEmL1f9&y_8(E+u-W*5F6Jqr zLaG2)G~K~G

8=g)D3&bQ3HCv6QW~J**qE4t09^k0?tr*JWY(V26|}<+SDJ1|fkM zT4-`=(S16~&N>_Ef*R{uT4pGeMVP7Um+1f$8t6`QC1*OcDUjKtBVa9YH?2-aUmzz8BJyorWG1@G zb}pxf=XxmXW!q{M4izGveEI}@nMNcDhoyAe(64x|iq=PfsQdZyiGyHyH26f$b_^|A zxDVSu>igJ?rH;{r4<$V~x#t%H4<}V(ac`hLQ|_-?L|G@{7q=Z@!TKoYxOPq2^~$gr zSa4ke`>?wJ9%-*G-}iaYYdmL$jVM={wGhbNIH2ETdctG}g1W3ttHaz#hyN(@8z6-( z=T*z$NSB08AB|4CrsfdAL)yv0Z}!xK&z|@G`E}ND`+xe9m+ZrCQ$HvUgh)o>;rUTKiYqjK2s#b;sYfz0vMU@AxP6%d4 zLOn{Q)Jr@u$$e;(x=YARZAeLjhz%u|pMYWD#-=~Y2C92-m_kSYg>nGGEmig;O-e;$ z4>Ae1z87Pg$Wm!C!Sc_CHEJYR)%+v7iIxewKc!tD9}5+mmg9lA6I(xGHU_lvkzjgvM1Oq`=g1Bc>vmXmF}I zS#L@|i6f*QH@|P{xq4+8d5G6u>it*tJ6s$9BTM&|;6*&k}Uv zg~WyAroF)SYNu94m1K@heJGNd6vRX_1s@xZNsu{ds=tCb<#b0nhJ>Y4 zzx>G<{A^~r(4J?m+8g~8)#uIo&*aQgPnut6`?=Itr%IKFoBciJ-E8QWEP@Hhd=hM} z2kspZ$-4ps z$uWHY$!FK%)|t?L@>u}a)FW}RG?GgGYH^B$%~IyvPYq=g+KU89VlLdwif{0K)#b5j z0i%K`7>K{)JFP$MzVX247v)IElqY6LSzx-+yq;&jwQ0nKXVMqiI#HaX*21Sw+R_wQ zmHxXzUE`kN{Zrr_j-2+jmv|vqPCYgGjD`!a#yt>_4e#vg4cu(5n+#9+ykdv81r6bn zTq2XiJ>i<7j&0Rmr8h7oLO?P$p8{(@Qw~qt7hSzBOe2gz@1kR$VMIFw?lld|lB|TD z=@MbrrJSJMuUtZ;2@`U~rkE+@itm-DW$;jxt*`)zxKcPqR6V%ujBFezN$KLpH7f`p zjO$2b)x|nd)oE_hvQE-$lT@?mQ>T~l1{y@B;Q4JMG<6+|Rj7W1iGtYjP zr>>kV?Ilj1`ioqWQj29QS*hsMBc^9Z@wfGhPREx8K8`Hd8jOo3&2x-g7D%yro~B@V zMK?FYyD=65CKXpvXl37o7o z=U#CQ6N-uFeAsPe@lR&bz~$fz;Y+fqu4PyNdaOP0gVopR)GdZRVr6>k>{oSOGYNoV zSw;7SjpEqwm@JTtR`1=+E(zvg=7i8anOEx?$qh~-4Tps#YfoUge$Jes@J0x5-St@$ z83|9lYdmBq9RDO1~ft(`&h( ztk%-XWmS1a`4}(wR+54a$3ubrtq$4kLoKav)U9X7dO+5q3!*g=<#HqX$fVM5Nl>XLBS^;o#GotUG$0Oo^?rJKiUX)ztM2onrM z7@mK_jPnc8bhi1(x4QR*fq@AN4#~B|LA82hNVHuq(}y&i!Lou%p5}k}-}Q(8*(l4Y zQ^Gi20Ill90^{Wa=KA)b&Mb z$s3>t%f(X zVxXR1WT4|E8}!f@l7;YS-&Y7tBEAo;8t6U&b-87(3F`j8>HiJMKgvpMeL3SN9dFOI zw@Ny87g2XO>vvA}jsjlwtSk?03IuGnXaA)EHpxL5!|37EL5W&+RmSU!Yd~Dyaz;9) zH*dT{WjWhl5r_ClH(1J9z`T;i(NwvZ+zPRI4^O^*{(5isqB24c=dV|G@rtjX5ITShxGb`+t9ub&{WC9XDA+nBWKTV-7!v?}D8b z?4;r6s-PPXQrrd_LZAIDk2J`zOTt8^^V<$s2QEn_S+=K3bX*n#_q0DmE{oOCV!P9L z#$DeJp=Zm41M&K}z;veBr^a4i&xj?H$U;Q#L}mJ-!>>zuVcHyStx9aGymKEkMuId3 zi$>$VPPCbPtwP6Y15oVC=0;IOkiEPA2x2$Ue2lAbw=-A-7SENC&8M1lsjXa4QCWkK zp=s;plK&y~Kz9(V31c%rbL&!>N0dqwE$bq~Ay+Hr3~X?lG)bl=Uy27lgJzcJvWPvJ zJa44PBbRDIxF3WLFX)wl!|w#R%6@Fnx$N8rGTr12I_L}f0_fp;s9Iv<-k3@^qf@qL ztb{=hHttp+r}_nXE$v?-3rFyD@|uHbYToF9QAE?H>bO)anf;3q!I$r+$Ni&M#r3|0 zp3L{e9_286IWonk1vkxp;kevgjYgzMlut86kSIGKq=6~^ne6p6$xQIpEf}fnA_2al zs}D2xsL)x+q-|9ycd(L0xu-d~d!%yAh<56^6@HiGYfLs4u_l_GpXYi5W@VW5z*bsz`msSsUO(t^AR3&W z9mnlH@CE8!bQ6yKSNLgTe>mTZ`ahiCyMdslZE%W>N^LDuDi!T==@sWKb`Htlp|K%R zI8X}^afzG`Je+-ThmGBlTn8iQq|Wrw%qy+shqqo!v!WTug~n5tSGI~3axtF|6lnC( zX_R3#*1r(WYQc?G%sEP-sZY?eK!TQ?Hyc*WA~bQ38`P;HK?7O~5Gs0vH2-#%yOg zBr5pW*o)H%Hb}SSgBGOdS!uFNRu@uuDuHe6w;5UN5#CuP7QdQHL(TuV7!zs3lB0wm zHjUgr!Pv#SWuY|SuCgG6`MbGOtdE1AqFKwz`NF2x2 z5o1F5yigympQ0kFjH4B80!WmmvP-ju=@8X}KC7Tg)$?NXpr#|g4+r+l;gI4^AI0V$ zKjA|aX4Z0OGG+M-P3>@$1OE@AzWw`nFg~6%J(s?xKzH`W^gpf50*^KGLYw z=02oijZ{rtM6qc9fJpsCb7$jUTc(YO7)R67ZC5mvxTKen?2EQ z^*A3XgU?~=&vWHY^vrD9y99CVgI2*|@-b}WKBZ)KWBcm@bRvS?R1-KQ*akfzO0E-fbvp9j~2;=xEc z7fH58vpL?DHt^M!d=xp)0)G{Nn|#dEGmP9P+yUBfE#6_WwJuYCA{qb#QcSMjR7}txv|9 z-mtJNcD-@!4zW7_(!9L6 zuG-xC`h6Lp+_5FVfn)r0HS)haRwSRScpraIKLL@PD}$5#DE=SJ|Nq=CcSK;;pT@~1 z+zBjl?k0Q=Q3qQL1rptS78-~VQjD|lE5P?x3Ko^Up4*;q=@|BO_KQWSI8@L}@&s+h z)W8Mz?oQf8W5mUx4HH2;v5vC4Yu~32ST>(NbzX@-7Q!#4;)MCoSU$E@d#{CUp9ACQ zxWeaq0EiR*N~R!FjG3VX*fMr27)*SyLyKI2bu(~SGlUpA2%Rfk=F72ztL5{TP1rOo2yr7|?MS>Hxw~r&EKS3?fZzE*(TU!CN9$}=@E8+@B zh&yqLKp5c{q%fx74UR0f0$)sQzZz5P`(?E{Ktr!>pyq&LL-B_RBw`SSzB>ZHEc@O?%K*3 zU*{Pi>aJs2Dhw%6wo5)u`vS~a3a2)nWxSMGk&;zJOf0Ds){t65^{~u=42u8C+t+;( zK&@Rt+K|`?beZlLT2fGcPg!vQ7kY^QJeMZYz=gauQeMh%$3tm-e+tTpotRA=)?7ca zUL~R$&kToqioI~XEBabdiR9qx5wjSjJublItWee}SQyz^2czf@LC7jwhJDA_qy3s& zjVkh5?H-R&P}g#N(^CX}T;k^w85P2F~(<5xa6WVe(4YE>KG1?@K9}Ty2?yjh) z09k|D@JPU`#FRNw;ezmN1xDZnnv31b0~!a3kMBN(Dp-Xp3)J1$`VV0k3C~T(+PR7! z!b8_vSrNBKg`DF_*3&$so5={jSs^q7I3Yok z=V*f#)Yso1p#>iF*K?f>Zk%Kx}_FO5lYe*J`oAmo3AhN9Ge%fbKaUzW-c9u8sV2!VD7 zo%1v%ge!Fr)|m0eZe0khR&KTBxLR27#xTEfwRMM`O@6R| z{<~b&__emYhW(TK+=A9z*W_)6BTlfutEH6i|3?jW6Yj;}@Yz=B@^zl7S#jK6p{C;) z0YDq|)oU_Fr93Po<+;R3y?brD-V885R-Xm4X>?n|+cwHHUU7>suOv~VP2#eteJr#n zHAGr>!H_VYD|`%Lb{8p{+Q6MuuNZ!a;Z8SBWzYz-io1NTJhApmcDXEwt!Vb`7Ow}y zpCaY;Qsl33Bde=-?yHIuJoXvT(AK3!fT0B@jD$32I_gV|2bIgt2o-XXT`6Yp#KQ<( z8a_WZsI`pr!E1O>MbN24NsfZc2a9d}8#U-J zi>0A{IAtK0Y?|&uoJ5@oy0`|*(4EEnuYxUyct0sH$;A4c+WXf)v6<#>Lc=6kz(z$1 zrws=&nsbWSspNkC<6=AWUoSe;#GlAup(4r6t|Qp;*x1d^5ZJW|D%-%Qm^SHfFm@+a zwpD8)lcw(FhFA@{a}V6IRPV{xXP6yYIO{#cyU|f;DUhfhsUqken}X!`X%B}?T~1oX zSX|v!=|u1qHr~1U3k78UA8i24y`0&=t?}G?VDn$Ju3`g)qgHJf?C`39U1{J+e*G0c9hDwd~BCTzzsDyg9 z3CM(+^hi=Vj?0~eI_q4KthKJh>4qFh9X3NG*f6I^i3~^ne#b&Qx(EScVQ20%(qOA4 zPX=M(EHWrPw@)@M#?bie68|oYt!68fesgSCXi?zi9li>EmlwlhsAHmxdKn57l|Tbs-bLf?VV640(fY z66d0uuYUtPLd%zIaHs1eF)|7WC_uTUnBpI187!F>G}VQ<~d9skQ_JOeS9fZX32 z!zQ=L8#N>{aEGo3adFx>w*kZ6f0JO$%II2c!U7wvgNnxj!&|3 zx_rUY`+sSNHlNd@T2Bm|4HFp*7N1P>hI3@;8wT6D4vIWXEe#tV#XImSjWnvikZ$e( zM>_TbQB=%?8T^ixjuX00dU_ie1v#&foH1NW7tn8@ch5TaT^{$G?QrV=3?E=G`hSI| zYA*Uxg)xaM(E{_@ZXWZtPwz7w!c7k*2a$S!+I}ZL(LkMFycEh*Qzak+bqK~&^J>6j zFeT7cTw=NCs(z~T>?%_|(-@ByUUK6-+D)gY!0yVBg=^bZ_9i>W)>(oS`vO!=1YyQp zk;DgZrqiC`w6eIuaQY`77qZMpJgIT!G$5c*!1xv)efQKzLPn#Fv>Rcs2ACQ zgu=F1k%$S-pY#aWW&*JShFE=CS|7BW%|-`H7``+9){>?!Ob`$}k23I$%_0QVG+pq> zRXIMMmS}FLTjEe~cIm$)P_rOauRh>jK=HiHw@l8sx&r&Z03E+)n%0vPB7nbmdC zMCI(xnv504{SgM7#~)#sfp1HR_61y0jHxG{V{$IdVe#Eg%i95Ek90$&fq`Y z{MmCshur)!6&X+cc)nW*Xrf)(E!P-^p5dUmb$S4ucG0^L#szST5UJZonvVIh;dI7?ePVtr{tp~d*|e(Bngon@|ltJ?C7 z0WmPWgmhb{!LU^2ayCb5)w03#oB`Myj5Dj##vWjU-pu&b_h0wFZJIbLbo6O}IoU#;{2q@*oXbXR)8X6X@)P0Gv>s z6t|LBQ$lA-dyqYb2)u;T2*?MvH8CQnk}jBsG!ePvb>a1y;oXD`wTtTVnXVhn8wY6n zOe9Kpgd~ziTc#9;+HH?7U$C%$YNs-e6#2L-@X$1wbaPWg)kMxs!z{<^f!TTjp(T#X&D`I;C($1Bzk15+G9%{1DkMvXfV12uE#?!ZaQd zGtXCTjtF@CY8>YnbHU6NYN^7FGAh&?{cSq>|7>yxCAw zCPqq5i6@_}jh+vcWiF!11KKFnPKkUosmGT7;dq;krjk(??TU3c;ojit?`@5JM?GJ+_fA2cBw9^N~_ttm?%F6m=`wqLFnA%8-+)r}-IS z-|Xmp+EqHas2~v+X&5Zo!=pdxhq*pX>BrK|I)ZcPpHyAXXD%37^GUTS)Sovh;Dqho z1mBhKV8cm%69P?rfC=6FYVCNdG2#N{XHYv`m0y}Hwm=*<#nWm;%6tngFjo4rxJb8p ze7o?ewGA&1*ne9XFuEQ*exF1}47?u;nY~;ywjxli(TH;cMh!mHE-~R3N>jWcpUAz4 zJ3L=;EY#>x;p8a6ZIRB7r9V5ipI6Mnt-4xK$K(|!T$5Mb!K+!}fnGOsfUa`b%ralL zTX|+uM*V)uP6d=e@U%n{lw}dLL_c$y-E^IzUChmC&Fy`woDt{$RUY~EoaI&>WMfRb zxn@7x8^)rvY1zHaL7(|y*V7HTVPm;v`mq&fAG_+q+g>0qFKH~?PM zwjYPl4XorjWdVS;>|HTh4fp0o^X)p+j>CV9v+@N2$$DCCT>n# zp%aKIWM|Q*X7vHNP>28(lIYg!@62>DEp3tHqQZ9fCu?yycgS-o=F5&PxXDXt#hX&_U|3x{sK&44zx*evPI3M#&_*(r9N(w3}AtekdUCBGx7 z3xV}a=n~-L>N&hl=0w&YUIm5d>8V46Nfk;?)DW3XcAe!mORPMRLdjBs+IX)oO~IQ4 zFmnRyBGAcZl8w_S&`u&BSJQE0bDjJvUU68T@YBqb(PGN)7zZuX`aLF~+t-9^5#t2} zA^=-a>2N3tZ;jiie)Bldac-0z-~H+8%_bdAwhu6S{1}SXw2W6{8dW(;PM%v^tAxD; zgFuLfIw^A1`YGqx79gak#QxdSLS272eVwcgonGywE4{H3Mi)iWwn4hYmT75=DTqfX z422Nk2z;Uvo{ewie%yoUuN50{sykhLC-CrOAH*bSOIVZlSMjf$Z;pG4cCut=>i2S8_N5z#U|B|_Ub$)z~3P9}j=QVEqZpr>IEinxHkud^Y; zYC&wmrntHvWhVahN3Lr}@elkx2AZxuM?P3&hw-L9rY$GofPCc^2vbU5RAwodNz&fo zO5ck35;oM@C*0%KO5})VDPJ!$5=9`_2?P-F>=)q*?~1NwmrrM#*Hmll0@kkYD3UGl z%;$~*k^O?IPx-~Ck2!=G&zR28ZcH6$9gA}6bZ*u7#349YVV%Eh^$Nd+;N81MLU4-i zGkCy7`*2-#YHz=@{Ay9|$hpow)M_kz>yP$#I-g0SDRHx0c3XJuV0dnLYFW)ElNLaF zY$aTcAp*)-2>RK6kEkM7_zd>8Gd02l_JkI5VT7Qwj(Gox^n#jZAr02oJ71^7(%Pn| z7s-d$OK*knsq4Bmhpu5a<__#9t=q@+*M@ccG+jH_F&0>tnNb$|nMV$8D_8~NWO^o@ zvy~9Oi+Ok+#LK7o2$5@|}E7h-2T)3fbSsYQ;U<>N^0Oai{)-e`C zh|WPnsk`_!@TYviA{wYIejmx;`&{J(c^4l#^kR(@qQ4iowP2by3B)7v$bF*N~)^IHAb3-fv!nF>0ny*zVR7!K6!taZ)GmV$v!V+_FNFU~T- z{BCZ3UT*&HW{5vgN4Om3(9wJlUCpAjj5G_;E@hcMmnorhaZcA`t{+O+vLR`RBJuip zw{?{&gyoHzuOTyUuEfVEgX3ln5KL#kolKx?~Lq zUG4@jfX}bHv4xQt$+3gvkP*NPqMwiNGN$Zup|LpKRz$;#^L?VfU(eun<6$FH%_pzR z1&#*~jVEqg#h4Ec8S#c~o;-JJg+&g|-}@?6D9T4wX)!a`uzO%OoK6QMchz0xyR5^# z1L3+vN*GRPkO9-v{$xs{dK0ThkxF-UM&f^^S*TGu#2Z#^G`4N@1hjzAXQ^HsI5Vqk4W*I|gRF^OhfHARS#oDcfj;9crb2=yFexRu88%T(XVa`lZm)%4g6=0bpt&A%p>Z1vEQbT%&Al?o`wCa#0H>Dkq_-tA*q$C@!TXB=W) z`F*F39mp7G1;nC^{FEXY-kMu_JqcIGK4Z61Rrx6imXu&i}j?-&Xe?m zu&2C``jZ(q9rjiE)<9hjExIPRgX}n2tcOKi?FHwNZ8v=4X*dAK1`a+_>DKj)KB9o?L(-lQS~OSbr5fbC z$(=?J&;V2AD?Pv@r>csgOP#dikC+A}INBQyCy2R4#=|L!n_ZRgvWBf50cyYR3ysN) zwoPdT9_=cgQ`)mw5)&gmgG6fZBx$r7d|18s;j0N0-IO^wGC6KZR;MYu>7J$*C0F1{ zxB-R=1@)zB)s#P_nQAEFh>Vs-78NsFcp+7mQ*)&BZ3Q6p9DNqE<)0l_L!r88iZ&%S z7)+LmUHkl+TyPqF>q0}qQ`mee)6+`!zpUVCI)tEOs&7ugY!LTlNt`pd`^33R@_oIbTnN1?T6NO5wF* zCEV#>K8*%qJ#!^vnyqZhMe`c%yL}Au-KQ!gvX)EfdOFG~DusgpQipHP2MbQjS^sj$ z?}pS};S!>r)3m>5-i|AtS`U&87;mk&|7RIdrxRNI{^vp<5h)o?TMVG@y3T{-|Kr+G zYj1!eUu&DhL5O6L6Ut_fDq}iN;SUW0cDJ~SJ?5}0u(=bUnFPPO8|=Dab8kH6+i2-I z<3pB=1d={g$-#yHQ3}e%K0%(GBCD%AYsFT;d)W87j^6(ynOlG!>l>5Lv%#y6B@rO# z2KtS4{=~CL{pvQUU;vQ)sB1<9HC%fUBWDiSD$i~N)~$pTYExryC&0cRy^D5B?wa)) z6ahXBb#6hd(|ncgiV*G%3Vx0cR|9$qx<_7rCl){qY+%~&*75vIh)v0Tguw^}R*Q#| zJ|963?}=folDwB>U*ynInszm#e#)HC((141UGd_A$k4& zBy=0JNKA4=NM@R2(R0#dXmef9ITvsluH|ev(2a2YV zEe)J|ZA@I+A#_z5!MIoKCzoI(9=WeJ7xJ7BgIT>0uc|N0X0=|kxZrbG^-d*@w}6*p zS*h-j-mr3iRluRH`4>*+V6_0-!$npd83ILdWJ%cIq2IjU>8g;;|Kdlbs zCA&kt2Ht5h2OvK(L25(I|3&78VnJh>9G@IXOxFGEnvgt%|$EYJL`d&yxY zYTm!h`2>(XH&sKIJW~np;!uiBC^h4gQQUTEI44(&X?`@Zd$+pYXi+^t5{3LW&oX>r{bQ#CwQuXIo1s& z4g1&)yN4Do>ItiUdpOm(=IwzfT+-IQI(rg-)e2?`3UjV z6#8xT#f~~5q6*MY4tK;ZcQ|(hUnt0azh1GX(%SfdYY6dHda(_D&kH*LdNW|6q6hdt ztpRGg$CAI|0pg35W2W_)t~=oVtk&CWD_51Jpd19%j=9H~S8TcI`f877g4;-RAqkt& z{llVLqP1FV#kaeXc`ryK(UNBVq1)h~0IIL&+m;^Kk0tHkQmaH?Ua6S8-$)dcO#FX@ zc~bfAZNCLUGE-$rk^sqXi2sxJqyG1YoR5L{1jRpHOY)ytFGVtWr}|4Q!G>d>i)*ExAbD3pbak-(&fm~pGmQFY$O-aUz)Sp|## zwyYyOhtR3U&_U5*Q2*%t-6T4)2VfD`bU76+Q%}XmyEYK2Q=*IMrarE1pg^5+G&v24 zf^V%56~1o?k0D4ZnP&#fAphZtY&0$x{WF?RY#K_5O$K8eYKb0Zc46RBJ7mv5gJD9E zVo-8yO^_a?R-{#KBw~sY%xY`R78HGMO}5a0iVG~3;viVI@uWI2Z;x;34G@6<7Gc1G z9&cLhT;-I4Q$^}usf%JWU8x#%o5FKV2>NRb9nEUJ$RrihTa@FUj%f2SdT9;Oz+{2eQ?5n#s-R{l_-C|M2iEiQo%q2Ft&}3yn~}FawLaX(Ger5Nxo+mRN4pJA z)q0hnVYyCETN-bV396q^4p5eZVs{tKgG!fbCfqM6D-BU4ItV{Lj@^8Ha&2C0%Y1^FbbSpa+r zY6bNU)ehlZfP4z^2>pod2HOtm&uycV7TD9vtfO`J_iLP|puwBE`cnIy&x!uulTY3Bl4Ens-x4C1PjB(*wj@Rj zrjd0D!A3d!0D^icd$C2NUsa0|$?P{*bzHyrD3~?ut2X3|b?MT0V^FsK0fsfgWJ>CL zumS(44c{c7on!H{u*MDt1VonX?1r1n9R`>DWq=0g(y(>hmq7cB8w9knItbU(AGw@^3tpiYEkG7br2Q3Oyx5Rv*i=?tw zTNMF0HdIg4&VPj|FX;#cPSGJr%nTmYh6q5soYDTa2{~Cp!uFeG!gRO9_*mpL)l3hU zgbIzSdDm{bG}M+e**M(+MAs=B%$l;QS_uO(stzgX>;sD3XpW{Yo*`yq@?d88oO3(7 z%CR_OzbGu|`Vmhn6SK>pP>ea>hN2ZbafVwVe()IopQlz}FH%q~CLF{{5mITeZ9kwD zMAdQ_^EQmmv|{_pXE~2gQ_Lip$jf}ZX=tWA(%7UVHpV)Z4q^doKoGKM*YrZ^p!3LV z-2{XKyh#GYFt%NyuuY3$i1eOI0qml+W@BhwB^YgJJb`$E9--Rr`i2u%Uo>m(E3rH9Yl=rp42iENT&_JE>aN?rMN0Ss{Cs|NO}r@s{uGLe279R z{SplSG+??!{MNOl0G9&|zA-WAV5d3{bbW|ufQvN@V0qt!&>RV0on9+1TQx+pvCO_o zZ7t>5f0gaWv|tr@$d^S9vZSb6qvJ@1tYi&wa>5s&{q?bY%{TiABuMv10m%?+a?E-| zWn){tHN*+qD%?Lq!%u=OC;@P=V$5rtsI;PXrYM-Db&VgIB|%FZsrM`49oS0Fgd}zR zk7<2#Q!$xI&RLQn?^r+!k^P6vrmyb1!hWz zoQxLgI1n~K{|PEMMKuCa=Q`Hx^*{6n>=)H6628vXxC83EJyiI9#%(@V#H^hJ{Y$R8 zYdn-`jQL=P4R zhIcuIV)8GW0NA{nxx-YMquZhH|6gbSTW0fb9$?13e?0t`sepip{)?8*O$Y(18&Vjb z3h3W^HL48(aBOLI2axeNrczEI;eFF`7OE-8F1YO`(s2aPKc8P;`8s+|B*ic%*r}ve zP>J`>FZt&$w9wn9{D_+x)stYeHm9BMfX_UV&)&S(RTE z*+HQv0;$!jr67LMr$x)>3MB~j+Ie4BFY|W+`D}<5X1pMd;U|olvZdW6ZN=a;dh2F~ zEg-_ObZSDB;5KBK$fw;!y>{Y+iz>f+p!e+Ci#wSiO5&W^9dD*UEdT=O*Y9hwwjLiQ zLj^-ERsZc0vkeMS*^H-84AGfcedzzgxS1g0+=T?^{(7Lr)m zYo1q3nGugWgSl570u#!rPP|LspIZ7?AW3cIN^fS`e`Yv;mh?n67e($&lq=gLjbsHO z?4*7bn$x9*8Nv~+&BzAu2K*}#YL=2WG!b3rb}UPbZ#3~2FybF1O^F> z&{K-~;YA!`r6~2KM1+cfBrn5*Y<26C$QU+pS$Ow?$HIsKu*krSl3H^UL7MA<9exRR34iEc5ElrZM0_BjQvTQ(IaqBegO^-v zo9+8c4B%D_cw(D=KuJ2Z0eh)Njb{~CEa(`1+%&}X!Yr?lEjRcrG6-lUS9$%p+7V0A zG8zQkz?>ga`6I3gZ&vt>ZYM%VX6>M$og@YY8v%1|N`r<4P@|PDjeGkj_bgw_hGJie zUBe2$+WVL{cZO`1(N4Y&miJC+HtSMOKH32b)vQpKA$`cg1#y{{26LO7(U7*y%zCOmg1(|i1JI7C!>mfrmCBVN%>UHj zkM9)>K>rLC4;$Qm-%2A#$4lMOJ%K+Z$T&5YEvK-rdKM#0VXk)PuWfwx)*0tp%vKG3 z6!5FRR9Oy;997n&G{cPs=+Bj#>9=t68KqGp;&r_ zT zrwgQeaRibU%ta?nda>5lVhs}b^%D4s*N%Te98(g_jKBV#q@yWdVyPQ%YfV#zT7w@2 zmDTC@eniuLaOB$mBRs+PMoETwq2%l@1XSR}(GB588GLT&G=2I5OWv%Polr{pTOBw( zH3Jr{U*g{lId>|gm1x023iaExi;;0A7$mQUD?uv=6}DK~J@`Jr_hBI$IClQfSnKQL z@cT`4&E5Xin_u4(Zpd`3AZ%09l$yrJ=XU1?r_L^G^6=~CTfTjj98UCl_iNy)SMYv^*6nWtAHNrWuEwo4=vpQ z{fp3e&am}i=Pe*ZgD+~*!*VWN(dY}v;zQh~N6H@k&nHQvVd(SH2uY!O#4Ll?u6Xy) z%*hww8d*FrtYj>pu8zQrAAn-_b8$YSMI=xiyN)@=@U`t5^omA_v8d5h?$|aH&J2t) z;RkqM$k~p1aL&5|c-Kre#}Z+1sTirXS0j4@c+B|!zq+n6EUK>U4j?Jr-Q696bb}z>jR;7$goheHLShI}8k88Mkx)`f zkW`QuKtMVqqy@eKpXWt<-*5k$>sov5d+*sl&biNhuZ3NTG4({TKMR?&qtDUyk>x16 z6pEqUf=VmDVfAi)u%6xis0Llx+q#!4Ck#UTd!xMv@vVBmLp+1SrJqV6`+E$1MU|@F z<{}Rr1cV-?1lGD#MC>R(5?S9b@WVmecn~lo=^*nJD{seeJTyzr;lp#?C*7N@-`%3L zMQ!)k?nX83a7A(r&~HB4=ky~yt|D_4^BT|?e8;jWb6AS{*@WX8XY=yP{QO29^3R^y z*)2IBqJ+x-Js^~s7yaFcrzBVD+}5`ZCRE3DvPIIzy7g|L8NUx@clf~Z+n2pseas9$eNJG?Z&tMoU5}rSa(jW14^SLcgC^KQ{{;ufsnF_mlnm7Cixfi%#((0u0wZCzbIp zw%9Lln(7be4M~v#Owxik@BC8!g&2S|p*FA>%16G@AjiO;gfC9B<=V1Ejjlp^I(B$M zsJD~k-w2$Y+{2lwHO6`tKfq%py4FO4a1NV+jhD48b&U~kY;LxF_slB41Z&pQ#Ozo%FIu^hdq0VDZoKD*;D|3b`L>}Z=vjPH*Sm;oKJY$P$q9#vYJ zZ;E)#R0`-NQ!u}nu{_YL4wi{b zcjhc5J4)zWJ=U9NKM-rm!oYi=H2V*!EZHh+9h5K$(@D4Ja#6;O+Awm?6{TMlt+Y&b z^CQ#dirUEo2D?SAr@ug5L3hUYQA4PQ?+R zMlTzx(hlM$FTp`Ip$KFSs*=X>h{Q!~O{^zsCF==cR0K419n(Ln&QHR$pD(e`D^uhw zYLQyXU^#AKD{|K~SD}G7yLasdDi>?$8(Fd6eCTdYL~#gg1ai65Kiq1{pN*w(MWK8( z8KTZ=EA=Hu=_v{(fiTi*R_n~i#KrdXMaZOah;h0LWE6oS{&L8 zYuzMWOiJ&OCDwfxJCzZgNQ+83JIDc4$THcbRGQqOY6_eW(QuutF^jFSd>@~PJ=RT& z!q*!>KQk!hA_n|t*Ox1JEeJKWrTxZT|N+Ap6rH|C%XeZ8p-#x43etP6R@N1m@;L>mlUw$c(M`$)RWR? zU6$qMF}0U0h!zSuP%@`CW4VP~wuLjdwjHIJyD{r+1(pDkHOvh>xb$C{P<`1Xy|c2h znSGwOnJKEm=9mZPN^jC(m{Xc4IpynsjwQw1G8!ct7=^`X*?NT;hnz6S^JDs;ZI}Z4 zDx{{V2U*{2)5Duyzn};W*Ensv`i`UD5J^*14?% zT+9cenF09UJdR#Fk@k$Q1;i^r8^8-0_WU+va|y%CDniqul!UrnCMj7D7?tMKsrL7s zB03_h2Huus+}cqMN*c>`d)H3R&FEv3WutGr)MfBl?9GFZHt~{Q&hkFHj0rGhMwb?Z zpj7CLgKg%ZWcuCd{@d(F`o%t9CGN`mPA~XB*bWDj?UU2)8qw!+;c6(FFV<^E`FIsR zOQ$optAB7~5{7=%$^Ny$J@1J$5n#+2V)=(P#%)m!y13Tg&4_8#@kKCFWBHrA$?U%ONo*yJxsBGC}{W#ozvUZnM9SE5Eus`~6{Vl0;U^havD=})RQ1>>M=*jrH zMHUTKZsfw($hlz|S3kjDhp!z(oL^()G7WLl=sMVTtM5i#oJ>o;x>Xp60_%(DQwDT~ z&L2Eh^%-$^>y}Y50((s*HGE@|Chqyx=x0_Z&IwMpR$vw-} zCJ)CNG>_Q96lEdv9+mGFAL0%|hbusPjyTT{rAd2kY^HA+OARsUn;tz&$1`CuDj*biEihlJifJmZ{0dgyaeXH``u*XZhZuUh!=OKOaV>{;u zT94N)0{9e2h)@hvKBbGFUm~Yj--} zbaAYJEkqtyc#(Aak8JjTdO}wDgSA7@Kp-nxh>Mpr0MBE=9|?Mv_xIow*gBf9(BeWkwq-3gkqx;m{NG6}yuK zI~SEs12(-XvewV+HEA$CRua#<8_0X;x*3c!rytvP5EMWyZOl8617N;RBl8RK;$dUsrH4CNb8f`m)%4N5{k1Tk%@Jgnp#pM1-WA*H{r~jMA z;`8ZL#&i;~jS(zWER{GkbwFV-2-Z8|qL=5>a6_?nCR(k`KDn)Gxs7MydG}ROAaWA6! z{Amv8h?80^f(?OojQ4o;qANDsk`te!P)j_Ln)!+~P09sd`TF83nB2}a_+j?Ym0w7- zr_9*vt9lYWNZ0yw0pw;JM~KvaTXwLnJK7052|+D)dZaozV(gt=wWo86>o<_`=0Ic& z#HSib2tVQDS#Qu_rJO~eirTPxd%JwB?DtQyO|P3Z`EtquIZ{8oJ5S2@XQrqr+wO}J zIw?+4_z#I|&M<+Q69Z?H5kc1SGUoZ?Sd>Vost2a`Z3=RT0c5|v>`@B_)W1Mcdu(O8-D=-M@!b9lHk z03#~hZ}~-lqKQ(bT2%toCT>v5Sc(ABTI99~Y;%FqBBPEq`!vqywgE(6B=e3KkZIia zR>h&~eodu(jmHyb2YtEu<}Glwc~VkZ%)FMqzC;rVil|+D!Ucx9;D)t@8G%__iU#_0 z&ad0PQB8Ngm#h~#;Szit77~J`_{w@w zq}oiWL&lLYkEICFu`!U%G(XVC?Fpc-GSwuBMzt(hII-^9Rn5VwWBd>bf2@gpnnzEEEv89DlR0470p9B@3I&@ljaTX?V` z9zE!VrylSWUU3`o)y^Q-7c5LtVwf^`?L_$4%MEr;@tx@!C`v?ry&9VjI9pV_m81e!3_>b0e&;j*0s^!H;PFzy!4nqAq5zxtGuw)(8Tr{t4WbkSfjTI%%Rc| z#&&9uh&ZqCq=~D9yL!9cbuT&Qe1{KDLDUrtUTD-8`|RR;wf9~?a2SC!5Wvn=?Wq>W z>GP1#;*QCXA7svwlIY^o6)G|-*Mm#;u5GL<@Bw+ zBlA9}MmU1fuXk%+A>+GM&aP@G6C|Cv)*>7jZ_ZTL-Jy~Z!ansNTHZBJPkBR2JfvyD zk(ORU=usT_(NbaEhI4$YwX=~EBUQCHu&f7j!3MLY3nOrki>Kg$=bRRPL1mV8BA}Pb zJ|08NGT9KyPjnGMG@fLRecPVLRQxTr+g|r+RN{4QGE)Vl|}E5`b5t5Nl3%q z8~R0gNETmqlXL{(1aCVw%ft62?q_i7>;+a8E$XK@W!4m(W9xLH*nVE#Pr7)WV=`=m zO2XE|mWw0AtS?d%tD>1XzQ2_o?gf^0QUcx^-d~8LQWq9TNr^UjU&(nJ{+y+I^nAch zSUg#zRJW7AhmP&k*{jxr(_(x@Z$g=<6u+V7jWQ9(#X>rU+ip{-ahcEyW4Wz!uTPU2 zrIZ|!xptcL#Jdj!s)Z^s8kXr&Yn?l_I{1y44oy4w4IQd=dZ5;op=GYciTi*A2d!fL z094$h{!Pcpary&dL+*y4HWYEiKJ+ENJb<0ihtdvk*A9^ zU+RXZlpV$>ViE%u}jY#Ba6P+8fw=m5TS)bnXxot-v{*5!s)8BivxdbuO z%Xf`x<&##e+%mM9tVEgsscaCCVxhn9^Yzp8Zpb}UFGEH5uigi7roxppL?Q%*$?VA< z#rXV!X|r8R9_$8P=FfQmmX~V8eXi?%HBc_Yj#H)9c20`HwpD}K!PV>l97p<7)v2`z zuP%*WHH~N41M&F+TOjIAyBM;Uz8D<3=lawyi%rWumG*OY>XudXrm{eQ4NP)5rrFgD-R`Fa@tr zxEj9~@`p?XQ5aq_w}fp)m&2J+X+R+OC&NE5yztn(UH(6AEd%H3VR+K!$$v#eK?c!y zLQH!}er+ZW0ukRJXQqRMKViHA{dRi1Ge#dZkmMs8Rj4#=zm*= zSvmc$Gr6{40bTuRmsG#cq*WAx1<+rG1UJX{!yDtz)!f7(ngGKU=-QXyZzds0NYXz{ z|Iv+yA2HEyqJNf~m45TKo(IqPqbU*M$RluD0`A73xwH>Ti&j0USgQIhRELuMlp?>)c>Y zFus};75e*z{wY5KPd{Fb-`AnT4ALCRa&-jPY7HRJP0+L@2r{cc4xtUhyh2_#um6pt zw7ou%n^XFYiMdscB6-WC6KTOi+hIw^t*F83H zfuS2nxF;7=IPVqRb(Jm%1g{mi8ozfR><5D28L>gK!+&q=M(N%S%Ye}oHEK`aY0|o@d1RIY<4X9GJu_Iwe`ivO_V9jw` zNDQ#S9#m@vfw_@UdP*?BvqYeYjGp7zH&|V*ZjoJ|aT}$yBpuB+iuP8T@i5LrnYnVz zxI?AVwVNsFGN21X<)-bXO4yDU<<&yl!kOXmxj<4fogfeiAuwSb|H$yq=mmqOO)?Iz z4ZuACl_EwT20(Fw6E8zf6j@cn!-Uu$07_G(HaDh|D4f=48vM3bI27hLV6Ts?-%E|n zGJeEA$4gcm&U2#9@1^#<4yK2-vYdQ+0Mr?>N5zLu6rlicasc|&lLc;U@9w{P2yfdA z`b_7#@B=N3^UJBK6&!B%Nm3V8BHE#b!1TsawSt8jfPN*0D*ugZiJT-US^;De>?{A& z+D(Whw_I)`8i1phasq)Olh{W(+~b?!j*G%EHabn&1%E$>05 zsiKBcTvI5e>+4z41vJqFD%g*-pGrkS8=}+EH6E34>flsBu|Jz`s16%>57Pup<8#7U zp@>b?0NVpKVW!d}v-`{L-o#j!J~$_Cdrr z;!Z{eQN@-<(l(t21@>=$V1p$*Cg}p>Clieq0gl5dTU#4!SNg^t8Prqv-e5V1z|ZnE z&DyO}dg9M`QbwiKgU+U1nST`_2h+gK_o1VTHO>W7v=(VE*Ji1kTccoMJZ8{yNjeKR zVEG98zp7WQmbR-^j_V)jt{#vKbM#^G^Fy@S5m6FfGYaWGoXTp;OH@=>yhw8SY|}Rq z0gR*aP%=*`rd{KTLPhQ2g!PXx>sBSW#Bi0v2qxE;V^ECY#>xfPROfIMk|mR$75QuM z!MGjhQ2FZtoXC7Aup~J0*YtcU)(w|KwI(H1B{AL2)SII{JM}&LkdV4!seV26NRZSxbcyjCHAQZ-;tknO2NhC0anj~ zs4=}C;9`SYgi8)kdaX??trng;&O`n}Ps6>!MqiA!3z2i(Q2kyoH#;9m>sH0lp-v{l ziIcG?ra4W9nxWVYDL1PyOWTurP$bwwTq{-y}}9$hYXL3 ze1_N3x{LeJv>ad!)tyvamok9}PjQH;Sg}=wEt(9#u zo`<1J{Wr@uC7JnEQYa^uL=1@^k!tzjcDal6{g86!?m=R`%Ri?KZAJ*f$&~7WF-@c?v^ustz+`h=)gdZJ+{f@3?dN>26W40;8HP(2XflQYyI1wi#;sCO``DZ=<%A=sSCUFk?;PEthL|bVB>T?+ z!K)~kHeVdwB*d%ZdO4b20NY?)>eHP`BfA@e7}ahXyM5q=39IzX)y)h0t+l`0^@{yG z5}0um)XI5qNRBi4U=4vfE3LCZ5qJ`?QUdT9mGCv7drJ210>@A8V{6!N;4^8o1FmvR zocf;@&vmonmK0Gr2zUJbU#a|`{zvaE=cm3LSII3;T8s^*8)2Ui@c$M`2s#@C;UAH< zRjTu~z=42@$r3MN83Cs%WcWtCu4nK;&W%%^T@Rq>g=eSEzbG6eRYy#l7pmXRW@Mp) zC}{3JW}QbO;q@QV62@k zU}XI~c)iD<7;O`3!HS9NgH-b0-2+(9hKPg(27+Qm{h77h z4)JY4L}evFiu(08%HLzBj8RdLcu$HDmID+`UG!CP0yPvu^jWm1{qqJb| zWWCF@OT&(Jt0iM<=?zh?<|@Q-vX#0rB?Bf^`rVIzE{uuh(wm8J?!Rcu@I<+$d68VZ zcJd+kFy($b}r1&P! zC(8sjx(mlM9Uxv=LV^&bMR$daiL>qpnTv#FkS6J{4h!fvZ4Y^P-DUb!Q53=`Nn3rc zC1|nTTp;tpCU9HUifnXH)bEQstlng7uZkXND0aAFvfWMKEPV|^&9p~@%6;AYtYcFc zAZvD_obpGPD|v}Oml49J!^`J=q^FjVAXwH|37edP*=#nYi9Yh3$~b|r$bG!;^C(9W z!cHey3=6Q2JCPB+)y|;8&#uafuO+bkb3{^jm?2{^y@o&vq zD>?0(y z;j&9MLpWmmVx~C7#zi9Z?S4x6s$)=(x>@U-hQ|PbqKeHB8zu3gzlWa}?%YS&#K|>o z+z>fJ$$2Y+w;gKYCwO@*KE4J%zGbi77)wu0%07*?e3~hIn5bPZD6R6YjQPecw{fC6 zV@`+Vu41Nc(g6--Nl^qY>}Wdm)kYBx3G0w@uc=rDG7F35aQkN|wT#(kcb=tC$AEd^ z(*?k3G~$>!RumIq)mn~i0i_L#l0u`h0JeXPoDsrUaUtWRU(_RB>yIP=tk1Em*goWV z;So(fH)f^sA0x71Erl$gq$=i}200~z%6S?!R$m*WD0?z+akbPU-1a*CDezwirLqcX!#N7zW60=W64rkU z(~RNuRfyYXfk;0yuHJ&CN*F!~OjIGK8RX7!6Kf&Gs_xoGle-GRnP_Q^EFrGwnHHCe z#!W|f=v?DXsGCiuUu{(%Y5tt|j0XV51~8TQcj|wrYQs(kjD@A$F^%rZSI6@9uw5)z zBPdRUyTdL1bxu_K>sVrx#SmWOV(kgfvIprQdMOOs!8}xq;*NQyCM*KRkV-uT!HxL5 zsJH>VOJvDVGuSW*Sdecj$eS4XTOMzql?aTuF|{8}yRTi=M1t!}aW`YE+uv-LX~J*1 zF0(4W;<_EhFla=MN|J2NP^KrltQ-lZ9jZr;(9^l&1@b-_e#Hk7WSpquLB6(oaiU%a zx^*t{8=T`qG{VONr7Jc+eGA_&2B@npT5_n5`{NAoFZWfjmUZgz_)eyi#CT+Cz`Er= z6H>?(s7GjSJ@9&C+5Ua+8Xb$x)O=BBE!(+?LRL6Ejg)9YOQBqkqNMp|q;3*A6iY^W zY&yVn09;}TB}J`7ZTpTRWM|lPf6hHfVp(g0Kj{Uz{>d~#>#=?)Ln9=5{zUy@(6XQW zXCqn{=b+wv2yM8#X9^ydp~yTE;L>&+PDmb2gbFvcoyrj{5+r*9a-cj_1+=Men72}h zxsRSQ5VsbCo;_p&N4uMxYaYorD3?s)r_>qR<)o=dxAY#Ftl1rl#Qe+H$g_wYZV@PI zaW%S4vPU0dGm2yeWsLrW>WrlBBK^LhW*OUin(s(!>uhKrxWD!SAl_l5gRO0GV^aB;Gk%iqjHB6 zJfKxR4Ie4LqK>`I!v^q^1o(B=KjeDz2*X*QjRG}(K%j!J~yQ15X=aw{GhOSjt-K8@yfh* zooy4vOS~rQ2(%l5=B*NAK@p&pkekXVRRFBGXK57KE-EPnE@v*TZjvcZCh!Vj1d-HH zuG#)qc{2z8&*3D^CTxLpKhNy4)_F1YDlj^I;T6Npt&d6W@ufx z5~m@0zP}}Q@)=`Nd@$DLG+*@JCGed>K+tGCD#{GChiu6D`X|u?}PT`XE=M0IRao>6M>Vc z#DxbGhy&pSRs&!(l1R`}gEF6lTB8%3^(8>^ZNP=ep<7o~du1d*R+>T79e|UDLJvMFbg-}r^~4YT@T%Sbtl$EW5~=k(c8UqVYdSh&wW_53Z^eTt%u zZV#>nk3unt=Ha9vk%(o~hylO_bmS+nh=$jnq`WQi0KG$+x%*sx@Z;|u(t{6=kQiEO zs->+#{3M4ct)kCGdp;pNPtuRU5xk1csn$%~q4~HV+Qogo{1`zboFH1}Q3%7syi8TC zvD1RJP6?dzF#F58a@M)YX;E`&LPJvF?#yax7BY1+x#+Voo!$UCp9P?#C)qXPByra6 z`q^Z)uDpNNeE*WRNN=N2V1o_ma#38pY2}7fa(Sv!@KWY*`ADbT5d`jnrlmEO2zUQO z&%PVvs{7C&><7*D=d=3A?sNgP$7-Pyfesyw{=_g(WaJuJWTDN47W%A(nBruptLB5| zN%YI0b7QY0W9~4=aUY;*vz^DKXT{@H6T+o6_n1bj=fmL<5&s!GhO)u~Cup;J2Ro+- z;&9b{42NT5X508sY4*vUr0LkeB?n*L%kmY)n}zGaV`_k9!YCs8mU$TO-9)3kl#WL5 z{Vte;Z=}GfGr4=CAw{-Ypw-m$}w;O5e)c1xJnP1?}i^~Q0zi)Tvr zVmh~ci(oeDrNYln? zjRWa(8t%(rWFaYa%s@J^(SJ%yIVSXGK}(x{SrI2WCNv zW#$3jjx(IJxjN8Zwv`u9*S2ZMX61)%z}>(6C&C?!6maTM(Ax5*!=bt(>wnX$v$$#* z!&`~_GYge)^e;C&g=m5Q2h%lSE^<%M4?pPOq8S~;zaJe>(OtNuNd{-{)UxL*BB=d% z)|K`xj)*suE5eOUrZlSlyY6su5++LO40zrWi^&V3<^H6*r3_dA_K)3;nU*KS7B|on zMBDZ?he)7fbm-c=3tdf(XW{VOM&^v3f)1f3@{BIAiGv_*yUafedkP*i!Y7yPDKoAwsA^la#E`A zR9N2NQoa0TKqEnkL8h(Qqyi%bh`x;r^2X$wx#FkRmuz*JWM<=ALKIW zim<;<;VKye1SQr}Q^4ym@@h4qQ$Cq7P+ng7)1J-i6E(^1IAh6p3GKEYAP0N{Uh$;u zBgCU+86u#j`h+QzYcYGm(D4Ld5sE<|M-T9Zln+B9cJ}h|AfLarAg*EY?s>WI4;?CYyOMCV6h8m>looVVnRH!Kd zO$v-v51tJvN@eJ72~!PR;YWuQ0)LYeo(3xqRa1W?N+gqzrhA%@D7F3R)%;bokyIr@ zX;Lv>fw8Kj`7K!~T1!V6>ex!Vq(Y_wZTWb`V}4m~wItO;e%bbb)Z8KI6^5P8+=Qu` zIN_P066bgwPJ}wNY7t71&4KV5&c+9T8BMF4S-rS{2D}QGf(w*}GfTXcO8Rs@w{eG9 zy)V4r)UPUgGnElVU#Q?;$!T`*J${}R_|b1^c-twOVjt_?rT0ryc~?lrX{8{ zFYD&~yEOSN6TAeu?I4ot9(p_gOk7sFPkBvE09;R(Lee^v<^)oskfH%=%r&mzK5b5| zk#*?lhG695xvL)sgBTH9H)xE{ijd1DHB2yw>+h>ms!OpOhpll~!!qt!C^cl^^rV$P z1!gbJNxw`24jU7I(O>L0Q%1QCZfI^eLECh7ZJ1U-IY;Y*Ul1f$xL&MQn-Mgcd4QKSBR}lh#v4)i{L!0>Z>e%z@vAO*xYVd5VS`Kv@E%`(klJaso;r~_2s0L1ND!a2 z{vFPIxjOIQ%j_k3wm^jIZ(bKip9H;AaRZ@zJYdlqkw@-sNC-XgtiwwZ5a|LH^22NH zZ{{S@9NuR$zb%(=rrnllbm=V_{*D<>4jGk;Ml5F)gj%yujJ)DyhX~RMR& zPlYZv^basPa)2tlvFJ^Z7sPY0GM`M^Bl%@yi+ThnC|nKYJ5ypryYj0|bSIxL()72z zR~F|P{q?LFM^7hTM<-toXAiHJL9IPvPwhz#=?ebkb$0X;WM1mSwBf<3ZcCIlc5i!i z3#1J?Aki(@D#{$pk?rpYu|nw#aXeJNaF(zs_nb4o@!Wv7>1e&sc~cf&$Gb81g^{V3 zJY~JIQ$12%1^De`orf6B^3zj0m>#@QY~Iu6J)MeBwZJKUu0;K&d>_>5nX{55Fc!G; zUO?0<@Us%siN+mt55H)6reuEAJvKanOBLTTKodO7eX>AwD%E!1|IVStv}MLc(>`W4 z$u6O8dVow`C{7~R7qdmd?9VUh)L*^tX841rLqqvD`arDw_Pd~Xg6J(Q^W?x^*Zb8k zWrTi)JfiU&ZlGoKqp@Y{0Tb&BjLQ&Q0>eKK)ZYh(@M!SiBW9v!g2} zE&hII)43=iuQNqxKWhvuVsIC_kXmvrP~sHa=d1d7;YQJK$v3C9Z> zbwBnIFD6-8>c1G9k&SWrOdW+F{AR#Vr)8M=A<+;xxTH-vg+F8xP!V&z?rQH70a&Lk z$!&0E@H4`cZCDD~{4Fo+d|HyIJl<;TI66>w7A!5P^}01Pi%-SCVaI{4nTh&EUq1SDbTbbx~l(F+XO_O?)9WJNnQ`KGz~?P zbcdpeVqM^gtN52JU0e$?l!ckWWvHbX(ISUB(Fmc4qyEe;$#sfRDz##ax|w@v4-A7W z?YeQ+=yiEq%z8;kz4?`U=PgIJT8s3F3o)t zKiAyv-lsWN1nPCJ7wY?V_}u$7)7NMB-%?Jg&M)tuPiC#JcViP#)4F)GvO9Hl0o@OF zI?to?GC|*kq&ctFaEl;QOmq)6sz1;$0R>vE`K^?k zpafwLyUEpVGUOCN3{dx1TH^IlA-$byYhCMP)3NY>Kx%pizoS5;odlTmRYK>3KPaLN zQ8X8Lx=}y=x!h?Wd2W7fdqq^7F-=Ri!rOOO!;ikvp0%)8yoN@U{VWISHn6>6A9=ft z;{|sh>9%8bHW#ymEz_c0-<-F6buECHMp$yn{xP0Gw}heCqv~#y)8eO%vr2KIXujTd z4cMsj2NhS06=Qk3k_F7WKyOg5_c#<(@Hfo;p=Voj9dzsIAvNu?4^?f=k1slEpisAD z*D76PXYVOodC$N?g%J1&a|qmuRCm(5S7J4|+@9bW;8Wig=+1ih?45NN4p|>*qq1$3pm!pzT=q-hN}qQSLh{yr zmU;t=C7=!VgxeN*wK8|>t|RsyG*&bp=Xs^Sp7hUI;yM198NtpWOp#*zy@TLiD~-Qr zKg!NQ5<(t+OoVeHN2=xb2d(sJ-k@v|lJxxsl|EI9eyYP{Y;I`#sXn56s5jjOHl~;Q z1^NFX5%E8BOlQ^dBYjXHATa2}OIdem=dUg;O*>#+vTl*T=mh40BF?-gG%R zIUrj%sN>_Olgpqwi^pA1D3$r?2m1<);JI2GmEA(sln-H*(_D-!hz)L17)X9VP`sg1 zUa+Jlq*j3yRWK@s&NM-M6(mGpHS74V3IeT*TC%Wmk>_@g0J8I<)fOHuT|zH{x7B9B zyOp-OeVlj_G?xK?30D1WgFn5hxb{Ih`Ka~vTj7yTo(awpPla%*njGFoO6uV_f_B_V z44c?PPb-pvCJ1nBppo!d3ii{0!Z`4ej&5CNnkf6VI0I4`Fbg4htvOYM#(t)5$V;{E%Z-%kO8U8fqpQ{BaD$crDB(=)DtRqn zU1dR@SZX2hKT{mho*f^k$2$tgbNZ}QWp6iJRNa2a&x@~pm7Xn^P{J0=(da-$_|EB6 z7XE^qc6%TD;riEDMspe?yBR0|6x?CxcTtcdV#2bn-2G?iMt%cXrLBzL6~-K4*RtO) z_R@I?i@ST^I?l|&$HP@P07H1j*%TYI`!n?>f_2C4l>zQ|_YQrEz+mwM@>^Tmxgb)t z(vp6JI=MqaHz~io2tXF;2FdjRP2cdQpByuZuZ8Td9RF0`)Y+&6Z6X_jolpDpHys>T zBXxv4msiuf5{x+*7zXwwaRRxrBzUK~1>J9!L3r!@DUev#!teJ zq#xi+ydcpsy$jzt6LTIqACod8gTIeZl_rp$mH{}_$X&dd3u}KXf~RU#n`JGXWSEsgk+3L$e+jPDsQm9$<#oy zdCZ1~?<#hQyXBNJ&Wtf5>=SJ*l_Y?XXkXl3USw@)4OiY>8UnYUwPV_ zee!dWO`B?#L{EfPERxa{Qra}PxXcESRAt2wTT=%!|1w3+Dk5u&DR-Lh&B27nKEiX$ zvAWI&$U`ptz*9RiAN^s$--#?(BGiefTg@U_`lRs{WR2GB?B)!t$(*Ktl_b(4dnx~o&swO81G zYi7j|-bntfSr>3(7&qg$WD5UC7W^$4;_=XG3Vj6$lr28ohW!6Xc7d@(PHMrvq-QtJ z!5Rn4`NYkhx*(SThM2gDs*ACI41V4~2=PG%=Qk9>gj1D7levo&JkPBwsH9?Lafvq@ zrz$H3qvhIolwM=u{vyJq7+J@ z&3{%*ixzSuM=Xq%uUE@{3@Xwe{Pb5l$H3pHJ!9C|8#H;}_5Ou(BT~EGXspj!!8z00d_eqL!$bGATDWfw zBY+cS_!z!5)cMvBEBFfb1u@irO*M57t#btuZE007JwIC)jnPo1rM8-0qNN^SmtcD$ z0y5?yJMD$?+#Smyse6+XVn=MDy1yx z*}LLOZPD{Enhw3&eY?R+jLmbz1?L6wUKITUGR4`bXm7SyqBsN_}8zojxF*%b5KVmh)Jyj!HVX z3SgLy=h+^YsBy{eJ}L6;%*mbT_y@81m0I+#{~&hIp7#=yVlDF&bsu*24`Sq*D;&L< zBa!Bb{~%^ZA#i&ePMktlaa`m})u3mh6s03Z5VQsOuNcT|o_`GZR%;go2nZ+9P6|EI zKok#Pqo^ZwCV=FFc)*`^riAK=iS z+K!)2(^=^fDaF*bm~M#fnuoEp&sHHE+>}`HLd25P*L`JbQoFy0V+$g?auVZZY z$fvdL{@T6q*L9=^(eWEB9*>v2xO-lX5%ML}peE=9UnNOna*)vc>6zhCRP$!pmg13| zTmyG@(2p!0-|bI90!QbJkK}Hq0C8R-2p7ji8ChQ-Fpl19xTBbUz+WYnBnyib&9@aw_d`w zP0#S3@ieq=Gl(RrbbO_!Ni_~M23qw&`7V;d%3bYdbJA1_;9SnrdxggQG&y@<1^s8# zC{YZ7K?Q9*kWN5z(@&ler1E$c%OPF(YAzeWjQ_?O_*EFe>AO%9Ac;HTtN<6qb<4ni zD)fw4G9OB1K~~e|Uq?-!q`1Zd7BE_#DXh+VUfuQXW44@D46U-^Vm3XQ^|QhM>djr7 zuV>E(y}L?ar1uoOdjV9{E9NCj;zb?``Jw9+tz5!n^CW+7B|!ljOQ_i_!6ZWpDa~iU zVb+U^fn)Xd=M^L>JfR;Vz)c9%yxV3IJUGo@zaRg%mZ7=fwbuO3PYN*Eqz!OlA;g3; zQPsa`16Up8moOqxj*EZbe`#F^WJ$^vqB;98OrXhA;TFX^MqMfvyZaVeY3|=o_fnEH zgV-A6_Vz5op>hhKP~h@YtPl#*ZWDEeTllcY9Zq~W-~s(Hax9S!0fciNvnG@TEyloo zbW*(?+*HCg!+97viY*ORY+Tx8o}|JR8X7L9u|FT9=)Vk&2mWS@f~PafATGlprVCGb zYF8PIBWZwkFlX6FS}=Y|8(xtsEeH?&oV@M8(r*njm$y2r_qUef#onixJsm5q_nNq9 zm*W55iu`9WG3_!KeDJ#@2B3-7QXJnUxw2bhLi&gq{JLI}BQq3a;uF+@wvo)5LL*8-I%26{o6H{I;Q(M?v6Djh zX#>yskj0&X0-#w}{{nRjfArOi=kAIx^eMfZM|vB{yN-iVe#K*Jjl!_6$i&}dU8U!G zzDOJh{y0lz%8jm*)E|Si(hkj?*=xCCaIZ-)%*(>1$q}*tkg>%zkhYuMZo-5Hm6HB@{%Blj_?!`|^OEUZi z<(G$;`j_g1NCO)zG;OjPM+IbradI2jOwI3J|BJx-qRczdwHI5CQ6@tn3aQ2vo)A#n z$=h^FcEL0CVp2j4Vo}u6{H?K%^jG6EbdfFtW9C&≪-d|Hq{@tHln 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 A%K!iX