ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß C o d e R u n n e R (R) ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Omega Point, Inc. 39 North Hancock Street Lexington, MA 02173 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ TEL: (617) 860 - 0048 FAX: (617) 860 - 0344 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ CodeRunneR is a library and startup code for C programmers optimized for creating highly efficient and reliable TSRs (Terminate and Stay Resident programs). After five+ years in the programming tool marketplace and its use by thousands of professional developers, from individual consultants to the largest corporations in all domains, CodeRunneR has become de facto TSR standard and a synonym for small, fast and rock solid TSRs. Here is what the industry experts say about CodeRunneR: ž CodeRunneR "will turn any C programmer into a TSR Michelangelo." ž "... it's the best TSR library I've ever seen." ž "Every original TSR I converted to CodeRunneR went down in memory size, became more compatible and more reliable. For example, a screen capture TSR I wrote required around 18k. The CodeRunneR version ... were under 5k with more functionality." ž "buffered high speed serial (COM) functions ... are the best I've seen." Stuart Warren, Computer Telephony Editors' Choice 1994 ž "the size of any program you develop with CodeRunneR will astound you" ž "CodeRunneR will make your C TSRs smaller than you could imagine" Mark Davidson, Computer Language ž "the cream of the crop" Tom Swan, PC-World ž "CodeRunneR not only solves problems, it inspires new possibilities. It is destined for the Programmer's Hall of Fame." Joe Campbell, Author of "C Programmer's Guide to Serial Communications" ž "CodeRunneR and its associated Professional Developer's Kits are highly useful set of utilities that open the difficult world of TSR programming to anyone who can grasp the C language." ž "The video routines make saving and displaying screen information a breeze" R. Bradley Andrews, Dr. Dobbs Journal ž "professional development tool that'll let you create compact, fast TSRs" Gary Entsminger, Micro Cornucopia ž "Using the TSR template provided with CodeRunneR, you can get your first TSR application up and running in days instead of weeks." ž "one of the best BBS support lines I have seen yet. The response time to the questions I posted on the BBS was excellent." ž "The CodeRunneR product excels in its TSR capabilities, coexistence with other DOS applications and technical support." Victor R. Volkman, The C Users Journal ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ TIME SAVING FEATURES ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ In addition to the top quality and unique capabilities of the code and the wide scope of the library, CodeRunneR package includes the following time and effort saving features: ž Quick Start templates and our PopFEATURE collection (fully operational, useful TSRs with C source) will help you create professional quality TSRs the first day. A dozen useful TSRs with full source include expression parsing calculators, calendar, text browser, ASCII chart, keyboard decoder, stopwatch, terminal TSR with file transfers, ...etc. ž On-Line Context-sensitive Hypertext Help (a TSR using 1.3K with LIM or 30K without LIM) has all CR functions and variables cross-referenced and linked to related topics as well as miscellaneous useful PC/AT technical facts. The TSR allows cut & paste of code into a foreground application. ž The printed documentation consists of a 300 page Reference manual and a 60 page Quick Start manual. The main reference includes a chapter on efficient C programming covering 41 techniques for optimizing size and speed of C programs. The Quick Start manual guides you quickly through the how-to phase in a pragmatic manner. It includes a chapter of the most often asked questions with answers. ž The package also contains a large collection of tips and discussions from the CodeRunneR Technical Support BBS (spanning 3 years; over 800K of text). The collection is a treasure of real life, practical problems and solutions, a gold mine of ideas and strategies from hundreds of programmers. ž Our In-Depth Technical support is unmatched in the industry. You can discuss with our TSR experts topics from strategies and algorithms for implementing your TSR to tracking down difficult bugs and optimizing your TSR. ž You can call, FAX or leave technical questions/code on the Tech Support BBS at any time (including weekends) and they'll be addressed and resolved usually within hours from the request. Registered users can download fixes and updates from the BBS as soon as they are available (we don't use phrase "known bug"). ž CodeRunneR works with all major C compilers (TC, BC, MSC, Watcom, Zortec). ž If your TSR deadline is "yesterday" ask about our TSR FOR HIRE service. ž No royalties are required for the programs linked with CodeRunneR and its associated add-on kits. In addition to the main package, there are 3 Professional Developer's Kits (add-on) for specialized needs: PDK-1,2 and 3. For example PDK-1 has a background communications library, LIM access and ability to move TSRs to LIM, copy protection, print spooler,...etc. Finally, there is an Advanced Developer's Kit ADK-1, a library for creating multi-application swappers. It includes PopSWAP, a fully functional software carousel-like TSR for fast swapping of up to 10 applications (easily extensible to any number). ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ TECHNICAL HIGHLIGHTS ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ž CodeRunneR has over 300 functions hand crafted in pure assembler for size and speed. The library is fully granular so that only the used facilities are linked in. ž Our unique memory manager discards initialization code and data before switching to resident mode. This means that any signon/help screens, command line/file parsers, set-up menus, ...etc. will not take any memory in TSR mode. Similarly disposed are any library facilities used only at load time such as startup code, hardware/environment identification routines, non- applicable video, keyboard, COM handlers ...etc. ž TSRs can use DOS/Networks safely. A set of efficient file i/o and directory functions provides full DOS directory/file access. ž The CodeRunneR task switcher supports execution of multiple threads in resident or non-resident mode. Context switching, stack allocation and thread entry control/locking is handled automatically (with facilities to override the defaults). ž TSR can define up to 256 simultaneous dynamic hotkeys, which may include multikey combinations such as Ctrl- Shift-Home. On extended keyboards the distinction can be made between Left and Right Ctl (or Alt) keys as well as between dedicated and non-dedicated cursor keys. The hotkeys can be added, removed or redefined at any time during TSR operation. The standard CodeRunneR header allows external programs to examine and modify hotkeys of a resident program. ž There are three different hotkey handlers: Hardware level, BIOS level (for triggering TSR by other applications via simulated hotkeys) and Timer-Hotkeys (for triggering TSR with applications which take over the keyboard exclusively). Any of the three handlers (or combination) triggers TSR by calling user specified C function with a hotkey value as a function argument. ž Two event schedulers are available: Tiny and Master scheduler. The Tiny scheduler is small and highly efficient, useful for single event scheduling. The Master scheduler allows any number of events to be scheduled and pending simultaneously. When some event becomes due, the TSR is triggered via a call to a specified C function with the pointer to the event structure as an argument. ž Interrupt traps trigger user's C function when specified software or hardware interrupts occur. The traps can be added and removed in TSR mode. The hooked interrupts are automatically restored when TSR unloads. The C service function can examine and modify caller's CPU registers (via structures) and in each trigger instance specify whether to return to the caller (IRET) or pass control to the original interrupt handler. An alternate assembly language interrupt handler can be enabled if necessary. A template for custom interrupt service in assembler with an interface to CodeRunneR task switcher is included. ž Very compact and accurate BCD floating point library supports from 12 to 248 digits of precision and exponents up to ń16383. It is ideal for business/financial computations since it eliminates the fraction rounding errors which are common with regular binary floating point. ž Ultra compact video functions perform lightning fast screen output. They automatically handle variable screen sizes and different video adapters. Another rich set of functions automates save and restore operation of screen windows, cursor position and type, fonts, palette, RGB colors, ...etc. ž Memory management functions support mixed far and near allocation and allow full control of the amount of memory which should remain resident. The compaction is done before going resident to eliminate gaps between near heap and stack as well as between the far heap and compacted near heap. ž Stack diagnostic functions provide information about resident stack use by different threads. This is helpful in minimizing the stack use in the final stages of development. ž Large number of functions cover all aspects of PC/AT hardware, BIOS and DOS control, such as printers, COM ports, sound, time, delays, old/new keyboards, key stuffing, video, interrupt controllers, ...etc. Please inquire about any features of interest which you didn't see listed in this brief overview. ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ PDK-1 Features ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Serial Communications The main part of PDK-1 is the interrupt driven serial communications library. Due to its compactness it is ideally suited for TSRs. Its speed makes it perfect for background, low overhead, communications. ž Support for multiple channels limited only by available hardware. It can service cases from the single channel single interrupt (IRQ) to the multichannel configurations with separate or shared IRQs (with one or two interrupt controllers). Also supported are two types of commercial multiport boards (Digiboard type with base-2 ID and Stargate type with bit-mask ID). ž Standard PC/AT UART 8250 and the high performance FIFO 16550 are supported. ž Automatic or manual flow control (RTS/CTS, DTR/DSR, XON/XOFF) is changeable at any time during operation. ž User's C function can be triggered in real time by any conditions of the COM channel (modem status lines change, ring, loss of carrier, errors, break, receive buffer above critical mark, output buffer below critical mark, ...etc). ž Buffered serial I/O provides several types of buffers, from simple flat and circular buffers to chained buffers. With chained buffers, the library interrupt handlers automatically switch from one buffer to the next. This is very helpful with packet protocols where the chained buffers perform automatic separation of the packet envelope from its content, greatly speeding up and simplifying the packet merge/split functions. ž Several types of polled I/O, from the ultra fast streamlined version to variations with built in timeouts. ž ANSI Terminal Emulator via a single functions ansi_chr(). The TERM.C sample utilizes this function to implement a tiny ANSI terminal emulator. ž Facilities to reduce system overhead (from other interrupt sources) in time critical situations include quick handlers for timer and keyboard interrupts and ability to increase priority of COM interrupts at hardware level. ž Multitasking functions sleep() and awake() simplify conversions of a straight non-background C code into a multitasking code for background operation. The sleep() suspends execution, freezing the state of the thread. Subsequent awake() (which can be triggered by a full/empty buffer, timeout or any other event source) resumes original thread as if sleep() has just returned. ž Very fast and small checksum and CRC functions (compatible with X/YMODEM protocols). ž Powerful HyperCOM program (C source included) demonstrates many library features. It supports XMODEM, YMODEM/BAT multifile background transfers, logon scripts, dial directory, ANSI Terminal emulator. LIM Support ž LIM (EMS) detection and LIM API support. ž Mixed model functions convenient for operating on LIM pages. ž TSR can move to LIM using a single call move_to_lim(). Code, Data or both can be moved. In all cases the move is transparent to the C code. The library will retain in low memory only the minimum interrupt handlers (such as timer for schedulers, keyboard for hotkeys, DOS idle,...). This leaves around 1K in low memory, the rest is in LIM. When a trigger condition is detected by the low memory handlers (event due, hotkey pressed, DOS became idle), the LIM state is saved, the TSRs image is remapped into the CPU address space and the control is passed to the original interrupt handlers. Upon thread return the LIM state is restored, so that the foreground applications can safely use LIM. Any number of TSRs can be moved to LIM, each leaving a small footprint in conventional memory (or in high memory with QEMM, 386Max or DOS 5 UMBs with 0K low memory overhead). Print Spooling ž The printer trap buffers printer data and triggers a C service function when buffer reaches a specified critical level. ž Special technique is used to allow DOS access (for buffer flushing to a file) even when printing is done through DOS (i.e. when DOS is "officially" busy). ž Data can be captured with or without passing them to the printer. The LPT status returned to the foreground application is fully customizable. All or just selected printers can be monitored. Registration & Copy Protection PDK-1 includes registration facility designed for copy protection. The protection method works as follows: You make available to potential customers an unregistered version of your program as a demo copy with some features disabled. With the demo you include a User Register program UREG (C source included in PDK-1). If the user decides to buy your program s/he can call in and request an Unlock Code (asked by UREG). A sales person at your site runs Internal Register program IREG, fills in user name and company. The end user does same with UREG. Based on this information the IREG will produce a unique number, the Unlock Code which the sales person tells the customer who enters it into the UREG's Unlock Code field. If the Unlock Code is valid UREG unlocks the primary application and simultaneously stores the encrypted user's name and company into some file from your package. The application can check and display at convenient time this information which should discourage software pirating. Besides the functions for generating, checking and locating the valid Unlock Code, several functions are supplied for defeating debugging or patching by would-be pirates. ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ PDK-2 Features ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ PDK-2 covers wider area of applications than PDK-1 or PDK-3, containing the facilities developers have often asked for. EXE Merge Facility ž Multiple EXE files are merged into a single EXE file. Each member EXE file can switch over to another one with a single call. The calling member EXE is discarded from the memory and the new member EXE is spawned. This facility is useful when there are several variations of a program or when there is a setup program plus one or more main executables. The EXE Merge packages all programs into a single EXE file which greatly simplifies consistent updates and installation by end users. Spawn Over This facility allows programs to spawn another application by swapping themselves to XMS, EMS or disk. Only a 1.4K footprint is left from the parent process. Upon exit of the child program, the parent program is restored. ž To gain speed only the minimum necessary swapping is done. Depending on the size of child program spawn_over() will first try to utilize any free memory. If that isn't sufficient it compacts the parent program (free heap/stack space) and only if that isn't enough it swaps out the minimum necessary parts of the parent program. ž Parent program can designate section of memory as shared with the child program. This memory is not swapped out and it can be accessed by the spawned program for fast two-way information exchange. XMS Support ž XMS API allows access to extended memory. The functions are similar to LIM support in PDK-1. ž XMS functions will also enhance the swappers in PDK-3 and ADK-1 for swapping graphics state and foreground applications to XMS. Except for the initial XMS presence check and xms_alloc() call, the rest is transparent to the C code (handled internally by the swappers). ž Official XMS specifications are included in the PDK-2 manual. Keyboard Stuffing & Monitoring ž TSRs can feed scan codes directly to hardware so they are indistinguishable from the real keys, even by applications which read hardware directly. This feature is available only on PS/2 and better AT clones (such as Compaq). A software emulation is provided for machines lacking this capability (detection included). ž High speed key feeding (at BIOS level) with a mechanism to handle applications which flush keyboard between keys received. ž Embedded command codes automate setting of keyboard flags (Shift, Ctl,..) without requiring special attention from C code. ž C service function can be awakened when the output string has been passed to the foreground application. ž A C function can watch all keystrokes and decide on action: pass, remove or substitute the keys typed. Time Slicing Functions ž Function wait(N) suspends current thread for N timer ticks. The control returns either when N ticks have expired or when another thread calls wait_done(). ž Function waitfor() is similar to wait() except that it also supplies a pattern and the address (such as video memory). The thread is awakened when either time expires or the pattern appears at specified location. This is useful for programs which control other applications (such as automated testers, screen data grabbers) where the TSR stays idle until some prompt occurs on the screen. Far Call Interface This facility is similar to software traps except that it allows external programs to call into TSR (without using interrupts) and to activate a TSR. Traps to LIM The TSRs which use move_to_lim() facilities cannot set interrupt vectors to point into LIM since the TSR image in LIM can get swapped out by other applications. The PDK-2 ltrap facility allows interrupt trapping by setting up an indirect handler in low memory which handles LIM state saving/restoring and TSR triggering. Utilizing System Idle Time Functions idle_on() and idle_off() allow TSRs which need to do time consuming processing in the background (e.g. printing) to utilize system idle time. Whenever system is idle the specified C service function is called with high frequency. Dual Monitor Access This set of functions allow CodeRunneR video functions to operate on a selected monitor on systems with two monitors. The selection can be changed at any time. ž Automatic screen overflow handler can redirect data scrolled off at the top of the primary monitor to the bottom of the secondary monitor. ž A useful sample program DMON demonstrates dual monitor functions. It can clone parts of the screen from the primary to the secondary monitor. ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ PDK-3 Features ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ With PDK-3 you can, in less than an hour, turn any application (graphics & floating point, too) into a TSR taking only 1.5K of RAM without any modifications to the application. You can also use PDK-3 for non-TSR applications which are too large to fit in 640K: a tiny TSR (1.5K) loads temporarily before your main application and serves as a swapper between several large components of the main application. PDK-3 performs its magic via the in-depth support for spawning applications from the TSR, swapping TSR or foreground application and swapping graphics. The TSR can spawn another application in several ways: by swapping foreground application to disk, LIM or XMS, by swapping itself, by remapping LIM pages, by using unused space from COMMAND.COM when at DOS prompt. ž Graphics swapping allows pop-up over graphics application. All major video adapters are supported (Hercules, CGA, MCGA, EGA, S/VGA). The graphics image can be swapped to disk, LIM or XMS. ž Mouse API is supported including interrupt driven triggers on mouse events (movement, button clicks or Shift, Alt, Ctl + button clicks). ž Mouse, graphics, math coprocessor, ... can be used by spawned programs without interfering with their use by foreground applications. ž Three fully operational spawn templates are supplied. They allow building your custom spawner by few simple changes in the header files (to set-up application name, memory size, graphics use and swap medium). The swapping to LIM (XMS) requires PDK-1 (PDK-2) respectively. The swap functions handle different swap media transparently to C code. ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ADK-1 Features ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ The Advanced Developers Kit ADK-1 contains very powerful multi-application swapping capabilities. Multiple (graphics) applications can be suspended, saved (to disk, EMS or XMS) then restored and resumed at any time from within the TSR. Any CodeRunneR trigger mechanisms can be used to initiate the switch (hotkeys, timer, interrupts from applications, phone ring, ...etc). ž The ADK-1 C interface is very simple, just few powerful functions: app_start(), app_suspend(), app_resume(). Yet it allows full dynamic customization via APP_CTL and SWAP_CTL structures. ž For speed, only the minimum necessary swapping is done. The use of available swap media (disk, EMS, XMS) can be dynamically adapted and mixed within the same swap operation for optimum performance. The resulting swapping is 2-3 times faster than with the DOS 5 swapper DOSSHELL. Yet the ADK-1 sample swapper PopSWAP is three times smaller than DOSSHELL (or 30 times if LIM is available). ž Generic I/O functions allow uniform access to files, EMS or XMS, with each media presented as a linear read/write space addressable via single 32-bit pointer. Read/Write blocks can be any size (the 32-bit read/write count is used). ž Full source for all ADK-1 library functions (ASM) is included. ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ PRICE & ORDERING ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ The prices for CodeRunneR and the add-on kits are: CodeRunneR $ 195 PDK-1, 2 or 3 $ 99 CodeRunneR + 3 PDKs $ 429 ADK-1 $ 995 For US orders add $5 for regular shipping, $10 for 2nd day or $15 for next day delivery. For Canada add $10 for Air Mail or $50 for FEDEX. For other countries add $25 for Air Mail. Alternatively provide your FEDEX number to be used for shipping. On international orders we accept VISA, MasterCard, AMEX (please include card number & exp. date) or a bank check in US funds (prepaid). ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Omega Point, Inc. 39 North Hancock Street Lexington, MA 02173 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ TEL: (617) 860 - 0048 FAX: (617) 860 - 0344 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