1
0
mirror of https://github.com/sasjs/core.git synced 2025-12-12 15:04:36 +00:00

Compare commits

..

117 Commits

Author SHA1 Message Date
github-actions
df832a184f chore: updating all.sas 2025-09-21 10:52:05 +00:00
allan
15084be09d chore: removing gitpod and funding files 2025-09-21 11:51:37 +01:00
github-actions
92ff1a53dc chore: updating all.sas 2025-09-21 10:37:39 +00:00
allan
7dd219e9f1 chore: fixing badges in README 2025-09-21 11:36:41 +01:00
Allan Bowe
cdd2b88b09 Merge pull request #403 from sasjs/issue400
Issue400
2025-06-30 19:26:52 +01:00
github-actions
7e4fb4a640 chore: updating all.sas 2025-06-30 18:26:32 +00:00
Allan Bowe
a428b4f66c Merge branch 'main' into issue400 2025-06-30 19:26:19 +01:00
github-actions
e2f0577e78 chore: updating all.sas 2025-06-30 18:26:03 +00:00
allan
d53eff7771 fix: reducing logging per #400 2025-06-30 19:25:40 +01:00
github-actions
5b56c85455 chore: updating all.sas 2025-06-30 16:38:43 +00:00
Allan Bowe
ff519c7f39 Merge pull request #402 from sasjs/issue400
fix: re-attempt of request, hopefully fixes #400
2025-06-30 17:38:39 +01:00
Allan Bowe
7d7778fd36 Merge branch 'main' into issue400 2025-06-30 17:38:19 +01:00
github-actions
b47f31cfe6 chore: updating all.sas 2025-06-30 16:37:46 +00:00
allan
542039b425 fix: re-attempt of request, hopefully fixes #400 2025-06-30 17:37:18 +01:00
Allan Bowe
cc908a82bc Merge pull request #401 from sasjs/issue400
fix: addresses #400
2025-06-30 16:08:58 +01:00
github-actions
71c31046f4 chore: updating all.sas 2025-06-30 15:06:32 +00:00
allan
33a487b2b4 fix: addresses #400 2025-06-30 16:05:57 +01:00
Allan Bowe
7240cf08d6 Merge pull request #399 from sasjs/uniquelibref
fix: increasing limit from 1k to 100k for mf_getuniquelibref()
2025-06-29 13:46:57 +01:00
github-actions
1cb702149c chore: updating all.sas 2025-06-29 12:46:06 +00:00
allan
a12ea6a7cb chore: removing commit size check 2025-06-29 13:45:48 +01:00
Allan Bowe
a6b52b5d9e Merge branch 'main' into uniquelibref 2025-06-29 13:43:12 +01:00
github-actions
0faba3581b chore: updating all.sas 2025-06-29 12:42:55 +00:00
allan
749309b749 fix: increasing limit from 1k to 100k for mf_getuniqueliref() 2025-06-29 13:42:23 +01:00
Allan Bowe
e54de44d4b chore: adding git precommit hook to avoid large files 2025-06-27 16:46:24 +01:00
Allan Bowe
40436be14f Merge pull request #397 from sasjs/omitsessionresults
fix: ensuring acceptable casing of _omitSessionResults
2025-06-09 21:00:14 +01:00
github-actions
909fef7143 chore: updating all.sas 2025-06-09 19:58:31 +00:00
allan
bcb93e62d4 fix: ensuring acceptable casing of _omitSessionResults
More info: https://communities.sas.com/t5/SAS-Viya/Returning-webout-from-JES-API/td-p/966992
2025-06-09 20:58:05 +01:00
Allan Bowe
6dbfd32dba Merge pull request #396 from sasjs/dc171
feat: new mfv_getfolderpath macro
2025-06-06 20:30:24 +01:00
github-actions
5706483886 chore: updating all.sas 2025-06-06 19:29:28 +00:00
allan
ce73e2bebd feat: new mfv_getfolderpath macro
+ associated test
created to support the fix for https://git.datacontroller.io/dc/dc/issues/171
2025-06-06 20:29:07 +01:00
Allan Bowe
bc77e5a5d1 Merge pull request #395 from sasjs/indexhtml
fix: ff downloading instead of streaming html on viya
2025-06-05 14:10:35 +01:00
github-actions
daa4e4e762 chore: updating all.sas 2025-06-05 13:10:16 +00:00
allan
9c1f68944f fix: ff downloading instead of streaming html on viya 2025-06-05 14:09:52 +01:00
Allan Bowe
3978ac5e05 Merge pull request #394 from sasjs/pngfix
fix: support png in streaming viya apps
2025-06-02 15:10:51 +01:00
github-actions
6b378749e5 chore: updating all.sas 2025-06-02 14:10:40 +00:00
allan
77c0e35c9d fix: support png in streaming viya apps 2025-06-02 15:10:11 +01:00
Allan Bowe
52d33ccafb Merge pull request #393 from sasjs/issue1403
feat: adding mp_replace option to mv_createfile
2025-06-02 12:17:55 +01:00
github-actions
10087dd6a6 chore: updating all.sas 2025-06-02 11:17:02 +00:00
allan
3bd2148ae9 fix: failing test 2025-06-02 12:16:36 +01:00
github-actions
60570b2e13 chore: updating all.sas 2025-05-30 18:15:58 +00:00
allan
6e033afb7b feat: adding mp_replace option to mv_createfile
Relates to https://github.com/sasjs/cli/issues/1403
2025-05-30 19:15:33 +01:00
allan
4f5fa414e1 fix: updating readme with new prefix
(also bumping the version for the previous commit)
2025-05-30 10:24:19 +01:00
Allan Bowe
4b142f1f45 Merge pull request #392 from sasjs/viya2025
chore: removing put statements
2025-05-30 10:14:12 +01:00
github-actions
3f73a565a6 chore: updating all.sas 2025-05-30 09:13:52 +00:00
allan
d3f1c8e960 chore: removing put statements 2025-05-30 10:13:30 +01:00
Allan Bowe
0d10441b89 Merge pull request #391 from sasjs/viyastream
fix: ensuring svg rendering from SAS drive
2025-05-30 09:59:02 +01:00
github-actions
85e1f56400 chore: updating all.sas 2025-05-30 08:58:30 +00:00
allan
c5ec21c7a0 fix: ensuring svg rendering from SAS drive
Also reducing put statements in the log
2025-05-30 09:58:06 +01:00
Allan Bowe
e049ab99a7 Merge pull request #390 from sasjs/svgfix
fix: streamlining viya deploys
2025-05-29 17:52:57 +01:00
github-actions
e9deab3885 chore: updating all.sas 2025-05-29 16:51:46 +00:00
allan
8d2f084316 fix: streamlining viya deploys 2025-05-29 17:51:23 +01:00
allan
33cb36fb8f fix: ensuring that mv_createfile always creates the file by default
Also some fixes to ensure that web files are served from Viya
2025-05-29 12:25:02 +01:00
allan
752e6305c9 chore: fixing docs of mfv_getpathuri 2025-05-19 15:20:41 +01:00
Allan Bowe
d24f0f3e25 Merge pull request #389 from sasjs/issue388
updated create_file service
2025-05-19 12:23:54 +01:00
github-actions
6c6561deba chore: updating all.sas 2025-05-19 11:23:29 +00:00
allan
a1c24b2e4a chore: remove server url 2025-05-19 12:23:09 +01:00
github-actions
d4f1df5bc0 chore: updating all.sas 2025-05-19 11:21:25 +00:00
allan
2ddded9600 chore: test fixes 2025-05-19 12:20:59 +01:00
github-actions
2de6fba5bb chore: updating all.sas 2025-05-19 09:19:44 +00:00
allan
7117e2e8e9 fix: enabling reading from / writing to SAS Drive. Closes #334 2025-05-19 10:19:23 +01:00
github-actions
376800d464 chore: updating all.sas 2025-05-19 08:05:57 +00:00
allan
de32d12b51 fix: applying correct typedefname 2025-05-19 09:05:34 +01:00
github-actions
285ca791d8 chore: updating all.sas 2025-05-18 17:49:16 +00:00
allan
667198e5c0 feat: mfv_getpathuri macro to get the uri of a file or folder
Also refactoring mv_createfolder.sas
2025-05-18 18:48:50 +01:00
github-actions
51042cbd47 chore: updating all.sas 2025-05-17 14:07:20 +00:00
allan
15c0576207 feat: new mf_mimetype macro
(and associated test)
2025-05-17 15:06:47 +01:00
Allan Bowe
f542ddec99 Merge pull request #387 from sasjs/allanbowe-patch-1
chore: readme
2025-05-12 20:21:55 +01:00
github-actions
8f147d3e01 chore: updating all.sas 2025-05-12 19:21:03 +00:00
Allan Bowe
9f7f27507c chore: readme
adding https://github.com/Criptic/sas_snippets
2025-05-12 20:20:45 +01:00
sasjs
bfa48ef172 fix: removing old email address 2025-03-18 12:29:55 +00:00
sasjs
47a265a706 chore: removing sasjs/cli dependency 2025-03-18 12:26:39 +00:00
sasjs
5fce4c8a83 feat: adding NLDATE and NLDATM to mcf_getfmttype 2025-03-11 20:37:00 +00:00
Allan Bowe
57131e5fa6 Merge pull request #386 from sasjs/385-support-nldatm-in-mp_getcols
385 support nldatm in mp getcols
2025-03-05 14:40:29 +00:00
github-actions
3d5e3895ab chore: updating all.sas 2025-03-05 14:39:33 +00:00
Allan Bowe
c5cc6e1a87 chore: merge 2025-03-05 14:39:02 +00:00
Allan Bowe
c05993ca6b feat: support for National Language. CLoses #385 2025-03-05 14:38:18 +00:00
github-actions
e2d2de6f76 chore: updating all.sas 2025-03-05 14:27:14 +00:00
Allan Bowe
61cce649cb Merge pull request #384 from sasjs/details
chore(docs): header for mm_getdetails
2025-02-26 19:38:30 +00:00
github-actions
9f85b3e1b2 chore: updating all.sas 2025-02-26 19:37:56 +00:00
Allan Bowe
37475e227d chore(docs): header for mm_getdetails 2025-02-26 19:37:14 +00:00
Allan Bowe
cbeb954d37 Merge pull request #383 from sasjs/feat-add-sort-options
Feat add sort options
2025-02-26 19:16:36 +00:00
github-actions
a9ae874a45 chore: updating all.sas 2025-02-26 16:03:24 +00:00
77038b48c2 chore(git): Merge branch 'feat-add-sort-options' of github.com:sasjs/core into feat-add-sort-options 2025-02-26 17:02:53 +01:00
e848690984 ci: vpn fix 2025-02-26 17:02:28 +01:00
github-actions
2ad8f0b44b chore: updating all.sas 2025-02-26 16:00:40 +00:00
6b41386667 chore(git): Merge branch 'feat-add-sort-options' of github.com:sasjs/core into feat-add-sort-options 2025-02-26 17:00:14 +01:00
c363cfe458 ci: vpn fix 2025-02-26 16:59:00 +01:00
github-actions
608dbd1085 chore: updating all.sas 2025-02-26 15:57:05 +00:00
c6d9e6fdb2 ci: vpn fix 2025-02-26 16:56:31 +01:00
github-actions
c7d46416ce chore: updating all.sas 2025-02-26 15:48:32 +00:00
Allan Bowe
86606c6f18 chore(docs): description of new param in mm_getdetails 2025-02-26 15:47:39 +00:00
github-actions
9730715558 chore: updating all.sas 2025-02-26 15:27:50 +00:00
Henrik Forsell
eff0f4eda3 feat: Add optional sort option 2025-02-26 16:27:05 +01:00
sasjs
f60b06844c chore(docs): fixing core.sasjs.io build errors 2025-02-24 11:10:06 +00:00
Allan Bowe
85ef2ecb84 Merge pull request #380 from sasjs/docs
chore: doc updates
2025-02-18 12:02:18 +00:00
github-actions
6b470e76fb chore: updating all.sas 2025-02-18 12:01:52 +00:00
Allan Bowe
46ca83a4d5 Merge branch 'main' into docs 2025-02-18 12:01:32 +00:00
Allan Bowe
2bb1df86ec Merge pull request #379 from sasjs/378-ms_triggerstpsas
378 ms triggerstpsas
2024-10-31 18:07:33 +00:00
github-actions
b1bff1b0a4 chore: updating all.sas 2024-10-31 16:58:16 +00:00
Trevor Moody
5c3ac8a123 chore: reverted position of the '&boundary' put statement. 2024-10-31 16:57:52 +00:00
github-actions
2765d8c2ec chore: updating all.sas 2024-10-31 12:49:45 +00:00
Trevor Moody
bd4610f0b8 chore: updates to address comments 2024-10-31 12:49:16 +00:00
github-actions
ae92e14660 chore: updating all.sas 2024-10-31 11:27:47 +00:00
Trevor Moody
424ae548d0 chore: replaced obs test with mp_assertdsobs 2024-10-31 11:27:18 +00:00
github-actions
69fe9ebaed chore: updating all.sas 2024-10-31 11:10:40 +00:00
Trevor Moody
1b16383fd8 chore: Added test of ms_triggerstp.sas 2024-10-31 11:10:10 +00:00
github-actions
08f291367d chore: updating all.sas 2024-10-30 22:04:10 +00:00
.
f1c761d5c1 chore: doc updates 2024-10-30 22:03:46 +00:00
github-actions
f88b219da1 chore: updating all.sas 2024-10-30 19:25:24 +00:00
Trevor Moody
900120df1b feat: Triggering of stored processes. Closes #378 2024-10-30 19:24:45 +00:00
github-actions
2a13ba72f6 chore: updating all.sas 2024-10-30 19:21:00 +00:00
Allan Bowe
21d6671a5f Merge pull request #376 from sasjs/issue375
fix: logic in mm_assigdirectlib to close #375
2024-08-27 13:41:51 +03:00
github-actions
5367126428 chore: updating all.sas 2024-08-20 15:19:13 +00:00
allan
8485d9ebdf fix: logic in mm_assigdirectlib to close #375 2024-08-20 17:18:27 +02:00
^
b7718fae6b fix: sorting output in create sas package 2024-05-16 18:18:09 +01:00
^
6e3b100170 fix: adding proc sort to create_sas_package.sas 2024-05-16 18:09:25 +01:00
^
414fe9ebde fix: SAS Macros list in SASPAC build job 2024-05-16 18:03:42 +01:00
39 changed files with 2418 additions and 2145 deletions

