Hi Sarah,
My bias/prejudices regarding threads/ASTs are well known and I shall not
repeat them here. (Unless your ask specifically :-) But to try and be of
some help: - Yes you have to use GLOBAL memory. Isn't that why all this UNIX
threading crap has to mutex around simple things like ADD 1 TO
CONNECTION_COUNT? VMS, Processor modes, and ASTs do all this for you but if
you insist on going againts the grain then that's up to you. Surely some
sicko could come up with a C wrapper routine to inline the $ICC calls
anaologous to the way the C socket API wrappers the $qio calls?
Anyway, my suggestion is to have static (compile-time or run-time allocated)
memory database of active and free connections. The address of the
individual connection info to be passed to each AST. Clearly not my idea but
one that's been around since year dot and one I first noticed in the lovely
MACRO DECnet programming examples. What's that you say? They're no longer
there on Alpha? Well that's another story. . .
I've attached a COBOL example of calling $ICC services. (Not that it solves
your problem; just something (single-threaded) I was testing out as the $ICC
interface for COBOL was by no means intuitive)
Regards Richard Maher
RE: .3
I haven't fully explored this, but please explain why you would possibly
open more than one association per server?
$on warning then exit
$set def sys$login
$!
$create icc_def.mar
.title icc_def
.library "sys$library:lib.mlb"
$iccdef GLOBAL
.end
$!
$macro/lis icc_def
$!
$create icc_server.cob
identification division.
program-id. icc_server.
author. Richard Maher.
data division.
working-storage section.
01 ast_receive pic 9(9) comp value external
ast_receive.
01 ast_handshake pic 9(9) comp value external
ast_handshake.
01 ss$_normal pic 9(9) comp value external
ss$_normal.
01 sys_status pic 9(9) comp.
*
01 assoc_handle pic 9(9) comp.
01 buffer_count pic 9(9) comp value 5.
01 prot_sysprv pic 9(9) comp value 2.
*
procedure division.
kick_off section.
00.
perform server_init.
display "Hibernating. . .zzzzzz".
call "sys$hiber" giving sys_status.
if sys_status not = ss$_normal call "lib$stop" using by value
sys_status.
*
fini.
call "sys$icc_close_assoc" using by value assoc_handle giving
sys_status.
if sys_status not = ss$_normal call "lib$stop" using by value
sys_status.
stop run.
*
server_init section.
00.
call "sys$icc_open_assoc"
using by reference assoc_handle
by descriptor "ICC_TEST_SERVER"
by value 0, 0,
ast_handshake,
ast_handshake,
ast_receive,
buffer_count, prot_sysprv
giving sys_status.
if sys_status not = ss$_normal call "lib$stop" using by value
sys_status.
*
fini.
*
end program icc_server.
identification division.
program-id. ast_handshake.
data division.
working-storage section.
01 ast_discon pic 9(9) comp value external
ast_discon.
01 ss$_reject pic 9(9) comp value external
ss$_reject.
01 ss$_abort pic 9(9) comp value external
ss$_abort.
01 ss$_normal pic 9(9) comp value external
ss$_normal.
01 sys_status pic 9(9) comp.
*
01 rem_pid pointer.
01 buff_init_size pic 9(9) comp value 1024.
01 event_type pointer.
88 icc$c_ev_connect value external
icc$c_ev_connect.
88 icc$c_ev_disconnect value external
icc$c_ev_disconnect.
01 cxn_handle pointer.
01 cxn_data_len pointer.
01 cxn_p5.
03 cxn_p5_lw pointer.
66 cxn_reply_buff_len renames cxn_p5_lw.
66 cxn_discon_status renames cxn_p5_lw.
01 user_context.
03 iosb.
05 cond_val pic 9(4) comp.
05 pic x(6).
03 input_buff pic 9(9) comp.
03 input_buff_size pic 9(9) comp.
03 ios_icc.
05 icc_status pic 9(4) comp.
05 pic xx.
05 recv_len pic 9(9) comp.
05 req_handle pic 9(9) comp.
05 reply_len pic 9(9) comp.
*
linkage section.
01 by_val_event_type pic 9(9) comp.
01 by_val_cxn_handle pic 9(9) comp.
01 by_val_cxn_data_len pic 9(9) comp.
01 cxn_data_buff pic x(1000).
01 by_val_cxn_p5 pic 9(9) comp.
01 discon_user_context pic x(32).
01 rem_username pic x(12).
*
procedure division
using by_val_event_type,
by_val_cxn_handle,
by_val_cxn_data_len,
cxn_data_buff,
by_val_cxn_p5,
discon_user_context,
rem_username.
kick_off section.
00.
set cxn_handle to reference by_val_cxn_handle.
set cxn_data_len to reference by_val_cxn_data_len.
set cxn_p5_lw to reference by_val_cxn_p5.
set event_type to reference by_val_event_type.
evaluate true
when icc$c_ev_connect perform accept_reject_cxn
when icc$c_ev_disconnect perform remove_cxn
when other call "lib$stop" using by value
ss$_abort
end-evaluate.
*
fini.
exit program.
*
accept_reject_cxn section.
00.
set rem_pid to reference discon_user_context.
display "pid = ", rem_pid with conversion.
display "username = ", rem_username.
display "connect data = ", cxn_data_buff(1:cxn_data_len).
display "cxn_data_len is ", cxn_data_len with conversion.
display "reply_buff_len = ", cxn_reply_buff_len with conversion.
if cxn_data_buff(1:cxn_data_len) = "*Hello!*"
call "sys$icc_accept"
using by value cxn_handle
by reference "*accepted*"
by value 10
by reference user_context
by value 0
giving sys_status
else
call "sys$icc_reject"
using by value cxn_handle
by reference "*rejected*"
by value 10, ss$_reject
giving sys_status.
if sys_status not = ss$_normal call "lib$stop" using by value
sys_status.
call "lib$get_vm" using buff_init_size, input_buff giving sys_status.
if sys_status not = ss$_normal call "lib$stop" using by value
sys_status.
move buff_init_size to input_buff_size.
*
fini.
*
remove_cxn section.
00.
move discon_user_context to user_context.
display "Exit Status was ", cxn_discon_status with conversion.
call "sys$icc_disconnect"
using by value cxn_handle
by reference iosb
by value ast_discon
by reference user_context
by value 0,0
giving sys_status.
if sys_status not = ss$_normal call "lib$stop" using by value
sys_status.
*
fini.
*
end program ast_handshake.
identification division.
program-id. ast_receive.
data division.
working-storage section.
01 ast_read_comp pic 9(9) comp value external
ast_read_comp.
01 ss$_abort pic 9(9) comp value external
ss$_abort.
01 ss$_normal pic 9(9) comp value external
ss$_normal.
01 sys_status pic 9(9) comp.
*
01 cxn_handle pointer.
01 message_size pointer.
*
linkage section.
01 by_val_msg_size pic 9(9) comp.
01 by_val_cxn_handle pic 9(9) comp.
01 user_context.
03 iosb.
05 cond_val pic 9(4) comp.
05 pic x(6).
03 input_buff pic 9(9) comp.
03 input_buff_size pic 9(9) comp.
03 ios_icc.
05 icc_status pic 9(4) comp.
05 pic xx.
05 recv_len pic 9(9) comp.
05 req_handle pic 9(9) comp.
05 reply_len pic 9(9) comp.
*
procedure division
using by_val_msg_size,
by_val_cxn_handle,
user_context.
00.
set message_size to reference by_val_msg_size.
set cxn_handle to reference by_val_cxn_handle.
display "MSG Size = ", message_size with conversion.
if message_size > input_buff_size
call "lib$free_vm" using input_buff_size, input_buff giving
sys_status
if sys_status not = ss$_normal call "lib$stop" using by value
sys_status end-if
call "lib$get_vm" using message_size, input_buff giving sys_status
if sys_status not = ss$_normal call "lib$stop" using by value
sys_status end-if
move message_size to input_buff_size.
call "sys$icc_receive"
using by value cxn_handle
by reference ios_icc
by value ast_read_comp
by reference user_context
by value input_buff, input_buff_size
giving sys_status.
if sys_status not = ss$_normal call "lib$stop" using by value
sys_status.
*
fini.
exit program.
*
end program ast_receive.
identification division.
program-id. ast_read_comp.
data division.
working-storage section.
01 ss$_abort pic 9(9) comp value external
ss$_abort.
01 ss$_normal pic 9(9) comp value external
ss$_normal.
01 sys_status pic 9(9) comp.
*
linkage section.
*
01 user_context.
03 iosb.
05 cond_val pic 9(4) comp.
05 pic x(6).
03 input_buff pic 9(9) comp.
03 input_buff_size pic 9(9) comp.
03 ios_icc.
05 icc_status pic 9(4) comp.
05 pic xx.
05 recv_len pic 9(9) comp.
05 req_handle pic 9(9) comp.
05 reply_len pic 9(9) comp.
*
procedure division using user_context.
00.
display "in read ast".
if icc_status not = ss$_normal call "lib$stop" using by value
icc_status.
if req_handle not = zeros
display "Can't handle transceives"
call "lib$stop" using by value ss$_abort.
call "output_msg"
using by value input_buff
by reference recv_len.
*
fini.
exit program.
*
end program ast_read_comp.
identification division.
program-id. ast_discon.
data division.
working-storage section.
01 ss$_abort pic 9(9) comp value external
ss$_abort.
01 ss$_linkdiscon pic 9(9) comp value external
ss$_linkdiscon.
01 ss$_normal pic 9(9) comp value external
ss$_normal.
01 sys_status pic 9(9) comp.
*
linkage section.
*
01 user_context.
03 iosb.
05 cond_val pic 9(4) comp.
05 pic x(6).
03 input_buff pic 9(9) comp.
03 input_buff_size pic 9(9) comp.
03 ios_icc.
05 icc_status pic 9(4) comp.
05 pic xx.
05 recv_len pic 9(9) comp.
05 req_handle pic 9(9) comp.
05 reply_len pic 9(9) comp.
*
procedure division using user_context.
00.
display "in discon ast".
if cond_val not = ss$_normal and ss$_linkdiscon
call "lib$stop" using by value cond_val.
*
fini.
exit program.
*
end program ast_discon.
identification division.
program-id. output_msg.
data division.
working-storage section.
01 ss$_abort pic 9(9) comp value external
ss$_abort.
01 ss$_linkdiscon pic 9(9) comp value external
ss$_linkdiscon.
01 ss$_normal pic 9(9) comp value external
ss$_normal.
01 sys_status pic 9(9) comp.
*
linkage section.
*
01 out_buff pic x(65535).
01 out_len pic 9(9) comp.
*
procedure division using out_buff, out_len.
00.
display "message = ", out_buff(1:out_len).
*
fini.
exit program.
*
end program output_msg.
$!
$create icc_server.inp
$deck
$run icc_server
$eod
$!
$cobol/lis icc_server
$link icc_server,icc_def
$run/detach
sys$system:loginout.exe/out=icc_server.out/inp=icc_server.inp/process_name=i
cc_server
$!
$create icc_client.cob
identification division.
program-id. icc_client.
author. Richard Maher.
data division.
working-storage section.
01 ast_receive pic 9(9) comp value external
ast_receive.
01 ast_disconnect pic 9(9) comp value external
ast_disconnect.
01 ast_cxn_comp pic 9(9) comp value external
ast_cxn_comp.
01 ss$_wasclr pic 9(9) comp value external
ss$_wasclr.
01 ss$_wasset pic 9(9) comp value external
ss$_wasset.
01 ss$_normal pic 9(9) comp value external
ss$_normal.
01 sys_status pic 9(9) comp.
*
01 syi_item_list.
03 item_node_name.
05 pic 9(4) comp value 6.
05 pic 9(4) comp value external
syi$_nodename.
05 pointer value reference
node_name.
05 pointer value reference
node_name_length.
03 pic 9(9) comp.
*
01 syi_iosb.
03 syi_status pic 9(9) comp.
03 pic x(4).
01 node_name pic x(6).
01 node_name_length pic 9(4) comp.
*
01 assoc_handle pic 9(9) comp.
01 buffer_count pic 9(9) comp value 5.
01 prot_sysprv pic 9(9) comp value 2.
01 user_context.
03 iosb.
05 cond_val pic 9(4) comp.
05 pic x(6).
03 input_buff pic 9(9) comp.
03 input_buff_size pic 9(9) comp.
03 cxn_handle pic 9(9) comp.
03 return_buff pic x(512).
03 return_buff_len pic 9(4) comp.
*
procedure division.
kick_off section.
00.
perform client_init.
call "sys$setast" using by value 0 giving sys_status.
if sys_status not = ss$_wasset call "lib$stop" using by value
sys_status.
call "sys$icc_connect"
using by reference iosb
by value ast_cxn_comp
by reference user_context
by value assoc_handle
by reference cxn_handle
by descriptor "ICC_TEST_SERVER",
node_name(1:node_name_length)
by reference user_context, "*Hello!*"
by value 8
by reference return_buff
by value 512
by reference return_buff_len
by value 0
giving sys_status.
if sys_status not = ss$_normal call "lib$stop" using by value
sys_status.
display "Hibernating. . .zzzzzzz".
call "sys$setast" using by value 1 giving sys_status.
if sys_status not = ss$_wasclr call "lib$stop" using by value
sys_status.
call "sys$hiber".
call "sys$setast" using by value 0 giving sys_status.
if sys_status not = ss$_wasset call "lib$stop" using by value
sys_status.
display "Trying again.".
call "sys$icc_connect"
using by reference iosb
by value ast_cxn_comp
by reference user_context
by value assoc_handle
by reference cxn_handle
by descriptor "ICC_TEST_SERVER",
node_name(1:node_name_length)
by reference user_context, "1234567"
by value 7
by reference return_buff
by value 512
by reference return_buff_len
by value 0
giving sys_status.
if sys_status not = ss$_normal call "lib$stop" using by value
sys_status.
display "Hibernating. . .zzzzzzz".
call "sys$setast" using by value 1 giving sys_status.
if sys_status not = ss$_wasclr call "lib$stop" using by value
sys_status.
call "sys$hiber".
display "Exiting.".
*
fini.
call "sys$icc_close_assoc" using by value assoc_handle giving
sys_status.
if sys_status not = ss$_normal call "lib$stop" using by value
sys_status.
stop run.
*
client_init section.
00.
call "sys$getsyiw"
using by value 0, 0, 0,
by reference syi_item_list, syi_iosb
by value 0, 0
giving sys_status.
if sys_status = ss$_normal move syi_status to sys_status.
if sys_status not = ss$_normal call "lib$stop" using by value
sys_status.
call "sys$icc_open_assoc"
using by reference assoc_handle
by descriptor "ICC_TEST_CLIENT"
by value 0, 0, 0,
ast_disconnect,
ast_receive,
buffer_count,
prot_sysprv
giving sys_status.
if sys_status not = ss$_normal call "lib$stop" using by value
sys_status.
*
fini.
*
end program icc_client.
identification division.
program-id. ast_disconnect.
data division.
working-storage section.
01 ast_discon pic 9(9) comp value external
ast_discon.
01 ss$_abort pic 9(9) comp value external
ss$_abort.
01 ss$_normal pic 9(9) comp value external
ss$_normal.
01 sys_status pic 9(9) comp.
*
01 rem_pid pointer.
01 buff_init_size pic 9(9) comp value 1024.
*
linkage section.
01 event_type pic 9(9) comp.
88 icc$c_ev_connect value external
icc$c_ev_connect.
88 icc$c_ev_disconnect value external
icc$c_ev_disconnect.
01 cxn_handle pic 9(9) comp.
01 cxn_data_len pic 9(9) comp.
01 cxn_data_buff pic x(1000).
01 cxn_p5.
03 cxn_p5_lw pic 9(9) comp.
66 cxn_reply_buff_len renames cxn_p5_lw.
66 cxn_discon_status renames cxn_p5_lw.
01 user_context.
03 iosb.
05 cond_val pic 9(4) comp.
05 pic x(6).
03 input_buff pic 9(9) comp.
03 input_buff_size pic 9(9) comp.
03 a_cxn_handle pic 9(9) comp.
03 return_buff pic x(512).
03 return_buff_len pic 9(4) comp.
01 rem_username pic x(12).
*
procedure division
using event_type,
cxn_handle,
cxn_data_len,
cxn_data_buff,
cxn_p5,
user_context,
rem_username.
kick_off section.
00.
if icc$c_ev_disconnect
perform remove_cxn
else
call "lib$stop" using by value ss$_abort.
*
fini.
exit program.
*
remove_cxn section.
00.
display "exit Status was ", cxn_discon_status with conversion.
call "sys$icc_disconnect"
using by value cxn_handle
by reference iosb
by value ast_discon
by reference user_context
by value 0,0
giving sys_status.
if sys_status not = ss$_normal call "lib$stop" using by value
sys_status.
*
fini.
*
end program ast_disconnect.
identification division.
program-id. ast_receive.
data division.
working-storage section.
01 ast_read_comp pic 9(9) comp value external
ast_read_comp.
01 ss$_abort pic 9(9) comp value external
ss$_abort.
01 ss$_normal pic 9(9) comp value external
ss$_normal.
01 sys_status pic 9(9) comp.
*
01 ast_param.
03 ios_icc.
05 icc_status pic 9(4) comp.
05 pic xx.
05 recv_len pic 9(9) comp.
05 req_handle pic 9(9) comp.
05 reply_len pic 9(9) comp.
*
linkage section.
01 message_size pic 9(9) comp.
01 cxn_handle pic 9(9) comp.
01 user_context.
03 iosb.
05 cond_val pic 9(4) comp.
05 pic x(6).
03 input_buff pic 9(9) comp.
03 input_buff_size pic 9(9) comp.
03 a_cxn_handle pic 9(9) comp.
03 return_buff pic x(512).
03 return_buff_len pic 9(4) comp.
*
procedure division
using message_size,
cxn_handle,
user_context.
00.
display "MSG Size = ", message_size with conversion.
if message_size > input_buff_size
call "lib$free_vm" using input_buff_size, input_buff giving
sys_status
if sys_status not = ss$_normal call "lib$stop" using by value
sys_status end-if
call "lib$get_vm" using message_size, input_buff giving sys_status
if sys_status not = ss$_normal call "lib$stop" using by value
sys_status end-if
move message_size to input_buff_size.
call "sys$icc_receive"
using by value cxn_handle
by reference ios_icc
by value ast_read_comp
by reference ast_param
by value input_buff, input_buff_size
giving sys_status.
if sys_status not = ss$_normal call "lib$stop" using by value
sys_status.
*
fini.
exit program.
*
end program ast_receive.
identification division.
program-id. ast_read_comp.
data division.
working-storage section.
01 ss$_abort pic 9(9) comp value external
ss$_abort.
01 ss$_normal pic 9(9) comp value external
ss$_normal.
01 sys_status pic 9(9) comp.
*
linkage section.
*
01 ast_param.
03 ios_icc.
05 icc_status pic 9(4) comp.
05 pic xx.
05 recv_len pic 9(9) comp.
05 req_handle pic 9(9) comp.
05 reply_len pic 9(9) comp.
*
procedure division using ast_param.
00.
display "in read ast".
if icc_status not = ss$_normal call "lib$stop" using by value
sys_status.
if req_handle not = zeros
display "Can't handle transceives"
call "lib$stop" using by value ss$_abort.
*
fini.
exit program.
*
end program ast_read_comp.
identification division.
program-id. ast_discon.
data division.
working-storage section.
01 ss$_abort pic 9(9) comp value external
ss$_abort.
01 ss$_normal pic 9(9) comp value external
ss$_normal.
01 sys_status pic 9(9) comp.
*
linkage section.
*
01 user_context.
03 iosb.
05 cond_val pic 9(4) comp.
05 pic x(6).
03 input_buff pic 9(9) comp.
03 input_buff_size pic 9(9) comp.
03 a_cxn_handle pic 9(9) comp.
03 return_buff pic x(512).
03 return_buff_len pic 9(4) comp.
*
procedure division using user_context.
00.
display "in discon ast", cond_val with conversion.
if cond_val not = ss$_normal call "lib$stop" using by value cond_val.
call "sys$wake" using by value 0, 0 giving sys_status.
if sys_status not = ss$_normal call "lib$stop" using by value
sys_status.
*
fini.
exit program.
*
end program ast_discon.
identification division.
program-id. ast_cxn_comp.
data division.
working-storage section.
01 ast_xmit pic 9(9) comp value external
ast_xmit.
01 ss$_reject pic 9(9) comp value external
ss$_reject.
01 ss$_abort pic 9(9) comp value external
ss$_abort.
01 ss$_normal pic 9(9) comp value external
ss$_normal.
01 sys_status pic 9(9) comp.
*
linkage section.
*
01 user_context.
03 iosb.
05 cond_val pic 9(4) comp.
05 pic x(6).
03 input_buff pic 9(9) comp.
03 input_buff_size pic 9(9) comp.
03 a_cxn_handle pic 9(9) comp.
03 return_buff pic x(512).
03 return_buff_len pic 9(4) comp.
*
procedure division using user_context.
00.
display "in cxn_comp ast".
if cond_val = ss$_reject
display "CXN rejected!"
call "sys$wake" using by value 0, 0 giving sys_status
if sys_status not = ss$_normal call "lib$stop" using by value
sys_status end-if
go to fini.
if cond_val not = ss$_normal call "lib$stop" using by value cond_val.
if return_buff_len not = zeros
display "Return buff = ", return_buff (1:return_buff_len).
call "sys$icc_transmit"
using by value a_cxn_handle
by reference iosb
by value ast_xmit
by reference user_context, "This is the message. . ."
by value 24
giving sys_status.
if sys_status not = ss$_normal call "lib$stop" using by value
sys_status.
*
fini.
exit program.
*
end program ast_cxn_comp.
identification division.
program-id. ast_xmit.
data division.
working-storage section.
01 ast_discon pic 9(9) comp value external
ast_discon.
01 ss$_linkdiscon pic 9(9) comp value external
ss$_linkdiscon.
01 ss$_abort pic 9(9) comp value external
ss$_abort.
01 ss$_normal pic 9(9) comp value external
ss$_normal.
01 sys_status pic 9(9) comp.
*
linkage section.
*
01 user_context.
03 iosb.
05 cond_val pic 9(4) comp.
05 pic x(6).
03 input_buff pic 9(9) comp.
03 input_buff_size pic 9(9) comp.
03 a_cxn_handle pic 9(9) comp.
03 return_buff pic x(512).
03 return_buff_len pic 9(4) comp.
*
procedure division using user_context.
00.
display "in xmit ast", cond_val with conversion.
if cond_val = ss$_linkdiscon go to fini.
if cond_val not = ss$_normal call "lib$stop" using by value cond_val.
call "sys$icc_disconnect"
using by value a_cxn_handle
by reference iosb
by value ast_discon
by reference user_context
by value 0,0
giving sys_status.
if sys_status not = ss$_normal call "lib$stop" using by value
sys_status.
*
fini.
exit program.
*
end program ast_xmit.
$!
$cobol/lis icc_client
$link icc_client,icc_def
$run icc_client
$stop icc_server
$exit
Sarah Page <sarah.page@sas.com> wrote in message
news:hjg2h0t8n7vcf6l52udt1ghhcf25qrim84@4ax.com...
> I am trying the ICC system service stuff (under OpenVMS 7.2-1) out for
> the first time and noone else at my site has ever used it.
>
> 1) I have a multi-threaded server and would like to convert it to use
> ICC (instead of mailboxes). I see that ICC relies heavily on ASTs and
> am a little leary because of the constraints / recommendations against
> mixing kernel threads and ASTs. Comments?
>
> 2) I am perplexed (and hopefully not missing something obvious) about
> how my application is to know the connection handle of an association.
> I.e., the server opens the assocation and the handle over which it can
> read from and write to the client is not known until the connection
> AST is hit. Where is the connection AST supposed to put that handle
> so that the rest of the server (including individual threads) can
> access it? Since this is a multi-threaded and very multi-cliented
> server, global storage is not ideal -- especially since I can't
> implement locking from an AST. I am trying to avoid the use of an AST
> to receive data from the client, so I've got to know that handle.
>
> 3) My server uses SYS$CREPRC() to create a detached process, which I
> subsequently send commands to and sometimes collect output from. The
> image specified is SYS$SYSTEM:LOGINOUT.EXE so that the process will be
> under the control of a CLI. For the input and output args I used to
> specify mailbox devices, but now I want to use ICC so that I can
> launch (and communicate with) processes on other nodes in the cluster.
> I am baffled about what to use for those parameters - I have tried
> both the logical name that I specify in the OPEN_ASSOC() call and the
> assocation name, and also the association name preceeded by
> <node_name>:: ?
>
> 4) Where can I find more doc about ICC? I have found one chapter in
> the Programming Concepts Manual, one section in the System Manager's
> Manual, and then the individual system service routines are of course
> doc'd in the System Services Manual. Programming examples in C would
> be outstanding right now.
>
> Thanks in advance for your input,
>
> Sarah Page
> sarah.page@sas.com
|