Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Tools

Fortran & GUIs


JUN91: FORTRAN & GUIS

John is a senior research engineer with the Georgia Tech Research Institute, where he specializes in radar and antenna research. He is also development manager for Scientific Concepts and can be reached there at 2359 Windy Hill Road, Suite 201-J, Marietta, GA 30067.


Since its creation in 1957, the Fortran language has been used in applications well beyond its original scope of FORmula TRANslation. Indeed, computers, operating systems, compilers, and peripherals have grown in complexity and capability at an almost exponential rate. While Fortran evolved from Fortran 66 to Fortran 77 (and hopefully soon to Fortran 90), a technological explosion in the ability to select and display large amounts of data with incredible speed and accuracy also occurred.

The basic I/O of CRTs has been supplemented with a wide variety of pointing and digitizing devices -- such as high-resolution scanners and graphics tablets -- with increasing demands for memory and speed. Simple operator interfaces and menus have expanded in scope to include these capabilities and requirements. As a by-product of this, a more universal concept called the Graphical User Interface (GUI) emerged. GUI-based applications span a wide range of implementations: from text-based pop-up windows to popular MIT X-Window-based products in Unix environments to Microsoft Windows and many other custom window systems. In the context of this article, GUI means a high-level bit-mapped menu system with many features common among CPU platforms and operating systems. Options are graphically represented and selections are made using a mouse or pointing device, with emphasis on reduced keystrokes and increased process, task and event monitoring.

Many applications written in Fortran (and other high-level languages) work perfectly well but could use a GUI "face lift." Perhaps the first thought is to give these applications a "cute" and more standard "windows look" by creating your own custom library of windows functions or interfacing with existing software tool kits.

In this article, I'll explore some of the options available to Fortran programmers in this area. Many programmers assume that because Fortran was not originally designed to write drivers, the only option available for creating a windows interface is to learn C and use the Windows SDK or X Window toolkit libraries. As you will see, low-level hardware and driver interface is certainly required for even the simplest of window interfaces, but by no means does this exclude Fortran applications from direct window support! I'll use programming examples and consider a few language factors as I explore options in creating more exciting menu displays that support Fortran-based applications. Regardless of whether you intend to design your own interface or shop around for the least painful windows interface kit, the information presented here will help you make a more informed decision.

Preparing Your Code for a GUI System

Prior to implementing a GUI system, a fundamental change in how you structure your program to handle parameter modifications might be in order. A menu-based implementation should minimize the amount of questions asked and answered by the user. In addition, user mistakes (bad input) should be trapped and rarely allowed to reach process tasks. In some cases, the windows environment itself seeks complete control of when and how any process or task interfaces with the user.

Windows programming tends to be more event driven than procedural and a few basic steps should be taken to make program conversion a little easier:

Centralize your application parameters as much as possible. In a menu system, parameters or variables are displayed in related groupings so that a user can see the current value at a glance and make changes by exception. By centralizing the routines for setting/displaying these global variables, functions or subroutines can be used as entry points for this process.

Group parameters based on association. As an extension of the centralization process, related variables can be placed in subroutines representing one or more submenus, as required. When the user clicks on an icon or widget to make a selection, the location of a pointing device or the cursor position can be used to uniquely identify a variable from the list. In this case, one subroutine sets all related variables and another subroutine performs the required operation based on the current values of the variables.

Utilize defaults and automatic variable initialization. At program startup or on demand, every variable of consequence should be given a meaningful initial value. This ensures that the user can operate quickly and safely without having to set every single variable in the system.

Substitute generic I/O routines for inline READ, WRITE, or OPEN statements. The usual approach to controlling user input consists of a program statement such as WRITE(LogicalUnit,...) followed by another program statement such as READ(LogicalUnit,...). This method should be replaced with a more generic function such as PROMPT(LogicalUnit,...). This provides more uniform program code appearance and makes modifying the I/O process much easier.