3
.github/FUNDING.yml vendored
View File

@@ -1,3 +0,0 @@
# These are supported funding model platforms
custom: https://getalby.com/p/sasjs

View File

@@ -3,10 +3,12 @@ client
tls-client tls-client
dev tun dev tun
# this will connect with whatever proto DNS tells us (https://community.openvpn.net/openvpn/ticket/934) # this will connect with whatever proto DNS tells us (https://community.openvpn.net/openvpn/ticket/934)
proto tcp proto udp
remote vpn.4gl.io 7494 remote vpn.4gl.io 7194
resolv-retry infinite resolv-retry infinite
cipher AES-256-CBC # this will fallback from udp6 to udp4 as well
connect-timeout 5
data-ciphers AES-256-CBC:AES-256-GCM
auth SHA256 auth SHA256
script-security 2 script-security 2
keepalive 10 120 keepalive 10 120

View File

@@ -8,7 +8,7 @@ on:
jobs: jobs:
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
strategy: strategy:
matrix: matrix:
@@ -34,6 +34,10 @@ jobs:
USER_KEY: ${{ secrets.USER_KEY }} USER_KEY: ${{ secrets.USER_KEY }}
TLS_KEY: ${{ secrets.TLS_KEY }} TLS_KEY: ${{ secrets.TLS_KEY }}
- name: Chmod VPN files
run: |
chmod 600 .github/vpn/ca.crt .github/vpn/user.crt .github/vpn/user.key .github/vpn/tls.key
- name: Install Open VPN - name: Install Open VPN
run: | run: |
sudo apt install apt-transport-https sudo apt install apt-transport-https
@@ -42,8 +46,13 @@ jobs:
sudo wget -O /etc/apt/sources.list.d/openvpn3.list https://swupdate.openvpn.net/community/openvpn3/repos/openvpn3-jammy.list sudo wget -O /etc/apt/sources.list.d/openvpn3.list https://swupdate.openvpn.net/community/openvpn3/repos/openvpn3-jammy.list
sudo apt update sudo apt update
sudo apt install openvpn3=17~betaUb22042+jammy sudo apt install openvpn3=17~betaUb22042+jammy
- name: Start Open VPN 3 - name: Start Open VPN 3
run: openvpn3 session-start --config .github/vpn/config.ovpn run: openvpn3 session-start --config .github/vpn/config.ovpn
- name: Fetch SASJS server
run: curl ${{ secrets.SASJS_SERVER_URL }}/SASjsApi/info
- name: Install Doxygen - name: Install Doxygen
run: sudo apt-get install doxygen run: sudo apt-get install doxygen

View File

@@ -1,6 +0,0 @@
FROM gitpod/workspace-full
RUN sudo apt-get update \
&& sudo apt-get install -y doxygen \
&& sudo apt-get install -y graphviz \
&& sudo rm -rf /var/lib/apt/lists/*

View File

@@ -1,27 +0,0 @@
tasks:
- init: npm install -g npm
- command: npm i
- command: npm i -g @sasjs/cli
image:
file: .gitpod.dockerfile
vscode:
extensions:
- sasjs.sasjs-for-vscode
github:
prebuilds:
# enable for the master/default branch (defaults to true)
master: true
# enable for all branches in this repo (defaults to false)
branches: false
# enable for pull requests coming from this repo (defaults to true)
pullRequests: true
# enable for pull requests coming from forks (defaults to false)
pullRequestsFromForks: true
# add a "Review in Gitpod" button as a comment to pull requests (defaults to true)
addComment: true
# add a "Review in Gitpod" button to pull requests (defaults to false)
addBadge: false
# add a label once the prebuild is ready to pull requests (defaults to false)
addLabel: prebuilt-in-gitpod

View File

@@ -1,19 +1,12 @@
# Macro Core # Macro Core
[![npm package][npm-image]][npm-url]
[![Github Workflow][githubworkflow-image]][githubworkflow-url] [![npm package](https://img.shields.io/npm/v/@sasjs/core.svg)](http://npmjs.org/package/@sasjs/core)
[![Github Workflow](https://github.com/sasjs/core/actions/workflows/main.yml/badge.svg)](https://github.com/sasjs/core/blob/main/.github/workflows/main.yml)
![npm](https://img.shields.io/npm/dt/@sasjs/core) ![npm](https://img.shields.io/npm/dt/@sasjs/core)
![GitHub top language](https://img.shields.io/github/languages/top/sasjs/core) ![GitHub top language](https://img.shields.io/github/languages/top/sasjs/core)
[![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/sasjs/core)](https://github.com/sasjs/core/issues?q=is%3Aissue+is%3Aclosed) [![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/sasjs/core)](https://github.com/sasjs/core/issues?q=is%3Aissue+is%3Aclosed)
[![GitHub issues](https://img.shields.io/github/issues-raw/sasjs/core)](https://github.com/sasjs/core/issues) [![GitHub issues](https://img.shields.io/github/issues-raw/sasjs/core)](https://github.com/sasjs/core/issues)
![total lines](https://tokei.rs/b1/github/sasjs/core) ![total lines](https://tokei.rs/b1/github/sasjs/core)
[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-908a85?logo=gitpod)](https://gitpod.io/#https://github.com/sasjs/core)
[npm-image]:https://img.shields.io/npm/v/@sasjs/core.svg
[npm-url]:http://npmjs.org/package/@sasjs/core
[githubworkflow-image]:https://github.com/sasjs/core/actions/workflows/main.yml/badge.svg
[githubworkflow-url]:https://github.com/sasjs/core/blob/main/.github/workflows/main.yml
[dependency-url]:https://github.com/sasjs/core/blob/main/package.json
Much quality. Many standards. The **Macro Core** library exists to save time and development effort! Herein ye shall find a veritable host of MIT-licenced, production quality SAS macros. These are a mix of tools, utilities, functions and code generators that are useful in the context of [Application Development](https://sasapps.io) on the SAS platform (eg https://datacontroller.io). [Contributions](https://github.com/sasjs/core/blob/main/.github/CONTRIBUTING.md) are welcome. Much quality. Many standards. The **Macro Core** library exists to save time and development effort! Herein ye shall find a veritable host of MIT-licenced, production quality SAS macros. These are a mix of tools, utilities, functions and code generators that are useful in the context of [Application Development](https://sasapps.io) on the SAS platform (eg https://datacontroller.io). [Contributions](https://github.com/sasjs/core/blob/main/.github/CONTRIBUTING.md) are welcome.
@@ -147,16 +140,17 @@ filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
- macro names must be lowercase - macro names must be lowercase
- one macro per file - one macro per file
- prefixes: - prefixes:
- _mcf_ for macro compiled functions (proc fcmp) - _mcf__: macro compiled functions (proc fcmp)
- _mddl_ for macros containing DDL (Data Definition Language) - _mddl__: macros containing DDL (Data Definition Language)
- _mf_ for macro functions (can be used in open code). - _mf__: macro functions (can be used in open code).
- _ml_ for macros that are used to compile LUA modules - _mfv__: macro functions that work only in Viya
- _mm_ for metadata macros (interface with the metadata server). - _ml__: macros that are used to compile LUA modules
- _mmx_ for macros that use metadata and are XCMD enabled (working on both windows and unix) - _mm__: metadata macros (interface with the metadata server).
- _mp_ for macro procedures (which generate sas code) - _mmx__: macros that use metadata and are XCMD enabled (working on both windows and unix)
- _ms_ for macro procedures that will only work with [@sasjs/server](https://github.com/sasjs/server) - _mp__: macro procedures (which generate sas code)
- _mv_ for macro procedures that will only work in Viya - _ms__: macro procedures that will only work with [@sasjs/server](https://github.com/sasjs/server)
- _mx_ for macros that work on Viya, SAS 9 EBI and SASjs Server - _mv__: macro procedures that will only work in Viya
- _mx__: macros that work on Viya, SAS 9 EBI and SASjs Server
- follow verb-noun convention - follow verb-noun convention
- unix style line endings (lf) - unix style line endings (lf)
- individual lines should be no more than 80 characters long - individual lines should be no more than 80 characters long
@@ -237,6 +231,7 @@ If you find this library useful, please leave a [star](https://github.com/sasjs/
The following repositories are also worth checking out: The following repositories are also worth checking out:
* [chris-swenson/sasmacros](https://github.com/chris-swenson/sasmacros) * [chris-swenson/sasmacros](https://github.com/chris-swenson/sasmacros)
* [Criptic/sas_snippets](https://github.com/Criptic/sas_snippets)
* [greg-wotton/sas-programs](https://github.com/greg-wootton/sas-programs) * [greg-wotton/sas-programs](https://github.com/greg-wootton/sas-programs)
* [KatjaGlassConsulting/SMILE-SmartSASMacros](https://github.com/KatjaGlassConsulting/SMILE-SmartSASMacros) * [KatjaGlassConsulting/SMILE-SmartSASMacros](https://github.com/KatjaGlassConsulting/SMILE-SmartSASMacros)
* [paul-canals/toolbox](https://github.com/paul-canals/toolbox) * [paul-canals/toolbox](https://github.com/paul-canals/toolbox)

1126
all.sas

File diff suppressed because it is too large Load Diff

View File

@@ -26,7 +26,7 @@
@author Allan Bowe @author Allan Bowe
**/ **/
%macro mf_getuniquelibref(prefix=mclib,maxtries=1000); %macro mf_getuniquelibref(prefix=mc,maxtries=1000);
%local x; %local x;
%if ( %length(&prefix) gt 7 ) %then %do; %if ( %length(&prefix) gt 7 ) %then %do;

436
base/mf_mimetype.sas Normal file
View File

