NESUG 2007 Coders' Corner An RTF Document Index: Easier Than You Think Electra Small, MDRC, New York, NY ABSTRACT With the ODS (Output Delivery System) RTF destination, SAS® users build tables that are opened directly in MS Word and other word-processing packages. A natural next step is to automate the creation of tables of contents and indexes for documents. The table of contents (TOC) and the index provide readers with road maps to find the tables of greatest interest to them. SAS does not yet build document indexes but there are RTF commands for building indexes. Further, SAS provides methods for embedding RTF commands in the Rich Text Format (RTF) documents it generates. This paper uses examples to clearly demonstrate how to mark words or phrases in SAS generated output for inclusion in an index in a RTF destination document. INTRODUCTION This is the third in a series of papers that chronicles a project that utilized SAS to create a book in a completely automated fashion. “The survey results book” had a title page, a table of contents, text and tables, and at the end a document index. In phase 1 of the project, Proc Tabulate was used to produce nicely formatted MS Word tables that documented the questions and responses from a telephone survey. This phase of the project was detailed in a paper presented at NESUG 2005. Phase 2 of the project utilized SAS to add a table of contents to the results book. This process was documented in a paper presented at NESUG 2006. The focus of this paper, Phase 3 of the project, used SAS to construct a document index. The index created an alphabetical listing of every table or set of survey results (e.g. age, gender, employment status) presented in the book. The title page will be the topic of a future paper. There are currently no commands that trigger SAS to build an index at the end of the results it generates. But SAS has methods for passing RTF commands from a SAS program into a RTF document and there are RTF commands that can be used to trigger RTF software (such as MS Word) to build document indexes. As can be imagined, SAS doesn’t recognize or process the RTF commands. Interspersing these RTF commands in a SAS program can cause SAS syntax errors unless done carefully. This paper uses 5 examples to demonstrate the SAS syntax to pass RTF commands from SAS into a RTF document. The paper focuses on how to pass RTF index building commands to mark words or phrases in SAS generated output for inclusion in the document index. When the SAS generated RTF document is opened in a word processor, the word processor completes the work by creating the index. CREATING INDEXES IN MS WORD To understand the RTF commands that must be passed from SAS to the RTF document, it is helpful to have some background knowledge about how indexes are produced in MS Word documents. One method of creating an index is to highlight a word or phrase (the index entry) and mark it for inclusion by pressing ALT+SHIFT+X and then clicking “Mark.” You will notice that {XE “Marked text”} appears next to the highlighted area; these codes are RTF index entry commands. After marking all the index entries, position the cursor where the index is to be located. From the menu, select InsertÆReferenceÆIndex and TablesÆIndexÆOK. MS Word collects all the index entries that were marked and places these alphabetically in the document index. This “index table” is also generated by RTF commands that are hidden behind the document index. To view the RTF commands, press ALT+F9 (a toggle), which reveals: {INDEX \c "2" \z "1033}. This command and parameters are detailed later. For now, note that to mark words for inclusion in the index the {XE “Marked text”} command must be passed. To build the document index table at the end of the document the {INDEX \c "2" \z "1033} command must be passed. As an aside, if the SAS-generated RTF document is “post edited” (i.e., adding text or custom headers, page breaks, tables), these modifications may change the page locations of the index entries. In MS Word to update a document index after any document edits, press Ctrl+A (to select all) and then F9 (to update the index), selecting “entire table” if prompted. This step is also advisable if changes are made to the page size or even printer selection. USING SAS TO PASS RTF COMMANDS The next step is to use SAS to pass the RTF commands into the RTF document. RTF documents are text documents. Open an RTF document with any text editor (e.g., Notepad); RTF commands are interspersed with the text, as shown in the left-hand column in the following table. Open this document with any RTF reader software (e.g., MS Word); formatted text as shown in the right-hand column is displayed. Text with RTF control strings or commands {I was }{\b very }{\ul happy}{ to hear}. Text rendered in MS Word I was very happy to hear. 1 NESUG 2007 Coders' Corner The RTF command \b is responsible for formatting the word “very” into boldface type, and \ul causes the word “happy” to be underlined. Note that the RTF commands (or RTF control words) are translated into formatting when such documents are opened with RTF reader software. The focus of this paper concerns similar RTF commands that can signal RTF readers to mark index entries and build the document index. To use a SAS program to build an automated document with an index these steps are followed: 1) use SAS to build tables (via Proc Tabulate, Report, Freq, Means…) 2) use ODS to send the tables to the RTF destination 3) use SAS to pass along RTF commands (that you supply) to the RTF destination without interfering with your SAS program. Notice in the table above {and \ are RTF evaluation triggers. These symbols don’t show in the display document they are triggers that request evaluation by the RTF software. But the {and \ symbols could also be part of literal text that might need to be displayed in the document. For example: TITLE “Printed from D:\Files”; The \ symbol in the text of the Title statement should be displayed, it is not the start of an RTF control word to be evaluated by the reader software. By default SAS signals the RTF reader software that all special characters (e.g. \ {) are to be displayed and not evaluated. In SAS’ terms it protects special characters. To embed RTF commands in a destination document SAS syntax must be used that signals to SAS that the text that follows is not to be protected in the destination document, otherwise {\b very }{\ul happy} will be displayed literally as {\b very }{\ul happy} in the document. The destination is the RTF document being created through SAS. The following command, ODS RTF FILE="C:\Files\TEST.RTF", creates an RTF destination document, TEST.RTF, on the C: drive, in the Files directory. There are two ways to place, or “pass,” RTF commands into the TEST.RTF document. Pass Technique 1 utilizes the ODS ESCAPECHAR statement and escape character sequences. Similar to the macro trigger characters (%,&), the escape character lets the SAS compiler know that what follows are RTF commands to be passed to the destination document. First, declare an ODS escape character: ODS ESCAPECHAR=’^’;. From this point forward, using the declared ODS escape character combined with any of the allowed escape sequence codes causes these codes to be passed to the destination document. Escape sequence code combinations are allowed wherever SAS allows a text string (e.g., titles, footnotes, labels, character variable values). The following example shows an ODS escape sequence. Example: TITLE '^R/RTF"\b" Very ^R/RTF"\b0\ul" Happy';. Notice the RTF commands are surrounded by quotes within the title quotes. This statement passes the \b, \b0 (bold off), and \ul RTF formatting commands to the RTF document, and Very Happy becomes the title line in your output. The ^R signals SAS that what follows is not to be protected from RTF evaluation. The /RTF signals that the text string that follows should be passed to the RTF document only. On occasion programmer use ODS to write to two or more types of destinations at the same time. If writing to RTF and PDF documents simultaneously the /RTF"\b" and /RTF"\b0\ul" commands are not passed to the PDF destination document. This is important since these commands are only understood by RTF readers. This technique uses a SAS raw text (^R) escape sequence, which is handy when only a few control words need to be unprotected. The syntax of this technique involves nesting single and double quotes; therefore, including any text with macro triggers or literal quote marks becomes a challenge. Pass Technique 2 utilizes RTF control words directly. To use this technique PROTECTSPECIALCHARS=OFF must be specified as an inline style on the proc (print, tabulate, report) or as a style attribute in a PROC TEMPLATE statement before the proc. This tells SAS to pass special characters (<>&/{), tags, and control words to the destination document without any translation, which allows the reader software to decide how to handle them. Once PROTECTSPECIALCHARS is turned off RTF control words can be used in your SAS program wherever a text string is allowed. Example: TITLE ‘\b Very \b0 \ul Happy’. This statement passes the \b,\b0, and \ul RTF formatting commands to the RTF document, and Very Happy becomes the title line in the output. Unfortunately, SAS does not currently have a way of setting the PROTECTSPECIALCHARS attribute to off for a whole document, instead commands must be issued to turn this attribute to off in each area of the output where RTF control words will be used (e.g. titles and footers, by lines, data, column headers, row headers…). Programmers who are not comfortable with PROC TEMPLATE or in-line styles find this cumbersome. This section reviewed the methods available for passing RTF commands from SAS to RTF destination documents. The following sections detail the use of these concepts to build indexes in RTF documents. MARKING INDEX ENTRIES IN SAS GENERATED OUTPUT Here is a simple programming example using the standard SASHELP.CLASS data set. One-way tables are produced using Proc Freq. ODS is used to create an RTF document named INDEX.RTF containing the Proc Freq output. This is a very simple and routine programming task. However, when the one-way tables are generated they must also be marked for inclusion in the document index. The Label statement is used just before the Proc Freq to label the variables. Since the RTF \xe control word is included as part of the variable labels when Proc Freq displays the variable label in the SAS generated tables the word processor will not only see the variable label it will also see an embedded command to include the variable label when the document index is built. 2 NESUG 2007 Coders' Corner data class; set sashelp.class; label Name ="^R/RTF' Sex ="^R/RTF' Age ="^R/RTF' Height="^R/RTF' Weight="^R/RTF' {\xe {\xe {\xe {\xe {\xe name}'" sex}'" age}'" height}'" weight}'"; run; ods rtf file="index.rtf" notoc_data; ods noproctitle; ods escapechar='^'; title; run; proc freq data=class; run; ODS RTF startpage=now; ods rtf text="{\pard\f2\b\fs32\qc {Index of Variable Names} \par}"; run; /* ods rtf text="{\field{\*\fldinst {\\INDEX \\e "" }}}" ; run; */ ods rtf close; run; "" \\c ""4"" \\z ""1033"" Note the NOTOC_DATA option on the first ODS RTF statement. This turns off the version 9 default behavior of including TOC information in the destination document. This option is not needed; it was included here to keep the destination document clean and simple to understand. The NOPROCTIITLE statement on the second ODS RTF statement is also optional (without it “The Frequency Procedure” title would be displayed before each table). This was also included to keep the destination document clean and simple to understand. The ODS RTF STARTPAGE=NOW statement places a hard page break after all of the tables produced by the Proc Freq and just before the index section header we created using the ODS RTF TEXT= statement. The RTF TEXT= is similar to a SAS Title statement. The Title statement places the specified text on the top of every page of output until it is cancelled or replaced. With the ODS RTF TEXT= statement the text is displayed on only one page in the place where the command is issued. Notice that RTF formatting control words are used here to format the text. This RTF TEXT= statement generates a 16pt. (\fs32, specified in half points) centered (\qc) and bolded (\b) section header: “Index of Variables Names.” The \pard and \par control words mark off a paragraph. The document’s default font 2 (\f2) will be used. If you are running SAS version 8 the last ODS RTF TEXT= statement (which has been commented out) will build the document index. SAS changed the way the RTF TEXT= statement works in version 9 and as a result this command no longer works. Don’t despair. First, the hardest part of building a document index is marking all of the entries. In this example we marked the index entries as part of the variable label statement. The method of marking index entries with the \xe control word works in version 8 and 9. As displayed in an earlier section of this paper in MS Word building the index table at the end of the document is just a few menu keystrokes (InsertÆReferenceÆIndex and TablesÆIndexÆOK). Secondly, there is a SAS version 9 workaround for building the index table from within a SAS program. The workaround is a bit complicated and it is a hacker’s solution so some might not feel it is worth the trouble. Therefore, for the time being, version 8 and 9 users should keep this line commented out and in a section later in the paper this command will be revisited with a full discussion of its use and its version 9 workaround. In the screen shot below a portion of the last frequency table and the document index is displayed. (Remember for now we are marking the index entries via the SAS program but we are generating the document index at the end of the document via MS Word commands: (InsertÆReferenceÆIndex and TablesÆIndexÆOK). 3 NESUG 2007 Coders' Corner To view the INDEX.RTF document created by the program open it in MS Word. To view the index entry (\xe) RTF control commands we have hidden in this document select the Show/Hide ¶ icon on the Standard toolbar. The previous example demonstrated the use of a Label statement to mark index entries. The next programming example demonstrates the use of a procedure option to mark index entries. This program creates two-way tables using Proc Tabulate. The statistic requested for each of the tables is a mean. In this example instead of using the variable label statement to mark the index entries the BOX= option of Proc Tabulate is used to pass the \xe control word and mark each index entries. For those who know Proc Tabulate the coding of this example should be clear. ods rtf file="index.rtf" notoc_data ; ods noproctitle; ods escapechar='^'; title; run; PROC TABULATE data=sashelp.class; var age height weight; CLASS sex; table age *MEAN,sex /BOX=[label="Item 1 ^R/RTF' {\xe age}" ]; table height*MEAN,sex /BOX=[label="Item 2 ^R/RTF' {\xe height}" ]; table weight*MEAN,sex /BOX=[label="Item 3 ^R/RTF' {\xe weight}" ]; RUN; ODS RTF startpage=now; ods rtf text="{\pard\f2\b\fs32\qc {Index of Variable Names} \par}"; run; ods rtf close; run; Tip: In the code above the single quote started just after the /RTF clause is not closed. The terminating quote is not required if no standard text follows the RTF index entry command. This is a helpful tip when programmers want to use ODS raw text escape sequences together with macro triggers that will not resolve within single quotes. Below is a screen shot of the last Proc Tabulate table and the document index that was produced: (Remember use MS Word commands to build the index table: (InsertÆReferenceÆIndex and TablesÆIndexÆOK). Again to view the INDEX.RTF document created by the program open it in MS Word. To view the index entry (\xe) RTF control commands we have hidden in this document select the Show/Hide ¶ icon on the Standard toolbar. The third example employs the Title statement to mark index entries. In this example Proc Report is used to generate a print of the data for each record. The records are sorted and printed by name using by-group processing and Proc Report. Since by-group processing is used the #BYVAR and #BYVAL options on the Title statement can be used. During by-group processing the #BYVAR options can be used to display in the SAS title the variable name(s) by which the file is being processed. Similarly, the #BYVAL options can be used to display the current value of the by variable(s) in the SAS title. In the following example the file is processed by name so including the #BYVAL option in the Title statement will cause the title on the top of each page to change and display the value of name on the current record. SAS is changing the name on each page in an automated fashion, therefore, by embedding the RTF index entry control word (\xe) in the Title statement each time SAS generates a new title that new value of name in the title is marked for inclusion in the document index. 4 NESUG 2007 Coders' Corner options nocenter nobyline; proc template ; define style RTFCW; parent=styles.rtf; style data from data /protectspecialchars=off; style header from header /protectspecialchars=off; style rowheader from rowheader / protectspecialchars=off; style systemtitle from systemtitle /protectspecialchars=off; style systemfooter from systemfooter /protectspecialchars=off; style usertext from usertext /protectspecialchars=off; style byline from byline /protectspecialchars=off; end; run; ods rtf file="index.rtf" notoc_data style=rtfcw bodytitle; ods noproctitle; run; PROC sort data=sashelp.class out=class; by name; PROC REPORT data=class; column sex age height weight; by name; title "Printing one person per page. This page is for #byvar(name)= {\xe #byval(name)}"; RUN; title; ODS RTF ods rtf \par}"; ods rtf startpage=now; text="{\pard\f2\b\fs32\qc {Listing of Persons Included in this Document} run; close; run; Notice that NOBYLINE is specified in the option statement. SAS procedures by default document changes in by variables and by values in the output. However, when using the Title statement to document the changes in by variables and by values use the NOBYLINES system option to cause the procedures to suppress this default behavior because the programming of the Title statement will document this in a more custom manner. In this example SAS passes RTF control words directly to the destination document without using an ODS ESCAPECHAR (e.g. ^ in previous examples). When passing ODS controls words directly without using an escape sequence PROCTECTSPECIALCHARS must be turned to OFF. Proc Template was used to do this by creating a new style template: RTFCW. The first ODS RTF statement references this new style (style=rtfcw) when INDEX.RTF is opened. The BODYTITLE option is also specified, this requests that the SAS titles be included in the body of the document not in the header section of the document. Index entries are only collected from the body of the document so the BODYTITLE option must be specified anytime the index entry information is marked in the SAS titles. Next a standard Proc Sort and Proc Report are used to create the printed report. One person’s data will be printed on each page of the RTF document until every record in the dataset has been printed. Notice that {\xe #byval} is included as part of Title statement. Each time the value of #byval changes that new value will be marked as an index entry by the \xe control word that has been embedded in the Title statement. Below is a screen shot of the last page of the Proc Report and a portion of the document index that was produced: (Remember for now we are marking the index entries via the SAS program but we are generating the document index at the end of the document via MS Word commands: (InsertÆReferenceÆIndex and TablesÆIndexÆOK). 5 NESUG 2007 Coders' Corner The fourth example makes use of user defined formats. Proc Format’s Value statement is used to mark index entries. This is another simple and straightforward programming task. Split the class roster into two listing, females in the class on one listing and males on the other. A Proc Print is done by sex to create the gender based rosters. The index is to list the page numbers of each roster. A user defined format is created that give F and M the more reader friendly Male and Female labels. This Proc Format also includes the index entry control word along with the Male and Female labels. Next the $fsex format that was created with Proc Format is assigned to GENDER on the Proc Print. Note that the RTFCW style template created in the last example is also referenced here. This style template is referenced to turn off PROTECTSPECIALCHARS in all relevant sections of the output. proc format; value $fsex "M"="{\xe Males}" "F"="{\xe Females}"; data class; set sashelp.class; Gender=Sex; label Gender="Student's Gender"; run; ods rtf file="index.rtf" notoc_data style=RTFCW; ods noproctitle; run; proc sort; by Gender Name; PROC print data=class; by Gender; pageby Gender; var Name Sex Age Height Weight; format Gender $fsex.; Title "Reporting Class List by Gender"; RUN; Title; ODS RTF startpage=now; ods rtf text="{\pard\f2\b\fs32\qc {Reports} \par}"; run; ods rtf close; run; Below is a screen shot of the last page of the Proc Print and the document index that was produced: (Remember for now we are marking the index entries via the SAS program but we are generating the document index at the end of the document via in MS Word commands: (InsertÆReferenceÆIndex and TablesÆIndexÆOK). 6 NESUG 2007 Coders' Corner The programming segment in the previous example is tweaked slightly for our next example. The fifth and last example provides an example of marking variable values for inclusion in the document index. Names are sometime unisex and it might not be clear if the sought for name would be found on the female roster or the male roster. Therefore, the page numbers of each student’s name are added to the index listing. The \xe index entry marker is concatenated to variables values (names) using an assignment statement in the data step. proc format; value $fsex "M"="{\xe Males}" "F"="{\xe Females}"; data class; set sashelp.class; Gender=Sex; label Gender="Student's Gender"; xName="{\xe "||Name||"}"; run; ods rtf file="index.rtf" notoc_data style=RTFCW; ods noproctitle; run; proc sort; by Gender Name; PROC print data=class; by Gender; pageby Gender; var xName Sex Age Height Weight; format Gender $fsex.; Title "Reporting Class List by Gender"; RUN; Title; ODS RTF startpage=now; ods rtf text="{\pard\f2\b\fs32\qc {Index} \par}"; run; ods rtf close; run; Below is a screen shot of the last page of the Proc Print and the document index that was produced: (Remember for now we are marking the index entries via the SAS program but we are generating the document index at the end of the document via MS Word commands: (InsertÆReferenceÆIndex and TablesÆIndexÆOK). 7 NESUG 2007 Coders' Corner Five examples have been given that illustrate ways to mark parts of SAS generated output for inclusion in a document index. The Label statement, the BOX= options of Proc Tabulate, the Title statement, the format procedure, and the data step assignment statement were all used to mark words or phrases in SAS output for inclusion in the document index. Output from Proc Freq, Tabulate, Report, and Print were all marked in some way. These are just examples and many more options for marking portions of SAS output are available. The key to generalizing the principles demonstrated here to other SAS output situations is the understanding of how to use SAS to pass the RTF index entry control word (\xe) to the destination document. In the examples above RTF control words were passed using ODS raw text escape sequences. Direct RTF controls words were also passed after turning PROTECTSPECIALCHARS=OFF. The RTF TEXT statement was also used to pass control words. This was demonstrated in the way we used the RTF TEXT statement and direct RTF control words to place a formatted header or title just before each index table. The next section will discuss the use of the RTF TEXT statement to pass the \index control word to build the index table. GENERATING THE DOCUMENT INDEX The document index is really a dynamic table that is generated by MS Word. It needs to be dynamic because if a page break is added, the paper size is changed, or a word that had been marked for inclusion in the index is deleted then the table that MS Word created will need to be regenerated or updated to reflect these changes. To issue a RTF command via SAS to build the dynamic index the following command in version 8 will work: ods rtf text="{\field{\*\fldinst {\\INDEX \\e "" "" \\c ""4"" \\z ""1033"" }}}" ; run; The \index control word is a field code control word. MS Word has field codes like date, file name, and time. Field code controls are dynamic. The values of field codes can change; therefore, the use of these controls requires execution and if conditions change these commands must be re-executed. The \e “” parameter specifies that the words in the index and the page numbers in the index should be separated by blanks. The parameter \c “4” specifies that the index table should have 4 columns. The \z “1033” parameter specifies that the index should be built in English. Having included this command in the SAS program the next step is to open the generated RTF document in MS Word. Go to the end of the document (or to the place in the document where the above command was issued). No table will be visible in the document. The command to build the table is embedded in the document (you can see the embedded command by toggling ATL+F9) but the command must be executed. Press Ctrl+A (to select all) and then F9 (to buld/update the index), selecting “entire table” if prompted. Because the index table is build dynamically by using the whole of the document settings at the point when the command is executed this step must always be taken. There is no way to automate this step. Further, if any changes are made after “executing” the table the steps should be repeated to rebuild the table. So it might be asked what steps does issuing ods rtf text="{\field{\*\fldinst {\\INDEX \\e "" "" \\c ""4"" \\z ""1033"" }}}" ; run; save the user? When you issue the above command via SAS the user does not have to select the following from the MS Word menu: InsertÆReferenceÆIndex and TablesÆIndexÆOK. Why doesn’t passing the \index control word work in version 9? In version 8 the text of a RTF TEXT= command is placed in a paragraph in the destination document. In version 9 the text of a RTF TEXT= command is placed in a table in the destination document. The \index command is a field code that builds a table dynamically so it can’t be 8 NESUG 2007 Coders' Corner placed inside of another table. MS Word interprets this as a dynamic table being executed within a static table and this generates an error. There is a version 9 workaround that first closes the static table that SAS opened and then issues the \index field command: ODS RTF startpage=now; ods rtf text="{\pard\f2\b\fs32\qc {Index of Variable Names} \par\cell}{\row}\pard{\field{\*\fldinst {\\INDEX \\e "" "" \\c ""4"" \\z ""1033"" }}}\par\trowd\trgaph180\cellx1440\pard\intbl{}"; run; This is admittedly a hacker’s solution and may not be worth the bother of placing this tedious and somewhat foreign code into a SAS program. It is included in the paper because some readers will feel comfortable with it. Programmers who are familiar with advanced RTF commands won’t find it foreign coding. In later releases of version 9 SAS has promised that there will be way to do this via custom tagsets. But RTF tagsets are not fully functional in version 9.1.3. CONCLUSION Regardless of which method you use, there are three steps that must be taken to build an index in a RTF document. First, throughout the document intersperse the text (words, phrases, etc.) that will eventually become entries in the index. Next, as these words are added throughout the document, they must also be marked with codes that indicate that this is the text that should become a part of the index. Third, create the index. The paper demonstrated the automating of this process using SAS. This was done by passing the RTF index entry control word (\xe) along with other SAS text strings in the example programs. In this way SAS allows users to embed RTF commands along with other text in SAS programs. Any where in a SAS program where you can specify a literal text string (e.g., titles, footnotes, labels, text variable values) you can embed the RTF index entry control word (\xe) that would mark that text string for inclusion in the document index. Once text strings have been marked for inclusion in the index, next an index table must be built. This can be done using the menu in MS Word or by passing RTF commands (\index) using the ODS RTF TEXT statement. In either case you populate and update the index when you open the RTF document by pressing Ctrl-A+F9. REFERENCES SAS Live Web Training Class: Advanced Output Delivery System Topics Course. Support.sas.com FAQ on proc template and ODS: http://support.sas.com/faq/040/FAQ04018.html TOC via \R/RTF"\s1 " RTF specification information: http://msdn.microsoft.com/library/?url=/library/en-us/dnrtfspec/html/rtfspec.asp http://www.oreilly.com/catalog/rtfpg/ Resource guidebook for sale Microsoft’s TOC and Index tutorials: http://office.microsoft.com/training/training.aspx?AssetID=RC011356771033 http://office.microsoft.com/training/training.aspx?AssetID=RC011525811033 Papers: How to Do Horrible Things with Raw RTF Specifications and the SAS RTF ODA, http://support.sas.com/rnd/papers/sugi27/rtfoda.pdf Skinning the Cat This Way and That: Using ODS to Create Word Documents that Work for You, Elizabeth Axelrod, David Shamlin, http://www2.sas.com/proceedings/sugi29/084-29.pdf Markup 101: Markup Basics, Cynthia Zender, http://support.sas.com/rnd/papers/sugi29/markupbasics.pdf Applying Microsoft Word Styles to ODS RTF, Output Lauren Haworth, http://www2.sas.com/proceedings/sugi30/043-30.pdf 9 NESUG 2007 Coders' Corner ACKNOWLEDGMENTS Cynthia Zender, Chevell Parker, Paulette Staum, Wayne Hester, and Eric Gebhart all helped by answering questions, providing information, reviewing the paper, recommending resources, and/or proofreading. CONTACT INFORMATION Electra Small Senior Technical Associate II MDRC 212-340-8824 (Direct) 16 East 34th Street, 19th Floor New York, NY 10016 Electra.Small@mdrc.org SAS and all other SAS Institute Inc. product or service names are registered trademarks or trademarks of SAS Institute Inc. in the USA and other countries. ® indicates USA registration. Other brand and product names are trademarks of their respective companies. 10