These ideas represent a few standard and modular structured programming techniques. There's a good chance your code already conforms in some or all of these areas. If not, you should seriously consider making such changes to your program(s) prior to any modifications for a GUI interface.

What's Required in a Language to Support GUI Development?

There are actually at least two stages of operator interface development beyond the simple "question --> wait for answer" type of program control. We can loosely define text-based pop-up windows as a simpler form of GUI interface for displays limited to characters instead of high-resolution bit maps. Figure 1 is an example of a typical text based pop-up menu display.

With this technique, the user selects choices highlighted by horizontal or vertical bars. The input and pointing devices recognized can be anything from mice, keyboards, or digitizer pads to light pens. As we move to more sophisticated GUI interface such as Microsoft Windows or Unix X Window, the list of support functions grows in number and complexity. Instead of text-based video memory, we use the bit-mapped graphics area. Each pixel on the screen is individually controllable. I/O becomes more complicated as events are distributed across machines and multitasking issues are raised. Requirements for speed and low-level driver interfaces to memory and hardware continue to expand the central theme of the design requirements. These factors cause concern for even a moderately experienced Fortran programmer.

Let's begin by considering the major requirements as if we are going to write this type of operator interface from scratch. This will take the form of a windows library of sorts. Because we will assume (for the moment) that we know all there is to know about windows development (we just haven't written the code yet), I'll name the new window system the MNIH ("My Not Invented Here") Windows Toolkit. To support the required features, we will "invent" a few library functions (top down approach). While the list of functions will not be complete at this point, it will illustrate some of the basic requirements for support of graphical and bit-mapped window systems. Our beginning step(s) include functions in logical groupings such as those in Table 1.

Table 1: Library functions required to implement the window library

InitGraphicsArea(Returncode) Finds and initializes the highest resolution graphics mode available. All workstations and video drivers are configured differently and have different capabilities. Return characteristics of current system to caller.

GetVideoPage(Pagenum) Returns the current video page number Pagenum to the caller for initialization and other bookkeeping. A video page refers to a region of memory representing characters displayed, and their attributes such as color and intensity. The characters are mapped through hardware in real time to the CRT screen. Therefore, reading/writing directly to/from video memory produces the instant pop-up/down effects in use today. Video page functions are primarily used in the pop-up text window modes.

SetVideoPage(Pagenum) Sets the display to the video page number Pagenum specified by the caller. In DOS-based systems, for example, this could be an integer in the range of 0-3 (CGA mode 2 or 3) to select the active display page (video services: Interrupt 10h, service 5).

CopyToVideoPage(Pagenum) Copies the current video page to a page specified by Pagenum. Used to create the instant pop-up/down window effect and to control the parent/child submenu or cascade process.

ReadWriteMemory(String,Row,Col,Pagenum) The character string String is copied to the Row and Column on the video page number specified.

Prompt(Question,Answer) Issues a prompt with a default answer string at the current cursor position. The user must be able to 'edit' or retype the Answer to reply. All required input devices such as a mouse or keyboard are scanned for a response.

ReadKbdNoWait(Keycode) Scans keyboard and returns code representing the key pressed. As defined, NoWait implies that if no key is pressed, this function must return immediately without waiting for a user response.

ReadMouse(Status,Row,Col) Returns mouse cursor position, if present, along with status codes representing the button(s) pushed. This function behaves in a fashion similar to that of the NoWait condition described in the ReadKdbNoWait function.

OpenCloseVerticalWindow(Menu, Foreground, Background, Status) Opens a Menu structure representing choices at the current row and specifies column position using the Foreground and Background colors. The height of the window box is automatically determined by the number of choices and the width by the longest character string in the list. A highlighted bar is scrolled vertically up and down the box as each choice is examined. The status code is used to open or close the window and to return other control codes to the program or process. Multiple window requests are stacked, representing various submenu or child processes. In bit-mapped modes, both window open functions become more complicated. As font sizes vary, the window dimensions must adapt accordingly.