@@ -0,0 +1,436 @@
/**
@file
@brief Returns a mime type from a file extension
@details Provide a file extension and get a mime type.
The mappings were derived from this source:
https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
@param [in] ext The file extension (unquoted)
@return output The mime type
@version 9.2
@author Allan Bowe
**/
%macro mf_mimetype(
ext
)/*/STORE SOURCE*/ /minoperator mindelimiter=' ';
%let ext=%lowcase(&ext);
%if &ext in (sas txt text conf def list log)
%then %do;%str(text/plain)%end;
%else %if &ext=xlsx %then %do;
%str(application/vnd.openxmlformats-officedocument.spreadsheetml.sheet)%end;
%else %if &ext in (xls xlm xla xlc xlt xlw)
%then %do;%str(application/vnd.ms-excel)%end;
%else %if &ext=xlsm
%then %do;%str(application/vnd.ms-excel.sheet.macroenabled.12)%end;
%else %if &ext=xlsb
%then %do;%str(application/vnd.ms-excel.sheet.binary.macroenabled.12)%end;
%else %if &ext in (css csv html n3 sgml vcard)
%then %do;%str(text/&ext)%end;
%else %if &ext in (avif bmp cgm gif ief jxl ktx png sgi tiff webp)
%then %do;%str(image/&ext)%end;
%else %if &ext in (exi gxf ipfix json mbox mp21 mxf oda oxps pdf rtf sdp wasm
xml yang zip)
%then %do;%str(application/&ext)%end;
%else %if &ext in (jpeg jpg jpe) %then %do;%str(image/jpeg)%end;
%else %if &ext in (mp4 mp4v mpg4) %then %do;%str(video/mp4)%end;
%else %if &ext in (otf ttf woff woff2) %then %do;%str(font/&ext)%end;
%else %if &ext in (mpeg mpg mpe m1v m2v)
%then %do;%str(video/mpeg)%end;
%else %if &ext in (h261 h263 h264 jpm mj2 webm)
%then %do;%str(video/&ext)%end;
%else %if &ext in (f4v fli flv m4v mng smv)
%then %do;%str(video/x-&ext)%end;
%else %if &ext in (3ds cmx pcx rgb tga)
%then %do;%str(image/x-&ext)%end;
%else %if &ext in (asm nfo opml sfv)
%then %do;%str(text/x-&ext)%end;
%else %if &ext in (aac caf flac wav)
%then %do;%str(audio/x-&ext)%end;
%else %if &ext in (ts m2t m2ts mts)
%then %do;%str(video/mp2t)%end;
%else %if &ext in (pfa pfb pfm afm)
%then %do;%str(application/x-font-type1)%end;
%else %if &ext in (oga ogg spx opus)
%then %do;%str(audio/ogg)%end;
%else %if &ext in (mid midi kar rmi)
%then %do;%str(audio/midi)%end;
%else %if &ext in (onetoc onetoc2 onetmp onepkg)
%then %do;%str(application/onenote)%end;
%else %if &ext in (mxml xhvml xvml xvm)
%then %do;%str(application/xv+xml)%end;
%else %if &ext in (f for f77 f90)
%then %do;%str(text/x-fortran)%end;
%else %if &ext in (wmf wmz emf emz)
%then %do;%str(application/x-msmetafile)%end;
%else %if &ext in (exe dll com bat msi)
%then %do;%str(application/x-msdownload)%end;
%else %if &ext in (bin dms lrf mar so dist distz pkg bpk dump elc deploy)
%then %do;%str(application/octet-stream)%end;
%else %if &ext in (atom atomcat atomsvc ccxml davmount emma gml gpx inkml mads
mathml metalink mets mods omdoc pls rdf rsd rss sbml shf smil sru ssdl ssml
tei wsdl wspolicy xaml xenc xhtml xop xslt xspf yin)
%then %do;%str(application/&ext+xml)%end;
%else %if &ext in (dir dcr dxr cst cct cxt w3d fgd swa)
%then %do;%str(application/x-director)%end;
%else %if &ext in (z1 z2 z3 z4 z5 z6 z7 z8)
%then %do;%str(application/x-zmachine)%end;
%else %if &ext in (c cc cxx cpp h hh dic)
%then %do;%str(text/x-c)%end;
%else %if &ext in (mpga mp2 mp2a mp3 m2a m3a)
%then %do;%str(audio/mpeg)%end;
%else %if &ext in (t tr roff man me ms)
%then %do;%str(text/troff)%end;
%else %if &ext in (cbr cba cbt cbz cb7)
%then %do;%str(application/x-cbr)%end;
%else %if &ext in (fh fhc fh4 fh5 fh7)
%then %do;%str(image/x-freehand)%end;
%else %if &ext in (aab x32 u32 vox)
%then %do;%str(application/x-authorware-bin)%end;
%else %if &ext in (uvi uvvi uvg uvvg)
%then %do;%str(image/vnd.dece.graphic)%end;
%else %if &ext in (cdx cif cmdf cml csml xyz)
%then %do;%str(chemical/x-&ext)%end;
%else %if &ext in (aif aiff aifc) %then %do;%str(audio/x-aiff)%end;
%else %if &ext in (ma nb mb) %then %do;%str(application/mathematica)%end;
%else %if &ext in (mvb m13 m14) %then %do;%str(application/x-msmediaview)%end;
%else %if &ext in (msh mesh silo) %then %do;%str(model/mesh)%end;
%else %if &ext in (uri uris urls) %then %do;%str(text/uri-list)%end;
%else %if &ext in (mkv mk3d mks) %then %do;%str(video/x-matroska)%end;
%else %if &ext=ez %then %do;%str(application/andrew-inset)%end;
%else %if &ext=aw %then %do;%str(application/applixware)%end;
%else %if &ext=cdmia %then %do;%str(application/cdmi-capability)%end;
%else %if &ext=cdmic %then %do;%str(application/cdmi-container)%end;
%else %if &ext=cdmid %then %do;%str(application/cdmi-domain)%end;
%else %if &ext=cdmio %then %do;%str(application/cdmi-object)%end;
%else %if &ext=cdmiq %then %do;%str(application/cdmi-queue)%end;
%else %if &ext=cu %then %do;%str(application/cu-seeme)%end;
%else %if &ext=dssc %then %do;%str(application/dssc+der)%end;
%else %if &ext=xdssc %then %do;%str(application/dssc+xml)%end;
%else %if &ext=ecma %then %do;%str(application/ecmascript)%end;
%else %if &ext=epub %then %do;%str(application/epub+zip)%end;
%else %if &ext=pfr %then %do;%str(application/font-tdpfr)%end;
%else %if &ext=stk %then %do;%str(application/hyperstudio)%end;
%else %if &ext=ink %then %do;%str(application/inkml+xml)%end;
%else %if &ext=jar %then %do;%str(application/java-archive)%end;
%else %if &ext=ser %then %do;%str(application/java-serialized-object)%end;
%else %if &ext=class %then %do;%str(application/java-vm)%end;
%else %if &ext=jsonml %then %do;%str(application/jsonml+json)%end;
%else %if &ext=lostxml %then %do;%str(application/lost+xml)%end;
%else %if &ext=hqx %then %do;%str(application/mac-binhex40)%end;
%else %if &ext=cpt %then %do;%str(application/mac-compactpro)%end;
%else %if &ext=mrc %then %do;%str(application/marc)%end;
%else %if &ext=mrcx %then %do;%str(application/marcxml+xml)%end;
%else %if &ext=mscml %then %do;%str(application/mediaservercontrol+xml)%end;
%else %if &ext=meta4 %then %do;%str(application/metalink4+xml)%end;
%else %if &ext=m21 %then %do;%str(application/mp21)%end;
%else %if &ext=mp4s %then %do;%str(application/mp4)%end;
%else %if &ext=doc %then %do;%str(application/msword)%end;
%else %if &ext=dot %then %do;%str(application/msword)%end;
%else %if &ext=opf %then %do;%str(application/oebps-package+xml)%end;
%else %if &ext=ogx %then %do;%str(application/ogg)%end;
%else %if &ext=xer %then %do;%str(application/patch-ops-error+xml)%end;
%else %if &ext=pgp %then %do;%str(application/pgp-encrypted)%end;
%else %if &ext=asc %then %do;%str(application/pgp-signature)%end;
%else %if &ext=sig %then %do;%str(application/pgp-signature)%end;
%else %if &ext=prf %then %do;%str(application/pics-rules)%end;
%else %if &ext=p10 %then %do;%str(application/pkcs10)%end;
%else %if &ext=p7m %then %do;%str(application/pkcs7-mime)%end;
%else %if &ext=p7c %then %do;%str(application/pkcs7-mime)%end;
%else %if &ext=p7s %then %do;%str(application/pkcs7-signature)%end;
%else %if &ext=p8 %then %do;%str(application/pkcs8)%end;
%else %if &ext=ac %then %do;%str(application/pkix-attr-cert)%end;
%else %if &ext=cer %then %do;%str(application/pkix-cert)%end;
%else %if &ext=crl %then %do;%str(application/pkix-crl)%end;
%else %if &ext=pkipath %then %do;%str(application/pkix-pkipath)%end;
%else %if &ext=pki %then %do;%str(application/pkixcmp)%end;
%else %if &ext=cww %then %do;%str(application/prs.cww)%end;
%else %if &ext=pskcxml %then %do;%str(application/pskc+xml)%end;
%else %if &ext=rif %then %do;%str(application/reginfo+xml)%end;
%else %if &ext=rnc %then %do;%str(application/relax-ng-compact-syntax)%end;
%else %if &ext=rld %then %do;%str(application/resource-lists-diff+xml)%end;
%else %if &ext=rl %then %do;%str(application/resource-lists+xml)%end;
%else %if &ext=gbr %then %do;%str(application/rpki-ghostbusters)%end;
%else %if &ext=mft %then %do;%str(application/rpki-manifest)%end;
%else %if &ext=roa %then %do;%str(application/rpki-roa)%end;
%else %if &ext=scq %then %do;%str(application/scvp-cv-request)%end;
%else %if &ext=scs %then %do;%str(application/scvp-cv-response)%end;
%else %if &ext=spq %then %do;%str(application/scvp-vp-request)%end;
%else %if &ext=spp %then %do;%str(application/scvp-vp-response)%end;
%else %if &ext=setpay %then %do;%str(application/set-payment-initiation)%end;
%else %if &ext=setreg %then %do;%str(application/set-registration-initiation)%end;
%else %if &ext=smi %then %do;%str(application/smil+xml)%end;
%else %if &ext=rq %then %do;%str(application/sparql-query)%end;
%else %if &ext=srx %then %do;%str(application/sparql-results+xml)%end;
%else %if &ext=gram %then %do;%str(application/srgs)%end;
%else %if &ext=grxml %then %do;%str(application/srgs+xml)%end;
%else %if &ext=teicorpus %then %do;%str(application/tei+xml)%end;
%else %if &ext=tfi %then %do;%str(application/thraud+xml)%end;
%else %if &ext=tsd %then %do;%str(application/timestamped-data)%end;
%else %if &ext=vxml %then %do;%str(application/voicexml+xml)%end;
%else %if &ext=wgt %then %do;%str(application/widget)%end;
%else %if &ext=hlp %then %do;%str(application/winhlp)%end;
%else %if &ext=7z %then %do;%str(application/x-7z-compressed)%end;
%else %if &ext=abw %then %do;%str(application/x-abiword)%end;
%else %if &ext=ace %then %do;%str(application/x-ace-compressed)%end;
%else %if &ext=dmg %then %do;%str(application/x-apple-diskimage)%end;
%else %if &ext=aam %then %do;%str(application/x-authorware-map)%end;
%else %if &ext=aas %then %do;%str(application/x-authorware-seg)%end;
%else %if &ext=bcpio %then %do;%str(application/x-bcpio)%end;
%else %if &ext=torrent %then %do;%str(application/x-bittorrent)%end;
%else %if &ext=blb %then %do;%str(application/x-blorb)%end;
%else %if &ext=blorb %then %do;%str(application/x-blorb)%end;
%else %if &ext=bz %then %do;%str(application/x-bzip)%end;
%else %if &ext=bz2 %then %do;%str(application/x-bzip2)%end;
%else %if &ext=boz %then %do;%str(application/x-bzip2)%end;
%else %if &ext=vcd %then %do;%str(application/x-cdlink)%end;
%else %if &ext=cfs %then %do;%str(application/x-cfs-compressed)%end;
%else %if &ext=chat %then %do;%str(application/x-chat)%end;
%else %if &ext=pgn %then %do;%str(application/x-chess-pgn)%end;
%else %if &ext=nsc %then %do;%str(application/x-conference)%end;
%else %if &ext=cpio %then %do;%str(application/x-cpio)%end;
%else %if &ext=csh %then %do;%str(application/x-csh)%end;
%else %if &ext=deb %then %do;%str(application/x-debian-package)%end;
%else %if &ext=udeb %then %do;%str(application/x-debian-package)%end;
%else %if &ext=dgc %then %do;%str(application/x-dgc-compressed)%end;
%else %if &ext=wad %then %do;%str(application/x-doom)%end;
%else %if &ext=ncx %then %do;%str(application/x-dtbncx+xml)%end;
%else %if &ext=dtb %then %do;%str(application/x-dtbook+xml)%end;
%else %if &ext=res %then %do;%str(application/x-dtbresource+xml)%end;
%else %if &ext=dvi %then %do;%str(application/x-dvi)%end;
%else %if &ext=evy %then %do;%str(application/x-envoy)%end;
%else %if &ext=eva %then %do;%str(application/x-eva)%end;
%else %if &ext=bdf %then %do;%str(application/x-font-bdf)%end;
%else %if &ext=gsf %then %do;%str(application/x-font-ghostscript)%end;
%else %if &ext=psf %then %do;%str(application/x-font-linux-psf)%end;
%else %if &ext=pcf %then %do;%str(application/x-font-pcf)%end;
%else %if &ext=snf %then %do;%str(application/x-font-snf)%end;
%else %if &ext=arc %then %do;%str(application/x-freearc)%end;
%else %if &ext=spl %then %do;%str(application/x-futuresplash)%end;
%else %if &ext=gca %then %do;%str(application/x-gca-compressed)%end;
%else %if &ext=ulx %then %do;%str(application/x-glulx)%end;
%else %if &ext=gnumeric %then %do;%str(application/x-gnumeric)%end;
%else %if &ext=gramps %then %do;%str(application/x-gramps-xml)%end;
%else %if &ext=gtar %then %do;%str(application/x-gtar)%end;
%else %if &ext=hdf %then %do;%str(application/x-hdf)%end;
%else %if &ext=install %then %do;%str(application/x-install-instructions)%end;
%else %if &ext=iso %then %do;%str(application/x-iso9660-image)%end;
%else %if &ext=jnlp %then %do;%str(application/x-java-jnlp-file)%end;
%else %if &ext=latex %then %do;%str(application/x-latex)%end;
%else %if &ext=lzh %then %do;%str(application/x-lzh-compressed)%end;
%else %if &ext=lha %then %do;%str(application/x-lzh-compressed)%end;
%else %if &ext=mie %then %do;%str(application/x-mie)%end;
%else %if &ext=prc %then %do;%str(application/x-mobipocket-ebook)%end;
%else %if &ext=mobi %then %do;%str(application/x-mobipocket-ebook)%end;
%else %if &ext=application %then %do;%str(application/x-ms-application)%end;
%else %if &ext=lnk %then %do;%str(application/x-ms-shortcut)%end;
%else %if &ext=wmd %then %do;%str(application/x-ms-wmd)%end;
%else %if &ext=wmz %then %do;%str(application/x-ms-wmz)%end;
%else %if &ext=xbap %then %do;%str(application/x-ms-xbap)%end;
%else %if &ext=mdb %then %do;%str(application/x-msaccess)%end;
%else %if &ext=obd %then %do;%str(application/x-msbinder)%end;
%else %if &ext=crd %then %do;%str(application/x-mscardfile)%end;
%else %if &ext=clp %then %do;%str(application/x-msclip)%end;
%else %if &ext=mny %then %do;%str(application/x-msmoney)%end;
%else %if &ext=pub %then %do;%str(application/x-mspublisher)%end;
%else %if &ext=scd %then %do;%str(application/x-msschedule)%end;
%else %if &ext=trm %then %do;%str(application/x-msterminal)%end;
%else %if &ext=wri %then %do;%str(application/x-mswrite)%end;
%else %if &ext=nc %then %do;%str(application/x-netcdf)%end;
%else %if &ext=cdf %then %do;%str(application/x-netcdf)%end;
%else %if &ext=nzb %then %do;%str(application/x-nzb)%end;
%else %if &ext=p12 %then %do;%str(application/x-pkcs12)%end;
%else %if &ext=pfx %then %do;%str(application/x-pkcs12)%end;
%else %if &ext=p7b %then %do;%str(application/x-pkcs7-certificates)%end;
%else %if &ext=spc %then %do;%str(application/x-pkcs7-certificates)%end;
%else %if &ext=p7r %then %do;%str(application/x-pkcs7-certreqresp)%end;
%else %if &ext=rar %then %do;%str(application/x-rar-compressed)%end;
%else %if &ext=ris %then %do;%str(application/x-research-info-systems)%end;
%else %if &ext=sh %then %do;%str(application/x-sh)%end;
%else %if &ext=shar %then %do;%str(application/x-shar)%end;
%else %if &ext=swf %then %do;%str(application/x-shockwave-flash)%end;
%else %if &ext=xap %then %do;%str(application/x-silverlight-app)%end;
%else %if &ext=sql %then %do;%str(application/x-sql)%end;
%else %if &ext=sit %then %do;%str(application/x-stuffit)%end;
%else %if &ext=sitx %then %do;%str(application/x-stuffitx)%end;
%else %if &ext=srt %then %do;%str(application/x-subrip)%end;
%else %if &ext=sv4cpio %then %do;%str(application/x-sv4cpio)%end;
%else %if &ext=sv4crc %then %do;%str(application/x-sv4crc)%end;
%else %if &ext=t3 %then %do;%str(application/x-t3vm-image)%end;
%else %if &ext=gam %then %do;%str(application/x-tads)%end;
%else %if &ext=tar %then %do;%str(application/x-tar)%end;
%else %if &ext=tcl %then %do;%str(application/x-tcl)%end;
%else %if &ext=tex %then %do;%str(application/x-tex)%end;
%else %if &ext=tfm %then %do;%str(application/x-tex-tfm)%end;
%else %if &ext=texinfo %then %do;%str(application/x-texinfo)%end;
%else %if &ext=texi %then %do;%str(application/x-texinfo)%end;
%else %if &ext=obj %then %do;%str(application/x-tgif)%end;
%else %if &ext=ustar %then %do;%str(application/x-ustar)%end;
%else %if &ext=src %then %do;%str(application/x-wais-source)%end;
%else %if &ext=der %then %do;%str(application/x-x509-ca-cert)%end;
%else %if &ext=crt %then %do;%str(application/x-x509-ca-cert)%end;
%else %if &ext=fig %then %do;%str(application/x-xfig)%end;
%else %if &ext=xlf %then %do;%str(application/x-xliff+xml)%end;
%else %if &ext=xpi %then %do;%str(application/x-xpinstall)%end;
%else %if &ext=xz %then %do;%str(application/x-xz)%end;
%else %if &ext=xdf %then %do;%str(application/xcap-diff+xml)%end;
%else %if &ext=xht %then %do;%str(application/xhtml+xml)%end;
%else %if &ext=xsl %then %do;%str(application/xml)%end;
%else %if &ext=dtd %then %do;%str(application/xml-dtd)%end;
%else %if &ext=xpl %then %do;%str(application/xproc+xml)%end;
%else %if &ext=adp %then %do;%str(audio/adpcm)%end;
%else %if &ext=au %then %do;%str(audio/basic)%end;
%else %if &ext=snd %then %do;%str(audio/basic)%end;
%else %if &ext=m4a %then %do;%str(audio/mp4)%end;
%else %if &ext=mp4a %then %do;%str(audio/mp4)%end;
%else %if &ext=s3m %then %do;%str(audio/s3m)%end;
%else %if &ext=sil %then %do;%str(audio/silk)%end;
%else %if &ext=uva %then %do;%str(audio/vnd.dece.audio)%end;
%else %if &ext=uvva %then %do;%str(audio/vnd.dece.audio)%end;
%else %if &ext=eol %then %do;%str(audio/vnd.digital-winds)%end;
%else %if &ext=dra %then %do;%str(audio/vnd.dra)%end;
%else %if &ext=dts %then %do;%str(audio/vnd.dts)%end;
%else %if &ext=dtshd %then %do;%str(audio/vnd.dts.hd)%end;
%else %if &ext=lvp %then %do;%str(audio/vnd.lucent.voice)%end;
%else %if &ext=pya %then %do;%str(audio/vnd.ms-playready.media.pya)%end;
%else %if &ext=ecelp4800 %then %do;%str(audio/vnd.nuera.ecelp4800)%end;
%else %if &ext=ecelp7470 %then %do;%str(audio/vnd.nuera.ecelp7470)%end;
%else %if &ext=ecelp9600 %then %do;%str(audio/vnd.nuera.ecelp9600)%end;
%else %if &ext=rip %then %do;%str(audio/vnd.rip)%end;
%else %if &ext=weba %then %do;%str(audio/webm)%end;
%else %if &ext=mka %then %do;%str(audio/x-matroska)%end;
%else %if &ext=m3u %then %do;%str(audio/x-mpegurl)%end;
%else %if &ext=wax %then %do;%str(audio/x-ms-wax)%end;
%else %if &ext=wma %then %do;%str(audio/x-ms-wma)%end;
%else %if &ext=ra %then %do;%str(audio/x-pn-realaudio)%end;
%else %if &ext=ram %then %do;%str(audio/x-pn-realaudio)%end;
%else %if &ext=rmp %then %do;%str(audio/x-pn-realaudio-plugin)%end;
%else %if &ext=xm %then %do;%str(audio/xm)%end;
%else %if &ext=ttc %then %do;%str(font/collection)%end;
%else %if &ext=g3 %then %do;%str(image/g3fax)%end;
%else %if &ext=btif %then %do;%str(image/prs.btif)%end;
%else %if &ext=svg %then %do;%str(image/svg+xml)%end;
%else %if &ext=svgz %then %do;%str(image/svg+xml)%end;
%else %if &ext=tif %then %do;%str(image/tiff)%end;
%else %if &ext=psd %then %do;%str(image/vnd.adobe.photoshop)%end;
%else %if &ext=djv %then %do;%str(image/vnd.djvu)%end;
%else %if &ext=djvu %then %do;%str(image/vnd.djvu)%end;
%else %if &ext=sub %then %do;%str(image/vnd.dvb.subtitle)%end;
%else %if &ext=dwg %then %do;%str(image/vnd.dwg)%end;
%else %if &ext=dxf %then %do;%str(image/vnd.dxf)%end;
%else %if &ext=fbs %then %do;%str(image/vnd.fastbidsheet)%end;
%else %if &ext=fpx %then %do;%str(image/vnd.fpx)%end;
%else %if &ext=fst %then %do;%str(image/vnd.fst)%end;
%else %if &ext=mmr %then %do;%str(image/vnd.fujixerox.edmics-mmr)%end;
%else %if &ext=rlc %then %do;%str(image/vnd.fujixerox.edmics-rlc)%end;
%else %if &ext=mdi %then %do;%str(image/vnd.ms-modi)%end;
%else %if &ext=wdp %then %do;%str(image/vnd.ms-photo)%end;
%else %if &ext=npx %then %do;%str(image/vnd.net-fpx)%end;
%else %if &ext=wbmp %then %do;%str(image/vnd.wap.wbmp)%end;
%else %if &ext=xif %then %do;%str(image/vnd.xiff)%end;
%else %if &ext=ras %then %do;%str(image/x-cmu-raster)%end;
%else %if &ext=ico %then %do;%str(image/x-icon)%end;
%else %if &ext=sid %then %do;%str(image/x-mrsid-image)%end;
%else %if &ext=pct %then %do;%str(image/x-pict)%end;
%else %if &ext=pic %then %do;%str(image/x-pict)%end;
%else %if &ext=pnm %then %do;%str(image/x-portable-anymap)%end;
%else %if &ext=pbm %then %do;%str(image/x-portable-bitmap)%end;
%else %if &ext=pgm %then %do;%str(image/x-portable-graymap)%end;
%else %if &ext=ppm %then %do;%str(image/x-portable-pixmap)%end;
%else %if &ext=xbm %then %do;%str(image/x-xbitmap)%end;
%else %if &ext=xpm %then %do;%str(image/x-xpixmap)%end;
%else %if &ext=xwd %then %do;%str(image/x-xwindowdump)%end;
%else %if &ext=eml %then %do;%str(message/rfc822)%end;
%else %if &ext=mime %then %do;%str(message/rfc822)%end;
%else %if &ext=iges %then %do;%str(model/iges)%end;
%else %if &ext=igs %then %do;%str(model/iges)%end;
%else %if &ext=dae %then %do;%str(model/vnd.collada+xml)%end;
%else %if &ext=dwf %then %do;%str(model/vnd.dwf)%end;
%else %if &ext=gdl %then %do;%str(model/vnd.gdl)%end;
%else %if &ext=gtw %then %do;%str(model/vnd.gtw)%end;
%else %if &ext=vtu %then %do;%str(model/vnd.vtu)%end;
%else %if &ext=vrml %then %do;%str(model/vrml)%end;
%else %if &ext=wrl %then %do;%str(model/vrml)%end;
%else %if &ext=x3db %then %do;%str(model/x3d+binary)%end;
%else %if &ext=x3dbz %then %do;%str(model/x3d+binary)%end;
%else %if &ext=x3dv %then %do;%str(model/x3d+vrml)%end;
%else %if &ext=x3dvz %then %do;%str(model/x3d+vrml)%end;
%else %if &ext=x3d %then %do;%str(model/x3d+xml)%end;
%else %if &ext=x3dz %then %do;%str(model/x3d+xml)%end;
%else %if &ext=appcache %then %do;%str(text/cache-manifest)%end;
%else %if &ext=ics %then %do;%str(text/calendar)%end;
%else %if &ext=ifb %then %do;%str(text/calendar)%end;
%else %if &ext=htm %then %do;%str(text/html)%end;
%else %if &ext=js %then %do;%str(text/javascript)%end;
%else %if &ext=mjs %then %do;%str(text/javascript)%end;
%else %if &ext=dsc %then %do;%str(text/prs.lines.tag)%end;
%else %if &ext=rtx %then %do;%str(text/richtext)%end;
%else %if &ext=sgm %then %do;%str(text/sgml)%end;
%else %if &ext=tsv %then %do;%str(text/tab-separated-values)%end;
%else %if &ext=ttl %then %do;%str(text/turtle)%end;
%else %if &ext=curl %then %do;%str(text/vnd.curl)%end;
%else %if &ext=dcurl %then %do;%str(text/vnd.curl.dcurl)%end;
%else %if &ext=mcurl %then %do;%str(text/vnd.curl.mcurl)%end;
%else %if &ext=scurl %then %do;%str(text/vnd.curl.scurl)%end;
%else %if &ext=sub %then %do;%str(text/vnd.dvb.subtitle)%end;
%else %if &ext=fly %then %do;%str(text/vnd.fly)%end;
%else %if &ext=flx %then %do;%str(text/vnd.fmi.flexstor)%end;
%else %if &ext=gv %then %do;%str(text/vnd.graphviz)%end;
%else %if &ext=3dml %then %do;%str(text/vnd.in3d.3dml)%end;
%else %if &ext=spot %then %do;%str(text/vnd.in3d.spot)%end;
%else %if &ext=jad %then %do;%str(text/vnd.sun.j2me.app-descriptor)%end;
%else %if &ext=wml %then %do;%str(text/vnd.wap.wml)%end;
%else %if &ext=wmls %then %do;%str(text/vnd.wap.wmlscript)%end;
%else %if &ext=s %then %do;%str(text/x-asm)%end;
%else %if &ext=java %then %do;%str(text/x-java-source)%end;
%else %if &ext=p %then %do;%str(text/x-pascal)%end;
%else %if &ext=pas %then %do;%str(text/x-pascal)%end;
%else %if &ext=etx %then %do;%str(text/x-setext)%end;
%else %if &ext=uu %then %do;%str(text/x-uuencode)%end;
%else %if &ext=vcs %then %do;%str(text/x-vcalendar)%end;
%else %if &ext=vcf %then %do;%str(text/x-vcard)%end;
%else %if &ext=3gp %then %do;%str(video/3gpp)%end;
%else %if &ext=3g2 %then %do;%str(video/3gpp2)%end;
%else %if &ext=jpgv %then %do;%str(video/jpeg)%end;
%else %if &ext=jpgm %then %do;%str(video/jpm)%end;
%else %if &ext=mjp2 %then %do;%str(video/mj2)%end;
%else %if &ext=ogv %then %do;%str(video/ogg)%end;
%else %if &ext=mov %then %do;%str(video/quicktime)%end;
%else %if &ext=qt %then %do;%str(video/quicktime)%end;
%else %if &ext=uvh %then %do;%str(video/vnd.dece.hd)%end;
%else %if &ext=uvvh %then %do;%str(video/vnd.dece.hd)%end;
%else %if &ext=uvm %then %do;%str(video/vnd.dece.mobile)%end;
%else %if &ext=uvvm %then %do;%str(video/vnd.dece.mobile)%end;
%else %if &ext=uvp %then %do;%str(video/vnd.dece.pd)%end;
%else %if &ext=uvvp %then %do;%str(video/vnd.dece.pd)%end;
%else %if &ext=uvs %then %do;%str(video/vnd.dece.sd)%end;
%else %if &ext=uvvs %then %do;%str(video/vnd.dece.sd)%end;
%else %if &ext=uvv %then %do;%str(video/vnd.dece.video)%end;
%else %if &ext=uvvv %then %do;%str(video/vnd.dece.video)%end;
%else %if &ext=dvb %then %do;%str(video/vnd.dvb.file)%end;
%else %if &ext=fvt %then %do;%str(video/vnd.fvt)%end;
%else %if &ext=m4u %then %do;%str(video/vnd.mpegurl)%end;
%else %if &ext=mxu %then %do;%str(video/vnd.mpegurl)%end;
%else %if &ext=pyv %then %do;%str(video/vnd.ms-playready.media.pyv)%end;
%else %if &ext=uvu %then %do;%str(video/vnd.uvvu.mp4)%end;
%else %if &ext=uvvu %then %do;%str(video/vnd.uvvu.mp4)%end;
%else %if &ext=viv %then %do;%str(video/vnd.vivo)%end;
%else %if &ext=asf %then %do;%str(video/x-ms-asf)%end;
%else %if &ext=asx %then %do;%str(video/x-ms-asf)%end;
%else %if &ext=vob %then %do;%str(video/x-ms-vob)%end;
%else %if &ext=wm %then %do;%str(video/x-ms-wm)%end;
%else %if &ext=wmv %then %do;%str(video/x-ms-wmv)%end;
%else %if &ext=wmx %then %do;%str(video/x-ms-wmx)%end;
%else %if &ext=wvx %then %do;%str(video/x-ms-wvx)%end;
%else %if &ext=avi %then %do;%str(video/x-msvideo)%end;
%else %if &ext=movie %then %do;%str(video/x-sgi-movie)%end;
%else %if &ext=ice %then %do;%str(x-conference/x-cooltalk)%end;
%else %if "&ext"="in" %then %do;%str(text/plain)%end;
%else %do;%str(application/octet-stream)%end;
%mend mf_mimetype;

