<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" version="2.0">

<channel>
	<title>The SAS Dummy</title>
	
	<link>https://blogs.sas.com/content/sasdummy</link>
	<description>A SAS® blog for the rest of us</description>
	<lastBuildDate>Tue, 12 Oct 2021 13:06:48 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.5.3</generator>
	<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/ASasBlogForTheRestOfUs" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="asasblogfortherestofus" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">ASasBlogForTheRestOfUs</feedburner:emailServiceId><feedburner:feedburnerHostname xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">https://feedburner.google.com</feedburner:feedburnerHostname><item>
		<title>How to work with emojis in SAS</title>
		<link>https://blogs.sas.com/content/sasdummy/2021/07/06/emojis-sas/</link>
					<comments>https://blogs.sas.com/content/sasdummy/2021/07/06/emojis-sas/#comments</comments>
		
		<dc:creator><![CDATA[Chris Hemedinger]]></dc:creator>
		<pubDate>Tue, 06 Jul 2021 16:33:32 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[diversity]]></category>
		<category><![CDATA[emoji]]></category>
		<guid isPermaLink="false">https://blogs.sas.com/content/sasdummy/?p=7248</guid>

					<description><![CDATA[<p>Emojis are showing up in our data. Here's what you need to know when working with emojis in your SAS code.</p>
<p>The post <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy/2021/07/06/emojis-sas/">How to work with emojis in SAS</a> appeared first on <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy">The SAS Dummy</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>When I was a computer science student in the 1980s, our digital alphabet was simple and small. We could express ourselves with the letters A..Z (and lowercase a..z) and numbers (0..9) and a handful of punctuation and symbols. Thanks to the ASCII standard, we could represent any of these characters in a single byte (actually just 7 bits). This allowed for a generous 128 different characters, and we had character slots to spare. (Of course for non-English and especially non-latin characters we had to resort to different code pages...but that was before the Internet forced us to work together. Before Unicode, we lived in a digital Tower of Babel.)</p>
<p>Even with the limited character set, pictorial communication was possible with ASCII through the fun medium of "ASCII art." ASCII art is basically the stone-age version of emojis. For example, consider the shrug emoji: &#129335;</p>
<p>Its text-art ancestor (not strictly ASCII as a sharp reader pointed out) is this: <code>¯\_(ツ)_/¯</code> While ASCII and text art currently enjoys a retro renaissance, the emoji has become indispensable in our daily communications. </p>
<h2>Emojis before Unicode</h2>
<p>Given the ubiquity of emojis in every communication channel, it's sometimes difficult to remember that just a few years ago emoji characters were devised and implemented in vendor-specific offerings. As the sole Android phone user in my house, I remember a time when my iPhone-happy family could express themselves in emojis that I couldn't read in the family group chat. Apple would release new emojis for their users, and then Android (Google) would leap frog with another set of their own fun symbols. But if you weren't trading messages with users of the same technology, then chunks of your text would be lost in translation.</p>
<p>Enter Unicode. A standard system for encoding characters that allows for multiple bytes of storage, Unicode has seemingly endless runway for adding new characters. More importantly, there is a standards body that sets revisions for Unicode characters periodically so everyone can use the same huge alphabet. <a href="https://emojipedia.org/emoji-1.0/">In 2015, emoji characters were added into Unicode</a> and have been revised steadily with universal agreement. </p>
<p>This standardization has helped to propel emojis as a main component of communication in every channel. Text messages, Twitter threads, Venmo payments, Facebook messages, Slack messages, GitHub comments -- everything accepts emojis. (Emojis are so ingrained and expected that if you send a Venmo payment without using an emoji and just use plain text, it could be interpreted as a slight or at the least as a miscue.)</p>
<p>For more background about emojis, read <a href="https://computer.howstuffworks.com/internet/social-networking/networks/emojis.htm">How Emjois Work (source: <strong>How Stuff Works</strong>)</a>.</p>
<p><b>Unicode is essential for emojis.</b> In SAS, the use of Unicode is possible by way of UTF-8 encoding. If you work in a modern SAS environment with a diverse set of data, you should already be using ENCODING=UTF8 as your SAS session encoding. If you use <a href="https://www.sas.com/en_us/software/on-demand-for-academics.html">SAS OnDemand for Academics</a> (the free environment for any learner), this is already set for you. And SAS Viya offers <strong>only</strong> UTF-8 -- which makes sense, because it's the best for most data and it's how most apps work these days.</p>
<h2>Emojis as data and processing in SAS</h2>
<p>Emojis are everywhere, and their presence can enrich (and complicate) the way that we analyze text data. For example, emojis are often useful cues for sentiment (smiley face! laughing-with-tears face! grimace face! poop!).  It's not unusual for a text message to be ALL emojis with no "traditional" words.</p>
<p>The website Unicode.org <a href="https://unicode.org/emoji/charts/full-emoji-list.html">maintains the complete compendium of emojis</a> as defined in the latest standards. They also provide the emoji definitions as data files, which we can easily read into SAS. This program reads all of the data as published and adds features for just the "basic" emojis:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="sas" style="font-family:monospace;"><span style="color: #006400; font-style: italic;">/* MUST be running with ENCODING=UTF8 */</span>
<span style="color: #0000ff;">filename</span> raw temp;
<span style="color: #000080; font-weight: bold;">proc http</span>
 url=<span style="color: #a020f0;">&quot;https://unicode.org/Public/emoji/13.1/emoji-sequences.txt&quot;</span>
 out=raw;
<span style="color: #000080; font-weight: bold;">run</span>;
&nbsp;
ods escapechar=<span style="color: #a020f0;">'~'</span>;
<span style="color: #000080; font-weight: bold;">data</span> emojis <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">drop</span>=line<span style="color: #66cc66;">&#41;</span>;
<span style="color: #0000ff;">length</span> line $ <span style="color: #2e8b57; font-weight: bold;">1000</span> codepoint_range $ <span style="color: #2e8b57; font-weight: bold;">45</span> val_start <span style="color: #2e8b57; font-weight: bold;">8</span> val_end <span style="color: #2e8b57; font-weight: bold;">8</span> type $ <span style="color: #2e8b57; font-weight: bold;">30</span> comments $ <span style="color: #2e8b57; font-weight: bold;">65</span> saschar $ <span style="color: #2e8b57; font-weight: bold;">20</span> htmlchar $ <span style="color: #2e8b57; font-weight: bold;">25</span>;
<span style="color: #0000ff;">infile</span> raw ;
<span style="color: #0000ff;">input</span>;
line = <span style="color: #0000ff;">_infile_</span>;
<span style="color: #0000ff;">if</span> <span style="color: #0000ff;">substr</span><span style="color: #66cc66;">&#40;</span>line,<span style="color: #2e8b57; font-weight: bold;">1</span>,<span style="color: #2e8b57; font-weight: bold;">1</span><span style="color: #66cc66;">&#41;</span>^=<span style="color: #a020f0;">'#'</span> <span style="color: #0000ff;">and</span> line ^= <span style="color: #a020f0;">' '</span> <span style="color: #0000ff;">then</span> <span style="color: #0000ff;">do</span>;
 <span style="color: #006400; font-style: italic;">/* read the raw codepoint value - could be single, a range, or a combo of several */</span>
 codepoint_range = <span style="color: #0000ff;">scan</span><span style="color: #66cc66;">&#40;</span>line,<span style="color: #2e8b57; font-weight: bold;">1</span>,<span style="color: #a020f0;">';'</span><span style="color: #66cc66;">&#41;</span>;
 <span style="color: #006400; font-style: italic;">/* read the type field */</span>
 type = <span style="color: #0000ff;">compress</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">scan</span><span style="color: #66cc66;">&#40;</span>line,<span style="color: #2e8b57; font-weight: bold;">2</span>,<span style="color: #a020f0;">';'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
 <span style="color: #006400; font-style: italic;">/* text description of this emoji */</span>
 comments = <span style="color: #0000ff;">scan</span><span style="color: #66cc66;">&#40;</span>line,<span style="color: #2e8b57; font-weight: bold;">3</span>,<span style="color: #a020f0;">'#;'</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
 <span style="color: #006400; font-style: italic;">/* for those emojis that have a range of values */</span>
 val_start = <span style="color: #0000ff;">input</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">scan</span><span style="color: #66cc66;">&#40;</span>codepoint_range,<span style="color: #2e8b57; font-weight: bold;">1</span>,<span style="color: #a020f0;">'. '</span><span style="color: #66cc66;">&#41;</span>, hex.<span style="color: #66cc66;">&#41;</span>;
 <span style="color: #0000ff;">if</span> find<span style="color: #66cc66;">&#40;</span>codepoint_range,<span style="color: #a020f0;">'..'</span><span style="color: #66cc66;">&#41;</span> &gt; <span style="color: #2e8b57; font-weight: bold;">0</span> <span style="color: #0000ff;">then</span> <span style="color: #0000ff;">do</span>;
  val_end = <span style="color: #0000ff;">input</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">scan</span><span style="color: #66cc66;">&#40;</span>codepoint_range,<span style="color: #2e8b57; font-weight: bold;">2</span>,<span style="color: #a020f0;">'.'</span><span style="color: #66cc66;">&#41;</span>, hex.<span style="color: #66cc66;">&#41;</span>;
 <span style="color: #0000ff;">end</span>;
 <span style="color: #0000ff;">else</span> val_end=val_start;
&nbsp;
 <span style="color: #0000ff;">if</span> type = <span style="color: #a020f0;">&quot;Basic_Emoji&quot;</span> <span style="color: #0000ff;">then</span> <span style="color: #0000ff;">do</span>;
  saschar = cat<span style="color: #66cc66;">&#40;</span><span style="color: #a020f0;">'~{Unicode '</span>,<span style="color: #0000ff;">scan</span><span style="color: #66cc66;">&#40;</span>codepoint_range,<span style="color: #2e8b57; font-weight: bold;">1</span>,<span style="color: #a020f0;">' .'</span><span style="color: #66cc66;">&#41;</span>,<span style="color: #a020f0;">'}'</span><span style="color: #66cc66;">&#41;</span>;
  htmlchar = cats<span style="color: #66cc66;">&#40;</span><span style="color: #a020f0;">'&lt;span&gt;&amp;#x'</span>,<span style="color: #0000ff;">scan</span><span style="color: #66cc66;">&#40;</span>codepoint_range,<span style="color: #2e8b57; font-weight: bold;">1</span>,<span style="color: #a020f0;">' .'</span><span style="color: #66cc66;">&#41;</span>,<span style="color: #a020f0;">';&lt;/span&gt;'</span><span style="color: #66cc66;">&#41;</span>;
 <span style="color: #0000ff;">end</span>;
 <span style="color: #0000ff;">output</span>;
<span style="color: #0000ff;">end</span>;
<span style="color: #000080; font-weight: bold;">run</span>;
&nbsp;
<span style="color: #000080; font-weight: bold;">proc print</span> <span style="color: #000080; font-weight: bold;">data</span>=emojis; <span style="color: #000080; font-weight: bold;">run</span>;</pre></td></tr></table></div>

<p>(As usual, all of the SAS code <a href="https://github.com/sascommunities/sas-dummy-blog/blob/master/emojis/emoji-sequences.sas">in this article is available on GitHub</a>.)</p>
<p>The "features" I added include the Unicode representation for an emoji character in SAS, which could then be used in any SAS report in ODS or any <a href="https://blogs.sas.com/content/graphicallyspeaking/2011/11/14/the-power-of-unicode/">graphics produced in the SG procedures</a>. I also added the HTML-encoded representation of the emoji, which uses the form <code>&amp;#xNNNN;</code> where NNNN is the Unicode value for the character.  Here's the raw data view:</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2021/07/emoji1.jpg"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2021/07/emoji1.jpg" alt="" width="902" height="294" class="alignnone size-full wp-image-7281" srcset="https://blogs.sas.com/content/sasdummy/files/2021/07/emoji1.jpg 902w, https://blogs.sas.com/content/sasdummy/files/2021/07/emoji1-300x98.jpg 300w, https://blogs.sas.com/content/sasdummy/files/2021/07/emoji1-768x250.jpg 768w" sizes="(max-width: 902px) 100vw, 902px" /></a></p>
<p>When you PROC PRINT to an HTML destination, here's the view in the results browser:</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2021/07/emoji2.jpg"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2021/07/emoji2.jpg" alt="" width="1222" height="355" class="alignnone size-full wp-image-7278" srcset="https://blogs.sas.com/content/sasdummy/files/2021/07/emoji2.jpg 1222w, https://blogs.sas.com/content/sasdummy/files/2021/07/emoji2-300x87.jpg 300w, https://blogs.sas.com/content/sasdummy/files/2021/07/emoji2-1024x297.jpg 1024w, https://blogs.sas.com/content/sasdummy/files/2021/07/emoji2-768x223.jpg 768w" sizes="(max-width: 1222px) 100vw, 1222px" /></a></p>
<h2>In search of structured emoji data</h2>
<p>The Unicode.org site can serve up the emoji definitions and codes, but this data isn't exactly ready for use within applications. One could work through the list of emojis (thousands of them!) and tag these with descriptive words and meanings. That could take a long time and to be honest, I'm not sure I could accurately interpret many of the emojis myself. So I began the hunt for data files that had this work already completed.</p>
<p>I found <a href="https://github.com/github/gemoji">the GitHub/gemoji project</a>, a Ruby-language code repository that contains a structured JSON file that describes a recent collection of emojis. From all of the files in the project, I need only one JSON file. Here's a SAS program that downloads the file with PROC HTTP and reads the data with the JSON libname engine:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="sas" style="font-family:monospace;"><span style="color: #0000ff;">filename</span> rawj temp;
 <span style="color: #000080; font-weight: bold;">proc http</span>
  url=<span style="color: #a020f0;">&quot;https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json&quot;</span>
  out=rawj;
<span style="color: #000080; font-weight: bold;">run</span>;
&nbsp;
<span style="color: #0000ff;">libname</span> emoji json <span style="color: #0000ff;">fileref</span>=rawj;</pre></td></tr></table></div>

<p>Upon reading these data, I quickly realized the JSON text contains the <strong>actual Unicode character</strong> for the emoji, and not the decimal or hex value that we might need for using it later in SAS.</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2021/07/emoji-looking.jpg"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2021/07/emoji-looking.jpg" alt="" width="429" height="471" class="alignnone size-full wp-image-7308" srcset="https://blogs.sas.com/content/sasdummy/files/2021/07/emoji-looking.jpg 429w, https://blogs.sas.com/content/sasdummy/files/2021/07/emoji-looking-273x300.jpg 273w" sizes="(max-width: 429px) 100vw, 429px" /></a></p>
<p>I wanted to convert the emoji character to its numeric code. That's when <a href="https://go.documentation.sas.com/doc/en/pgmsascdc/9.4_3.5/nlsref/n16dtsekpfhk8cn1skrvzvsk1yhv.htm">I discovered the UNICODEC function</a>, which can "decode" the Unicode sequence into its numeric values. (Note that some characters use more than one value in a sequence). </p>
<p>Here's my complete program, which includes some reworking of the tags and aliases attributes so I can have one record per emoji:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="sas" style="font-family:monospace;"><span style="color: #0000ff;">filename</span> rawj temp;
 <span style="color: #000080; font-weight: bold;">proc http</span>
  url=<span style="color: #a020f0;">&quot;https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json&quot;</span>
  out=rawj;
<span style="color: #000080; font-weight: bold;">run</span>;
&nbsp;
<span style="color: #0000ff;">libname</span> emoji json <span style="color: #0000ff;">fileref</span>=rawj;
&nbsp;
<span style="color: #006400; font-style: italic;">/* reformat the tags and aliases data for inclusion in a single data set */</span>
<span style="color: #000080; font-weight: bold;">data</span> tags;
 <span style="color: #0000ff;">length</span> ordinal_root <span style="color: #2e8b57; font-weight: bold;">8</span> tags $ <span style="color: #2e8b57; font-weight: bold;">60</span>;
 <span style="color: #0000ff;">set</span> emoji.tags;
 tags = catx<span style="color: #66cc66;">&#40;</span><span style="color: #a020f0;">', '</span>,of tags:<span style="color: #66cc66;">&#41;</span>;
 <span style="color: #0000ff;">keep</span> ordinal_root tags;
<span style="color: #000080; font-weight: bold;">run</span>;
&nbsp;
<span style="color: #000080; font-weight: bold;">data</span> aliases;
 <span style="color: #0000ff;">length</span> ordinal_root <span style="color: #2e8b57; font-weight: bold;">8</span> aliases $ <span style="color: #2e8b57; font-weight: bold;">60</span>;
 <span style="color: #0000ff;">set</span> emoji.aliases;
 aliases = catx<span style="color: #66cc66;">&#40;</span><span style="color: #a020f0;">', '</span>,of aliases:<span style="color: #66cc66;">&#41;</span>;
 <span style="color: #0000ff;">keep</span> ordinal_root aliases;
<span style="color: #000080; font-weight: bold;">run</span>;
&nbsp;
<span style="color: #006400; font-style: italic;">/* Join together in one record per emoji */</span>
<span style="color: #000080; font-weight: bold;">proc sql</span>;
 <span style="color: #0000ff;">create</span> <span style="color: #0000ff;">table</span> full_emoji <span style="color: #0000ff;">as</span> 
 <span style="color: #0000ff;">select</span>  t1.emoji <span style="color: #0000ff;">as</span> emoji_char, 
    unicodec<span style="color: #66cc66;">&#40;</span>t1.emoji,<span style="color: #a020f0;">'esc'</span><span style="color: #66cc66;">&#41;</span> <span style="color: #0000ff;">as</span> emoji_code, 
    t1.description, t1.category, t1.unicode_version, 
    case 
     when t1.skin_tones = <span style="color: #2e8b57; font-weight: bold;">1</span> <span style="color: #0000ff;">then</span>  t1.skin_tones
	 <span style="color: #0000ff;">else</span> <span style="color: #2e8b57; font-weight: bold;">0</span>
	<span style="color: #0000ff;">end</span> <span style="color: #0000ff;">as</span> has_skin_tones,
    t2.tags, t3.aliases
  <span style="color: #0000ff;">from</span> emoji.root t1
  <span style="color: #0000ff;">left</span> join tags t2 <span style="color: #0000ff;">on</span> <span style="color: #66cc66;">&#40;</span>t1.ordinal_root = t2.ordinal_root<span style="color: #66cc66;">&#41;</span>
  <span style="color: #0000ff;">left</span> join aliases t3 <span style="color: #0000ff;">on</span> <span style="color: #66cc66;">&#40;</span>t1.ordinal_root = t3.ordinal_root<span style="color: #66cc66;">&#41;</span>
 ;
<span style="color: #000080; font-weight: bold;">quit</span>;
&nbsp;
<span style="color: #000080; font-weight: bold;">proc print</span> <span style="color: #000080; font-weight: bold;">data</span>=full_emoji; <span style="color: #000080; font-weight: bold;">run</span>;</pre></td></tr></table></div>

<p>Here's a snippet of the report that includes some of the more interesting sequences:</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2021/07/emoji_html.jpg"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2021/07/emoji_html.jpg" alt="" width="1371" height="276" class="alignnone size-full wp-image-7290" srcset="https://blogs.sas.com/content/sasdummy/files/2021/07/emoji_html.jpg 1371w, https://blogs.sas.com/content/sasdummy/files/2021/07/emoji_html-300x60.jpg 300w, https://blogs.sas.com/content/sasdummy/files/2021/07/emoji_html-1024x206.jpg 1024w, https://blogs.sas.com/content/sasdummy/files/2021/07/emoji_html-768x155.jpg 768w" sizes="(max-width: 1371px) 100vw, 1371px" /></a></p>
<p>The diversity and inclusion aspect of emoji glyphs is ever-expanding. For example, consider the emoji for "family":</p>
<ul>
<li>The basic family emoji code is \u0001F46A (&#x1F46A;)
</li>
<li>But since families come in all shapes and sizes, you can find a family that better represents you. For example, how about "family: man, man, girl, girl"? The code is <code>\u0001F468\u200D\u0001F468\u200D\u0001F467\u200D\u0001F467</code>, which includes the codes for each component "member" all smooshed together with a <a href="https://emojipedia.org/zero-width-joiner/">"zero-width joiner" (ZWJ) code</a> in between (&#x1F468;&zwj;&#x1F468;&zwj;&#x1F467;&zwj;&#x1F467;)
</li>
<li>All of the above, but <a href="https://emojipedia.org/emoji-modifier-sequence/">with a dark-skin-tone modifier</a> (\u0001F3FF) for 2 of the family members: <code>\u0001F468\u0001F3FF\u200D\u0001F468\u200D\u0001F467\u200D\u0001F467\u0001F3FF</code> (&#x1F468;&#x1F3FF;&zwj;&#x1F468;&zwj;&#x1F467;&zwj;&#x1F467;&#x1F3FF;)
</li>
</ul>
<p>Note: I noticed that not all browsers have caught up on rendering that last example. In my browser it looks like this:<br />
<a href="https://blogs.sas.com/content/sasdummy/files/2021/07/mixed-family.jpg"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2021/07/mixed-family.jpg" alt="" width="92" height="64" class="alignnone size-full wp-image-7347" /></a></p>
<h2>Conclusion: Emojis reflect society, and society adapts to emojis</h2>
<p>As you might have noticed from that last sequence I shared, a single concept can call for many different emojis.  As our society becomes more inclusive around gender, skin color, and differently capable people, emojis are keeping up. Everyone can express the concept in the way that is most meaningful for them. This is just one way that the language of emojis enriches our communication, and in turn our experience feeds back into the process and grows the emoji collection even more.</p>
<p>As emoji-rich data is used for reporting and for training of AI models, it's important for our understanding of emoji context and meaning to keep up with the times. Already <a href="https://www.cnn.com/2021/02/14/tech/crying-laughing-emoji-gen-z/index.html">we know that emoji use differs among different age generations</a> and across other demographic groups. The use and application of emojis -- separate from the definition of emoji codes -- is yet another dimension to the data.</p>
<p>Our task as data scientists is to bring all of this intelligence and context into the process when we parse, interpret and build training data sets. The mechanics of parsing and producing emoji-rich data is just the start.</p>
<p>If you're encountering emojis in your data and considering them in your reporting and analytics, please let me know how! I'd love to hear from you in the comments.</p>
<p>The post <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy/2021/07/06/emojis-sas/">How to work with emojis in SAS</a> appeared first on <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy">The SAS Dummy</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=gtH3QpEkgws:5meWiwhw1P4:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=gtH3QpEkgws:5meWiwhw1P4:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=gtH3QpEkgws:5meWiwhw1P4:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=gtH3QpEkgws:5meWiwhw1P4:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=gtH3QpEkgws:5meWiwhw1P4:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=gtH3QpEkgws:5meWiwhw1P4:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=gtH3QpEkgws:5meWiwhw1P4:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=gtH3QpEkgws:5meWiwhw1P4:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=gtH3QpEkgws:5meWiwhw1P4:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=gtH3QpEkgws:5meWiwhw1P4:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=TzevzKxY174" border="0"></img></a>
</div>]]></content:encoded>
					
					<wfw:commentRss>https://blogs.sas.com/content/sasdummy/2021/07/06/emojis-sas/feed/</wfw:commentRss>
			<slash:comments>11</slash:comments>
		
		
			<enclosure url="https://blogs.sas.com/content/sasdummy/files/2021/07/emoji-looking-150x150.jpg" />
	</item>
		<item>
		<title>Visualizing our Netflix Trip through "The Office"</title>
		<link>https://blogs.sas.com/content/sasdummy/2021/01/18/sas-netflix-trip/</link>
					<comments>https://blogs.sas.com/content/sasdummy/2021/01/18/sas-netflix-trip/#comments</comments>
		
		<dc:creator><![CDATA[Chris Hemedinger]]></dc:creator>
		<pubDate>Mon, 18 Jan 2021 15:05:10 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Netflix]]></category>
		<category><![CDATA[SAS programming]]></category>
		<category><![CDATA[The Office]]></category>
		<category><![CDATA[visualization]]></category>
		<guid isPermaLink="false">https://blogs.sas.com/content/sasdummy/?p=7107</guid>

					<description><![CDATA[<p>Over 57 billion minutes of The Office was streamed in 2020. My family bears some responsibility. Here's our activity visualized -- using SAS.</p>
<p>The post <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy/2021/01/18/sas-netflix-trip/">Visualizing our Netflix Trip through &quot;The Office&quot;</a> appeared first on <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy">The SAS Dummy</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><em>Recommended soundtrack for this blog post: <a href="https://youtu.be/lc9eEphSxqc" target="_blank" rel="noopener noreferrer">Netflix Trip by AJR</a>.</em></p>
<aside class="pullquote alignright">"I wish there was a way to know you were in the good old days before you actually left them."<br />
Andy Bernard from <em>The Office</em></aside>
This week's news confirms what I already knew: <a href="https://screenrant.com/office-show-streaming-minutes-watched-america-2020/">"The Office" was the most-streamed television show of 2020</a>. According to reports that I've seen, the show was streamed for <strong>57 billion minutes</strong> during this extraordinary year. I'm guessing that's in part because we've all been shut in and working from home; we crave our missing office interactions. We lived vicariously (and perhaps dysfunctionally) through watching Dunder Mifflin staff. But another major factor was the looming deadline of the departure of <em>The Office</em> from Netflix as of January 1, 2021. It was a well-publicized event, so Netflix viewers had to get their binge on while they could.</p>
<p>People in my house are fans of the show, and they account for nearly 6,000 of those 57 billion streaming minutes. I can be this precise (<em>nerd alert!</em>) because I'm in the habit of analyzing our Netflix activity by using SAS. In fact, I can tell you that since late 2017, we've streamed 576 episodes of "The Office". We streamed 297 episodes in 2020. (Since the show has only 201 episodes we clearly we have a few repeats in there.)</p>
<p>I built a heatmap that shows the frequency and intensity of our streaming of this popular show. In this graph each <strong>row</strong> is a month, each <strong>square</strong> is a day. White squares are <em>Office</em>-free. A square with any red indicates at least one virtual visit with the Scranton crew; the darker the shade, the more episodes streamed during that day. You can see that Sept 15, 2020 was a particular big binge with 17 episodes. (Each episode is about 20-21 minutes, so it's definitely achievable.)</p>
<div id="attachment_7128" style="width: 1104px" class="wp-caption alignnone"><a href="https://blogs.sas.com/content/sasdummy/files/2021/01/nfjourney.png"><img aria-describedby="caption-attachment-7128" loading="lazy" class="size-full wp-image-7128" src="https://blogs.sas.com/content/sasdummy/files/2021/01/nfjourney.png" alt="netflix trip through The Office" width="1094" height="994" srcset="https://blogs.sas.com/content/sasdummy/files/2021/01/nfjourney.png 1094w, https://blogs.sas.com/content/sasdummy/files/2021/01/nfjourney-300x273.png 300w, https://blogs.sas.com/content/sasdummy/files/2021/01/nfjourney-1024x930.png 1024w, https://blogs.sas.com/content/sasdummy/files/2021/01/nfjourney-768x698.png 768w" sizes="(max-width: 1094px) 100vw, 1094px" /></a><p id="caption-attachment-7128" class="wp-caption-text">Heatmap of our household streaming of The Office</p></div>
<h2>How to build the heatmap</h2>
<p>To build this heatmap, I started with my Netflix viewing history (downloaded from my Netflix account as CSV files). I filtered to just "The Office (U.S.)" titles, and then merged with a complete "calendar" of dates between late 2017 and the start of 2021. Summarized and merged, the data looks something like this:</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2021/01/dataprep1.png"><img loading="lazy" class="alignnone size-full wp-image-7140" src="https://blogs.sas.com/content/sasdummy/files/2021/01/dataprep1.png" alt="" width="465" height="316" srcset="https://blogs.sas.com/content/sasdummy/files/2021/01/dataprep1.png 465w, https://blogs.sas.com/content/sasdummy/files/2021/01/dataprep1-300x204.png 300w" sizes="(max-width: 465px) 100vw, 465px" /></a><br />
With all of the data summarized in this way such that there is only one observation per X and Y value, <a href="https://go.documentation.sas.com/?cdcId=pgmsascdc&amp;cdcVersion=9.4_3.5&amp;docsetId=grstatproc&amp;docsetTarget=p0y94pnvxskvkmn19u7sx2j043lq.htm&amp;locale=en" target="_blank" rel="noopener noreferrer">I can use the HEATMAPPARM statement in PROC SGPLOT</a> to visualize it. (If I needed the procedure to summarize/bin the data for me, I would use the HEATMAP statement. Thanks to Rick Wicklin for this tip!)</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="sas" style="font-family:monospace;"><span style="color: #000080; font-weight: bold;">proc sgplot</span> <span style="color: #000080; font-weight: bold;">data</span>=ofc_viewing;
 <span style="color: #0000ff;">title</span> height=<span style="color: #2e8b57; font-weight: bold;">2.5</span> <span style="color: #a020f0;">&quot;The Office - a Netflix Journey&quot;</span>;
 title2 height=<span style="color: #2e8b57; font-weight: bold;">2</span> <span style="color: #a020f0;">&quot;&amp;episodes. episodes streamed on &amp;days. days, over 3 years&quot;</span>;
 <span style="color: #0000ff;">label</span> Episodes=<span style="color: #a020f0;">&quot;Episodes per day&quot;</span>;
 <span style="color: #0000ff;">format</span> monyear monyy7.;
 heatmapparm <span style="color: #0000ff;">x</span>=<span style="color: #0000ff;">day</span> y=monyear 
   colorresponse=episodes / x2axis
    outline
   colormodel=<span style="color: #66cc66;">&#40;</span>white  CXfcae91 CXfb6a4a CXde2d26 CXa50f15<span style="color: #66cc66;">&#41;</span> ;
 yaxis  minor <span style="color: #0000ff;">reverse</span> <span style="color: #0000ff;">display</span>=<span style="color: #66cc66;">&#40;</span>nolabel<span style="color: #66cc66;">&#41;</span> 
  values=<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff; font-weight: bold;">&amp;allmon</span>.<span style="color: #66cc66;">&#41;</span>
  ;
 x2axis values=<span style="color: #66cc66;">&#40;</span><span style="color: #2e8b57; font-weight: bold;">1</span> to <span style="color: #2e8b57; font-weight: bold;">31</span> <span style="color: #0000ff;">by</span> <span style="color: #2e8b57; font-weight: bold;">1</span><span style="color: #66cc66;">&#41;</span> 
   <span style="color: #0000ff;">display</span>=<span style="color: #66cc66;">&#40;</span>nolabel<span style="color: #66cc66;">&#41;</span>  ;
<span style="color: #000080; font-weight: bold;">run</span>;</pre></td></tr></table></div>

<p>You can see the full code -- with all of the data prep -- on <a href="https://github.com/sascommunities/sas-dummy-blog/blob/master/netflix-trip/NetflixTrip.sas" target="_blank" rel="noopener noreferrer">my GitHub repository here</a>. You may even run the code in your own SAS environment -- it will fetch my Netflix viewing data from another GitHub location where I've stashed it.</p>
<h2>Distribution of Seasons (not "seasonal distribution")</h2>
<p>If you examine the heatmap I produced, you can almost see our Office enthusiasm in three different bursts. These relate directly to our 3 children and the moments they discovered the show. First was early 2018 (middle child), then late 2019 (youngest child), then late 2020 (oldest child, now 22 years old, striving to catch up).</p>
<p>The Office ran for 9 seasons, and our kids have their favorite seasons and episodes -- hence the repeated viewings. I used PROC FREQ to show the distribution of episode views across the seasons:</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2021/01/ofcseason.png"><img loading="lazy" class="alignnone size-full wp-image-7125" src="https://blogs.sas.com/content/sasdummy/files/2021/01/ofcseason.png" alt="" width="793" height="394" srcset="https://blogs.sas.com/content/sasdummy/files/2021/01/ofcseason.png 793w, https://blogs.sas.com/content/sasdummy/files/2021/01/ofcseason-300x149.png 300w, https://blogs.sas.com/content/sasdummy/files/2021/01/ofcseason-768x382.png 768w, https://blogs.sas.com/content/sasdummy/files/2021/01/ofcseason-164x82.png 164w" sizes="(max-width: 793px) 100vw, 793px" /></a><br />
Season 1 is remarkably low for two reasons. First and most importantly, it contains the fewest episodes. Second, many viewers agree that Season 1 is the "cringiest" content, and can be uncomfortable to watch. (This Reddit user leaned into the cringe with <a href="https://www.reddit.com/r/dataisbeautiful/comments/kn28iz/thats_what_she_said_a_visual_history_the_office_oc/">his data visualization of "that's what she said" jokes.</a>)</p>
<p>From the data (and from listening to my kids), I know that Season 2 is a favorite. Of the 60 episodes we streamed at least 4 times, 19 of them were in Season 2.</p>
<h2>More than streaming, it's an Office lifestyle</h2>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2021/01/57981861204__8B26F93F-83B9-4925-994E-B5D9EF0A9C06.jpg"><img loading="lazy" class="alignright size-medium wp-image-7191" src="https://blogs.sas.com/content/sasdummy/files/2021/01/57981861204__8B26F93F-83B9-4925-994E-B5D9EF0A9C06-300x174.jpg" alt="" width="300" height="174" srcset="https://blogs.sas.com/content/sasdummy/files/2021/01/57981861204__8B26F93F-83B9-4925-994E-B5D9EF0A9C06-300x174.jpg 300w, https://blogs.sas.com/content/sasdummy/files/2021/01/57981861204__8B26F93F-83B9-4925-994E-B5D9EF0A9C06-1024x595.jpg 1024w, https://blogs.sas.com/content/sasdummy/files/2021/01/57981861204__8B26F93F-83B9-4925-994E-B5D9EF0A9C06-768x447.jpg 768w, https://blogs.sas.com/content/sasdummy/files/2021/01/57981861204__8B26F93F-83B9-4925-994E-B5D9EF0A9C06.jpg 1436w" sizes="(max-width: 300px) 100vw, 300px" /></a><br />
Office fandom goes beyond just watching the show. Our kids continue to embrace "The Office" in other mediums as well. We have t-shirts depicting the memes for "FALSE." and "Schrute Farms." We listen <a href="https://www.earwolf.com/show/office-ladies/">to The Office Ladies podcast</a>, hosted by two stars of the show. In 2019 our daughter's<a href="https://www.odysseyofthemind.com/"> Odyssey of the Mind team</a> created a parody skit based on "The Office" (a weather-based office named Thunder Mifflin) -- and advanced to world finals.</p>
<p>Rarely does a day go by without some reference to an iconic phrase or life lesson that we gleaned from "The Office." We're grateful for the shared experience, and we'll miss our friends from the Dunder Mifflin Paper Company.</p>
<p>The post <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy/2021/01/18/sas-netflix-trip/">Visualizing our Netflix Trip through &quot;The Office&quot;</a> appeared first on <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy">The SAS Dummy</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=0qyJtJgzDEw:4WGSRqZfWpM:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=0qyJtJgzDEw:4WGSRqZfWpM:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=0qyJtJgzDEw:4WGSRqZfWpM:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=0qyJtJgzDEw:4WGSRqZfWpM:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=0qyJtJgzDEw:4WGSRqZfWpM:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=0qyJtJgzDEw:4WGSRqZfWpM:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=0qyJtJgzDEw:4WGSRqZfWpM:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=0qyJtJgzDEw:4WGSRqZfWpM:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=0qyJtJgzDEw:4WGSRqZfWpM:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=0qyJtJgzDEw:4WGSRqZfWpM:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=TzevzKxY174" border="0"></img></a>
</div>]]></content:encoded>
					
					<wfw:commentRss>https://blogs.sas.com/content/sasdummy/2021/01/18/sas-netflix-trip/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			<enclosure url="https://blogs.sas.com/content/sasdummy/files/2021/01/nfjourney-150x150.png" />
	</item>
		<item>
		<title>How to organize your SAS projects in Git</title>
		<link>https://blogs.sas.com/content/sasdummy/2020/11/10/sas-projects-git/</link>
					<comments>https://blogs.sas.com/content/sasdummy/2020/11/10/sas-projects-git/#respond</comments>
		
		<dc:creator><![CDATA[Chris Hemedinger]]></dc:creator>
		<pubDate>Tue, 10 Nov 2020 13:23:11 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[best practices]]></category>
		<category><![CDATA[Developers]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[SAS programming]]></category>
		<category><![CDATA[source control]]></category>
		<guid isPermaLink="false">https://blogs.sas.com/content/sasdummy/?p=7043</guid>

					<description><![CDATA[<p>As you begin managing your SAS code and projects in Git, here are a few guidelines for how to organize your work and collaborate with others.</p>
<p>The post <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy/2020/11/10/sas-projects-git/">How to organize your SAS projects in Git</a> appeared first on <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy">The SAS Dummy</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The code and data that drive analytics projects are important assets to the organizations that sponsor them.  As such, there is a growing trend to manage these items in the source management systems of record. For most companies these days, that means Git. The specific system might be GitHub Enterprise, GitLab, or Bitbucket -- all platforms that are based on Git.</p>
<p>For a quick-start tutorial <a href="https://www.youtube.com/watch?v=0eVhllpj11A">check out this 12-minute video</a> on the SAS Users YouTube channel:</p>

<!-- iframe plugin v.4.5 wordpress.org/plugins/iframe/ -->
<iframe width="560" height="315" src="https://www.youtube.com/embed/0eVhllpj11A" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" 0="allowfullscreen" scrolling="yes" class="iframe-class"></iframe>
<p>Many SAS products support direct integration with Git. This includes SAS Studio, SAS Enterprise Guide, and the SAS programming language. (That last one checks <strong>a lot</strong> of boxes for ways to use Git and SAS together.) While we have good documentation and videos to help you learn about Git and SAS, we often get questions around "best practices" -- what is <strong>the best/correct way</strong> to organize your SAS projects in Git?</p>
<p>In this article I'll dodge that question, but I'll still try to provide some helpful advice in the process.</p>
<a href="https://communities.sas.com/t5/Ask-the-Expert/Using-SAS-with-Git-Bring-a-DevOps-Mindset-to-Your-SAS-Code/ta-p/557476" class="sc-button sc-button-default"><span><span class="btnheader">Ask the Expert resource:</span> Using SAS® With Git: Bring a DevOps Mindset to Your SAS® Code</span></a>
<h2>Guidelines for managing SAS projects in Git</h2>
<p>It’s difficult for us to prescribe exactly how to organize project repositories in source control.  Your best approach will depend so much on the type of work, the company organization, and the culture of collaboration. But I can provide some guidance -- mainly things to do and things to avoid -- based on experience. </p>
<h3>Do not create one huge repository</h3>
<p><strong>DO NOT</strong> build one huge repository that contains everything you currently maintain.  Your work only grows over time and you'll come to regret/revisit the internal organization of a huge project.  Once established, it can be tricky to change the folder structure and organization. If you later try to break a large project into smaller pieces, it can be difficult or impossible to maintain the integrity of source management benefits like file histories and differences.  </p>
<h3>Design with collaboration in mind</h3>
<p><strong>DO NOT</strong> organize projects based only on the teams that maintain them. And of course, don't organize projects based on individual team members.</p>
<ul>
<li>Good repo names: <code>risk-adjustment-model</code>, <code>engagement-campaigns</code>
</li>
<li>Bad repo names: <code>joes-code</code>, <code>claims-dept</code>
</li>
</ul>
<p>All teams reorganize over time, and you don't want to have to reorganize all of your code each time that happens. And code projects change hands, so keep the structure personnel-agnostic if you can. Major refactoring of code can introduce errors, and you don't want to risk that just because you got a new VP or someone changed departments.</p>
<p>Instead, <strong>DO</strong> organize projects based on function/work that the code accomplishes. Think modular...but don't make projects <strong>too</strong> granular (or you'll have a million projects).  I personally maintain several SAS code projects.  The one thing they have in common is that I'm the main contributor -- but I organize them into functional repos that theoretically (oh please oh please) someone else could step in to take over.</p>
<div id="attachment_7064" style="width: 1124px" class="wp-caption alignnone"><a href="https://blogs.sas.com/content/sasdummy/files/2020/11/git_yt.jpg"><img aria-describedby="caption-attachment-7064" loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2020/11/git_yt.jpg" alt="" width="1114" height="705" class="size-full wp-image-7064" srcset="https://blogs.sas.com/content/sasdummy/files/2020/11/git_yt.jpg 1114w, https://blogs.sas.com/content/sasdummy/files/2020/11/git_yt-300x190.jpg 300w, https://blogs.sas.com/content/sasdummy/files/2020/11/git_yt-1024x648.jpg 1024w, https://blogs.sas.com/content/sasdummy/files/2020/11/git_yt-768x486.jpg 768w" sizes="(max-width: 1114px) 100vw, 1114px" /></a><p id="caption-attachment-7064" class="wp-caption-text">The Git view of my YouTube API project in SAS Enterprise Guide</p></div>
<h3>Up with reuse, down with ownership</h3>
<p>This might seem a bit communist, but collaboration works best when we don't regard code that we write as "our turf." <strong>DO NOT</strong> cling to notions of code "ownership."  It makes sense for teams/subject-matter experts to have primary responsibility for a project, but systems like Git are designed to help with transparency and collaboration.  Be open to another team member suggesting and merging (with review and approval) a change that improves things. GitHub, GitLab, and Bitbucket all support mechanisms for issue tracking and merge requests. These allow changes to be suggested, submitted, revised, and approved in an efficient, transparent way.</p>
<p><strong>DO</strong> use source control to enable code reuse. Many teams have foundational "shared code" for standard operations, coded in SAS macros or shared statements.  Consider placing these into their own project that other projects and teams can import.  You can even use Git functions within SAS to fetch and include this code directly from your Git repository:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="sas" style="font-family:monospace;"><span style="color: #006400; font-style: italic;">/* create a temp folder to hold the shared code */</span>
<span style="color: #0000ff;">options</span> dlcreatedir;
<span style="color: #0000ff;">%let</span> repoPath = <span style="color: #0000ff;">%sysfunc</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">getoption</span><span style="color: #66cc66;">&#40;</span>WORK<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>/shared-code;
<span style="color: #0000ff;">libname</span> repo <span style="color: #a020f0;">&quot;&amp;repoPath.&quot;</span>;
<span style="color: #0000ff;">libname</span> repo clear;
&nbsp;
<span style="color: #006400; font-style: italic;">/* Fetch latest code from Git */</span>
<span style="color: #000080; font-weight: bold;">data</span> <span style="color: #0000ff;">_null_</span>;
 rc = git_clone<span style="color: #66cc66;">&#40;</span> 
   <span style="color: #a020f0;">&quot;https://gitlab.mycompany.com/sas-projects/shared-code/&quot;</span>,
   <span style="color: #a020f0;">&quot;&amp;repoPath.&quot;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #000080; font-weight: bold;">run</span>;
&nbsp;
<span style="color: #0000ff;">options</span> source2;
<span style="color: #006400; font-style: italic;">/* run the code in this session */</span>
%include <span style="color: #a020f0;">&quot;&amp;repoPath./bootstrap-macros.sas&quot;</span>;</pre></td></tr></table></div>

<p>If you rely on a repository for shared code and components, make sure that tests are in place so changes can be validated and will not break downstream systems.  You can even automate tests with <a href="https://communities.sas.com/t5/SAS-Communities-Library/DevOps-Applied-to-SAS-9-SAS-Code-GitLab-and-Jenkins/ta-p/676039">continuous integration tools like Jenkins</a>.</p>
<p><strong>DO</strong> document how projects relate to each other, dependencies, and prepare guidance for new team members to get started quickly. For most of us, we feel more accountable when we know that our code will be placed in central repositories visible to our peers. It may inspire cleaner code, more complete documentation, and a robust on-boarding process for new team members. Use the Markdown files (README.md and others) in a repository to keep your documentation close to the code.</p>
<div id="attachment_7085" style="width: 896px" class="wp-caption alignnone"><a href="https://blogs.sas.com/content/sasdummy/files/2020/11/git_ps.jpg"><img aria-describedby="caption-attachment-7085" loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2020/11/git_ps.jpg" alt="" width="886" height="816" class="size-full wp-image-7085" srcset="https://blogs.sas.com/content/sasdummy/files/2020/11/git_ps.jpg 886w, https://blogs.sas.com/content/sasdummy/files/2020/11/git_ps-300x276.jpg 300w, https://blogs.sas.com/content/sasdummy/files/2020/11/git_ps-768x707.jpg 768w" sizes="(max-width: 886px) 100vw, 886px" /></a><p id="caption-attachment-7085" class="wp-caption-text">My SAS code to check Pagespeed Insights, with documentation</p></div>
<h3>Work with Git features (and not against them)</h3>
<p>Once your project files are in a Git repository, you might need to change your way of working so that you aren't going against the grain of Git benefits.</p>
<p><strong>DO NOT</strong> work on code changes in a shared directory with multiple team members –- you'll step on each other.  The advantage of Git is that it's a distributed workflow and each developer can work with their own copy of the repository, and merge/accept changes from others at their own pace.</p>
<p><strong>DO</strong> <a href="https://www.atlassian.com/git/tutorials/using-branches">use Git branching</a> to organize and isolate changes until you are ready to merge them with the main branch. <a href="https://www.robinwieruch.de/git-team-workflow">It takes a little bit of learning and practice</a>, but when you adopt a branching approach you'll find it much easier to manage -- it beats keeping multiple copies of your code with slightly different file and folder names to mark "works in progress."</p>
<p><strong>DO</strong> consider learning and using Git tools such as <a href="https://docs.gitlab.com/ee/gitlab-basics/start-using-git.html">Git Bash (command line)</a>, Git GUI, and a code IDE like VS Code.  These don't replace the SAS-provided coding tools with their Git integration, but they can supplement your workflow and make it easier to manage content among several projects.</p>
<h2>Learning more</h2>
<p>When you're ready to learn more about working with Git and SAS, we have many webinars, videos, and documentation resources:</p>
<ul>
<li><a href="https://communities.sas.com/t5/Ask-the-Expert/Using-SAS-with-Git-Bring-a-DevOps-Mindset-to-Your-SAS-Code/ta-p/557476">Using SAS with Git: Bring a DevOps Mindset to Your SAS Code</a> (Ask the Expert webinar)
</li>
<li><a href="https://communities.sas.com/t5/Ask-the-Expert/How-Do-You-Manage-Your-SAS-Projects-With-Git-Slides-Q-amp-A-and/ta-p/672160">How do you manage your SAS projects with Git?</a> (Ask the Expert webinar)
</li>
<li><a href="https://go.documentation.sas.com/?docsetId=lefunctionsref&amp;docsetTarget=n1mlc3f9w9zh9fn13qswiq6hrta0.htm&amp;docsetVersion=9.4&amp;locale=en">Git functions in SAS 9.4 and SAS Viya</a> (doc)</li>
<li><a href="https://go.documentation.sas.com/?activeCdc=egdoccdc&amp;cdcId=egcdc&amp;cdcVersion=8.2&amp;docsetId=egug&amp;docsetTarget=p1ov5qodzk4ur2n1r200wdr5jz75.htm&amp;locale=en&amp;docsetVersion=8.2">Using Git in SAS Enterprise Guide</a> (doc)</li>
<li><a href="https://www.youtube.com/watch?v=CZwT7kxmBmw" target="_blank" rel="noopener noreferrer">Git with SAS Studio and SAS Enterprise Guide</a> (video)</li>
<li><a href="https://blogs.sas.com/content/sasdummy/2019/01/17/git-in-sas/" target="_blank" rel="noopener noreferrer">Using built-in Git operations in SAS</a> (blog)</li>
<li><a href="https://communities.sas.com/t5/SAS-Communities-Library/DevOps-Applied-to-SAS-9-SAS-Code-GitLab-and-Jenkins/ta-p/676039" target="_blank" rel="noopener noreferrer">DevOps with SAS 9: SAS code, GitLab, and Jenkins</a> (community)</li>
<li><a href="https://developer.sas.com/" target="_blank" rel="noopener noreferrer">developer.sas.com</a> for SAS app development</li>
<li><i><a href="https://git-scm.com/book/en/v2" target="_blank" rel="noopener noreferrer">Pro Git</a></i> by Scott Chacon and Ben Straub, free online book about Git</li>
<li><a href="https://support.sas.com/kb/66/215.html" target="_self" rel="noopener noreferrer">SAS Note about generating SSH key for use with Git and SAS</a></li>
</ul>
<p>The post <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy/2020/11/10/sas-projects-git/">How to organize your SAS projects in Git</a> appeared first on <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy">The SAS Dummy</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=JotsJKiE6MQ:tGF8-TbiiEQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=JotsJKiE6MQ:tGF8-TbiiEQ:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=JotsJKiE6MQ:tGF8-TbiiEQ:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=JotsJKiE6MQ:tGF8-TbiiEQ:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=JotsJKiE6MQ:tGF8-TbiiEQ:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=JotsJKiE6MQ:tGF8-TbiiEQ:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=JotsJKiE6MQ:tGF8-TbiiEQ:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=JotsJKiE6MQ:tGF8-TbiiEQ:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=JotsJKiE6MQ:tGF8-TbiiEQ:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=JotsJKiE6MQ:tGF8-TbiiEQ:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=TzevzKxY174" border="0"></img></a>
</div>]]></content:encoded>
					
					<wfw:commentRss>https://blogs.sas.com/content/sasdummy/2020/11/10/sas-projects-git/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			<enclosure url="https://blogs.sas.com/content/sasdummy/files/2020/11/git_ps-150x150.jpg" />
	</item>
		<item>
		<title>Using SAS to convert IP addresses into numerical IP values</title>
		<link>https://blogs.sas.com/content/sasdummy/2020/09/04/using-sas-to-convert-ip-addresses-into-numerical-ip-values/</link>
					<comments>https://blogs.sas.com/content/sasdummy/2020/09/04/using-sas-to-convert-ip-addresses-into-numerical-ip-values/#comments</comments>
		
		<dc:creator><![CDATA[Chris Hemedinger]]></dc:creator>
		<pubDate>Fri, 04 Sep 2020 16:00:36 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[geocode]]></category>
		<category><![CDATA[IP addresses]]></category>
		<category><![CDATA[IPv4]]></category>
		<category><![CDATA[SAS programming]]></category>
		<category><![CDATA[SAS tips]]></category>
		<guid isPermaLink="false">http://blogs.sas.com/content/sasdummy/?p=2618</guid>

					<description><![CDATA[<p>As citizens of the Internet, we are all familiar with IP addresses -- probably more so than our Internet founding fathers had ever intended. These addresses are typically represented in a 4-piece segmented list of numbers separated by dots. Here is an example: "149.173.5.120". Each segment is called an octet [...]</p>
<p>The post <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy/2020/09/04/using-sas-to-convert-ip-addresses-into-numerical-ip-values/">Using SAS to convert IP addresses into numerical IP values</a> appeared first on <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy">The SAS Dummy</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>As citizens of the Internet, we are all familiar with <a href="http://en.wikipedia.org/wiki/IP_address" title="In case you're not, here's Wikipedia">IP addresses</a> -- probably more so than our Internet founding fathers had ever intended.  These addresses are typically represented in a 4-piece segmented list of numbers separated by dots.  Here is an example: "149.173.5.120". </p>
<p>Each segment is called an octet because it contains 8 (count 'em, eight!) bits.  The four-octect IP address is part of the IPv4 standard.  </p>
<p><em><strong>Note:</strong> There is a newer IPv6 standard (featuring 16 octets) that many newer networks use and which allows for more addresses.  This has become necessary because all new consumer products are required by law to connect to the Internet.  (I think that each of my daughter's <a href="http://en.wikipedia.org/wiki/Polly_Pocket" title="tiny little things. Vacuum cleaner food.">"Polly Pocket" pieces</a> can connect to WiFi.)  But in this article I'm ignoring IPv6.</em></p>
<p><strong>UPDATE 2020-Sep-04:</strong> My colleague Agata Bogacki <a href="https://communities.sas.com/t5/SAS-Communities-Library/Using-SAS-to-Merge-IPv4-and-IPv6-Addresses-to-Geolocation-CIDR/ta-p/681633">has written a newer article that <strong>includes IPv6 and IPv4</strong> and techniques to map to a geolocation</a>.</p>
<p>The easy-to-read segmented IP address is actually a 32-bit number, and sometimes it is useful to convert the display value into its numeric form.  For example, consider the databases that help you to map an IP address to a geographic location in the world.  These databases use a numerical range to map an address to a country or city.  (<a href="https://go.documentation.sas.com/?docsetId=grmapref&docsetTarget=n0g3zwh3fbjb0yn1hwyzwuti4lgu.htm&docsetVersion=9.4_01&locale=en" title="PROC GEOCODE range coding" rel="noopener noreferrer">For more on range-based geocoding, see this topic in the PROC GEOCODE documentation.</a>)</p>
<h2>SAS code for converting IPv4 values to numbers</h2>
<p>Here is a SAS program that converts a character-based, 4-segment IP address into its equivalent numeric value.  It uses the SCAN function, a DATA step ARRAY, and a little bit of math to do the work:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="sas" style="font-family:monospace;"><span style="color: #006400; font-style: italic;">/* Calculate the numerical IP from &quot;segmented&quot; IP address            */</span>
<span style="color: #006400; font-style: italic;">/* Example: (from Right to Left)                                     */</span>
<span style="color: #006400; font-style: italic;">/* 1.2.3.4 = 4 + (3 * 256) + (2 * 256 * 256) + (1 * 256 * 256 * 256) */</span>
<span style="color: #006400; font-style: italic;">/*   is 4 + 768 + 13,1072 + 16,777,216 = 16,909,060                  */</span>
<span style="color: #000080; font-weight: bold;">data</span> ip_numbers <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">keep</span>=ip_address ip_numeric<span style="color: #66cc66;">&#41;</span>;
  <span style="color: #0000ff;">infile</span> datalines dsd;
  <span style="color: #0000ff;">length</span> ip_address $ <span style="color: #2e8b57; font-weight: bold;">20</span> ip_numeric <span style="color: #2e8b57; font-weight: bold;">8</span>;
  <span style="color: #0000ff;">input</span> ip_address;
  <span style="color: #0000ff;">array</span> ip_part <span style="color: #66cc66;">&#123;</span><span style="color: #2e8b57; font-weight: bold;">4</span><span style="color: #66cc66;">&#125;</span>;
  <span style="color: #0000ff;">do</span> i = <span style="color: #2e8b57; font-weight: bold;">1</span> to <span style="color: #2e8b57; font-weight: bold;">4</span>;
    ip_part<span style="color: #66cc66;">&#123;</span>i<span style="color: #66cc66;">&#125;</span> = <span style="color: #0000ff;">scan</span><span style="color: #66cc66;">&#40;</span>ip_address,i,<span style="color: #a020f0;">'.'</span><span style="color: #66cc66;">&#41;</span>;
  <span style="color: #0000ff;">end</span>;
  ip_numeric = ip_part<span style="color: #66cc66;">&#123;</span><span style="color: #2e8b57; font-weight: bold;">4</span><span style="color: #66cc66;">&#125;</span> +
    <span style="color: #66cc66;">&#40;</span>ip_part<span style="color: #66cc66;">&#123;</span><span style="color: #2e8b57; font-weight: bold;">3</span><span style="color: #66cc66;">&#125;</span> <span style="color: #006400; font-style: italic;">* 256) +
    (ip_part{2} * 256 * 256) +
    (ip_part{1} * 256 * 256 * 256);</span>
datalines;
115.85.65.148
117.203.114.198
118.96.201.156
119.247.220.11
12.201.116.58
128.2.38.96
128.204.197.27
128.204.207.83
134.102.237.2
141.155.113.98
169.2.124.79
172.16.26.231
172.16.30.229
173.234.211.69
176.63.76.232
178.157.198.132
178.32.145.44
178.32.177.184
178.33.174.213
178.63.199.204
184.82.208.149
188.165.187.71
;
<span style="color: #000080; font-weight: bold;">run</span>;</pre></td></tr></table></div>

<p>Here's the output:<br />
<a href="https://blogs.sas.com/content/sasdummy/files/2012/10/ipout.png"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2012/10/ipout.png" alt="" width="227" height="395" class="alignnone size-full wp-image-2623" srcset="https://blogs.sas.com/content/sasdummy/files/2012/10/ipout.png 227w, https://blogs.sas.com/content/sasdummy/files/2012/10/ipout-172x300.png 172w" sizes="(max-width: 227px) 100vw, 227px" /></a></p>
<h3>Mapping IP address to a geo location</h3>
<p>With this mapping, I can then combine my collection of IP addresses with one of the IP-to-geolocation databases that are available.  (SAS provides a <a href="https://go.documentation.sas.com/?docsetId=grmapref&docsetTarget=n0g3zwh3fbjb0yn1hwyzwuti4lgu.htm&docsetVersion=9.4_01&locale=en" title="Scroll further down to find it." rel="noopener noreferrer">macro to help work with MaxMind, which you can learn about in this topic.</a>)  Here's a sample result:</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2012/10/ipregion.png"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2012/10/ipregion.png" alt="" width="638" height="105" class="alignnone size-full wp-image-2626" srcset="https://blogs.sas.com/content/sasdummy/files/2012/10/ipregion.png 638w, https://blogs.sas.com/content/sasdummy/files/2012/10/ipregion-300x49.png 300w" sizes="(max-width: 638px) 100vw, 638px" /></a></p>
<p>The post <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy/2020/09/04/using-sas-to-convert-ip-addresses-into-numerical-ip-values/">Using SAS to convert IP addresses into numerical IP values</a> appeared first on <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy">The SAS Dummy</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=OSFcjxytR7E:nhax6N6cjUY:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=OSFcjxytR7E:nhax6N6cjUY:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=OSFcjxytR7E:nhax6N6cjUY:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=OSFcjxytR7E:nhax6N6cjUY:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=OSFcjxytR7E:nhax6N6cjUY:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=OSFcjxytR7E:nhax6N6cjUY:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=OSFcjxytR7E:nhax6N6cjUY:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=OSFcjxytR7E:nhax6N6cjUY:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=OSFcjxytR7E:nhax6N6cjUY:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=OSFcjxytR7E:nhax6N6cjUY:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=TzevzKxY174" border="0"></img></a>
</div>]]></content:encoded>
					
					<wfw:commentRss>https://blogs.sas.com/content/sasdummy/2020/09/04/using-sas-to-convert-ip-addresses-into-numerical-ip-values/feed/</wfw:commentRss>
			<slash:comments>11</slash:comments>
		
		
			<enclosure url="https://blogs.sas.com/content/sasdummy/files/2012/10/ipout-150x150.png" />
	</item>
		<item>
		<title>Through the years: SAS Enterprise Guide versions</title>
		<link>https://blogs.sas.com/content/sasdummy/2020/08/25/eg-versions-through-years/</link>
					<comments>https://blogs.sas.com/content/sasdummy/2020/08/25/eg-versions-through-years/#comments</comments>
		
		<dc:creator><![CDATA[Chris Hemedinger]]></dc:creator>
		<pubDate>Tue, 25 Aug 2020 17:00:08 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[SAS 9.4]]></category>
		<category><![CDATA[SAS Enterprise Guide]]></category>
		<category><![CDATA[SGPLOT]]></category>
		<guid isPermaLink="false">http://blogs.sas.com/content/sasdummy/?p=3819</guid>

					<description><![CDATA[<p>My colleague Rick Wicklin maintains a nifty chart that shows the timeline of SAS releases since Version 8. A few of you asked if I could post a similar chart for SAS Enterprise Guide. Here it is. Like Rick, I used new features in SAS 9.4 to produce this chart [...]</p>
<p>The post <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy/2020/08/25/eg-versions-through-years/">Through the years: SAS Enterprise Guide versions</a> appeared first on <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy">The SAS Dummy</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>My colleague Rick Wicklin maintains <a href="https://blogs.sas.com/content/iml/2013/08/02/how-old-is-your-version-of-sas-release-dates-for-sas-software/" title="SAS releases since 1999">a nifty chart that shows the timeline of SAS releases</a> since Version 8.  A few of you asked if I could post a similar chart for SAS Enterprise Guide.  Here it is.  Like Rick, I used new features in SAS 9.4 to produce this chart (in fact, I cribbed heavily from his code)...but I used SAS Enterprise Guide to run the program.</p>
<p><em><strong>Update 25Aug2020</strong>: I've updated the graph and code in this post for the most recent versions of SAS Enterprise Guide and SAS. I also gave the chart a branding facelift, switching to the light-on-dark theme named "Raven". It's a personal preference influenced by today's trends -- but it's not economical on printer ink if you decide you want a hard copy.</em></p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2020/08/egversions3.png"><img src="https://blogs.sas.com/content/sasdummy/files/2020/08/egversions3.png" alt="EG versions through the years" class="alignnone size-full wp-image-6959" /></a></p>
<p>You might notice that my chart is a bit busier than Rick's version.  As a <a href="https://blogs.sas.com/content/sasdummy/2013/08/02/sas94-eg-versions/" title="Cross version magic">desktop client application that works across multiple SAS versions</a>, we tend to issue major releases of SAS Enterprise Guide more often than we update the core engine of SAS software.</p>
<p>On my chart, the labels on the data points indicate the "event" that motivated the release.  In some cases, we issued a new release to go with a new version of SAS (such as v1.2 with SAS 8.2).  In other cases, we "remastered" a version to support more languages or another operating system (such as Microsoft Vista support with v4.1 in 2007, or the <a href="http://en.wikipedia.org/wiki/L10n" title="what is L10N?">L10N release</a> of v4.3 in 2010).</p>
<p>You might also notice that some of these releases happened very close together.  Often, SAS R&amp;D works on updates to multiple releases in parallel.  Developers make changes to multiple versions to provide maintenance and hotfix changes (based on customer needs), while still contributing to the Next Big Version that will contain the compelling new features (based on customer wishes).</p>
<p>Here's the code that produced the chart:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="sas" style="font-family:monospace;"><span style="color: #000080; font-weight: bold;">data</span> Releases;
  <span style="color: #0000ff;">format</span> <span style="color: #0000ff;">Date</span> DATE7.;
  <span style="color: #0000ff;">input</span> Category $8. Release $7. <span style="color: #0000ff;">Date</span> DATE9. Details $15.;
  datalines;
Ancient <span style="color: #2e8b57; font-weight: bold;">1.0</span>    01Nov1999 SAS <span style="color: #2e8b57; font-weight: bold;">8.0</span>
Ancient <span style="color: #2e8b57; font-weight: bold;">1.1</span>    01Jul2000 SAS <span style="color: #2e8b57; font-weight: bold;">8.1</span>
Ancient <span style="color: #2e8b57; font-weight: bold;">1.2</span>    01Apr2001 SAS <span style="color: #2e8b57; font-weight: bold;">8.2</span>
Ancient <span style="color: #2e8b57; font-weight: bold;">1.3</span>    01Sep2001 
Ancient <span style="color: #2e8b57; font-weight: bold;">2.0</span>    01Sep2002 
Ancient <span style="color: #2e8b57; font-weight: bold;">2.05</span>   01May2003 SAS <span style="color: #2e8b57; font-weight: bold;">9.0</span>
Ancient <span style="color: #2e8b57; font-weight: bold;">2.1</span>    01Apr2004 SAS <span style="color: #2e8b57; font-weight: bold;">9.1</span>
Ancient <span style="color: #2e8b57; font-weight: bold;">3.0</span>    01May2004 .NET rewrite
Ancient <span style="color: #2e8b57; font-weight: bold;">3.02</span>   01Feb2005 remaster/L10N
Ancient <span style="color: #2e8b57; font-weight: bold;">4.1</span>    01Mar2006 
Ancient 4.1v   01Apr2007 Vista
Ancient <span style="color: #2e8b57; font-weight: bold;">4.2</span>    01Mar2009 SAS <span style="color: #2e8b57; font-weight: bold;">9.2</span>
Ancient <span style="color: #2e8b57; font-weight: bold;">4.22</span>   01Sep2009 SAS 9.2m2
Old     <span style="color: #2e8b57; font-weight: bold;">4.3</span>    01Aug2010
Old     4.305l 01Sep2010 L10N
Old     4.305r 01Jul2011 SAS <span style="color: #2e8b57; font-weight: bold;">9.3</span>
Old     <span style="color: #2e8b57; font-weight: bold;">5.1</span>    01Feb2012
Old     <span style="color: #2e8b57; font-weight: bold;">6.1</span>    01Jul2013 SAS <span style="color: #2e8b57; font-weight: bold;">9.4</span>
Old     <span style="color: #2e8b57; font-weight: bold;">7.1</span>    01Oct2014 
Old     <span style="color: #2e8b57; font-weight: bold;">7.11</span>   01May2015
Old     <span style="color: #2e8b57; font-weight: bold;">7.12</span>   01Feb2016
Old     <span style="color: #2e8b57; font-weight: bold;">7.13</span>   01Nov2016 SAS 9.4m4
Recent  <span style="color: #2e8b57; font-weight: bold;">7.15</span>   01Sep2017 SAS 9.4m5
Recent  <span style="color: #2e8b57; font-weight: bold;">8.1</span>    01Jun2019 Redesign
Recent  <span style="color: #2e8b57; font-weight: bold;">8.2</span>    01Nov2019
Recent  <span style="color: #2e8b57; font-weight: bold;">8.3</span>    18Aug2020 SAS 9.4m7
;
&nbsp;
<span style="color: #006400; font-style: italic;">/* running in SAS EG - modify active ODS to add title to graph */</span>
ods html5<span style="color: #66cc66;">&#40;</span>id=eghtml<span style="color: #66cc66;">&#41;</span> style=raven gtitle;
&nbsp;
ods graphics / height=<span style="color: #2e8b57; font-weight: bold;">850</span> width=<span style="color: #2e8b57; font-weight: bold;">1200</span> ;
<span style="color: #0000ff;">title</span> font=<span style="color: #a020f0;">&quot;AvenirNextforSAS Light&quot;</span> height=<span style="color: #2e8b57; font-weight: bold;">2.2</span> 
  <span style="color: #a020f0;">&quot;SAS Enterprise Guide Releases (1999-2020)&quot;</span>;
<span style="color: #000080; font-weight: bold;">proc sgplot</span> <span style="color: #000080; font-weight: bold;">data</span>=Releases noautolegend;
  styleattrs datacolors=<span style="color: #66cc66;">&#40;</span>red yellow green<span style="color: #66cc66;">&#41;</span>;
  block <span style="color: #0000ff;">x</span>=<span style="color: #0000ff;">date</span> block=category / transparency = <span style="color: #2e8b57; font-weight: bold;">0.75</span> 
     valueattrs=<span style="color: #66cc66;">&#40;</span>weight=bold size=14pt color=yellow 
      family=<span style="color: #a020f0;">'AvenirNextforSAS Light'</span><span style="color: #66cc66;">&#41;</span>;
  scatter <span style="color: #0000ff;">x</span>=<span style="color: #0000ff;">date</span> y=release / datalabel=Details 
    datalabelpos=topleft dataskin=matte
    datalabelattrs=<span style="color: #66cc66;">&#40;</span>size=10pt weight=bold<span style="color: #66cc66;">&#41;</span>
    markerattrs=<span style="color: #66cc66;">&#40;</span>symbol=CircleFilled size=<span style="color: #2e8b57; font-weight: bold;">14</span><span style="color: #66cc66;">&#41;</span>;
  xaxis grid type=<span style="color: #0000ff;">time</span> offsetmax=<span style="color: #2e8b57; font-weight: bold;">0.1</span> offsetmin=<span style="color: #2e8b57; font-weight: bold;">0</span> 
        ranges=<span style="color: #66cc66;">&#40;</span><span style="color: #a020f0;">'01Jan1998'</span>d-<span style="color: #a020f0;">'01Jan2021'</span>d<span style="color: #66cc66;">&#41;</span> <span style="color: #0000ff;">display</span>=<span style="color: #66cc66;">&#40;</span>nolabel<span style="color: #66cc66;">&#41;</span> ;
  yaxis type=discrete grid offsetmax=<span style="color: #2e8b57; font-weight: bold;">0.1</span> 
    <span style="color: #0000ff;">label</span>=<span style="color: #a020f0;">&quot;Release/Event&quot;</span>;
  inset <span style="color: #a020f0;">&quot;Updated &amp;SYSDATE9.&quot;</span> / 
     textattrs=<span style="color: #66cc66;">&#40;</span>weight=bold<span style="color: #66cc66;">&#41;</span> position=bottomright;
<span style="color: #000080; font-weight: bold;">run</span>;</pre></td></tr></table></div>

<p>The post <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy/2020/08/25/eg-versions-through-years/">Through the years: SAS Enterprise Guide versions</a> appeared first on <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy">The SAS Dummy</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=xlHRYNlHjoc:21lFz1vy-Uo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=xlHRYNlHjoc:21lFz1vy-Uo:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=xlHRYNlHjoc:21lFz1vy-Uo:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=xlHRYNlHjoc:21lFz1vy-Uo:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=xlHRYNlHjoc:21lFz1vy-Uo:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=xlHRYNlHjoc:21lFz1vy-Uo:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=xlHRYNlHjoc:21lFz1vy-Uo:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=xlHRYNlHjoc:21lFz1vy-Uo:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=xlHRYNlHjoc:21lFz1vy-Uo:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=xlHRYNlHjoc:21lFz1vy-Uo:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=TzevzKxY174" border="0"></img></a>
</div>]]></content:encoded>
					
					<wfw:commentRss>https://blogs.sas.com/content/sasdummy/2020/08/25/eg-versions-through-years/feed/</wfw:commentRss>
			<slash:comments>12</slash:comments>
		
		
			<enclosure url="https://blogs.sas.com/content/sasdummy/files/2020/08/egversions3-150x150.png" />
	</item>
		<item>
		<title>Using SAS with Microsoft 365 (OneDrive, Teams, and SharePoint)</title>
		<link>https://blogs.sas.com/content/sasdummy/2020/07/09/sas-programming-office-365-onedrive/</link>
					<comments>https://blogs.sas.com/content/sasdummy/2020/07/09/sas-programming-office-365-onedrive/#comments</comments>
		
		<dc:creator><![CDATA[Chris Hemedinger]]></dc:creator>
		<pubDate>Thu, 09 Jul 2020 12:00:33 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Developers]]></category>
		<category><![CDATA[Microsoft Office 365]]></category>
		<category><![CDATA[OAuth2]]></category>
		<category><![CDATA[OneDrive]]></category>
		<category><![CDATA[PROC HTTP]]></category>
		<category><![CDATA[REST API]]></category>
		<category><![CDATA[SharePoint]]></category>
		<guid isPermaLink="false">https://blogs.sas.com/content/sasdummy/?p=6683</guid>

					<description><![CDATA[<p>Learn how to use SAS code (PROC HTTP) to read and write files from your Microsoft OneDrive, Microsoft Teams or SharePoint Online. You'll learn how to create a Microsoft Office 365 app, connect to it with SAS, and automate the integration with your office productivity environment.</p>
<p>The post <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy/2020/07/09/sas-programming-office-365-onedrive/">Using SAS with Microsoft 365 (OneDrive, Teams, and SharePoint)</a> appeared first on <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy">The SAS Dummy</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>If your work environment is like ours here at SAS, you're seeing more of your data and applications move to the cloud.  It's not yet a complete replacement for having local files on your desktop machine, but with cloud storage and apps -- like Microsoft OneDrive -- I can now access my work documents from any browser and any device, including my smartphone.  I can update now my spreadsheets while waiting in the dentist office. Oh joy.</p>
<p>For those of us who use SAS to read and create Microsoft Excel documents, cloud-based files can add an extra wrinkle when we automate the process.  It also adds some exciting possibilities!  The Microsoft 365 suite offers APIs to discover, fetch, and update our documents using code.  In this article, I'll show you how to use SAS programs to reach into your Microsoft OneDrive (or SharePoint Online) cloud to read and update your files.  <strong>Note:</strong> All of this assumes that you already have a Microsoft 365 account -- perhaps provisioned by your IT support team -- and that you're using it to manage your documents.</p>
<p>Before I go on, I have to give <strong>major credit</strong> to Joseph Henry, the SAS developer who maintains PROC HTTP.  Joseph did the heavy lifting for putting together the code and examples in this article.  He also regularly adds new features to PROC HTTP that make it a more natural fit for calling REST APIs that require special authentication flows, such as OAuth2.</p>
<p><strong>Note: </strong>I've updated this article several times to include detailed steps and "gotchas." I've added use cases for SharePoint Online and Microsoft Teams.  I wrote <a href="https://www.sas.com/content/dam/SAS/support/en/sas-global-forum-proceedings/2020/4439-2020.pdf">a comprehensive paper for SAS Global Forum 2020</a>.  And <a href="https://communities.sas.com/t5/SAS-Communities-Library/How-to-use-SAS-to-access-Microsoft-365/ta-p/667869" rel="noopener noreferrer" target="_blank">I also recorded a 25-minute video</a> (posted on SAS Support Communities) that shows all of the steps that I followed.  </p>
<div id="attachment_7012" style="width: 310px" class="wp-caption alignnone"><a href="https://communities.sas.com/t5/SAS-Communities-Library/How-to-use-SAS-to-access-Microsoft-365/ta-p/667869"><img aria-describedby="caption-attachment-7012" loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2018/11/ms365_video-300x180.png" alt="" width="300" height="180" class="size-medium wp-image-7012" srcset="https://blogs.sas.com/content/sasdummy/files/2018/11/ms365_video-300x180.png 300w, https://blogs.sas.com/content/sasdummy/files/2018/11/ms365_video-1024x616.png 1024w, https://blogs.sas.com/content/sasdummy/files/2018/11/ms365_video.png 1295w" sizes="(max-width: 300px) 100vw, 300px" /></a><p id="caption-attachment-7012" class="wp-caption-text">Click to watch the video tutorial.</p></div>
<h2>Using SAS with Microsoft 365: an overview</h2>
<p>Microsoft 365 uses an OAuth2-style authentication flow to grant access and permissions to third-party apps.  If you're accustomed to the simpler style of just user/password authentication (ah, those were the days), OAuth2 can be intimidating.  Joseph Henry does a great <a href="http://support.sas.com/resources/papers/proceedings17/SAS0224-2017.pdf">job of deconstructing OAuth2 -- with code samples -- in this SAS Global Forum paper</a>.</p>
<p>When we're writing SAS programs to access Microsoft OneDrive or SharePoint, we're actually writing a third-party app.  This requires several setup steps, a few of which cannot be automated.  Fortunately, these need to be done just once, or at least infrequently.  Here's an outline of the steps:</p>
<ol>
<li>Register a new client application at <a href="https://portal.azure.com/">the Microsoft Azure Portal</a>.  (You will need to sign in with your Microsoft 365 credentials, which might be your primary organization credentials if you have single-signon with Active Directory.)
</li>
<li>Using your browser while you are signed into Microsoft 365, navigate to a special web address to obtain an authorization code for your application.
</li>
<li>With your authorization code in hand, plug this into a SAS program (PROC HTTP step) to retrieve an OAuth2 access token (and a refresh token).
</li>
<li>With the access token, you can now use PROC HTTP and the Microsoft 365 APIs to retrieve your OneDrive folders and files, download files, upload files, and replace files.
</li>
</ol>
<p>You'll have to complete Step 1 just once for your application or project.  Steps 2 and 3 can be done just once, or at least just occasionally.  The access token is valid for a limited time (usually 1 hour), but you can always exchange the refresh token for a new valid access token.  This refresh token step can be automated in your program, usually run just once per session.  Occasionally that refresh token can be revoked (and thus made invalid) when certain events occur (such as you changing your account password).  When that happens, you'll need to repeat steps 2 and 3 to get a new set of access/refresh tokens.</p>
<p>Oh, and by the way, even though the examples in this article are specific to OneDrive, the exact same authentication flow and steps can be used for all of the Microsoft 365 APIs.  Have fun with Outlook, Teams, Excel, and all of your favorite cloud-based Microsoft apps.</p>
<h2>Step 1: Register your application</h2>
<p>Visit the <a href="https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade">Microsoft Application Registration portal</a> to register your new app.  You'll sign in with your Microsoft 365 credentials. </p>
<div id="attachment_6690" style="width: 668px" class="wp-caption alignnone"><a href="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_reg.png"><img aria-describedby="caption-attachment-6690" loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_reg.png" alt="" width="658" height="356" class="size-full wp-image-6690" srcset="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_reg.png 658w, https://blogs.sas.com/content/sasdummy/files/2018/11/azure_reg-300x162.png 300w" sizes="(max-width: 658px) 100vw, 658px" /></a><p id="caption-attachment-6690" class="wp-caption-text">Microsoft Application Registration portal</p></div>
<p>Click <strong>New Registration</strong> to get started.  This presents you with a form where you can complete the details that define your app.  Mainly, you're giving it a name and defining its scope.  You'll probably want to limit its use to just your organization (your company) unless you're collaborating with colleagues who work elsewhere.</p>
<div id="attachment_6997" style="width: 739px" class="wp-caption alignnone"><a href="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_reg-1.png"><img aria-describedby="caption-attachment-6997" loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_reg-1.png" alt="" width="729" height="480" class="size-full wp-image-6997" srcset="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_reg-1.png 729w, https://blogs.sas.com/content/sasdummy/files/2018/11/azure_reg-1-300x198.png 300w, https://blogs.sas.com/content/sasdummy/files/2018/11/azure_reg-1-214x140.png 214w" sizes="(max-width: 729px) 100vw, 729px" /></a><p id="caption-attachment-6997" class="wp-caption-text">"Register an application" form</p></div>
<p>As you register your application, you also need to provide a redirect URL for the authorization flow.  In our example, our app is considered "Public client/native (mobile/desktop)."  The standard URL to indicate this is:<br />
<pre>
 https://login.microsoftonline.com/common/oauth2/nativeclient 
</pre></p>
<p>In the Redirect URI section, select this option and specify this URL value.</p>
<div id="attachment_7000" style="width: 964px" class="wp-caption alignnone"><a href="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_reg_url.png"><img aria-describedby="caption-attachment-7000" loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_reg_url.png" alt="" width="954" height="167" class="size-full wp-image-7000" srcset="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_reg_url.png 954w, https://blogs.sas.com/content/sasdummy/files/2018/11/azure_reg_url-300x53.png 300w" sizes="(max-width: 954px) 100vw, 954px" /></a><p id="caption-attachment-7000" class="wp-caption-text">Redirect URI Selections</p></div>
<p>When you create an app, you'll receive a Client ID (unique to your app) and Tenant ID (unique to your organization).  You'll need these values to obtain your authorization code and tokens later.  The application portal provides a sort of control center for all aspects of your app.  (Note: I masked out my client ID and tenant ID in this screenshot.)</p>
<div id="attachment_6693" style="width: 837px" class="wp-caption alignnone"><a href="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_app_details.png"><img aria-describedby="caption-attachment-6693" loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_app_details.png" alt="" width="827" height="503" class="size-full wp-image-6693" srcset="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_app_details.png 827w, https://blogs.sas.com/content/sasdummy/files/2018/11/azure_app_details-300x182.png 300w" sizes="(max-width: 827px) 100vw, 827px" /></a><p id="caption-attachment-6693" class="wp-caption-text">Details for my sample application</p></div>
<h3>Specifying your app permissions</h3>
<p>Your app will need specific permissions in order to function.  In my example, I want my SAS program to read documents from my OneDrive, and also add new docs and update existing docs.  The permissions I need are:</p>
<ul>
<li><strong>Files.ReadWrite.All</strong>: Allows the app to read, create, update and delete all OneDrive files that you can access.
</li>
<li><strong>User.Read</strong>: Allows you to sign in to the app with your organizational account and let the app read your profile.
</li>
<li><strong>Sites.ReadWrite.All</strong> (if using SharePoint): Allows the app to read, create, update and delete SharePoint Online files for sites that you can access.
</li>
</ul>
<p>To add these to your app, click the API Permissions tab in the control center.  To be clear, these are not permissions that your app will automatically <em>have</em>.  These are the permissions that will be <em>requested</em> when you "sign into" the app for the first time, and that you'll have to agree to in order for the app to run. </p>
<div id="attachment_7003" style="width: 712px" class="wp-caption alignnone"><a href="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_api_perm.png"><img aria-describedby="caption-attachment-7003" loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_api_perm-1024x433.png" alt="" width="702" height="297" class="size-large wp-image-7003" srcset="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_api_perm-1024x433.png 1024w, https://blogs.sas.com/content/sasdummy/files/2018/11/azure_api_perm-300x127.png 300w, https://blogs.sas.com/content/sasdummy/files/2018/11/azure_api_perm.png 1157w" sizes="(max-width: 702px) 100vw, 702px" /></a><p id="caption-attachment-7003" class="wp-caption-text">Adding permissions that the app needs</p></div>
<p>Permission types have their own terminology that is important to understand:</p>
<ul>
<li>
<strong>Delegated versus Application Permissions</strong>: In our example, we are sticking to <strong>Delegated</strong> permissions, which allow the application to take actions on behalf of the signed-in user and provides access to the user's data.  However, some use cases require use of <strong>Application </strong>permissions, which allow the application to take actions without a signed-in user and potentially access data across the system and different users.
</li>
<li>
<strong>Admin Consent Required</strong>: Some permissions cannot be delegated or granted without the approval of an administrator.  This restriction permits the organization to maintain oversight of the important resources that might be accessed by the application and to prevent unauthorized uses.  The Microsoft Azure Portal provides an easy way for you to submit a request to an admin, so you can get the permissions that you need. However, I recommend that you follow up (or better yet, precede this) with a formal request to your IT support staff to state what you need and your business case.  In my experience, this helps to expedite the process. A good working relationship with IT is important for any SAS user!
</li>
</ul>
<p>The <a href="https://docs.microsoft.com/en-us/graph/permissions-reference">documentation for the Microsoft Graph API</a> provides a comprehensive list of the permission names, whether they are Delegated or Application level, and whether Admin Consent is required.  This documentation also includes a helpful 4-minute video on the topic.</p>
<h4>Possibly required: Obtaining admin consent</h4>
<p>We're creating an app that hooks into your enterprise productivity suite -- and that's usually the domain of IT professionals.  At SAS we are a tech company with many "citizen app developers", so our IT grants us more latitude than you might find at other places.  But even at SAS, "normal" employees can't just create apps and empower them with access to our data. We have a process.</p>
<p>Because it's a common request, our IT folks created a form that makes it easy for them to review requests for new apps in our Microsoft 365 environment.  The form asks:</p>
<ul>
<li>Your app name (“SAS via PROC HTTP” for mine)
</li>
<li>Your App (client) ID
</li>
<li>Grant type – my instructions assume "Authorization code grant type"
</li>
<li>Whether you need additional Delegated API permissions: Most need 'Files.ReadWrite.All' for OneDrive, 'Sites.ReadWrite.All' for SharePoint (in addition to the default 'User.Read').
</li>
<li>Whether your app needs Application Permissions.  (Note: Answering YES here will trigger more scrutiny.)
</li>
</ul>
<h3>Creating a configuration file</h3>
<p>There are a few app-specific values that we'll need to reference throughout the SAS programs we're writing.  I decided to create a configuration file for these settings rather than hard-code them into my SAS statements.  This will make it easier for other people to reuse my code in their own applications.</p>
<p>I created a file named config.json that looks like this (but with different tenant_id and client_id values):<br />
<pre>
{
  &quot;tenant_id&quot;: &quot;206db638-6adb-41b9-b20c-95d8d04abcbe&quot;,
  &quot;client_id&quot;: &quot;8fb7804a-8dfd-40d8-bf5b-d02c2cbc56f3&quot;,
  &quot;redirect_uri&quot;: &quot;https://login.microsoftonline.com/common/oauth2/nativeclient&quot;,
  &quot;resource&quot; : &quot;https://graph.microsoft.com&quot;
}
</pre></p>
<p>By "externalizing" the IDs specific to my account/instance, I can use SAS code to read the values at run time.  <strong>Note:</strong> This code, like all of the code in this article, uses features from SAS 9.4 Maintenance 5.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="sas" style="font-family:monospace;"><span style="color: #006400; font-style: italic;">/*
  Set the variables that will be needed through the code
  We'll need these for authorization and also for runtime 
  use of the service.
&nbsp;
  Reading these from a config.json file so that the values
  are easy to adapt for different users or projects.
*/</span>
&nbsp;
<span style="color: #0000ff;">%if</span> %symexist<span style="color: #66cc66;">&#40;</span>config_root<span style="color: #66cc66;">&#41;</span> <span style="color: #0000ff;">%then</span> <span style="color: #0000ff;">%do</span>;
  <span style="color: #0000ff;">filename</span> config <span style="color: #a020f0;">&quot;&amp;config_root./config.json&quot;</span>;
  <span style="color: #0000ff;">libname</span> config json <span style="color: #0000ff;">fileref</span>=config;
  <span style="color: #000080; font-weight: bold;">data</span> <span style="color: #0000ff;">_null_</span>;
   <span style="color: #0000ff;">set</span> config.root;
   <span style="color: #0000ff;">call</span> symputx<span style="color: #66cc66;">&#40;</span><span style="color: #a020f0;">'tenant_id'</span>,tenant_id,<span style="color: #a020f0;">'G'</span><span style="color: #66cc66;">&#41;</span>;
   <span style="color: #0000ff;">call</span> symputx<span style="color: #66cc66;">&#40;</span><span style="color: #a020f0;">'client_id'</span>,client_id,<span style="color: #a020f0;">'G'</span><span style="color: #66cc66;">&#41;</span>;
   <span style="color: #0000ff;">call</span> symputx<span style="color: #66cc66;">&#40;</span><span style="color: #a020f0;">'redirect_uri'</span>,redirect_uri,<span style="color: #a020f0;">'G'</span><span style="color: #66cc66;">&#41;</span>;
   <span style="color: #0000ff;">call</span> symputx<span style="color: #66cc66;">&#40;</span><span style="color: #a020f0;">'resource'</span>,resource,<span style="color: #a020f0;">'G'</span><span style="color: #66cc66;">&#41;</span>;
  <span style="color: #000080; font-weight: bold;">run</span>;
<span style="color: #0000ff;">%end</span>;
<span style="color: #0000ff;">%else</span> <span style="color: #0000ff;">%do</span>;
  <span style="color: #0000ff;">%put</span> <span style="color: #ff0000;">ERROR</span>: You must define the CONFIG_ROOT macro variable.; 
<span style="color: #0000ff;">%end</span>;</pre></td></tr></table></div>

<h2>Step 2: Obtain an authorization code</h2>
<p>Now that I've defined the application, it's time to "sign into it" and grant it the permission to read and manage content in OneDrive.  This step needs to be completed from a web browser<strong> while I am signed into my Microsoft 365 account</strong>.  The web address is very long...but we can use a SAS program to generate it for us.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="sas" style="font-family:monospace;"><span style="color: #006400; font-style: italic;">/* location of my config file */</span>
<span style="color: #0000ff;">%let</span> config_root=/folders/myfolders/onedrive;
&nbsp;
%include <span style="color: #a020f0;">&quot;&amp;config_root./onedrive_config.sas&quot;</span>;
&nbsp;
<span style="color: #006400; font-style: italic;">/* Run this line to build the authorization URL */</span>
<span style="color: #0000ff;">%let</span> authorize_url=https://login.microsoftonline.com/<span style="color: #0000ff; font-weight: bold;">&amp;tenant_id</span>./oauth2/authorize?client_id=<span style="color: #0000ff; font-weight: bold;">&amp;client_id</span>.<span style="color: #0000ff;">%nrstr</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff; font-weight: bold;">&amp;response_type</span><span style="color: #66cc66;">&#41;</span>=code%nrstr<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff; font-weight: bold;">&amp;redirect_uri</span><span style="color: #66cc66;">&#41;</span>=<span style="color: #0000ff; font-weight: bold;">&amp;redirect_uri</span>.<span style="color: #0000ff;">%nrstr</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff; font-weight: bold;">&amp;resource</span><span style="color: #66cc66;">&#41;</span>=<span style="color: #0000ff; font-weight: bold;">&amp;resource</span>.;
<span style="color: #0000ff;">options</span> nosource;
<span style="color: #0000ff;">%put</span> Paste this URL <span style="color: #0000ff;">into</span> your web browser:;
<span style="color: #0000ff;">%put</span> -- START -------;
<span style="color: #0000ff;">%put</span> <span style="color: #0000ff; font-weight: bold;">&amp;authorize_url</span>;
<span style="color: #0000ff;">%put</span> ---<span style="color: #0000ff;">END</span> ---------;
<span style="color: #0000ff;">options</span> source;</pre></td></tr></table></div>

<p>This produces these output lines in the SAS log:<br />
<pre>
 Paste this URL into your web browser:
 -- START -------
https://login.microsoftonline.com/206db638-6adb-41b9-b20c-95d8d04abcbe/oauth2/authorize?client_id=8fb7804a-8dfd-40d8-bf5b-d02c2cbc56
f3&amp;response_type=code&amp;redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient&amp;resource=https://graph.microsoft.com
 ---END ---------
</pre></p>
<p>Copy and paste the URL (<strong>all on one line, no spaces</strong>) into the address bar of your web browser.  When you press Enter, you'll be prompted to grant the required permissions:</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_app_permissions.png"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_app_permissions.png" alt="" width="446" height="461" class="alignnone size-full wp-image-6688" srcset="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_app_permissions.png 446w, https://blogs.sas.com/content/sasdummy/files/2018/11/azure_app_permissions-290x300.png 290w" sizes="(max-width: 446px) 100vw, 446px" /></a></p>
<p>Once you click Accept, the browser will redirect to what <em>looks like</em> a blank page, but the URL contains the authorization code that we need:</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_access_code.png"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_access_code.png" alt="" width="1064" height="71" class="alignnone size-full wp-image-6698" /></a></p>
<p>Copy the value that appears after the <strong>code=</strong> in the URL, <strong>only up to</strong> the &amp;session= part.  It's going to be a very long string -- over 700 characters.  We'll need that value for the next step.</p>
<p><strong>Note:</strong> if you don't see the permissions prompt but instead see something like this:</p>
<div id="attachment_7006" style="width: 374px" class="wp-caption alignnone"><a href="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_need_admin.png"><img aria-describedby="caption-attachment-7006" loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_need_admin.png" alt="" width="364" height="238" class="size-full wp-image-7006" srcset="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_need_admin.png 364w, https://blogs.sas.com/content/sasdummy/files/2018/11/azure_need_admin-300x196.png 300w, https://blogs.sas.com/content/sasdummy/files/2018/11/azure_need_admin-214x140.png 214w" sizes="(max-width: 364px) 100vw, 364px" /></a><p id="caption-attachment-7006" class="wp-caption-text">App needs permission to access resources</p></div>
<p>Then you probably need to work with your IT support to grant consent for your app.  See the section "Possibly required: Obtaining admin consent" above.</p>
<h2>Step 3: Obtain an access token</h2>
<p>My colleague Joseph wrote a few convenient utility macros that can help manage the access token and refresh token within your SAS session.  These macros include:</p>
<ul>
<li>%get_token - get the initial access and refresh tokens, given an authorization code.  Remember, an access token will expire in about 60 minutes. But the refresh token can be used to get a renewed access token.
</li>
<li>%refresh - exchange a valid refresh token for a new access token
</li>
<li>%process_token_file - read/update an external token file so that these values persist beyond your current SAS session.</li>
</ul>
<p>I'm not going to walk through the macro code in this article, but the SAS programs are straightforward and well-documented.  See <a href="#sourcecode">"How to get this example code"</a> at the end of this article.</p>
<p>With these macros in place, we can paste the (very long) authorization code we retrieved in the previous step into a macro variable. Then we can run the <strong>%get_token</strong> macro to generate the tokens and store them in a local file.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="sas" style="font-family:monospace;"><span style="color: #0000ff;">%let</span> config_root=/folders/myfolders/onedrive;
&nbsp;
%include <span style="color: #a020f0;">&quot;&amp;config_root./onedrive_config.sas&quot;</span>;
%include <span style="color: #a020f0;">&quot;&amp;config_root./onedrive_macros.sas&quot;</span>;
&nbsp;
<span style="color: #0000ff;">filename</span> token <span style="color: #a020f0;">&quot;&amp;config_root./token.json&quot;</span>;
<span style="color: #0000ff;">%let</span> auth_code=AQABAAIAAAC5una0EUFgTIF8ElaxtWjTqwohjyfG; <span style="color: #006400; font-style: italic;">* and much more;</span>
&nbsp;
<span style="color: #006400; font-style: italic;">/*
  Now that we have an authorization code we can get the access token
  This step will write the tokens.json file that we can use in our
  production programs.
*/</span>
%get_token<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff; font-weight: bold;">&amp;client_id</span>.,<span style="color: #0000ff; font-weight: bold;">&amp;auth_code</span>,<span style="color: #0000ff; font-weight: bold;">&amp;resource</span>.,token,tenant=<span style="color: #0000ff; font-weight: bold;">&amp;tenant_id</span><span style="color: #66cc66;">&#41;</span>;</pre></td></tr></table></div>

<p>Running this step will create a new file, token.json, in your designated config folder.  Here's an screenshot of what my version looks like right now: </p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_token.png"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_token.png" alt="" width="549" height="320" class="alignnone size-full wp-image-6712" srcset="https://blogs.sas.com/content/sasdummy/files/2018/11/azure_token.png 549w, https://blogs.sas.com/content/sasdummy/files/2018/11/azure_token-300x175.png 300w" sizes="(max-width: 549px) 100vw, 549px" /></a></p>
<p>It's <strong>very important</strong> that you keep this file secure.  With the information in this file (your refresh token) and your conf.json file (with your client ID and tenant ID), anyone can use these code techniques to impersonate you and access your Microsoft 365 data.  <a href="https://blogs.sas.com/content/sasdummy/2018/01/16/hide-rest-api-tokens/">There are techniques for storing these files such that only you can see them</a>.</p>
<h2>Using Microsoft 365 APIs to access OneDrive from SAS</h2>
<p>Whew!  I've spent nearly 1500 words to get this far, so thanks for sticking with me.  The good news is that these steps take much longer to describe than to actually execute.  Plus, creating apps is fun! (Right?)</p>
<p>From the screenshots I've shared, you probably already noticed that these services are working on Microsoft Azure, which is Microsoft's cloud platform for applications. For the remainder of this article, I'll be using methods from <a href="https://developer.microsoft.com/en-us/graph">the Microsoft Graph API</a>.  This REST-based API provides access to almost all of Microsoft's hosted services.  For my examples, I'll be using methods within the <a href="https://docs.microsoft.com/en-us/graph/api/resources/onedrive?view=graph-rest-1.0">Files component of the API</a>: Drives and Drive Items (folders and files).   </p>
<p>You can explore and try the Microsoft 365 APIs <a href="https://developer.microsoft.com/en-us/graph/graph-explorer" rel="noopener noreferrer" target="_blank">with the Graph Explorer application</a> from Microsoft.  If you sign in with your own account, you can use the APIs with your own data.  This is a great way to try these APIs and discover the correct methods to use before implementing them in your SAS code.</p>
<div id="attachment_6956" style="width: 1056px" class="wp-caption alignnone"><a href="https://blogs.sas.com/content/sasdummy/files/2018/11/graphexplorer.png"><img aria-describedby="caption-attachment-6956" loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2018/11/graphexplorer.png" alt="" width="1046" height="604" class="size-full wp-image-6956" srcset="https://blogs.sas.com/content/sasdummy/files/2018/11/graphexplorer.png 1046w, https://blogs.sas.com/content/sasdummy/files/2018/11/graphexplorer-300x173.png 300w, https://blogs.sas.com/content/sasdummy/files/2018/11/graphexplorer-1024x591.png 1024w" sizes="(max-width: 1046px) 100vw, 1046px" /></a><p id="caption-attachment-6956" class="wp-caption-text">Example from a Graph Explorer session</p></div>
<h3>Initializing and refreshing the access token in a new session</h3>
<p>Now that we have the access and refresh tokens, we can get down to business with some actual OneDrive interactions.  Here's how to initialize your SAS session with the tokens.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="sas" style="font-family:monospace;"><span style="color: #0000ff;">%let</span> config_root=/folders/myfolders/onedrive;
&nbsp;
%include <span style="color: #a020f0;">&quot;&amp;config_root./onedrive_config.sas&quot;</span>;
%include <span style="color: #a020f0;">&quot;&amp;config_root./onedrive_macros.sas&quot;</span>;
&nbsp;
<span style="color: #006400; font-style: italic;">/*
  Our json file that contains the oauth token information
*/</span>
<span style="color: #0000ff;">filename</span> token <span style="color: #a020f0;">&quot;&amp;config_root./token.json&quot;</span>;
&nbsp;
%process_token_file<span style="color: #66cc66;">&#40;</span>token<span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #006400; font-style: italic;">/* If this is first use for the session, we'll likely need to refresh  */</span>
<span style="color: #006400; font-style: italic;">/* the token.  This will also call process_token_file again and update */</span>
<span style="color: #006400; font-style: italic;">/* our token.json file.                                                */</span>
%refresh<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff; font-weight: bold;">&amp;client_id</span>.,<span style="color: #0000ff; font-weight: bold;">&amp;refresh_token</span>.,<span style="color: #0000ff; font-weight: bold;">&amp;resource</span>.,token,tenant=<span style="color: #0000ff; font-weight: bold;">&amp;tenant_id</span>.<span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #006400; font-style: italic;">/*
  At this point we have a valid access token and we can start using the API.
*/</span></pre></td></tr></table></div>

<p>If all goes well, we'll have our access token, and it will be stored in a macro variable named <strong>&amp;access_token</strong>.  It's going to be another long and illegible (&gt;700 characters) value.</p>
<p>(Ever hear of the "infinite monkey theorem?" That a monkey hitting a typewriter for an infinite amount of time is certain to produce a certain text, such as the complete works of Shakespeare?  Well, that monkey is <strong>not</strong> going to produce this access token.  Plus, who has a typewriter anymore?)</p>
<h3>Retrieving the top-level drive identifier (OneDrive)</h3>
<p>We'll need to explore the OneDrive system from the top-down, using code.  First, we need the identifier for the root drive.  It's possible for you to have multiple root drives, and if that's the case for you, you'll need to modify this code a bit.  This code queries the service for your drives, and stores the identifier for just the first drive in a macro variable.  We'll need that identifier later to retrieve a list of top-level items.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="sas" style="font-family:monospace;"><span style="color: #006400; font-style: italic;">/*
First we need the ID of the &quot;drive&quot; we are going to use.
to list the drives the current user has access to you can do this
*/</span>
<span style="color: #0000ff;">filename</span> resp TEMP;
<span style="color: #006400; font-style: italic;">/* Note: oauth_bearer option added in 9.4M5 */</span>
<span style="color: #000080; font-weight: bold;">proc http</span> url=<span style="color: #a020f0;">&quot;https://graph.microsoft.com/v1.0/me/drives/&quot;</span>
     oauth_bearer=<span style="color: #a020f0;">&quot;&amp;access_token&quot;</span>
     out = resp;
	 <span style="color: #000080; font-weight: bold;">run</span>;
&nbsp;
<span style="color: #0000ff;">libname</span> jresp json <span style="color: #0000ff;">fileref</span>=resp;
&nbsp;
<span style="color: #006400; font-style: italic;">/*
 I only have access to 1 drive, but if you have multiple you can filter 
 the set with a where clause on the name value.
&nbsp;
 This creates a data set with the one record for the drive.
*/</span>
<span style="color: #000080; font-weight: bold;">data</span> drive;
 <span style="color: #0000ff;">set</span> jresp.value;
<span style="color: #000080; font-weight: bold;">run</span>;
&nbsp;
<span style="color: #006400; font-style: italic;">/* store the ID value for the drive in a macro variable */</span>
<span style="color: #000080; font-weight: bold;">proc sql</span> noprint;
 <span style="color: #0000ff;">select</span> id <span style="color: #0000ff;">into</span>: driveId <span style="color: #0000ff;">from</span> drive;
<span style="color: #000080; font-weight: bold;">quit</span>;</pre></td></tr></table></div>

<p>Note that this code uses the new OAUTH_BEARER option in PROC HTTP -- a convenient addition when working with OAuth2-compliant APIs.  This is shorthand -- and more intuitive syntax -- for placing "Authorization: Bearer TOKEN-VALUE" in the HTTP headers.</p>
<h3>Retrieving the top-level drive identifier (SharePoint Online)</h3>
<p>The steps for SharePoint Online are nearly the same as for OneDrive, except that we need to reference the site hostname (yoursite.sharepoint.com, for example) <a href="https://docs.microsoft.com/en-us/graph/api/resources/sharepoint?view=graph-rest-1.0" title="SharePoint resources for the Graph API" rel="noopener noreferrer" target="_blank">and the /sites resource</a> (instead of the /me/drives resource).</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="sas" style="font-family:monospace;"><span style="color: #006400; font-style: italic;">/* Note: oauth_bearer option added in 9.4M5                       */</span>
<span style="color: #006400; font-style: italic;">/* Using the /sites methods in the Microsoft Graph API            */</span>
<span style="color: #006400; font-style: italic;">/* May require the Sites.ReadWrite.All permission for your app    */</span>
<span style="color: #006400; font-style: italic;">/* Set these values per your SharePoint Online site.
   Ex: https://yourcompany.sharepoint.com/sites/YourSite 
    breaks down to:
       yourcompany.sharepoint.com -&gt; hostname
       /sites/YourSite -&gt; sitepath
   This example uses the /drive method to access the files on the
   Sharepoint site -- works just like OneDrive.
   API also supports a /lists method for SharePoint lists.
   Use the Graph Explorer app to find the correct APIs for your purpose.
    https://developer.microsoft.com/en-us/graph/graph-explorer
*/</span>
<span style="color: #0000ff;">%let</span> hostname = yourcompany.sharepoint.com;
<span style="color: #0000ff;">%let</span> sitepath = /sites/YourSite;
<span style="color: #000080; font-weight: bold;">proc http</span> url=<span style="color: #a020f0;">&quot;https://graph.microsoft.com/v1.0/sites/&amp;hostname.:&amp;sitepath.:/drive&quot;</span>
     oauth_bearer=<span style="color: #a020f0;">&quot;&amp;access_token&quot;</span>
     out = resp;
	 <span style="color: #000080; font-weight: bold;">run</span>;
&nbsp;
<span style="color: #0000ff;">libname</span> jresp json <span style="color: #0000ff;">fileref</span>=resp;
&nbsp;
<span style="color: #006400; font-style: italic;">/*
 This creates a data set with the one record for the drive.
 Need this object to get the Drive ID
*/</span>
<span style="color: #000080; font-weight: bold;">data</span> drive;
 <span style="color: #0000ff;">set</span> jresp.root;
<span style="color: #000080; font-weight: bold;">run</span>;
&nbsp;
<span style="color: #006400; font-style: italic;">/* store the ID value for the drive in a macro variable */</span>
<span style="color: #000080; font-weight: bold;">proc sql</span> noprint;
 <span style="color: #0000ff;">select</span> id <span style="color: #0000ff;">into</span>: driveId <span style="color: #0000ff;">from</span> drive;
<span style="color: #000080; font-weight: bold;">quit</span>;</pre></td></tr></table></div>

<h3>Retrieve a list of top-level folders/files</h3>
<p>With the drive identifier in hand (whether OneDrive or SharePoint), I can use the <a href="https://docs.microsoft.com/en-us/graph/api/driveitem-list-children?view=graph-rest-1.0">/children verb on the Microsoft Graph API</a> to get a list of all of the top-level objects in that drive.  These represent the folders and files that are at the root.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="sas" style="font-family:monospace;"><span style="color: #006400; font-style: italic;">/*
 To list the items in the drive, use the /children verb with the drive ID
*/</span>
<span style="color: #0000ff;">filename</span> resp TEMP;
<span style="color: #000080; font-weight: bold;">proc http</span> url=<span style="color: #a020f0;">&quot;https://graph.microsoft.com/v1.0/me/drives/&amp;driveId./items/root/children&quot;</span>
     oauth_bearer=<span style="color: #a020f0;">&quot;&amp;access_token&quot;</span>
     out = resp;
	 <span style="color: #000080; font-weight: bold;">run</span>;
&nbsp;
<span style="color: #0000ff;">libname</span> jresp json <span style="color: #0000ff;">fileref</span>=resp;
&nbsp;
<span style="color: #006400; font-style: italic;">/* Create a data set with the top-level paths/files in the drive */</span>
<span style="color: #000080; font-weight: bold;">data</span> paths;
 <span style="color: #0000ff;">set</span> jresp.value;
<span style="color: #000080; font-weight: bold;">run</span>;</pre></td></tr></table></div>

<p>Here's what I'm keeping in my OneDrive right now.  It's not too disorganized, is it?</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2018/11/onedrive_paths.png"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2018/11/onedrive_paths.png" alt="" width="763" height="440" class="alignnone size-full wp-image-6703" srcset="https://blogs.sas.com/content/sasdummy/files/2018/11/onedrive_paths.png 763w, https://blogs.sas.com/content/sasdummy/files/2018/11/onedrive_paths-300x173.png 300w" sizes="(max-width: 763px) 100vw, 763px" /></a></p>
<h3>List the files in a particular folder</h3>
<p>If I'm interested in exploring a particular folder, I'll need to find the folder identifier as it's known to OneDrive.  Using PROC SQL and SELECT INTO, I can find the folder by its name and store its ID in another macro variable.  Then, I use the /children verb again, but this time with the folder ID instead of the "root" constant.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="sas" style="font-family:monospace;"><span style="color: #006400; font-style: italic;">/*
 At this point, if you want to act on any of the items, you just replace &quot;root&quot; 
 with the ID of the item. So to list the items in the &quot;SASGF&quot; folder I have:
  - find the ID for that folder
  - list the items within by using the &quot;/children&quot; verb
*/</span>
&nbsp;
<span style="color: #006400; font-style: italic;">/* Find the ID of the folder I want */</span>
<span style="color: #000080; font-weight: bold;">proc sql</span> noprint;
 <span style="color: #0000ff;">select</span> id <span style="color: #0000ff;">into</span>: folderId <span style="color: #0000ff;">from</span> paths
  <span style="color: #0000ff;">where</span> name=<span style="color: #a020f0;">&quot;SASGF&quot;</span>;
<span style="color: #000080; font-weight: bold;">quit</span>;
&nbsp;
<span style="color: #0000ff;">filename</span> resp TEMP;
<span style="color: #000080; font-weight: bold;">proc http</span> url=<span style="color: #a020f0;">&quot;https://graph.microsoft.com/v1.0/me/drives/&amp;driveId./items/&amp;folderId./children&quot;</span>
     oauth_bearer=<span style="color: #a020f0;">&quot;&amp;access_token&quot;</span>
     out = resp;
	 <span style="color: #000080; font-weight: bold;">run</span>;
&nbsp;
<span style="color: #006400; font-style: italic;">/* This creates a data set of the items in that folder, 
   which might include other folders.
*/</span>
<span style="color: #0000ff;">libname</span> jresp json <span style="color: #0000ff;">fileref</span>=resp;
<span style="color: #000080; font-weight: bold;">data</span> folderItems;
 <span style="color: #0000ff;">set</span> jresp.value;
<span style="color: #000080; font-weight: bold;">run</span>;</pre></td></tr></table></div>

<p>Here are the items from my SASGF folder.  Can you tell that I don't throw anything away?</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2018/11/onedrive_folderitems.png"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2018/11/onedrive_folderitems.png" alt="" width="758" height="487" class="alignnone size-full wp-image-6704" srcset="https://blogs.sas.com/content/sasdummy/files/2018/11/onedrive_folderitems.png 758w, https://blogs.sas.com/content/sasdummy/files/2018/11/onedrive_folderitems-300x193.png 300w" sizes="(max-width: 758px) 100vw, 758px" /></a></p>
<h3>Download a file from OneDrive and import into SAS</h3>
<p>I know that I keep a spreadsheet named "sas_tech_talks_18.xlsx" in this SASGF folder.  With the /content verb, I can download the file from OneDrive and store it in the file system that is local to my SAS session.  Then, I can use PROC IMPORT to read it into a SAS data set.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="sas" style="font-family:monospace;"><span style="color: #006400; font-style: italic;">/*
 With a list of the items in this folder, we can download
 any item of interest by using the /content verb 
*/</span>
&nbsp;
<span style="color: #006400; font-style: italic;">/* Find the item with a certain name */</span>
<span style="color: #000080; font-weight: bold;">proc sql</span> noprint;
 <span style="color: #0000ff;">select</span> id <span style="color: #0000ff;">into</span>: fileId <span style="color: #0000ff;">from</span> folderItems
  <span style="color: #0000ff;">where</span> name=<span style="color: #a020f0;">&quot;sas_tech_talks_18.xlsx&quot;</span>;
<span style="color: #000080; font-weight: bold;">quit</span>;
&nbsp;
<span style="color: #0000ff;">filename</span> fileout <span style="color: #a020f0;">&quot;&amp;config_root./sas_tech_talks_18.xlsx&quot;</span>;
<span style="color: #000080; font-weight: bold;">proc http</span> url=<span style="color: #a020f0;">&quot;https://graph.microsoft.com/v1.0/me/drives/&amp;driveId./items/&amp;fileId./content&quot;</span>
     oauth_bearer=<span style="color: #a020f0;">&quot;&amp;access_token&quot;</span>
     out = fileout;
	 <span style="color: #000080; font-weight: bold;">run</span>;
&nbsp;
<span style="color: #006400; font-style: italic;">/* Import the first sheet into a SAS data set */</span>
<span style="color: #000080; font-weight: bold;">proc import</span> <span style="color: #0000ff;">file</span>=fileout 
 out=sasgf
 dbms=xlsx <span style="color: #0000ff;">replace</span>;
<span style="color: #000080; font-weight: bold;">run</span>;</pre></td></tr></table></div>

<p>Boom! I've just downloaded my data from the cloud and brought it into my SAS session.</p>
<h3>Add a new file to OneDrive</h3>
<p>We can build wonderful documents from SAS too, and it's important to be able to share those.  By using the PUT method with the /content verb, we can copy a file from the local SAS session into a target folder on OneDrive.  Most often, this will probably be an Excel spreadsheet or maybe a PDF report.  (But hey, maybe it's a good opportunity to try out <a href="https://go.documentation.sas.com/?docsetId=odsug&amp;docsetTarget=p10mxeb6wxqfjgn1p5u0w4t8qf20.htm&amp;docsetVersion=9.4&amp;locale=en" rel="noopener noreferrer">the new ODS WORD destination in SAS 9.4 Maint 6</a>?)</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="sas" style="font-family:monospace;"><span style="color: #006400; font-style: italic;">/*
  We can upload a new file to that same folder with the PUT method and /content verb
  Notice the : after the folderId and the target filename
*/</span>
&nbsp;
<span style="color: #006400; font-style: italic;">/* Create a simple Excel file to upload */</span>
<span style="color: #0000ff;">%let</span> targetFile=iris.xlsx;
<span style="color: #0000ff;">filename</span> tosave <span style="color: #a020f0;">&quot;%sysfunc(getoption(WORK))/&amp;targetFile.&quot;</span>;
ods excel<span style="color: #66cc66;">&#40;</span>id=upload<span style="color: #66cc66;">&#41;</span> <span style="color: #0000ff;">file</span>=tosave;
<span style="color: #000080; font-weight: bold;">proc print</span> <span style="color: #000080; font-weight: bold;">data</span>=sashelp.iris;
<span style="color: #000080; font-weight: bold;">run</span>;
ods excel<span style="color: #66cc66;">&#40;</span>id=upload<span style="color: #66cc66;">&#41;</span> <span style="color: #0000ff;">close</span>;
&nbsp;
<span style="color: #0000ff;">filename</span> details temp;
<span style="color: #000080; font-weight: bold;">proc http</span> url=<span style="color: #a020f0;">&quot;https://graph.microsoft.com/v1.0/me/drives/&amp;driveId./items/&amp;folderId.:/&amp;targetFile.:/content&quot;</span>
  method=<span style="color: #a020f0;">&quot;PUT&quot;</span>
  <span style="color: #0000ff;">in</span>=tosave
  out=details
  oauth_bearer=<span style="color: #a020f0;">&quot;&amp;access_token&quot;</span>;
<span style="color: #000080; font-weight: bold;">run</span>;
&nbsp;
<span style="color: #006400; font-style: italic;">/*
  This returns a json response that describes the item uploaded.
  This step pulls out the main file attributes from that response.
*/</span>
<span style="color: #0000ff;">libname</span> attrs json <span style="color: #0000ff;">fileref</span>=details;
<span style="color: #000080; font-weight: bold;">data</span> newfileDetails <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">keep</span>=<span style="color: #0000ff;">filename</span> createdDate modifiedDate filesize<span style="color: #66cc66;">&#41;</span>;
 <span style="color: #0000ff;">length</span> <span style="color: #0000ff;">filename</span> $ <span style="color: #2e8b57; font-weight: bold;">100</span> createdDate <span style="color: #2e8b57; font-weight: bold;">8</span> modifiedDate <span style="color: #2e8b57; font-weight: bold;">8</span> filesize <span style="color: #2e8b57; font-weight: bold;">8</span>;
 <span style="color: #0000ff;">set</span> attrs.root;
 <span style="color: #0000ff;">filename</span> = name;
 modifiedDate = <span style="color: #0000ff;">input</span><span style="color: #66cc66;">&#40;</span>lastModifiedDateTime,anydtdtm.<span style="color: #66cc66;">&#41;</span>;
 createdDate  = <span style="color: #0000ff;">input</span><span style="color: #66cc66;">&#40;</span>createdDateTime,anydtdtm.<span style="color: #66cc66;">&#41;</span>;
 <span style="color: #0000ff;">format</span> createdDate datetime20. modifiedDate datetime20.;
 filesize = size;
<span style="color: #000080; font-weight: bold;">run</span>;</pre></td></tr></table></div>

<h3>Replace/update a file in OneDrive</h3>
<p>If you want to replace an existing file, then you'll want to perform the additional step of retrieving the unique ID for that file from OneDrive.  When you PUT the new version of the file into place, its history and sharing properties should remain intact.  Here is my code for navigating the folder/file structure in my OneDrive and finally replacing an existing file.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="sas" style="font-family:monospace;"><span style="color: #006400; font-style: italic;">/*
  If you want to replace a file instead of making a new file 
  then you need to upload it with the existing file ID.  If you
  don't replace it with the existing ID, some sharing properties
  and history could be lost.
*/</span>
<span style="color: #006400; font-style: italic;">/* Create a simple Excel file to upload */</span>
<span style="color: #0000ff;">%let</span> targetFile=iris.xlsx;
<span style="color: #0000ff;">filename</span> tosave <span style="color: #a020f0;">&quot;%sysfunc(getoption(WORK))/&amp;targetFile.&quot;</span>;
ods excel<span style="color: #66cc66;">&#40;</span>id=upload<span style="color: #66cc66;">&#41;</span> <span style="color: #0000ff;">file</span>=tosave;
<span style="color: #000080; font-weight: bold;">proc print</span> <span style="color: #000080; font-weight: bold;">data</span>=sashelp.iris;
<span style="color: #000080; font-weight: bold;">run</span>;
ods excel<span style="color: #66cc66;">&#40;</span>id=upload<span style="color: #66cc66;">&#41;</span> <span style="color: #0000ff;">close</span>;
&nbsp;
<span style="color: #006400; font-style: italic;">/* Navigate the folder and file IDs from my OneDrive */</span>
<span style="color: #000080; font-weight: bold;">proc sql</span> noprint;
 <span style="color: #0000ff;">select</span> id <span style="color: #0000ff;">into</span>: folderId <span style="color: #0000ff;">from</span> paths
  <span style="color: #0000ff;">where</span> name=<span style="color: #a020f0;">&quot;SASGF&quot;</span>;
<span style="color: #000080; font-weight: bold;">quit</span>;
&nbsp;
<span style="color: #000080; font-weight: bold;">proc http</span> url=<span style="color: #a020f0;">&quot;https://graph.microsoft.com/v1.0/me/drives/&amp;driveId./items/&amp;folderId./children&quot;</span>
     oauth_bearer=<span style="color: #a020f0;">&quot;&amp;access_token&quot;</span>
     out = resp;
	 <span style="color: #000080; font-weight: bold;">run</span>;
&nbsp;
<span style="color: #0000ff;">libname</span> jresp json <span style="color: #0000ff;">fileref</span>=resp;
<span style="color: #000080; font-weight: bold;">data</span> folderItems;
 <span style="color: #0000ff;">set</span> jresp.value;
<span style="color: #000080; font-weight: bold;">run</span>;
&nbsp;
<span style="color: #006400; font-style: italic;">/* Find the ID of the existing file */</span>
<span style="color: #000080; font-weight: bold;">proc sql</span> noprint;
 <span style="color: #0000ff;">select</span> id <span style="color: #0000ff;">into</span>: fileId <span style="color: #0000ff;">from</span> folderItems
  <span style="color: #0000ff;">where</span> name=<span style="color: #a020f0;">&quot;iris.xlsx&quot;</span>;
<span style="color: #000080; font-weight: bold;">quit</span>;
&nbsp;
<span style="color: #0000ff;">libname</span> attrs json <span style="color: #0000ff;">fileref</span>=details;
<span style="color: #000080; font-weight: bold;">proc http</span> url=<span style="color: #a020f0;">&quot;https://graph.microsoft.com/v1.0/me/drives/&amp;driveId./items/&amp;fileId./content&quot;</span>
 method=<span style="color: #a020f0;">&quot;PUT&quot;</span>
 <span style="color: #0000ff;">in</span>=tosave
 out=details
 oauth_bearer=<span style="color: #a020f0;">&quot;&amp;access_token&quot;</span>;
<span style="color: #000080; font-weight: bold;">run</span>;</pre></td></tr></table></div>

<p>As you can see from my OneDrive history for this file, I've tested this program a few times -- resulting in 23 revisions of this file in its history!</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2018/11/onedrive_iris_history.png"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2018/11/onedrive_iris_history.png" alt="" width="1017" height="505" class="alignnone size-full wp-image-6706" srcset="https://blogs.sas.com/content/sasdummy/files/2018/11/onedrive_iris_history.png 1017w, https://blogs.sas.com/content/sasdummy/files/2018/11/onedrive_iris_history-300x149.png 300w, https://blogs.sas.com/content/sasdummy/files/2018/11/onedrive_iris_history-164x82.png 164w" sizes="(max-width: 1017px) 100vw, 1017px" /></a></p>
<p><a name="sourcecode"></a> </p>
<h2>How to get this example code</h2>
<p>You can <a href="https://github.com/sascommunities/sas-dummy-blog/tree/master/onedrive">find the source files for these examples on GitHub</a>.</p>
<p>I've organized this code into 5 different files in order to make it easy to reuse:</p>
<ul>
<li>onedrive_config.sas - read the fields from the conf.json and set them as global macro variables.  This includes your client_id and tenant_id.
</li>
<li>onedrive_setup.sas - the SAS statements that represent code you will need to run just once to get your authorization code and first access code.
</li>
<li>onedrive_macros.sas - three utility macros that help you to create, refresh, and manage your access token and refresh token in your token.json file
</li>
<li>onedrive_example_use.sas - sample SAS steps that I used in this article.  They won't quite work for you as-is, since you don't have the same files that I do. (Unless <em>you do</em> have the same files, in which case...creepy.)  My hope is that you can read and adapt them for your own content.
</li>
<li>onedrive_sharepoint_example.sas - sample SAS steps for reading and writing files with SharePoint Online.  The basic steps are the same as for OneDrive, except that you use the /sites resource instead of the OneDrive-specific methods.
</li>
</ul>
<p>I also included a template for the conf.json file, with obvious placeholders for the client_id and tenant_id that you'll substitute with your own values.  You'll also need to change the statements that define &amp;CONFIG_LOC -- the location of your configuration directory where you're storing these files.  I developed these examples in SAS University Edition -- yes, this works there!  I also ran the code from my full SAS environment via SAS Enterprise Guide.</p>
<h2>More about using REST APIs from SAS</h2>
<p>This has been a monster article -- in terms of its length.  But I hope it's clear enough to follow and has sufficient detail for you to try this on your own.  If you have questions, post in the comments.</p>
<p>I've published a number of other articles about using REST APIs from SAS -- it's one of my favorite things to do.  Check out:</p>
<ul>
<li><a href="https://blogs.sas.com/content/sasdummy/2017/04/14/using-sas-to-access-google-analytics-apis/">Using Google Analytics APIs from SAS</a>
</li>
<li><a href="https://blogs.sas.com/content/sasdummy/2017/01/05/reporting-on-github-accounts-with-sas/">Using GitHub APIs from SAS</a>
</li>
<li><a href="https://blogs.sas.com/content/sasdummy/2019/09/05/sas-microsoft-teams/">How to publish to a Microsoft Teams channel using SAS</a>
</li>
<li><a href="https://blogs.sas.com/content/sasdummy/2016/07/22/slack-channel-with-sas/">Sending messages to a Slack channel with SAS</a>
</li>
<li><a href="https://blogs.sas.com/content/sasdummy/2018/07/02/snackbot-api-timeseries/">The Internet of Snacks: SnackBot data and what it reveals about SAS life</a>
</li>
<li><a href="https://blogs.sas.com/content/sasdummy/2018/01/23/check-json-and-http/">How to test PROC HTTP and the JSON library engine</a>
</li>
<li><a href="https://blogs.sas.com/content/sasdummy/2018/01/16/hide-rest-api-tokens/">Securing your REST API credentials in your SAS programs</a>
</li>
</ul>
<p>The post <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy/2020/07/09/sas-programming-office-365-onedrive/">Using SAS with Microsoft 365 (OneDrive, Teams, and SharePoint)</a> appeared first on <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy">The SAS Dummy</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=8KWDybgunpk:XSTNkcLvSQ8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=8KWDybgunpk:XSTNkcLvSQ8:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=8KWDybgunpk:XSTNkcLvSQ8:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=8KWDybgunpk:XSTNkcLvSQ8:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=8KWDybgunpk:XSTNkcLvSQ8:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=8KWDybgunpk:XSTNkcLvSQ8:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=8KWDybgunpk:XSTNkcLvSQ8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=8KWDybgunpk:XSTNkcLvSQ8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=8KWDybgunpk:XSTNkcLvSQ8:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=8KWDybgunpk:XSTNkcLvSQ8:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=TzevzKxY174" border="0"></img></a>
</div>]]></content:encoded>
					
					<wfw:commentRss>https://blogs.sas.com/content/sasdummy/2020/07/09/sas-programming-office-365-onedrive/feed/</wfw:commentRss>
			<slash:comments>81</slash:comments>
		
		
			<enclosure url="https://blogs.sas.com/content/sasdummy/files/2018/11/onedrive_feature-150x150.png" />
	</item>
		<item>
		<title>How to copy files in SAS Enterprise Guide</title>
		<link>https://blogs.sas.com/content/sasdummy/2020/05/19/copy-files-in-sas-eg/</link>
					<comments>https://blogs.sas.com/content/sasdummy/2020/05/19/copy-files-in-sas-eg/#comments</comments>
		
		<dc:creator><![CDATA[Chris Hemedinger]]></dc:creator>
		<pubDate>Tue, 19 May 2020 19:00:05 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Copy Files]]></category>
		<category><![CDATA[FTP]]></category>
		<category><![CDATA[PROC DOWNLOAD]]></category>
		<category><![CDATA[PROC UPLOAD]]></category>
		<category><![CDATA[SAS custom tasks]]></category>
		<category><![CDATA[SAS Enterprise Guide]]></category>
		<guid isPermaLink="false">http://blogs.sas.com/content/sasdummy/?p=2765</guid>

					<description><![CDATA[<p>One of the problems that trips up experienced SAS users when they begin to use SAS Enterprise Guide is a result of simple geography. The SAS Enterprise Guide application runs here, on your desktop. The SAS Workspace session (which accesses data and cranks through your analysis) runs over there, on [...]</p>
<p>The post <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy/2020/05/19/copy-files-in-sas-eg/">How to copy files in SAS Enterprise Guide</a> appeared first on <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy">The SAS Dummy</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>One of the problems that trips up <em>experienced</em> SAS users when they begin to use SAS Enterprise Guide is a result of simple geography.</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2012/12/geography.png"><img loading="lazy" class="alignnone size-full wp-image-2773" src="https://blogs.sas.com/content/sasdummy/files/2012/12/geography.png" alt="" width="600" height="248" srcset="https://blogs.sas.com/content/sasdummy/files/2012/12/geography.png 600w, https://blogs.sas.com/content/sasdummy/files/2012/12/geography-300x124.png 300w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<p>The SAS Enterprise Guide application runs <em>here</em>, on your desktop. The SAS Workspace session (which accesses data and cranks through your analysis) runs <em>over there</em>, on a remote machine. If you're accustomed to "PC SAS" running all on your local box, you might be forced to rethink a few of your processes. For example, do you have Excel files on your PC to import using PROC IMPORT? Does your SAS program create output that you have to save on your PC? How will you get these files to where they need to be?</p>
<p>There are some strategies that help, including mapped drives, UNC paths, and network shares via a mechanism like <a title="About Samba" href="http://www.samba.org/">Samba</a>. These mechanisms allow your local SAS Enterprise Guide and your remote SAS to "see" a shared location on the network. Also, SAS Enterprise Guide has a few focused tasks that can "move" files for you under the guise of "import" and "export" steps.</p>
<p>But there isn't a general method to <strong>copy any file you want</strong> from your PC to the SAS Workspace, or from the SAS Workspace to your PC. Until now.</p>
<p>I give you: the <strong>Copy Files</strong> task for SAS Enterprise Guide.</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2012/12/copyfiles.png"><img loading="lazy" class="alignnone size-full wp-image-2779" src="https://blogs.sas.com/content/sasdummy/files/2012/12/copyfiles.png" alt="" width="444" height="496" srcset="https://blogs.sas.com/content/sasdummy/files/2012/12/copyfiles.png 444w, https://blogs.sas.com/content/sasdummy/files/2012/12/copyfiles-268x300.png 268w" sizes="(max-width: 444px) 100vw, 444px" /></a></p>
<p><em>Note: This article was originally published in 2012. It's been updated periodically with new information. Most recently, I added a link to a video tutorial about the Copy Files task.</em></p>
<h4>What "Copy Files" does</h4>
<p>The Copy Files task allows you to capture file transfer steps within your SAS Enterprise Guide process flow. You can upload files from your local PC to the remote machine where your SAS Workspace is running. And you can download files from your remote SAS Workspace to a folder on your local PC. It is similar in concept to an <a title="That is, File Transfer Protocol" href="http://en.wikipedia.org/wiki/File_Transfer_Protocol">FTP process</a>, except that this transfer operation uses your already-existing connection to a SAS Workspace and does not require a separate application.</p>
<p>Some readers might be familiar with <a title="SAS/CONNECT doc" href="http://support.sas.com/documentation/cdl/en/connref/63066/HTML/default/viewer.htm#p17dpmu6bnrxvtn15iqucoqndxwj.htm">SAS/CONNECT Data Transfer Services</a> (PROC UPLOAD and PROC DOWNLOAD), which allows you to transfer files between two SAS sessions. Again, this is similar in concept, but since there is only one SAS session in play here, we need to use a different mechanism.</p>
<h4>How to copy files in bulk</h4>
<p>The Copy Files task supports two features that allow you to copy multiple files with a single step. First, you can use wildcard characters to match on multiple file names. An asterisk (*) matches all characters, in any number, before the next non-wildcard character. A question mark (?) matches any single character that occupies that position in the file name.</p>
<p>Second, you can use SAS macro variables and expressions to specify any part of the source file names or destination folder. Use a SAS program to determine the files you need to copy earlier in the process, assign that value to a macro variable, and then have the task "dynamically" select the correct files when it's time to copy them.</p>
<h4>Support for Task Templates</h4>
<p>The Copy Files task also supports a standard SAS Enterprise Guide feature: <a title="very handy feature!" href="https://blogs.sas.com/content/sastraining/2012/09/28/watch-and-learn-save-time-with-task-templates/">Task Templates</a>. You can create an instance of the task that is useful in one process, then save those task settings to your personalized set of Task Templates that you can use in another process or even in another project. To save your settings as a template, right-click on the Copy Files task within your process flow and select <strong>Create Task Template</strong>. To use the new template, select it as a menu item from <strong>Tasks-&gt;Task Templates</strong>.</p>
<p>To see the Copy Files task in action, <a href="https://youtu.be/GX9qqfVIpM8?start=5708&amp;end=6360">watch this 11-minute portion of my SAS Enterprise Guide tutorial</a>.</p>

<!-- iframe plugin v.4.5 wordpress.org/plugins/iframe/ -->
<iframe width="560" height="315" src="https://www.youtube.com/embed/GX9qqfVIpM8?start=5708&#038;end=6360" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" 0="allowfullscreen" scrolling="yes" class="iframe-class"></iframe>
<h4>Limitations to note</h4>
<p>This task does <strong>not</strong> generate a SAS program that you can reuse in a batch SAS process or SAS stored process. The task works by using SAS Workspace APIs to transfer data across your network connection, so all of the work happens "behind the scenes". However, the task does <a title="here's what it looks like" href="https://blogs.sas.com/content/sasdummy/files/2012/12/copyfileslog.png">create a detailed log output</a> that shows what files were copied, how many bytes were transferred, how long it took, and whether there were any errors.</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2012/12/copyfileslog.png"><img loading="lazy" class="alignnone size-full wp-image-2778" src="https://blogs.sas.com/content/sasdummy/files/2012/12/copyfileslog.png" alt="" width="823" height="450" srcset="https://blogs.sas.com/content/sasdummy/files/2012/12/copyfileslog.png 823w, https://blogs.sas.com/content/sasdummy/files/2012/12/copyfileslog-300x164.png 300w" sizes="(max-width: 823px) 100vw, 823px" /></a></p>
<h4>How to access the Copy Files task</h4>
<p>You'll find the Copy Files task in the Data category of the SAS Tasks list. Here's the view from SAS Enterprise Guide v8.2:</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2012/12/copyfilesmenu.png"><img loading="lazy" class="alignnone size-full wp-image-6976" src="https://blogs.sas.com/content/sasdummy/files/2012/12/copyfilesmenu.png" alt="" width="348" height="318" srcset="https://blogs.sas.com/content/sasdummy/files/2012/12/copyfilesmenu.png 348w, https://blogs.sas.com/content/sasdummy/files/2012/12/copyfilesmenu-300x274.png 300w" sizes="(max-width: 348px) 100vw, 348px" /></a></p>
<p>This task has been included in SAS Enterprise Guide since the v7.13 release (late 2017). Are you using an older version? You really should consider upgrading! But, with a little work, you can add the task to older versions.</p>
<p>You can <a title="download link to the zip file" href="http://support.sas.com/documentation/onlinedoc/guide/customtasks/samples/SASFileTransferTask.zip">download the Copy Files task from this link</a> (Zip file). The download package includes multiple versions that depend on your version of SAS Enterprise Guide: v4.3, v5.1, v6.1, v7.1 (before v7.13), and one for v4.1 (with a reduced feature set). There is also a documentation file (PDF) that provides instruction for how to install and use the task. You might need to <a href="https://blogs.sas.com/content/sasdummy/2013/05/19/unblocking-custom-task-dlls/">perform this extra step to "unblock" the downloaded DLL</a> to avoid an error ("HRESULT: 0x80131515") when you try to add the task to your installation.</p>
<a href="https://www.sas.com/gms/redirect.jsp?detail=GMS168352_234280" class="sc-button sc-button-default"><span><span class="btnheader">WANT MORE GREAT INSIGHTS MONTHLY? | </span> SUBSCRIBE TO THE SAS LEARNING REPORT</span></a>
<p>The post <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy/2020/05/19/copy-files-in-sas-eg/">How to copy files in SAS Enterprise Guide</a> appeared first on <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy">The SAS Dummy</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=dRD58jivbkk:xAUx__AP0dw:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=dRD58jivbkk:xAUx__AP0dw:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=dRD58jivbkk:xAUx__AP0dw:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=dRD58jivbkk:xAUx__AP0dw:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=dRD58jivbkk:xAUx__AP0dw:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=dRD58jivbkk:xAUx__AP0dw:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=dRD58jivbkk:xAUx__AP0dw:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=dRD58jivbkk:xAUx__AP0dw:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=dRD58jivbkk:xAUx__AP0dw:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=dRD58jivbkk:xAUx__AP0dw:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=TzevzKxY174" border="0"></img></a>
</div>]]></content:encoded>
					
					<wfw:commentRss>https://blogs.sas.com/content/sasdummy/2020/05/19/copy-files-in-sas-eg/feed/</wfw:commentRss>
			<slash:comments>177</slash:comments>
		
		
			<enclosure url="https://blogs.sas.com/content/sasdummy/files/2012/12/geography-150x150.png" />
	</item>
		<item>
		<title>How to share your SAS knowledge with your professional network</title>
		<link>https://blogs.sas.com/content/sasdummy/2020/04/03/sas-professional-sharing/</link>
					<comments>https://blogs.sas.com/content/sasdummy/2020/04/03/sas-professional-sharing/#comments</comments>
		
		<dc:creator><![CDATA[Chris Hemedinger]]></dc:creator>
		<pubDate>Fri, 03 Apr 2020 13:25:34 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[LinkedIn]]></category>
		<category><![CDATA[SAS Communities]]></category>
		<category><![CDATA[SAS global forum]]></category>
		<guid isPermaLink="false">https://blogs.sas.com/content/sasdummy/?p=6390</guid>

					<description><![CDATA[<p>SAS Global Forum 2020 is not the conference experience we thought it would be. Thousands of us had planned to gather in person to share our enthusiasm and knowledge about SAS and power of data and analytics. We were going to combine our skills and knowledge to inspire one another [...]</p>
<p>The post <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy/2020/04/03/sas-professional-sharing/">How to share your SAS knowledge with your professional network</a> appeared first on <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy">The SAS Dummy</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>SAS Global Forum 2020 is not the conference experience we thought it would be.  Thousands of us had planned to gather <em>in person</em> to share our enthusiasm and knowledge about SAS and power of data and analytics.  We were going to combine our skills and knowledge to inspire one another to <strong>Do More</strong>.  For me, attending the conference is an annual treat (albeit a ton of work) because I get to witness the achievements and excitement of so many SAS professionals.</p>
<p>If you're among the hundreds of people who had planned to present (as I am), you might feel a sense of great loss.  After all, you already did most of the work: proposed a topic, earned an acceptance, wrote a paper (!), and maybe even completed your presentation materials. (Did you already rehearse for your colleagues or in front of a mirror?)</p>
<p>In this article, I'll share some ideas that you can use to fill the gap, and to extend the reach of your SAS knowledge beyond just those who would have attended the conference. Specifically, I'll address how you can make the biggest splash and have an enduring impact with that traditional mode of SAS-knowledge sharing: <strong>the SAS conference paper</strong>.</p>
<h2>Extending the reach of your SAS Global Forum paper</h2>
<p>Like many of you, I've written and presented a few technical papers for SAS Global Forum (and also for its predecessor, SUGI). With each conference, SAS publishes a set of proceedings that provide perpetual access to the PDF version of my papers. If you know what you're looking for, you can find my papers in several ways:</p>
<ul>
<li>On the dedicated proceedings page for each conference year. For example, here's the <a href="https://www.sas.com/en_us/events/sas-global-forum/program/proceedings.html">collection from SAS Global Forum 2020</a>.</li>
<li>By <a href="https://support.sas.com">searching the SAS support site</a>, using the proper keywords that relate to my topics.</li>
<li>By <a href="http://www.lexjansen.com/">searching lexjansen.com</a> -- a labor-of-love website by Lex Jansen, who indexes and makes it easy to find virtually all SAS-related conference papers.</li>
</ul>
<p>All of these methods work with <strong>no</strong> additional effort from me. When your paper is published as part of a SAS conference, that content is automatically archived and findable within these conference assets. But for as far as this goes, there is opportunity to do so much more.</p>
<h3>Write an article for SAS Support Communities</h3>
<div id="attachment_6394" style="width: 310px" class="wp-caption alignright"><a href="https://blogs.sas.com/content/sasdummy/files/2017/12/artcpp.png"><img aria-describedby="caption-attachment-6394" loading="lazy" class="size-medium wp-image-6394" src="https://blogs.sas.com/content/sasdummy/files/2017/12/artcpp-300x167.png" alt="" width="300" height="167" srcset="https://blogs.sas.com/content/sasdummy/files/2017/12/artcpp-300x167.png 300w, https://blogs.sas.com/content/sasdummy/files/2017/12/artcpp.png 602w" sizes="(max-width: 300px) 100vw, 300px" /></a><p id="caption-attachment-6394" class="wp-caption-text">ArtC's presenter page</p></div>
<p>Back in the day, sasCommunity.org supported the idea of "presenter pages" -- a mini-destination for information about your conference paper. As an author, you would create a page that contains the description of your paper, links to supporting code, and any other details that you wanted to lift out of the PDF version of your paper. Creating such a page required a bit of learning time with the wiki syntax, and just a small subset of paper presenters ever took the time to complete this step. (But some prolific contributors, such as Art Carpenter or Don Henderson, shared blurbs about dozens of their papers in this way.) Personally, I created a few pages on sasCommunity.org to support my own papers over the years.</p>
<p>SAS Support Communities offers a similar mechanism: <a href="https://communities.sas.com/t5/SAS-Communities-Library/tkb-p/library">the SAS Communities Library</a>. Any community member can create an article to share his or her insights about a SAS related topic. A conference paper is a great opportunity to add to the SAS Communities Library and bring some more attention to your work. A communities article also serves as platform for readers to ask you questions about your work, as the library supports a commenting feature that allows for discussion.</p>
<p>I created articles on SAS Support Communities to address some of my previous papers. I also updated the content, where appropriate, to ensure that my examples work for modern releases of SAS. Here are two examples of presentation pages that I created on SAS Support Communities:</p>
<ul>
<li><a href="https://communities.sas.com/t5/SAS-Communities-Library/Doing-More-with-SAS-Enterprise-Guide-Automation/ta-p/417832">Doing more with SAS Enterprise Guide automation</a> (supporting a paper from 2012)</li>
<li><a href="https://communities.sas.com/t5/SAS-Communities-Library/Create-your-own-client-apps-using-SAS-Integration-Technologies/ta-p/418253">Create your own client apps with SAS Integration Technologies</a> (supporting a paper from 2013)</li>
</ul>
<div id="attachment_6396" style="width: 1100px" class="wp-caption alignnone"><a href="https://blogs.sas.com/content/sasdummy/files/2017/12/cjharticle.png"><img aria-describedby="caption-attachment-6396" loading="lazy" class="size-full wp-image-6396" src="https://blogs.sas.com/content/sasdummy/files/2017/12/cjharticle.png" alt="" width="1090" height="425" srcset="https://blogs.sas.com/content/sasdummy/files/2017/12/cjharticle.png 1090w, https://blogs.sas.com/content/sasdummy/files/2017/12/cjharticle-300x117.png 300w, https://blogs.sas.com/content/sasdummy/files/2017/12/cjharticle-1024x399.png 1024w" sizes="(max-width: 1090px) 100vw, 1090px" /></a><p id="caption-attachment-6396" class="wp-caption-text">One of my presentations on in the SAS Communities Library</p></div>
<p>When you publish a topic in the SAS Communities Library, especially if it's a topic that people search for, your article will get an automatic boost in visitors thanks to the great search engine traffic that drives the communities site. With that in mind, use these guidelines when publishing:</p>
<ul>
<li><strong>Use relevant key words/phrases in your article title.</strong> Cute and clever titles are a fun tradition in SAS conference papers, and you should definitely keep those intact within the body of your article. But reserve the title field for a more practical description of the content you're sharing.</li>
<li><strong>Include an image or two.</strong> Does your paper include an architecture diagram? A screen shot? A graph or plot? Use the Insert Photos button to add these to your article for visual interest and to give the reader a better idea of what's in your paper.</li>
<li><strong>Add a snippet of code.</strong> You don't have to attach all of your sample code with hundreds of program lines, but a little bit of code can help the reader with some context. Got lots of code? We'll cover that in the next section.</li>
</ul>
<h4>More examples to inspire you</h4>
<p>This year (2020), the industry conference PharmaSUG was also cancelled due to COVID-19. But that didn't stop Jeffrey Meyers, a prolific PharmaSUG contributor, from sharing his work! He published his presentations in article form on the SAS Communities Library, and attached code and his formal paper as a PDF.  (For SAS Global Forum, the papers are published in the proceedings -- so if you follow Jeff's example you <strong>should not</strong> attach your paper.  Rather, just link to it from your article.)</p>
<ul>
<li><a href="https://communities.sas.com/t5/SAS-Communities-Library/MVMODELS-a-Macro-for-Survival-and-Logistic-Analysis/ta-p/635217">%MVMODELS: a Macro for Survival and Logistic Analysis</a>
</li>
<li><a href="https://communities.sas.com/t5/SAS-Communities-Library/Data-Library-Comparison-Macro-COMPARE-ALL/ta-p/634341">Data Library Comparison Macro %COMPARE_ALL</a>
</li>
<li><a href="https://communities.sas.com/t5/SAS-Communities-Library/Demographic-Table-and-Subgroup-Summary-Macro-TABLEN/ta-p/634030">Demographic Table and Subgroup Summary Macro %TABLEN </a>
</li>
</ul>
<p>To get started with the process for creating an article...<a href="https://communities.sas.com/t5/Community-Memo/3-reasons-why-you-should-write-an-article-for-the-SAS/ba-p/309034">see this article</a>!</p>
<h3>Share your code on GitHub</h3>
<p>SAS program code is an important feature in SAS conference papers. A code snippet in a PDF-style paper can help to illustrate your points, but you cannot effectively share entire programs or code libraries within this format. Code that is locked up in a PDF document is difficult for a reader to lift and reuse. It's also impossible to revise after the paper is published.</p>
<p>GitHub is a free service that supports sharing and collaboration for any code-based technology, including SAS. Anyone who works with code -- data scientists, programmers, application developers -- is familiar with GitHub at least as a reader. If you haven't done so already, it might be time to create your own GitHub account and share your useful SAS code. <a href="https://github.com/cjdinger">I have several GitHub repositories</a> (or "repos" as we GitHub hipsters say) that are related to papers, blog posts, and books that I've written. It just feels like a natural way to share code. Occasionally a reader suggests an improvement or finds a bug, and I can change the code immediately. (Alas, I cannot go back in time and change a published paper...)</p>
<p>We invite you to contribute your code and other materials to <a href="https://github.com/sascommunities/sas-global-forum-2020">the SAS Global Forum GitHub repository</a>. We organized this repo as a central location for all presenters to share code that helps other SAS professionals to use the tips you've shared in your paper.</p>
<div id="attachment_6402" style="width: 919px" class="wp-caption alignnone"><a href="https://github.com/cjdinger/sas-eg-automation"><img aria-describedby="caption-attachment-6402" loading="lazy" class="size-full wp-image-6402" src="https://blogs.sas.com/content/sasdummy/files/2017/12/githubcode.png" alt="" width="909" height="520" srcset="https://blogs.sas.com/content/sasdummy/files/2017/12/githubcode.png 909w, https://blogs.sas.com/content/sasdummy/files/2017/12/githubcode-300x172.png 300w" sizes="(max-width: 909px) 100vw, 909px" /></a><p id="caption-attachment-6402" class="wp-caption-text">A sample of conference-paper-code on my GitHub.</p></div>
<h3>Add a video of your presentation</h3>
<p>Many SAS Global Forum presenters have been invited and agreed to record a short video version of their presentation.  These will be available on <a href="https://www.youtube.com/sasusers">the SAS Users channel on YouTube</a>.  If you write an article for the SAS Community, you can also embed your video from YouTube to complete the package.</p>
<p>If you don't have a YouTube version, you're still invited to contribute a video! On the SAS Community you can upload your own video to include in your article.  Record these using Camtasia or <a href="https://obsproject.com/">OBS (Open Broadcaster Software)</a> or whatever tech you're comfortable with.  You can then add the MP4 or MOV file via the Add Video tool while editing your SAS Communities Library article.  Here's an example of a video within the community: <a href="https://communities.sas.com/t5/SAS-Communities-Library/Viewing-SAS-catalog-entries-and-formats-within-SAS-Enterprise/ta-p/385690">Viewing SAS catalog entries and formats within SAS Enterprise Guide</a>.</p>
<h3>List your published work on your LinkedIn profile</h3>
<p>So, you've prepared/presented your work at a major SAS conference! Your professional network <em>needs to know</em> this about you. You should list this as an accomplishment on your resume, and definitely on your LinkedIn profile.</p>
<p>LinkedIn offers a "publication" section -- perfect for listing books and papers that you've written. Or, you can add this to the "projects" section of your profile, especially if you collaborate with someone else that you want to include in this accomplishment. I have yet to add my <em>entire</em> back-catalog of conference papers, but I have added a few recent papers <a href="https://www.linkedin.com/in/sasdummy/">to my LinkedIn profile</a>.</p>
<div id="attachment_6399" style="width: 795px" class="wp-caption alignnone"><a href="https://blogs.sas.com/content/sasdummy/files/2017/12/li_pub.png"><img aria-describedby="caption-attachment-6399" loading="lazy" class="size-full wp-image-6399" src="https://blogs.sas.com/content/sasdummy/files/2017/12/li_pub.png" alt="" width="785" height="477" srcset="https://blogs.sas.com/content/sasdummy/files/2017/12/li_pub.png 785w, https://blogs.sas.com/content/sasdummy/files/2017/12/li_pub-300x182.png 300w" sizes="(max-width: 785px) 100vw, 785px" /></a><p id="caption-attachment-6399" class="wp-caption-text">One of a few publications listed on my LinkedIn profile</p></div>
<h3>Bonus step: write about your experience in a LinkedIn article</h3>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2017/12/li_article.png"><img loading="lazy" class="alignleft size-medium wp-image-6404" src="https://blogs.sas.com/content/sasdummy/files/2017/12/li_article-300x71.png" alt="" width="300" height="71" srcset="https://blogs.sas.com/content/sasdummy/files/2017/12/li_article-300x71.png 300w, https://blogs.sas.com/content/sasdummy/files/2017/12/li_article.png 564w" sizes="(max-width: 300px) 100vw, 300px" /></a>Introspection has a special sort of currency on LinkedIn that doesn't always translate well to other places. A LinkedIn article -- a long-form post that you write from a first-person perspective -- gives you a chance to talk about the deeper meaning of your project. This can include the story of inspiration behind your conference paper, personal lessons that you learned along the way, and the impact that the project had in your workplace and on your career. This "color commentary" adds depth to how others see your work and experience, which helps them to learn more about you and what drives you.</p>
<p>Here are a few examples of what I'm talking about:</p>
<ul>
<li>Susan Slaughter (coauthor of <em>The Little SAS Book</em>) <a href="https://www.linkedin.com/pulse/now-starring-susan-lora-sgplot-sgpanel-procedures-susan-slaughter/">talks about her paper/presentation about SGPLOT</a>.</li>
<li>Here's a <a href="https://www.linkedin.com/pulse/shining-light-smart-ones-chris-hemedinger/">LinkedIn article that I wrote about a SAS Global Forum video series that I host</a> -- a sort of "behind the scenes" story.</li>
<li>And you should connect with/follow our <a href="https://www.linkedin.com/in/kirkpaullafler/">favorite "SAS Nerd" Kirk Lafler</a>. He's a master <a href="https://www.linkedin.com/pulse/kirks-presentations-sas-global-forum-2016-kirk-paul-lafler/?trackingId=mfYFWrvxJynwxgLZMQZtSg%3D%3D">at sharing his SAS content on LinkedIn</a>.</li>
</ul>
<h3>It's not about you. It's about us.</h3>
<p>The techniques I've shared here might sound like "how to promote yourself." Of course, that's important -- we each need to take responsibility for our own self-promotion and ensure that our professional achievements shine through. But more importantly, these steps play a big role in helping your content to be findable -- even "stumble-uponable" (a word I've just invented). You've already invested a tremendous amount of work into researching your topic and crafting a paper and presentation -- take it the extra bit of distance to make sure that the rest of us can't miss it.</p>
<p>(<em>Author's note:</em> I originally published this article in 2017, when sasCommunity.org was "retired" and SAS professionals were looking for an outlet to share their work.  I've adapted the guidance here for our "virtual conference" reality in 2020.)</p>
<p>The post <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy/2020/04/03/sas-professional-sharing/">How to share your SAS knowledge with your professional network</a> appeared first on <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy">The SAS Dummy</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=Y3ZdaJdOnYI:HuXCwHAXJ-Q:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=Y3ZdaJdOnYI:HuXCwHAXJ-Q:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=Y3ZdaJdOnYI:HuXCwHAXJ-Q:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=Y3ZdaJdOnYI:HuXCwHAXJ-Q:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=Y3ZdaJdOnYI:HuXCwHAXJ-Q:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=Y3ZdaJdOnYI:HuXCwHAXJ-Q:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=Y3ZdaJdOnYI:HuXCwHAXJ-Q:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=Y3ZdaJdOnYI:HuXCwHAXJ-Q:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=Y3ZdaJdOnYI:HuXCwHAXJ-Q:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=Y3ZdaJdOnYI:HuXCwHAXJ-Q:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=TzevzKxY174" border="0"></img></a>
</div>]]></content:encoded>
					
					<wfw:commentRss>https://blogs.sas.com/content/sasdummy/2020/04/03/sas-professional-sharing/feed/</wfw:commentRss>
			<slash:comments>11</slash:comments>
		
		
			<enclosure url="https://blogs.sas.com/content/sasdummy/files/2017/12/84A5974-150x150.jpg" />
	</item>
		<item>
		<title>Tricks for importing text files in SAS Enterprise Guide</title>
		<link>https://blogs.sas.com/content/sasdummy/2020/03/23/import-text-data-sas-enterprise-guide/</link>
					<comments>https://blogs.sas.com/content/sasdummy/2020/03/23/import-text-data-sas-enterprise-guide/#comments</comments>
		
		<dc:creator><![CDATA[Chris Hemedinger]]></dc:creator>
		<pubDate>Mon, 23 Mar 2020 20:00:30 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[import data]]></category>
		<category><![CDATA[SAS Enterprise Guide]]></category>
		<category><![CDATA[SAS programming]]></category>
		<guid isPermaLink="false">https://blogs.sas.com/content/sasdummy/?p=6365</guid>

					<description><![CDATA[<p>I'm a big fan of the Import Data task in SAS Enterprise Guide, especially for its support of text-based files (CSV, tab delimited, fixed width, and more). There's no faster method for generating SAS code that reads your data exactly the way you need it. I use the tool so [...]</p>
<p>The post <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy/2020/03/23/import-text-data-sas-enterprise-guide/">Tricks for importing text files in SAS Enterprise Guide</a> appeared first on <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy">The SAS Dummy</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>I'm a big fan of the Import Data task in SAS Enterprise Guide, especially for its support of text-based files (CSV, tab delimited, fixed width, and more).  There's no faster method for generating SAS code that reads your data exactly the way you need it.  I use the tool so often that I take for granted some of its neatest features, and I forget that many new users (and even veteran users) might not know about them.  In this article, I'll review a few of the cool things that this task can do for you.</p>
<p>(<em>Update 23Mar2020</em>) I've recorded a video that shows how to use the Import Data task as a start, and then adapt the code that it generates for reuse in other environments, with other files, and to read multiple text files in a single step.  <a href="https://youtu.be/UDKcTXMACEU">Watch the video to learn more</a>, or scroll down to read my step-by-step tips.</p>

<!-- iframe plugin v.4.5 wordpress.org/plugins/iframe/ -->
<iframe width="720" src="https://www.youtube.com/embed/UDKcTXMACEU" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" 0="allowfullscreen" height="500" scrolling="yes" class="iframe-class"></iframe>
<h3>Read fixed-width text files into SAS</h3>
<p>We think of CSV files (and...alas...Excel files) as the main standard for data exchange among systems, but many legacy systems still produce and consume fixed-width text data formats.  The SAS DATA step is a perfect tool for reading these files, but defining the columns and their properties can be tedious.  The "Fixed columns" option on the Import Data task can make this job simple.  </p>
<p>Suppose that you're beginning with a spec like this:</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2017/12/fwdef.png"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2017/12/fwdef.png" alt="" width="498" height="236" class="alignnone size-full wp-image-6373" srcset="https://blogs.sas.com/content/sasdummy/files/2017/12/fwdef.png 498w, https://blogs.sas.com/content/sasdummy/files/2017/12/fwdef-300x142.png 300w" sizes="(max-width: 498px) 100vw, 498px" /></a></p>
<p>And a raw data file like this:</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2017/12/fwraw.png"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2017/12/fwraw.png" alt="" width="985" height="126" class="alignnone size-full wp-image-6384" srcset="https://blogs.sas.com/content/sasdummy/files/2017/12/fwraw.png 985w, https://blogs.sas.com/content/sasdummy/files/2017/12/fwraw-300x38.png 300w" sizes="(max-width: 985px) 100vw, 985px" /></a></p>
<p>You can use the Import Data wizard to define the boundaries of your columns by adding boundary lines with just click-and-drag operations.  Beginning with the File-&gt;Import Data task, select your source text file and advance to the second page of the wizard.  When you select "Fixed columns" as the input text format, you'll see a layout ruler that looks like this:</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2017/12/fwdlg.png"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2017/12/fwdlg.png" alt="" width="938" height="490" class="alignnone size-full wp-image-6372" srcset="https://blogs.sas.com/content/sasdummy/files/2017/12/fwdlg.png 938w, https://blogs.sas.com/content/sasdummy/files/2017/12/fwdlg-300x157.png 300w" sizes="(max-width: 938px) 100vw, 938px" /></a></p>
<p>Click at the column boundaries (referring to your original spec!) and drag the rule lines as needed to define those column boundaries.  Then click Next, and fill out details for the column names and types:</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2017/12/fwcols.png"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2017/12/fwcols.png" alt="" width="886" height="276" class="alignnone size-full wp-image-6370" srcset="https://blogs.sas.com/content/sasdummy/files/2017/12/fwcols.png 886w, https://blogs.sas.com/content/sasdummy/files/2017/12/fwcols-300x93.png 300w" sizes="(max-width: 886px) 100vw, 886px" /></a></p>
<p>Which then tells the Import Data task how to generate the proper INPUT statements:</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2017/12/fwinput.png"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2017/12/fwinput.png" alt="" width="372" height="249" class="alignnone size-full wp-image-6368" /></a></p>
<p>When you click <strong>Finish</strong>, you end up with a data set that's ready for business:</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2017/12/fwdata.png"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2017/12/fwdata.png" alt="" width="1016" height="217" class="alignnone size-full wp-image-6369" srcset="https://blogs.sas.com/content/sasdummy/files/2017/12/fwdata.png 1016w, https://blogs.sas.com/content/sasdummy/files/2017/12/fwdata-300x64.png 300w" sizes="(max-width: 1016px) 100vw, 1016px" /></a></p>
<h3>Modify the properties for multiple columns -- with one step</h3>
<p>Here's a click-saving trick.  Sometimes you have an input data file that contains many columns that share the same properties: type, length, and SAS format.  It can be tedious to click and modify the properties of <strong>each</strong> column that you want to import.  There's a shortcut on the <strong>Define Field Attributes</strong> page of the wizard that you can use to change the attributes for several columns at the same time.  Simply SHIFT+Click to select multiple column definitions on the page, then click <strong>Modify...</strong>.  The "Field Attributes for Multiple Selections" window appears, and you can change the necessary attributes just once and apply to the many items you picked.</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2017/12/importmulti.png"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2017/12/importmulti.png" alt="" width="934" height="500" class="alignnone size-full wp-image-6376" srcset="https://blogs.sas.com/content/sasdummy/files/2017/12/importmulti.png 934w, https://blogs.sas.com/content/sasdummy/files/2017/12/importmulti-300x161.png 300w" sizes="(max-width: 934px) 100vw, 934px" /></a></p>
<p>This trick works as you import any text file or Excel file.</p>
<h3>Create SAS program code that you can reuse anywhere</h3>
<p>In a <a href="https://blogs.sas.com/content/sasdummy/2011/05/18/behind-the-scenes-importing-excel-files-using-sas-enterprise-guide/">previous article I described how the Import Data task works</a> "behind the scenes."  Some of the magic that the task performs is not captured in SAS code, and that can present a challenge when you want to reuse this work in other settings -- for example, in a batch process or in a larger SAS program.  However, with a couple of tweaks you can coerce the Import Data task into creating SAS code that you can almost just "lift and shift," as is.</p>
<p>The first option is hidden under the Performance window, labeled as "Bypass the data cleansing process."  By default, the Import Data task reformats your input text file to normalize it for a cleaner import step.  While doing no harm, most of the time this step isn't needed -- especially if your original data file is well formed.  And since this step changes the input file, it's isn't repeatable outside of this task.  My first tip for the best reusable code: click <strong>Performance...</strong> on the first page of the wizard, then select the "Bypass.." checkbox.  That guarantees that the code will be formulated to read your original raw file.  (Note that the Performance button is available only when importing text files, not Excel files.)</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2017/12/importbypass.png"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2017/12/importbypass.png" alt="" width="564" height="479" class="alignnone size-full wp-image-6379" srcset="https://blogs.sas.com/content/sasdummy/files/2017/12/importbypass.png 564w, https://blogs.sas.com/content/sasdummy/files/2017/12/importbypass-300x255.png 300w" sizes="(max-width: 564px) 100vw, 564px" /></a></p>
<p>The second option you'll want to change is related to this, but you'll find it on the final page with the Advanced Options.  Select "Generalize import step to run outside of SAS Enterprise Guide."  This ensures that the task won't attempt any behind-the-scenes monkey business with your original file -- everything is captured in the DATA step that the task generates.  Well, almost everything...</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2017/12/importgeneralize.png"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2017/12/importgeneralize.png" alt="" width="562" height="248" class="alignnone size-full wp-image-6378" srcset="https://blogs.sas.com/content/sasdummy/files/2017/12/importgeneralize.png 562w, https://blogs.sas.com/content/sasdummy/files/2017/12/importgeneralize-300x132.png 300w" sizes="(max-width: 562px) 100vw, 562px" /></a></p>
<p>The one missing piece, a confounding factor when you select a local text file to import on a remote SAS Workspace session, is the transfer of the local file to the remote server.  SAS Enterprise Guide copies the file for you -- behind the scenes -- and there is no SAS code to represent this step.  </p>
<p>You can take control of even this step, though, if you <a href="https://blogs.sas.com/content/sasdummy/2016/11/14/copy-files-task-moved-menus/">make use of the Copy Files task</a> (now available for you on the Tasks-&gt;Data menu).  You can then copy the file from a local source folder, and land it wherever you want on the SAS server.  Modify your newly repurposed Import Data code to pull from that server-based destination, giving you more control over the individual steps in the import process.</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2017/12/flow.png"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2017/12/flow.png" alt="" width="415" height="113" class="alignnone size-full wp-image-6381" srcset="https://blogs.sas.com/content/sasdummy/files/2017/12/flow.png 415w, https://blogs.sas.com/content/sasdummy/files/2017/12/flow-300x82.png 300w" sizes="(max-width: 415px) 100vw, 415px" /></a></p>
<h3>Learn more about importing text files</h3>
<p>If you're new to importing data into SAS, whether using a SAS program or SAS Enterprise Guide, you might learn some of the basics from these video tutorials that were produced by SAS instructors:</p>
<ul>
<li>
<a href="http://video.sas.com/detail/videos/sas-enterprise-guide_/video/2127025935001/sas-enterprise-guide:-import-and-combine-data-from-excel-sheets?autoStart=true">Using the Import Data task in SAS Enterprise Guide</a>.  This one shows how to import Microsoft Excel files, but the basic steps are similar in the interface.
</li>
<li><a href="http://video.sas.com/detail/video/4664327156001/reading-and-generating-csv-files-using-snippets-in-sas-studio?autoStart=true">Read CSV files with SAS Studio</a>
</li>
<li><a href="http://go.documentation.sas.com/?cdcId=pgmmvacdc&amp;cdcVersion=9.4&amp;docsetId=lrcon&amp;docsetTarget=n1w749t788cgi2n1txpuccsuqtro.htm&amp;locale=en" rel="noopener noreferrer">Reading raw data with the INPUT statement.</a> (Documentation topic)
</li>
</ul>
<p>The post <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy/2020/03/23/import-text-data-sas-enterprise-guide/">Tricks for importing text files in SAS Enterprise Guide</a> appeared first on <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy">The SAS Dummy</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=OlA5x2gn0jc:f8n6k-isNiQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=OlA5x2gn0jc:f8n6k-isNiQ:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=OlA5x2gn0jc:f8n6k-isNiQ:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=OlA5x2gn0jc:f8n6k-isNiQ:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=OlA5x2gn0jc:f8n6k-isNiQ:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=OlA5x2gn0jc:f8n6k-isNiQ:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=OlA5x2gn0jc:f8n6k-isNiQ:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=OlA5x2gn0jc:f8n6k-isNiQ:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=OlA5x2gn0jc:f8n6k-isNiQ:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=OlA5x2gn0jc:f8n6k-isNiQ:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=TzevzKxY174" border="0"></img></a>
</div>]]></content:encoded>
					
					<wfw:commentRss>https://blogs.sas.com/content/sasdummy/2020/03/23/import-text-data-sas-enterprise-guide/feed/</wfw:commentRss>
			<slash:comments>24</slash:comments>
		
		
			<enclosure url="https://blogs.sas.com/content/sasdummy/files/2017/12/squarefw-150x150.png" />
	</item>
		<item>
		<title>Viewing SAS macro variables in SAS Enterprise Guide</title>
		<link>https://blogs.sas.com/content/sasdummy/2020/02/27/inspecting-sas-macro-variables-in-sas-enterprise-guide/</link>
					<comments>https://blogs.sas.com/content/sasdummy/2020/02/27/inspecting-sas-macro-variables-in-sas-enterprise-guide/#comments</comments>
		
		<dc:creator><![CDATA[Chris Hemedinger]]></dc:creator>
		<pubDate>Thu, 27 Feb 2020 12:00:43 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[debugging]]></category>
		<category><![CDATA[macro programming]]></category>
		<category><![CDATA[SAS custom tasks]]></category>
		<category><![CDATA[SAS Enterprise Guide]]></category>
		<category><![CDATA[SAS programming]]></category>
		<guid isPermaLink="false">http://blogs.sas.com/content/sasdummy/?p=1348</guid>

					<description><![CDATA[<p>If you use SAS macro variables in your programs (who doesn't?), then the SAS Macro Variable viewer is immensely useful to see current macro var values.</p>
<p>The post <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy/2020/02/27/inspecting-sas-macro-variables-in-sas-enterprise-guide/">Viewing SAS macro variables in SAS Enterprise Guide</a> appeared first on <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy">The SAS Dummy</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The SAS macro variable viewer is a tool that's part of SAS Enterprise Guide.  You can use it to view the current values for all SAS macro variables that are defined within your SAS session.  You can also evaluate "immediate" macro expressions in a convenient quick view window.  If you develop or run SAS macro programs, this task can be a valuable debugging and learning tool. If you want to learn how to use the tool and see it in action, <a href="https://youtu.be/cMNycxza6Zo">watch my SAS Tip tutorial on YouTube</a>.</p>

<!-- iframe plugin v.4.5 wordpress.org/plugins/iframe/ -->
<iframe src="https://www.youtube.com/embed/cMNycxza6Zo" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" 0="allowfullscreen" width="100%" height="500" scrolling="yes" class="iframe-class"></iframe>
<h2>SAS Macro Variable viewer: features and function</h2>
<p>This tool offers the following main features:</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2011/11/macroview.png"><img loading="lazy" src="https://blogs.sas.com/content/sasdummy/files/2011/11/macroview-276x300.png" alt="" width="276" height="300" class="alignright size-medium wp-image-1376" srcset="https://blogs.sas.com/content/sasdummy/files/2011/11/macroview-276x300.png 276w, https://blogs.sas.com/content/sasdummy/files/2011/11/macroview.png 510w" sizes="(max-width: 276px) 100vw, 276px" /></a><strong>Always-visible window:</strong> Once you open the task from the Tools menu, you can leave it open for your entire SAS Enterprise Guide session.  The window uses a "modeless" display, so you can still interact with other SAS Enterprise Guide features while the window is visible.  This makes it easy to switch between SAS programs and other SAS Enterprise Guide windows and the macro variable viewer to see results.</p>
<p><strong>Select active SAS server:</strong> If your SAS environment contains multiple SAS workspace connections, you can switch among the different servers to see macro values on multiple systems.</p>
<p><strong>One-click refresh:</strong> Refresh the list of macro variables by clicking on the Refresh button in the toolbar.</p>
<p><strong>View by scope or as a straight list:</strong> View the macro variables in their scope categories (for example, Global and Automatic) or as a straight list, sorted by variable name or current value.  Click on the column headers to sort the list.</p>
<p><strong>Filter results:</strong> Type a string of characters in the "Filter results" field, and the list of macro variable results will be instantly filtered to those that contain the sequence that you type.  The filtered results will match on variable names as well as values, and the search is case-insensitive.  This is a convenient way to narrow the list to just a few variables that you're interested in.  To clear the filter, click on the <strong>X</strong> button next to the "Filter results" field, or "blank out" the text field. </p>
<p><strong>Set window transparency:</strong> You can make the window appear "see-through" so that it doesn't completely obscure your other windows as you work with it.</p>
<p><strong>Copy macro variables as %LET statements:</strong> Select one or more macro variables within the window, right-click and select <strong>Copy assignments</strong>.  This generates a series of %LET statements -- one for each macro variable/value pair -- which you can then paste into a SAS program.</p>
<p><strong>Macro expression "quick view":</strong> Have you ever wanted to test out a macro expression before using it in a longer program?  This window allows you to get immediate feedback on a macro expression, whether a simple macro reference or a more complex expression with nested functions.   If the expression generates a SAS warning or error, the feedback window shows that as well.  Note: the expression can be any macro expression that is valid for the right-side of a macro variable assignment (<strong>%let</strong> statement).</p>
<p><a href="https://blogs.sas.com/content/sasdummy/files/2011/11/macroquickview.png"><img class="alignnone size-medium wp-image-1346" src="https://blogs.sas.com/content/sasdummy/files/2011/11/macroquickview-300x141.png" alt="" width="450" srcset="https://blogs.sas.com/content/sasdummy/files/2011/11/macroquickview-300x141.png 300w, https://blogs.sas.com/content/sasdummy/files/2011/11/macroquickview.png 600w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<h2>Source code available on GitHub</h2>
<p>I created this tool years ago as a custom task, but it's been included with SAS Enterprise Guide as an "official" tool for several releases.  I built the task <a href="http://support.sas.com/documentation/onlinedoc/guide/customtasks/">using the custom task APIs and Microsoft .NET</a>.  If you're interested, I've shared a <a href="https://github.com/cjdinger/SasMacroViewer">version of the source code behind this task on GitHub</a>.</p>
<p>The post <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy/2020/02/27/inspecting-sas-macro-variables-in-sas-enterprise-guide/">Viewing SAS macro variables in SAS Enterprise Guide</a> appeared first on <a rel="nofollow" href="https://blogs.sas.com/content/sasdummy">The SAS Dummy</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=qIerg0BnGdE:wxs0_n7oScM:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=qIerg0BnGdE:wxs0_n7oScM:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=qIerg0BnGdE:wxs0_n7oScM:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=qIerg0BnGdE:wxs0_n7oScM:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=qIerg0BnGdE:wxs0_n7oScM:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=qIerg0BnGdE:wxs0_n7oScM:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=qIerg0BnGdE:wxs0_n7oScM:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?i=qIerg0BnGdE:wxs0_n7oScM:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=qIerg0BnGdE:wxs0_n7oScM:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?a=qIerg0BnGdE:wxs0_n7oScM:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/ASasBlogForTheRestOfUs?d=TzevzKxY174" border="0"></img></a>
</div>]]></content:encoded>
					
					<wfw:commentRss>https://blogs.sas.com/content/sasdummy/2020/02/27/inspecting-sas-macro-variables-in-sas-enterprise-guide/feed/</wfw:commentRss>
			<slash:comments>56</slash:comments>
		
		
			<enclosure url="https://blogs.sas.com/content/sasdummy/files/2011/11/macroview-150x150.png" />
	</item>
	</channel>
</rss>
