@sasjs/utils 2.49.0 → 2.49.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fs/internal/helper.js +19 -24
- package/fs/internal/helper.js.map +1 -1
- package/macros/mf_abort.sas +27 -0
- package/macros/mf_dedup.sas +53 -0
- package/macros/mf_deletefile.sas +31 -0
- package/macros/mf_existds.sas +30 -0
- package/macros/mf_existfeature.sas +59 -0
- package/macros/mf_existfileref.sas +33 -0
- package/macros/mf_existfunction.sas +37 -0
- package/macros/mf_existvar.sas +39 -0
- package/macros/mf_existvarlist.sas +56 -0
- package/macros/mf_fmtdttm.sas +42 -0
- package/macros/mf_getapploc.sas +78 -0
- package/macros/mf_getattrc.sas +34 -0
- package/macros/mf_getattrn.sas +34 -0
- package/macros/mf_getengine.sas +54 -0
- package/macros/mf_getfilesize.sas +64 -0
- package/macros/mf_getfmtlist.sas +61 -0
- package/macros/mf_getfmtname.sas +44 -0
- package/macros/mf_getkeyvalue.sas +32 -0
- package/macros/mf_getplatform.sas +75 -0
- package/macros/mf_getquotedstr.sas +57 -0
- package/macros/mf_getschema.sas +43 -0
- package/macros/mf_getuniquefileref.sas +60 -0
- package/macros/mf_getuniquelibref.sas +57 -0
- package/macros/mf_getuniquename.sas +22 -0
- package/macros/mf_getuser.sas +44 -0
- package/macros/mf_getvalue.sas +36 -0
- package/macros/mf_getvarcount.sas +49 -0
- package/macros/mf_getvarformat.sas +72 -0
- package/macros/mf_getvarlen.sas +56 -0
- package/macros/mf_getvarlist.sas +74 -0
- package/macros/mf_getvarnum.sas +58 -0
- package/macros/mf_getvartype.sas +52 -0
- package/macros/mf_getxengine.sas +43 -0
- package/macros/mf_increment.sas +29 -0
- package/macros/mf_isblank.sas +27 -0
- package/macros/mf_isdir.sas +34 -0
- package/macros/mf_isint.sas +36 -0
- package/macros/mf_islibds.sas +40 -0
- package/macros/mf_loc.sas +29 -0
- package/macros/mf_mkdir.sas +67 -0
- package/macros/mf_mval.sas +19 -0
- package/macros/mf_nobs.sas +26 -0
- package/macros/mf_trimstr.sas +50 -0
- package/macros/mf_uid.sas +21 -0
- package/macros/mf_verifymacvars.sas +72 -0
- package/macros/mf_wordsinstr1andstr2.sas +53 -0
- package/macros/mf_wordsinstr1butnotstr2.sas +54 -0
- package/macros/mf_writefile.sas +67 -0
- package/macros/mp_abort.sas +301 -0
- package/macros/mp_appendfile.sas +57 -0
- package/macros/mp_applyformats.sas +181 -0
- package/macros/mp_assert.sas +56 -0
- package/macros/mp_assertcols.sas +145 -0
- package/macros/mp_assertcolvals.sas +168 -0
- package/macros/mp_assertdsobs.sas +121 -0
- package/macros/mp_assertscope.sas +147 -0
- package/macros/mp_base64copy.sas +117 -0
- package/macros/mp_binarycopy.sas +79 -0
- package/macros/mp_chop.sas +194 -0
- package/macros/mp_cleancsv.sas +78 -0
- package/macros/mp_cntlout.sas +85 -0
- package/macros/mp_copyfolder.sas +84 -0
- package/macros/mp_coretable.sas +73 -0
- package/macros/mp_createconstraints.sas +70 -0
- package/macros/mp_createwebservice.sas +32 -0
- package/macros/mp_csv2ds.sas +140 -0
- package/macros/mp_deleteconstraints.sas +52 -0
- package/macros/mp_deletefolder.sas +70 -0
- package/macros/mp_dictionary.sas +52 -0
- package/macros/mp_dirlist.sas +262 -0
- package/macros/mp_distinctfmtvalues.sas +50 -0
- package/macros/mp_dropmembers.sas +46 -0
- package/macros/mp_ds2cards.sas +291 -0
- package/macros/mp_ds2csv.sas +212 -0
- package/macros/mp_ds2ddl.sas +30 -0
- package/macros/mp_ds2fmtds.sas +105 -0
- package/macros/mp_ds2inserts.sas +180 -0
- package/macros/mp_ds2md.sas +103 -0
- package/macros/mp_ds2squeeze.sas +120 -0
- package/macros/mp_dsmeta.sas +110 -0
- package/macros/mp_filtercheck.sas +251 -0
- package/macros/mp_filtergenerate.sas +105 -0
- package/macros/mp_filterstore.sas +254 -0
- package/macros/mp_filtervalidate.sas +105 -0
- package/macros/mp_getcols.sas +67 -0
- package/macros/mp_getconstraints.sas +115 -0
- package/macros/mp_getdbml.sas +335 -0
- package/macros/mp_getddl.sas +400 -0
- package/macros/mp_getformats.sas +124 -0
- package/macros/mp_getmaxvarlengths.sas +130 -0
- package/macros/mp_getpk.sas +281 -0
- package/macros/mp_gitadd.sas +45 -0
- package/macros/mp_gitreleaseinfo.sas +74 -0
- package/macros/mp_gitstatus.sas +67 -0
- package/macros/mp_gsubfile.sas +58 -0
- package/macros/mp_guesspk.sas +332 -0
- package/macros/mp_hashdataset.sas +91 -0
- package/macros/mp_hashdirectory.sas +164 -0
- package/macros/mp_include.sas +106 -0
- package/macros/mp_init.sas +76 -0
- package/macros/mp_jsonout.sas +406 -0
- package/macros/mp_lib2cards.sas +78 -0
- package/macros/mp_lib2inserts.sas +77 -0
- package/macros/mp_loadformat.sas +303 -0
- package/macros/mp_lockanytable.sas +243 -0
- package/macros/mp_lockfilecheck.sas +103 -0
- package/macros/mp_makedata.sas +107 -0
- package/macros/mp_md5.sas +58 -0
- package/macros/mp_perflog.sas +43 -0
- package/macros/mp_prevobs.sas +88 -0
- package/macros/mp_recursivejoin.sas +90 -0
- package/macros/mp_replace.sas +151 -0
- package/macros/mp_reseterror.sas +27 -0
- package/macros/mp_resetoption.sas +39 -0
- package/macros/mp_retainedkey.sas +247 -0
- package/macros/mp_runddl.sas +49 -0
- package/macros/mp_searchcols.sas +103 -0
- package/macros/mp_searchdata.sas +131 -0
- package/macros/mp_setkeyvalue.sas +55 -0
- package/macros/mp_sortinplace.sas +122 -0
- package/macros/mp_stackdiffs.sas +592 -0
- package/macros/mp_storediffs.sas +230 -0
- package/macros/mp_stprequests.sas +74 -0
- package/macros/mp_streamfile.sas +212 -0
- package/macros/mp_testjob.sas +92 -0
- package/macros/mp_testservice.sas +39 -0
- package/macros/mp_testwritespeedlibrary.sas +59 -0
- package/macros/mp_tree.sas +71 -0
- package/macros/mp_unzip.sas +90 -0
- package/macros/mp_updatevarlength.sas +93 -0
- package/macros/mp_validatecol.sas +97 -0
- package/macros/mp_wait4file.sas +35 -0
- package/macros/mp_webin.sas +59 -0
- package/macros/mp_zip.sas +85 -0
- package/package.json +5 -2
- package/scripts/copySASjsCore.ts +36 -0
- package/utils/index.d.ts +1 -2
- package/utils/index.js +2 -3
- package/utils/index.js.map +1 -1
- package/utils/utils.d.ts +1 -0
- package/utils/utils.js +7 -1
- package/utils/utils.js.map +1 -1
- package/utils/getNodeModulePath.d.ts +0 -2
- package/utils/getNodeModulePath.js +0 -83
- package/utils/getNodeModulePath.js.map +0 -1
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Recursively scans a directory tree to get all subfolders and content
|
|
4
|
+
@details
|
|
5
|
+
Usage:
|
|
6
|
+
|
|
7
|
+
%mp_tree(dir=/tmp, outds=work.tree)
|
|
8
|
+
|
|
9
|
+
Credits:
|
|
10
|
+
|
|
11
|
+
Roger Deangelis:
|
|
12
|
+
https://communities.sas.com/t5/SAS-Programming/listing-all-files-within-a-directory-and-subdirectories/m-p/332616/highlight/true#M74887
|
|
13
|
+
|
|
14
|
+
Tom:
|
|
15
|
+
https://communities.sas.com/t5/SAS-Programming/listing-all-files-of-all-types-from-all-subdirectories/m-p/334113/highlight/true#M75419
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@param dir= Directory to be scanned (default=/tmp)
|
|
19
|
+
@param outds= Dataset to create (default=work.mp_tree)
|
|
20
|
+
|
|
21
|
+
@returns outds contains the following variables:
|
|
22
|
+
|
|
23
|
+
- `dir`: a flag (1/0) to say whether it is a directory or not. This is not
|
|
24
|
+
reliable - folders that you do not have permission to open will be flagged
|
|
25
|
+
as directories.
|
|
26
|
+
- `ext`: file extension
|
|
27
|
+
- `filename`: file name
|
|
28
|
+
- `dirname`: directory name
|
|
29
|
+
- `fullpath`: directory + file name
|
|
30
|
+
|
|
31
|
+
@version 9.2
|
|
32
|
+
**/
|
|
33
|
+
|
|
34
|
+
%macro mp_tree(dir=/tmp
|
|
35
|
+
,outds=work.mp_tree
|
|
36
|
+
)/*/STORE SOURCE*/;
|
|
37
|
+
|
|
38
|
+
data &outds ;
|
|
39
|
+
length dir 8 ext filename dirname $256 fullpath $512 ;
|
|
40
|
+
call missing(of _all_);
|
|
41
|
+
fullpath = "&dir";
|
|
42
|
+
run;
|
|
43
|
+
|
|
44
|
+
%local sep;
|
|
45
|
+
%if &sysscp=WIN or &SYSSCP eq DNTHOST %then %let sep=\;
|
|
46
|
+
%else %let sep=/;
|
|
47
|
+
|
|
48
|
+
data &outds ;
|
|
49
|
+
modify &outds ;
|
|
50
|
+
retain sep "&sep";
|
|
51
|
+
rc=filename('tmp',fullpath);
|
|
52
|
+
dir_id=dopen('tmp');
|
|
53
|
+
dir = (dir_id ne 0) ;
|
|
54
|
+
if dir then dirname=fullpath;
|
|
55
|
+
else do;
|
|
56
|
+
filename=scan(fullpath,-1,sep) ;
|
|
57
|
+
dirname =substrn(fullpath,1,length(fullpath)-length(filename));
|
|
58
|
+
if index(filename,'.')>1 then ext=scan(filename,-1,'.');
|
|
59
|
+
end;
|
|
60
|
+
replace;
|
|
61
|
+
if dir then do;
|
|
62
|
+
do i=1 to dnum(dir_id);
|
|
63
|
+
fullpath=cats(dirname,sep,dread(dir_id,i));
|
|
64
|
+
output;
|
|
65
|
+
end;
|
|
66
|
+
rc=dclose(dir_id);
|
|
67
|
+
end;
|
|
68
|
+
rc=filename('tmp');
|
|
69
|
+
run;
|
|
70
|
+
|
|
71
|
+
%mend mp_tree;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file mp_unzip.sas
|
|
3
|
+
@brief Unzips a zip file
|
|
4
|
+
@details Opens the zip file and copies all the contents to another directory.
|
|
5
|
+
It is not possible to retain permissions / timestamps, also the BOF marker
|
|
6
|
+
is lost so it cannot extract binary files.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
|
|
10
|
+
filename mc url
|
|
11
|
+
"https://raw.githubusercontent.com/sasjs/core/main/all.sas";
|
|
12
|
+
%inc mc;
|
|
13
|
+
|
|
14
|
+
%mp_unzip(ziploc="/some/file.zip",outdir=/some/folder)
|
|
15
|
+
|
|
16
|
+
More info: https://blogs.sas.com/content/sasdummy/2015/05/11/using-filename-zip-to-unzip-and-read-data-files-in-sas/
|
|
17
|
+
|
|
18
|
+
@param ziploc= Fileref or quoted full path to zip file ("/path/to/file.zip")
|
|
19
|
+
@param outdir= (%sysfunc(pathname(work))) Directory in which to write the
|
|
20
|
+
outputs (created if non existant)
|
|
21
|
+
|
|
22
|
+
<h4> SAS Macros </h4>
|
|
23
|
+
@li mf_mkdir.sas
|
|
24
|
+
@li mf_getuniquefileref.sas
|
|
25
|
+
@li mp_binarycopy.sas
|
|
26
|
+
|
|
27
|
+
@version 9.4
|
|
28
|
+
@author Allan Bowe
|
|
29
|
+
@source https://github.com/sasjs/core
|
|
30
|
+
|
|
31
|
+
**/
|
|
32
|
+
|
|
33
|
+
%macro mp_unzip(
|
|
34
|
+
ziploc=
|
|
35
|
+
,outdir=%sysfunc(pathname(work))
|
|
36
|
+
)/*/STORE SOURCE*/;
|
|
37
|
+
|
|
38
|
+
%local f1 f2 ;
|
|
39
|
+
%let f1=%mf_getuniquefileref();
|
|
40
|
+
%let f2=%mf_getuniquefileref();
|
|
41
|
+
|
|
42
|
+
/* Macro variable &datazip would be read from the file */
|
|
43
|
+
filename &f1 ZIP &ziploc;
|
|
44
|
+
|
|
45
|
+
/* create target folder */
|
|
46
|
+
%mf_mkdir(&outdir)
|
|
47
|
+
|
|
48
|
+
/* Read the "members" (files) from the ZIP file */
|
|
49
|
+
data _data_(keep=memname isFolder);
|
|
50
|
+
length memname $200 isFolder 8;
|
|
51
|
+
fid=dopen("&f1");
|
|
52
|
+
if fid=0 then stop;
|
|
53
|
+
memcount=dnum(fid);
|
|
54
|
+
do i=1 to memcount;
|
|
55
|
+
memname=dread(fid,i);
|
|
56
|
+
/* check for trailing / in folder name */
|
|
57
|
+
isFolder = (first(reverse(trim(memname)))='/');
|
|
58
|
+
output;
|
|
59
|
+
end;
|
|
60
|
+
rc=dclose(fid);
|
|
61
|
+
run;
|
|
62
|
+
|
|
63
|
+
filename &f2 temp;
|
|
64
|
+
|
|
65
|
+
/* loop through each entry and either create the subfolder or extract member */
|
|
66
|
+
data _null_;
|
|
67
|
+
set &syslast;
|
|
68
|
+
file &f2;
|
|
69
|
+
if isFolder then call execute('%mf_mkdir(&outdir/'!!memname!!')');
|
|
70
|
+
else do;
|
|
71
|
+
qname=quote(cats("&outdir/",memname));
|
|
72
|
+
bname=cats('(',memname,')');
|
|
73
|
+
put '/* hat tip: "data _null_" on SAS-L */';
|
|
74
|
+
put 'data _null_;';
|
|
75
|
+
put ' infile &f1 ' bname ' lrecl=256 recfm=F length=length eof=eof unbuf;';
|
|
76
|
+
put ' file ' qname ' lrecl=256 recfm=N;';
|
|
77
|
+
put ' input;';
|
|
78
|
+
put ' put _infile_ $varying256. length;';
|
|
79
|
+
put ' return;';
|
|
80
|
+
put 'eof:';
|
|
81
|
+
put ' stop;';
|
|
82
|
+
put 'run;';
|
|
83
|
+
end;
|
|
84
|
+
run;
|
|
85
|
+
|
|
86
|
+
%inc &f2/source2;
|
|
87
|
+
|
|
88
|
+
filename &f2 clear;
|
|
89
|
+
|
|
90
|
+
%mend mp_unzip;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file mp_updatevarlength.sas
|
|
3
|
+
@brief Change the length of a variable
|
|
4
|
+
@details The library is assumed to be assigned. Simple character updates
|
|
5
|
+
currently supported, numerics are more complicated and will follow.
|
|
6
|
+
|
|
7
|
+
data example;
|
|
8
|
+
a='1';
|
|
9
|
+
b='12';
|
|
10
|
+
c='123';
|
|
11
|
+
run;
|
|
12
|
+
%mp_updatevarlength(example,a,3)
|
|
13
|
+
%mp_updatevarlength(example,c,1)
|
|
14
|
+
proc sql;
|
|
15
|
+
describe table example;
|
|
16
|
+
|
|
17
|
+
@param libds the library.dataset to be modified
|
|
18
|
+
@param var The variable to modify
|
|
19
|
+
@param len The new length to apply
|
|
20
|
+
|
|
21
|
+
<h4> SAS Macros </h4>
|
|
22
|
+
@li mf_existds.sas
|
|
23
|
+
@li mp_abort.sas
|
|
24
|
+
@li mf_existvar.sas
|
|
25
|
+
@li mf_getvarlen.sas
|
|
26
|
+
@li mf_getvartype.sas
|
|
27
|
+
@li mf_getnobs.sas
|
|
28
|
+
@li mp_createconstraints.sas
|
|
29
|
+
@li mp_getconstraints.sas
|
|
30
|
+
@li mp_deleteconstraints.sas
|
|
31
|
+
|
|
32
|
+
@version 9.2
|
|
33
|
+
@author Allan Bowe
|
|
34
|
+
|
|
35
|
+
**/
|
|
36
|
+
|
|
37
|
+
%macro mp_updatevarlength(libds,var,len
|
|
38
|
+
)/*/STORE SOURCE*/;
|
|
39
|
+
|
|
40
|
+
%if %index(&libds,.)=0 %then %let libds=WORK.&libds;
|
|
41
|
+
|
|
42
|
+
%mp_abort(iftrue=(%mf_existds(&libds)=0)
|
|
43
|
+
,mac=&sysmacroname
|
|
44
|
+
,msg=%str(Table &libds not found!)
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
%mp_abort(iftrue=(%mf_existvar(&libds,&var)=0)
|
|
48
|
+
,mac=&sysmacroname
|
|
49
|
+
,msg=%str(Variable &var not found on &libds!)
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
/* not possible to in-place modify a numeric length, to add later */
|
|
53
|
+
%mp_abort(iftrue=(%mf_getvartype(&libds,&var)=0)
|
|
54
|
+
,mac=&sysmacroname
|
|
55
|
+
,msg=%str(Only character resizings are currently supported)
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
%local oldlen;
|
|
59
|
+
%let oldlen=%mf_getvarlen(&libds,&var);
|
|
60
|
+
%if &oldlen=&len %then %do;
|
|
61
|
+
%put &sysmacroname: Old and new lengths (&len) match!;
|
|
62
|
+
%return;
|
|
63
|
+
%end;
|
|
64
|
+
|
|
65
|
+
%let libds=%upcase(&libds);
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
data;run;
|
|
69
|
+
%local dsconst; %let dsconst=&syslast;
|
|
70
|
+
%mp_getconstraints(lib=%scan(&libds,1,.),ds=%scan(&libds,2,.),outds=&dsconst)
|
|
71
|
+
|
|
72
|
+
%mp_abort(iftrue=(&syscc ne 0)
|
|
73
|
+
,mac=&sysmacroname
|
|
74
|
+
,msg=%str(syscc=&syscc)
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
%if %mf_getnobs(&dscont)=0 %then %do;
|
|
78
|
+
/* must use SQL as proc datasets does not support length changes */
|
|
79
|
+
proc sql;
|
|
80
|
+
alter table &libds modify &var char(&len);
|
|
81
|
+
%return;
|
|
82
|
+
%end;
|
|
83
|
+
|
|
84
|
+
/* we have constraints! */
|
|
85
|
+
|
|
86
|
+
%mp_deleteconstraints(inds=&dsconst,outds=&dsconst._dropd,execute=YES)
|
|
87
|
+
|
|
88
|
+
proc sql;
|
|
89
|
+
alter table &libds modify &var char(&len);
|
|
90
|
+
|
|
91
|
+
%mp_createconstraints(inds=&dsconst,outds=&dsconst._addd,execute=YES)
|
|
92
|
+
|
|
93
|
+
%mend mp_updatevarlength;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Used to validate variables in a dataset
|
|
4
|
+
@details Useful when sanitising inputs, to ensure that they arrive with a
|
|
5
|
+
certain pattern.
|
|
6
|
+
Usage:
|
|
7
|
+
|
|
8
|
+
data test;
|
|
9
|
+
infile datalines4 dsd;
|
|
10
|
+
input;
|
|
11
|
+
libds=_infile_;
|
|
12
|
+
%mp_validatecol(libds,LIBDS,is_libds)
|
|
13
|
+
datalines4;
|
|
14
|
+
some.libname
|
|
15
|
+
!lib.blah
|
|
16
|
+
%abort
|
|
17
|
+
definite.ok
|
|
18
|
+
not.ok!
|
|
19
|
+
nineletrs._
|
|
20
|
+
;;;;
|
|
21
|
+
run;
|
|
22
|
+
|
|
23
|
+
For more examples, see mp_validatecol.test.sas
|
|
24
|
+
|
|
25
|
+
Tip - when contributing, use https://regex101.com to test the regex validity!
|
|
26
|
+
|
|
27
|
+
@param [in] incol The column to be validated
|
|
28
|
+
@param [in] rule The rule to apply. Current rules:
|
|
29
|
+
@li ISINT - checks if the variable is an integer
|
|
30
|
+
@li ISNUM - checks if the variable is numeric
|
|
31
|
+
@li LIBDS - matches LIBREF.DATASET format
|
|
32
|
+
@li FORMAT - checks if the provided format is syntactically valid
|
|
33
|
+
@param [out] outcol The variable to create, with the results of the match
|
|
34
|
+
|
|
35
|
+
<h4> SAS Macros </h4>
|
|
36
|
+
@li mf_getuniquename.sas
|
|
37
|
+
|
|
38
|
+
<h4> Related Macros </h4>
|
|
39
|
+
@li mp_validatecol.test.sas
|
|
40
|
+
|
|
41
|
+
@version 9.3
|
|
42
|
+
**/
|
|
43
|
+
|
|
44
|
+
%macro mp_validatecol(incol,rule,outcol);
|
|
45
|
+
|
|
46
|
+
/* tempcol is given a unique name with every invocation */
|
|
47
|
+
%local tempcol;
|
|
48
|
+
%let tempcol=%mf_getuniquename();
|
|
49
|
+
|
|
50
|
+
%if &rule=ISINT %then %do;
|
|
51
|
+
&outcol=0;
|
|
52
|
+
if not missing(&incol) then do;
|
|
53
|
+
&tempcol=input(&incol,?? best32.);
|
|
54
|
+
if not missing(&tempcol) then if mod(&tempcol,1)=0 then &outcol=1;
|
|
55
|
+
end;
|
|
56
|
+
drop &tempcol;
|
|
57
|
+
%end;
|
|
58
|
+
%else %if &rule=ISNUM %then %do;
|
|
59
|
+
/*
|
|
60
|
+
credit SØREN LASSEN
|
|
61
|
+
https://sasmacro.blogspot.com/2009/06/welcome-isnum-macro.html
|
|
62
|
+
*/
|
|
63
|
+
&tempcol=input(&incol,?? best32.);
|
|
64
|
+
if missing(&tempcol) then &outcol=0;
|
|
65
|
+
else &outcol=1;
|
|
66
|
+
drop &tempcol;
|
|
67
|
+
%end;
|
|
68
|
+
%else %if &rule=LIBDS %then %do;
|
|
69
|
+
/* match libref.dataset */
|
|
70
|
+
if _n_=1 then do;
|
|
71
|
+
retain &tempcol;
|
|
72
|
+
&tempcol=prxparse('/^[_a-z]\w{0,7}\.[_a-z]\w{0,31}$/i');
|
|
73
|
+
if missing(&tempcol) then do;
|
|
74
|
+
putlog "%str(ERR)OR: Invalid expression for LIBDS";
|
|
75
|
+
stop;
|
|
76
|
+
end;
|
|
77
|
+
drop &tempcol;
|
|
78
|
+
end;
|
|
79
|
+
if prxmatch(&tempcol, trim(&incol)) then &outcol=1;
|
|
80
|
+
else &outcol=0;
|
|
81
|
+
%end;
|
|
82
|
+
%else %if &rule=FORMAT %then %do;
|
|
83
|
+
/* match valid format - regex could probably be improved */
|
|
84
|
+
if _n_=1 then do;
|
|
85
|
+
retain &tempcol;
|
|
86
|
+
&tempcol=prxparse('/^[_a-z\$]\w{0,31}\.[0-9]*$/i');
|
|
87
|
+
if missing(&tempcol) then do;
|
|
88
|
+
putlog "%str(ERR)OR: Invalid expression for FORMAT";
|
|
89
|
+
stop;
|
|
90
|
+
end;
|
|
91
|
+
drop &tempcol;
|
|
92
|
+
end;
|
|
93
|
+
if prxmatch(&tempcol, trim(&incol)) then &outcol=1;
|
|
94
|
+
else &outcol=0;
|
|
95
|
+
%end;
|
|
96
|
+
|
|
97
|
+
%mend mp_validatecol;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Wait until a file arrives before continuing execution
|
|
4
|
+
@details Loops with a `sleep()` command until a file arrives or the max wait
|
|
5
|
+
period expires.
|
|
6
|
+
|
|
7
|
+
Example: Wait 3 minutes OR for /tmp/flag.txt to appear
|
|
8
|
+
|
|
9
|
+
%mp_wait4file(/tmp/flag.txt , maxwait=60*3)
|
|
10
|
+
|
|
11
|
+
@param [in] file The file to wait for. Must be provided.
|
|
12
|
+
@param [in] maxwait= (0) Number of seconds to wait. If set to zero, will
|
|
13
|
+
loop indefinitely (to a maximum of 46 days, per SAS [documentation](
|
|
14
|
+
https://support.sas.com/documentation/cdl/en/lrdict/64316/HTML/default/viewer.htm#a001418809.htm
|
|
15
|
+
)). Otherwise, execution will proceed upon sleep expiry.
|
|
16
|
+
@param [in] interval= (1) The wait period between sleeps, in seconds
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
**/
|
|
20
|
+
|
|
21
|
+
%macro mp_wait4file(file, maxwait=0, interval=1);
|
|
22
|
+
|
|
23
|
+
%if %str(&file)=%str() %then %do;
|
|
24
|
+
%put %str(ERR)OR: file not provided;
|
|
25
|
+
%end;
|
|
26
|
+
|
|
27
|
+
data _null_;
|
|
28
|
+
maxwait=&maxwait;
|
|
29
|
+
if maxwait=0 then maxwait=60*60*24*46;
|
|
30
|
+
do until (fileexist("&file") or slept>maxwait );
|
|
31
|
+
slept=sum(slept,sleep(&interval,1));
|
|
32
|
+
end;
|
|
33
|
+
run;
|
|
34
|
+
|
|
35
|
+
%mend mp_wait4file;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Fix the `_WEBIN` variables provided to SAS web services
|
|
4
|
+
@details When uploading files to SAS Stored Processes or Viya Jobs a number
|
|
5
|
+
of global macro variables are automatically created - however there are some
|
|
6
|
+
differences in behaviour both between SAS 9 and Viya, and also between a
|
|
7
|
+
single file upload and a multi-file upload.
|
|
8
|
+
|
|
9
|
+
This macro "straightens" up the global macro variables to make it easier /
|
|
10
|
+
simpler to write code that works in both environments and with a variable
|
|
11
|
+
number of file inputs.
|
|
12
|
+
|
|
13
|
+
After running this macro, the following global variables will *always* exist:
|
|
14
|
+
@li `_WEBIN_FILE_COUNT`
|
|
15
|
+
@li `_WEBIN_FILENAME1`
|
|
16
|
+
@li `_WEBIN_FILEREF1`
|
|
17
|
+
@li `_WEBIN_NAME1`
|
|
18
|
+
|
|
19
|
+
Usage:
|
|
20
|
+
|
|
21
|
+
%mp_webin()
|
|
22
|
+
|
|
23
|
+
This was created as a macro procedure (over a macro function) as it will also
|
|
24
|
+
use the filename statement in Viya environments (where `_webin_fileuri` is
|
|
25
|
+
provided).
|
|
26
|
+
|
|
27
|
+
<h4> SAS Macros </h4>
|
|
28
|
+
@li mf_getplatform.sas
|
|
29
|
+
@li mf_getuniquefileref.sas
|
|
30
|
+
|
|
31
|
+
**/
|
|
32
|
+
|
|
33
|
+
%macro mp_webin();
|
|
34
|
+
|
|
35
|
+
/* prepare global variables */
|
|
36
|
+
%global _webin_file_count
|
|
37
|
+
_webin_filename _webin_filename1
|
|
38
|
+
_webin_fileref _webin_fileref1
|
|
39
|
+
_webin_fileuri _webin_fileuri1
|
|
40
|
+
_webin_name _webin_name1
|
|
41
|
+
;
|
|
42
|
+
|
|
43
|
+
/* create initial versions */
|
|
44
|
+
%let _webin_file_count=%eval(&_webin_file_count+0);
|
|
45
|
+
%let _webin_filename1=%sysfunc(coalescec(&_webin_filename1,&_webin_filename));
|
|
46
|
+
%let _webin_fileref1=%sysfunc(coalescec(&_webin_fileref1,&_webin_fileref));
|
|
47
|
+
%let _webin_fileuri1=%sysfunc(coalescec(&_webin_fileuri1,&_webin_fileuri));
|
|
48
|
+
%let _webin_name1=%sysfunc(coalescec(&_webin_name1,&_webin_name));
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
/* If Viya, create temporary fileref(s) */
|
|
52
|
+
%local i;
|
|
53
|
+
%if %mf_getplatform()=SASVIYA %then %do i=1 %to &_webin_file_count;
|
|
54
|
+
%let _webin_fileref&i=%mf_getuniquefileref();
|
|
55
|
+
filename &&_webin_fileref&i filesrvc "&&_webin_fileuri&i";
|
|
56
|
+
%end;
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
%mend mp_webin;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Creates a zip file
|
|
4
|
+
@details For DIRECTORY usage, will ignore subfolders. For DATASET usage,
|
|
5
|
+
provide a column that contains the full file path to each file to be zipped.
|
|
6
|
+
|
|
7
|
+
%mp_zip(in=myzips,type=directory,outname=myDir)
|
|
8
|
+
%mp_zip(in=/my/file/path.txt,type=FILE,outname=myFile)
|
|
9
|
+
%mp_zip(in=SOMEDS,incol=FPATH,type=DATASET,outname=myFile)
|
|
10
|
+
|
|
11
|
+
If you are sending zipped output to the _webout destination as part of an STP
|
|
12
|
+
be sure that _debug is not set (else the SPWA will send non zipped content
|
|
13
|
+
as well).
|
|
14
|
+
|
|
15
|
+
<h4> SAS Macros </h4>
|
|
16
|
+
@li mp_dirlist.sas
|
|
17
|
+
|
|
18
|
+
@param in= unquoted filepath, dataset of files or directory to zip
|
|
19
|
+
@param type= (FILE) Valid values:
|
|
20
|
+
@li FILE - /full/path/and/filename.extension to a particular file
|
|
21
|
+
@li DATASET - a dataset containing a list of files to zip (see `incol`)
|
|
22
|
+
@li DIRECTORY - a directory to zip
|
|
23
|
+
@param outname= (FILE) Output file to create, _without_ .zip extension
|
|
24
|
+
@param outpath= (%sysfunc(pathname(WORK))) Parent folder for output zip file
|
|
25
|
+
@param incol= if DATASET input, say which column contains the filepath
|
|
26
|
+
|
|
27
|
+
<h4> Related Macros </h4>
|
|
28
|
+
@li mp_unzip.sas
|
|
29
|
+
@li mp_zip.test.sas
|
|
30
|
+
|
|
31
|
+
@version 9.2
|
|
32
|
+
@author Allan Bowe
|
|
33
|
+
@source https://github.com/sasjs/core
|
|
34
|
+
|
|
35
|
+
**/
|
|
36
|
+
|
|
37
|
+
%macro mp_zip(
|
|
38
|
+
in=
|
|
39
|
+
,type=FILE
|
|
40
|
+
,outname=FILE
|
|
41
|
+
,outpath=%sysfunc(pathname(WORK))
|
|
42
|
+
,incol=
|
|
43
|
+
,debug=NO
|
|
44
|
+
)/*/STORE SOURCE*/;
|
|
45
|
+
|
|
46
|
+
%let type=%upcase(&type);
|
|
47
|
+
%local ds;
|
|
48
|
+
|
|
49
|
+
ods package open nopf;
|
|
50
|
+
|
|
51
|
+
%if &type=FILE %then %do;
|
|
52
|
+
ods package add file="&in" mimetype="application/x-compress";
|
|
53
|
+
%end;
|
|
54
|
+
%else %if &type=DIRECTORY %then %do;
|
|
55
|
+
%mp_dirlist(path=&in,outds=_data_)
|
|
56
|
+
%let ds=&syslast;
|
|
57
|
+
data _null_;
|
|
58
|
+
set &ds;
|
|
59
|
+
length __command $4000;
|
|
60
|
+
if file_or_folder='file';
|
|
61
|
+
__command=cats('ods package add file="',filepath
|
|
62
|
+
,'" mimetype="application/x-compress";');
|
|
63
|
+
call execute(__command);
|
|
64
|
+
run;
|
|
65
|
+
/* tidy up */
|
|
66
|
+
%if &debug=NO %then %do;
|
|
67
|
+
proc sql; drop table &ds;quit;
|
|
68
|
+
%end;
|
|
69
|
+
%end;
|
|
70
|
+
%else %if &type=DATASET %then %do;
|
|
71
|
+
data _null_;
|
|
72
|
+
set ∈
|
|
73
|
+
length __command $4000;
|
|
74
|
+
__command=cats('ods package add file="',&incol
|
|
75
|
+
,'" mimetype="application/x-compress";');
|
|
76
|
+
call execute(__command);
|
|
77
|
+
run;
|
|
78
|
+
%end;
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
ods package publish archive properties
|
|
82
|
+
(archive_name="&outname..zip" archive_path="&outpath");
|
|
83
|
+
ods package close;
|
|
84
|
+
|
|
85
|
+
%mend mp_zip;
|
package/package.json
CHANGED
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
"preinstall": "npm run nodeVersionMessage",
|
|
16
16
|
"prebuild": "npm run nodeVersionMessage",
|
|
17
17
|
"build": "rimraf build && tsc",
|
|
18
|
+
"postbuild": "npm run copy:macros",
|
|
19
|
+
"copy:macros": "ts-node ./scripts/copySASjsCore.ts",
|
|
18
20
|
"prepublishOnly": "cp -r ./build/* . && rm -rf ./build && rm -rf ./src && rm jest.config.js && rm tsconfig.json",
|
|
19
21
|
"postpublish": "git clean -fd",
|
|
20
22
|
"package:lib": "npm run build && cp ./package.json build && cp README.md build && cd build && npm version \"5.0.0\" && npm pack",
|
|
@@ -34,7 +36,7 @@
|
|
|
34
36
|
},
|
|
35
37
|
"homepage": "https://github.com/sasjs/utils#readme",
|
|
36
38
|
"devDependencies": {
|
|
37
|
-
"@sasjs/core": "4.
|
|
39
|
+
"@sasjs/core": "^4.43.1",
|
|
38
40
|
"@types/cli-table": "0.3.0",
|
|
39
41
|
"@types/find": "0.2.1",
|
|
40
42
|
"@types/jest": "27.4.0",
|
|
@@ -45,6 +47,7 @@
|
|
|
45
47
|
"jest-extended": "1.1.0",
|
|
46
48
|
"ts-jest": "27.1.3",
|
|
47
49
|
"ts-loader": "9.2.6",
|
|
50
|
+
"ts-node": "10.9.1",
|
|
48
51
|
"typescript": "4.5.4"
|
|
49
52
|
},
|
|
50
53
|
"dependencies": {
|
|
@@ -61,5 +64,5 @@
|
|
|
61
64
|
"rimraf": "3.0.2",
|
|
62
65
|
"valid-url": "1.0.9"
|
|
63
66
|
},
|
|
64
|
-
"version": "2.49.
|
|
67
|
+
"version": "2.49.2"
|
|
65
68
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import { asyncForEach, copy, createFolder, deleteFolder } from '../src'
|
|
3
|
+
|
|
4
|
+
const root = path.join(__dirname, '..')
|
|
5
|
+
|
|
6
|
+
const sasjsCorePath = path.join(root, 'node_modules', '@sasjs', 'core')
|
|
7
|
+
|
|
8
|
+
export const macrosPath = path.join(root, 'build', 'macros')
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* We need @sasjs/core macros at runtime for compilation of programs, but we
|
|
12
|
+
* can't directly import them like a javascript file.
|
|
13
|
+
* So, we have to read the macro files directly. For this we can't use the
|
|
14
|
+
* node_modules folder, as it will not always be available after the library is
|
|
15
|
+
* built / packed (eg in the VS Code extension)
|
|
16
|
+
* Therefore, we copy the macros to a folder in the post build step, so that we
|
|
17
|
+
* can read them at runtime.
|
|
18
|
+
*
|
|
19
|
+
* These macros are / will be used by the sasjs fs command / fs sync utilites
|
|
20
|
+
* as well as for general compilation of SAS Jobs, Services, and Tests.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
export const copySASjsCore = async () => {
|
|
24
|
+
await deleteFolder(macrosPath)
|
|
25
|
+
await createFolder(macrosPath)
|
|
26
|
+
|
|
27
|
+
const foldersToCopy = ['base']
|
|
28
|
+
|
|
29
|
+
await asyncForEach(foldersToCopy, async (coreSubFolder) => {
|
|
30
|
+
const coreSubFolderPath = path.join(sasjsCorePath, coreSubFolder)
|
|
31
|
+
|
|
32
|
+
await copy(coreSubFolderPath, macrosPath)
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
copySASjsCore()
|
package/utils/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { uuidv4, asyncForEach, uniqArray, isWindows, isLinux, escapeWinSlashes } from './utils';
|
|
1
|
+
export { uuidv4, asyncForEach, uniqArray, isWindows, isLinux, escapeWinSlashes, getMacrosPath } from './utils';
|
|
2
2
|
export * from './fileTree';
|
|
3
3
|
export { urlOrigin } from './url';
|
|
4
4
|
export { encodeToBase64, decodeFromBase64 } from './base64';
|
|
@@ -6,4 +6,3 @@ export { getExecutorPath } from './executor';
|
|
|
6
6
|
export { bytesToSize } from './bytesToSize';
|
|
7
7
|
export { diff } from './diff';
|
|
8
8
|
export { chunk } from './chunk';
|
|
9
|
-
export { getNodeModulePath } from './getNodeModulePath';
|
package/utils/index.js
CHANGED
|
@@ -10,7 +10,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
10
10
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
11
|
};
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
exports.
|
|
13
|
+
exports.chunk = exports.diff = exports.bytesToSize = exports.getExecutorPath = exports.decodeFromBase64 = exports.encodeToBase64 = exports.urlOrigin = exports.getMacrosPath = exports.escapeWinSlashes = exports.isLinux = exports.isWindows = exports.uniqArray = exports.asyncForEach = exports.uuidv4 = void 0;
|
|
14
14
|
var utils_1 = require("./utils");
|
|
15
15
|
Object.defineProperty(exports, "uuidv4", { enumerable: true, get: function () { return utils_1.uuidv4; } });
|
|
16
16
|
Object.defineProperty(exports, "asyncForEach", { enumerable: true, get: function () { return utils_1.asyncForEach; } });
|
|
@@ -18,6 +18,7 @@ Object.defineProperty(exports, "uniqArray", { enumerable: true, get: function ()
|
|
|
18
18
|
Object.defineProperty(exports, "isWindows", { enumerable: true, get: function () { return utils_1.isWindows; } });
|
|
19
19
|
Object.defineProperty(exports, "isLinux", { enumerable: true, get: function () { return utils_1.isLinux; } });
|
|
20
20
|
Object.defineProperty(exports, "escapeWinSlashes", { enumerable: true, get: function () { return utils_1.escapeWinSlashes; } });
|
|
21
|
+
Object.defineProperty(exports, "getMacrosPath", { enumerable: true, get: function () { return utils_1.getMacrosPath; } });
|
|
21
22
|
__exportStar(require("./fileTree"), exports);
|
|
22
23
|
var url_1 = require("./url");
|
|
23
24
|
Object.defineProperty(exports, "urlOrigin", { enumerable: true, get: function () { return url_1.urlOrigin; } });
|
|
@@ -32,6 +33,4 @@ var diff_1 = require("./diff");
|
|
|
32
33
|
Object.defineProperty(exports, "diff", { enumerable: true, get: function () { return diff_1.diff; } });
|
|
33
34
|
var chunk_1 = require("./chunk");
|
|
34
35
|
Object.defineProperty(exports, "chunk", { enumerable: true, get: function () { return chunk_1.chunk; } });
|
|
35
|
-
var getNodeModulePath_1 = require("./getNodeModulePath");
|
|
36
|
-
Object.defineProperty(exports, "getNodeModulePath", { enumerable: true, get: function () { return getNodeModulePath_1.getNodeModulePath; } });
|
|
37
36
|
//# sourceMappingURL=index.js.map
|
package/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,iCAQgB;AAPd,+FAAA,MAAM,OAAA;AACN,qGAAA,YAAY,OAAA;AACZ,kGAAA,SAAS,OAAA;AACT,kGAAA,SAAS,OAAA;AACT,gGAAA,OAAO,OAAA;AACP,yGAAA,gBAAgB,OAAA;AAChB,sGAAA,aAAa,OAAA;AAEf,6CAA0B;AAE1B,6BAAiC;AAAxB,gGAAA,SAAS,OAAA;AAElB,mCAA2D;AAAlD,wGAAA,cAAc,OAAA;AAAE,0GAAA,gBAAgB,OAAA;AAEzC,uCAA4C;AAAnC,2GAAA,eAAe,OAAA;AAExB,6CAA2C;AAAlC,0GAAA,WAAW,OAAA;AACpB,+BAA6B;AAApB,4FAAA,IAAI,OAAA;AACb,iCAA+B;AAAtB,8FAAA,KAAK,OAAA"}
|
package/utils/utils.d.ts
CHANGED
package/utils/utils.js
CHANGED
|
@@ -35,8 +35,12 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
35
35
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
|
+
};
|
|
38
41
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.escapeWinSlashes = exports.isLinux = exports.isWindows = exports.uniqArray = exports.uuidv4 = exports.asyncForEach = void 0;
|
|
42
|
+
exports.getMacrosPath = exports.escapeWinSlashes = exports.isLinux = exports.isWindows = exports.uniqArray = exports.uuidv4 = exports.asyncForEach = void 0;
|
|
43
|
+
var path_1 = __importDefault(require("path"));
|
|
40
44
|
function asyncForEach(array, callback) {
|
|
41
45
|
return __awaiter(this, void 0, void 0, function () {
|
|
42
46
|
var index;
|
|
@@ -80,4 +84,6 @@ var escapeWinSlashes = function (path) {
|
|
|
80
84
|
return (0, exports.isWindows)() ? path.replace(/\\/g, '\\\\') : path;
|
|
81
85
|
};
|
|
82
86
|
exports.escapeWinSlashes = escapeWinSlashes;
|
|
87
|
+
var getMacrosPath = function () { return path_1.default.join(__dirname, '..', 'macros'); };
|
|
88
|
+
exports.getMacrosPath = getMacrosPath;
|
|
83
89
|
//# sourceMappingURL=utils.js.map
|
package/utils/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils/utils.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,8CAAuB;AAEvB,SAAsB,YAAY,CAChC,KAAY,EACZ,QAAiE;;;;;;oBAExD,KAAK,GAAG,CAAC;;;yBAAE,CAAA,KAAK,GAAG,KAAK,CAAC,MAAM,CAAA;oBACtC,qBAAM,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,EAAA;;oBAA1C,SAA0C,CAAA;;;oBADF,KAAK,EAAE,CAAA;;;;;;CAGlD;AAPD,oCAOC;AAEM,IAAM,MAAM,GAAG;IACpB,OAAA,sCAAsC,CAAC,OAAO,CAAC,OAAO,EAAE,UAAC,CAAC;QACxD,IAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,EAChC,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAA;QAEpC,OAAO,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;IACvB,CAAC,CAAC;AALF,CAKE,CAAA;AANS,QAAA,MAAM,UAMf;AAEG,IAAM,SAAS,GAAG,UAAC,IAAW,IAAK,OAAA,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,EAAzB,CAAyB,CAAA;AAAtD,QAAA,SAAS,aAA6C;AAE5D,IAAM,SAAS,GAAG,cAAM,OAAA,OAAO,CAAC,QAAQ,KAAK,OAAO,EAA5B,CAA4B,CAAA;AAA9C,QAAA,SAAS,aAAqC;AAEpD,IAAM,OAAO,GAAG,cAAM,OAAA,OAAO,CAAC,QAAQ,KAAK,OAAO,EAA5B,CAA4B,CAAA;AAA5C,QAAA,OAAO,WAAqC;AAEzD;;GAEG;AACI,IAAM,gBAAgB,GAAG,UAAC,IAAY;IAC3C,OAAA,IAAA,iBAAS,GAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI;AAAhD,CAAgD,CAAA;AADrC,QAAA,gBAAgB,oBACqB;AAE3C,IAAM,aAAa,GAAG,cAAM,OAAA,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC,EAApC,CAAoC,CAAA;AAA1D,QAAA,aAAa,iBAA6C"}
|