View File

@@ -53,10 +53,11 @@ data &outds(keep=name type length varnum format label ddtype fmtname);
else if formatd=0 then format=cats(fmtname,formatl,'.'); else if formatd=0 then format=cats(fmtname,formatl,'.');
else format=cats(fmtname,formatl,'.',formatd); else format=cats(fmtname,formatl,'.',formatd);
type='N'; type='N';
if format=:'DATETIME' or format=:'E8601DT' then ddtype='DATETIME'; if format=:'DATETIME' or format=:'E8601DT' or format=:'NLDATM'
then ddtype='DATETIME';
else if format=:'DATE' or format=:'DDMMYY' or format=:'MMDDYY' else if format=:'DATE' or format=:'DDMMYY' or format=:'MMDDYY'
or format=:'YYMMDD' or format=:'E8601DA' or format=:'B8601DA' or format=:'YYMMDD' or format=:'E8601DA' or format=:'B8601DA'
or format=:'MONYY' or format=:'MONYY' or format=:'NLDATE'
then ddtype='DATE'; then ddtype='DATE';
else if format=:'TIME' then ddtype='TIME'; else if format=:'TIME' then ddtype='TIME';
else ddtype='NUMERIC'; else ddtype='NUMERIC';

View File

@@ -70,6 +70,7 @@ options
%if "%substr(&sysver,1,1)" ne "4" and "%substr(&sysver,1,1)" ne "5" %then %do; %if "%substr(&sysver,1,1)" ne "4" and "%substr(&sysver,1,1)" ne "5" %then %do;
noautocorrect /* disallow misspelled procedure names */ noautocorrect /* disallow misspelled procedure names */
dsoptions=note2err /* undocumented - convert bad NOTEs to ERRs */ dsoptions=note2err /* undocumented - convert bad NOTEs to ERRs */
/* turn off with dsoptions=nonote2err */
%end; %end;
; ;