OpenCloseHorizontalWindow(Menu, Foreground, Background, Status) Opens a Menu structure representing choices at the current row and specifies column position using the Foreground and Background colors. The length of the window box is automatically determined by the number of choices and the width of the highlight bar changes with each selection in the list. The status code is used to open or close the window and to return other control codes to the program or process.

SetWindowDimensions(Height, Width) Sets window display height and width using some internal unit of measure.

SetWindowBorder(Title) Displays title bar string across top of window.

SetWindowFont(Fontname) Looks up and initializes font (bit-mapped window only) for window operations.

GetWindowEvent(Eventcode) Waits for user input from mouse button, keyboard, trackball, and so on.

SpawnChildProcess(Childname) Loads and runs child process from current window. In single tasking systems, parent process suspends, pending termination of child. In multitasking systems, child and parent may run concurrently.

Figure 2 illustrates a proposed class hierarchy of the MNIH Window System. (Note: A more complete MNIH implementation could require as few as 50 or as many as several hundred level 0 and level 1 functions. The numbers depend on the window modes of operation -- text-based versus bit-mapped -- and the level of window sophistication desired.)

The hierarchy diagram in Figure 2 illustrates an implied relationship between the functions of the MNIH library system. As you might suspect, the higher-level functions (level 2) have a much greater chance of being implemented entirely in Fortran. However, based on the nature and description of requirements, the low- and medium-level functions are beyond the capability and scope of the Fortran 77 language standard.

Program Example: Bell Curve Plot Utility

Listings One and Two (page 101 and 102 respectively) are the program and include files for a Gaussian distribution, or bell curve calculation and plotting utility called BELL. The program was originally written in ANSI X3.9-1978 Fortran 77 and later enhanced using the military extensions defined in the MIL-STD-1753 standard. This standard is supported by many popular Fortran compiler environments such as Microsoft 5.0 and VAX Fortran.

The bell program is used to calculate a Gaussian distribution by getting multiple data values from the user (in the range 0-100), calculating the distribution constants for the Gaussian equation and plotting the results in histogram form followed by mean, variance, and other related values. Duplicate values are accounted for by the value supplied for the number of occurrences.

As discussed earlier, the bell program structure contains some modifications suggested for initial preparation in linking to a GUI interface library, such as:

Centralize application parameters and Group parameters based on association. In this example program, the parameters are located in the common include file. Routines can centrally access and control these parameters, as required.

Substitute generic I/O routines for inline READ, WRITE, or OPEN statements. User input is controlled through iprompt and drprompt routines for integer and double-precision reals. For a larger application with more variable types, a better approach might be to interpret all input as strings and convert it to the appropriate data types, as needed.

To extend the program as written to add a windows interface structure such as our MNIH example, the two routines GET_BELL_DATA( ) and PLOT_BELL_DATA( ) in the main program could be changed. You could call Get_bell_data from an open_window routine for controlling bell data input and Plot_bell_data could be called from another open_window routine to present the results of the Gaussian process.

Interestingly, languages such as C and Ada contain many built-in mechanisms from which to implement most of the routines at all levels indicated in Figure 1. In C, for example, direct access to memory locations is available in some form in every implementation. Keyboard and device I/O routines are varied and provide for many levels of access and control. Many of the window characteristics are best implemented with structures and records, where mixed variable types can be organized under one user-defined class. This can be readily done in C and many other high-level languages, including nonstandard vendor enhancements to Fortran 77.

Based on these and other factors, most window development software kits include software interface hooks for C.

At this point, we have sufficiently defined many of the requirements and language considerations in development interfacing to our MNIH library system. However, a few questions remain unanswered. If we were interested in implementing all levels of our MNIH library for Fortran applications, what options would we have? Do we implement levels 0 - 1 in C or assembler and fight a mixed-language interface war? Do we punt and wait for Fortran 90? Have we examined the problem from the proper perspective?

Another View of the MNIH Library and the GUI System

