RPG Chart Engine. Exploit the power of open source java from RPG. Krengel Technology Inc. Leverage Java from your RPG to save time and money!



Similar documents
Excel Spreadsheets from RPG With Apache's POI / HSSF

Introduction to Web services for RPG developers

Instrumentation Software Profiling

User Guide Flying Cloud Drive, Suite 200 Eden Prairie, MN Phone 952/ Fax 952/

FileMaker 11. ODBC and JDBC Guide

BARCODE LABELING SOFTWARE

Smart Shopping- An Android Based Shopping Application

Extending XSLT with Java and C#

ANDROID BASED MOBILE APPLICATION DEVELOPMENT and its SECURITY

Sisense. Product Highlights.

Manual. Netumo NETUMO HELP MANUAL Copyright Netumo 2014 All Rights Reserved

FreeForm Designer. Phone: Fax: POB 8792, Natanya, Israel Document2

FileMaker 14. ODBC and JDBC Guide

Anyone remember this old banner ad? (it was for Net Nanny Pornography? On *MY* Computer? It s more likely than you think. )

FileMaker 13. ODBC and JDBC Guide

FAQ CE 5.0 and WM 5.0 Application Development

Accesssing External Databases From ILE RPG (with help from Java)

CS506 Web Design and Development Solved Online Quiz No. 01

DB2 Connect for NT and the Microsoft Windows NT Load Balancing Service

Creating and Using Databases for Android Applications


Last Class: OS and Computer Architecture. Last Class: OS and Computer Architecture

FileMaker 12. ODBC and JDBC Guide

CS420: Operating Systems OS Services & System Calls

3.5. cmsg Developer s Guide. Data Acquisition Group JEFFERSON LAB. Version

PHP Batch Jobs on IBM i. Alan Seiden Consulting alanseiden.com

Barcodes principle. Identification systems (IDFS) Department of Control and Telematics Faculty of Transportation Sciences, CTU in Prague

Agility Database Scalability Testing

Rational Developer for IBM i (RDI) Distance Learning hands-on Labs IBM Rational Developer for i. Maintain an ILE RPG application using

OPERATING SYSTEM SERVICES

An Overview of Java. overview-1

Java Language Tools COPYRIGHTED MATERIAL. Part 1. In this part...

B M C S O F T W A R E, I N C. BASIC BEST PRACTICES. Ross Cochran Principal SW Consultant

FileMaker Server 12. FileMaker Server Help

Java the UML Way: Integrating Object-Oriented Design and Programming

Getting Started with SandStorm NoSQL Benchmark

SQL Basics for RPG Developers

The Sun Certified Associate for the Java Platform, Standard Edition, Exam Version 1.0

The IBM i on Rails + + Anthony Avison anthony@powerruby.com. Copyright 2014 PowerRuby, Inc.

Starting User Guide 11/29/2011

PHP Batch Jobs on IBM i

MySQL for Beginners Ed 3

New Features for Sybase Mobile SDK and Runtime. Sybase Unwired Platform 2.1 ESD #2

VIRTUAL LABORATORY: MULTI-STYLE CODE EDITOR

Evaluator s Guide. PC-Duo Enterprise HelpDesk v5.0. Copyright 2006 Vector Networks Ltd and MetaQuest Software Inc. All rights reserved.

Introduction to TightVNC. Installation. TightVNC for Windows: Installation and Getting Started. TightVNC Version 2.6 Copyright 2012 GlavSoft LLC.

Tool - 1: Health Center

There are also IBM Knowledge Base documents available on the internet at the following location. Search for SMTP to view the relevant documents:

Introduction to WebGL

1 Introduction FrontBase is a high performance, scalable, SQL 92 compliant relational database server created in the for universal deployment.