View File

@@ -33,7 +33,8 @@
LUA, you can also use this macro: mp_gsubfile.sas LUA, you can also use this macro: mp_gsubfile.sas
@param [in] infile The QUOTED path to the file on which to perform the @param [in] infile The QUOTED path to the file on which to perform the
substitution substitution. Note that you can extract the pathname from a fileref using
the pathname function, eg: `"%sysfunc(pathname(fref))"`;
@param [in] findvar= Macro variable NAME containing the string to search for @param [in] findvar= Macro variable NAME containing the string to search for
@param [in] replacevar= Macro variable NAME containing the replacement string @param [in] replacevar= Macro variable NAME containing the replacement string
@param [out] outfile= (0) Optional QUOTED path to the adjusted output file (to @param [out] outfile= (0) Optional QUOTED path to the adjusted output file (to
@@ -147,6 +148,6 @@ data _null_;
run; run;
/* END */ /* END */
%put &sysmacroname took %sysevalf(%sysfunc(datetime())-&dttm) seconds to run; /* %put &sysmacroname took %sysevalf(%sysfunc(datetime())-&dttm) secs to run; */
%mend mp_replace; %mend mp_replace;

View File

@@ -80,8 +80,8 @@ function mcf_getfmttype(fmtnm $) $8;
/* apply lookups */ /* apply lookups */
if cats(fmt) in ('DATETIME','B8601DN','B8601DN','B8601DT','B8601DT' if cats(fmt) in ('DATETIME','B8601DN','B8601DN','B8601DT','B8601DT'
,'B8601DZ','B8601DZ','DATEAMPM','DTDATE','DTMONYY','DTWKDATX','DTYEAR' ,'B8601DZ','B8601DZ','DATEAMPM','DTDATE','DTMONYY','DTWKDATX','DTYEAR'
,'DTYYQC','E8601DN','E8601DN','E8601DT','E8601DT','E8601DZ','E8601DZ') ,'DTYYQC','E8601DN','E8601DN','E8601DT','E8601DT','E8601DZ','E8601DZ'
then return('DATETIME'); ,'NLDATM') then return('DATETIME');
else if fmt in ('DATE','YYMMDD','B8601DA','B8601DA','DAY','DDMMYY' else if fmt in ('DATE','YYMMDD','B8601DA','B8601DA','DAY','DDMMYY'
,'DDMMYYB','DDMMYYC','DDMMYYD','DDMMYYN','DDMMYYP','DDMMYYS','DDMMYYx' ,'DDMMYYB','DDMMYYC','DDMMYYD','DDMMYYN','DDMMYYP','DDMMYYS','DDMMYYx'
,'DOWNAME','E8601DA','E8601DA','JULDAY','JULIAN','MMDDYY','MMDDYYB' ,'DOWNAME','E8601DA','E8601DA','JULDAY','JULIAN','MMDDYY','MMDDYYB'
@@ -92,7 +92,7 @@ function mcf_getfmttype(fmtnm $) $8;
,'YYMMD','YYMMDDB','YYMMDDC','YYMMDDD','YYMMDDN','YYMMDDP','YYMMDDS' ,'YYMMD','YYMMDDB','YYMMDDC','YYMMDDD','YYMMDDN','YYMMDDP','YYMMDDS'
,'YYMMDDx','YYMMN','YYMMP','YYMMS','YYMMx','YYMON','YYQ','YYQC','YYQD' ,'YYMMDDx','YYMMN','YYMMP','YYMMS','YYMMx','YYMON','YYQ','YYQC','YYQD'
,'YYQN','YYQP','YYQR','YYQRC','YYQRD','YYQRN','YYQRP','YYQRS','YYQRx' ,'YYQN','YYQP','YYQR','YYQRC','YYQRD','YYQRN','YYQRP','YYQRS','YYQRx'
,'YYQS','YYQx','YYQZ') then return('DATE'); ,'YYQS','YYQx','YYQZ','NLDATE') then return('DATE');
else if fmt in ('TIME','B8601LZ','B8601LZ','B8601TM','B8601TM','B8601TZ' else if fmt in ('TIME','B8601LZ','B8601LZ','B8601TM','B8601TM','B8601TZ'
,'B8601TZ','E8601LZ','E8601LZ','E8601TM','E8601TM','E8601TZ','E8601TZ' ,'B8601TZ','E8601LZ','E8601LZ','E8601TM','E8601TM','E8601TZ','E8601TZ'
,'HHMM','HOUR','MMSS','TIMEAMPM','TOD') then return('TIME'); ,'HHMM','HOUR','MMSS','TIMEAMPM','TOD') then return('TIME');

View File

@@ -54,7 +54,8 @@
%local cur_engine; %local cur_engine;
%let cur_engine=%mf_getengine(&libref); %let cur_engine=%mf_getengine(&libref);
%if &cur_engine ne META and &cur_engine ne %then %do; %if &cur_engine ne META and &cur_engine ne and %length(&open_passthrough)=0
%then %do;
%put NOTE: &libref already has a direct (&cur_engine) libname connection; %put NOTE: &libref already has a direct (&cur_engine) libname connection;
%return; %return;
%end; %end;

View File

@@ -1,22 +1,25 @@
/** /**
@file mm_getdetails.sas @file mm_getdetails.sas
@brief extracts metadata attributes and associations for a particular uri @brief extracts metadata attributes and associations for a particular uri
@param [in] uri the metadata object for which to return @param [in] uri the metadata object for which to return
attributes / associations attributes / associations
@param [in] sortoptions= Enables sorting of the output datasets, for example,
`SORTSEQ=LINGUISTIC`
@param [out] outattrs= (work.attributes) @param [out] outattrs= (work.attributes)
The dataset to create that contains the list of attributes The dataset to create that contains the list of attributes
@param [out] outassocs= (work.associations) @param [out] outassocs= (work.associations)
The dataset to contain the list of associations The dataset to contain the list of associations
@version 9.2 <h4> Related Files </h4>
@author Allan Bowe @li mm_getobjects.sas
@li mm_gettypes.sas
**/ **/
%macro mm_getdetails(uri %macro mm_getdetails(uri
,outattrs=work.attributes ,outattrs=work.attributes
,outassocs=work.associations ,outassocs=work.associations
,sortoptions=
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
data &outassocs; data &outassocs;
@@ -41,7 +44,7 @@ data &outassocs;
n1+1; n1+1;
end; end;
run; run;
proc sort; proc sort &sortoptions;
by assoc name; by assoc name;
run; run;
@@ -61,7 +64,7 @@ data &outattrs;
n1+1; n1+1;
end; end;
run; run;
proc sort; proc sort &sortoptions;
by type name; by type name;
run; run;

1896
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@
"Viya", "Viya",
"SASjs" "SASjs"
], ],
"author": "Allan Bowe <support@macropeople.com>", "author": "Allan Bowe",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/sasjs/core.git" "url": "git+https://github.com/sasjs/core.git"
@@ -26,13 +26,10 @@
"homepage": "https://core.sasjs.io", "homepage": "https://core.sasjs.io",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"build": "sasjs cbd -t server", "build": "npx @sasjs/cli cbd -t server",
"docs": "sasjs doc -t docsonly && ./sasjs/utils/build.sh", "docs": "npx @sasjs/cli doc -t docsonly && ./sasjs/utils/build.sh",
"test": "sasjs test -t server", "test": "npx @sasjs/cli test -t server",
"lint": "sasjs lint", "lint": "npx @sasjs/cli lint",
"prepare": "git rev-parse --git-dir && git config core.hooksPath ./.git-hooks || true" "prepare": "git rev-parse --git-dir && git config core.hooksPath ./.git-hooks || true"
},
"devDependencies": {
"@sasjs/cli": "^4.4.1"
} }
} }

View File

@@ -37,6 +37,10 @@
"allowInsecureRequests": false "allowInsecureRequests": false
}, },
"appLoc": "/Public/app/macrocore", "appLoc": "/Public/app/macrocore",
"deployConfig": {
"deployServicePack": true,
"deployScripts": []
},
"macroFolders": [ "macroFolders": [
"viya", "viya",
"tests/viyaonly" "tests/viyaonly"

View File

@@ -1,22 +1,27 @@
#!/bin/bash #!/bin/bash
#################################################################### ####################################################################
# PROJECT: Macro Core Docs Build # # PROJECT: SASjs Core Docs Build
# To execute, use the npm command (npm run docs) # # To execute, use the npm command (npm run docs)
# Target repo will have github action to create sitemap
# https://github.com/marketplace/actions/generate-sitemap
#################################################################### ####################################################################
# refresh github pages site # refresh github pages site
rm -rf sasjsbuild/docsite rm -rf sasjsbuild/docsite
git clone git@github.com:sasjs/core.github.io.git sasjsbuild/docsite git clone git@github.com:sasjs/core.github.io.git sasjsbuild/docsite
rm -rf sasjsbuild/docsite/* rm -rf sasjsbuild/docsite/*.html
mv sasjsbuild/docs/* sasjsbuild/docsite/ rm -rf sasjsbuild/docsite/*.js
rm -rf sasjsbuild/docsite/*.png
rm -rf sasjsbuild/docsite/*.dot
rm -rf sasjsbuild/docsite/*.css
rm -rf sasjsbuild/docsite/*.svg
rm -rf search
cp -R sasjsbuild/docs/* sasjsbuild/docsite/
cd sasjsbuild/docsite/ cd sasjsbuild/docsite/
git config user.name sasjs
echo 'core.sasjs.io' > CNAME echo 'core.sasjs.io' > CNAME
git add . git add .
git commit -m "build.sh build on $(date +%F:%H:%M:%S)" git commit -m "build.sh build on $(date +%F:%H:%M:%S)"
git push git push
npx sitemap-generator-cli https://core.sasjs.io
git add .
git commit -m "adding sitemap"
git push
echo "check it out: https://sasjs.github.io/core.github.io/files.html" echo "check it out: https://sasjs.github.io/core.github.io/files.html"

View File

@@ -8,6 +8,12 @@
Requires the server to have SSH keys. Requires the server to have SSH keys.
<h4> SAS Macros </h4>
@li mf_mkdir.sas
@li mp_gitadd.sas
@li mp_gitreleaseinfo.sas
@li mp_gitstatus.sas
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mp_gitadd.sas @li mp_gitadd.sas
@li mp_gitreleaseinfo.sas @li mp_gitreleaseinfo.sas
@@ -124,11 +130,15 @@ data members(compress=char);
keep name name2 path; keep name name2 path;
run; run;
proc sort data=members;
by name name2;
run;
%let temp_options = %sysfunc(getoption(source)) %sysfunc(getoption(notes)); %let temp_options = %sysfunc(getoption(source)) %sysfunc(getoption(notes));
options nosource nonotes; options nosource nonotes;
data _null_; data _null_;
set members; set members;
by name notsorted; by name;
ord + first.name; ord + first.name;

231
server/ms_triggerstp.sas Normal file
View File

@@ -0,0 +1,231 @@
/**
@file
@brief Triggers a SASjs Server STP using the /SASjsApi/stp/trigger endpoint
@details Triggers the STP and returns the sessionId
Example:
%ms_triggerstp(/some/stored/program
,debug=131
,outds=work.myresults
)
@param [in] pgm The full path to the Stored Program in SASjs Drive (_program
parameter)
@param [in] debug= (131) The value to supply to the _debug URL parameter
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
@param [in] inputparams=(_null_) A dataset containing name/value pairs in the
following format:
|name:$32|value:$10000|
|---|---|
|stpmacname|some value|
|mustbevalidname|can be anything, oops, %abort!!|
@param [in] inputfiles= (_null_) A dataset containing fileref/name/filename in
the following format:
|fileref:$8|name:$32|filename:$256|
|---|---|--|
|someref|some_name|some_filename.xls|
|fref2|another_file|zyx_v2.csv|
@param [in] expiresaftermins= (15) The number of minutes to retain the session
folder after the session ends.
@param [out] outds= (work.ms_triggerstp) Set to the name of a dataset to
contain the sessionId. If this dataset already exists, and contains the
sessionId, it will be appended to.
Format:
|sessionId:$36|
|---|
|20241028074744-54132-1730101664824|
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_getuniquelibref.sas
@li mf_getuniquename.sas
@li mp_abort.sas
@li mp_dropmembers.sas
@li mf_nobs.sas
**/
%macro ms_triggerstp(pgm
,debug=131
,inputparams=_null_
,inputfiles=_null_
,expiresAfterMins=15
,outds=work.ms_triggerstp
,mdebug=0
);
%local dbg mainref authref boundary libref triggered_sid;
%let mainref=%mf_getuniquefileref();
%let authref=%mf_getuniquefileref();
%let boundary=%mf_getuniquename();
%if &inputparams=0 %then %let inputparams=_null_;
%if &mdebug=1 %then %do;
%put &sysmacroname entry vars:;
%put _local_;
%end;
%else %let dbg=*;
%mp_abort(iftrue=("&pgm"="")
,mac=&sysmacroname
,msg=%str(Program not provided)
)
%mp_abort(iftrue=("&outds"="")
,mac=&sysmacroname
,msg=%str(Output dataset not provided)
)
/* avoid sending bom marker to API */
%local optval;
%let optval=%sysfunc(getoption(bomfile));
options nobomfile;
/* Add params to the content */
data _null_;
file &mainref termstr=crlf lrecl=32767 mod;
length line $1000 name $32 value $32767;
if _n_=1 then call missing(of _all_);
set &inputparams;
put "--&boundary";
line=cats('Content-Disposition: form-data; name="',name,'"');
put line;
put ;
put value;
run;
/* parse input file list */
%local webcount;
%let webcount=0;
data _null_;
set &inputfiles end=last;
length fileref $8 name $32 filename $256;
call symputx(cats('webref',_n_),fileref,'l');
call symputx(cats('webname',_n_),name,'l');
call symputx(cats('webfilename',_n_),filename,'l');
if last then do;
call symputx('webcount',_n_);
call missing(of _all_);
end;
run;
/* write out the input files to the content */
%local i;
%do i=1 %to &webcount;
data _null_;
file &mainref termstr=crlf lrecl=32767 mod;
infile &&webref&i lrecl=32767;
if _n_ = 1 then do;
length line $32767;
line=cats(
'Content-Disposition: form-data; name="'
,"&&webname&i"
,'"; filename="'
,"&&webfilename&i"
,'"'
);
put "--&boundary";
put line;
put "Content-Type: text/plain";
put ;
end;
input;
put _infile_; /* add the actual file to be sent */
run;
%end;
/* Add footer to the content */
data _null_;
file &mainref termstr=crlf mod;
put / "--&boundary--";
run;
data _null_;
file &authref lrecl=1000;
infile "&_sasjs_tokenfile" lrecl=1000;
input;
if _n_=1 then put "Content-Type: multipart/form-data; boundary=&boundary";
put _infile_;
run;
%if &mdebug=1 %then %do;
data _null_;
if _n_ eq 1 then putlog "NOTE: ***** authref=&authref content *****";
infile &authref;
input;
put _infile_;
data _null_;
if _n_ eq 1 then putlog "NOTE: ***** mainref=&mainref content *****";
infile &mainref;
input;
put _infile_;
run;
%end;
%local resp_path outref;
%let resp_path=%sysfunc(pathname(work))/%mf_getuniquename();
%let outref=%mf_getuniquefileref();
filename &outref "&resp_path" lrecl=32767;
/* prepare request*/
proc http method='POST' headerin=&authref in=&mainref out=&outref
url="&_sasjs_apiserverurl/SASjsApi/stp/trigger?%trim(
)_program=&pgm%str(&)_debug=131%str(&)expiresAfterMins=&expiresaftermins";
%if &mdebug=1 %then %do;
debug level=2;
%end;
run;
%if (&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201)
or &mdebug=1
%then %do;
data _null_;
if _n_ eq 1 then putlog "NOTE: ***** outref=&outref content *****";
infile &outref;
input;
putlog _infile_;
run;
%end;
%mp_abort(
iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 200
and &SYS_PROCHTTP_STATUS_CODE ne 201)
,mac=&sysmacroname
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
)
/* reset options */
options &optval;
%let libref=%mf_getuniquelibref();
libname &libref JSON fileref=&outref;
%let triggered_sid=%mf_getuniquename(prefix=triggered_sid_);
data work.&triggered_sid (keep=sessionid);
set &libref..root;
%if &mdebug=1 %then %do;
putlog (_all_)(=);
%end;
run;
%if %mf_nobs(work.&triggered_sid)>0 %then %do;
proc append base=&outds data=work.&triggered_sid;
run;
%end;
%if &mdebug=1 %then %do;
%put &sysmacroname exit vars:;
%put _local_;
%end;
%else %do;
/* clear refs */
filename &authref;
filename &mainref;
filename &outref;
libname &libref clear;
/* and remove temp dataset */
%mp_dropmembers(&triggered_sid,libref=work);
%end;
%mend ms_triggerstp;