The layered approach to specification of the MNIH system allows examination of the menu library system's scope. To implement this kind of system, a blue print such as Figure 2 could be used. However, a better approach is to consider the two following facts:

  • As you might suspect, the MNIH library already exists in one form or another in commercially available X Toolkits or window development kits. For now, most cases require a mixed-language approach to supplement Fortran.
  • At the highest level of interface, the MNIH window creation calls bear a strong resemblance to the high-level file access routines! If you don't write drivers for file track and sector manipulation in Fortran, why should it be required for general-purpose window interfaces?
As GUI systems continue to mature, the level of standard interface at higher levels will become commonly available. Ideally, vendors supplying compilers could also supply "extensions" to make low-level MNIH implementations unnecessary. At the time of writing, Microsoft was the only company I am aware of that had already begun an aggressive campaign to close the development gap between Fortran and window interfaces. The newer version of the bell program running in a Microsoft Windows environment (Figure 2 through Figure 5) shows just how close a direct Fortran/Windows interface is to becoming reality.

These figures represent the result of windows interface modifications made to allow the bell curve program to execute in a Microsoft Windows 3.0 environment! The code used fits the patterns suggested earlier but with the addition of less than ten additional lines of source code! Compare this small effort to that of implementing the remainder of the MNIH low-level routines, especially if you are not already comfortable with C or assembler.

The final program changes were made using a beta version of the upcoming Microsoft Fortran. The following code fragments were the only changes required to make the bell program windows-based as in the figure.

In the main program, the line added to produce the help box "About Bell" in Figure 3 was: CALL ABOUTBOXQQ('Bell Curve Program\r Version 2.0'C). In the subroutines get_bell_data and plot_bell_data, a graphics logical unit was added to open a child window for I/O. The LU variable was replace with the GLU variable in the prompt calls. The code added is shown in Example 1.

Example 1: Code changes required to make the bell program a Windows 3-based application

  C
       INTEGER    GLU    !LOGICAL UNIT NUMBER
  C
       GLU=10
       OPEN (UNIT=GLU, FILE = 'USER')
  .
  .    (See Listings 1-2 for rest of body)
  .
  C
       CLOSE (GLU, STATUS = 'KEEP')
  C

The STATUS = 'KEEP' part of the close call is used to keep the child windows in view until the application is finally exited. Microsoft refers to this level of window interface as "Quick Window." As the first child window is opened for data values, the window error checking is automatically activated, as shown in Figure 4. Figure 5 shows final bell data output as the last child window opened. Note that the window unit numbers match the logical unit assignments in the program fragments.

For more sophisticated icon and parameter control, additional levels of interface are made available through this window development system.

Where Best to Put Your Development Efforts!

This article defines a high-level structure for developing custom GUI library systems. For those truly interested in developing their own window library system, the blueprint is here to follow. Unfortunately for the Fortran purist, the Fortran 77 standard simply does not allow this task to be performed without investing serious effort in writing mixed-language libraries and a lot of interface code. Happily, this is not the only option available.

