mirror of
https://github.com/yabwon/SAS_PACKAGES.git
synced 2025-12-11 11:14:35 +00:00
Compare commits
249 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b99a5651d | ||
|
|
7e5c98976b | ||
|
|
9f4143af53 | ||
|
|
bd8e378829 | ||
|
|
dc3bedae3f | ||
|
|
af94d49a79 | ||
|
|
4069f066aa | ||
|
|
266a1fe1a7 | ||
|
|
3111b6667e | ||
|
|
e3b86f1157 | ||
|
|
c9b388b661 | ||
|
|
82681a3f91 | ||
|
|
cb4f82eac9 | ||
|
|
98e2125028 | ||
|
|
77d6b0a2e5 | ||
|
|
c1182ea8cb | ||
|
|
ddfac01483 | ||
|
|
d8c8cfc9e3 | ||
|
|
c126e7c0a3 | ||
|
|
e7883142b8 | ||
|
|
e55275d308 | ||
|
|
72a77edb16 | ||
|
|
dbe8dbc938 | ||
|
|
9168f4b4f0 | ||
|
|
2f5cb056b1 | ||
|
|
44be31bd84 | ||
|
|
227e522f5b | ||
|
|
9a3ff6a265 | ||
|
|
62a14b4560 | ||
|
|
0bd2f6f2d8 | ||
|
|
e3c42e6441 | ||
|
|
8807a1560e | ||
|
|
a282349c86 | ||
|
|
6dc4f22103 | ||
|
|
2fd23f5b35 | ||
|
|
f3f4747df6 | ||
|
|
edca6a8a8c | ||
|
|
f59c2a4893 | ||
|
|
b4314c03e3 | ||
|
|
3a824b4d8b | ||
|
|
ba4b5f8c32 | ||
|
|
15e7d48adf | ||
|
|
a5b4f117cc | ||
|
|
b3ea02b7b0 | ||
|
|
e4dfc6a863 | ||
|
|
7d083e879c | ||
|
|
35e6ff8d5e | ||
|
|
5bd013c925 | ||
|
|
2ad317db01 | ||
|
|
6c38872ee2 | ||
|
|
d35ac328cc | ||
|
|
e3a813b257 | ||
|
|
67bd3abd58 | ||
|
|
1968330049 | ||
|
|
7e202f81ff | ||
|
|
26d9c735fe | ||
|
|
11c0b95d7e | ||
|
|
be89c6b9c6 | ||
|
|
17b1239087 | ||
|
|
bbba37d8eb | ||
|
|
6ccc07a5bb | ||
|
|
b5e15bda11 | ||
|
|
160c1bc9d3 | ||
|
|
76297dc5d8 | ||
|
|
ea866123d9 | ||
|
|
75029a488f | ||
|
|
642bc5ba72 | ||
|
|
6d10426474 | ||
|
|
7048adb3b6 | ||
|
|
5ab1f4c73e | ||
|
|
4452d9ee7c | ||
|
|
df04e48656 | ||
|
|
76c7793e34 | ||
|
|
cc6528bbeb | ||
|
|
2bb633a55b | ||
|
|
10009b33ae | ||
|
|
68e85eb5ba | ||
|
|
0778a71ada | ||
|
|
0cf35c15a7 | ||
|
|
00c63c4d8a | ||
|
|
9dedc53c31 | ||
|
|
a7d61f6026 | ||
|
|
9f92b5f5d4 | ||
|
|
a95c672693 | ||
|
|
9bccc4329a | ||
|
|
b76b1ed9eb | ||
|
|
942879a5b8 | ||
|
|
fe631f9e44 | ||
|
|
3f380b4e64 | ||
|
|
02de8f0bc0 | ||
|
|
7fa70d5ad4 | ||
|
|
98e822bde2 | ||
|
|
2026254b96 | ||
|
|
9ff8fd506c | ||
|
|
7be17a3a57 | ||
|
|
e2e54b8025 | ||
|
|
cdf07fc232 | ||
|
|
bcbd078b7d | ||
|
|
c12260fdcd | ||
|
|
b45b79fd3c | ||
|
|
2ce8a83499 | ||
|
|
59cda13330 | ||
|
|
f7485ce6c4 | ||
|
|
8f3cbe1b92 | ||
|
|
bc36780cee | ||
|
|
3a0fc83433 | ||
|
|
b8905ca4a7 | ||
|
|
47426131a5 | ||
|
|
8a23978694 | ||
|
|
f3f3bc3688 | ||
|
|
c2e06995f5 | ||
|
|
40f3a00cb2 | ||
|
|
6f1f30fef9 | ||
|
|
78f202b150 | ||
|
|
97d393bb71 | ||
|
|
98af4c8bc3 | ||
|
|
c04d9c4eb2 | ||
|
|
8b65e85f3a | ||
|
|
582c12d908 | ||
|
|
742e4ac3d3 | ||
|
|
74360b4cca | ||
|
|
aba2ee4f44 | ||
|
|
55f4e35e0e | ||
|
|
50f307f370 | ||
|
|
3cd73a858d | ||
|
|
acd3a4872d | ||
|
|
36b766da9a | ||
|
|
b1e61b587a | ||
|
|
34b46d1e85 | ||
|
|
41a314d3f8 | ||
|
|
f021a2fd08 | ||
|
|
9277a83561 | ||
|
|
e505c3658e | ||
|
|
222d88511a | ||
|
|
ac10ab21ff | ||
|
|
c45c0d9921 | ||
|
|
0a9d070055 | ||
|
|
b5564bca76 | ||
|
|
740ce9b04b | ||
|
|
afa8ebbacf | ||
|
|
c1f60d112e | ||
|
|
68e1562c19 | ||
|
|
0bd4f69209 | ||
|
|
9b6a567298 | ||
|
|
2a773d0994 | ||
|
|
c716bf5789 | ||
|
|
40e8a0806e | ||
|
|
d2c445e395 | ||
| 370bfc52d5 | |||
|
|
1b036c94f0 | ||
|
|
fdb8e8b47c | ||
|
|
c1b9344e86 | ||
|
|
4eaa1e63ec | ||
|
|
2730a9438f | ||
|
|
975a48e242 | ||
|
|
ba4a49f95f | ||
|
|
e00353e693 | ||
|
|
7c1d58c165 | ||
|
|
02f71de424 | ||
|
|
bfdcd238ec | ||
|
|
252c15b1c3 | ||
|
|
a77e99adbe | ||
|
|
7231049666 | ||
|
|
2f743475f6 | ||
|
|
cb59027079 | ||
|
|
a93881f5d2 | ||
|
|
64e7dafa72 | ||
|
|
b373917770 | ||
|
|
e7d94ad030 | ||
|
|
cf2ab0a7e7 | ||
|
|
b113b47869 | ||
|
|
a9ae379b59 | ||
|
|
5ecccacdce | ||
|
|
b274d0dcda | ||
|
|
3881f936ca | ||
|
|
d53f622776 | ||
|
|
8c584c8030 | ||
|
|
5c640cba21 | ||
|
|
73e8d10200 | ||
|
|
93904a03cb | ||
|
|
55aaa8748c | ||
|
|
63f849dd24 | ||
|
|
ef5864dc88 | ||
|
|
c10851e9ef | ||
|
|
10994721b4 | ||
|
|
5461c587be | ||
|
|
e97c8e31ad | ||
|
|
16d55d7dcb | ||
|
|
c54ef20fac | ||
|
|
be2af5883a | ||
|
|
b867ed4309 | ||
|
|
6a53bbe50a | ||
|
|
3e44e6b8ae | ||
|
|
f3f7a3896a | ||
|
|
7491d42378 | ||
|
|
16a20907af | ||
|
|
f3107f0db3 | ||
|
|
0ca3eac3c9 | ||
|
|
4eac2a0fea | ||
|
|
ad81e0cb0e | ||
|
|
f542d70332 | ||
|
|
80fdc9f214 | ||
|
|
f23afe7486 | ||
|
|
e467959d77 | ||
|
|
035e184b74 | ||
|
|
61d5806e79 | ||
|
|
98871647dd | ||
|
|
16b744a763 | ||
|
|
4765dc5c43 | ||
|
|
e1c95da0b7 | ||
|
|
319dd8c46b | ||
|
|
96555584a3 | ||
|
|
a6cfb9f93f | ||
|
|
63b30d7b6e | ||
|
|
eef8649f3c | ||
|
|
4511c812f0 | ||
|
|
5ca878d178 | ||
|
|
5c042cadff | ||
|
|
3eb09f29cd | ||
|
|
da3c8df259 | ||
|
|
b9fa8fc5d7 | ||
|
|
1fda328de8 | ||
|
|
322a951290 | ||
|
|
b090fdbe8d | ||
|
|
42663d56f7 | ||
|
|
bed882582e | ||
|
|
532f1ec90e | ||
|
|
861c5d866b | ||
|
|
f22d06fb42 | ||
|
|
c0212cb8af | ||
|
|
4ae8f23716 | ||
|
|
7fd4dd9774 | ||
|
|
f41d73cd90 | ||
|
|
863d6cb251 | ||
|
|
790816e229 | ||
|
|
88ace7321b | ||
|
|
f4ac0f1fe3 | ||
|
|
eb5cd6975c | ||
|
|
b975f75ff3 | ||
|
|
bb22a3e274 | ||
|
|
f981751c28 | ||
|
|
2f110adf1f | ||
|
|
5b1f8a3aae | ||
|
|
ef6473ad35 | ||
|
|
e30261410e | ||
|
|
3ede4541fd | ||
|
|
387898e01a | ||
|
|
e801f99e1c | ||
|
|
850e003ea9 |
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) since 2019 Bartosz Jablonski
|
||||
Copyright (c) 2019 - 2023 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
|
||||
|
||||
250
README.md
250
README.md
@@ -1,4 +1,6 @@
|
||||
# SAS_PACKAGES - a SAS Packages Repository
|
||||
# SAS_PACKAGES - a SAS Packages Framework
|
||||
|
||||
---
|
||||
|
||||
## Intro:
|
||||
|
||||
@@ -6,101 +8,225 @@ A **SAS package** is an automatically generated, single, stand alone *zip* file
|
||||
|
||||
The *purpose of a package* is to be a simple, and easy to access, code sharing medium, which will allow: on the one hand, to separate the code complex dependencies created by the developer from the user experience with the final product and, on the other hand, reduce developer's and user's unnecessary frustration related to a remote deployment process.
|
||||
|
||||
In this repository we are presenting the **SAS Packages Framework** which allows to develop and use SAS packages. The latest version of SPF is `20200730`.
|
||||
In this repository we are presenting the **SAS Packages Framework** which allows to develop and use SAS packages.
|
||||
|
||||
Read the **`SAS(r) packages - the way to share (a how to)- Paper 4725-2020 - extended.pdf`** to learn more (see the `./SPF/Documentation` directory).
|
||||
Don't forget to **STAR** (:star:) the repository! :-)
|
||||
|
||||
**General overview video:**
|
||||
- SAS Global Forum 2020 V.E.: `https://www.youtube.com/watch?v=qCkb-bx0Dv8&t=0s`
|
||||
- Sasensei Internationa Dojo: `https://www.youtube.com/watch?v=BFhdUBQgjYQ&t=0s`
|
||||
---
|
||||
|
||||
### Current version:
|
||||
|
||||
**The latest version** of SPF is **`20231024`**.
|
||||
|
||||
To get started with SAS Packages try this [**`Getting Started with SAS Packages`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/Getting_Started_with_SAS_Packages.pdf "Getting Started with SAS Packages") presentation (see the `./SPF/Documentation` directory).
|
||||
|
||||
The documentation and more advance reading would be the [**`SAS(r) packages - the way to share (a how to)- Paper 4725-2020 - extended.pdf`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/SAS(r)%20packages%20-%20the%20way%20to%20share%20(a%20how%20to)-%20Paper%204725-2020%20-%20extended.pdf "SAS packages - the way to share") article (see the `./SPF/Documentation` directory).
|
||||
|
||||
Short description of the SAS Packages Framework macros can be found [here](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/SPFinit.md "Short description of the SAS Packages Framework macros")
|
||||
|
||||
### Recordings and Presentations:
|
||||
|
||||
Videos presenting the SPF and packages, from various conferences and meetups (the newer the better):
|
||||
|
||||
- ["SAS Packages: The Way to Share" - SAS Global Forum 2020 V.E.](https://www.youtube.com/watch?v=qCkb-bx0Dv8&t=0s "SGF2020") (April 2020, ~20 minutes, general overview but with a bit obsolete technical details)
|
||||
- ["SAS Packages: The Way to Share" - SaSensei International Dojo No. 1](https://www.youtube.com/watch?v=BFhdUBQgjYQ&t=0s "SID no. 1") (April 2020, ~28 minutes, general overview but with a bit obsolete technical details)
|
||||
- ["Co nowego z pakietami SAS?" - SAS dla Administratorów i Praktyków 2020](https://www.youtube.com/watch?v=mXuep2k48Z8&feature=youtu.be&t=0s "SASAiP2020") (October 2020, in Polish, ~41 minutes, general overview and technical details how to use SPF)
|
||||
- ["SAS Packages - The Way to Share" - Boston Area SAS Users Group webinar](https://www.basug.org/videos?wix-vod-video-id=78067e61413d43d3a6951974b3bc3014&wix-vod-comp-id=comp-klv807gt "BASUG") (November 2020, ~59 minutes, general overview and technical details how to use SPF)
|
||||
- ["My First SAS Package: A How-To" - SAS Global Forum 2021 V.E.](https://www.youtube.com/watch?v=hqexaQtGw88 "SGF2021") (May 20th 2021, ~30 minutes, technical workshop on how to create a package)
|
||||
- ["Kod SASowy ukryty na widoku" - SAS dla Administratorów i Praktyków 2021](https://www.youtube.com/watch?v=LtaWPe2sgRY&t=1s) (November 24th 2021, in Polish, ~34 minutes, technical presentation with details about the GSM package)
|
||||
- ["A BasePlus Package for SAS" - SAS Explore 2022](https://communities.sas.com/t5/SAS-Explore-Presentations/A-BasePlus-Package-for-SAS/ta-p/838246 "SASexplore2022 communities.sas.com") (September 27th-29th 2022, ~28 minutes, technical presentation with details about the BasePlus package), alternative video at YouTube is [here](https://www.youtube.com/watch?v=-Poxkx5WfOQ "SASexplore2022 TouTube")
|
||||
- ["SAS Packages - State of the Union" - SaSensei International Dojo No. 13](https://www.youtube.com/watch?v=1GEldZYQjj0&t=0s "SID no. 13") (November 10th 2022, ~50 minutes, general overview with the latest technical details)
|
||||
- ["SAS Packages Framework - an easy code sharing medium for SAS" - Warsaw IT Days 2023](https://youtu.be/T52Omisi0dk&t=0s "Warsaw IT Days 2023") (March 31st 2023, ~60 minutes, general overview with technical details for user and developer)
|
||||
|
||||
|
||||
---
|
||||
|
||||
### Initiative to add SAS Packages Framework to SAS Base/Viya:
|
||||
|
||||
A **SASware Ballot Idea** for adding *SAS Packages Framework* macros into Base SAS and Viya was submitted Friday, May 27th 2022. If you would like to support the idea visit this [communities.sas.com post](https://communities.sas.com/t5/SASware-Ballot-Ideas/Add-SAS-Packages-Framework-to-the-SAS-Base-Viya/idi-p/815508) and up vote the idea!
|
||||
|
||||
---
|
||||
|
||||
### The User:
|
||||
To use a package:
|
||||
- Create a folder for your packages, under Windows OS family, e.g. `C:/SAS_PACKAGES` or under Linux/UNIX OS family, e.g. `/home/<username>/SAS_PACKAGES`.
|
||||
|
||||
and then either:
|
||||
The first step to use a package with the SAS Packages Framework:
|
||||
|
||||
- Download the `SPFinit.sas` file (the SAS Packages Framework) into the local packages folder.
|
||||
- Create a folder for your packages, under Windows OS family e.g., `C:/SAS_PACKAGES` or under Linux/UNIX OS family e.g., `/home/<username>/SAS_PACKAGES`.
|
||||
|
||||
Then either:
|
||||
|
||||
- Manually download the `SPFinit.sas` file (the SAS Packages Framework) into the local packages folder.
|
||||
- \[Optional\] Manually download the `<packageName>.zip` file into the local packages folder.
|
||||
- and Execute:
|
||||
```
|
||||
filename packages "<directory/containing/packages/>"; /* setup directory for packages */
|
||||
%include packages(SPFinit.sas); /* enable the framework */
|
||||
|
||||
/* %installPackage(packageName) */ /* install the package, unless you downloaded it manually */
|
||||
```sas
|
||||
filename packages "<directory/containing/packages/>"; /* setup directory for packages */
|
||||
%include packages(SPFinit.sas); /* enable the framework */
|
||||
|
||||
%helpPackage(packageName) /* get help about the package */
|
||||
%loadPackage(packageName) /* load the package content into the SAS session */
|
||||
/* %installPackage(packageName) */ /* install the package, unless you downloaded it manually */
|
||||
|
||||
%helpPackage(packageName) /* get help about the package */
|
||||
%loadPackage(packageName) /* load the package content into the SAS session */
|
||||
```
|
||||
|
||||
or if you need it just for "one time" only Execute:
|
||||
or if you need it just for "one time" only:
|
||||
|
||||
```
|
||||
filename packages "%sysfunc(pathname(work))"; /* setup temporary directory for packages in the WORK */
|
||||
filename SPFinit url "https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/master/SPF/SPFinit.sas";
|
||||
- Execute:
|
||||
|
||||
```sas
|
||||
filename packages "%sysfunc(pathname(work))"; /* setup WORK as temporary directory for packages */
|
||||
filename SPFinit url "https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas";
|
||||
%include SPFinit; /* enable the framework */
|
||||
|
||||
%installPackage(packageName) /* install the package */
|
||||
%installPackage(packageName) /* install a package */
|
||||
%helpPackage(packageName) /* get help about the package */
|
||||
%loadPackage(packageName) /* load the package content into the SAS session */
|
||||
```
|
||||
|
||||
**Workshop video for the User**\[May 6th, 2020\]**: `https://youtu.be/qX_-HJ76g8Y`** [a bit outdated but gives the idea how it works]
|
||||
|
||||
or do it pragmatically:
|
||||
|
||||
- Enable the framework [first time only]:
|
||||
|
||||
```sas
|
||||
filename SPFinit url "https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas";
|
||||
%include SPFinit; /* enable the framework */
|
||||
```
|
||||
|
||||
or (shorter) with:
|
||||
|
||||
```sas
|
||||
filename SPFinit url "https://bit.ly/SPFinit";
|
||||
%include SPFinit; /* enable the framework */
|
||||
```
|
||||
|
||||
- Install the framework on your machine in the folder you created:
|
||||
|
||||
```sas
|
||||
filename packages "<directory/containing/packages/>";
|
||||
%installPackage(SPFinit) /* install the framework */
|
||||
```
|
||||
|
||||
- From now on run it like this:
|
||||
|
||||
```sas
|
||||
filename packages "<directory/containing/packages/>";
|
||||
%include packages(SPFinit.sas);
|
||||
|
||||
%installPackage(packageName) /* install a package */
|
||||
%helpPackage(packageName) /* get help about the package */
|
||||
%loadPackage(packageName) /* load the package content into the SAS session */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
The "Workshop video for the User" got outdated (in general). Newer version is coming soon, in the mean time see some of the videos from the "Recordings and Presentations" section above.
|
||||
(You can watch the workshop if you wish, link is working and some parts are still valid source of information e.g., "`ICE` loading" or "`disk` loading")
|
||||
|
||||
<s>[**Workshop video for the User**](https://youtu.be/qX_-HJ76g8Y) \[May 6th, 2020\] [~86 minutes, outdated (installPackage macro was not there yet) but gives the idea how it works especially load, help, unload, ICEload, and other details]</s>
|
||||
|
||||
---
|
||||
|
||||
### The Developer:
|
||||
|
||||
To create your own package:
|
||||
- Read the **`SAS(r) packages - the way to share (a how to)- Paper 4725-2020 - extended.pdf`** to learn more details.
|
||||
- Download and use the `SPFinit.sas` file (the SAS Packages Framework) file (user part of the framework required for *testing* is there too).
|
||||
|
||||
#### If you have any questions, suggestions, or ideas do not hesitate to contact me!
|
||||
- Download (and use) the `SPFinit.sas` file (the SAS Packages Framework), the part of the framework required for *testing* is there too.
|
||||
|
||||
**Update**\[June 3rd, 2020\]**:** `%installPackage()` **macro is available**. The `%installPackage()` macro is embedded in the `loadpackage.sas` part of the framework.
|
||||
|
||||
**Update**\[June 10th, 2020\]**:** To see help info about framework macros and their parameters just run: `%generatePackage()`, `%installPackage()`, `%helpPackage()`, `%loadPackage()`, and `%unloadPackage()` with empty parameter list.
|
||||
|
||||
**Update**\[July 30th, 2020\]**:** All components of SAS Packages Framework are now in one file `SPFinit.sas` (located in the `./SPF` directory). Documentation moved to `./SPF/Documentation` directory. Packages zip files moved to `./packages` directory.
|
||||
- See this ["Hello World" example tutorial.](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/HelloWorldPackage.md "Hello World")
|
||||
|
||||
- Read the [**`SAS Packages - The Way to Share (a How-To) - Paper 4725-2020 - extended version`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/SAS(r)%20packages%20-%20the%20way%20to%20share%20(a%20how%20to)-%20Paper%204725-2020%20-%20extended.pdf "SAS packages - the way to share") article to learn more details.
|
||||
|
||||
- Read the **`My First SAS Package: A How-To - Paper 1079-2021`** article available at communities.sas.com [**`here`**](https://communities.sas.com/t5/SAS-Global-Forum-Proceedings/My-First-SAS-Package-A-How-To/ta-p/726319 "My First SAS Package: A How-To") or locally [**`here`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/Paper_1079-2021/My%20First%20SAS%20Package%20-%20a%20How%20To.pdf "My First SAS Package: A How-To")
|
||||
|
||||
The SAS Packages Framework [(short) documentation](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/SPFinit.md) to quickly see macros options and parameters.
|
||||
|
||||
---
|
||||
|
||||
### If you have any questions, suggestions, or ideas do not hesitate to contact me!
|
||||
|
||||
---
|
||||
|
||||
### Updates worth mentioning:
|
||||
|
||||
**Update**\[February 7th, 2023\]**:** `ADDCNT` **type for *additional content* feature and ** `%loadPackageAddCnt()` **macro added to the framework. (see [here](https://github.com/yabwon/SAS_PACKAGES/releases/tag/20230207 "Additional Content"))**.
|
||||
|
||||
**Update**\[December 12th, 2022\]**:** `CASLUDF` **type for CASL user defined functions added to the framework. Utility macros for for loading content in proc IML and proc CAS added. (see [here](https://github.com/yabwon/SAS_PACKAGES/releases/tag/20221212 "New Type and Utility macros"))**.
|
||||
|
||||
**Update**\[November 21st, 2022\]**:** `%loadPackage()` **macro allows Cherry Picking of content (see [here](https://github.com/yabwon/SAS_PACKAGES/releases/tag/20221121 "Cherry Picking"))**.
|
||||
|
||||
**Update**\[September 30th, 2022\]**:** **New dedicated repository:** *SASPAC - the SAS Packages Archive* **is available as new location for packages storage**. Location of SASPAC is: [`https://github.com/SASPAC`](https://github.com/SASPAC)
|
||||
|
||||
**Update**\[November 11th, 2021\]**:** `%extendPackagesFileref()` **macro is available**.
|
||||
|
||||
**Update**\[October 15th, 2020\]**:** `%previewPackage()` **macro is available**.
|
||||
|
||||
**Update**\[September 11th, 2020\]**:** ` %loadPackageS()` and `%verifyPackage()` **macros are available**.
|
||||
|
||||
**Update**\[July 30th, 2020\]**:** All components of SAS Packages Framework are now in one file `SPFinit.sas` (located in the `./SPF` directory). Documentation moved to `./SPF/Documentation` directory. Packages zip files moved to `./packages` directory.
|
||||
|
||||
**Update**\[June 10th, 2020\]**:** To see help info about framework macros and their parameters just run: `%generatePackage()`, `%installPackage()`, `%helpPackage()`, `%loadPackage()`, and `%unloadPackage()` with empty parameter list.
|
||||
|
||||
**Update**\[June 3rd, 2020\]**:** `%installPackage()` **macro is available**. The `%installPackage()` macro is embedded in the `loadpackage.sas` part of the framework.
|
||||
|
||||
---
|
||||
|
||||
## Where the SAS Packages Framework is used:
|
||||
This is a list of locations where the SAS Packages Framework is used:
|
||||
- Warsaw (Poland)
|
||||
|
||||
If you want to share that you are using the SPF let me know and I'll update the list.
|
||||
|
||||
If you find the SPF useful **share info** about it or **give it a [star (:star:)](https://github.com/yabwon/SAS_PACKAGES/stargazers)** so more people will know.
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Available packages:
|
||||
Currently the following packages are available (see the `./packages` directory):
|
||||
|
||||
- **SQLinDS**\[2.1\], 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.
|
||||
```
|
||||
data class;
|
||||
set %SQL(select * from sashelp.class order by age);
|
||||
run;
|
||||
```
|
||||
This section presents some example of available SAS packages.
|
||||
|
||||
- **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.
|
||||
- **macroArray**\[0.3\], implementation of an array concept in a macrolanguage, e.g.
|
||||
```
|
||||
%array(ABC[17] (111:127), macarray=Y);
|
||||
**(!)** Since *September 2022* the default location for packages is **SASPAC - the SAS Packages Archive** located under: [`https://github.com/SASPAC`](https://github.com/SASPAC) where each package is stored as a separate repository with historical versions too.
|
||||
|
||||
%do i = 1 %to 17;
|
||||
%put &i.) %ABC(&i.);
|
||||
%end;
|
||||
**(!)** For "backward compatibility"/historical point of view the following packages are also available under the `./packages` directory in this repository.
|
||||
|
||||
%let %ABC(13,i) = 999; /* i = insert */
|
||||
Packages:
|
||||
|
||||
%do i = 1 %to 17;
|
||||
%put &i.) %ABC(&i.);
|
||||
%end;
|
||||
```
|
||||
- **SQLinDS**
|
||||
|
||||
- **BasePlus**\[0.5\] adds a bunch of functionalities I am missing in BASE SAS, such as:
|
||||
```
|
||||
call arrMissToRight(myArray);
|
||||
call arrFillMiss(17, myArray);
|
||||
call arrFill(42, myArray);
|
||||
[Documentation for SQLinDS](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/sqlinds.md "Documentation for SQLinDS")
|
||||
|
||||
rc = delDataset("DataSetToDrop");
|
||||
[SQLinDS in SASPAC](https://github.com/SASPAC/sqlinds "SQLinDS in SASPAC")
|
||||
|
||||
string = catXFn("date9.", "#", myArray);
|
||||
|
||||
format x bool.;
|
||||
- **DFA** (Dynamic Function Arrays)
|
||||
|
||||
%put %getVars(sashelp.class, patern = ght$, sep = +, varRange = _numeric_);
|
||||
```
|
||||
[Documentation for DFA](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/dfa.md "Documentation for DFA")
|
||||
|
||||
[DFA in SASPAC](https://github.com/SASPAC/dfa "DFA in SASPAC")
|
||||
|
||||
- **macroArray**
|
||||
|
||||
[Documentation for macroArray](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/macroarray.md "Documentation for macroArray")
|
||||
|
||||
[MacroArray in SASPAC](https://github.com/SASPAC/macroarray "MacroArray in SASPAC")
|
||||
|
||||
- **BasePlus**
|
||||
|
||||
[Documentation for BasePlus](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/baseplus.md "Documentation for BasePlus")
|
||||
|
||||
[BasePlus in SASPAC](https://github.com/SASPAC/baseplus "BasePlus in SASPAC")
|
||||
|
||||
- **GSM** (Generate Secure Macros)
|
||||
|
||||
[Documentation for GSM](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/gsm.md "Documentation for GSM")
|
||||
|
||||
[GSM in SASPAC](https://github.com/SASPAC/gsm "GSM in SASPAC")
|
||||
|
||||
- **dynMacroArray**
|
||||
|
||||
Development of this package is currently on hold.
|
||||
|
||||
- **dynMacroArray**\[0.2\], set of macros (wrappers for a hash table) emulating dynamic array in the data step (macro predecessor of DFA)
|
||||
|
||||
### ======
|
||||
|
||||
BIN
SPF/Documentation/Getting_Started_with_SAS_Packages.pdf
Normal file
BIN
SPF/Documentation/Getting_Started_with_SAS_Packages.pdf
Normal file
Binary file not shown.
147
SPF/Documentation/HelloWorldPackage.md
Normal file
147
SPF/Documentation/HelloWorldPackage.md
Normal file
@@ -0,0 +1,147 @@
|
||||
|
||||
## The "Hello World" Package
|
||||
|
||||
---
|
||||
|
||||
This is a "Hello World" example on how to build your first package with help of the SAS Packages Framework.
|
||||
|
||||
We will generate a `HelloWorld` package.
|
||||
|
||||
Follow the step by step instruction below.
|
||||
|
||||
---
|
||||
|
||||
`Step 1.` Create a folder for the framework e.g.,
|
||||
`/home/<myUserName>/SASpackages` or `C:/SASpackages`
|
||||
|
||||
`Step 2.` Run the following code to install The SAS Packages Framework
|
||||
in the folder you created in the `Step 1.`
|
||||
|
||||
```sas
|
||||
filename packages "<put/folder/from/the/step/one/here>";
|
||||
filename SPFinit url "https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas";
|
||||
%include SPFinit;
|
||||
%installPackage(SPFinit)
|
||||
```
|
||||
|
||||
Check out the *log* to verify if the `Step 2.` was successful.
|
||||
If it was - then continue.
|
||||
|
||||
|
||||
`Step 3.` Create a folder for the content of the package we will generate e.g.,
|
||||
`/home/<myUserName>/HelloWorldPackage` or `C:/HelloWorldPackage`
|
||||
|
||||
`Step 4.` Inside the directory from the `Step 3.` create two sub-folders: `01_formats`
|
||||
and `02_macros`. Remember to use *lower case letters* only!
|
||||
|
||||
`Step 5.` Inside the `01_formats` folder create a `helloworldformat.sas` file.
|
||||
Remember to use lower case letters in the file name. Copy-paste below code
|
||||
into that file:
|
||||
|
||||
```sas
|
||||
/*** HELP START ***//*
|
||||
This is a help info for the HelloWorldFormat. format
|
||||
*//*** HELP END ***/
|
||||
|
||||
value HelloWorldFormat
|
||||
1 = " Hello"
|
||||
2 = " SAS"
|
||||
3 = " Packages"
|
||||
4 = " World"
|
||||
other = "!"
|
||||
;
|
||||
```
|
||||
|
||||
`Step 6.` Inside the `02_macros` folder create a `helloworldmacro.sas` file.
|
||||
Remember to use lower case letters in the file name. Copy-paste below code
|
||||
into that file:
|
||||
```sas
|
||||
/*** HELP START ***//*
|
||||
This is a help info for the helloWorldMacro() macro
|
||||
*//*** HELP END ***/
|
||||
|
||||
%macro HelloWorldMacro(n);
|
||||
data _null_;
|
||||
do i = 1 to &n.;
|
||||
put i HelloWorldFormat. @;
|
||||
end;
|
||||
run;
|
||||
%mend HelloWorldMacro;
|
||||
```
|
||||
|
||||
|
||||
`Step 7.` Inside the directory from the `Step 3.` create a `description.sas` file.
|
||||
Remember to use lower case letters in the file name. Copy-paste below text
|
||||
into that file, adjust lines 5 and 6:
|
||||
```txt
|
||||
Type: Package
|
||||
Package: helloWorld
|
||||
Title: My Hello World SAS package.
|
||||
Version: 1.0
|
||||
Author: <myFirstname> <myLastname> (my@mail.com)
|
||||
Maintainer: <myFirstname> <myLastname> (my@mail.com)
|
||||
License: MIT
|
||||
Encoding: UTF8
|
||||
|
||||
Required: "Base SAS Software"
|
||||
|
||||
DESCRIPTION START:
|
||||
## My "Hello World" SAS package ##
|
||||
|
||||
The "Hello World" is my first SAS package and
|
||||
for sure it will not be the last package one!
|
||||
DESCRIPTION END:
|
||||
```
|
||||
|
||||
`Step 8.` Execute the following code and check the log
|
||||
to read the `%generatePackage()` macro help info.
|
||||
|
||||
```sas
|
||||
%generatePackage()
|
||||
```
|
||||
|
||||
`Step 9.` Execute the following code using the folder
|
||||
from the `Step 3.` and check the log to see how
|
||||
the process of package generation went.
|
||||
|
||||
```sas
|
||||
%generatePackage(
|
||||
filesLocation=<put/folder/from/the/step/three/here>
|
||||
)
|
||||
```
|
||||
|
||||
`Step 10.` See the information in the output window and in the log.
|
||||
The `WARNING:[License] No license.sas file provided, default (MIT) licence file will be generated.` can be ignored.
|
||||
|
||||
`Step 11.` Check the directory from the `Step 3.` and look for the `helloworld.zip` package file.
|
||||
|
||||
---
|
||||
|
||||
`Step 12.` Start a new SAS session, run the following code, and investigate the log:
|
||||
|
||||
```sas
|
||||
filename packages ("<put/folder/from/the/step/one/here>" "<put/folder/from/the/step/three/here>");
|
||||
%include packages(SPFinit.sas);
|
||||
|
||||
%loadPackage(HelloWorld)
|
||||
|
||||
%HelloWorldMacro(7)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Congratulations!! You've just created your first HelloWorld package.
|
||||
|
||||
Now you are ready to do smome more advanced work.
|
||||
|
||||
- Read the **`My First SAS Package: A How-To - Paper 1079-2021`** article, available at communities.sas.com [**`here`**](https://communities.sas.com/t5/SAS-Global-Forum-Proceedings/My-First-SAS-Package-A-How-To/ta-p/726319 "My First SAS Package: A How-To + Video") (video included) or locally [**`here`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/Paper_1079-2021/My%20First%20SAS%20Package%20-%20a%20How%20To.pdf "My First SAS Package: A How-To"), describing the proces of a package creation with more advanced example and technical details.
|
||||
|
||||
- Go to "bare metal" and read the [**`SAS Packages - The Way to Share (a How-To) - Paper 4725-2020 - extended version`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/SAS(r)%20packages%20-%20the%20way%20to%20share%20(a%20how%20to)-%20Paper%204725-2020%20-%20extended.pdf "SAS packages - the way to share") - an article which contains all technical details on how the SAS Packages Framework works and how to use it (both as a develope and as a user).
|
||||
|
||||
---
|
||||
|
||||
The SAS Packages Framework [(short) documetation](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/SPFinit.md) to quickly see macros options and parametera.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Binary file not shown.
80
SPF/Documentation/Paper_1079-2021/Paper_1079-2021.sas
Normal file
80
SPF/Documentation/Paper_1079-2021/Paper_1079-2021.sas
Normal file
@@ -0,0 +1,80 @@
|
||||
/*one library "myLib" created in the (same named) subderectory of the "WORK" directory.*/
|
||||
data _null_;
|
||||
length rc0 $ 32767 rc1 rc2 8;
|
||||
lib = "myLib";
|
||||
rc0 = DCREATE(lib, "%sysfunc(pathname(work))/");
|
||||
put rc0 = ;
|
||||
rc1 = LIBNAME(lib, "%sysfunc(pathname(work))/" !! lib, "BASE");
|
||||
rc2 = LIBREF (lib);
|
||||
if rc2 NE 0 then
|
||||
rc1 = LIBNAME(lib, "%sysfunc(pathname(work))", "BASE");
|
||||
run;
|
||||
|
||||
libname myLib LIST;
|
||||
|
||||
/*two FCMP functions: "F1" and "F2", */
|
||||
proc FCMP outlib = work.f.p;
|
||||
function F1(n);
|
||||
return (n+1);
|
||||
endsub;
|
||||
|
||||
function F2(n);
|
||||
return (n+2);
|
||||
endsub;
|
||||
run;
|
||||
options cmplib = work.f;
|
||||
|
||||
/*one numeric format "fmtNum" and informat "infNum", */
|
||||
proc FORMAT;
|
||||
value fmtNum
|
||||
low -< 0 = "negative"
|
||||
0 = "zero"
|
||||
0 <- high = "positive"
|
||||
other = "missing"
|
||||
;
|
||||
invalue infNum
|
||||
"negative" = -1
|
||||
"zero" = 0
|
||||
"positive" = 1
|
||||
"missing" = .
|
||||
other = 42
|
||||
;
|
||||
run;
|
||||
|
||||
/*one exemplary small dataset "myLib.smallDataset", and*/
|
||||
data myLib.smallDataset;
|
||||
do n = ., -1, 0, 1;
|
||||
m = put(n, fmtNum.);
|
||||
output;
|
||||
end;
|
||||
run;
|
||||
|
||||
/*one exemplary bigger dataset "myLib.biggerDataset".*/
|
||||
data myLib.biggerDataset;
|
||||
do i = ., -1e6 to 1e6;
|
||||
j = put(i, fmtNum.);
|
||||
k = ranuni(17);
|
||||
output;
|
||||
end;
|
||||
run;
|
||||
|
||||
/*two macros: "mcrOne" and "mcrTwo" */
|
||||
%macro mcrOne();
|
||||
%put **Hi! This is macro &sysmacroname.**;
|
||||
data _null_;
|
||||
set myLib.smallDataset;
|
||||
p = f1(n);
|
||||
p + f2(n);
|
||||
put (n p) (= fmtNum.);
|
||||
run;
|
||||
%mend mcrOne;
|
||||
|
||||
%macro mcrTwo(m=mcrOne);
|
||||
%put **This is macro &sysmacroname.**;
|
||||
%put **and I am calling the &m.**;
|
||||
%&m.()
|
||||
|
||||
%put The answer is: %sysfunc(inputn("I don't know...", infNum.));
|
||||
%mend mcrTwo;
|
||||
|
||||
/* %mcrTwo() */
|
||||
4
SPF/Documentation/Paper_1079-2021/generate_package.sas
Normal file
4
SPF/Documentation/Paper_1079-2021/generate_package.sas
Normal file
@@ -0,0 +1,4 @@
|
||||
filename packages "~/saspackages";
|
||||
%include packages(SPFinit.sas);
|
||||
|
||||
%generatePackage(~/saspackages/myPackage)
|
||||
@@ -0,0 +1,7 @@
|
||||
filename packages "~/saspackages";
|
||||
|
||||
filename SPFinit url
|
||||
"https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas";
|
||||
%include SPFinit;
|
||||
|
||||
%installPackage(SPFinit)
|
||||
@@ -0,0 +1,18 @@
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
`myLib` library
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
data _null_;
|
||||
length rc0 $ 32767 rc1 rc2 8;
|
||||
lib = "myLib";
|
||||
rc0 = DCREATE(lib, "%sysfunc(pathname(work))/");
|
||||
put rc0 = ;
|
||||
rc1 = LIBNAME(lib, "%sysfunc(pathname(work))/" !! lib, "BASE");
|
||||
rc2 = LIBREF (lib);
|
||||
if rc2 NE 0 then
|
||||
rc1 = LIBNAME(lib, "%sysfunc(pathname(work))", "BASE");
|
||||
run;
|
||||
|
||||
libname myLib LIST;
|
||||
@@ -0,0 +1,9 @@
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
`F1` function
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
function F1(n);
|
||||
return (n+1);
|
||||
endsub;
|
||||
@@ -0,0 +1,9 @@
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
`F2` function
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
function F2(n);
|
||||
return (n+2);
|
||||
endsub;
|
||||
@@ -0,0 +1,12 @@
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
`fmtNum` format
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
value fmtNum
|
||||
low -< 0 = "negative"
|
||||
0 = "zero"
|
||||
0 <- high = "positive"
|
||||
other = "missing"
|
||||
;
|
||||
@@ -0,0 +1,13 @@
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
`infNum` informat
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
invalue infNum
|
||||
"negative" = -1
|
||||
"zero" = 0
|
||||
"positive" = 1
|
||||
"missing" = .
|
||||
other = 42
|
||||
;
|
||||
@@ -0,0 +1,12 @@
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
`myLib.smallDataset` data
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
data myLib.smallDataset;
|
||||
do n = ., -1, 0, 1;
|
||||
m = put(n, fmtNum.);
|
||||
output;
|
||||
end;
|
||||
run;
|
||||
@@ -0,0 +1,13 @@
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
`myLib.biggerDataset` data
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
data myLib.biggerDataset;
|
||||
do i = ., -1e6 to 1e6;
|
||||
j = put(i, fmtNum.);
|
||||
k = ranuni(17);
|
||||
output;
|
||||
end;
|
||||
run;
|
||||
@@ -0,0 +1,15 @@
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
`mcrOne` macro
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
%macro mcrOne();
|
||||
%put **Hi! This is macro &sysmacroname.**;
|
||||
data _null_;
|
||||
set myLib.smallDataset;
|
||||
p = f1(n);
|
||||
p + f2(n);
|
||||
put (n p) (= fmtNum.);
|
||||
run;
|
||||
%mend mcrOne;
|
||||
@@ -0,0 +1,30 @@
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
## General Info: ##
|
||||
|
||||
The `%mcrTwo()` macro is the main macro of the package.
|
||||
|
||||
It has one key-value parameter `m` with default value `mcrOne`.
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
%macro mcrTwo(m=mcrOne);
|
||||
%put **This is macro &sysmacroname.**;
|
||||
%put **and I am calling the &m.**;
|
||||
%&m.()
|
||||
|
||||
%put The answer is: %sysfunc(inputn("I don't know...", infNum.));
|
||||
%mend mcrTwo;
|
||||
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
## Examples: ##
|
||||
|
||||
Example 1. Basic use-case:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
%mcrTwo(m=mcrOne)
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
21
SPF/Documentation/Paper_1079-2021/myPackage/description.sas
Normal file
21
SPF/Documentation/Paper_1079-2021/myPackage/description.sas
Normal file
@@ -0,0 +1,21 @@
|
||||
Type: Package
|
||||
Package: myPackage
|
||||
Title: My first SAS package.
|
||||
Version: 1.0
|
||||
Author: John Smith (john.smith@mail.com)
|
||||
Maintainer: Jane Smith (jane.smith@mail.com)
|
||||
License: MIT
|
||||
Encoding: UTF8
|
||||
|
||||
Required: "Base SAS Software"
|
||||
|
||||
DESCRIPTION START:
|
||||
## The myPackage ##
|
||||
|
||||
The `myPackage` is my first SAS package and
|
||||
for sure it won't be the last package!
|
||||
It was created during SAS Global Forum 2021
|
||||
virtual event.
|
||||
|
||||
It helps me to share my code with other SAS users!
|
||||
DESCRIPTION END:
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
%mcrTwo(m=mcrOne)
|
||||
14
SPF/Documentation/Paper_1079-2021/mypackage.md
Normal file
14
SPF/Documentation/Paper_1079-2021/mypackage.md
Normal file
@@ -0,0 +1,14 @@
|
||||
## General Info: ##
|
||||
|
||||
The `%mcrTwo()` macro is the main macro of the package.
|
||||
|
||||
It has one key-value parameter `m` with default value `mcrOne`.
|
||||
|
||||
## Examples: ##
|
||||
|
||||
Example 1. Basic use-case:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
%mcrTwo(m=mcrOne)
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Binary file not shown.
Binary file not shown.
104
SPF/Macros/extendpackagesfileref.sas
Normal file
104
SPF/Macros/extendpackagesfileref.sas
Normal file
@@ -0,0 +1,104 @@
|
||||
/*+extendPackagesFileref+*/
|
||||
/*** HELP START ***/
|
||||
|
||||
%macro extendPackagesFileref(
|
||||
packages /* A valid fileref name,
|
||||
when empty the "packages" value is used */
|
||||
)/secure
|
||||
/*** HELP END ***/
|
||||
des = 'Macro to list directories pointed by "packages" fileref, version 20231024. Run %extendPackagesFileref(HELP) for help info.'
|
||||
;
|
||||
|
||||
%if %QUPCASE(&packages.) = HELP %then
|
||||
%do;
|
||||
%local options_tmp ;
|
||||
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
|
||||
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
|
||||
msglevel=%sysfunc(getoption(msglevel))
|
||||
;
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
%put ;
|
||||
%put ###########################################################################################;
|
||||
%put ### This is short help information for the `extendPackagesFileref` macro #;
|
||||
%put #-----------------------------------------------------------------------------------------#;;
|
||||
%put # #;
|
||||
%put # Macro to list directories pointed by 'packages' fileref, version `20231024` #;
|
||||
%put # #;
|
||||
%put # A SAS package is a zip file containing a group #;
|
||||
%put # of SAS codes (macros, functions, data steps generating #;
|
||||
%put # data, etc.) wrapped up together and embedded inside the zip. #;
|
||||
%put # #;
|
||||
%put # The `%nrstr(%%extendPackagesFileref())` macro lists directories pointed by #;
|
||||
%put # the packages fileref. It allows to add new dierctories to packages folder list. #;
|
||||
%put # #;
|
||||
%put #### Parameters: #;
|
||||
%put # #;
|
||||
%put # 1. `packages` *Optional.* A valid fileref name, when empty the "packages" is used. #;
|
||||
%put # Use case: #;
|
||||
%put # `%nrstr(%%extendPackagesFileref()).` #;
|
||||
%put # #;
|
||||
%put # When used as: `%nrstr(%%extendPackagesFileref(HELP))` it displays this help information. #;
|
||||
%put # #;
|
||||
%put #-----------------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
|
||||
%put # to learn more. #;
|
||||
%put # #;
|
||||
%put #### Example ##############################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and adding #;
|
||||
%put # new directory. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in one of "C:/SAS_PK1" or "C:/SAS_PK2" folders. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages ("C:/SAS_PK1" "C:/SAS_PK2"); %%* setup a directory for packages; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
|
||||
%put ;
|
||||
%put %nrstr( filename packages ("D:/NEW_DIR" %%extendPackagesFileref()); %%* add new directory; );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put ###########################################################################################;
|
||||
%put ;
|
||||
options &options_tmp.;
|
||||
%GOTO ENDextendPackagesFileref;
|
||||
%end;
|
||||
|
||||
%if %superq(packages) = %then %let packages = packages;
|
||||
%if %qsysfunc(pathname(&packages.)) ne %then
|
||||
%do;
|
||||
%if %qsubstr(%qsysfunc(pathname(&packages.)), 1, 1) = %str(%() %then
|
||||
%do;
|
||||
%local length;
|
||||
%let length = %eval(%length(%qsysfunc(pathname(&packages.)))-2);
|
||||
%unquote(%qsubstr(%qsysfunc(pathname(&packages.)), 2, &length.))
|
||||
%end;
|
||||
%else "%sysfunc(pathname(&packages.))";
|
||||
%end;
|
||||
%ENDextendPackagesFileref:
|
||||
%mend extendPackagesFileref;
|
||||
|
||||
/* Examples:
|
||||
|
||||
filename packages "C:\";
|
||||
%include packages(SPFinit.sas)
|
||||
|
||||
%extendPackagesFileref(HELP)
|
||||
|
||||
filename packages (%extendPackagesFileref() "D:\");
|
||||
filename packages list;
|
||||
|
||||
filename packages clear;
|
||||
|
||||
filename packages "C:\";
|
||||
filename packages ("D:\" %extendPackagesFileref());
|
||||
filename packages list;
|
||||
|
||||
%put *%extendPackagesFileref()*;
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
3335
SPF/Macros/generatepackage.sas
Normal file
3335
SPF/Macros/generatepackage.sas
Normal file
File diff suppressed because it is too large
Load Diff
190
SPF/Macros/helppackage.sas
Normal file
190
SPF/Macros/helppackage.sas
Normal file
@@ -0,0 +1,190 @@
|
||||
/*+helpPackage+*/
|
||||
/*** HELP START ***/
|
||||
|
||||
%macro helpPackage(
|
||||
packageName /* name of a package,
|
||||
e.g. myPackageFile.zip,
|
||||
required and not null */
|
||||
, helpKeyword /* phrase to search in help,
|
||||
when empty prints description
|
||||
"*" means print all help
|
||||
"license" prints license */
|
||||
, path = %sysfunc(pathname(packages)) /* location of a package,
|
||||
by default it looks for
|
||||
location of "packages" fileref */
|
||||
, options = %str(LOWCASE_MEMNAME) /* possible options for ZIP filename */
|
||||
, source2 = /*source2*/ /* option to print out details,
|
||||
null by default */
|
||||
, zip = zip /* standard package is zip (lowcase),
|
||||
e.g. %helpPackage(PiPackage,*)
|
||||
if the zip is not available use a folder
|
||||
unpack data to "pipackage.disk" folder
|
||||
and use helpPackage in the form:
|
||||
%helpPackage(PiPackage, *, zip=disk, options=) */
|
||||
, packageContentDS = 0 /* indicates if a data set with package
|
||||
content should be generated in WORK,
|
||||
if set to 1 then WORK.packageName_content
|
||||
dataset is created
|
||||
*/
|
||||
)/secure
|
||||
/*** HELP END ***/
|
||||
des = 'Macro to get help about SAS package, version 20231024. Run %helpPackage() for help info.'
|
||||
;
|
||||
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
|
||||
%do;
|
||||
%local options_tmp ;
|
||||
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
|
||||
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
|
||||
msglevel=%sysfunc(getoption(msglevel))
|
||||
;
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
%put ;
|
||||
%put #################################################################################;
|
||||
%put ### This is short help information for the `helpPackage` macro #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Macro to get help about SAS packages, version `20231024` #;
|
||||
%put # #;
|
||||
%put # A SAS package is a zip file containing a group #;
|
||||
%put # of SAS codes (macros, functions, data steps generating #;
|
||||
%put # data, etc.) wrapped up together and provided with #;
|
||||
%put # a single `help.sas` file (also embedded inside the zip). #;
|
||||
%put # #;
|
||||
%put # The `%nrstr(%%helpPackage())` macro prints in the SAS log help #;
|
||||
%put # information about the package provided by the developer. #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put #### Parameters: #;
|
||||
%put # #;
|
||||
%put # 1. `packageName` *Required.* Name of a package, e.g. myPackage, #;
|
||||
%put # Required and not null, default use case: #;
|
||||
%put # `%nrstr(%%helpPackage(myPackage)).` #;
|
||||
%put # If empty displays this help information. #;
|
||||
%put # #;
|
||||
%put # 2. `helpKeyword` *Optional.* A phrase to search in help, #;
|
||||
%put # - when empty prints description, #;
|
||||
%put # - "*" means: print all help, #;
|
||||
%put # - "license" prints the license. #;
|
||||
%put # #;
|
||||
%put # - `path=` *Optional.* Location of a package. By default it #;
|
||||
%put # looks for location of the **packages** fileref, i.e. #;
|
||||
%put # `%nrstr(%%sysfunc(pathname(packages)))` #;
|
||||
%put # #;
|
||||
%put # - `options=` *Optional.* Possible options for ZIP filename, #;
|
||||
%put # default value: `LOWCASE_MEMNAME` #;
|
||||
%put # #;
|
||||
%put # - `source2=` *Optional.* Option to print out details about #;
|
||||
%put # what is loaded, null by default. #;
|
||||
%put # #;
|
||||
%put # - `zip=` Standard package is zip (lowcase), #;
|
||||
%put # e.g. `%nrstr(%%helpPackage(PiPackage))`. #;
|
||||
%put # If the zip is not available use a folder. #;
|
||||
%put # Unpack data to "pipackage.disk" folder #;
|
||||
%put # and use helpPackage in the following form: #;
|
||||
%put # `%nrstr(%%helpPackage(PiPackage, ,zip=disk, options=))` #;
|
||||
%put # #;
|
||||
%put # - `packageContentDS=` *Optional.* Indicates if a data set with package #;
|
||||
%put # content should be generated in `WORK`, #;
|
||||
%put # with default value (`0`) the dataset is not produced, #;
|
||||
%put # if set to `1` then `WORK.packageName_content`. #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
|
||||
%put # to learn more. #;
|
||||
%put # #;
|
||||
%put #### Example ####################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and installing & loading #;
|
||||
%put # the SQLinDS package from the Internet. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
|
||||
%put ;
|
||||
%put %nrstr( %%installPackage(SQLinDS) %%* install the package from the Internet; );
|
||||
%put %nrstr( %%helpPackage(SQLinDS) %%* get help about the package; );
|
||||
%put %nrstr( %%loadPackage(SQLinDS) %%* load the package content into the SAS session; );
|
||||
%put %nrstr( %%unloadPackage(SQLinDS) %%* unload the package content from the SAS session; );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put #################################################################################;
|
||||
%put ;
|
||||
options &options_tmp.;
|
||||
%GOTO ENDofhelpPackage;
|
||||
%end;
|
||||
|
||||
/* local variables for options */
|
||||
%local ls_tmp ps_tmp notes_tmp source_tmp msglevel_tmp;
|
||||
%let ls_tmp = %sysfunc(getoption(ls));
|
||||
%let ps_tmp = %sysfunc(getoption(ps));
|
||||
%let notes_tmp = %sysfunc(getoption(notes));
|
||||
%let source_tmp = %sysfunc(getoption(source));
|
||||
%let msglevel_tmp = %sysfunc(getoption(msglevel));
|
||||
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
|
||||
%local _PackageFileref_;
|
||||
/* %let _PackageFileref_ = P%sysfunc(MD5(%lowcase(&packageName.)),hex7.); */
|
||||
data _null_; call symputX("_PackageFileref_", "P" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L"); run;
|
||||
|
||||
/* when the packages reference is multi-directory search for the first one containing the package */
|
||||
data _null_;
|
||||
exists = 0;
|
||||
length packages $ 32767 p $ 4096;
|
||||
packages = resolve(symget("path"));
|
||||
if char(packages,1) ^= "(" then packages = quote(strip(packages)); /* for paths with spaces */
|
||||
do i = 1 to kcountw(packages, "()", "QS");
|
||||
p = dequote(kscanx(packages, i, "()", "QS"));
|
||||
exists + fileexist(catx("/", p, "%lowcase(&packageName.).&zip."));
|
||||
if exists then leave;
|
||||
end;
|
||||
if exists then call symputx("path", p, "L");
|
||||
run;
|
||||
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
/* put location of package myPackageFile.zip here */
|
||||
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
|
||||
;
|
||||
%if %sysfunc(fexist(&_PackageFileref_.)) %then
|
||||
%do;
|
||||
%include &_PackageFileref_.(packagemetadata.sas) / &source2.;
|
||||
filename &_PackageFileref_. clear;
|
||||
options ls = &ls_tmp. ps = &ps_tmp. ¬es_tmp. &source_tmp.;
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
|
||||
ENCODING =
|
||||
%if %bquote(&packageEncoding.) NE %then &packageEncoding. ;
|
||||
%else utf8 ;
|
||||
;
|
||||
%if 1=%superq(packageContentDS) %then %let packageContentDS=work.&packageName._content;
|
||||
%else %let packageContentDS=;
|
||||
|
||||
%include &_PackageFileref_.(help.sas) / &source2.;
|
||||
%end;
|
||||
%else %put ERROR:[&sysmacroname] File "&path./&packageName..&zip." does not exist!;
|
||||
filename &_PackageFileref_. clear;
|
||||
|
||||
options ls = &ls_tmp. ps = &ps_tmp. ¬es_tmp. &source_tmp. msglevel = &msglevel_tmp.;
|
||||
|
||||
%ENDofhelpPackage:
|
||||
%mend helpPackage;
|
||||
|
||||
/*
|
||||
TODO:
|
||||
- macro for testing available packages in the packages folder [DONE] checkout: %listPackages()
|
||||
- add MD5(&packageName.) value hash instead "package" word in filenames [DONE]
|
||||
*/
|
||||
|
||||
/* Macros to install SAS packages, version 20231024 */
|
||||
/* A SAS package is a zip file containing a group of files
|
||||
with SAS code (macros, functions, data steps generating
|
||||
data, etc.) wrapped up together and %INCLUDEed by
|
||||
a single load.sas file (also embedded inside the zip).
|
||||
*/
|
||||
|
||||
503
SPF/Macros/installpackage.sas
Normal file
503
SPF/Macros/installpackage.sas
Normal file
@@ -0,0 +1,503 @@
|
||||
/*+installPackage+*/
|
||||
/*** HELP START ***/
|
||||
|
||||
%macro installPackage(
|
||||
packagesNames /* space separated list of packages names, without the zip extension */
|
||||
, sourcePath = /* location of the package, e.g. "www.some.page/", mind the "/" at the end */
|
||||
, mirror = 0 /* indicates which location for package source should be used */
|
||||
, version = /* indicates which version of a package to install */
|
||||
, replace = 1 /* 1 = replace if the package already exist, 0 = otherwise */
|
||||
, URLuser = /* user name for the password protected URLs */
|
||||
, URLpass = /* password for the password protected URLs */
|
||||
, URLoptions = /* options for the `sourcePath` URLs */
|
||||
, loadAddCnt=0 /* should the additional content be loaded?
|
||||
default is 0 - means No, 1 means Yes */
|
||||
)
|
||||
/secure
|
||||
minoperator
|
||||
/*** HELP END ***/
|
||||
des = 'Macro to install SAS package, version 20231024. Run %%installPackage() for help info.'
|
||||
;
|
||||
%if (%superq(packagesNames) = ) OR (%qupcase(&packagesNames.) = HELP) %then
|
||||
%do;
|
||||
%local options_tmp ;
|
||||
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
|
||||
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
|
||||
msglevel=%sysfunc(getoption(msglevel))
|
||||
;
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
%put ;
|
||||
%put ##############################################################################################;
|
||||
%put ### This is short help information for the `installPackage` macro #;
|
||||
%put #--------------------------------------------------------------------------------------------#;;
|
||||
%put # #;
|
||||
%put # Macro to install SAS packages, version `20231024` #;
|
||||
%put # #;
|
||||
%put # A SAS package is a zip file containing a group #;
|
||||
%put # of SAS codes (macros, functions, data steps generating #;
|
||||
%put # data, etc.) wrapped up together and embedded inside the zip. #;
|
||||
%put # #;
|
||||
%put # The `%nrstr(%%installPackage())` macro installs the package zip #;
|
||||
%put # in the packages folder. The process of installation is equivalent with #;
|
||||
%put # manual downloading the package zip file into the packages folder. #;
|
||||
%put # #;
|
||||
%put # In case the packages fileref is a multi-directory one the first directory #;
|
||||
%put # will be selected as a destination. #;
|
||||
%put # #;
|
||||
%put #--------------------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put #### Parameters: #;
|
||||
%put # #;
|
||||
%put # 1. `packagesNames` Space separated list of packages names _without_ #;
|
||||
%put # the zip extension, e.g. myPackage1 myPackage2, #;
|
||||
%put # Required and not null, default use case: #;
|
||||
%put # `%nrstr(%%installPackage(myPackage1 myPackage2))`. #;
|
||||
%put # If empty displays this help information. #;
|
||||
%put # If the package name is *SPFinit* or *SASPackagesFramework* #;
|
||||
%put # then the framework itself is downloaded. #;
|
||||
%put # #;
|
||||
%put # - `sourcePath=` Location of the package, e.g. "www.some.web.page/" #;
|
||||
%put # Mind the "/" at the end of the path! #;
|
||||
%put # Current default location for packages is: #;
|
||||
%put # `https://github.com/SASPAC/` #;
|
||||
%put # Current default location for the framework is: #;
|
||||
%put # `https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/` #;
|
||||
%put # #;
|
||||
%put # - `mirror=` Indicates which web location for packages installation is used. #;
|
||||
%put # Value `0` indicates: #;
|
||||
%put # `https://github.com/SASPAC/` #;
|
||||
%put # Value `1` indicates: #;
|
||||
%put # `https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main` #;
|
||||
%put # Value `2` indicates: #;
|
||||
%put # `https://pages.mini.pw.edu.pl/~jablonskib/SASpublic/SAS_PACKAGES` #;
|
||||
%put # Default value is `0`. #;
|
||||
%put # #;
|
||||
%put # - `version=` Indicates which historical version of a package to install. #;
|
||||
%put # Historical version are available only if `mirror=0` is set. #;
|
||||
%put # Default value is null which means "install the latest". #;
|
||||
%put # When there are multiple packages to install version #;
|
||||
%put # is scan sequentially. #;
|
||||
%put # #;
|
||||
%put # - `replace=` With default value of `1` it causes existing package file #;
|
||||
%put # to be replaced by new downloaded file. #;
|
||||
%put # #;
|
||||
%put # - `URLuser=` A user name for the password protected URLs, no quotes needed. #;
|
||||
%put # #;
|
||||
%put # - `URLpass=` A password for the password protected URLs, no quotes needed. #;
|
||||
%put # #;
|
||||
%put # - `URLoptions=` Options for the `sourcePath` URLs filename. Consult the SAS #;
|
||||
%put # documentation for the further details. #;
|
||||
%put # #;
|
||||
%put # - `loadAddCnt=` *Optional.* A package zip may contain additional #;
|
||||
%put # content. The option indicates if it should be loaded #;
|
||||
%put # Default value of zero (`0`) means "No", one (`1`) #;
|
||||
%put # means "Yes". Content is extracted into the **packages** fileref #;
|
||||
%put # directory in `<packageName>_AdditionalContent` folder. #;
|
||||
%put # For other locations use `%nrstr(%%loadPackageAddCnt())` macro. #;
|
||||
%put # #;
|
||||
%put #--------------------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
|
||||
%put # to learn more. #;
|
||||
%put # #;
|
||||
%put #### Example #################################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and installing & loading #;
|
||||
%put # the SQLinDS package from the Internet. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
|
||||
%put ;
|
||||
%put %nrstr( %%installPackage(SQLinDS) %%* install the package from the Internet; );
|
||||
%put %nrstr( %%helpPackage(SQLinDS) %%* get help about the package; );
|
||||
%put %nrstr( %%loadPackage(SQLinDS) %%* load the package content into the SAS session; );
|
||||
%put %nrstr( %%unloadPackage(SQLinDS) %%* unload the package content from the SAS session; );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put #### Example #################################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and installing & loading #;
|
||||
%put # the multiple packages from the Internet. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages "C:/SAS_PACKAGES"; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); );
|
||||
%put ;
|
||||
%put %nrstr( %%installPackage(baseplus(1.17) macroarray(1.0) dfa(0.5) GSM) );
|
||||
%put %nrstr( %%loadPackageS(GSM, baseplus(1.17), macroarray(1.0), dfa(0.5)) );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put ##############################################################################################;
|
||||
%put ;
|
||||
options &options_tmp.;
|
||||
%GOTO ENDofinstallPackage;
|
||||
%end;
|
||||
|
||||
/* local variables for options */
|
||||
%local ls_tmp ps_tmp notes_tmp source_tmp stimer_tmp fullstimer_tmp msglevel_tmp;
|
||||
|
||||
%let ls_tmp = %sysfunc(getoption(ls));
|
||||
%let ps_tmp = %sysfunc(getoption(ps));
|
||||
%let notes_tmp = %sysfunc(getoption(notes));
|
||||
%let source_tmp = %sysfunc(getoption(source));
|
||||
%let stimer_tmp = %sysfunc(getoption(stimer));
|
||||
%let fullstimer_tmp = %sysfunc(getoption(fullstimer));
|
||||
%let msglevel_tmp = %sysfunc(getoption(msglevel));
|
||||
|
||||
options NOnotes NOsource ls=MAX ps=MAX NOfullstimer NOstimer msglevel=N;
|
||||
|
||||
/*
|
||||
Reference:
|
||||
https://blogs.sas.com/content/sasdummy/2011/06/17/how-to-use-sas-data-step-to-copy-a-file-from-anywhere/
|
||||
*/
|
||||
|
||||
/* in case the 'packages' fileref is multi-directory the first directory will be selected as a destination */
|
||||
data _null_;
|
||||
if "(" =: pathname("packages") then
|
||||
/* get the firstPackagesPath */
|
||||
call symputX("firstPackagesPath", dequote(kscanx(pathname("packages"), 1, "()", "QS")), "L");
|
||||
else
|
||||
call symputX("firstPackagesPath", pathname("packages"), "L");
|
||||
run;
|
||||
|
||||
%if %superq(sourcePath)= %then
|
||||
%do;
|
||||
%local SPFinitMirror;
|
||||
/* the defaults are: */
|
||||
%let SPFinitMirror = https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas;
|
||||
%let sourcePath = https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/packages/;
|
||||
|
||||
%if 0 = %superq(mirror) %then
|
||||
%do;
|
||||
%let SPFinitMirror = https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas;
|
||||
%let sourcePath = https://github.com/SASPAC/; /*usercontent*/
|
||||
%goto mirrorEnd;
|
||||
%end;
|
||||
|
||||
%if 1 = %superq(mirror) %then
|
||||
%do;
|
||||
%let SPFinitMirror = https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas;
|
||||
%let sourcePath = https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/packages/;
|
||||
%goto mirrorEnd;
|
||||
%end;
|
||||
|
||||
%if 2 = %superq(mirror) %then
|
||||
%do;
|
||||
%let SPFinitMirror = https://pages.mini.pw.edu.pl/~jablonskib/SASpublic/SAS_PACKAGES/SPF/SPFinit.sas;
|
||||
%let sourcePath = https://pages.mini.pw.edu.pl/~jablonskib/SASpublic/SAS_PACKAGES/packages/;
|
||||
%goto mirrorEnd;
|
||||
%end;
|
||||
%mirrorEnd:
|
||||
%put INFO: Source path is &sourcePath.;
|
||||
%end;
|
||||
%else
|
||||
%do;
|
||||
%let mirror=-1;
|
||||
%let SPFinitMirror = &sourcePath.SPFinit.sas;
|
||||
%end;
|
||||
|
||||
%local i str;
|
||||
/* standardise list of packages */
|
||||
%let str = %qsysfunc(compress(%superq(packagesNames),[{(. _)}],kad));
|
||||
%let str = %qsysfunc(translate(%superq(str),[[]],{()}));
|
||||
%let str = %qsysfunc(transtrn(%superq(str),],%str(] )));
|
||||
%let str = %qsysfunc(compbl(%superq(str)));
|
||||
%let str = %qsysfunc(transtrn(%superq(str),%str([ ),[));
|
||||
%let str = %qsysfunc(transtrn(%superq(str),%str( [),[));
|
||||
%let str = %qsysfunc(transtrn(%superq(str),%str( ]),]));
|
||||
%let str = %unquote(&str.);
|
||||
%let packagesNames = %qsysfunc(translate(%superq(str),(),[]));
|
||||
|
||||
%if %length("%sysfunc(compress(%superq(str),[,k))") NE %length("%sysfunc(compress(%superq(str),],k))") %then
|
||||
%do;
|
||||
%put ERROR: Syntax error in list of packages!;
|
||||
%put ERROR- %superq(packagesNames);
|
||||
%goto packagesListError;
|
||||
%end;
|
||||
|
||||
%put ;
|
||||
%put INFO: Calling: &packagesNames.;
|
||||
|
||||
%do i = 1 %to %sysfunc(countw(&packagesNames., , S));
|
||||
/*-++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-*/
|
||||
%local packageName packageSubDir vers versA versB;
|
||||
%put ;
|
||||
/*%put ### %scan(&packagesNames., &i., , S) ###;*/
|
||||
%let packageName = %scan(%scan(&packagesNames., &i., , S),1,{[()]});
|
||||
%let versA = %scan(%scan(&packagesNames., &i., , S),2,{[()]});
|
||||
%let versB = %scan(&version., &i., , S);
|
||||
%let vers=;
|
||||
%if %superq(versB) ne %then %let vers = &versB.;
|
||||
%if %superq(versA) ne %then %let vers = &versA.;
|
||||
%if -1 = &mirror %then /* ignore version when direct path is provided */
|
||||
%do;
|
||||
%let vers=;
|
||||
%end;
|
||||
%put ### &packageName.(&vers.) ###;
|
||||
|
||||
%put *** %lowcase(&packageName.) start *****************************************;
|
||||
%local in out _IOFileref_;
|
||||
data _null_; call symputX("_IOFileref_", put(MD5("%lowcase(&packageName.)"), hex7. -L), "L"); run;
|
||||
%let in = i&_IOFileref_.;
|
||||
%let out = o&_IOFileref_.;
|
||||
/* %let in = i%sysfunc(md5(&packageName.),hex7.); */
|
||||
/* %let out = o%sysfunc(md5(&packageName.),hex7.); */
|
||||
|
||||
/*options MSGLEVEL=i;*/
|
||||
%if %upcase(&packageName.) in (SPFINIT SASPACKAGEFRAMEWORK SASPACKAGESFRAMEWORK) %then
|
||||
%do;
|
||||
/* allows to install/download the framework file like any other package */
|
||||
%if %superq(mirror) in (0 1) AND (%superq(vers) ne) %then
|
||||
%do;
|
||||
%let SPFinitMirror = https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/&vers./SPF/SPFinit.sas;
|
||||
%end;
|
||||
|
||||
filename &in URL
|
||||
"&SPFinitMirror."
|
||||
recfm=N lrecl=1;
|
||||
filename &out
|
||||
"&firstPackagesPath./SPFinit.sas"
|
||||
recfm=N lrecl=1;
|
||||
%end;
|
||||
%else
|
||||
%do;
|
||||
%if 0 = %superq(mirror) %then
|
||||
%do;
|
||||
%let packageSubDir = %lowcase(&packageName.)/raw/main/;
|
||||
|
||||
%if %superq(vers) ne %then
|
||||
%do;
|
||||
/*%let packageSubDir = %lowcase(&packageName.)/main/hist/&version./;*/
|
||||
%let packageSubDir = %lowcase(&packageName.)/raw/&vers./;
|
||||
%end;
|
||||
%end;
|
||||
filename &in URL "&sourcePath.&packageSubDir.%lowcase(&packageName.).zip"
|
||||
%if (%superq(URLuser) ne ) %then
|
||||
%do;
|
||||
user = "&URLuser."
|
||||
pass = "&URLuser."
|
||||
%end;
|
||||
&URLoptions.
|
||||
recfm=N lrecl=1;
|
||||
filename &out "&firstPackagesPath./%lowcase(&packageName.).zip" recfm=N lrecl=1;
|
||||
%end;
|
||||
/*
|
||||
filename in list;
|
||||
filename out list;
|
||||
*/
|
||||
/* copy the file byte-by-byte */
|
||||
%local installationRC;
|
||||
%let installationRC=1;
|
||||
data _null_;
|
||||
length filein 8 out_path in_path $ 4096;
|
||||
out_path = pathname ("&out");
|
||||
in_path = pathname ("&in" );
|
||||
|
||||
|
||||
filein = fopen( "&in", 'S', 1, 'B');
|
||||
if filein = 0 then
|
||||
put "ERROR: Source file:" /
|
||||
"ERROR- " in_path /
|
||||
"ERROR- is unavailable!";
|
||||
if filein > 0;
|
||||
|
||||
put @2 "Source information:";
|
||||
infonum = FOPTNUM(filein);
|
||||
length infoname $ 32 infoval $ 128;
|
||||
do i=1 to coalesce(infonum, -1);
|
||||
infoname = FOPTNAME(filein, i);
|
||||
infoval = FINFO(filein, infoname);
|
||||
put @4 infoname ":"
|
||||
/ @6 infoval
|
||||
;
|
||||
end;
|
||||
rc = FCLOSE(filein);
|
||||
put;
|
||||
|
||||
if FEXIST("&out") = 0 then
|
||||
do;
|
||||
put @2 "Installing the &packageName. package"
|
||||
/ @2 "in the &firstPackagesPath. directory.";
|
||||
rc = FCOPY("&in", "&out");
|
||||
end;
|
||||
else if FEXIST("&out") = 1 then
|
||||
do;
|
||||
if symgetn("replace")=1 then
|
||||
do;
|
||||
put @2 "The following file will be replaced during "
|
||||
/ @2 "installation of the &packageName. package: "
|
||||
/ @5 out_path;
|
||||
rc = FDELETE("&out");
|
||||
rc = FCOPY("&in", "&out");
|
||||
end;
|
||||
else
|
||||
do;
|
||||
put @2 "The following file will NOT be replaced: "
|
||||
/ @5 out_path;
|
||||
rc = 1;
|
||||
end;
|
||||
end;
|
||||
|
||||
put @2 "Done with return code " rc= "(zero = success)";
|
||||
call symputX("installationRC", rc, "L");
|
||||
run;
|
||||
|
||||
filename &in clear;
|
||||
filename &out clear;
|
||||
|
||||
%if 1 = &loadAddCnt.
|
||||
AND 0 = &installationRC.
|
||||
AND NOT (%upcase(&packageName.) in (SPFINIT SASPACKAGEFRAMEWORK SASPACKAGESFRAMEWORK))
|
||||
%then
|
||||
%do;
|
||||
%put; %put - Additional content loading - Start -;
|
||||
%loadPackageAddCnt(&packageName.
|
||||
,path=&firstPackagesPath.
|
||||
,target=&firstPackagesPath.
|
||||
)
|
||||
%put - Additional content loading - End -;
|
||||
%end;
|
||||
%put *** %lowcase(&packageName.) end *******************************************;
|
||||
/*-++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-*/
|
||||
%end;
|
||||
|
||||
%packagesListError:
|
||||
|
||||
options ls = &ls_tmp. ps = &ps_tmp.
|
||||
¬es_tmp. &source_tmp.
|
||||
&stimer_tmp. &fullstimer_tmp.
|
||||
msglevel=&msglevel_tmp.;
|
||||
|
||||
%ENDofinstallPackage:
|
||||
%mend installPackage;
|
||||
|
||||
/*** HELP START ***/
|
||||
|
||||
/*
|
||||
Filenames references "packages" and "package" are reserved keywords.
|
||||
The first one should be used to point local folder with packages.
|
||||
The second is used internally by macros.
|
||||
Do not use them otherwise than:
|
||||
filename packages "</the/folder/with/sas/packages>";
|
||||
since it may affect stability of the framework.
|
||||
**/
|
||||
|
||||
/* Example 1: Enabling the SAS Package Framework
|
||||
and loading the SQLinDS package from the local directory.
|
||||
|
||||
Assume that the SPFinit.sas file and the SQLinDS
|
||||
package (sqlinds.zip file) are located in
|
||||
the "C:/SAS_PACKAGES/" folder.
|
||||
|
||||
Run the following code in your SAS session:
|
||||
|
||||
filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
|
||||
%include packages(SPFinit.sas); %* enable the framework;
|
||||
|
||||
%helpPackage(SQLinDS) %* get help about the package;
|
||||
%loadPackage(SQLinDS) %* load the package content into the SAS session;
|
||||
%unloadPackage(SQLinDS) %* unload the package content from the SAS session;
|
||||
*/
|
||||
|
||||
/* Example 2: Enabling the SAS Package Framework
|
||||
from the local directory and installing & loading
|
||||
the SQLinDS package from the Internet.
|
||||
|
||||
Assume that the SPFinit.sas file
|
||||
is located in the "C:/SAS_PACKAGES/" folder.
|
||||
|
||||
Run the following code in your SAS session:
|
||||
|
||||
filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
|
||||
%include packages(SPFinit.sas); %* enable the framework;
|
||||
|
||||
%installPackage(SQLinDS) %* install the package from the Internet;
|
||||
%helpPackage(SQLinDS) %* get help about the package;
|
||||
%loadPackage(SQLinDS) %* load the package content into the SAS session;
|
||||
%unloadPackage(SQLinDS) %* unload the package content from the SAS session;
|
||||
*/
|
||||
|
||||
/* Example 3: Enabling the SAS Package Framework
|
||||
and installing & loading the SQLinDS package
|
||||
from the Internet.
|
||||
|
||||
Run the following code in your SAS session:
|
||||
|
||||
filename packages "%sysfunc(pathname(work))"; %* setup WORK as a temporary directory for packages;
|
||||
|
||||
filename spfinit url "https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPFinit.sas";
|
||||
%include spfinit; %* enable the framework;
|
||||
|
||||
%installPackage(SQLinDS) %* install the package from the Internet;
|
||||
%helpPackage(SQLinDS) %* get help about the package;
|
||||
%loadPackage(SQLinDS) %* load the package content into the SAS session;
|
||||
%unloadPackage(SQLinDS) %* unload the package content from the SAS session;
|
||||
*/
|
||||
|
||||
/* Example 4:
|
||||
Assume that the SPFinit.sas file and the SQLinDS package (sqlinds.zip file)
|
||||
are located in the "C:/SAS_PACKAGES/" folder.
|
||||
|
||||
In case when user SAS session does not support ZIP fileref
|
||||
the following solution could be used.
|
||||
|
||||
Unzip the packagename.zip content into the packagename.disk folder
|
||||
and run macros with the following options: ;
|
||||
|
||||
%loadPackage(packageName,zip=disk,options=)
|
||||
%helpPackage(packageName,,zip=disk,options=) %* mind the double comma!! ;
|
||||
%unloadPackage(packageName,zip=disk,options=)
|
||||
|
||||
*/
|
||||
|
||||
/* Example 5: Enabling the SAS Package Framework from the local directory
|
||||
and installing the SQLinDS package from the Internet.
|
||||
|
||||
Assume that the SPFinit.sas file is located in
|
||||
the "C:/SAS_PACKAGES/" folder.
|
||||
|
||||
filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
|
||||
%include packages(SPFinit.sas); %* enable the framework;
|
||||
|
||||
%installPackage(SQLinDS); %* install package;
|
||||
%installPackage(SQLinDS); %* overwrite already installed package;
|
||||
%installPackage(SQLinDS,replace=0); %* prevent overwrite installed package;
|
||||
|
||||
|
||||
%installPackage(NotExistingPackage); %* handling with not existing package;
|
||||
|
||||
*/
|
||||
|
||||
/*** HELP END ***/
|
||||
|
||||
/*** HELP START ***/
|
||||
|
||||
/* Macro to list SAS packages in packages folder.
|
||||
|
||||
Version 20231024
|
||||
|
||||
A SAS package is a zip file containing a group
|
||||
of SAS codes (macros, functions, data steps generating
|
||||
data, etc.) wrapped up together and %INCLUDEed by
|
||||
a single load.sas file (also embedded inside the zip).
|
||||
*/
|
||||
/*
|
||||
* Example 1: Set local packages directory, enable the framework,
|
||||
and list packages in the local repository.
|
||||
|
||||
filename packages "C:\SAS_PACKAGES";
|
||||
%include packages(SPFinit.sas);
|
||||
%listPackages()
|
||||
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
180
SPF/Macros/listpackages.sas
Normal file
180
SPF/Macros/listpackages.sas
Normal file
@@ -0,0 +1,180 @@
|
||||
/*+listPackages+*/
|
||||
|
||||
%macro listPackages()/secure PARMBUFF
|
||||
des = 'Macro to list SAS packages from `packages` fileref, type %listPackages(HELP) for help, version 20231024.'
|
||||
;
|
||||
%if %QUPCASE(&SYSPBUFF.) = %str(%(HELP%)) %then
|
||||
%do;
|
||||
%local options_tmp ;
|
||||
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
|
||||
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
|
||||
msglevel=%sysfunc(getoption(msglevel))
|
||||
;
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
%put ;
|
||||
%put ###########################################################################################;
|
||||
%put ### This is short help information for the `listPackages` macro #;
|
||||
%put #-----------------------------------------------------------------------------------------#;;
|
||||
%put # #;
|
||||
%put # Macro to list available SAS packages, version `20231024` #;
|
||||
%put # #;
|
||||
%put # A SAS package is a zip file containing a group #;
|
||||
%put # of SAS codes (macros, functions, data steps generating #;
|
||||
%put # data, etc.) wrapped up together and embedded inside the zip. #;
|
||||
%put # #;
|
||||
%put # The `%nrstr(%%listPackages())` macro lists packages available #;
|
||||
%put # in the packages folder. List is printed inthe SAS Log. #;
|
||||
%put # #;
|
||||
%put #### Parameters: #;
|
||||
%put # #;
|
||||
%put # NO PARAMETERS #;
|
||||
%put # #;
|
||||
%put # When used as: `%nrstr(%%listPackages(HELP))` it displays this help information. #;
|
||||
%put # #;
|
||||
%put #-----------------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
|
||||
%put # to learn more. #;
|
||||
%put # #;
|
||||
%put #### Example ##############################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and listing #;
|
||||
%put # available packages. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
|
||||
%put ;
|
||||
%put %nrstr( %%listPackages() %%* list available packages; );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put ###########################################################################################;
|
||||
%put ;
|
||||
options &options_tmp.;
|
||||
%GOTO ENDoflistPackages;
|
||||
%end;
|
||||
|
||||
%local ls_tmp ps_tmp notes_tmp source_tmp filesWithCodes;
|
||||
|
||||
%let filesWithCodes = WORK._%sysfunc(datetime(), hex16.)_;
|
||||
|
||||
%let ls_tmp = %sysfunc(getoption(ls));
|
||||
%let ps_tmp = %sysfunc(getoption(ps));
|
||||
%let notes_tmp = %sysfunc(getoption(notes));
|
||||
%let source_tmp = %sysfunc(getoption(source));
|
||||
|
||||
options NOnotes NOsource ls=MAX ps=MAX;
|
||||
|
||||
data _null_;
|
||||
length baseAll $ 32767;
|
||||
baseAll = pathname("packages");
|
||||
|
||||
if baseAll = " " then
|
||||
do;
|
||||
put "NOTE: The file reference PACKAGES is not assigned.";
|
||||
stop;
|
||||
end;
|
||||
|
||||
if char(baseAll,1) ^= "(" then baseAll = quote(strip(baseAll)); /* for paths with spaces */
|
||||
|
||||
do k = 1 to kcountw(baseAll, "()", "QS"); drop k;
|
||||
base = dequote(kscanx(baseAll, k, "()", "QS"));
|
||||
|
||||
length folder $ 64 file $ 1024 folderRef fileRef $ 8;
|
||||
|
||||
folderRef = "_%sysfunc(datetime(), hex6.)0";
|
||||
|
||||
rc=filename(folderRef, base);
|
||||
folderid=dopen(folderRef);
|
||||
|
||||
putlog " ";
|
||||
put "/*" 100*"+" ;
|
||||
do i=1 to dnum(folderId); drop i;
|
||||
|
||||
if i = 1 then
|
||||
do;
|
||||
put " #";
|
||||
put " # Listing packages for: " base;
|
||||
put " #";
|
||||
end;
|
||||
|
||||
folder = dread(folderId, i);
|
||||
|
||||
fileRef = "_%sysfunc(datetime(), hex6.)1";
|
||||
rc = filename(fileRef, catx("/", base, folder));
|
||||
fileId = dopen(fileRef);
|
||||
|
||||
EOF = 0;
|
||||
if fileId = 0 and lowcase(kscanx(folder, -1, ".")) = 'zip' then
|
||||
do;
|
||||
file = catx('/',base, folder);
|
||||
|
||||
rc1 = filename("package", strip(file), 'zip', 'member="description.sas"');
|
||||
rcE = fexist("package");
|
||||
rc2 = filename("package", " ");
|
||||
|
||||
if rcE then /* if the description.sas exists in the zip then read it */
|
||||
do;
|
||||
putlog " * ";
|
||||
length nn $ 96;
|
||||
if (96-lengthn(file)) < 1 then
|
||||
put " * " file;
|
||||
else
|
||||
do;
|
||||
nn = repeat("*", (96-lengthn(file)));
|
||||
put " * " file nn;
|
||||
end;
|
||||
|
||||
infile _DUMMY_ ZIP FILEVAR=file member="description.sas" end=EOF;
|
||||
|
||||
do until(EOF);
|
||||
input;
|
||||
if strip(upcase(kscanx(_INFILE_,1,":"))) in ("PACKAGE" "TITLE" "VERSION" "AUTHOR" "MAINTAINER" "LICENSE") then
|
||||
do;
|
||||
_INFILE_ = kscanx(_INFILE_,1,":") !! ":" !! kscanx(_INFILE_,2,":");
|
||||
putlog " * " _INFILE_;
|
||||
end;
|
||||
if strip(upcase(strip(_INFILE_))) =: "DESCRIPTION START:" then leave;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
rc = dclose(fileId);
|
||||
rc = filename(fileRef);
|
||||
end;
|
||||
|
||||
putlog " * ";
|
||||
put 100*"+" "*/";
|
||||
rc = dclose(folderid);
|
||||
rc = filename(folderRef);
|
||||
end;
|
||||
|
||||
stop;
|
||||
run;
|
||||
|
||||
options ls = &ls_tmp. ps = &ps_tmp. ¬es_tmp. &source_tmp.;
|
||||
|
||||
%ENDoflistPackages:
|
||||
%mend listPackages;
|
||||
|
||||
|
||||
/*** HELP START ***/
|
||||
|
||||
/* Macro to generate SAS packages.
|
||||
|
||||
Version 20231024
|
||||
|
||||
A SAS package is a zip file containing a group
|
||||
of SAS codes (macros, functions, data steps generating
|
||||
data, etc.) wrapped up together and %INCLUDEed by
|
||||
a single load.sas file (also embedded inside the zip).
|
||||
|
||||
See examples below.
|
||||
*/
|
||||
|
||||
/*** HELP END ***/
|
||||
|
||||
285
SPF/Macros/loadpackage.sas
Normal file
285
SPF/Macros/loadpackage.sas
Normal file
@@ -0,0 +1,285 @@
|
||||
/*+loadPackage+*/
|
||||
/*** HELP START ***/
|
||||
|
||||
%macro loadPackage(
|
||||
packageName /* name of a package,
|
||||
e.g. myPackage,
|
||||
required and not null */
|
||||
, path = %sysfunc(pathname(packages)) /* location of a package,
|
||||
by default it looks for
|
||||
location of "packages" fileref */
|
||||
, options = %str(LOWCASE_MEMNAME) /* possible options for ZIP filename */
|
||||
, source2 = /*source2*/ /* option to print out details,
|
||||
null by default */
|
||||
, requiredVersion = . /* option to test if loaded package
|
||||
is provided in required version */
|
||||
, lazyData = /* a list of names of lazy datasets
|
||||
to be loaded, if not null then
|
||||
datasets from the list are loaded
|
||||
instead of a package, asterisk
|
||||
means "load all datasets" */
|
||||
, zip = zip /* standard package is zip (lowcase),
|
||||
e.g. %loadPackage(PiPackage)
|
||||
if the zip is not available use a folder
|
||||
unpack data to "pipackage.disk" folder
|
||||
and use loadPackage in the form:
|
||||
%loadPackage(PiPackage, zip=disk, options=) */
|
||||
, cherryPick=* /* space separated list of selected elements of the package
|
||||
to be loaded into the session, default value "*" means
|
||||
"load all elements of the package" */
|
||||
, loadAddCnt=0 /* should the additional content be loaded?
|
||||
default is 0 - means No, 1 means Yes */
|
||||
, suppressExec=0 /* indicates if loading of exec files
|
||||
should be suppressed, 1=suppress
|
||||
*/
|
||||
)/secure
|
||||
/*** HELP END ***/
|
||||
des = 'Macro to load SAS package, version 20231024. Run %loadPackage() for help info.'
|
||||
minoperator
|
||||
;
|
||||
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
|
||||
%do;
|
||||
%local options_tmp ;
|
||||
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
|
||||
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
|
||||
msglevel=%sysfunc(getoption(msglevel))
|
||||
;
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
%put ;
|
||||
%put #################################################################################;
|
||||
%put ### This is short help information for the `loadPackage` macro #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Macro to *load* SAS packages, version `20231024` #;
|
||||
%put # #;
|
||||
%put # A SAS package is a zip file containing a group #;
|
||||
%put # of SAS codes (macros, functions, data steps generating #;
|
||||
%put # data, etc.) wrapped up together and included by #;
|
||||
%put # a single `load.sas` file (also embedded inside the zip). #;
|
||||
%put # #;
|
||||
%put # The `%nrstr(%%loadPackage())` macro loads package content, i.e. macros, #;
|
||||
%put # functions, formats, etc., from the zip into the SAS session. #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put #### Parameters: #;
|
||||
%put # #;
|
||||
%put # 1. `packageName` *Required.* Name of a package, e.g. myPackage, #;
|
||||
%put # Required and not null, default use case: #;
|
||||
%put # `%nrstr(%%loadPackage(myPackage)).` #;
|
||||
%put # If empty displays this help information. #;
|
||||
%put # #;
|
||||
%put # - `path=` *Optional.* Location of a package. By default it #;
|
||||
%put # looks for location of the **packages** fileref, i.e. #;
|
||||
%put # `%nrstr(%%sysfunc(pathname(packages)))` #;
|
||||
%put # #;
|
||||
%put # - `options=` *Optional.* Possible options for ZIP filename, #;
|
||||
%put # default value: `LOWCASE_MEMNAME` #;
|
||||
%put # #;
|
||||
%put # - `source2=` *Optional.* Option to print out details about #;
|
||||
%put # what is loaded, null by default. #;
|
||||
%put # #;
|
||||
%put # - `requiredVersion=` *Optional.* Option to test if the loaded #;
|
||||
%put # package is provided in required version, #;
|
||||
%put # default value: `.` #;
|
||||
%put # #;
|
||||
%put # - `lazyData=` *Optional.* A space separated list of names of lazy #;
|
||||
%put # datasets to be loaded. If not null datasets from the #;
|
||||
%put # list are loaded instead of the package. #;
|
||||
%put # An asterisk (*) means *load all lazy datasets*. #;
|
||||
%put # #;
|
||||
%put # - `zip=` *Optional.* Standard package is zip (lowcase), #;
|
||||
%put # e.g. `%nrstr(%%loadPackage(PiPackage))`. #;
|
||||
%put # If the zip is not available use a folder. #;
|
||||
%put # Unpack data to "pipackage.disk" folder #;
|
||||
%put # and use loadPackage in the following form: #;
|
||||
%put # `%nrstr(%%loadPackage(PiPackage, zip=disk, options=))` #;
|
||||
%put # #;
|
||||
%put # - `cherryPick=` *Optional.* A space separated list of selected elements #;
|
||||
%put # of the package to be loaded into the SAS session. #;
|
||||
%put # Default value of an asterisk (*) means: #;
|
||||
%put # "load all elements of the package". #;
|
||||
%put # #;
|
||||
%put # - `loadAddCnt=` *Optional.* A package zip may contain additional #;
|
||||
%put # content. The option indicates if it should be loaded #;
|
||||
%put # Default value of zero (`0`) means "No", one (`1`) #;
|
||||
%put # means "Yes". Content is extracted into the **Work** #;
|
||||
%put # directory in `<packageName>_AdditionalContent` folder. #;
|
||||
%put # For other locations use `%nrstr(%%loadPackageAddCnt())` macro. #;
|
||||
%put # #;
|
||||
%put # - `suppressExec=` *Optional.* Indicates if loading of `exec` type files #;
|
||||
%put # should be suppressed, default value is `0`, #;
|
||||
%put # when set to `1` `exec` files are *not* loaded #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
|
||||
%put # to learn more. #;
|
||||
%put # #;
|
||||
%put ### Example 1 ###################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and installing & loading #;
|
||||
%put # the SQLinDS package from the Internet. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
|
||||
%put ;
|
||||
%put %nrstr( %%installPackage(SQLinDS) %%* install the package from the Internet; );
|
||||
%put %nrstr( %%helpPackage(SQLinDS) %%* get help about the package; );
|
||||
%put %nrstr( %%loadPackage(SQLinDS) %%* load the package content into the SAS session; );
|
||||
%put %nrstr( %%unloadPackage(SQLinDS) %%* unload the package content from the SAS session; );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put # #;
|
||||
%put ### Example 2 ###################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and installing & cherry picking #;
|
||||
%put # elements of the BasePlus package. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
|
||||
%put ;
|
||||
%put %nrstr( %%installPackage(BasePlus) %%* install the package from the Internet; );
|
||||
%put %nrstr( %%loadPackage(BasePlus, cherryPick=getVars) %%* cherry pick the content; );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put # #;
|
||||
%put #################################################################################;
|
||||
%put ;
|
||||
options &options_tmp.;
|
||||
%GOTO ENDofloadPackage;
|
||||
%end;
|
||||
/* local variables for options */
|
||||
%local ls_tmp ps_tmp notes_tmp source_tmp stimer_tmp fullstimer_tmp msglevel_tmp;
|
||||
%let ls_tmp = %sysfunc(getoption(ls));
|
||||
%let ps_tmp = %sysfunc(getoption(ps));
|
||||
%let notes_tmp = %sysfunc(getoption(notes));
|
||||
%let source_tmp = %sysfunc(getoption(source));
|
||||
%let stimer_tmp = %sysfunc(getoption(stimer));
|
||||
%let fullstimer_tmp = %sysfunc(getoption(fullstimer));
|
||||
%let msglevel_tmp = %sysfunc(getoption(msglevel));
|
||||
|
||||
options NOnotes NOsource ls=MAX ps=MAX NOfullstimer NOstimer msglevel=N;
|
||||
|
||||
%local _PackageFileref_;
|
||||
/* %let _PackageFileref_ = P%sysfunc(MD5(%lowcase(&packageName.)),hex7.); */
|
||||
data _null_; call symputX("_PackageFileref_", "P" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L"); run;
|
||||
|
||||
/* when the packages reference is multi-directory search for the first one containing the package */
|
||||
data _null_;
|
||||
exists = 0;
|
||||
length packages $ 32767 p $ 4096;
|
||||
packages = resolve(symget("path"));
|
||||
if char(packages,1) ^= "(" then packages = quote(strip(packages)); /* for paths with spaces */
|
||||
do i = 1 to kcountw(packages, "()", "QS");
|
||||
p = dequote(kscanx(packages, i, "()", "QS"));
|
||||
exists + fileexist(catx("/", p, "%lowcase(&packageName.).&zip."));
|
||||
if exists then leave;
|
||||
end;
|
||||
if exists then call symputx("path", p, "L");
|
||||
run;
|
||||
|
||||
/* convert cherryPick to lower case if needed */
|
||||
%if NOT (%str(*) = %superq(cherryPick)) %then
|
||||
%do;
|
||||
data _null_;
|
||||
call symputX("cherryPick",lowcase(compbl(compress(symget("cherryPick"),". _","KDA"))),"L");
|
||||
run;
|
||||
%end;
|
||||
/* empty list is equivalent to "*" */
|
||||
%if %superq(cherryPick)= %then
|
||||
%do;
|
||||
%let cherryPick=*;
|
||||
%end;
|
||||
|
||||
%if %superq(loadAddCnt) NE 1 %then
|
||||
%do;
|
||||
%let loadAddCnt = 0;
|
||||
%end;
|
||||
|
||||
%if %superq(suppressExec) NE 1 %then
|
||||
%do;
|
||||
%let suppressExec = 0;
|
||||
%end;
|
||||
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
/* put location of package myPackageFile.zip here */
|
||||
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
|
||||
;
|
||||
%if %sysfunc(fexist(&_PackageFileref_.)) %then
|
||||
%do;
|
||||
%include &_PackageFileref_.(packagemetadata.sas) / &source2.;
|
||||
filename &_PackageFileref_. clear;
|
||||
|
||||
/* test if required version of package is "good enough" */
|
||||
%local rV pV;
|
||||
%let pV = %sysfunc(compress(&packageVersion.,.,kd));
|
||||
%let pV = %sysevalf((%scan(&pV.,1,.,M)+0)*1e8
|
||||
+ (%scan(&pV.,2,.,M)+0)*1e4
|
||||
+ (%scan(&pV.,3,.,M)+0)*1e0);
|
||||
%let rV = %sysfunc(compress(&requiredVersion.,.,kd));
|
||||
%let rV = %sysevalf((%scan(&rV.,1,.,M)+0)*1e8
|
||||
+ (%scan(&rV.,2,.,M)+0)*1e4
|
||||
+ (%scan(&rV.,3,.,M)+0)*1e0);
|
||||
|
||||
%if %sysevalf(&rV. > &pV.) %then
|
||||
%do;
|
||||
%put ERROR: Package &packageName. will not be loaded!;
|
||||
%put ERROR- Required version is &requiredVersion.;
|
||||
%put ERROR- Provided version is &packageVersion.;
|
||||
%put ERROR- Verify installed version of the package.;
|
||||
%put ERROR- ;
|
||||
%GOTO WrongVersionOFPackage; /*%RETURN;*/
|
||||
%end;
|
||||
|
||||
options ls = &ls_tmp. ps = &ps_tmp. ¬es_tmp. &source_tmp.;
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
|
||||
ENCODING =
|
||||
%if %bquote(&packageEncoding.) NE %then &packageEncoding. ;
|
||||
%else utf8 ;
|
||||
;
|
||||
%if %superq(lazyData) = %then
|
||||
%do;
|
||||
%local tempLoad_minoperator;
|
||||
%let tempLoad_minoperator = %sysfunc(getoption(minoperator));
|
||||
options minoperator; /* MinOperator option is required for cherryPicking to work */
|
||||
%include &_PackageFileref_.(load.sas) / &source2.;
|
||||
options &tempLoad_minoperator.;
|
||||
%if 1 = &loadAddCnt. %then
|
||||
%do;
|
||||
%put; %put - Additional content loading - Start -;
|
||||
%loadPackageAddCnt(&packageName.,
|
||||
path=&path.)
|
||||
%put - Additional content loading - End -;
|
||||
%end;
|
||||
%end;
|
||||
%else
|
||||
%do;
|
||||
%include &_PackageFileref_.(lazydata.sas) / &source2.;
|
||||
%end;
|
||||
|
||||
%end;
|
||||
%else %put ERROR:[&sysmacroname] File "&path./&packageName..&zip." does not exist!;
|
||||
filename &_PackageFileref_. clear;
|
||||
|
||||
%WrongVersionOFPackage:
|
||||
|
||||
/* restore optionos */
|
||||
options ls = &ls_tmp. ps = &ps_tmp.
|
||||
¬es_tmp. &source_tmp.
|
||||
&stimer_tmp. &fullstimer_tmp.
|
||||
msglevel=&msglevel_tmp.;
|
||||
|
||||
%ENDofloadPackage:
|
||||
%mend loadPackage;
|
||||
|
||||
375
SPF/Macros/loadpackageaddcnt.sas
Normal file
375
SPF/Macros/loadpackageaddcnt.sas
Normal file
@@ -0,0 +1,375 @@
|
||||
/*+loadPackageAddCnt+*/
|
||||
/*** HELP START ***/
|
||||
|
||||
%macro loadPackageAddCnt(
|
||||
packageName /* name of a package,
|
||||
e.g. myPackage,
|
||||
required and not null */
|
||||
, path = %sysfunc(pathname(packages)) /* location of a package,
|
||||
by default it looks for
|
||||
location of "packages" fileref */
|
||||
, target = %sysfunc(pathname(WORK)) /* a path in which the directory with
|
||||
additional content will be generated,
|
||||
name of directory created is set to
|
||||
`&packageName._AdditionalContent`
|
||||
default location is SAS work */
|
||||
, source2 = /*source2*/ /* option to print out details,
|
||||
null by default */
|
||||
, requiredVersion = . /* option to test if loaded package
|
||||
is provided in required version */
|
||||
)/secure
|
||||
/*** HELP END ***/
|
||||
des = 'Macro to load additional content for a SAS package, version 20231024. Run %loadPackageAddCnt() for help info.'
|
||||
minoperator
|
||||
;
|
||||
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
|
||||
%do;
|
||||
%local options_tmp ;
|
||||
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
|
||||
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
|
||||
msglevel=%sysfunc(getoption(msglevel))
|
||||
;
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
%put ;
|
||||
%put #################################################################################;
|
||||
%put ### This is short help information for the `loadPackageAddCnt` macro #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Macro to *load* additional content for a SAS package, version `20231024` #;
|
||||
%put # #;
|
||||
%put # A SAS package is a zip file containing a group #;
|
||||
%put # of SAS codes (macros, functions, data steps generating #;
|
||||
%put # data, etc.) wrapped up together and included by #;
|
||||
%put # a single `load.sas` file (also embedded inside the zip). #;
|
||||
%put # #;
|
||||
%put # The `%nrstr(%%loadPackageAddCnt())` macro loads additional content #;
|
||||
%put # for a package (of course only if one is provided). #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put #### Parameters: #;
|
||||
%put # #;
|
||||
%put # 1. `packageName` *Required.* Name of a package, e.g. myPackage, #;
|
||||
%put # Required and not null, default use case: #;
|
||||
%put # `%nrstr(%%loadPackageAddCnt(myPackage))`. #;
|
||||
%put # If empty displays this help information. #;
|
||||
%put # #;
|
||||
%put # - `path=` *Optional.* Location of a package. By default it #;
|
||||
%put # looks for location of the **packages** fileref, i.e. #;
|
||||
%put # `%nrstr(%%sysfunc(pathname(packages)))` #;
|
||||
%put # #;
|
||||
%put # - `target=` *Optional.* Location where the directory with #;
|
||||
%put # additional content will be generated, #;
|
||||
%put # name of the directory created is set to #;
|
||||
%put # `<packagename>_AdditionalContent`, the default #;
|
||||
%put # location is `%nrstr(%%sysfunc(pathname(WORK)))` #;
|
||||
%put # #;
|
||||
%put # - `source2=` *Optional.* Option to print out details about #;
|
||||
%put # what is loaded, null by default. #;
|
||||
%put # #;
|
||||
%put # - `requiredVersion=` *Optional.* Option to test if the loaded #;
|
||||
%put # package is provided in required version, #;
|
||||
%put # default value: `.` #;
|
||||
%put # #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
|
||||
%put # to learn more. #;
|
||||
%put # #;
|
||||
%put ### Example 1 ###################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and installing & loading additional content #;
|
||||
%put # for the SQLinDS package. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
|
||||
%put ;
|
||||
%put %nrstr( %%installPackage(SQLinDS) %%* install the package from the Internet; );
|
||||
%put %nrstr( %%loadPackageAddCnt(SQLinDS) %%* load additional content for the package; );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put # #;
|
||||
%put #################################################################################;
|
||||
%put ;
|
||||
options &options_tmp.;
|
||||
%GOTO ENDofloadPackageAddCnt;
|
||||
%end;
|
||||
/* local variables for options */
|
||||
%local ls_tmp ps_tmp notes_tmp source_tmp stimer_tmp fullstimer_tmp msglevel_tmp zip;
|
||||
%let ls_tmp = %sysfunc(getoption(ls));
|
||||
%let ps_tmp = %sysfunc(getoption(ps));
|
||||
%let notes_tmp = %sysfunc(getoption(notes));
|
||||
%let source_tmp = %sysfunc(getoption(source));
|
||||
%let stimer_tmp = %sysfunc(getoption(stimer));
|
||||
%let fullstimer_tmp = %sysfunc(getoption(fullstimer));
|
||||
%let msglevel_tmp = %sysfunc(getoption(msglevel));
|
||||
|
||||
%let zip = zip;
|
||||
|
||||
options NOnotes NOsource ls=MAX ps=MAX NOfullstimer NOstimer msglevel=N;
|
||||
|
||||
%local _PackageFileref_;
|
||||
/* %let _PackageFileref_ = P%sysfunc(MD5(%lowcase(&packageName.)),hex7.); */
|
||||
data _null_;
|
||||
call symputX("_PackageFileref_", "A" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L");
|
||||
call symputX("_TargetFileref_", "T" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L");
|
||||
run;
|
||||
|
||||
/* when the packages reference is multi-directory search for the first one containing the package */
|
||||
data _null_;
|
||||
exists = 0;
|
||||
length packages $ 32767 p $ 4096;
|
||||
packages = resolve(symget("path"));
|
||||
if char(packages,1) ^= "(" then packages = quote(strip(packages)); /* for paths with spaces */
|
||||
do i = 1 to kcountw(packages, "()", "QS");
|
||||
p = dequote(kscanx(packages, i, "()", "QS"));
|
||||
exists + fileexist(catx("/", p, "%lowcase(&packageName.).&zip."));
|
||||
if exists then leave;
|
||||
end;
|
||||
if exists then call symputx("path", p, "L");
|
||||
run;
|
||||
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
/* put location of package myPackageFile.zip here */
|
||||
"&path./%lowcase(&packageName.).&zip."
|
||||
;
|
||||
%if %sysfunc(fexist(&_PackageFileref_.)) %then
|
||||
%do;
|
||||
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
/* check existence of addcnt.zip inside package */
|
||||
"&path./%lowcase(&packageName.).&zip."
|
||||
member='addcnt.zip'
|
||||
;
|
||||
%if %sysfunc(fexist(&_PackageFileref_.)) %then
|
||||
%do;
|
||||
|
||||
/* get metadata */
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
"&path./%lowcase(&packageName.).&zip."
|
||||
;
|
||||
%include &_PackageFileref_.(packagemetadata.sas) / &source2.;
|
||||
filename &_PackageFileref_. clear;
|
||||
|
||||
/* test if required version of package is "good enough" */
|
||||
%local rV pV;
|
||||
%let pV = %sysfunc(compress(&packageVersion.,.,kd));
|
||||
%let pV = %sysevalf((%scan(&pV.,1,.,M)+0)*1e8
|
||||
+ (%scan(&pV.,2,.,M)+0)*1e4
|
||||
+ (%scan(&pV.,3,.,M)+0)*1e0);
|
||||
%let rV = %sysfunc(compress(&requiredVersion.,.,kd));
|
||||
%let rV = %sysevalf((%scan(&rV.,1,.,M)+0)*1e8
|
||||
+ (%scan(&rV.,2,.,M)+0)*1e4
|
||||
+ (%scan(&rV.,3,.,M)+0)*1e0);
|
||||
|
||||
%if %sysevalf(&rV. > &pV.) %then
|
||||
%do;
|
||||
%put ERROR: Additional content for package &packageName. will not be loaded!;
|
||||
%put ERROR- Required version is &requiredVersion.;
|
||||
%put ERROR- Provided version is &packageVersion.;
|
||||
%put ERROR- Verify installed version of the package.;
|
||||
%put ERROR- ;
|
||||
%GOTO WrongVersionOFPackageAddCnt; /*%RETURN;*/
|
||||
%end;
|
||||
|
||||
/*options ls = &ls_tmp. ps = &ps_tmp. ¬es_tmp. &source_tmp.;*/
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
"&path./%lowcase(&packageName.).&zip."
|
||||
member='addcnt.zip'
|
||||
;
|
||||
/*********************/
|
||||
filename &_TargetFileref_. "&target.";
|
||||
%if %sysfunc(fexist(&_TargetFileref_.)) %then
|
||||
%do;
|
||||
|
||||
%if %sysfunc(fileexist(%sysfunc(pathname(&_TargetFileref_.))/%lowcase(&packageName.)_AdditionalContent)) %then
|
||||
%do; /* dir for AC already exists */
|
||||
%put WARNING: Target location:;
|
||||
%put WARNING- %sysfunc(pathname(&_TargetFileref_.))/%lowcase(&packageName.)_AdditionalContent;
|
||||
%put WARNING- already exist. Please remove it manually to upload additional contents.;
|
||||
%put WARNING- Additional Content will not be loaded.;
|
||||
%put WARNING- ;
|
||||
%end;
|
||||
%else
|
||||
%do;
|
||||
/*-+-+-+-*/
|
||||
/* create target location */
|
||||
%put INFO:;
|
||||
%put Additional content will be located in:;
|
||||
%put %sysfunc(dcreate(%lowcase(&packageName.)_AdditionalContent,%sysfunc(pathname(&_TargetFileref_.))));
|
||||
|
||||
%if NOT (%sysfunc(fileexist(%sysfunc(pathname(&_TargetFileref_.))/%lowcase(&packageName.)_AdditionalContent))) %then
|
||||
%do; /* dir for AC cannot be generated */
|
||||
%put ERROR: Cannot create target location:;
|
||||
%put ERROR- %sysfunc(pathname(&_TargetFileref_.))/%lowcase(&packageName.)_AdditionalContent;
|
||||
%put ERROR- Additional Content will not be loaded.;
|
||||
%put ERROR- ;
|
||||
%end;
|
||||
%else
|
||||
%do;
|
||||
/* extract addcnt.zip to work and, if successful, load additional content */
|
||||
%put NOTE- **%sysfunc(DoSubL(%nrstr(
|
||||
;
|
||||
options nonotes nosource ps=min ls=max;
|
||||
data _null_;
|
||||
call symputx("AdditionalContent", 0, "L");
|
||||
|
||||
rc1=filename("in", pathname("&_PackageFileref_."), "ZIP", "lrecl=1 recfm=n member='addcnt.zip'");
|
||||
length rc1txt $ 8192;
|
||||
rc1txt=sysmsg();
|
||||
|
||||
if fexist("in") then
|
||||
do;
|
||||
rc2=filename("out", pathname("WORK")!!"/%lowcase(&packageName.)addcnt.zip", "disk", "lrecl=1 recfm=n");
|
||||
length rc2txt $ 8192;
|
||||
rc2txt=sysmsg();
|
||||
|
||||
rc3=fcopy("in","out");
|
||||
length rc3txt $ 8192;
|
||||
rc3txt=sysmsg();
|
||||
|
||||
if rc3 then put _N_ @12 (rc:) (=);
|
||||
|
||||
if fexist("out") then
|
||||
do;
|
||||
call symputx("AdditionalContent", 1, "L");
|
||||
end;
|
||||
else put "INFO: No additional content for package &packageName..";
|
||||
|
||||
rc1=filename("in");
|
||||
rc2=filename("out");
|
||||
end;
|
||||
else
|
||||
do;
|
||||
call symputx("AdditionalContent", 0, "L");
|
||||
put "INFO: No additional content for package &packageName..";
|
||||
end;
|
||||
run;
|
||||
|
||||
%if &AdditionalContent. %then
|
||||
%do;
|
||||
filename f DUMMY;
|
||||
filename f ZIP "%sysfunc(pathname(WORK))/%lowcase(&packageName.)addcnt.zip";
|
||||
options dlCreateDir;
|
||||
libname outData "%sysfunc(pathname(&_TargetFileref_.))/%lowcase(&packageName.)_AdditionalContent";
|
||||
|
||||
data WORK.__&_TargetFileref_._zip___;
|
||||
did = dopen("f");
|
||||
if not did then
|
||||
do;
|
||||
put "ERROR: Can not access Additional Content data.";
|
||||
stop;
|
||||
end;
|
||||
if did then
|
||||
do i=1 to dnum(did);
|
||||
length file $ 8192;
|
||||
file = dread(did, i);
|
||||
output;
|
||||
keep file;
|
||||
end;
|
||||
did = dclose(did);
|
||||
run;
|
||||
|
||||
data _null_;
|
||||
set WORK.__&_TargetFileref_._zip___ end = EOF;
|
||||
wc = countw(file,"/\");
|
||||
|
||||
length libText pathname_f $ 8192;
|
||||
libText = pathname("outData", "L");
|
||||
|
||||
if scan(file, wc , "/\") = "" then
|
||||
do j = 1 to wc-1;
|
||||
libText = catx("/", libText, scan(file, j , "/\"));
|
||||
rc = libname("test", libText);
|
||||
rc = libname("test");
|
||||
end;
|
||||
else
|
||||
do;
|
||||
do j = 1 to wc-1;
|
||||
libText = catx("/", libText, scan(file, j , "/\"));
|
||||
rc = libname("test", libText);
|
||||
rc = libname("test");
|
||||
end;
|
||||
|
||||
pathname_f = pathname("f");
|
||||
rc1 = filename("in", strip(pathname_f), "zip", "member='" !! strip(file) !! "' lrecl=1 recfm=n");
|
||||
length rc1txt $ 8192;
|
||||
rc1msg = sysmsg();
|
||||
rc2 = filename("out", catx("/", libText, scan(file, j , "/\")), "disk", "lrecl=1 recfm=n");
|
||||
length rc2txt $ 8192;
|
||||
rc2msg = sysmsg();
|
||||
|
||||
rc3 = fcopy("in", "out");
|
||||
length rc3txt $ 8192;
|
||||
rc3msg = sysmsg();
|
||||
|
||||
loadingProblem + (rc3 & 1);
|
||||
|
||||
if rc3 then
|
||||
do;
|
||||
put "ERROR: Cannot extract: " file;
|
||||
put (rc1 rc2 rc3) (=);
|
||||
put (rc1msg rc2msg rc3msg) (/);
|
||||
put "ERROR-";
|
||||
end;
|
||||
crc1=filename("in");
|
||||
crc2=filename("out");
|
||||
end;
|
||||
|
||||
if EOF and loadingProblem then
|
||||
do;
|
||||
put "ERROR: Not all files from Additional Content were extracted successfully!";
|
||||
end;
|
||||
run;
|
||||
|
||||
data _null_;
|
||||
rc = fdelete("f");
|
||||
run;
|
||||
|
||||
proc delete data = WORK.__&_TargetFileref_._zip___;
|
||||
run;
|
||||
|
||||
libname outData;
|
||||
filename f DUMMY;
|
||||
%end;
|
||||
)))**;
|
||||
%end;
|
||||
/*-+-+-+-*/
|
||||
%end;
|
||||
|
||||
%end;
|
||||
%else
|
||||
%do;
|
||||
%put ERROR: Cannot access target location:;
|
||||
%put ERROR- %sysfunc(pathname(&_TargetFileref_.));
|
||||
%put ERROR- Additional Content will not be loaded.;
|
||||
%put ERROR- ;
|
||||
%end;
|
||||
filename &_TargetFileref_. clear;
|
||||
/*********************/
|
||||
%end;
|
||||
%else %put INFO: No additional content for &packageName. package.;
|
||||
%end;
|
||||
%else %put ERROR:[&sysmacroname] File "&path./&packageName..&zip." does not exist!;
|
||||
filename &_PackageFileref_. clear;
|
||||
|
||||
%WrongVersionOFPackageAddCnt:
|
||||
|
||||
/* restore optionos */
|
||||
options ls = &ls_tmp. ps = &ps_tmp.
|
||||
¬es_tmp. &source_tmp.
|
||||
&stimer_tmp. &fullstimer_tmp.
|
||||
msglevel=&msglevel_tmp.;
|
||||
|
||||
%ENDofloadPackageAddCnt:
|
||||
%mend loadPackageAddCnt;
|
||||
|
||||
|
||||
|
||||
|
||||
/**/
|
||||
111
SPF/Macros/loadpackages.sas
Normal file
111
SPF/Macros/loadpackages.sas
Normal file
@@ -0,0 +1,111 @@
|
||||
/*+loadPackageS+*/
|
||||
/*** HELP START ***/
|
||||
|
||||
%macro loadPackageS(
|
||||
packagesNames /* A comma separated list of packages names,
|
||||
e.g. myPackage, myPackage1, myPackage2, myPackage3
|
||||
required and not null.
|
||||
Package version, in brackets behind a package name,
|
||||
can be provided, e.g.
|
||||
%loadPackageS(myPackage1(1.7), myPackage2(4.2))
|
||||
*/
|
||||
)/secure
|
||||
/*** HELP END ***/
|
||||
des = 'Macro to load multiple SAS packages at one run, version 20231024. Run %loadPackages() for help info.'
|
||||
parmbuff
|
||||
;
|
||||
%if (%superq(packagesNames) = ) OR (%qupcase(&packagesNames.) = HELP) %then
|
||||
%do;
|
||||
%local options_tmp ;
|
||||
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
|
||||
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
|
||||
msglevel=%sysfunc(getoption(msglevel))
|
||||
;
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
%put ;
|
||||
%put #################################################################################;
|
||||
%put ### This is short help information for the `loadPackageS` macro #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Macro wrapper for the loadPackage macro, version `20231024` #;
|
||||
%put # #;
|
||||
%put # A SAS package is a zip file containing a group #;
|
||||
%put # of SAS codes (macros, functions, data steps generating #;
|
||||
%put # data, etc.) wrapped up together and embedded inside the zip. #;
|
||||
%put # #;
|
||||
%put # The `%nrstr(%%loadPackageS())` allows to load multiple packages at one time, #;
|
||||
%put # *ONLY* from the *ZIP* with *DEFAULT OPTIONS*, into the SAS session. #;
|
||||
%put # #;
|
||||
%put #### Parameters: #;
|
||||
%put # #;
|
||||
%put # 1. `packagesNames` A comma separated list of packages names, #;
|
||||
%put # e.g. myPackage, myPackage1, myPackage2, myPackage3 #;
|
||||
%put # Required and not null, default use case: #;
|
||||
%put # `%nrstr(%%loadPackageS(myPackage1, myPackage2, myPackage3))`. #;
|
||||
%put # Package version, in brackets behind a package name, can #;
|
||||
%put # be provided, example is the following: #;
|
||||
%put # `%nrstr(%%loadPackageS(myPackage1(1.7), myPackage2(4.2)))`. #;
|
||||
%put # If empty displays this help information. #;
|
||||
%put # #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
|
||||
%put # to learn more. #;
|
||||
%put # #;
|
||||
%put #### Example ####################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and installing & loading #;
|
||||
%put # the SQLinDS package from the Internet. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
|
||||
%put ;
|
||||
%put %nrstr( %%installPackage(SQLinDS DFA) %%* install packages from the Internet; );
|
||||
%put %nrstr( %%loadPackageS(SQLinDS, DFA) %%* load packags content into the SAS session; );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put #################################################################################;
|
||||
%put ;
|
||||
options &options_tmp.;
|
||||
%GOTO ENDofloadPackageS;
|
||||
%end;
|
||||
|
||||
%local lengthOfsyspbuff numberOfPackagesNames i packageElement packageName packageVersion str;
|
||||
|
||||
%let lengthOfsyspbuff = %qsysfunc(length(&syspbuff.));
|
||||
%let packagesNames = %qsysfunc(compress(%qsubstr(&syspbuff., 2, %eval(&lengthOfsyspbuff.-2)), {[(. _,)]}, KDA));
|
||||
|
||||
%let str = %qsysfunc(translate(%superq(packagesNames),[[ ]],{(,)}));
|
||||
%let str = %qsysfunc(transtrn(%superq(str),],%str(] )));
|
||||
%let str = %qsysfunc(compbl(%superq(str)));
|
||||
%let str = %qsysfunc(transtrn(%superq(str),%str([ ),[));
|
||||
%let str = %qsysfunc(transtrn(%superq(str),%str( [),[));
|
||||
%let str = %qsysfunc(transtrn(%superq(str),%str( ]),]));
|
||||
%let str = %qsysfunc(translate(%superq(str),(),[]));
|
||||
%let packagesNames = %unquote(&str.);
|
||||
|
||||
%let numberOfPackagesNames = %qsysfunc(countw(&packagesNames., %str( )));
|
||||
|
||||
%put NOTE: List of packages to be loaded contains &numberOfPackagesNames. element(s).;
|
||||
%put NOTE- The list is: &packagesNames..;
|
||||
%put NOTE- ;
|
||||
|
||||
%do i = 1 %to &numberOfPackagesNames.;
|
||||
%let packageElement = %qscan(&packagesNames., &i., %str( ) );
|
||||
%let packageName = %qscan(&packageElement., 1, %str(()));
|
||||
%let packageVersion = %qscan(&packageElement., 2, %str(()));
|
||||
%if %superq(packageVersion) = %then %let packageVersion = .;
|
||||
|
||||
%loadPackage(%unquote(&packageName.), requiredVersion=%unquote(&packageVersion.))
|
||||
%end;
|
||||
|
||||
%ENDofloadPackageS:
|
||||
%mend loadPackageS;
|
||||
|
||||
|
||||
159
SPF/Macros/previewpackage.sas
Normal file
159
SPF/Macros/previewpackage.sas
Normal file
@@ -0,0 +1,159 @@
|
||||
/*+previewPackage+*/
|
||||
/*** HELP START ***/
|
||||
|
||||
%macro previewPackage(
|
||||
packageName /* name of a package,
|
||||
e.g. myPackageFile.zip,
|
||||
required and not null */
|
||||
, helpKeyword /* phrase to search for preview,
|
||||
when empty prints description
|
||||
"*" means prints all */
|
||||
, path = %sysfunc(pathname(packages)) /* location of a package,
|
||||
by default it looks for
|
||||
location of "packages" fileref */
|
||||
, options = %str(LOWCASE_MEMNAME) /* possible options for ZIP filename */
|
||||
, source2 = /*source2*/ /* option to print out details,
|
||||
null by default */
|
||||
, zip = zip /* standard package is zip (lowcase),
|
||||
e.g. %previewPackage(PiPackage,*)
|
||||
if the zip is not available use a folder
|
||||
unpack data to "pipackage.disk" folder
|
||||
and use previewPackage in the form:
|
||||
%previewPackage(PiPackage, *, zip=disk, options=)
|
||||
*/
|
||||
)/secure
|
||||
/*** HELP END ***/
|
||||
des = 'Macro to preview content of a SAS package, version 20231024. Run %previewPackage() for help info.'
|
||||
;
|
||||
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
|
||||
%do;
|
||||
%local options_tmp ;
|
||||
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
|
||||
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
|
||||
msglevel=%sysfunc(getoption(msglevel))
|
||||
;
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
%put ;
|
||||
%put #################################################################################;
|
||||
%put ### This is short help information for the `previewPackage` macro #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Macro to get previwe of a SAS packages, version `20231024` #;
|
||||
%put # #;
|
||||
%put # A SAS package is a zip file containing a group #;
|
||||
%put # of SAS codes (macros, functions, data steps generating #;
|
||||
%put # data, etc.) wrapped up together and provided with #;
|
||||
%put # a single `preview.sas` file (also embedded inside the zip). #;
|
||||
%put # #;
|
||||
%put # The `%nrstr(%%previewPackage())` macro prints, in the SAS log, content #;
|
||||
%put # of a SAS package. Code of a package is printed out. #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put #### Parameters: #;
|
||||
%put # #;
|
||||
%put # 1. `packageName` *Required.* Name of a package, e.g. myPackage, #;
|
||||
%put # Required and not null, default use case: #;
|
||||
%put # `%nrstr(%%previewPackage(myPackage)).` #;
|
||||
%put # If empty displays this help information. #;
|
||||
%put # #;
|
||||
%put # 2. `helpKeyword` *Optional.* A phrase to search in preview, #;
|
||||
%put # - when empty prints description, #;
|
||||
%put # - "*" means: print all preview. #;
|
||||
%put # #;
|
||||
%put # - `path=` *Optional.* Location of a package. By default it #;
|
||||
%put # looks for location of the **packages** fileref, i.e. #;
|
||||
%put # `%nrstr(%%sysfunc(pathname(packages)))` #;
|
||||
%put # #;
|
||||
%put # - `options=` *Optional.* Possible options for ZIP filename, #;
|
||||
%put # default value: `LOWCASE_MEMNAME` #;
|
||||
%put # #;
|
||||
%put # - `source2=` *Optional.* Option to print out details about #;
|
||||
%put # what is loaded, null by default. #;
|
||||
%put # #;
|
||||
%put # - `zip=` Standard package is zip (lowcase), #;
|
||||
%put # e.g. `%nrstr(%%previewPackage(PiPackage))`. #;
|
||||
%put # If the zip is not available use a folder. #;
|
||||
%put # Unpack data to "pipackage.disk" folder #;
|
||||
%put # and use previewPackage in the following form: #;
|
||||
%put # `%nrstr(%%previewPackage(PiPackage, , zip=disk, options=))` #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
|
||||
%put # to learn more. #;
|
||||
%put # #;
|
||||
%put #### Example ####################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and installing & loading #;
|
||||
%put # the SQLinDS package from the Internet. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
|
||||
%put ;
|
||||
%put %nrstr( %%installPackage(SQLinDS) %%* install the package from the Internet; );
|
||||
%put %nrstr( %%previewPackage(SQLinDS) %%* get content of the package; );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put #################################################################################;
|
||||
%put ;
|
||||
options &options_tmp.;
|
||||
%GOTO ENDofpreviewPackage;
|
||||
%end;
|
||||
|
||||
%local ls_tmp ps_tmp notes_tmp source_tmp msglevel_tmp;
|
||||
%let ls_tmp = %sysfunc(getoption(ls));
|
||||
%let ps_tmp = %sysfunc(getoption(ps));
|
||||
%let notes_tmp = %sysfunc(getoption(notes));
|
||||
%let source_tmp = %sysfunc(getoption(source));
|
||||
%let msglevel_tmp = %sysfunc(getoption(msglevel));
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
|
||||
%local _PackageFileref_;
|
||||
/* %let _PackageFileref_ = P%sysfunc(MD5(%lowcase(&packageName.)),hex7.); */
|
||||
data _null_; call symputX("_PackageFileref_", "P" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L"); run;
|
||||
|
||||
/* when the packages reference is multi-directory search for the first one containing the package */
|
||||
data _null_;
|
||||
exists = 0;
|
||||
length packages $ 32767 p $ 4096;
|
||||
packages = resolve(symget("path"));
|
||||
if char(packages,1) ^= "(" then packages = quote(strip(packages)); /* for paths with spaces */
|
||||
do i = 1 to kcountw(packages, "()", "QS");
|
||||
p = dequote(kscanx(packages, i, "()", "QS"));
|
||||
exists + fileexist(catx("/", p, "%lowcase(&packageName.).&zip."));
|
||||
if exists then leave;
|
||||
end;
|
||||
if exists then call symputx("path", p, "L");
|
||||
run;
|
||||
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
/* put location of package myPackageFile.zip here */
|
||||
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
|
||||
;
|
||||
%if %sysfunc(fexist(&_PackageFileref_.)) %then
|
||||
%do;
|
||||
%include &_PackageFileref_.(packagemetadata.sas) / &source2.;
|
||||
filename &_PackageFileref_. clear;
|
||||
options ls = &ls_tmp. ps = &ps_tmp. ¬es_tmp. &source_tmp.;
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
|
||||
ENCODING =
|
||||
%if %bquote(&packageEncoding.) NE %then &packageEncoding. ;
|
||||
%else utf8 ;
|
||||
;
|
||||
%include &_PackageFileref_.(preview.sas) / &source2.;
|
||||
%end;
|
||||
%else %put ERROR:[&sysmacroname] File "&path./&packageName..&zip." does not exist!;
|
||||
filename &_PackageFileref_. clear;
|
||||
|
||||
options ls = &ls_tmp. ps = &ps_tmp. ¬es_tmp. &source_tmp. msglevel = &msglevel_tmp.;
|
||||
|
||||
%ENDofpreviewPackage:
|
||||
%mend previewPackage;
|
||||
|
||||
156
SPF/Macros/unloadpackage.sas
Normal file
156
SPF/Macros/unloadpackage.sas
Normal file
@@ -0,0 +1,156 @@
|
||||
/*+unloadPackage+*/
|
||||
/*** HELP START ***/
|
||||
|
||||
%macro unloadPackage(
|
||||
packageName /* name of a package,
|
||||
e.g. myPackage,
|
||||
required and not null */
|
||||
, path = %sysfunc(pathname(packages)) /* location of a package,
|
||||
by default it looks for
|
||||
location of "packages" fileref */
|
||||
, options = %str(LOWCASE_MEMNAME) /* possible options for ZIP filename */
|
||||
, source2 = /*source2*/ /* option to print out details,
|
||||
null by default */
|
||||
, zip = zip /* standard package is zip (lowcase),
|
||||
e.g. %unloadPackage(PiPackage)
|
||||
if the zip is not available use a folder
|
||||
unpack data to "pipackage.disk" folder
|
||||
and use unloadPackage in the form:
|
||||
%unloadPackage(PiPackage, zip=disk, options=)
|
||||
*/
|
||||
)/secure
|
||||
/*** HELP END ***/
|
||||
des = 'Macro to unload SAS package, version 20231024. Run %unloadPackage() for help info.'
|
||||
;
|
||||
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
|
||||
%do;
|
||||
%local options_tmp ;
|
||||
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
|
||||
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
|
||||
msglevel=%sysfunc(getoption(msglevel))
|
||||
;
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
%put ;
|
||||
%put #################################################################################;
|
||||
%put ### This is short help information for the `unloadPackage` macro #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Macro to unload SAS packages, version `20231024` #;
|
||||
%put # #;
|
||||
%put # A SAS package is a zip file containing a group #;
|
||||
%put # of SAS codes (macros, functions, data steps generating #;
|
||||
%put # data, etc.) wrapped up together and provided with #;
|
||||
%put # a single `unload.sas` file (also embedded inside the zip). #;
|
||||
%put # #;
|
||||
%put # The `%nrstr(%%unloadPackage())` macro clears the package content #;
|
||||
%put # from the SAS session. #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put #### Parameters: #;
|
||||
%put # #;
|
||||
%put # 1. `packageName` *Required.* Name of a package, e.g. myPackage, #;
|
||||
%put # Required and not null, default use case: #;
|
||||
%put # `%nrstr(%%unloadPackage(myPackage)).` #;
|
||||
%put # If empty displays this help information. #;
|
||||
%put # #;
|
||||
%put # - `path=` *Optional.* Location of a package. By default it #;
|
||||
%put # looks for location of the **packages** fileref, i.e. #;
|
||||
%put # `%nrstr(%%sysfunc(pathname(packages)))` #;
|
||||
%put # #;
|
||||
%put # - `options=` *Optional.* Possible options for ZIP filename, #;
|
||||
%put # default value: `LOWCASE_MEMNAME` #;
|
||||
%put # #;
|
||||
%put # - `source2=` *Optional.* Option to print out details about #;
|
||||
%put # what is loaded, null by default. #;
|
||||
%put # #;
|
||||
%put # - `zip=` Standard package is zip (lowcase), #;
|
||||
%put # e.g. `%nrstr(%%unloadPackage(PiPackage))`. #;
|
||||
%put # If the zip is not available use a folder. #;
|
||||
%put # Unpack data to "pipackage.disk" folder #;
|
||||
%put # and use unloadPackage in the following form: #;
|
||||
%put # `%nrstr(%%unloadPackage(PiPackage, zip=disk, options=))` #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
|
||||
%put # to learn more. #;
|
||||
%put # #;
|
||||
%put ### Example #####################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and installing & loading #;
|
||||
%put # the SQLinDS package from the Internet. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
|
||||
%put ;
|
||||
%put %nrstr( %%installPackage(SQLinDS) %%* install the package from the Internet; );
|
||||
%put %nrstr( %%helpPackage(SQLinDS) %%* get help about the package; );
|
||||
%put %nrstr( %%loadPackage(SQLinDS) %%* load the package content into the SAS session; );
|
||||
%put %nrstr( %%unloadPackage(SQLinDS) %%* unload the package content from the SAS session; );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put #################################################################################;
|
||||
%put ;
|
||||
options &options_tmp.;
|
||||
%GOTO ENDofunloadPackage;
|
||||
%end;
|
||||
|
||||
/* local variables for options */
|
||||
%local ls_tmp ps_tmp notes_tmp source_tmp msglevel_tmp;
|
||||
%let ls_tmp = %sysfunc(getoption(ls));
|
||||
%let ps_tmp = %sysfunc(getoption(ps));
|
||||
%let notes_tmp = %sysfunc(getoption(notes));
|
||||
%let source_tmp = %sysfunc(getoption(source));
|
||||
%let msglevel_tmp = %sysfunc(getoption(msglevel));
|
||||
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
|
||||
%local _PackageFileref_;
|
||||
/* %let _PackageFileref_ = P%sysfunc(MD5(%lowcase(&packageName.)),hex7.); */
|
||||
data _null_; call symputX("_PackageFileref_", "P" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L"); run;
|
||||
|
||||
/* when the packages reference is multi-directory search for the first one containing the package */
|
||||
data _null_;
|
||||
exists = 0;
|
||||
length packages $ 32767 p $ 4096;
|
||||
packages = resolve(symget("path"));
|
||||
if char(packages,1) ^= "(" then packages = quote(strip(packages)); /* for paths with spaces */
|
||||
do i = 1 to kcountw(packages, "()", "QS");
|
||||
p = dequote(kscanx(packages, i, "()", "QS"));
|
||||
exists + fileexist(catx("/", p, "%lowcase(&packageName.).&zip."));
|
||||
if exists then leave;
|
||||
end;
|
||||
if exists then call symputx("path", p, "L");
|
||||
run;
|
||||
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
/* put location of package myPackageFile.zip here */
|
||||
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
|
||||
;
|
||||
%if %sysfunc(fexist(&_PackageFileref_.)) %then
|
||||
%do;
|
||||
%include &_PackageFileref_.(packagemetadata.sas) / &source2.;
|
||||
filename &_PackageFileref_. clear;
|
||||
options ls = &ls_tmp. ps = &ps_tmp. ¬es_tmp. &source_tmp.;
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
|
||||
ENCODING =
|
||||
%if %bquote(&packageEncoding.) NE %then &packageEncoding. ;
|
||||
%else utf8 ;
|
||||
;
|
||||
%include &_PackageFileref_.(unload.sas) / &source2.;
|
||||
%end;
|
||||
%else %put ERROR:[&sysmacroname] File "&path./&packageName..&zip." does not exist!;
|
||||
filename &_PackageFileref_. clear;
|
||||
|
||||
options ls = &ls_tmp. ps = &ps_tmp. ¬es_tmp. &source_tmp. msglevel = &msglevel_tmp.;
|
||||
|
||||
%ENDofunloadPackage:
|
||||
%mend unloadPackage;
|
||||
|
||||
184
SPF/Macros/verifypackage.sas
Normal file
184
SPF/Macros/verifypackage.sas
Normal file
@@ -0,0 +1,184 @@
|
||||
/*+verifyPackage+*/
|
||||
/*** HELP START ***/
|
||||
|
||||
%macro verifyPackage(
|
||||
packageName /* name of a package,
|
||||
e.g. myPackage,
|
||||
required and not null */
|
||||
, path = %sysfunc(pathname(packages)) /* location of a package,
|
||||
by default it looks for
|
||||
location of "packages" fileref */
|
||||
, hash = /* The SHA256 hash digest for
|
||||
the package generated by
|
||||
hashing_file() function, SAS 9.4M6 */
|
||||
)/secure
|
||||
/*** HELP END ***/
|
||||
des = 'Macro to verify SAS package with the hash digest, version 20231024. Run %verifyPackage() for help info.'
|
||||
;
|
||||
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
|
||||
%do;
|
||||
%local options_tmp ;
|
||||
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
|
||||
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
|
||||
msglevel=%sysfunc(getoption(msglevel))
|
||||
;
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
%put ;
|
||||
%put #################################################################################;
|
||||
%put ### This is short help information for the `verifyPackage` macro #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Macro to verify SAS package with it hash digest, version `20231024` #;
|
||||
%put # #;
|
||||
%put # A SAS package is a zip file containing a group #;
|
||||
%put # of SAS codes (macros, functions, data steps generating #;
|
||||
%put # data, etc.) wrapped up together and embedded inside the zip. #;
|
||||
%put # #;
|
||||
%put # The `%nrstr(%%verifyPackage())` macro generate package SHA256 hash #;
|
||||
%put # and compares it with the one provided by the user. #;
|
||||
%put # #;
|
||||
%put # #;
|
||||
%put # *Minimum SAS version required for the process is 9.4M6.* #;
|
||||
%put # #;
|
||||
%put #### Parameters: #;
|
||||
%put # #;
|
||||
%put # 1. `packageName` Name of a package, e.g. myPackage, #;
|
||||
%put # Required and not null, default use case: #;
|
||||
%put # `%nrstr(%%loadPackage(myPackage))`. #;
|
||||
%put # If empty displays this help information. #;
|
||||
%put # #;
|
||||
%put # - `hash=` A value of the package `SHA256` hash. #;
|
||||
%put # Provided by the user. #;
|
||||
%put # #;
|
||||
%put # - `path=` Location of a package. By default it looks for #;
|
||||
%put # location of the "packages" fileref, i.e. #;
|
||||
%put # `%nrstr(%%sysfunc(pathname(packages)))` #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
|
||||
%put # to learn more. #;
|
||||
%put # #;
|
||||
%put #### Example ####################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and installing & loading #;
|
||||
%put # the SQLinDS package from the Internet. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* set-up a directory for packages; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
|
||||
%put ;
|
||||
%put %nrstr( %%installPackage(SQLinDS) %%* install the package from the Internet; );
|
||||
%put %nrstr( %%verifyPackage%(SQLinDS, %%* verify the package with provided hash; );
|
||||
%put %nrstr( hash=HDA478ANJ3HKHRY327FGE88HF89VH89HFFFV73GCV98RF390VB4%) );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put #################################################################################;
|
||||
%put ;
|
||||
options &options_tmp.;
|
||||
%GOTO ENDofverifyPackage;
|
||||
%end;
|
||||
|
||||
%local ls_tmp ps_tmp notes_tmp source_tmp stimer_tmp fullstimer_tmp msglevel_tmp;
|
||||
%let ls_tmp = %sysfunc(getoption(ls));
|
||||
%let ps_tmp = %sysfunc(getoption(ps));
|
||||
%let notes_tmp = %sysfunc(getoption(notes));
|
||||
%let source_tmp = %sysfunc(getoption(source));
|
||||
%let stimer_tmp = %sysfunc(getoption(stimer));
|
||||
%let fullstimer_tmp = %sysfunc(getoption(fullstimer));
|
||||
%let msglevel_tmp = %sysfunc(getoption(msglevel));
|
||||
|
||||
options NOnotes NOsource ls=MAX ps=MAX NOfullstimer NOstimer msglevel=N;
|
||||
|
||||
%local _PackageFileref_;
|
||||
/* %let _PackageFileref_ = P%sysfunc(MD5(%lowcase(&packageName.)),hex7.); */
|
||||
data _null_; call symputX("_PackageFileref_", "P" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L"); run;
|
||||
|
||||
/* when the packages reference is multi-directory search for the first one containing the package */
|
||||
data _null_;
|
||||
exists = 0;
|
||||
length packages $ 32767 p $ 4096;
|
||||
packages = resolve(symget("path"));
|
||||
if char(packages,1) ^= "(" then packages = quote(strip(packages)); /* for paths with spaces */
|
||||
do i = 1 to kcountw(packages, "()", "QS");
|
||||
p = dequote(kscanx(packages, i, "()", "QS"));
|
||||
exists + fileexist(catx("/", p, "%lowcase(&packageName.).zip"));
|
||||
if exists then leave;
|
||||
end;
|
||||
if exists then call symputx("path", p, "L");
|
||||
run;
|
||||
|
||||
filename &_PackageFileref_.
|
||||
/* put location of package myPackageFile.zip here */
|
||||
"&path./%lowcase(&packageName.).zip"
|
||||
;
|
||||
%if %sysfunc(fexist(&_PackageFileref_.)) %then
|
||||
%do;
|
||||
/* create hash SHA256 id *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
%local HASHING_FILE_exist;
|
||||
%let HASHING_FILE_exist = 0;
|
||||
|
||||
%if %sysfunc(exist(sashelp.vfunc, VIEW)) %then
|
||||
%do;
|
||||
data _null_;
|
||||
set sashelp.vfunc(keep=fncname);
|
||||
where fncname = "HASHING_FILE";
|
||||
call symputX('HASHING_FILE_exist', 1, "L");
|
||||
stop;
|
||||
run;
|
||||
%end;
|
||||
|
||||
%if &HASHING_FILE_exist. = 1 %then
|
||||
%do;
|
||||
options notes;
|
||||
filename &_PackageFileref_. list;
|
||||
|
||||
data _null_;
|
||||
length providedHash $ 100;
|
||||
providedHash = strip(symget("hash"));
|
||||
select;
|
||||
when ( 'F*' = upcase(substr(providedHash,1,2)) ) /* F = file digest */
|
||||
SHA256 = 'F*' !! HASHING_FILE("SHA256", pathname("&_PackageFileref_.",'F'), 0);
|
||||
when ( 'C*' = upcase(substr(providedHash,1,2)) ) /* C = content digest */
|
||||
SHA256 = 'C*' !! HASHING_FILE("SHA256", "&_PackageFileref_.", 4);
|
||||
otherwise /* legacy approach, without C or F, digest value equivalent to C */
|
||||
SHA256 = HASHING_FILE("SHA256", "&_PackageFileref_.", 4);
|
||||
end;
|
||||
put "Provided Hash: " providedHash;
|
||||
put "SHA256 digest: " SHA256;
|
||||
put " ";
|
||||
|
||||
if upcase(SHA256) = upcase(providedHash) then
|
||||
do;
|
||||
put "NOTE: Package verification SUCCESSFUL.";
|
||||
put "NOTE- Generated hash is EQUAL to the provided one.";
|
||||
end;
|
||||
else
|
||||
do;
|
||||
put "ERROR: Package verification FAILED!!";
|
||||
put "ERROR- Generated hash is DIFFERENT than the provided one.";
|
||||
put "ERROR- Confirm if the package is genuine.";
|
||||
end;
|
||||
run;
|
||||
%let HASHING_FILE_exist = 0;
|
||||
%end;
|
||||
%else
|
||||
%put WARNING: Verification impossible! Minimum SAS version required for the process is 9.4M6. ;
|
||||
/*-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-*/
|
||||
%end;
|
||||
%else %put ERROR:[&sysmacroname] File "&path./&packageName..zip" does not exist!;
|
||||
filename &_PackageFileref_. clear;
|
||||
|
||||
options ls = &ls_tmp. ps = &ps_tmp.
|
||||
¬es_tmp. &source_tmp.
|
||||
&stimer_tmp. &fullstimer_tmp.
|
||||
msglevel=&msglevel_tmp.;
|
||||
|
||||
%ENDofverifyPackage:
|
||||
%mend verifyPackage;
|
||||
/**/
|
||||
|
||||
1068
SPF/SPFinit.md
Normal file
1068
SPF/SPFinit.md
Normal file
File diff suppressed because it is too large
Load Diff
4858
SPF/SPFinit.sas
4858
SPF/SPFinit.sas
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2019 - 2020 Bartosz Jablonski
|
||||
Copyright (c) 2019 - 2023 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
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
## Available packages:
|
||||
Currently the following packages are available:
|
||||
## SAS Packages:
|
||||
To get started with SAS Packages try this [**`Getting Started with SAS Packages`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/Getting_Started_with_SAS_Packages.pdf "Getting Started with SAS Packages") presentation (see the `./SPF/Documentation` directory).
|
||||
|
||||
- **SQLinDS**\[2.1\], 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.
|
||||
```
|
||||
## Available packages:
|
||||
For "backward compatibility"/historical point of view the following packages are available under the `./packages` directory.
|
||||
|
||||
Since *September 2022* the default location for packages is **SASPAC - the SAS Packages Archive** located under: [`https://github.com/SASPAC`](https://github.com/SASPAC) where each package is stored as a separate repository with historical versions too.
|
||||
|
||||
Packages:
|
||||
|
||||
---
|
||||
|
||||
- **SQLinDS**\[2.2.7\], 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.
|
||||
```sas
|
||||
data class;
|
||||
set %SQL(
|
||||
select age, name, weight, height
|
||||
@@ -13,10 +22,15 @@ data class;
|
||||
WH = weight + height;
|
||||
run;
|
||||
```
|
||||
SHA256 digest for SQLinDS: F*42DC179E1D2B946AD519C4EC04A068061B312E021C3F4BC4826D2775E116E1B9
|
||||
|
||||
- **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.
|
||||
```
|
||||
%createDFArray(ArrDynamic, resizefactor=17);
|
||||
[Documentation for SQLinDS](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/sqlinds.md "Documentation for SQLinDS")
|
||||
|
||||
---
|
||||
|
||||
- **DFA** (Dynamic Function Arrays)\[0.5.6\], 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.
|
||||
```sas
|
||||
%createDFArray(ArrDynamic, resizefactor=17);
|
||||
|
||||
data _null_;
|
||||
call ArrDynamic("Allocate", -2, 2);
|
||||
@@ -41,24 +55,39 @@ data _null_;
|
||||
end;
|
||||
run;
|
||||
```
|
||||
SHA256 digest for DFA: F*09EA5201360922A91A9EEE72F4567792E9CFDFB591BA33419E2BF2B31D9B7C62
|
||||
|
||||
- **macroArray**\[0.3\], implementation of an array concept in a macrolanguage, e.g.
|
||||
```
|
||||
[Documentation for DFA](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/dfa.md "Documentation for DFA")
|
||||
|
||||
---
|
||||
|
||||
- **macroArray**\[1.1.1\], implementation of an array concept in a macro language, e.g.
|
||||
```sas
|
||||
%array(ABC[17] (111:127), macarray=Y);
|
||||
|
||||
%macro test();
|
||||
%do i = 1 %to 17;
|
||||
%put &i.) %ABC(&i.);
|
||||
%end;
|
||||
%mend;
|
||||
%test()
|
||||
|
||||
%let %ABC(13,i) = 99999; /* i = insert */
|
||||
|
||||
%do i = 1 %to 17;
|
||||
%put &i.) %ABC(&i.);
|
||||
%end;
|
||||
|
||||
%let %ABC(13,i) = 999; /* i = insert */
|
||||
|
||||
%do i = 1 %to 17;
|
||||
%put &i.) %ABC(&i.);
|
||||
%end;
|
||||
%do_over(ABC, phrase=%nrstr(
|
||||
%put &_i_.%) %ABC(&_i_.);
|
||||
),
|
||||
which = 1:H:2
|
||||
);
|
||||
```
|
||||
SHA256 digest for macroArray: F*E9C0C58FB36AC40C76A518066B8C6F9942202A9DB2C2D737E95D2BB6E4ECED50
|
||||
|
||||
- **BasePlus**\[0.5\] adds a bunch of functionalities I am missing in BASE SAS, such as:
|
||||
```
|
||||
[Documentation for macroArray](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/macroarray.md "Documentation for macroArray")
|
||||
|
||||
---
|
||||
|
||||
- **BasePlus**\[1.32.0\] adds a bunch of functionalities I am missing in BASE SAS, such as:
|
||||
```sas
|
||||
call arrMissToRight(myArray);
|
||||
call arrFillMiss(17, myArray);
|
||||
call arrFill(42, myArray);
|
||||
@@ -69,8 +98,41 @@ string = catXFn("date9.", "#", myArray);
|
||||
|
||||
format x bool.;
|
||||
|
||||
%put %getVars(sashelp.class, patern = ght$, sep = +, varRange = _numeric_);
|
||||
%put %getVars(sashelp.class, pattern = ght$, sep = +, varRange = _numeric_);
|
||||
|
||||
%rainCloudPlot(sashelp.cars,DriveTrain,Invoice)
|
||||
|
||||
%zipLibrary(sashelp,libOut=work)
|
||||
|
||||
%bpPIPE(ls -la ~/)
|
||||
|
||||
%dirsAndFiles(C:\SAS_WORK\,ODS=work.result)
|
||||
|
||||
%put %repeatTxt(#,15,s=$) HELLO SAS! %repeatTxt(#,15,s=$);
|
||||
|
||||
%put %date() %time() %datetime();
|
||||
|
||||
%put %monthShift(2023,1,-5);
|
||||
```
|
||||
SHA256 digest for BasePlus: F*3407AD8068C7528E129034144F9A44CFDF14B7DC34334C64C2F1D67351D1E01E
|
||||
|
||||
- **dynMacroArray**\[0.2\], set of macros (wrappers for a hash table) emulating dynamic array in the data step (macro predecessor of DFA)
|
||||
[Documentation for BasePlus](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/baseplus.md "Documentation for BasePlus")
|
||||
|
||||
---
|
||||
|
||||
- **GSM** (Generate Secure Macros)\[0.21.1\], package allows
|
||||
to create secured macros stored in SAS Proc FCMP functions.
|
||||
The dataset with functions can be shared between different operating systems
|
||||
and allows to generate macros on site without showing their code.
|
||||
|
||||
SHA256 digest for GSM: F*2FECDDB568B38E206CA4ADA6FDEF5209C0A08B99401A1510D777BABF9DA54682
|
||||
|
||||
[Documentation for GSM](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/gsm.md "Documentation for GSM")
|
||||
|
||||
---
|
||||
|
||||
- **dynMacroArray**\[0.2.6\], set of macros (wrappers for a hash table) emulating dynamic array in the data step (macro predecessor of DFA). Development of this package is currently on hold.
|
||||
|
||||
SHA256 digest for dynMacroArray: F*F50BEDB542D96B07C763EAB7549FBC5F08ED389DC2338BFAAEBFBD1FD20E22B6
|
||||
|
||||
---
|
||||
|
||||
301
packages/SHA256_for_packages.txt
Normal file
301
packages/SHA256_for_packages.txt
Normal file
@@ -0,0 +1,301 @@
|
||||
/* 20231026 */
|
||||
BasePlus: F*3407AD8068C7528E129034144F9A44CFDF14B7DC34334C64C2F1D67351D1E01E
|
||||
|
||||
/* 20231012 */
|
||||
BasePlus: F*7EF23E80A2C03B29402183D97ECFF608B62BEDD9458848709B52DC362E6201B9
|
||||
|
||||
/* 20230921 */
|
||||
macroArray: F*E9C0C58FB36AC40C76A518066B8C6F9942202A9DB2C2D737E95D2BB6E4ECED50
|
||||
|
||||
/* 20230919 */
|
||||
BasePlus: F*B91771D45C781B6806DBB44A3B491A0784D7698B9F3BBBE1A86EE5594834315F
|
||||
|
||||
/* 20230906 */
|
||||
macroArray: F*6A22A01868F4203862B3685F543D723C7DB8E9AB3C1A6357D2BFA030971B0D3C
|
||||
|
||||
/* 20230904 */
|
||||
BasePlus: F*2FE68DD9B3692B9D46EF85B82F63C7E65010BF9E89D670FD1779F4670FA03F31
|
||||
DFA: F*09EA5201360922A91A9EEE72F4567792E9CFDFB591BA33419E2BF2B31D9B7C62
|
||||
dynMacroArray: F*F50BEDB542D96B07C763EAB7549FBC5F08ED389DC2338BFAAEBFBD1FD20E22B6
|
||||
GSM: F*2FECDDB568B38E206CA4ADA6FDEF5209C0A08B99401A1510D777BABF9DA54682
|
||||
macroArray: F*4FAAEE7DF2854EA31933AE017A89C1615C7291A66A07CCE345041EB0D587ED4E
|
||||
SQLinDS: F*42DC179E1D2B946AD519C4EC04A068061B312E021C3F4BC4826D2775E116E1B9
|
||||
|
||||
/* 20230824 */
|
||||
BasePlus: F*9EEE4F4B99EA725B60141645AB6A50BFEBA32CE54848593F8D832D907D63CAD7
|
||||
|
||||
/* 20230727 */
|
||||
GSM: F*56DC0DCCE06B4281BF3FA6FA3875CBA87772BDA7FAB601B06740A7980FFB0E07
|
||||
|
||||
/* 20230602 */
|
||||
BasePlus: F*D6DC5AD1B60A92AD300B639B3C361C1F7846EB01E5AB35BF4FDDA6E783408172
|
||||
|
||||
/* 20230601 */
|
||||
BasePlus: F*B3CACDA32A5E70940E667DCA859483BD76DB082D19BAF326F28A580226DDD962
|
||||
|
||||
/* 20230526 */
|
||||
BasePlus: F*2A4F3953EC56DB914024457F74286D565C23DCF220FF151040BDB704FD8DDB06
|
||||
|
||||
/* 20230520 */
|
||||
BasePlus: F*0CCAA009D64CC20ED315FA123C233E0383967E635EB8708E7A48EEE3767C6BC5
|
||||
|
||||
/* 20230503 */
|
||||
BasePlus: F*B297440903337E1AE6F12A6001B80B8AB743079847D16D63DF1C649AE51AA411
|
||||
|
||||
/* 20230419 */
|
||||
BasePlus: F*625E56B017C4AA8D436959C0A03C8503773A9A3823D43FA9E0326276E52DA6F2
|
||||
|
||||
/* 20230417 */
|
||||
BasePlus: F*F39F38CE80A5D8EED3BC9F2413CD6DEF38E8657E5DCF427CBA8938EB8C4350B6
|
||||
|
||||
/* 20230411 */
|
||||
BasePlus: F*B5BF05531BF78DCEBC436BD93311FED0436D83AA3D106ABFBAD96B04C7D63DF2
|
||||
DFA: F*924711C77E413B8CFC18336DDA2293A9F5294D02E267C1BB7BC876B4AF0AABE4
|
||||
dynMacroArray: F*6E087F38BB39B93CBF983124272812E14693C4EF5EE0A3A218BD2BAA069A74BF
|
||||
GSM: F*91C619E47EFAB44CCEB8B892BA1D7A8F9948590DA1317B8EA330F5D12642CE0E
|
||||
macroArray: F*85E3BE4D163AC5223B6EC9D3C25C46564A656E3830998B4555A963180D767160
|
||||
SQLinDS: F*3BB422E8C94515DEE9E13E674A0D119794F464D9597C28D5D536E71F64EB5298
|
||||
|
||||
/* 20230401 */
|
||||
BasePlus: F*AD0B78F94A6FD1C394999CBBC8DD16017FB06DFC3FA1F51AC17B43AC8F517432
|
||||
|
||||
/* 20230210 */
|
||||
SQLinDS: F*229ACF1A62E5194A25C75D8E554BEF1B7D29227A498ED5862F23892BB0D57644
|
||||
|
||||
/* 20221215 */
|
||||
BasePlus: A6F1977DC4EC22A39DDC7BCE68CF562AF54351A3D385D488EC3067B5A7C0F3CB
|
||||
DFA: 6DEB02BE1C30453FBC688AF1F561709C7D6BF10B3B67988B238853A2A9D53034
|
||||
dynMacroArray: 7800F36877DC0B9A94B1AC8FFDF8B43ADB216F11B5B26343E41165E7F5E32FC0
|
||||
GSM: 83EC349DF97EFA71187536E8CC6CD62215CE675D20DA355E14D4ACE3FBC6D524
|
||||
macroArray: 8584C249C308B5E8B620ED5F695BC58CD426172FB2EACD5FF9C6899F9DE2B470
|
||||
SQLinDS: 42677CEBB0778A6B72DE9C0071B66A345811EE470289E3847D7737F782E709E0
|
||||
|
||||
|
||||
/* 20221125 */
|
||||
BasePlus: D8DBB7CC5952331FA59FEBBBDD15BC543FE3C89A8BA9150FE6AF5E412868EBE7
|
||||
DFA: 7520CF21CBF1FD4AD2BC05C5DD343E508FCEA507575EBC060B4AD322FB80AB04
|
||||
dynMacroArray: 440920272D1838505EA5C033B1C448C612DE2FCCFD57F157BB90ED980E4001CC
|
||||
GSM: 50D8340E080BEA459E68BE315146AD3B809930DB8DC7B23C7A492C3815ACD83F
|
||||
macroArray: 244B88C82AD7E6E93B8B85BC701ECDDB20B68F38B16C500EE9B49E1167ADC298
|
||||
SQLinDS: D5A66E60602270E5FB1E592FA3E0C2F2C640BC077FE799A2223CB9BA275F6F47
|
||||
|
||||
|
||||
/* 20221121 */
|
||||
BasePlus: EBA9EDB3D50D854288970CC0E965DA6AD5B057F6E6433EEBEC4A02B9A25CF6E2
|
||||
DFA: 3F618EDAC8B4F4BE6C19D606E6BCC58121A16BA1383D2EE64C680B4B7FA9C96A
|
||||
dynMacroArray: DD0BF1768DA05EBB5F8C6E7409A0929E28DF11CB499F75B433D9648855AACAE4
|
||||
GSM: E47C94B536B661DEE390F5C3EA1684DD1A246106F4FBBDAFA57F5E34D4BB16D5
|
||||
macroArray: DA57FFE85F49201FD61A53411D19E97FB5A6AC3C34E34FDF4B913545699551FF
|
||||
SQLinDS: 085F0B8BD4A59343E2913FF9635EA6E551ADD54E9678C35F5096D4A0A895B9C5
|
||||
|
||||
/* 20221112 */
|
||||
BasePlus: A80006D3C1409465E49F383D08F2F3AF1E33D6A67D71A8CAF29747ADC917E2E4
|
||||
DFA: 5A6FD2F6E962E6C191346A141FFAF354E35A546CA93146B55D7C6163BFB1BDD6
|
||||
dynMacroArray: C987C08615A53D7BD7AEC3911EADF436C676EAB3E233E7E422E42995B890E169
|
||||
GSM: 5D1925970C9590CD195C15B8641B01D7857E3B2546323DC77D09154BCCA40922
|
||||
macroArray: 371B92A5ABBE82C53F7D63BC5C0D1EBD4695603D3894D8A9A5D5777D1AB59B30
|
||||
SQLinDS: A070214517CC36590083FCF9D5F488AC6E746793E94B9AA55D09A419CF291B5B
|
||||
|
||||
/* 20220830 */
|
||||
BasePlus: 56B260350FEB7D5118F581B9EFD1B9CE1F0298DCB9A4C000A7654E2FF3F0298C
|
||||
DFA: 5BFFCE78439E1CDDCBB15C95CD287AA4195BF64BB17DDB8FE374EC3535B4F491
|
||||
dynMacroArray: D7E0B8F85C05EBF8622204E0D2F3E990D48D0A9B3911051C3AD44DC98954DDCF
|
||||
GSM: 2AEBC150FBA99A4AAB0265A21C57E89200BFD96B633B898F32743D1C8831A159
|
||||
macroArray: ED12BC96F8A4E9E7C4D651EC1E15479DB9B55D98B274B63C507ED842081F7AB7
|
||||
SQLinDS: 96D0EFE02DF1AE0D7D875A10CAF7EF63CDEF85DD0CF9418934BEFAF0C067D453
|
||||
|
||||
/* 20220511 */
|
||||
BasePlus: 619D4B2562F1D9E42C9C5DCB326E8F4D6A020B5D0CEE29A6174F65F8E1B0E7BD
|
||||
|
||||
/* 20220509 */
|
||||
BasePlus: 4CD3926B9842925C86B80B5B47B47BEA1FB9707826B545B9B4D52AE97BC3617E
|
||||
|
||||
/* 20220508 */
|
||||
BasePlus: 0331C673052D5221DA98C5CC93295634D8A0BC62C7D2FEF9D0D85B0B2DEDE4E9
|
||||
|
||||
/* 20220420 */
|
||||
BasePlus: 12A9A2155D9C6F969DF0A66E3A18D0938B8194FA3AA9D70EDDE1CB71DEF9691E
|
||||
DFA: 6B3FB0B06B47A7EF1BB004B483B0F39B8F553F7F16D02A7E24CDE388BBA704EA
|
||||
dynMacroArray: 7DA9BFDED37C18C4FB5BD7579A81A4B2578EEEF1546D1A3AB5C80DE07C88A615
|
||||
GSM: E6E2A6214EE7DC6E06AA76916A68B216DD7665184E63CF2C01F487A038E71B09
|
||||
macroArray: DF63B0E027827A82038F1C8422787A0BC569BA93104BA1778DB6DD088A5D255C
|
||||
SQLinDS: 701B69BE71B99792803BCE7718ED486259310FFB92E6D77ED1BC029D9CC67B60
|
||||
|
||||
/* 20220406 */
|
||||
GSM: BE9508C8E37706B2EB2FBCA68B64F7DCF63C65E8E24775C92E28FE34E547893D
|
||||
|
||||
/* 20220307 */
|
||||
GSM: F63B8C602C1DB02F4107D9AF78182D87CD64AEA6521163067B7EB6D5C1B368AF
|
||||
|
||||
/* 20220307 */
|
||||
GSM: 8D730316043A6523A3AF2AA15D2820BB75A46E06307F2B8916D30AC102AEE31D
|
||||
|
||||
/* 20220217 */
|
||||
macroArray: DAEB87654D99965BF2B7A6AB14626B3E617D0ABF526E77725DF89A1AB4C812C2
|
||||
|
||||
/* 20220113 */
|
||||
BasePlus: A60A300E083628C65DD6899E7EF95588916F8F66B6A25B32B3228987B6F74857
|
||||
DFA: 5F89AC6AE628EB27D87FF6A9D72A515FFA3FF6694D04DE0D9811BFFB81444ABB
|
||||
dynMacroArray: 766DF3F330B87E99FAC32A00A569D9A45DA1157F591DE34DD0892CD864779409
|
||||
GSM: 3B70D8C31F02CB2B6AC47CC1DB3EC9E462796226CBFF519936AF5EEDB0C46B8F
|
||||
macroArray: 833D747526F4CE83FFD73F9EB3A2A9065401B498DFEC79045A28A42E0E57A8CA
|
||||
SQLinDS: DCAB62267B52822F416BA7E6713A696D843E8092A4E3A37DF06CBE1E1D5DAD11
|
||||
|
||||
/* 20220111 */
|
||||
BasePlus: 1B6AA5A38846C30B3DD3E9FED86CB4ECACF25FBAF3011CBE108ED996C3FBB823
|
||||
|
||||
/* 20211228 */
|
||||
macroArray: 95164E71AF0B86AC816F13821F6468F611C6E5BB9036AC10459CDEB10487B08E
|
||||
|
||||
/* 20211123 */
|
||||
BasePlus: 105F0CEB95C49102BDB085DF67C785301F623CB337D466F07B5E051626E4AE61
|
||||
|
||||
/* 20211119 */
|
||||
BasePlus: 55AC07F7322F504EF22C5D00D46587744CD373E70A83932F837EA8C6ECB6D987
|
||||
|
||||
/* 20211114 */
|
||||
BasePlus: 319109732B5CBD99ADDA6D48EA26DA5236622F9C5D332F94EF282F1C9DCE73F9
|
||||
|
||||
/* 20211113 */
|
||||
BasePlus: 4EDB786B9D6F6D6C5741B5CAC1CB169DD10D8196600B2CB385DDE479A54F0FA3
|
||||
|
||||
/* 20211112 */
|
||||
GSM: F6EE77A3C042E1E083E970BE255D126B52A75205DC1FB9A4A7337D0A89EEC7EB
|
||||
|
||||
/* 20211111 */
|
||||
BasePlus: B34E352EC52E05B8BBE1816E6104F47677CBFDEAF7CD71B8BF04FDBFA01B0EF0
|
||||
DFA: C32A81304A411C1EB6BA7B76EDB8D70550F3935F35A1506E2B8019A2036FB5FF
|
||||
dynMacroArray: 9FE227EF3144431B51063D599148BDD8873509D1B32F1AC2979EC566E1BB1487
|
||||
GSM: BEFAA87266D6DBA3D5983117FC36A24DE03A2F93791AC786DCDB37571A4494AC
|
||||
macroArray: 70032D27081A0EE15BC82B8F14D2A61700FA7C1F0D88B4DB516AB433CD06C4D3
|
||||
SQLinDS: F2BE3CC68C9A34DD324FD35C8287A4F89737E2E28E806E0DD7FB0EBF60F7C569
|
||||
|
||||
/* 20211105 */
|
||||
GSM: 3EAF6E93642CCA9B5B592DF9BED4C8B20B60BCD4B0434720D12D26096717C4A9
|
||||
|
||||
/* 20211005 */
|
||||
BasePlus: D01BDFB50EF023EF51806F5F0ED664523C1A6F25AA2778808558C212E6D74725
|
||||
|
||||
/* 20211001 */
|
||||
BasePlus: 5EAEF846754F19759C0492308478417C9667C9651F1EF14F70E4FF8AB4C857F6
|
||||
|
||||
/* 20210908 */
|
||||
GSM: 93D88D4465B68984E938212241DE55C7B12EBC20601538553AC9E1AC0628C006
|
||||
|
||||
/* 20210818 */
|
||||
BasePlus: C9D26CAC2504634EF25F02B5BD04596B2F873E3C25E8CEDDD7F496A78B184E9F
|
||||
|
||||
/* 20210726 */
|
||||
GSM: 2FC239B5A2216D073826125999BFD64FBA32BFEA3EE6EA2B22EC64E8C1B04144
|
||||
|
||||
/* 20210722 */
|
||||
GSM: 311BCF510B7B189AE9A75C56C4D2F99F844114CC5AD32329FAD690BA1F10422A
|
||||
|
||||
/* 20210719 */
|
||||
GSM: 4322D79C382B9D58EF5E51AFD0856331F8B38B1B35AC21295DADFC43F81B2AF8
|
||||
|
||||
/* 20210716 */
|
||||
GSM: 7134C8672023972BA0D5D5CE1E611F0DBB5F60ADAE847BC59C94FF7E2BEC0278
|
||||
|
||||
/* 20210528 */
|
||||
BasePlus: A321A4BC54D444B82575EC5D443553A096557AD69DC171D578A330277E67637A
|
||||
DFA: 22AB51B85E3344B8C0FB7AF164247881B656F5CBA88BBA974AD8BC41ED79327F
|
||||
dynMacroArray: 67956116578E71327748B7EB3DAFF9D872DBC6F6EDD0DC11B7CF2A54FDA71785
|
||||
macroArray: 849629D3AF3FE3AB45D86990E303F1D5E4D5F9F31C8ED6864C95B0DFAADCA445
|
||||
SQLinDS: 1853CD6262CF66582A33C373AA612CA714B61CB88A1C51745E7A57D5A03C39B4
|
||||
|
||||
/* 20210117 */
|
||||
DFA: 179AAB9DF3DE8F049A4EFDF5FB0BE92AE5F7BFA7708D4365F39D4DC71C4F90FE
|
||||
|
||||
/* 20210109 */
|
||||
BasePlus: 28F3DE865C5E3B914FFB7CC2627D8B0975527EEECEE7AFEAD7B335C3FDC1BFD3
|
||||
DFA: E777D4578DFDEB2277D58264BAB5BFDBEAFD4E538D4831CDCBFFB4216D2441C2
|
||||
dynMacroArray: 8B0777EA3CF41968C0B029AA57B1F809D21D1BAB1B88A35B0EA5DB3C6DD9E748
|
||||
macroArray: 42E87B80450B3E1AD462B9B63B41F34C83B7745AA0F98C3CA72AA19F3B1FF10E
|
||||
SQLinDS: 3034A0C8AC43683AD55698861DBBDEBDE6FC8567D59ECF2BB5F3389FE6BC8062
|
||||
|
||||
/* 20201229 */
|
||||
DFA: 5B41657A8A3BEAD185B13D072BC54902AB81FEAD32330DA8ABA90CF777D4D76E
|
||||
|
||||
/* 20201207 */
|
||||
macroArray: AC3AD58AFBBE459616743DC6346330BD8DD33FBA8CDD595423F181B67D0475BC
|
||||
BasePlus: 9EA40F72191D1916189F043315CA519F6E42CEB05C186F7653AE464D21D21CFB
|
||||
|
||||
/* 20201202 */
|
||||
BasePlus: 7933E6BCFDCA7C04EAAC537773574799759007A5D2AED639E86CF4EA631F1351
|
||||
|
||||
/* 20201130 */
|
||||
DFA: 1FC8D030D576C33F1B5DEB27E17534946209BC148D57A1357CA025ED1E69AEB8
|
||||
|
||||
/* 20201115 */
|
||||
BasePlus: B25A3992B6FCD13528BEE462B3ADD0F5A6D15E607A6DABAA984CA66B0AD69415
|
||||
DFA: C795736F55B3C6EFBEF2E82362694EB017D37C54E6AEC3EB0F6F813F69F54B5F
|
||||
dynMacroArray: 5E8CCC88CC048A0B564CEE37C6CF4013857D9CFF3FA1B6B9AD6F719D08B30005
|
||||
macroArray: 0F1B985E2FC34C91D2A3BD237DC294502A76913B71266D76702A5E77A78C9CA7
|
||||
SQLinDS: CE1A266B9030E5E336B45F53DF483F6913FD8AE88A2884CEE88BEEF621FDBD78
|
||||
|
||||
/* 20201103 */
|
||||
BasePlus: 612095260F73D00A08D64C49FC57F4D5BEE0AFBA9D8194AE63EA5BCF7A15E068
|
||||
DFA: 069BD1BD482634F2D6EB3EFF68E7F8569D2F2C232BFF5D7D44BBD839D8F224A4
|
||||
dynMacroArray: CA9BFF0747019BA6FDB2107C60F58D2D6C5E686EADFA4E1C6A81BC469CBC9F4A
|
||||
macroArray: 0DB634148FA104F4AD9D6A522466D605118EE8696774DC1BB7C4145ED3BB9B9B
|
||||
SQLinDS: 9788D7ED2863B2B0A575EB9AB07B5F88AE79A56D9ED9B3B4F15A02E34DF7AA64
|
||||
|
||||
/* 20201029 */
|
||||
MacroCore: A23C29529F3CE7D0C8BEE9545C5D22D5B5594907547374A5135B8E5A48D7687B
|
||||
|
||||
/* 20201023 */
|
||||
macroArray: 75056F508E96296DC50096BBB054C58334DB913AD37885958099EDCE0C330CB2
|
||||
|
||||
/* 20201020 */
|
||||
BasePlus: 9549378E5F81DA4DC421C366DF006D270261852336CE3DCD88FF8E2A759938C8
|
||||
|
||||
/* 20201018 */
|
||||
BasePlus: BDEA8AA6EED9739284ABF8297BEC7EC0F12490D72EF9B685F477E99AFA734B82
|
||||
DFA: E67A0863992722A5F535F56E14EF8D19A55F74FB374447BF11B5ED74029C29CB
|
||||
dynMacroArray: 694AACE925B7F4E149C3B90383F56370ED76233D8F5040713D66C1F3A4E414FE
|
||||
macroArray: 42771AA7CD2A0608E1EE25F104F21CCCC296919910E4BCA7AD9AE46A291BB8D7
|
||||
SQLinDS: 135DC50C0412B8CEAF6D5349B8A203C0ADB23D4F5C2680B6A35FD2E5482B6C49
|
||||
|
||||
/* 20201017 */
|
||||
macroArray: 022A7CD5F0C1E72032CC3426A8AC53D61A8766868B6B48195BC69F59007323B8
|
||||
|
||||
/* 20201014 */
|
||||
BasePlus: 4E0C2A45CF8A5863C0D054568C712D10A296240877D604E77A778451A740874B
|
||||
DFA: CC19058354D4B51F0675A8414F18089CCC583AA45822CEFC79368F06D8715846
|
||||
dynMacroArray: 0854317DE7A97DCFE30411B37D909F04BBE12F1F9F7C45D39CBCD61641158F80
|
||||
macroArray: 96215AC04EF26C97719F6B1EDA5ACAF7DD491B7F2DDDE9985A0560CD2916ABA1
|
||||
SQLinDS: FCD7EE5B59E08CD1A2E31F6A5D94D7275C99AFFAACEA3D187F60A57CD0520FCD
|
||||
|
||||
/* 20201010 */
|
||||
SQLinDS: D76B85EFF129678B45233FB397A2BDB8D23F234013BD821D55141CA18DD5589E
|
||||
DFA: 43AE8BB0FC7D2121AABDD8DB8AD2C3F226C7D2699CAACC171FCB72B75D9141FA
|
||||
macroArray: 085A0F3D544EAF01378BB6C6B4F429123F8BFEEFC76013D1B05DFADFEE3FA661
|
||||
BasePlus: 54232DA5E253EB58E49A09DD0DF244F433B61983D921E27F2E4FFB1EA73A5C6D
|
||||
dynMacroArray: 281D9493564A8185B858D9525AA7D9D5343E42414AAB1D8A00AE85AB80882661
|
||||
|
||||
/* 20201007 */
|
||||
BasePlus: 884BAD527DE77A9AF4325053BF42B3B2FCD3DB1239B63D70B1198064095E1A6D
|
||||
DFA: 57944FF5ABC7A9879C402412DA0C18C38206301930DC834BC7DD3E968E283D1E
|
||||
dynMacroArray: 20B27D2CACCC17DE9AB70F7AA7105FF1B29397584538632CAE167A687ACD859A
|
||||
macroArray: F2AF51F9271B4AF5366DCC4E6403407393F245561B98A89C0F1699A6BCA84772
|
||||
SQLinDS: AE2093A1D28F93FA665B4174FC38C0487C489D2B281FE398FF18CA738D841155
|
||||
|
||||
/* 20201003 */
|
||||
BasePlus: 66E966489F4C183CA75FC32D3AF581FEC20FC9C5FF0C36E4DDC5A14BBDA82EAB
|
||||
|
||||
/* 20200914 */
|
||||
macroArray: 53C248E1DE3268946C9CEC7E77BC222F652FBB006D9317BE36B86410DA31AE35
|
||||
SQLinDS: B280D0B72DB77001ADAAE9C1612B67AD30C2C672371B27F1ACB12016C7A1363D
|
||||
|
||||
/* 20200914 */
|
||||
SQLinDS: DD5E319EB5AA29C7054EC428072F987E77C29D36874DED1AE5C62E4B300845EB
|
||||
macroArray: 69F6CF496F921D0E21F3524FC7FD130B4B8290C1E0B9BB3ABEA212B734EBE8A1
|
||||
|
||||
/* 20200911 */
|
||||
sqlindsdemo: CCA3CB51587E30D1A4338EAF732EF03E0922918AAA21C3ECF85CABE93CD2FB15
|
||||
macroArray: 5C9208ADD091E354794C24FA830F527D17CFC758C24CB77BF2154949059F7E6F
|
||||
BasePlus: 278621A6D8BBBB791DEA4C215D4261F2CB8F8B76B1397F7FA9B2E4219E77CB5A
|
||||
SQLinDS: 3EBC11A0890B6128DDB51643DC91F9DA1BDBF283535664540887FA7E7EA9744F
|
||||
dynMacroArray: 066186B94B2976167C797C6A6E6217E361E8DEB10F2AB81906E0A325E5243084
|
||||
DFA: BB8768E977D62429368CFF2E5338A6553C35C998AEC09AF24088BA713BB54DDA
|
||||
@@ -1,20 +1,22 @@
|
||||
/*** HELP START ***/
|
||||
/*** HELP START ***//*
|
||||
|
||||
## >>> library `dsSQL`: <<< <a name="library-dssql"></a> ########################
|
||||
|
||||
/* >>> dsSQL library: <<<
|
||||
*
|
||||
* The dsSQL library stores temporary views
|
||||
* generated during the %SQL() macro execution.
|
||||
* If possible a subdirectory of WORK is created as:
|
||||
The `dsSQL` library stores temporary views
|
||||
generated during the `%SQL()` macro execution.
|
||||
|
||||
LIBNAME dsSQL BASE "%sysfunc(pathname(WORK))/dsSQLtmp";
|
||||
If possible a subdirectory of the `WORK` location is created, like:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
LIBNAME dsSQL BASE "%sysfunc(pathname(WORK))/dsSQLtmp";
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* if not possible then redirects to WORK as:
|
||||
if not possible, then redirects to the `WORK` location, like:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
LIBNAME dsSQL BASE "%sysfunc(pathname(WORK))";
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
---
|
||||
|
||||
LIBNAME dsSQL BASE "%sysfunc(pathname(WORK))";
|
||||
|
||||
**/
|
||||
|
||||
/*** HELP END ***/
|
||||
*//*** HELP END ***/
|
||||
|
||||
data _null_;
|
||||
length rc0 $ 32767 rc1 rc2 8;
|
||||
@@ -25,5 +27,5 @@ data _null_;
|
||||
rc1 = LIBNAME("dsSQL", "%sysfunc(pathname(work))", "BASE");
|
||||
run;
|
||||
|
||||
/* list details about the library in the log */
|
||||
/* list the details about the library in the log */
|
||||
libname dsSQL LIST;
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
/*** HELP START ***/
|
||||
/*** HELP START ***//*
|
||||
|
||||
## >>> `%dsSQL_Inner()` macro: <<< <a name="dssql-inner-macro"></a> #############
|
||||
|
||||
/* >>> %dsSQL_Inner() macro: <<<
|
||||
*
|
||||
* Internal macro called by dsSQL() function.
|
||||
* The macro generates a uniqualy named sql view on the fly
|
||||
* which is stored in DSSQL library.
|
||||
*
|
||||
* Recommended for SAS 9.3 and higher.
|
||||
* Based on paper:
|
||||
* "Use the Full Power of SAS in Your Function-Style Macros"
|
||||
* by Mike Rhoads, Westat, Rockville, MD
|
||||
* https://support.sas.com/resources/papers/proceedings12/004-2012.pdf
|
||||
*
|
||||
**/
|
||||
**Internal** macro called by `dsSQL()` function.
|
||||
The macro generates a uniquely named SQL view on the fly
|
||||
which is then stored in the `dsSQL` library.
|
||||
|
||||
Recommended for *SAS 9.3* and higher.
|
||||
|
||||
/*** HELP END ***/
|
||||
---
|
||||
|
||||
*//*** HELP END ***/
|
||||
|
||||
/* inner macro */
|
||||
%MACRO dsSQL_Inner() / secure;
|
||||
@@ -57,7 +53,7 @@
|
||||
%put *****************;
|
||||
|
||||
proc sql;
|
||||
%include &tempfile2.; /* &query */
|
||||
%include &tempfile2.; /* the &query */
|
||||
;
|
||||
quit;
|
||||
filename &tempfile1. clear;
|
||||
|
||||
@@ -1,42 +1,48 @@
|
||||
/*** HELP START ***/
|
||||
/*** HELP START ***//*
|
||||
|
||||
## >>> `%SQL()` macro: <<< <a name="dssql-macro"></a> ###########################
|
||||
|
||||
/* >>> %SQL() macro: <<<
|
||||
*
|
||||
* Main macro which allows to use
|
||||
* SQL's queries in the data step.
|
||||
* Recommended for SAS 9.3 and higher.
|
||||
* Based on paper:
|
||||
* "Use the Full Power of SAS in Your Function-Style Macros"
|
||||
* by Mike Rhoads, Westat, Rockville, MD
|
||||
* https://support.sas.com/resources/papers/proceedings12/004-2012.pdf
|
||||
*
|
||||
* SYNTAX:
|
||||
The **main** macro which allows to use
|
||||
SQL queries in the data step.
|
||||
|
||||
Recommended for *SAS 9.3* and higher.
|
||||
|
||||
Based on the article *"Use the Full Power of SAS in Your Function-Style Macros"*
|
||||
by *Mike Rhoads* (Westat, Rockville), available at:
|
||||
[https://support.sas.com/resources/papers/proceedings12/004-2012.pdf](https://support.sas.com/resources/papers/proceedings12/004-2012.pdf)
|
||||
|
||||
%sql(<nonempty sql querry code>)
|
||||
### SYNTAX: ###################################################################
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%sql(<nonempty sql querry code>)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* The sql querry code is limited to 32000 bytes.
|
||||
*
|
||||
* EXAMPLE 1: simple sql query
|
||||
The sql query code is limited to *32000* bytes.
|
||||
|
||||
data class_subset;
|
||||
set %SQL(select name, sex, height from sashelp.class where age > 12);
|
||||
run;
|
||||
### EXAMPLES: #################################################################
|
||||
|
||||
* EXAMPLE 2: query with dataset options
|
||||
**EXAMPLE 1**: simple SQL query
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
data class_subset;
|
||||
set %SQL(select name, sex, height from sashelp.class where age > 12);
|
||||
run;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
data renamed;
|
||||
set %SQL(select * from sashelp.class where sex = "F")(rename = (age=age2));
|
||||
run;
|
||||
**EXAMPLE 2**: query with dataset options
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
data renamed;
|
||||
set %SQL(select * from sashelp.class where sex = "F")(rename = (age=age2));
|
||||
run;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* EXAMPLE 3: dictionaries in datastep
|
||||
**EXAMPLE 3**: dictionaries in the data step
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
data dictionary;
|
||||
set %SQL(select * from dictionary.macros);
|
||||
run;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
---
|
||||
|
||||
data dictionary;
|
||||
set %SQL(select * from dictionary.macros);
|
||||
run;
|
||||
|
||||
**/
|
||||
|
||||
/*** HELP END ***/
|
||||
*//*** HELP END ***/
|
||||
|
||||
|
||||
/* Main User macro */
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
/*** HELP START ***/
|
||||
/*** HELP START ***//*
|
||||
|
||||
## >>> `dsSQL()` function: <<< <a name="dssql-function"></a> ####################
|
||||
|
||||
/* >>> dsSQL() function: <<<
|
||||
*
|
||||
* Internal function called by %SQL() macro.
|
||||
* The function pass query code from the %SQL()
|
||||
* macro to the %dsSQL_Inner() innternal macreo.
|
||||
*
|
||||
* Recommended for SAS 9.3 and higher.
|
||||
* Based on paper:
|
||||
* "Use the Full Power of SAS in Your Function-Style Macros"
|
||||
* by Mike Rhoads, Westat, Rockville, MD
|
||||
* https://support.sas.com/resources/papers/proceedings12/004-2012.pdf
|
||||
*
|
||||
**/
|
||||
**Internal** function called by the `%SQL()` macro.
|
||||
The function pass a query code from the `%SQL()`
|
||||
macro to the `%dsSQL_Inner()` internal macro.
|
||||
|
||||
/*** HELP END ***/
|
||||
Recommended for *SAS 9.3* and higher.
|
||||
|
||||
### SYNTAX: ###################################################################
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
dsSQL(unique_index_2, query)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Arguments description**:
|
||||
|
||||
1. `unique_index_2` - *Numeric*, internal variable, a unique index for views.
|
||||
|
||||
2. `query` - *Character*, internal variable, contains query text.
|
||||
|
||||
---
|
||||
|
||||
*//*** HELP END ***/
|
||||
|
||||
proc fcmp
|
||||
/*inlib = work.&packageName.fcmp*/
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
Type: Package :/*required, not null, constant value*/
|
||||
Package: SQLinDS :/*required, not null, up to 24 characters, naming restrictions like for a dataset name! */
|
||||
Title: SQL queries in Data Step :/*required, not null*/
|
||||
Version: 2.1 :/*required, not null*/
|
||||
Version: 2.2 :/*required, not null*/
|
||||
Author: Mike Rhoads (RhoadsM1@Westat.com) :/*required, not null*/
|
||||
Maintainer: Bartosz Jablonski (yabwon@gmail.com) :/*required, not null*/
|
||||
License: MIT :/*required, not null, values: MIT, GPL2, BSD, etc.*/
|
||||
@@ -18,28 +18,32 @@ Required: "Base SAS Software" :/*optional, COMMA separated, Q
|
||||
/* All the text below will be used in help */
|
||||
DESCRIPTION START:
|
||||
|
||||
The SQLinDS package is an implementation of
|
||||
the macro-function-sandwich concept introduced in:
|
||||
"Use the Full Power of SAS in Your Function-Style Macros"
|
||||
the article by Mike Rhoads, Westat, Rockville, MD
|
||||
# The SQLinDS package [ver. 2.2] <a name="sqlinds-package"></a> ###############################################
|
||||
|
||||
The **SQLinDS** package is an implementation of
|
||||
the *macro-function-sandwich* concept introduced in the
|
||||
*"Use the Full Power of SAS in Your Function-Style Macros"*,
|
||||
the article by *Mike Rhoads (Westat, Rockville)*.
|
||||
|
||||
Copy of the article is available at:
|
||||
https://support.sas.com/resources/papers/proceedings12/004-2012.pdf
|
||||
|
||||
Package provides ability to "execute" SQL queries inside a datastep, e.g.
|
||||
[https://support.sas.com/resources/papers/proceedings12/004-2012.pdf](https://support.sas.com/resources/papers/proceedings12/004-2012.pdf)
|
||||
|
||||
Package provides ability to *execute* SQL queries inside a data step, e.g.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
data class;
|
||||
set %SQL(select * from sashelp.class);
|
||||
run;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
See the help for the `%SQL()` macro to find more examples.
|
||||
|
||||
### Content ###################################################################
|
||||
|
||||
SQLinDS package contains the following components:
|
||||
|
||||
1) %SQL() macro - the main package macro available for the User
|
||||
|
||||
2) dsSQL() function (internal)
|
||||
3) %dsSQL_inner() macro (internal)
|
||||
4) Library DSSQL (created in a subdirectory of the WORK library)
|
||||
|
||||
See help for the %SQL() macro to find more examples.
|
||||
1. `%SQL()` macro - the main package macro available for the User
|
||||
2. `dsSQL()` function (internal)
|
||||
3. `%dsSQL_inner()` macro (internal)
|
||||
4. Library `DSSQL` (created as a subdirectory of the `WORK` library)
|
||||
|
||||
---
|
||||
DESCRIPTION END:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
resetline;
|
||||
|
||||
|
||||
filename packages "C:\SAS_PACKAGES\SASPackagesFramework";
|
||||
filename packages "C:\SAS_PACKAGES\SPF";
|
||||
%include packages(SPFinit.sas);
|
||||
|
||||
ods html;
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
|
||||
options dlCreateDir;
|
||||
libname dsSQL "%sysfunc(pathname(work))/dsSQLtmp";
|
||||
|
||||
/* makro zewnetrzne */
|
||||
%MACRO SQL() / PARMBUFF SECURE;
|
||||
%let SYSPBUFF = %superq(SYSPBUFF); /* maskujemy znaki specjalne */
|
||||
%let SYSPBUFF = %substr(&SYSPBUFF,2,%LENGTH(&SYSPBUFF) - 2); /* kasujemy otwierający i zamykający nawias */
|
||||
%let SYSPBUFF = %superq(SYSPBUFF); /* maskujemy jeszcze raz */
|
||||
%let SYSPBUFF = %sysfunc(quote(&SYSPBUFF)); /* dodajemy cudzyslowy */
|
||||
%put ***the querry***;
|
||||
%put &SYSPBUFF.;
|
||||
%put ****************;
|
||||
|
||||
%local UNIQUE_INDEX; /* dodatkowa zmienna indeksujaca, zeby tworzony widok byl unikalny */
|
||||
%let UNIQUE_INDEX = &SYSINDEX; /* przypisujemy jej wartosc */
|
||||
%sysfunc(dsSQL(&UNIQUE_INDEX, &SYSPBUFF)) /* <-- wywolulemy funkcje dsSQL */
|
||||
%MEND SQL;
|
||||
|
||||
/* funkcja */
|
||||
%macro MacroFunctionSandwich_functions();
|
||||
|
||||
%local _cmplib_;
|
||||
options APPEND=(cmplib = WORK.DATASTEPSQLFUNCTIONS) ;
|
||||
%let _cmplib_ = %sysfunc(getoption(cmplib));
|
||||
%put NOTE:[&sysmacroname.] *&=_cmplib_*;
|
||||
|
||||
options cmplib = _null_;
|
||||
|
||||
proc fcmp outlib=work.datastepSQLfunctions.package;
|
||||
function dsSQL(unique_index_2, query $) $ 41;
|
||||
|
||||
length query query_arg $ 32000 viewname $ 41; /* query_arg mozna zmienic na dluzszy, np. 32000 :-) */
|
||||
query_arg = dequote(query);
|
||||
rc = run_macro('dsSQL_Inner', unique_index_2, query_arg, viewname); /* <-- wywolulemy makro wewnetrzne dsSQL_Inner */
|
||||
if rc = 0 then return(trim(viewname));
|
||||
else do;
|
||||
return(" ");
|
||||
put 'ERROR:[function dsSQL] A problem with the function';
|
||||
end;
|
||||
endsub;
|
||||
run;
|
||||
|
||||
options cmplib = &_cmplib_.;
|
||||
%let _cmplib_ = %sysfunc(getoption(cmplib));
|
||||
%put NOTE:[&sysmacroname.] *&=_cmplib_*;
|
||||
|
||||
%mend MacroFunctionSandwich_functions;
|
||||
%MacroFunctionSandwich_functions()
|
||||
|
||||
/* delete macro MacroFunctionSandwich_functions since it is not needed */
|
||||
proc sql;
|
||||
create table _%sysfunc(datetime(), hex16.)_ as
|
||||
select memname, objname
|
||||
from dictionary.catalogs
|
||||
where
|
||||
objname = upcase('MACROFUNCTIONSANDWICH_FUNCTIONS')
|
||||
and objtype = 'MACRO'
|
||||
and libname = 'WORK'
|
||||
order by memname, objname
|
||||
;
|
||||
quit;
|
||||
data _null_;
|
||||
set _last_;
|
||||
call execute('proc catalog cat = work.' !! strip(memname) !! ' et = macro force;');
|
||||
call execute('delete ' !! strip(objname) !! '; run;');
|
||||
call execute('quit;');
|
||||
run;
|
||||
proc delete data = _last_;
|
||||
run;
|
||||
|
||||
/* makro wewnetrzne */
|
||||
%MACRO dsSQL_Inner() / SECURE;
|
||||
%local query;
|
||||
%let query = %superq(query_arg);
|
||||
%let query = %sysfunc(dequote(&query));
|
||||
|
||||
%let viewname = dsSQL.dsSQLtmpview&UNIQUE_INDEX_2;
|
||||
proc sql;
|
||||
create view &viewname as &query;
|
||||
quit;
|
||||
%MEND dsSQL_Inner;
|
||||
5932
packages/baseplus.md
Normal file
5932
packages/baseplus.md
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
BIN
packages/baseplus_RainCloudPlot_Ex0_9.png
Normal file
BIN
packages/baseplus_RainCloudPlot_Ex0_9.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
BIN
packages/baseplus_RainCloudPlot_Ex1.png
Normal file
BIN
packages/baseplus_RainCloudPlot_Ex1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
BIN
packages/baseplus_RainCloudPlot_Ex2a.png
Normal file
BIN
packages/baseplus_RainCloudPlot_Ex2a.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
BIN
packages/baseplus_RainCloudPlot_Ex2b.png
Normal file
BIN
packages/baseplus_RainCloudPlot_Ex2b.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
BIN
packages/baseplus_RainCloudPlot_Ex3.png
Normal file
BIN
packages/baseplus_RainCloudPlot_Ex3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
1597
packages/dfa.md
Normal file
1597
packages/dfa.md
Normal file
File diff suppressed because it is too large
Load Diff
BIN
packages/dfa.zip
BIN
packages/dfa.zip
Binary file not shown.
Binary file not shown.
329
packages/gsm.md
Normal file
329
packages/gsm.md
Normal file
@@ -0,0 +1,329 @@
|
||||
- [The GSM package](#gsm-package)
|
||||
- [Content description](#content-description)
|
||||
* [`%GSM()` macro](#gsm-macro)
|
||||
* [`%GSMpck_makeFCMPcode()` macro](#gsmpck-makefcmpcode-macro)
|
||||
|
||||
* [License](#license)
|
||||
|
||||
---
|
||||
|
||||
|
||||
# The GSM package [ver. 0.21.1] <a name="gsm-package"></a> ###############################################
|
||||
|
||||
The **GSM** (a.k.a. *Generate Secure Macros*) package allows
|
||||
to create secured macros stored in SAS Proc FCMP functions.
|
||||
The dataset with functions can be shared and allows to generate
|
||||
macros without showing their code.
|
||||
|
||||
The GSM package is basically an automated version of the following:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
proc fcmp outlib = work.gsm.secure ENCRYPT;
|
||||
function generateMacro() $;
|
||||
rc = RESOLVE('
|
||||
%macro secretMacro(x) / SECURE;
|
||||
data test;
|
||||
a = "&x.";
|
||||
run;
|
||||
%mend;
|
||||
');
|
||||
return (rc);
|
||||
endsub;
|
||||
run;
|
||||
|
||||
/* share work.gsm dataset */
|
||||
options cmplib = work.gsm;
|
||||
data _null_;
|
||||
rc = generateMacro();
|
||||
put rc=;
|
||||
run;
|
||||
|
||||
/* enjoy */
|
||||
%secretMacro(42)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
See examples for more details.
|
||||
|
||||
Recording of presentation with "how it works" description, in Polish, is avaliable [here](https://www.youtube.com/watch?v=LtaWPe2sgRY&t=1s).
|
||||
|
||||
*How to use it:*
|
||||
- Copy all files with your secured macros code into a directory.
|
||||
Best approach is to have one file for one macro.
|
||||
- Copy a path to the directory.
|
||||
- Run the following code:
|
||||
```
|
||||
%GSM(<the path to directory>, cmplib=<name of the dataset>)
|
||||
```
|
||||
- Share generated `ZIP` file (unzip and run the code).
|
||||
|
||||
**Limitations:**
|
||||
- Single macro file cannot be longer than 32760 bytes.
|
||||
|
||||
- Multiline text variable. Consider the following code text file:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
%macro~test()/SECURE;~#@
|
||||
data~test;~#@
|
||||
a~=~"abc~#@
|
||||
~#@
|
||||
def";~#@
|
||||
put~a~hex20.;~#@
|
||||
run;~#@
|
||||
%mend~test;~#@
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
where `~` symbols the space character,
|
||||
`#` symbols the carriage return (`0D`),
|
||||
and `@` symbols the line feed (`0A`).
|
||||
The code file is scanned and inserted into
|
||||
the `resolve()` function argument in a "byte by byte"
|
||||
fashion hence also the "end of line" characters are included.
|
||||
As the result value of variable `a` will be:
|
||||
|
||||
`a = "abc~#@~#@def"`.
|
||||
|
||||
If you want to use the `GSM` package avoid
|
||||
such "style" of coding in your macros.
|
||||
|
||||
|
||||
---
|
||||
|
||||
Package contains:
|
||||
1. macro gsm
|
||||
2. macro gsmpck_makefcmpcode
|
||||
|
||||
Required SAS Components:
|
||||
`Base SAS Software`
|
||||
|
||||
*SAS package generated by generatePackage, version 20230905*
|
||||
|
||||
The SHA256 hash digest for package GSM:
|
||||
`F*2FECDDB568B38E206CA4ADA6FDEF5209C0A08B99401A1510D777BABF9DA54682`
|
||||
|
||||
|
||||
## >>> `%GSM()` macro: <<< <a name="gsm-macro"></a> #######################
|
||||
|
||||
The `%GSM()` macro is the main macro of
|
||||
the **GSM** (a.k.a. *Generate Secure Macros*) package.
|
||||
|
||||
It converts a list of macros provided by the user into
|
||||
a data set of the Proc FCMP functions. The macros are stored
|
||||
in functions are encrypted which allow to share them without
|
||||
showing their code. *Important* thing is that macros provided
|
||||
by the user *has* to be "secure", i.e. the `secure` option has to
|
||||
be added to the macro definition. See the example:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%macro secretMacro(x) / SECURE; /* <- the secure option */
|
||||
<... some code ...>
|
||||
%mend secretMacro;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
As a result a zip file, containing dataset with functions and
|
||||
code to be executed on site, is generated.
|
||||
|
||||
Since encrypted code is stored in a SAS dataset it has
|
||||
no limitation in sharing between operating systems (like catalogs have).
|
||||
|
||||
*Limitation:* Due to the `Resolve()` function limitations
|
||||
a single macro file cannot be longer than 32760 bytes.
|
||||
|
||||
*Notes:*
|
||||
- All macros have to have the `secure` option added, i.e. `%macro aMacroname(...) / SECURE ;`.
|
||||
- During the execution a test macro, named `%GSMpck_dummyMacroForTests()`, is generated.
|
||||
- The `%GSM()` macro calls the `%GSMpck_makeFCMPcode(...)` macro internally.
|
||||
|
||||
### SYNTAX: ###################################################################
|
||||
|
||||
The basic syntax is the following, the `<...>` means optional parameters:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%GSM(
|
||||
path
|
||||
<,trim=0>
|
||||
<,cmplib=work.generateMacros>
|
||||
<,source2=>
|
||||
<,outpath=>
|
||||
<,encodingRestricted=>
|
||||
<,secret=>
|
||||
<,lineEnd=>
|
||||
<,encrypt=>
|
||||
)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Arguments description**:
|
||||
|
||||
1. `path` - *Required*, indicates a directory which contains files with macros.
|
||||
Only files with `sas` extension are used.
|
||||
|
||||
* `cmplib=` - *Optional*, the default value is `work.generateMacros`.
|
||||
Names the dataset which will contain generated functions.
|
||||
|
||||
* `source2=` - *Optional*, the default value is null.
|
||||
Indicate if `%includ`-ed files are printed out.
|
||||
Any value other than null enables printing.
|
||||
|
||||
* `outpath=` - *Optional*, the default value is set the same as the `path`.
|
||||
Points a directory in which a result (a zip file) is generated.
|
||||
|
||||
* `encodingRestricted=` - *Optional*, the default value is `0`.
|
||||
If set to 1 then if User session encoding is different from
|
||||
encoding of the session which generates the dataset then
|
||||
the generateMacros() function will not execute macro code.
|
||||
|
||||
* `secret=` - *Optional*, the default value is null, in such case the
|
||||
secret is generated from the `sha256(datetime(), hex32.)` function
|
||||
and is printed in the log. When not null then should be
|
||||
alphanumerical constant. Non-alphanumerical characters are removed.
|
||||
Required to execute the `resolve()` function.
|
||||
User who do not know the value will not be able
|
||||
to run the `_maxro_XX_()` function.
|
||||
|
||||
* `lineEnd=` - *Optional*, the default value is `0D0A`, indicates which of:
|
||||
line feed, carriage return, or both, or a space be inserted
|
||||
at the end of line in the intermediate code file that is generated.
|
||||
Value has to be hexadecimal code (_NOT_ null),
|
||||
since the value is resolved as `"&lineEnd."x`, so use e.g.
|
||||
`0A` for line feed, `0D` for carriage return,
|
||||
`0D0A` for both, and `20` for space.
|
||||
|
||||
* `encrypt=` - *Optional*, the default value is `ENCRYPT`.
|
||||
Indicate if `FCMP` functions generated by the package
|
||||
are encrypted. Value has to be either empty or `ENCRYPT`,
|
||||
all other are converted to default. The option is
|
||||
dedicated for debugging, keep the default value
|
||||
for production use.
|
||||
|
||||
* `trim=` - *Deprecated*, the default value is `0`.
|
||||
*Kept for backward compatibility.*
|
||||
|
||||
---
|
||||
|
||||
### Example: ###################################################################
|
||||
|
||||
Example 1. Prepare 2 files: `f1.sas` and `f2.sas` and use the `%GSM()` macro.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%let path = %sysfunc(pathname(work))/path2files;
|
||||
|
||||
%put &=path.;
|
||||
options dlcreatedir;
|
||||
libname path "&path.";
|
||||
filename path "&path.";
|
||||
|
||||
data _null_;
|
||||
file path(f1.sas);
|
||||
input;
|
||||
put _infile_;
|
||||
cards4;
|
||||
%macro abc(x) / SECURE;
|
||||
data test;
|
||||
do i = 1 to &x.;
|
||||
put i=;
|
||||
end;
|
||||
run;
|
||||
%mend;
|
||||
;;;;
|
||||
run;
|
||||
|
||||
data _null_;
|
||||
file path(f2.sas);
|
||||
input;
|
||||
put _infile_;
|
||||
cards4;
|
||||
%macro xyz(x) / SECURE;
|
||||
%do i = 1 %to &x.;
|
||||
%put &=i;
|
||||
%end;
|
||||
%mend;
|
||||
;;;;
|
||||
run;
|
||||
|
||||
%GSM(&path., cmplib=work.myMacros)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
## >>> `%GSMpck_makeFCMPcode()` macro: <<< <a name="GSMpck-makeFCMPcode-macro"></a> #######################
|
||||
|
||||
The `%GSMpck_makeFCMPcode()` macro is an internal macro of
|
||||
the **GSM** (a.k.a. *Generate Secure Macros*) package.
|
||||
|
||||
It executes a process of converting
|
||||
a macro provided by the user into
|
||||
a Proc FCMP function.
|
||||
|
||||
Since encrypted code is stored in a SAS dataset it has
|
||||
no limitation in sharing between operating systems (like catalogs have).
|
||||
|
||||
*Limitation:* Single macro file cannot be longer than 32760 bytes.
|
||||
|
||||
### SYNTAX: ###################################################################
|
||||
|
||||
The basic syntax is the following, the `<...>` means optional parameters:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%GSMpck_makeFCMPcode(
|
||||
path
|
||||
,number
|
||||
<,outlib=work.generateMacros.secure>
|
||||
<,source2=>
|
||||
<,fileNameCode=FNC>
|
||||
<,secret=123456789>
|
||||
<,lineEnd=0A>
|
||||
)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Arguments description**:
|
||||
|
||||
1. `path` - *Required*, indicates a directory which contains files with macros.
|
||||
Only files with `sas` extension are used.
|
||||
|
||||
2. `number` - *Required*, a sequential number.
|
||||
|
||||
|
||||
* `cmplib=` - *Optional*, the default value is `work.generateMacros`.
|
||||
Names the dataset which will contain generated functions.
|
||||
|
||||
* `source2=` - *Optional*, the default value is null.
|
||||
Indicate if `%includ`-ed files are printed out.
|
||||
Any value other than null enables printing.
|
||||
|
||||
* `fileNameCode=` - *Optional*, the default value is `FNC`.
|
||||
Internal fileref.
|
||||
|
||||
* `secret=` - *Optional*, internal, the default value is `1234567890`.
|
||||
Alphanumerical constant required to execute the `resolve()`
|
||||
function. User who do not know the value will not be able
|
||||
to run the `_maxro_XX_()` function.
|
||||
|
||||
* `lineEnd=` - *Optional*, the default value is `0D0A`, indicates which of:
|
||||
line feed, carriage return, or both, or a space be inserted
|
||||
at the end of line in the intermediate code file that is generated.
|
||||
Value has to be hexadecimal code (_NOT_ null),
|
||||
since the value is resolved as `"&lineEnd."x`, so use e.g.
|
||||
`0A` for line feed, `0D` for carriage return,
|
||||
`0D0A` for both, and `20` for space.
|
||||
|
||||
* `trim=` - *Deprecated*, the default value is `0`.
|
||||
*Kept for backward compatibility.*
|
||||
|
||||
---
|
||||
|
||||
|
||||
## License ####################################################################
|
||||
|
||||
Copyright (c) Bartosz Jablonski, since 2021
|
||||
|
||||
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.
|
||||
|
||||
---
|
||||
BIN
packages/gsm.zip
Normal file
BIN
packages/gsm.zip
Normal file
Binary file not shown.
2204
packages/macroarray.md
Normal file
2204
packages/macroarray.md
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
BIN
packages/macrocore.zip
Normal file
BIN
packages/macrocore.zip
Normal file
Binary file not shown.
180
packages/sqlinds.md
Normal file
180
packages/sqlinds.md
Normal file
@@ -0,0 +1,180 @@
|
||||
- [The SQLinDS package](#sqlinds-package)
|
||||
- [Content description](#content-description)
|
||||
* [library `dsSQL`](#library-dssql)
|
||||
* [`%dsSQL_inner()` macro](#dssql-inner-macro)
|
||||
* [`%SQL()` macro](#dssql-inner-macro)
|
||||
* [`dsSQL()` function](#dssql-function)
|
||||
* [License](#license)
|
||||
|
||||
---
|
||||
|
||||
# The SQLinDS package [ver. 2.2.7] <a name="sqlinds-package"></a> ###############################################
|
||||
|
||||
The **SQLinDS** package is an implementation of
|
||||
the *macro-function-sandwich* concept introduced in the
|
||||
*"Use the Full Power of SAS in Your Function-Style Macros"*,
|
||||
the article by *Mike Rhoads (Westat, Rockville)*.
|
||||
|
||||
The article is available at:
|
||||
[https://support.sas.com/resources/papers/proceedings12/004-2012.pdf](https://support.sas.com/resources/papers/proceedings12/004-2012.pdf)
|
||||
|
||||
Copy of the article can also be found in *additional content* directory.
|
||||
|
||||
|
||||
Package provides ability to *execute* SQL queries inside a data step, e.g.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
data class;
|
||||
set %SQL(select * from sashelp.class);
|
||||
run;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
See the help for the `%SQL()` macro to find more examples.
|
||||
|
||||
### Content ###################################################################
|
||||
|
||||
SQLinDS package contains the following components:
|
||||
|
||||
1. `%SQL()` macro - the main package macro available for the User
|
||||
2. `dsSQL()` function (internal)
|
||||
3. `%dsSQL_inner()` macro (internal)
|
||||
4. Library `DSSQL` (created as a subdirectory of the `WORK` library)
|
||||
|
||||
---
|
||||
|
||||
Package contains:
|
||||
1. libname dssql
|
||||
2. macro dssql_inner
|
||||
3. macro sql
|
||||
4. function dssql
|
||||
|
||||
Required SAS Components:
|
||||
*Base SAS Software*
|
||||
|
||||
*SAS package generated by generatePackage, version 20230905*
|
||||
|
||||
The SHA256 hash digest for package SQLinDS:
|
||||
`F*42DC179E1D2B946AD519C4EC04A068061B312E021C3F4BC4826D2775E116E1B9`
|
||||
|
||||
---
|
||||
# Content description ############################################################################################
|
||||
|
||||
|
||||
## >>> library `dsSQL`: <<< <a name="library-dssql"></a> ########################
|
||||
|
||||
The `dsSQL` library stores temporary views
|
||||
generated during the `%SQL()` macro execution.
|
||||
|
||||
If possible a subdirectory of the `WORK` location is created, like:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
LIBNAME dsSQL BASE "%sysfunc(pathname(WORK))/dsSQLtmp";
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
if not possible, then redirects to the `WORK` location, like:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
LIBNAME dsSQL BASE "%sysfunc(pathname(WORK))";
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
---
|
||||
|
||||
|
||||
|
||||
## >>> `%dsSQL_Inner()` macro: <<< <a name="dssql-inner-macro"></a> #############
|
||||
|
||||
**Internal** macro called by `dsSQL()` function.
|
||||
The macro generates a uniquely named SQL view on the fly
|
||||
which is then stored in the `dsSQL` library.
|
||||
|
||||
Recommended for *SAS 9.3* and higher.
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
## >>> `%SQL()` macro: <<< <a name="dssql-macro"></a> ###########################
|
||||
|
||||
The **main** macro which allows to use
|
||||
SQL queries in the data step.
|
||||
|
||||
Recommended for *SAS 9.3* and higher.
|
||||
|
||||
Based on the article *"Use the Full Power of SAS in Your Function-Style Macros"*
|
||||
by *Mike Rhoads* (Westat, Rockville), available at:
|
||||
[https://support.sas.com/resources/papers/proceedings12/004-2012.pdf](https://support.sas.com/resources/papers/proceedings12/004-2012.pdf)
|
||||
|
||||
Copy of the article can also be found in *additional content* directory.
|
||||
|
||||
### SYNTAX: ###################################################################
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%sql(<nonempty sql querry code>)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The sql query code is limited to *32000* bytes.
|
||||
|
||||
### EXAMPLES: #################################################################
|
||||
|
||||
**EXAMPLE 1**: simple SQL query
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
data class_subset;
|
||||
set %SQL(select name, sex, height from sashelp.class where age > 12);
|
||||
run;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**EXAMPLE 2**: query with dataset options
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
data renamed;
|
||||
set %SQL(select * from sashelp.class where sex = "F")(rename = (age=age2));
|
||||
run;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**EXAMPLE 3**: dictionaries in the data step
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
data dictionary;
|
||||
set %SQL(select * from dictionary.macros);
|
||||
run;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
---
|
||||
|
||||
|
||||
|
||||
## >>> `dsSQL()` function: <<< <a name="dssql-function"></a> ####################
|
||||
|
||||
**Internal** function called by the `%SQL()` macro.
|
||||
The function pass a query code from the `%SQL()`
|
||||
macro to the `%dsSQL_Inner()` internal macro.
|
||||
|
||||
Recommended for *SAS 9.3* and higher.
|
||||
|
||||
### SYNTAX: ###################################################################
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
dsSQL(unique_index_2, query)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Arguments description**:
|
||||
|
||||
1. `unique_index_2` - *Numeric*, internal variable, a unique index for views.
|
||||
|
||||
2. `query` - *Character*, internal variable, contains query text.
|
||||
|
||||
---
|
||||
|
||||
## License ####################################################################
|
||||
|
||||
Copyright (c) 2012 Mike Rhoads
|
||||
|
||||
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.
|
||||
|
||||
---
|
||||
Binary file not shown.
Reference in New Issue
Block a user