View File

@@ -0,0 +1,16 @@
/**
@file
@brief Testing mf_mimetype macro
<h4> SAS Macros </h4>
@li mf_mimetype.sas
@li mp_assert.sas
**/
%mp_assert(
iftrue=("%mf_mimetype(XLS)"="application/vnd.ms-excel",
desc=Checking correct value
)

View File

@@ -0,0 +1,90 @@
/**
@file
@brief Testing ms_triggerstp.sas macro
<h4> SAS Macros </h4>
@li mf_getuniquename.sas
@li mp_assert.sas
@li mp_assertscope.sas
@li ms_createfile.sas
@li ms_triggerstp.sas
@li mf_existds.sas
@li mp_assertdsobs.sas
@li mp_assertcols.sas
@li mf_getvartype.sas
@li ms_deletefile.sas
**/
/* first, create multiple STPs to run */
filename stpcode1 temp;
data _null_;
file stpcode1;
put '%put hello world;';
put '%put _all_;';
put 'data _null_; file _webout1; put "triggerstp test 1";run;';
run;
filename stpcode2 temp;
data _null_;
file stpcode2;
put '%put Lorem Ipsum;';
put '%put _all_;';
put 'data _null_; file _webout2; put "triggerstp test 2";run;';
run;
options mprint;
%let fname1=%mf_getuniquename();
%let fname2=%mf_getuniquename();
%ms_createfile(/sasjs/tests/&fname1..sas
,inref=stpcode1
,mdebug=1
)
%ms_createfile(/sasjs/tests/&fname2..sas
,inref=stpcode2
)
%mp_assertscope(SNAPSHOT)
%ms_triggerstp(/sasjs/tests/&fname1
,debug=131
,outds=work.mySessions
)
%ms_triggerstp(/sasjs/tests/&fname2
,outds=work.mySessions
)
%mp_assertscope(COMPARE
,ignorelist=MCLIB0_JADP1LEN MCLIB0_JADPNUM MCLIB0_JADVLEN)
%mp_assert(iftrue=%str(%mf_existds(work.mySessions)=1)
,desc=Testing output exists
,outds=work.test_results
)
%mp_assertdsobs(work.mySessions,
test=EQUALS 2,
desc=Testing observations,
outds=work.test_results
)
%mp_assertcols(work.mySessions,
cols=sessionid,
test=ALL,
desc=Testing column exists,
outds=work.test_results
)
data _null_;
retain contentCheck 1;
set work.mySessions end=last;
if missing(sessionID) then contentCheck = 0;
if last then do;
call symputx("contentCheck",contentCheck,"l");
end;
run;
%let typeCheck = %mf_getvartype(work.mySessions,sessionid);
%mp_assert(iftrue=%str(&typeCheck = C and &contentCheck = 1)
,desc=Testing type and content of output
,outds=work.test_results
)
%ms_deletefile(/sasjs/tests/&fname1..sas)
%ms_deletefile(/sasjs/tests/&fname2..sas)

View File

@@ -10,7 +10,7 @@
**/ **/
/* location in metadata or SAS Drive for temporary files */ /* location in metadata or SAS Drive for temporary files */
%let mcTestAppLoc=/tmp/tests/sasjs/core/%mf_uid(); %let mcTestAppLoc=/Public/testresults/sasjs_core/%mf_uid();
/* set defaults */ /* set defaults */
%mp_init() %mp_init()

View File

@@ -0,0 +1,31 @@
/**
@file
@brief Testing mfv_getfolderpath macro function
<h4> SAS Macros </h4>
@li mf_uid.sas
@li mfv_getfolderpath.sas
@li mfv_getpathuri.sas
@li mp_assert.sas
@li mv_createfolder.sas
**/
options mprint sgen;
%let folder=%mf_uid();
/* create a folder */
%mv_createfolder(path=&mcTestAppLoc/&folder)
%mp_assert(
iftrue=(&syscc=0),
desc=no errs on folder creation
)
%let uri=%mfv_getpathuri(&mcTestAppLoc/&folder);
%put %mfv_getfolderpath(&uri);
%mp_assert(
iftrue=("%mfv_getfolderpath(&uri)"="&mcTestAppLoc/&folder"),
desc=Check if correct folder was returned
)

View File

@@ -0,0 +1,35 @@
/**
@file
@brief Testing mfv_getpathuri macro function
<h4> SAS Macros </h4>
@li mf_uid.sas
@li mfv_getpathuri.sas
@li mp_assert.sas
@li mv_createfile.sas
**/
options mprint sgen;
%let file=%mf_uid();
/* create a file */
filename somefile temp;
data _null_;
file somefile;
put 'hello testings';
run;
%let path=&mcTestAppLoc/temp;
%mv_createfile(path=&path, name=&file..txt,inref=somefile)
%mp_assert(
iftrue=(%mfv_existfile(&path/&file..txt)=1),
desc=Check if created file exists
)
%mp_assert(
iftrue=(%length(%mfv_getpathuri(&path/&file..txt))>0),
desc=Check that a URI was returned
)

View File

@@ -6,6 +6,7 @@
@li mf_uid.sas @li mf_uid.sas
@li mfv_existfile.sas @li mfv_existfile.sas
@li mp_assert.sas @li mp_assert.sas
@li mp_assertscope.sas
@li mv_createfile.sas @li mv_createfile.sas
@@ -21,22 +22,90 @@ data _null_;
file somefile; file somefile;
put 'hello testings'; put 'hello testings';
run; run;
%mv_createfile(path=&mcTestAppLoc/temp, name=&file..txt,inref=somefile) %mp_assertscope(SNAPSHOT)
%mv_createfile(path=&mcTestAppLoc, name=&file..txt,inref=somefile,mdebug=1)
%mp_assertscope(COMPARE
,ignorelist=MCLIB0_JADP1LEN MCLIB0_JADP2LEN MCLIB0_JADPNUM
MCLIB0_JADVLEN MCLIB2_JADP1LEN
SASJSPROCESSMODE SASJS_STPSRV_HEADER_LOC
MCLIB2_JADP2LEN MCLIB2_JADPNUM MCLIB2_JADVLEN
)
%mp_assert( %mp_assert(
iftrue=(%mfv_existfile(&mcTestAppLoc/temp/&file..txt)=1), iftrue=(%mfv_existfile(&mcTestAppLoc/&file..txt)=1),
desc=Check if created file exists desc=Check if created file exists
) )
%put TEST 2 - dataset upload ; %put TEST 2 - html file;
filename f2 temp;
data _null_;
file f2;
put '<html><body><p>Hello world</p></body></html>';
run;
%mv_createfile(path=&mcTestAppLoc, name=test.html,inref=f2,mdebug=1)
%mp_assert(
iftrue=(%mfv_existfile(&mcTestAppLoc/test.html)=1),
desc=Check if created file exists
)
%put TEST 3 - dataset upload ;
data temp; data temp;
x=1; x=1;
run; run;
filename ds "%sysfunc(pathname(work))/temp.sas7bdat"; filename ds "%sysfunc(pathname(work))/temp.sas7bdat";
%mv_createfile(path=&mcTestAppLoc/temp, name=&file..sas7bdat,inref=ds) %mv_createfile(path=&mcTestAppLoc, name=&file..sas7bdat,inref=ds,mdebug=1)
%mp_assert( %mp_assert(
iftrue=(%mfv_existfile(&mcTestAppLoc/temp/&file..sas7bdat)=1), iftrue=(%mfv_existfile(&mcTestAppLoc/&file..sas7bdat)=1),
desc=Check if created dataset exists desc=Check if created dataset exists
) )
%put TEST 4 - create a .sas file;
filename f4 temp;
data _null_;
file f4;
put '%put hello FromSASStudioBailey; ';
run;
%mv_createfile(path=&mcTestAppLoc, name=test4.sas,inref=f4,mdebug=1)
%mp_assert(
iftrue=(%mfv_existfile(&mcTestAppLoc/test4.sas)=1),
desc=Check if created sas program exists
)
%put TEST 5 - reading from files service and writing back;
filename sendfrom filesrvc folderpath="&mcTestAppLoc" filename='test4.sas';
OPTIONS MERROR SYMBOLGEN MLOGIC MPRINT;
%mv_createfile(path=&mcTestAppLoc,name=test5.sas,inref=sendfrom,mdebug=1) ;
%put TEST 6 - try the find and replace;
filename f6 temp;
data _null_;
file f6;
put '//Hello world!';
put 'let var=/some/path/name;';
run;
%let in=/some/path/name;
%let out=/final/destination;
%mv_createfile(path=&mcTestAppLoc, name=test6.js,inref=f6,mdebug=1,swap=in out)
filename getback filesrvc folderpath="&mcTestAppLoc" filename='test6.js';
%let test6=0;
data _null_;
infile getback;
input;
if _infile_="let var=&out;" then call symputx('test6',1);
putlog _infile_;
run;
%mp_assert(
iftrue=(&test6=1),
desc=Check if find & replace worked
)

View File

@@ -30,3 +30,19 @@ run;
iftrue=(&test=1), iftrue=(&test=1),
desc=Check if temp folder can be successfully created desc=Check if temp folder can be successfully created
) )
/* create a folder without output dataset as part of the original macro */
%mv_createfolder(path=&mcTestAppLoc/temp/&folder/folder2,outds=folders2)
%let test=0;
data _null_;
set work.folders2;
putlog (_all_)(=);
if not missing(self_uri) and not missing(parent_uri)
then call symputx('test2',1);
run;
%mp_assert(
iftrue=(&test2=1),
desc=Check if outds param works
)

View File

@@ -33,16 +33,23 @@
msg=Cannot enter mfv_existfolder.sas with syscc=&syscc msg=Cannot enter mfv_existfolder.sas with syscc=&syscc
) )
%local fref rc; %local fref rc var;
%let fref=%mf_getuniquefileref(); %let fref=%mf_getuniquefileref();
%if %sysfunc(filename(fref,,filesrvc,folderPath="&path"))=0 %then %do; %if %sysfunc(filename(fref,,filesrvc,folderPath="&path"))=0 %then %do;
1 1
%let var=_FILESRVC_&fref._URI;
%let rc=%sysfunc(filename(fref)); %let rc=%sysfunc(filename(fref));
%symdel &var;
%end; %end;
%else %do; %else %do;
0 0
%let syscc=0; %let syscc=0;
%end; %end;
%mf_abort(
iftrue=(&syscc ne 0),
msg=Cannot leave mfv_existfolder.sas with syscc=&syscc
)
%mend mfv_existfolder; %mend mfv_existfolder;