Java 7 Recipes. Freddy Guime. vk» (,\['«** g!p#« Carl Dea. Josh Juneau. John O'Conner

Fundamentals of Java Programming

FileMaker Server 10 Help

Migrate AS 400 Applications to Windows, UNIX or Linux

Transaction Monitoring Version for AIX, Linux, and Windows. Reference IBM

Resource Utilization of Middleware Components in Embedded Systems

WebSphere Business Monitor V6.2 KPI history and prediction lab

Università Degli Studi di Parma. Distributed Systems Group. Android Development. Lecture 1 Android SDK & Development Environment. Marco Picone

Risks with web programming technologies. Steve Branigan Lucent Technologies

MATLAB in Production Systems, Database Integration, and Big Data Eugene McGoldrick

CS3600 SYSTEMS AND NETWORKS

PTC System Monitor Solution Training

BIRT Application and BIRT Report Deployment Functional Specification

Scan to Network and Scan to Network Premium

CS346: Database Programming.

Effective Java Programming. efficient software development

Java Application Developer Certificate Program Competencies

Scan to Network and Scan to Network Premium. Administrator's Guide

System i Windows Integration Solutions

How To Port A Program To Dynamic C (C) (C-Based) (Program) (For A Non Portable Program) (Un Portable) (Permanent) (Non Portable) C-Based (Programs) (Powerpoint)

Migrate AS 400 Applications to Linux

GTask Developing asynchronous applications for multi-core efficiency

Protect, License and Sell Xojo Apps

Web Dashboard User Guide

Microsoft SQL Server Features that can be used with the IBM i

Information Server Documentation SIMATIC. Information Server V8.0 Update 1 Information Server Documentation. Introduction 1. Web application basics 2

BI 4.1 Quick Start Java User s Guide

Runtime Monitoring & Issue Tracking

Safewhere*Identify 3.4. Release Notes

Accounts Payable Workflow Guide. Version 11.2

IBM SDK, Java Technology Edition Version 1. IBM JVM messages IBM

Configuring a Random Weight Bar Code

PHP Debugging. Draft: March 19, Christopher Vickery

ORACLE BUSINESS INTELLIGENCE WORKSHOP

AppConnect FAQ for MobileIron Technology Partners! AppConnect Overview

WEBAPP PATTERN FOR APACHE TOMCAT - USER GUIDE

Perceived Performance Test Toolkit

Hypercosm. Studio.

SimWebLink.NET Remote Control and Monitoring in the Simulink

Business Application Services Testing

Java Troubleshooting and Performance

SAIP 2012 Performance Engineering

Computing Concepts with Java Essentials

Running a Program on an AVD

Unit 4 i5/os Work Management

IT Best Practices Audit TCS offers a wide range of IT Best Practices Audit content covering 15 subjects and over 2200 topics, including:

Transcription:

Exploit the power of open source java from RPG Leverage Java from your RPG to save time and money! RPG Chart Engine Copyright Aaron Bartell 2011 by Aaron Bartell Krengel Technology Inc. aaronbartell@mowyourlawn.com

Abstract This session explains how RPG's Java interface extensions can be used to exploit the wealth of Open Source Java applications. Step through the basic RPG syntax extensions and see how the interface works through practical examples. Understand how to interface with the Twitter API to easily send tweets (a.k.a. status updates) from your RPG programs. Find out how to create QR codes interfacing with ZXing APIs from the community and Google. Get best practices for building pie charts, bar graphs, and more by interfacing to the JFree.org APIs. Leave this session with an understanding of how the performance of such Java utilities can be improved through the use of server job and data queue interfaces.

RPG direct to Java 1) V5R1 introduced the O, or Object, data type to RPG IBM s docs for RPG s Object data type: http://bit.ly/qs4o7u 2) Example of prototyping a Java method Djava2RPGStr pr 65535a varying D extproc(*java:'java.lang.string':'getbytes') /free RPGStrVar = getbytes(javastrvar); /end-free 3) Java operates within a JVM (Java Virtual Machine). Think of this as Java having it s own operating system runtime on top of the IBM i operating system, though it is much smaller. 4) The JVM doesn t start with the RPG cycle and instead starts when the first Java method is invoked with the RPG program.

MowYourLawn.com Inception: 2002-11-03 Free and Open SourceTools OpenRPGUI - RPG talks to web and mobile RPGMail - Email from RPG RPG Chart Engine - Bar, pie, line charts from RPG RPG To Desktop - Communicate with the desktop TweetMe4i - Send twitter updates from RPG QR4i - Create QR codes from RPG HTML2PDF4i - Create PDF files from HTML ( control System i SVN Client(source WebServiceTester - Lightweight client for testing web services

TweetMe4i What,Why,How? What: An RPG and *CMD interface over some custom Java I wrote that communicates status updates to a Twitter.com account. Why: Twitter is becoming something and is being used more and more in business scenarios for notifying customers and marketing purposes. How: Make use of open source Java project http://twitter4j.org

TweetMe4i Example H dftactgrp(*no) D TweetMe4i pr extpgm('tweetme4ir') D pptxt 140a const D ppresult likeds(gresult) D gresult ds qualified D code 10a D text 5000a /free *inlr = *on; TweetMe4i( 'Where are my feathers! Time:' + %char(%timestamp): gresult ); if gresult.code <> 'SUCCESS'; dsply 'Error occurred'; // review gresult.text for Java error. endif; /end-free

TWEETME4IR - Java setup Prime the Java environment. Note that this only needs to be called once per job. Calling it again will simply have no affect. What is a CLASSPATH you ask? Very similar to a library list. monitor; cmd = 'ADDENVVAR ENVVAR(CLASSPATH) VALUE(' + qte + '/java/tweetme4i' + ':/java/tweetme4i/tweetme4i.jar' + ':/java/tweetme4i/twitter4j-core-2.2.3.jar' + qte + ')'; QCMDEXC(%trimr(cmd): %len(%trimr(cmd)) ); cmd = 'ADDENVVAR ENVVAR(QIBM_RPG_JAVA_PROPERTIES) ' + 'REPLACE(*YES) VALUE(' + qte + '-Djava.version=1.5;' + qte + ')'; QCMDEXC(%trimr(cmd): %len(%trimr(cmd)) ); on-error; endmon;

TWEETME4IR - Invoke Java The TweetM34i_sendUpdate() prototype is configure in the glocal D-specs of TWEETME4IR source member. RPG strings need to be converted to Java strings using newstr(). Java strings need to be converted to RPG strings using getbytes(). monitor; jstr = TweetMe4i_sendUpdate( newstr(pptxt) ); gresult = getbytes(jstr); on-error ; gresult.code = 'ERROR'; gresult.text = 'An error occurred during the call to TweetMe4i_sendUpdate. ' + 'Check the joblog for more information.'; endmon; select; when %parms = 1 and gresult.code <> 'SUCCESS'; Error_throw(gResult.code: gresult.text); when %parms = 2; ppresult = gresult; endsl; Determine if we were called by the *CMD and if so, throw an error on the call stack and job log.

TweetMe4i_sendUpdate Prototype that allows RPG to call the sendupdate() Java method within Java class TweetMe4i. D jstrconst c 'java.lang.string' D TweetMe4i_sendUpdate... D pr o class(*java: jstrconst) static D extproc( D *java: D 'com.mowyourlawn.twitter.tweetme4i': D 'sendupdate') D ptxt o class(*java: jstrconst) const DgetBytes pr 65535a varying D extproc(*java:jstrconst:'getbytes')

Configure TweetMe4i TweetMe4i requires a twitter account and twitter application be created. That process is described in this article: http://bit.ly/osffp5

TweetMe4i *CMD Location: TWEETME4I/QCLSRC,TWEETME4I CMD PARM PROMPT('TweetMe4i') KWD(TXT) TYPE(*CHAR) LEN(140) PROMPT('Tweet Text') MIN(1) From the command line... TWEETME4I TXT('Where are my feathers!?!') NOTE: Twitter has mechanisms in place to prevent duplicate postings! So you can t send the same message repeatedly if you are looking to just test the API.

TweetMe4i.java Guts Example Java program that shows how to make use of the TweetMe4i.java object which is contained within /java/tweetme4i/tweetme4i.jar. The twitter4j API by itself wasn t able to be quickly implemented in other Java programs so an additional Java wrapper (TweetMe4i.java) was added to lessen the number of API calls on the RPG side. public static String sendupdate(string tweettext) { String result = ""; } try { Twitter twitter = new TwitterFactory().getInstance(); if (!twitter.getauthorization().isenabled()) { result = resultds("fail", "OAuth consumer key/secret is not set."); } Status status = twitter.updatestatus(tweettext); result = resultds( "SUCCESS", "Successfully updated the status to [" + status.gettext() + "]."); } catch (Exception te) { result = resultds("fail", "Java Exception:" + stacktracetostring(te)); } return result;

QR4i What,Why,How? What: An RPG and *CMD interface over some custom Java I wrote that creates QR codes on the fly. Why: QR codes are becoming popular because of the major boom in smart phones. How: Use http://code.google.com/p/zxing/ (Zxing)

Supported Barcodes Zxing (pronounced zebra crossing ) UPC-A and UPC-E EAN-8 and EAN-13 Code 39 Code 93 Code 128 QR Code ITF Codabar RSS-14 (all variants) Data Matrix PDF 417 ('alpha' quality) Aztec ('alpha' quality) http://code.google.com/p/zxing

QR4i Example H dftactgrp(*no) D QR4i pr extpgm('qr4ir') D pptxt 4296a const D ppfile 1024a const D ppwidth 10i 0 const D ppheight 10i 0 const D ppfmt 10a const D ppresult likeds(gresult) NOTE: Max QR code size is 4296 bytes. D gresult ds qualified D code 10a D text 5000a D gtxt s 4296a varying D gfile s 1024a varying D gwidth s 10i 0 inz(200) D gheight s 10i 0 inz(200) D gfmt s 10a inz('png') /free Ex: Text string with new line character gtxt = 'Aaron Bartell\n150 Center Mountain Drive\nMankato, MN 56001'; gfile = '/java/qr4i/newline.png'; QR4i(gTxt: gfile: gwidth: gheight: gfmt: gresult);...

QR4i Example... Ex: Business Card gtxt = 'MECARD:N:Bartell,Aaron;ADR:Center Mountain Drive, Mankato,MN' + ' 56001;TEL:+12345678901;EMAIL:aaronbartell@mowyourlawn.com;;'; gfile = '/java/qr4i/mecard.png'; QR4i(gTxt: gfile: gwidth: gheight: gfmt: gresult); Ex: Pre-filled Email gtxt = 'MATMSG:TO:aaronbartell@mowyourlawn.com;SUB:QR4i Test;' + 'BODY:Hi Aaron, Do you want my winning lottery ticket?;'; gfile = '/java/qr4i/matmsg.png'; QR4i(gTxt: gfile: gwidth: gheight: gfmt: gresult); Ex: URL gtxt = 'http://mowyourlawn.com'; gfile = '/java/qr4i/url.png'; QR4i(gTxt: gfile: gwidth: gheight: gfmt: gresult);

QR4iR - Java setup Prime the Java environment. Note that this only needs to be called once per job. Calling it again will simply have no affect. What is a CLASSPATH you ask? Very similar to a library list. monitor; cmd = 'ADDENVVAR ENVVAR(CLASSPATH) REPLACE(*YES) VALUE(' + qte + '/java/qr4i' + ':/java/qr4i/qr4i.jar' + qte + ')'; QCMDEXC(%trimr(cmd): %len(%trimr(cmd)) ); cmd = 'ADDENVVAR ENVVAR(QIBM_RPG_JAVA_PROPERTIES) ' + 'REPLACE(*YES) VALUE(' + qte + '-Djava.version=1.5;' + '-Djava.awt.headless=true;' + qte + ')'; QCMDEXC(%trimr(cmd): %len(%trimr(cmd)) ); on-error; endmon; The Zxing code is compiled into the QR4i.jar file because they didn t offer a separate.jar file on their site. When on a machine without a graphical display attached.

QR4IR - Invoke Java The TweetM34i_sendUpdate() prototype is configure in the glocal D-specs of TWEETME4IR source member. RPG strings need to be converted to Java strings using newstr(). Java strings need to be converted to RPG strings using getbytes(). monitor; jstr = QR4i_create( newstr(pptxt): newstr(ppfile): ppwidth: ppheight: newstr(ppfmt)); gresult = getbytes(jstr); on-error ; gresult.code = 'ERROR'; gresult.text = 'An error occurred during the call to QR4i_sendUpdate. Check ' + 'the joblog for more information.'; endmon; select; when %parms = 5 and gresult.code <> 'SUCCESS'; Error_throw(gResult.code: gresult.text); when %parms = 6; ppresult = gresult; endsl; Determine if we were called by the *CMD and if so, throw an error on the call stack and job log.

QR4i *CMD Location: QR4I/QCLSRC,QR4I CMD PARM PROMPT('TweetMe4i') KWD(TXT) TYPE(*CHAR) LEN(140) PROMPT('Tweet Text') MIN(1) From the command line... QR4I TXT('This is a test') FILE('/java/QR4i/test.png') WIDTH(200) HEIGHT(200) FMT(PNG) NOTE: You can also produce JPEG files.

MowYourLawn.com RPGChartEngine - What, Why and How? What: A set of RPG sub procedures (say service program) that can create graphical charts with ease from your IBM i RPG program to be used in other mediums (i.e. PDF, Excel, Word, www, etc). Why: Personal challenge and after reviewing the Java API s I realized it wouldn t be that hard. Also wanted to learn and show how to have RPG talk to Java through data queues. How: utilize the JFreeChart API's from http://jfree.org

MowYourLawn.com RPG Chart Engine Approach 1 Make calls to RCE_* sub procedures which in turn do WRITE s to RCEHDRPF and RCEDTAPF. 2 Execute RCE_run which in turn writes a record with a unique key to data queue DQRCE. RPG program immediately goes to wait for a response on the same data queue for the same unique key. 3 Java program RPGChartEngine.java is listening for new entries on data queue DQRCE. 4 Java uses unique key from data queue entry to do an SQL select out to tables RCEHDRPF and RCEDTAPF to obtain the information necessary to produce the appropriate graph. 5 Using the information in RCEHDRPF the Java program knows which type of chart to create and uses data from RCEDTAPF to produce the data detail aspect of the chart. The result is placed in the IFS at the location your RPG program specified. If debugging is turned on the Java program will also trickle statements into that file during processing. 6 Java program completes and writes the result of the chart creation back to the data queue. 7 RPG program receives response and continues processing based on the result.

Data Queue Definition CRTDTAQ DTAQ(&LIB/DQRCE) MAXLEN(32766) SEQ(*KEYED) KEYLEN(15) AUTORCL(*YES) Data queue DQRCE is used to connect the RPG and Java programs. Two data queues could have been created, one for requests and one for responses, but it is stated in IBM documentation that having a single *KEYED data queue is a better practice if the situation can facilitate it. A keyed data queue is neat because you can tell your RPG program to listen for ANY entry or only entries with a specific key. In RPG Chart Engines case the Java program is listening for ALL entries, and the RPG program that made the request is waiting for specific uniquely keyed response.

MowYourLawn.com Starting The Java Process PGM DCL DCL DCL DCL DCL DCL DCL DCL DCL PARM(&HOST &USER &PW &DTALIB &DQLIB &DQNAM &DQWAIT &DBG &DBGFLR) VAR(&HOST) TYPE(*CHAR) LEN(100) VAR(&USER) TYPE(*CHAR) LEN(10) VAR(&PW) TYPE(*CHAR) LEN(10) VAR(&DTALIB) TYPE(*CHAR) LEN(10) VAR(&DQLIB) TYPE(*CHAR) LEN(10) VAR(&DQNAM) TYPE(*CHAR) LEN(10) VAR(&DQWAIT) TYPE(*CHAR) LEN(5) VAR(&DBG) TYPE(*CHAR) LEN(5) VAR(&DBGFLR) TYPE(*CHAR) LEN(256) SBMJOB CMD(RUNJVA CLASS(com.mowyourlawn.os.RPGChartEngine) PARM(&HOST &USER &PW &DTALIB &DQLIB &DQNAM &DQWAIT &DBG &DBGFLR) + CLASSPATH('/java/rce/RPGChartEngine.jar:/java/rce/jcommon-1.0.0.jar:/java/rce/ jfreechart-1.0.1.jar:/java/rce/jt400.jar') PROP((java.version 1.4) (java.awt.headless true)) OPTION(*VERBOSE)) JOB(RCERUNJVA) ENDPGM Calling the below command will in turn call CL program STRRCEC which submits a RUNJVA command. ('/ DBGFLR('/java/rce RCE/STRRCE DTALIB(RCE) DQLIB(RCE) DQNAM(DQRCE) DQWAIT(-1) DBG(TRUE) With DBG(TRUE) specified, text will be trickled into /java/rce/rce_debug_2011-apr-09.log ( WRKACTJOB ) RPG Chart Engine jobs running Subsystem/Job User Type CPU % Function Status QBASE QSYS SBS.0 DEQW QJVACMDSRV AARON BCI.0 JVM-RPGChartEn JVAW RCERUNJVA AARON BCH.0 CMD-RUNJVA TIMW

MowYourLawn.com Example Program Copy in RCECP from library RCE source physical file QSOURCE. This contains all the necessary RPG prototypes. Variable uid is used to keep track of a particular charts data in the RCEHDRPF and RCEDTAPF physical files. Currently there are three charts from JFreeChart that are implemented Bar, Pie, and XY charts. To add new charts would require RPG and Java programming.

MowYourLawn.com Bar Chart First execute RCE_newBarChart and pass in parameters to initialize values specific to your business need. A unique number will be passed back that will be used on subsequent calls to RCE_addBarChartData so that when data is written to RCEDTAPF it can be related.

MowYourLawn.com Pie Chart Pie Chart First execute RCE_newPieChart and pass in parameters to initialize values specific to your business need. A unique number will be passed back that will be used on subsequent calls to RCE_addPieChartData so that when data is written to RCEDTAPF it can be related. The number and data types of parameters for RCE_addPieChartData are different than RCE_addBarChartData, but in the end they all go to the same physical file RCEDTAPF. Separate procedures were created to more easily understand what was required for detail data concerning each chart.

Line Chart First execute RCE_newXYLineChart and pass in parameters to initialize values specific to your business need. A unique number will be passed back that will be used on subsequent calls to RCE_addXYLineChartData so that when data is written to RCEDTAPF it can be related.

Innards Each API starting with RCE_new* has a specific set of parms it calls for and those parms will be placed in the appropriate fields of physical file RCEHDRPF. The unqnbr() sub procedure is locally defined and increments a value in a data queue by one and returns the new value. The remainder of the RCE_new* sub procedures have the same concept, just different parms that are place in different header fields.

MowYourLawn.com Java Communication RCE_run is where the communication with Java starts. At this point there is data in RCEHDRPF and RCEDTAPF that provides all the information necessary for the Java side to create a chart. SndDtaQ is simply writing the unique key

Java Guts - RPGChartEngine.java When STRRCE is executed it instantiates the RPGChartEngine Java object and attaches to the DQRCE data queue waiting for entries. Instantiates simply means the Java program goes through it s initial execution much akin to *INZSR in RPG. As you can see in the code there is a debug statement. This will write out to a file in the IFS if debugging was turned on during startup of this Java process. As soon as an entry is received the processentry() method is called.

MowYourLawn.com Java Guts - processentry Method processentry s purpose is to obtain the unique key value and start a new Java thread. Starting a thread is similar to submitting a job in OS/400; you pass some priming input parms and disconnect from the process so it can do it s own processing apart from the main process. This enables better throughput as multiple charts can be created at the same time. If any errors occur during this process then a text message will be placed in the debug file residing in the IFS.

MowYourLawn.com Java Guts - JFreeChartTransaction The content of inner class JFreeChartTransaction is too big to place here, so only the finer points will be noted. To create the chart at hand the program obviously needs to gain access to the physical file data. Below is the Java code necessary to read the data into result sets. Result sets are very similar to a result set in RPG when using embedded SQL.

MowYourLawn.com Java Guts - JFreeChartTransaction... The following code is where physical file data meets the actual chart. The chart type is determined and then the appropriate Java classes are called to build the chart. Once the chart variable has been loaded appropriately it can be placed into a JPEG file in the IFS.

MowYourLawn.com Java Guts - JFreeChartTransaction... The last step from the Java side is to write a response entry to data queue DQRCE. If an error occurs then the RPG program waiting for the response will simply have to time out and appropriately generate a notification so somebody knows the process failed.

Other Open Source Java Utilities Try one of these guys out for yourself to see what you can do! http://sourceforge.net/projects/jfreechart/ (Graphical charts) http://jakarta.apache.org/poi/ (Excel Spreadsheets) http://www.lowagie.com/itext/ (PDF creation) http://www.eclipse.org/birt (Reports) (check out http://www.opensource4iseries.com/ for a ( project start to this ( Reporting ) http://www.pentaho.com/products/reporting/

Other Open Source Sites http://www.opensource4iseries.com/ http://iseries-toolkit.sourceforge.net/ http://www.softlanding.com/websphere/rse.htm http://www.scottklement.com/oss.html http://www.martinvt.com/code_samples/code_samples.html http://netshare400.com http://www.think400.dk/downloads.htm/ http://home.alltel.net/craigru/jcrcmd2.html http://sourceforge.net/projects/iseriestoexcel http://www.rpgiv.com/downloads/ http://www.code400.com http://rpgnextgen.com http://freerpgtools.com

We have reached the end! Aaron Bartell aaronbartell@mowyourlawn.com ( www.rpg-xml.com ) lead developer of RPG-XML Suite and owner of www.mowyourlawn.com and check out his latest effort at www.softwaresaveslives.com.com/aaronbartell