A great deal of effort should be spent in providing better structure to Fortran code prior to the window treatments. The Fortran 90 standard should make this effort much easier (provided it's universally implemented during this century!).

Aside from Fortran implementation issues, larger issues concern the nature and definition of the GUI itself. As GUI interface concepts continue to mature and become more of a standard device type, the lower-level driver support of languages other than C will increase. By carefully structuring your software applications, you can take advantage of any of these cases and increase program portability without severe changes to most of your code.


_FORTRAN & GUIS_
by John L. Bradberry


[LISTING ONE]
<a name="0142_000c">

C    >**************************************************************
      PROGRAM BELL
C     **************************************************************
C     AUTHOR: JOHN L. BRADBERRY         CREATION DATE: FEB 15,1989
C     UTILITY TO CREATE A BELL CURVE DATA 'PLOT' BY READING IN A SERIES
C     OF NUMBERS IN THE RANGE OF 0-100. THE NUMBERS ARE USED TO CREATE
C     THE GAUSSIAN DISTRIBUTION CONSTANTS. THE CONSTANTS ARE THEN USED TO
C     CALCULATE A NORMAL DISTRIBUTION FROM 0 TO 100 IN STEPS OF 5. '*' ARE
C     PLOTTED IN HISTOGRAM FORM TO SIMULATE BELL SHAPE.
C     --------------------------------------------------------------
C
      IMPLICIT NONE
C
      INCLUDE 'BELLCOM.INC'
C
C
      INTEGER*2         LU              !LOGICAL UNIT NUMBER
C
      LU=6
C
C     INITIALIZE BELL CURVE DATA (CONTAINED IN COMMON)...
C
      BCIDX=0
      BCTOT=0
      BCEX=0
      BCEXS=0


C     GET BELL CURVE VALUES FROM USER TO BE USED FOR CALCULATIONS...
C
      CALL GET_BELL_DATA(LU)
C
C     CALCULATE CONSTANTS FOR GAUSSIAN DISTRIBUTION AND PLOT BELL CURVE
C     USING THE '*' CHARACTER...
C
      CALL PLOT_BELL_DATA(LU)
C
C
      END
C
C    >**************************************************************
      SUBROUTINE GET_BELL_DATA(LU)
C     **************************************************************
C     SUBROUTINE TO PROMPT USER FOR INTEGER VALUE...
C     --------------------------------------------------------------
C     AUTHOR: JOHN L. BRADBERRY         CREATION DATE: FEB 8,1989
C
      IMPLICIT NONE
C
      INCLUDE 'BELLCOM.INC'
C
C
      INTEGER*2         I               !LOOP INDEX COUNTER
      INTEGER*2         LU              !LOGICAL UNIT NUMBER
      INTEGER*2         BCCOUNT         !BELL CURVE DATA POINT COUNT
C
C
      BCCOUNT=1
      DO WHILE (BCCOUNT.GT.0)
C
        CALL IPROMPT(LU,'Enter Number Of Occurrences Next Data Point '//
     +                  'Value (Or 0 To Exit).',BCCOUNT)

        IF (BCCOUNT.GT.0) THEN
          CALL DRPROMPT(LU,'Enter Data Point Value (Range 0-100):',
     +                  BCDAT)
        END IF
C
        IF (BCCOUNT.GT.0) THEN
          DO I=1,BCCOUNT
            BCIDX=BCIDX+1
            BCTOT=BCTOT+BCDAT
          END DO
          BCEX=BCEX+BCCOUNT*BCDAT
          BCEXS=BCEXS+BCCOUNT*BCDAT*BCDAT
        END IF
      END DO
C
C

      RETURN
      END
C
C    >**************************************************************
      SUBROUTINE PLOT_BELL_DATA(LU)
C     **************************************************************
C     SUBROUTINE TO PROMPT USER FOR INTEGER VALUE...
C     --------------------------------------------------------------
C     AUTHOR: JOHN L. BRADBERRY         CREATION DATE: FEB 8,1989
C
      IMPLICIT NONE
C
      INCLUDE 'BELLCOM.INC'
C
C
      INTEGER*2         LU              !LOGICAL UNIT NUMBER
      INTEGER*2         KX              !LOOP INDEX COUNTER
      INTEGER*2         STARCOUNT       !NUMBER OF STARS TO OUTPUT IN BELL
      INTEGER*2         MAXSTARS        !MAXIMUM STARS IN CHARACTER STRING

      PARAMETER         (MAXSTARS=51)

      CHARACTER         STARS*51        !STRING 'STAR' ARRAY

      REAL*8            RVAL1           !TEMPORARY
      REAL*8            RVAL2           !TEMPORARY
      REAL*8            DEGRAD          !DEGREES TO RADIAN CONVERSION
C
C
      STARS='***************************************************'
C
      DEGRAD=3.141592654D0/180D0
C
      IF (BCIDX.GT.0) THEN
        BCEX=BCEX/BCIDX
        BCEXS=BCEXS/BCIDX
        BCMEAN=BCEX
        BCVAR=BCEXS-BCEX*BCEX
        BCSIGMA=SQRT(BCVAR)
      END IF
C
C     BELL CURVE FORMULA...
C
C     1/(SIGMA(SQRT(2PI)))*EXP(-(X-MEAN)**2/(2*SIGMA))
C
      RVAL1=1.0/(BCSIGMA*SQRT(2*3.141592654))
      DO KX=0,100,5
        RVAL2=RVAL1*EXP(-1.0*((KX-BCMEAN)**2)/(2.0*BCSIGMA*BCSIGMA))
        RVAL2=1000*RVAL2

        STARCOUNT=MIN(NINT(RVAL2),MAXSTARS)
        WRITE(LU,*)KX,' |',STARS(1:STARCOUNT)
      END DO
C
      WRITE(LU,'(/,1X,A10,I2,2X,3(A10,F8.3,2X))')
     +      '# POINTS= ',BCIDX,'MEAN= ',BCMEAN,'VARIANCE= ',
     +      BCVAR,'   SIGMA= ',BCSIGMA
C
C
      RETURN
      END
C
C    >**************************************************************
      SUBROUTINE IPROMPT(LU,PROMPT,IVAL)
C     **************************************************************
C     SUBROUTINE TO PROMPT USER FOR INTEGER VALUE...
C     --------------------------------------------------------------
C     AUTHOR: JOHN L. BRADBERRY         CREATION DATE: FEB 8,1989
C
      IMPLICIT NONE
C
      INTEGER*2         IVAL            !INTEGER VALUE RETURNED
      INTEGER*2         LU              !LOGICAL UNIT NUMBER
C
      CHARACTER*(*)     PROMPT          !STRING PROMPT TO BE ISSUED
C
C
      WRITE(LU,*)PROMPT
      READ(LU,*)IVAL
C
C
      RETURN
      END
C
C
C    >**************************************************************
      SUBROUTINE DRPROMPT(LU,PROMPT,DRVAL)
C     **************************************************************
C     SUBROUTINE TO PROMPT USER FOR DOUBLE PRECISION REAL VALUE...
C     --------------------------------------------------------------
C     AUTHOR: JOHN L. BRADBERRY         CREATION DATE: FEB 8,1989
C
      IMPLICIT NONE
C
      INTEGER*2         LU              !LOGICAL UNIT NUMBER
C
      CHARACTER*(*)     PROMPT          !STRING PROMPT TO BE ISSUED

C
      REAL*8            DRVAL           !REAL VALUE RETURNED
C
C
      WRITE(LU,*)PROMPT
      READ(LU,*)DRVAL
C
C
      RETURN
      END
C




<a name="0142_000d">
<a name="0142_000e">
[LISTING TWO]
<a name="0142_000e">


C     -----------------------------------------------------------
C     BELL CURVE CONTROL COMMON ...
C     -----------------------------------------------------------
C
      INTEGER*2         BCIDX           !BELL CURVE INDEX
C
      REAL*8            BCMEAN          !BELL CURVE MEAN
      REAL*8            BCEX            !BELL CURVE EX TERM
      REAL*8            BCEXS           !BELL CURVE EX TERM SQUARED
      REAL*8            BCTOT           !BELL CURVE TOTAL
      REAL*8            BCDAT           !BELL CURVE DATA
      REAL*8            BCVAR           !BELL CURVE VARIANCE
      REAL*8            BCSIGMA         !BELL CURVE SIGMA
C
C
      COMMON /BELLCURVE/
C
     +BCIDX,
     +BCMEAN,
     +BCEX,
     +BCEXS,
     +BCTOT,
     +BCDAT,
     +BCVAR,
     +BCSIGMA
C



[Example 1]

C
      INTEGER           GLU             !LOGICAL UNIT NUMBER
C
      GLU=10
      OPEN (UNIT=GLU, FILE = 'USER')
.
.     (see listings 1-2 for rest of body)
.
C
      CLOSE (GLU, STATUS = 'KEEP')
C


Copyright © 1991, Dr. Dobb's Journal


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.