View File

@@ -0,0 +1,53 @@
/**
@file
@brief Returns the path of a folder from the URI
@details Makes use of the SYSMSG() ER8OR response, which resolves the uri,
seemingly without entering an er8or state.
Usage:
%mv_createfolder(path=/public/demo)
%let uri=%mfv_getpathuri(/public/demo);
%put %mfv_getfolderpath(&uri);
Notice above the new path has an uppercase P - the correct path.
@param [in] uri The uri of the folder -eg /folders/folders/xxxx)
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
<h4> Related Macros </h4>
@li mfv_getpathuri.sas
@version 4
@author [Allan Bowe](https://www.linkedin.com/in/allanbowe/)
**/
%macro mfv_getfolderpath(uri
)/*/STORE SOURCE*/;
%local fref rc path msg var /* var used to avoid delete timing issue */;
%let fref=%mf_getuniquefileref();
%if %quote(%substr(%str(&uri),1,17)) ne %quote(/folders/folders/)
%then %do;
%put &sysmacroname: Invalid URI: &uri;
%end;
%else %if %sysfunc(filename(fref,,filesrvc,folderuri="&uri" ))=0
%then %do;
%let var=_FILESRVC_&fref._URI;
%local fid ;
%let fid= %sysfunc(fopen(&fref,I));
%let msg=%quote(%sysfunc(sysmsg()));
%unquote(%scan(&msg,2,%str(,.)))
%let rc=%sysfunc(fclose(&fid));
%let rc=%sysfunc(filename(fref));
%symdel &var;
%end;
%else %do;
%put &sysmacroname: Not Found: &uri;
%let syscc=0;
%end;
%mend mfv_getfolderpath ;

56
viya/mfv_getpathuri.sas Normal file
View File

@@ -0,0 +1,56 @@
/**
@file
@brief Returns the uri of a file or folder
@details The automatic variable `_FILESRVC_[fref]_URI` is used after assigning
a fileref using the filesrvc engine.
Usage:
%put %mfv_getpathuri(/Public/folder/file.txt);
%put %mfv_getpathuri(/Public/folder);
@param [in] filepath The full path to the file on SAS drive
(eg /Public/myfile.txt)
<h4> SAS Macros </h4>
@li mf_abort.sas
@li mf_getuniquefileref.sas
<h4> Related Macros </h4>
@li mfv_existfile.sas
@li mfv_existfolder.sas
@version 3.5
@author [Allan Bowe](https://www.linkedin.com/in/allanbowe/)
**/
%macro mfv_getpathuri(filepath
)/*/STORE SOURCE*/;
%mf_abort(
iftrue=(&syscc ne 0),
msg=Cannot enter &sysmacroname with syscc=&syscc
)
%local fref rc path name var /* var is used to avoid delete timing issue */;
%let fref=%mf_getuniquefileref();
%let name=%scan(&filepath,-1,/);
%let path=%substr(&filepath,1,%length(&filepath)-%length(&name)-1);
%if %sysfunc(filename(fref,,filesrvc,folderPath="&path" filename="&name"))=0
%then %do;
%let var=_FILESRVC_&fref._URI;
%str(&&&var)
%let rc=%sysfunc(filename(fref));
%symdel &var;
%end;
%else %do;
%put &sysmacroname: did not find &filepath;
%let syscc=0;
%end;
%mf_abort(
iftrue=(&syscc ne 0),
msg=Cannot leave &sysmacroname with syscc=&syscc
)
%mend mfv_getpathuri;

View File

@@ -1,8 +1,12 @@
/** /**
@file @file
@brief Creates a file in SAS Drive @brief Creates a file in SAS Drive using the API method
@details Creates a file in SAS Drive and adds the appropriate content type. @details Creates a file in SAS Drive using the API interface.
If the parent folder does not exist, it is created. If the parent folder does not exist, it is created.
The API approach is more flexible than using the filesrvc engine of the
filename statement, as it provides more options.
SAS docs: https://developer.sas.com/rest-apis/files/createNewFile
Usage: Usage:
@@ -13,50 +17,76 @@
run; run;
%mv_createfile(path=/Public/temp,name=newfile.txt,inref=myfile) %mv_createfile(path=/Public/temp,name=newfile.txt,inref=myfile)
The macro also supports find & replace (used by the SASjs Streaming App
build program). This allows one string to be replaced by another at the
point at which the file is created. This is done by passing in the NAMES of
the macro variables containing the values to be swapped, eg:
@param [in] path= The parent folder in which to create the file filename fref temp;
data _null_;
file fref;
put 'whenever life gets you down, Mrs Brown..';
run;
%let f=Mrs Brown;
%let r=just remember that you're standing on a planet that's evolving;
%mv_createfile(path=/Public,name=life.md,inref=fref,fin,swap=f r)
@param [in] path= The parent (SAS Drive) folder in which to create the file
@param [in] name= The name of the file to be created @param [in] name= The name of the file to be created
@param [in] inref= The fileref pointing to the file to be uploaded @param [in] inref= The fileref pointing to the file to be uploaded
@param [in] intype= (BINARY) The type of the input data. Valid values: @param [in] intype= (BINARY) The type of the input data. Valid values:
@li BINARY File is copied byte for byte using the mp_binarycopy.sas macro. @li BINARY File is copied byte for byte using the mp_binarycopy.sas macro.
@li BASE64 File will be first decoded using the mp_base64.sas macro, then @li BASE64 File will be first decoded using the mp_base64.sas macro, then
loaded byte by byte to SAS Drive. loaded byte by byte to SAS Drive.
@param [in] contentdisp= (inline) Content Disposition. Example values: @param [in] contentdisp= (attchment) Content Disposition. Example values:
@li inline @li inline
@li attachment @li attachment
@param [in] ctype= (0) Set a default HTTP Content-Type header to be returned @param [in] ctype= (0) The actual MIME type of the file (if blank will be
with the file when the content is retrieved from the Files service. determined based on file extension))
@param [in] access_token_var= The global macro variable to contain the access @param [in] access_token_var= The global macro variable to contain the access
token, if using authorization_code grant type. token, if using authorization_code grant type.
@param [in] grant_type= (sas_services) Valid values are: @param [in] grant_type= (sas_services) Valid values are:
@li password @li password
@li authorization_code @li authorization_code
@li sas_services @li sas_services
@param [in] force= (YES) Will overwrite (delete / recreate) files by default.
Set to NO to abort if a file already exists in that location.
@param pin] swap= (0) Provide two macro variable NAMES that contain the values
to be swapped, eg swap=find replace (see also the example above)
@param [out] outds= (_null_) Output dataset with the uri of the new file
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages @param [in] mdebug= (0) Set to 1 to enable DEBUG messages
@version VIYA V.03.05
@author Allan Bowe, source: https://github.com/sasjs/core
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mf_getplatform.sas
@li mf_getuniquefileref.sas @li mf_getuniquefileref.sas
@li mf_getuniquename.sas
@li mf_isblank.sas @li mf_isblank.sas
@li mf_mimetype.sas
@li mfv_getpathuri.sas
@li mp_abort.sas @li mp_abort.sas
@li mp_base64copy.sas @li mp_base64copy.sas
@li mp_binarycopy.sas @li mp_replace.sas
@li mv_createfolder.sas @li mv_createfolder.sas
<h4> Related Macros</h4>
@li mv_createfile.sas
**/ **/
%macro mv_createfile(path= %macro mv_createfile(path=
,name= ,name=
,inref= ,inref=
,intype=BINARY ,intype=BINARY
,contentdisp=inline ,contentdisp=attachment
,ctype=0 ,ctype=0
,access_token_var=ACCESS_TOKEN ,access_token_var=ACCESS_TOKEN
,grant_type=sas_services ,grant_type=sas_services
,mdebug=0 ,mdebug=0
,outds=_null_
,force=YES
,swap=0
); );
%local dbg; %local dbg;
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
@@ -65,6 +95,11 @@
%end; %end;
%else %let dbg=*; %else %let dbg=*;
%mp_abort(
iftrue=(&syscc ne 0),
msg=Cannot enter &sysmacroname with syscc=&syscc
)
%local oauth_bearer; %local oauth_bearer;
%if &grant_type=detect %then %do; %if &grant_type=detect %then %do;
%if %symexist(&access_token_var) %then %let grant_type=authorization_code; %if %symexist(&access_token_var) %then %let grant_type=authorization_code;
@@ -78,52 +113,157 @@
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password %mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
and &grant_type ne sas_services and &grant_type ne sas_services
) )
,mac=&sysmacroname ,mac=MV_CREATEFILE
,msg=%str(Invalid value for grant_type: &grant_type) ,msg=%str(Invalid value for grant_type: &grant_type)
) )
%mp_abort(iftrue=(%mf_isblank(&path)=1 or %length(&path)=1) %mp_abort(iftrue=(%mf_isblank(&path)=1 or %length(&path)=1)
,mac=&sysmacroname ,mac=MV_CREATEFILE
,msg=%str(path value must be provided) ,msg=%str(path value must be provided)
) )
%mp_abort(iftrue=(%mf_isblank(&name)=1 or %length(&name)=1) %mp_abort(iftrue=(%mf_isblank(&name)=1 or %length(&name)=1)
,mac=&sysmacroname ,mac=MV_CREATEFILE
,msg=%str(name value with length >1 must be provided) ,msg=%str(name value with length >1 must be provided)
) )
/* prep the source file */
%local fref;
%let fref=%mf_getuniquefileref();
%if %upcase(&intype)=BINARY %then %let fref=&inref;
%else %if %upcase(&intype)=BASE64 %then %do;
%mp_base64copy(inref=&inref, outref=&fref, action=DECODE)
%end;
%else %put %str(ERR)OR: invalid value for intype: &intype;
%if "&swap" ne "0" %then %do;
%mp_replace("%sysfunc(pathname(&fref))"
,findvar=%scan(&swap,1,%str( ))
,replacevar=%scan(&swap,2,%str( ))
)
%end;
%if &mdebug=1 %then %do;
data _null_;
infile &fref lrecl=32767;
input;
put _infile_;
run;
%end;
options noquotelenmax;
%local base_uri; /* location of rest apis */
%let base_uri=%mf_getplatform(VIYARESTAPI);
/* create folder if it does not already exist */ /* create folder if it does not already exist */
%local folderds self_uri;
%let folderds=%mf_getuniquename(prefix=folderds);
%mv_createfolder(path=&path %mv_createfolder(path=&path
,access_token_var=&access_token_var ,access_token_var=&access_token_var
,grant_type=&grant_type ,grant_type=&grant_type
,mdebug=&mdebug ,mdebug=&mdebug
,outds=&folderds
)
data _null_;
set &folderds;
call symputx('self_uri',self_uri,'l');
run;
/* abort or delete if file already exists */
%let force=%upcase(&force);
%local fileuri ;
%let fileuri=%mfv_getpathuri(&path/&name);
%mp_abort(iftrue=(%mf_isblank(&fileuri)=0 and &force ne YES)
,mac=MV_CREATEFILE
,msg=%str(File &path/&name already exists and force=&force)
)
%mp_abort(
iftrue=(&syscc ne 0),
mac=MV_CREATEFILE182
msg=syscc=&syscc after mfv_getpathuri
) )
/* create file with relevant options */ %if %mf_isblank(&fileuri)=0 and &force=YES %then %do;
%local fref; proc http method="DELETE" url="&base_uri&fileuri" &oauth_bearer;
%let fref=%mf_getuniquefileref(); headers
filename &fref filesrvc %if &grant_type=authorization_code %then %do;
folderPath="&path" "Authorization"="Bearer &&&access_token_var"
filename="&name" %end;
cdisp="&contentdisp" "Accept"="*/*";
%if "&ctype" ne "0" %then %do; run;
ctype="&ctype" %put &sysmacroname DELETE &base_uri&fileuri;
%end; %if &SYS_PROCHTTP_STATUS_CODE ne 204 %then %do;
lrecl=1048544; %put &=SYS_PROCHTTP_STATUS_CODE &=SYS_PROCHTTP_STATUS_PHRASE;
%if &intype=BINARY %then %do; %end;
%mp_binarycopy(inref=&inref, outref=&fref)
%end;
%else %if &intype=BASE64 %then %do;
%mp_base64copy(inref=&inref, outref=&fref, action=DECODE)
%end; %end;
filename &fref clear; %local url mimetype ext;
%let url=&base_uri/files/files?parentFolderUri=&self_uri;
%let ext=%upcase(%scan(&name,-1,.));
%local base_uri; /* location of rest apis */ /* fetch job info */
%let base_uri=%mf_getplatform(VIYARESTAPI); %local fname1;
%let fname1=%mf_getuniquefileref();
proc http method='POST' out=&fname1 &oauth_bearer in=&fref
%if "&ctype" = "0" %then %do;
%let mimetype=%mf_mimetype(&ext);
ct="&mimetype"
%end;
%else %do;
ct="&ctype"
%end;
%if "&ext"="HTML" or "&ext"="CSS" or "&ext"="JS" or "&ext"="PNG"
or "&ext"="SVG" %then %do;
url="&url%str(&)typeDefName=file";
%end;
%else %do;
url="&url";
%end;
%put &sysmacroname: File &name successfully created in &path; headers "Accept"="application/json"
%put &sysmacroname:;%put; %if &grant_type=authorization_code %then %do;
%put &base_uri/SASJobExecution?_file=&path/&name;%put; "Authorization"="Bearer &&&access_token_var"
%put &sysmacroname:; %end;
"Content-Disposition"=
%if "&ext"="SVG" or "&ext"="HTML" %then %do;
"filename=""&name"";"
%end;
%else %do;
"&contentdisp filename=""&name""; name=""&name"";"
%end;
;
run;
%if &mdebug=1 %then %put &sysmacroname POST &=url
&=SYS_PROCHTTP_STATUS_CODE &=SYS_PROCHTTP_STATUS_PHRASE;
%mp_abort(iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 201)
,mac=MV_CREATEFILE
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
)
%local libref2;
%let libref2=%mf_getuniquelibref();
libname &libref2 JSON fileref=&fname1;
/* Grab the follow on link */
data &outds;
set &libref2..links end=last;
if rel='createChild' then do;
call symputx('href',quote(cats("&base_uri",href)),'l');
&dbg put (_all_)(=);
end;
run;
%put &sysmacroname: %trim(&base_uri)%mfv_getpathuri(&path/&name);
%put /SASJobExecution?_file=&path/&name;%put;
%if &mdebug=0 %then %do;
/* clear refs */
filename &fname1 clear;
filename &fref clear;
libname &libref2 clear;
%end;
%mp_abort(
iftrue=(&syscc ne 0),
msg=Cannot leave &sysmacroname with syscc=&syscc
)
%mend mv_createfile; %mend mv_createfile;

View File

@@ -17,15 +17,16 @@
@li sas_services @li sas_services
@param [in] mdebug=(0) set to 1 to enable DEBUG messages @param [in] mdebug=(0) set to 1 to enable DEBUG messages
@param [out] outds=(_null_) Optionally create an output dataset which will
contain the uri (self_uri) of the created (and parent) folder.
@version VIYA V.03.04
@author Allan Bowe, source: https://github.com/sasjs/core
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mp_abort.sas @li mp_abort.sas
@li mf_getuniquefileref.sas @li mf_getuniquefileref.sas
@li mf_getuniquelibref.sas @li mf_getuniquelibref.sas
@li mf_isblank.sas @li mf_isblank.sas
@li mfv_getpathuri.sas
@li mf_getplatform.sas @li mf_getplatform.sas
@li mfv_existfolder.sas @li mfv_existfolder.sas
@@ -36,6 +37,7 @@
,access_token_var=ACCESS_TOKEN ,access_token_var=ACCESS_TOKEN
,grant_type=sas_services ,grant_type=sas_services
,mdebug=0 ,mdebug=0
,outds=_null_
); );
%local dbg; %local dbg;
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
@@ -44,10 +46,21 @@
%end; %end;
%else %let dbg=*; %else %let dbg=*;
%mp_abort(
iftrue=(&syscc ne 0),
msg=Cannot enter &sysmacroname with syscc=&syscc
)
%if %mfv_existfolder(&path)=1 %then %do; %if %mfv_existfolder(&path)=1 %then %do;
%put &sysmacroname: &path already exists; %&dbg.put &sysmacroname: &path already exists;
data &outds;
self_uri="%mfv_getpathuri(&path)";
output;
stop;
run;
%return; %return;
%end; %end;
%mp_abort(iftrue=(&syscc ne 0),msg=syscc=&syscc when folder checking)
%local oauth_bearer; %local oauth_bearer;
%if &grant_type=detect %then %do; %if &grant_type=detect %then %do;
@@ -80,12 +93,12 @@ options noquotelenmax;
%local subfolder_cnt; /* determine the number of subfolders */ %local subfolder_cnt; /* determine the number of subfolders */
%let subfolder_cnt=%sysfunc(countw(&path,/)); %let subfolder_cnt=%sysfunc(countw(&path,/));
%local href; /* resource address (none for root) */
%let href="/folders/folders?parentFolderUri=/folders/folders/none";
%local base_uri; /* location of rest apis */ %local base_uri; /* location of rest apis */
%let base_uri=%mf_getplatform(VIYARESTAPI); %let base_uri=%mf_getplatform(VIYARESTAPI);
%local href; /* resource address (none for root) */
%let href="&base_uri/folders/folders?parentFolderUri=/folders/folders/none";
%local x newpath subfolder; %local x newpath subfolder;
%do x=1 %to &subfolder_cnt; %do x=1 %to &subfolder_cnt;
%let subfolder=%scan(&path,&x,%str(/)); %let subfolder=%scan(&path,&x,%str(/));
@@ -101,6 +114,17 @@ options noquotelenmax;
headers "Authorization"="Bearer &&&access_token_var"; headers "Authorization"="Bearer &&&access_token_var";
%end; %end;
run; run;
%if &SYS_PROCHTTP_STATUS_CODE=401 %then %do;
/* relates to: https://github.com/sasjs/core/issues/400 */
%put 401 thrown in &sysmacroname;
%put sleeping: %sysfunc(sleep(12,1)) secs - will try again;
proc http method='GET' out=&fname1 &oauth_bearer
url="&base_uri/folders/folders/@item?path=&newpath";
%if &grant_type=authorization_code %then %do;
headers "Authorization"="Bearer &&&access_token_var";
%end;
run;
%end;
%local libref1; %local libref1;
%let libref1=%mf_getuniquelibref(); %let libref1=%mf_getuniquelibref();
libname &libref1 JSON fileref=&fname1; libname &libref1 JSON fileref=&fname1;
@@ -108,14 +132,14 @@ options noquotelenmax;
iftrue=( iftrue=(
&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 404 &SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 404
) )
,mac=&sysmacroname ,mac=mv_createfolder124
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE) ,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
) )
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
%put &sysmacroname following check to see if &newpath exists:; %put &sysmacroname following check to see if &newpath exists:;
%put _local_; %put _local_;
data _null_; data _null_;
set &fname1; infile &fname1;
input; input;
putlog _infile_; putlog _infile_;
run; run;
@@ -157,8 +181,9 @@ options noquotelenmax;
'Content-Type'='application/vnd.sas.content.folder+json' 'Content-Type'='application/vnd.sas.content.folder+json'
'Accept'='application/vnd.sas.content.folder+json'; 'Accept'='application/vnd.sas.content.folder+json';
run; run;
%put &=SYS_PROCHTTP_STATUS_CODE; %if &SYS_PROCHTTP_STATUS_CODE ne 201 %then %do;
%put &=SYS_PROCHTTP_STATUS_PHRASE; %put &=SYS_PROCHTTP_STATUS_CODE &=SYS_PROCHTTP_STATUS_PHRASE;
%end;
%mp_abort(iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 201) %mp_abort(iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 201)
,mac=&sysmacroname ,mac=&sysmacroname
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE) ,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
@@ -167,12 +192,17 @@ options noquotelenmax;
%let libref2=%mf_getuniquelibref(); %let libref2=%mf_getuniquelibref();
libname &libref2 JSON fileref=&fname2; libname &libref2 JSON fileref=&fname2;
%put &sysmacroname &newpath now created. Grabbing the follow on link ; %put &sysmacroname &newpath now created. Grabbing the follow on link ;
data _null_; data &outds;
set &libref2..links; set &libref2..links;
if rel='createChild' then do; if rel='createChild' then do;
call symputx('href',quote(cats("&base_uri",href)),'l'); call symputx('href',quote(cats("&base_uri",href)),'l');
&dbg put (_all_)(=); &dbg put (_all_)(=);
end; end;
if method='GET' and rel='self' then do;
self_uri=uri;
output;
end;
keep self_uri ;
run; run;
libname &libref2 clear; libname &libref2 clear;
@@ -181,4 +211,8 @@ options noquotelenmax;
filename &fname1 clear; filename &fname1 clear;
libname &libref1 clear; libname &libref1 clear;
%end; %end;
%mp_abort(
iftrue=(&syscc ne 0),
msg=Cannot leave &sysmacroname with syscc=&syscc
)
%mend mv_createfolder; %mend mv_createfolder;

View File

@@ -122,7 +122,7 @@ options noquotelenmax;
%let path=%substr(&path,1,%length(&path)-1); %let path=%substr(&path,1,%length(&path)-1);
/* ensure folder exists */ /* ensure folder exists */
%put &sysmacroname: Path &path being checked / created; %&dbg.put &sysmacroname: Path &path being checked / created;
%mv_createfolder(path=&path) %mv_createfolder(path=&path)
%local base_uri; /* location of rest apis */ %local base_uri; /* location of rest apis */
@@ -955,12 +955,7 @@ run;
libname &libref1 clear; libname &libref1 clear;
%end; %end;
%put &sysmacroname: Job &name successfully created in &path; %put &sysmacroname: Job &name created! Check it out:;
%put &sysmacroname:; %put &url/SASJobExecution?_PROGRAM=&path/&name;
%put &sysmacroname: Check it out here:;
%put &sysmacroname:;%put;
%put &url/SASJobExecution?_PROGRAM=&path/&name;%put;
%put &sysmacroname:;
%put &sysmacroname:;
%mend mv_createwebservice; %mend mv_createwebservice;

View File

@@ -111,13 +111,15 @@ proc http method='GET' out=&fname1a &oauth_bearer
headers "Authorization"="Bearer &&&access_token_var"; headers "Authorization"="Bearer &&&access_token_var";
%end; %end;
run; run;
%put &=SYS_PROCHTTP_STATUS_CODE; %if &SYS_PROCHTTP_STATUS_CODE ne 200 %then %do;
%put &=sysmacroname &=SYS_PROCHTTP_STATUS_CODE &=SYS_PROCHTTP_STATUS_PHRASE;
%end;
%local libref1a; %local libref1a;
%let libref1a=%mf_getuniquelibref(); %let libref1a=%mf_getuniquelibref();
libname &libref1a JSON fileref=&fname1a; libname &libref1a JSON fileref=&fname1a;
%local uri found; %local uri found;
%let found=0; %let found=0;
%put Getting object uri from &libref1a..items; /* %put Getting object uri from &libref1a..items; */
data _null_; data _null_;
length contenttype name $1000; length contenttype name $1000;
set &libref1a..items; set &libref1a..items;

View File

@@ -69,8 +69,7 @@
options noquotelenmax; options noquotelenmax;
%local base_uri; /* location of rest apis */ %local base_uri; /* location of rest apis */
%let base_uri=%mf_getplatform(VIYARESTAPI); %let base_uri=%mf_getplatform(VIYARESTAPI);
/* fetch the members of the folder to get the uri */
%put &sysmacroname: fetching details for &path ;
%local fname1; %local fname1;
%let fname1=%mf_getuniquefileref(); %let fname1=%mf_getuniquefileref();
proc http method='GET' out=&fname1 &oauth_bearer proc http method='GET' out=&fname1 &oauth_bearer
@@ -90,7 +89,7 @@ run;
) )
%end; %end;
%put &sysmacroname: grab the follow on link ; /* grab the follow on link */
%local libref1; %local libref1;
%let libref1=%mf_getuniquelibref(); %let libref1=%mf_getuniquelibref();
libname &libref1 JSON fileref=&fname1; libname &libref1 JSON fileref=&fname1;
@@ -108,13 +107,15 @@ proc http method='GET' out=&fname1a &oauth_bearer
headers "Authorization"="Bearer &&&access_token_var"; headers "Authorization"="Bearer &&&access_token_var";
%end; %end;
run; run;
%put &=SYS_PROCHTTP_STATUS_CODE; %if &SYS_PROCHTTP_STATUS_CODE ne 200 %then %do;
%put &=sysmacroname &=SYS_PROCHTTP_STATUS_CODE &=SYS_PROCHTTP_STATUS_PHRASE;
%end;
%local libref1a; %local libref1a;
%let libref1a=%mf_getuniquelibref(); %let libref1a=%mf_getuniquelibref();
libname &libref1a JSON fileref=&fname1a; libname &libref1a JSON fileref=&fname1a;
%local uri found; %local uri found;
%let found=0; %let found=0;
%put Getting object uri from &libref1a..items; /* %put Getting object uri from &libref1a..items; */
data _null_; data _null_;
length contenttype name $1000; length contenttype name $1000;
set &libref1a..items; set &libref1a..items;
@@ -140,7 +141,7 @@ run;
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE) ,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
) )
%end; %end;
%else %put &sysmacroname: &path/&name successfully deleted; %else %put &sysmacroname: &path/&name deleted;
/* clear refs */ /* clear refs */
filename &fname1 clear; filename &fname1 clear;

View File

@@ -1,6 +1,6 @@
/** /**
@file mv_deleteviyafolder.sas @file
@brief Creates a viya folder if that folder does not already exist @brief Deletes a viya folder
@details If not running in Studo 5 +, will expect an oauth token in a global @details If not running in Studo 5 +, will expect an oauth token in a global
macro variable (default ACCESS_TOKEN). macro variable (default ACCESS_TOKEN).

View File

@@ -126,7 +126,7 @@ data _null_;
uri=symget('uri'); uri=symget('uri');
if length(uri)<12 then do; if length(uri)<12 then do;
call symputx('errflg',1); call symputx('errflg',1);
call symputx('errmsg',"URI is invalid (too short) - '&uri'",'l'); call symputx('errmsg',"URI is too short - "!!uri,'l');
end; end;
if scan(uri,-1)='state' or scan(uri,1) ne 'jobExecution' then do; if scan(uri,-1)='state' or scan(uri,1) ne 'jobExecution' then do;
call symputx('errflg',1); call symputx('errflg',1);
@@ -191,7 +191,7 @@ data _null_;
uri=symget('loglocation'); uri=symget('loglocation');
if length(uri)<12 then do; if length(uri)<12 then do;
call symputx('errflg',1); call symputx('errflg',1);
call symputx('errmsg',"URI is invalid (too short) - '&uri'",'l'); call symputx('errmsg',"URI is too short - "!!uri,'l');
end; end;
else if (scan(uri,1,'/') ne 'compute' or scan(uri,2,'/') ne 'sessions') else if (scan(uri,1,'/') ne 'compute' or scan(uri,2,'/') ne 'sessions')
and (scan(uri,1,'/') ne 'files' or scan(uri,2,'/') ne 'files') and (scan(uri,1,'/') ne 'files' or scan(uri,2,'/') ne 'files')

View File

@@ -188,6 +188,8 @@
%if %mf_existvarList(&inds,FLOW_ID)=0 %then %do; %if %mf_existvarList(&inds,FLOW_ID)=0 %then %do;
retain FLOW_ID 0; retain FLOW_ID 0;
%end; %end;
/* https://github.com/sasjs/adapter/pull/845#issuecomment-2956589644 */
retain _omitSessionResults "false";
set &inds; set &inds;
&dbg. putlog (_all_)(=); &dbg. putlog (_all_)(=);
run; run;