Filewatcher File Search
FTP Search
  
Directory 
  
Content Search 
   
pkg://pp84-1.1.6b-2.src.rpm:201874/pp84-1.1.6b.tar.gz  info  downloads

pp84-1.1.6b/ 40775    145    145           0  6573110463  11363 5ustar  nemethnemethpp84-1.1.6b/pic84.asm100775    145    145        5572  6342110371  13115 0ustar  nemethnemeth
	; ********************************************
	;
	;       PIC84.ASM
	;       PIC16C84 SAPMLE PROGRAM
	;       PIC 84 SOURCE CODE
	;
	; ********************************************

	LIST            F=INHX8M
	PROCESSOR       16C84
	RADIX           DEC
        __CONFIG        B'11111' ; RC

			; B4:   CODE PROTECTION, 1=OFF
			; B3:   POWER UP, 1=TIMED
			; B2:   WDOG, 1=ON
			; B1-0: OSC SELECT, 01=XT, 11=RC

	__IDLOCS	H'0001'

; ------------------------------------------------------

	;       EQUATES

	;       PORT B BIT ALLOCATIONS

BLED1   EQU     0       ; o/p ; bicolour led + => green
BLED2   EQU     1       ; o/p ; bicolour led + => red

	;       STORAGE ALLOCATIONS
	;       VARIABLE DATA STORAGE STARTS AT ADDR 12

TEMP1   EQU     12     

	;       DATA STORAGE ENDS AT ADDR 47

	;       CONSTANTS

	include p16c84.inc

; ---------------------------------------------------------

	ORG     0

	GOTO	START

	ORG	4

	;	interrupt service

	RETFIE

; ---------------------------------------------------------

	;       SETUP

START   MOVLW   B'11111111'     ; PORT REGS TO DEFAULTS
	MOVWF   PORTA
	MOVLW   B'11111111'
	MOVWF   PORTB

	BSF     STATUS,RP0      ; OPTION & TRIS ARE HI REGS

	MOVLW   B'00000111'
	; B7:   RBPU   - ENABLE PORT B PULL-UP RES, 0=OFF
	; B6:   INTEDG - RB0 INT EDGE SEL 0=-VE
	; B5:   T0CS   - TMR0 SOURCE, 0=FOSC/4, 1=RA4 PIN
	; B4:   T0SE   - RA4CLK PIN EDGE SELECT, 0=+VE
	; B3:   PSA    - PRESCALE ASSIGN 0=TIMER, 1=WDG
	; B2-0: PS2-0  - PRESCALE RATE 111=256 FOR TIMER (=127 FOR WDT)
	MOVWF   OPTION_REG

	MOVLW   B'00000000'     ; 0=OUTPUT
	MOVWF   TRISB

	MOVLW   B'11111'        ; 1=INPUT
	MOVWF   TRISA

	BCF     STATUS,RP0      ; BACK TO LO REGS

	MOVLW   B'00000000'        
	; B7: GIE  - GLOBAL INT ENABLE, 0=OFF
	; B6: EEIE - EERAW WRITE DONE INT ENABLE, 0=OFF
	; B5: T0IE - TMR0 O/FLOW INT ENABLE, 0=OFF
	; B4: INTE - RB0 INT ENABLE, 0=OFF
	; B3: RBIE - PORTB CHANGE-OF-STATE INT ENABLE, 0=OFF
	; B2: T0IF - TMR0 O'FLOW FLAG, 1=O/FLOW, S/WARE MUST RESET
	; B1: INTF - RB0 INT FLAG, ACTIVE HIGH
	; B0: RBIF - PORTB CHANGE-OF-STATE FLAG, ACTIVE HIGH
	MOVWF   INTCON

; ----------------------------------------------------------------

MAIN:   
	;	sample program flashes the b-colour LED
	;	from red to green once a second.

	MOVLW   15
	MOVWF   TEMP1
LOOP0:  BCF     INTCON,T0IF
LOOP1:  CLRWDT
	BTFSS   INTCON,T0IF
	GOTO    LOOP1
	DECFSZ  TEMP1
	GOTO    LOOP0

	BSF     PORTB,BLED1
	NOP
	BCF     PORTB,BLED2
	
	MOVLW   15
	MOVWF   TEMP1
LOOP2:  BCF     INTCON,T0IF
LOOP3:  CLRWDT
	BTFSS   INTCON,T0IF
	GOTO    LOOP3
	DECFSZ  TEMP1
	GOTO    LOOP2

	BCF     PORTB,BLED1
	NOP
	BSF     PORTB,BLED2
	
	GOTO    MAIN           ; DONE

; ---------------------------------------------------------

	ORG	H'2100'

	DE	"EEProm data initialisation"

; --------------------------------------------------------

	END

pp84-1.1.6b/pp84.doc100775    145    145        2674  6544273175  12766 0ustar  nemethnemethPP84.DOC
PP84 programmer software general usage notes
Steve Marchant, CCC, Nottingham university

PP84 with no parameters will reset the in-system PIC

Other command line options via 'pp84 --help' 

PP84 with the name of an 8-bit HEX file will read in the file,
 validate it, report its 16 bit code check-sum, then proceed
 to program the embedded data into the attached PIC16C84 device.
 
 Data words at locations below $400 are programmed into code memory.
 
 Data nibbles at locations $2000-2004 are programmed into ID memory.
 
 Any Data item at location $2007 is programmed into the Config word. 
 
 Note that code protection is delayed 'til the end of programming.
 
 Data bytes at locations $2100-$213F are programmed into EE data memory.
 
 Programming errors are displayed to the screen, but programming continues.

 Upto 5 errors are tollerated before aborting the job.

 A code protected device will automatically be bulk erased.

 Only the locations specified the HEX file are programmed & verified.

 A location which already contains the correct data will not be programmed.

 The software will not start unless a PROG84 adapter is connected, unless
 forced by a command line option.

 PP84 scans for PROG84 hardware at 3 common LPT port addresses.

 An overall verify pass is executed after the programming sequence.


To Do List:

* Option to override OSC settings in config word.

Bugs:

 Please report to: nemeth@mzperx.ddns.org              (Linux)
pp84-1.1.6b/Makefile100775    145    145         734  6446536511  13114 0ustar  nemethnemethSHELL		= /bin/sh

srcdir		= .
prefix		= /usr/bin
exec_prefix	= ${prefix}
libdir		= $(exec_prefix)/lib
includedir	= $(exec_prefix)/include

CC		= gcc
CFLAGS		= -O2 -Wall -fno-strength-reduce
CCFLAGS		= $(CFLAGS)

LINK		= $(CC)
LD_FLAGS	= -lncurses

PROTO = pp84

.c.o:
	$(CC) -c $(CCFLAGS) $<

all: $(PROTO)

pp84: $(srcdir)/pp84.c
	 $(LINK) $(CCFLAGS) $(srcdir)/$@.c $(LD_FLAGS) -o $@

install:
	-install -oroot -groot -m4755 -s $(PROTO) $(prefix)

clean:
	-rm -rf  $(PROTO)

pp84-1.1.6b/pp84.c100775    145    145       57034  6573013755  12461 0ustar  nemethnemeth/* PIC16C84 programmer, using PROG84 hardware
 *  Copyright (C) 1996-1997 by Steve Marchant (TP code for DOS)
 *  Copyright (C) 1997-1998 by Laszlo Nemeth (Linux port)
 *
 * Original version by Steve Marchant
 *             (Steve.Marchant@Nottingham.ac.uk)
 * Ported to Linux by Laszlo Nemeth
 *                          (nemeth@mzperx.ddns.org)
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <asm/io.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/resource.h>
#include <sched.h>
#include <curses.h>
#include <sys/timeb.h>
#include <sys/stat.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>

#ifdef __GLIBC__
#include <sys/io.h>
#endif

static const char *RELDATE = "01/09/98";
static const char *VERSION = "1.1.6b";

#define	true	1
#define	false	0

static const int lp1_add = 0x378;
static const int lp2_add = 0x278;
static const int lp0_add = 0x3bc;

static char keyw, cal;
static long cp, conf;
static short GPCounter;
static unsigned short LPTDAT, LPTSTAT;
static unsigned long DlyCal;
static int fd0 = -1, fd1 = -1, fd2 = -1;
static WINDOW *mainw;
static char lp0_use = false, lp1_use = false, lp2_use = false;
static char port_force = false;
static char hw_timer = false;

static char *
 strsub(char *s, char *ct, int p, size_t n)
{
    *s = '\0';
    s = strncat(s, ct + p - 1, n);
    return (s);
}


static void done()
{
    if (fd0 >= 0)
	close(fd0);
    if (fd1 >= 0)
	close(fd1);
    if (fd2 >= 0)
	close(fd2);
    if (keyw) {
	wprintw(mainw, "\nPress any key to finish\n");
	wgetch(mainw);
    }
    endwin();
    ioperm(LPTDAT, 8, 0);
    ioperm(LPTSTAT, 8, 0);
    signal(SIGINT, SIG_DFL);
    signal(SIGTERM, SIG_DFL);
    exit(0);
}


static void calm()
{
    cal = false;
}


static unsigned long dlyrecal(void)
{
    unsigned long ct = 0;
    double a;
    FILE *dummy;

    signal(SIGALRM, calm);

    dummy = fopen("/dev/null", "w");
    cal = true;
    alarm(1);
    while (cal == true) {
	ct++;
	fprintf(dummy, " ");
    }
    a = ct / 130;
    fclose(dummy);
    signal(SIGALRM, SIG_DFL);
    return (a);
}


static void Dly(unsigned short del)
{
    unsigned long ct;
    if (del == 0)
	del = 1;
    del = (del * 10);
    for (ct = 0; ct < (DlyCal * del); ct++)
	ct = ct;
}


static void TickDly()
{
    unsigned long ct, del;
    del = DlyCal / 200;
    if (del == 0)
	del = 1;
    for (ct = 0; ct < del; ct++)
	ct = ct;
}


static long HexValue(char *s)
{
    unsigned int i;
    short j;
    j = (sscanf(s, "%x", &i) == 0);
    if (j == 0)
	return i;
    else
	return -1;
}


static char Hex(short x)
{
    char temp;

    if (x < 10)
	temp = x + '0';
    else
	temp = x - 10 + 'A';
    if (x >= 16)
	temp = 'X';
    return temp;
}


static char *
 HexStr2(char *Result, short x)
{
    snprintf(Result, 3, "%c%c", Hex(x / 16), Hex(x & 15));
    return Result;
}


static char *
 HexStr4(char *Result, long x)
{
    short i;
    char tmp[20];
    char STR1[20];

    *tmp = '\0';
    for (i = 1; i <= 4; i++) {
	snprintf(tmp, sizeof(tmp), "%c%s", Hex((int) (x & 15)), strcpy(STR1, tmp));
	x /= 16;
    }
    return strcpy(Result, tmp);
}


static char GetCodeCheckSumOf(FILE * infile)
{
    short i, j, k, m;
    char l[256];
    char err = false;
    char STR1[256];

    while (!feof(infile) && !err) {
	fgets(l, 81, infile);
	if (l[0] != ':' || strlen(l) <= 11)
	    continue;
	if (strchr(l, '\r') != NULL)
	    *(strchr(l, '\r') + 1) = '\0';
	if ((i = HexValue(strsub(STR1, l, strlen(l) - 2, 2))) == -1) {
	    err = true;
	    break;
	}
	k = 0;
	for (j = 2; j < (strlen(l) - 2); j += 2) {
	    if ((m = HexValue(strsub(STR1, l, j, 2))) == -1) {
		err = true;
		break;
	    } else
		k += m;
	}
	err = ((-k & 0xff) != i);
    }
    return (!err);
}


static void Tick(void)
{
    unsigned char i, j;

    if (!port_force || hw_timer) {
	i = inb(LPTSTAT) & 32;
	j = i;
	while (j == i)
	    j = inb(LPTSTAT) & 32;
    } else
	TickDly();
}


static void Tx6(short d)
{
    short i, j, k;

    j = d;
    outb(0xcc, LPTDAT);
    Tick();			/* CK=LO DAT=HZ */
    for (i = 1; i <= 6; i++) {
	k = (j & 1) + 0xca;	/* CK=HI DAT=LSB */
	outb(k, LPTDAT);
	Tick();
	outb((k & 0xfd), LPTDAT);
	Tick();			/* CK=LO DAT=DAT */
	j /= 2;
    }
    outb(0xcc, LPTDAT);
    Tick();
}


static void Tx16(long d)
{
    short i, k;
    long j;

    j = (d & 0x3fff) * 2;
    outb(0xcc, LPTDAT);
    Tick();			/* CK=LO DAT=HZ */
    for (i = 1; i <= 16; i++) {
	k = (j & 1) + 0xca;	/* CK=HI DAT=LSB */
	outb(k, LPTDAT);
	Tick();
	outb((k & 0xfd), LPTDAT);
	Tick();			/* CK=LO DAT=DAT */
	j /= 2;
    }
    outb(0xcc, LPTDAT);
    Tick();
}


static void ResetProg(void)
{

    /* Exit & re-enter program mode to reset cp */
    outb(0xe4, LPTDAT);		/* 11100100 RB6=HZ RB7=HZ CLR=HI */
    Dly(100);
    outb(0xf4, LPTDAT);		/* 11110100 RB6=HZ RB7=HZ CLR=LO */
    Dly(100);
    outb(0xd0, LPTDAT);		/* 11010000 RB6=LO RB7=LO CLR=LO */
    Dly(100);
    outb(0xc8, LPTDAT);		/* 11001000 RB6=LO RB7=LO CLR=12V */
    Dly(100);
    outb(0xcc, LPTDAT);		/* 11001100 RB6=LO RB7=HZ CLR=12V */
    Dly(100);
    cp = 0;
}


static void InitProg(void)
{

    /* Assert program mode */
    /* Bulk erase */
    outb(0xf4, LPTDAT);		/* 11110100 RB6=HZ RB7=HZ CLR=LO */
    Dly(100);
    waddch(mainw, '.');
    outb(0xd0, LPTDAT);		/* 11010000 RB6=LO RB7=LO CLR=LO */
    Dly(100);
    waddch(mainw, '.');
    outb(0xc8, LPTDAT);		/* 11001000 RB6=LO RB7=LO CLR=12V */
    Dly(100);
    waddch(mainw, '.');
    outb(0xcc, LPTDAT);		/* 11001100 RB6=LO RB7=HZ CLR=12V */
    Dly(100);
    waddch(mainw, '.');

    /* MicroChip recommended initialisation procedure */

    Tx6(0);			/* load configuration */
    Tx16(16L);			/* Code Protect off */
    Tx6(6);
    Tx6(6);
    Tx6(6);
    Tx6(6);
    Tx6(6);
    Tx6(6);
    Tx6(6);			/* inc to 2007 */
    Tx6(1);
    Tx6(7);			/* mystery commands */
    Tx6(8);			/* start programming */
    Dly(30);
    Tx6(1);
    Tx6(7);			/* mystery commands */
    Dly(100);
    waddch(mainw, '.');

    ResetProg();

    Tx6(9);
    Tx6(8);
    Dly(30);

    ResetProg();
}


static void LoadPData(long d14)
{
    Tx6(2);
    Tx16(d14);
}


static void LoadCData(long d14)
{
    Tx6(0);
    Tx16(d14);
    cp = 0x2000;
}


static void LoadDData(long d14)
{
    Tx6(3);
    Tx16(d14);
}


static void StartProg(void)
{
    Tx6(8);
    Dly(30);
    waddch(mainw, '*');
}


static short ReadPData(void)
{
    unsigned short i, k;
    long j;

    Tx6(4);
    Tick();
    j = 0;
    for (i = 1; i <= 16; i++) {
	outb(0xce, LPTDAT);
	Tick();			/* clk hi */
	k = inb(LPTSTAT);
	outb(0xcc, LPTDAT);
	Tick();
	j = j / 2 + (k & 64) * 512;
    }
    return ((j & 0x7ffe) / 2);
}


static short ReadDData(void)
{
    unsigned short i;
    long k, j;

    Tx6(5);
    Tick();
    j = 0;
    for (i = 1; i <= 16; i++) {
	outb(0xce, LPTDAT);
	Tick();			/* clk hi */
	k = inb(LPTSTAT);
	outb(0xcc, LPTDAT);
	Tick();
	j = j / 2 + (k & 64) * 512;
    }
    return ((j & 0x7ffe) / 2);
}


static void SeekAddr(long a)
{
    while (cp < a) {
	Tx6(6);
	cp++;
    }
}


static char Blow(long a, long drq)
{
    char ok, doit;
    long d, q;
    char STR3[5], STR5[5];

    d = drq;
    ok = true;
    /* dont set protect bit half way through programming */
    if (a != 0x2007)
	d = drq;
    else {
	d = drq | 0x10;
	conf = drq & 0x1f;
    }
    if ((cp < 0) || (cp > a))
	ResetProg();
    doit = false;
    waddch(mainw, '\015');
    clrtoeol();
    if (a < 0x400) {
	doit = true;
	wprintw(mainw, "Program memory");
    }
    if (a > 0x1fff && a < 0x2004) {
	doit = true;
	wprintw(mainw, "ID location");
    }
    if (a == 0x2007) {
	doit = true;
	wprintw(mainw, "Config Word");
    }
    if (a > 0x20ff && a < 0x2140) {
	doit = true;
	wprintw(mainw, "EE Data memory");
    }
    if (!doit)
	wprintw(mainw, "Illegal");
    wprintw(mainw, " Addr: %s := %s", HexStr4(STR3, a), HexStr4(STR5, d));
    if (!doit) {
	wprintw(mainw, " ! skipped\n");
	return ok;
    }
    if (a > 0x1fff && a < 0x2008)
	LoadCData(d);
    if (a > 0x20ff && cp < 0x2000)
	LoadCData(0L);
    SeekAddr(a);

    q = -1;
    if (a > 0x20ff)
	q = ReadDData();
    if (a < 0x2008)
	q = ReadPData();
    if (a > 0x1fff)
	q &= 0xff;
    if (a == 0x2007)
	q &= 0x1f;
    if (a > 0x2000 && a < 0x2007)
	q &= 0xf;

    if (q != d) {
	if (a > 0x1fff && a < 0x2008)
	    LoadCData(d);
	SeekAddr(a);
	if (a < 1024)
	    LoadPData(d);
	if (a > 0x20ff)
	    LoadDData(d);
	StartProg();
	GPCounter++;
    }
    q = -1;
    if (a > 0x20ff)
	q = ReadDData();
    if (a < 0x2008)
	q = ReadPData();
    if (a > 0x1fff)
	q &= 0xff;
    if (a == 0x2007)
	q &= 0x1f;
    if (a > 0x2000 && a < 0x2007)
	q &= 0xf;

    if (q != d) {
	ok = false;
	wprintw(mainw, " ! NOT VERIFIED, Device = %s\n", HexStr4(STR3, q));
    }
    return ok;
}


static char Vfy(short a, short drq)
{
    char ok, doit;
    long d, q;

    d = drq;
    ok = true;
    /* dont set protect bit half way through programming */
    if (a != 0x2007)
	d = drq;
    else {
	d = drq | 0x10;
	conf = drq & 0x1f;
    }
    if (cp < 0)
	ResetProg();
    if (cp > a)
	ResetProg();
    doit = (a < 0x400) | (a > 0x1fff && a < 0x2004) | (a == 0x2007);
    doit |= (a > 0x20ff && a < 0x2140);

    if (!doit)
	return ok;
    if (a > 0x1fff && a < 0x2008)
	LoadCData(d);
    if (a > 0x20ff && cp < 0x2000)
	LoadCData(0L);
    SeekAddr(a);
    GPCounter++;
    q = -1;
    if (a > 0x20ff)
	q = ReadDData();
    if (a < 0x2008)
	q = ReadPData();
    if (a > 0x1fff)
	q &= 0xff;
    if (a == 0x2007)
	q &= 0x1f;
    if (a > 0x2000 && a < 0x2007)
	q &= 0xf;

    ok = (q == d);
    return ok;
}


static void ShowDeviceConfig(void)
{
    short i;
    char tmp[20];
    char STR3[20];


    ResetProg();
    LoadCData(0L);
    *tmp = '\0';
    for (i = 1; i <= 4; i++) {
	snprintf(tmp + strlen(tmp), sizeof(tmp)-strlen(tmp)-1, "%c", Hex((int) (ReadPData() & 0xf)));
	Tx6(6);
    }
    Tx6(6);
    Tx6(6);
    Tx6(6);
    i = ReadPData() & 0x1f;
    wprintw(mainw, "Config word:        %s\n", HexStr2(STR3, i));
    wprintw(mainw, "Hex ID nibbles:     %s\n", tmp);
    wprintw(mainw, "Code Protection:    O");
    if ((i & 16) != 0)
	wprintw(mainw, "FF\n");
    else
	wprintw(mainw, "N\n");
    wprintw(mainw, "Power-up timer:     O");
    if ((i & 8) != 0)
	wprintw(mainw, "N\n");
    else
	wprintw(mainw, "FF\n");
    wprintw(mainw, "Watchdog timer:     O");
    if ((i & 4) != 0)
	wprintw(mainw, "N\n");
    else
	wprintw(mainw, "FF\n");
    wprintw(mainw, "Oscillator type:    ");
    switch (i & 3) {
    case 0:
	wprintw(mainw, "LP\n");
	break;
    case 1:
	wprintw(mainw, "XT\n");
	break;
    case 2:
	wprintw(mainw, "HS\n");
	break;
    case 3:
	wprintw(mainw, "RC\n");
	break;
    }
    waddch(mainw, '\n');
    outb(0xe4, LPTDAT);
}


static short ReadDeviceConfig(void)
{
    short i;

    ResetProg();
    LoadCData(0L);
    for (i = 1; i <= 7; i++)
	Tx6(6);
    i = ReadPData() & 0x1f;
    outb(0xe4, LPTDAT);
    Dly(100);
    return i;
}


static void ProtectDevice(void)
{
    short i;

    ResetProg();
    LoadCData(conf);
    for (i = 1; i <= 7; i++)
	Tx6(6);
    Tx6(8);
    Dly(100);
}


static char TestHardware(short addrs)
{
    static short j, i;

    LPTDAT = addrs;
    LPTSTAT = addrs + 1;
    outb(0xe4, LPTDAT);
    wprintw(mainw, "0x%x", addrs);
    Dly(100);
    j = 0;
    for (i = 1; i <= 10000; i++)
	if ((inb(LPTSTAT) & 32) == 0)
	    j++;
    return (j > 200 && j < 9800);
}


static char *
 GetDeviceProgBlockString(char *Result, short adr)
{
    short i, j, k, l;
    unsigned char tmp[81];
    unsigned char STR1[20], tmp2[20];


    snprintf(tmp, sizeof(tmp), ":10%s00", HexStr4(STR1, (long) adr * 2));
    k = 0x10 + (adr * 2) / 0x100;
    k += (adr * 2) - 0x100 * k;
    for (i = adr; i <= adr + 7; i++) {
	SeekAddr((long) i);
	j = ReadPData();
	l = j / 0x100;
	l += j - 0x100 * l;
	k += l;
	HexStr4(STR1, j);
	strcpy(tmp2, STR1 + 2);
	strcat(tmp2, STR1);
	tmp2[4] = '\0';
	snprintf(tmp + strlen(tmp), sizeof(tmp)-strlen(tmp)-1, "%s", tmp2);
    }
    snprintf(tmp + strlen(tmp), sizeof(tmp)-strlen(tmp)-1, "%s", HexStr2(STR1, -k & 0xff));
    return strcpy(Result, tmp);

}



static char *
 GetDeviceCFGBlockString(char *Result)
{
    short i, j, k;
    unsigned char tmp[81];
    unsigned char STR1[20], tmp2[20];


    ResetProg();
    LoadCData(0L);
    strcpy(tmp, ":08400000\0");
    k = 0x08 + 0x40;
    for (i = 1; i <= 4; i++) {
	j = ReadPData() & 0xf;
	k += j;
	HexStr4(STR1, j);
	strcpy(tmp2, STR1 + 2);
	strcat(tmp2, STR1);
	tmp2[4] = '\0';
	snprintf(tmp + strlen(tmp), sizeof(tmp)-strlen(tmp)-1, "%s", tmp2);
	Tx6(6);
    }
    snprintf(tmp + strlen(tmp), sizeof(tmp)-strlen(tmp)-1, "%s\n", HexStr2(STR1, -k & 0xff));
    Tx6(6);
    Tx6(6);
    Tx6(6);
    i = ReadPData() & 0x1f;
    HexStr4(STR1, i);
    strcpy(tmp2, STR1 + 2);
    strcat(tmp2, STR1);
    tmp2[4] = '\0';
    k = i + 0x02 + 0x40 + 0x0e;
    snprintf(tmp + strlen(tmp), sizeof(tmp)-strlen(tmp)-1, ":02400E00%s%s", tmp2, HexStr2(STR1, -k & 0xff));
    strcpy(Result, tmp);
    ResetProg();
    LoadCData(0L);

    return Result;
}


static char *
 GetDeviceEEBlockString(char *Result, short adr)
{
    static short j, i, k;
    static unsigned char tmp[81], tmpa[81];
    static unsigned char STR1[20];
    static unsigned char STR5[20];

    adr += 0x2100;
    k = 0x10 + (adr * 2) / 0x100;
    k += (adr * 2) - 0x100 * k;
    snprintf(tmp, sizeof(tmp), ":10%s00", HexStr4(STR1, (long) adr * 2));
    *tmpa = '\0';
    for (i = adr; i <= adr + 7; i++) {
	SeekAddr((long) i);
	j = ReadDData() & 0xff;
	k += j;
	snprintf(tmp + strlen(tmp), sizeof(tmp)-strlen(tmp)-1, "%s00", HexStr2(STR5, j));
    }
    snprintf(tmp + strlen(tmp), sizeof(tmp)-strlen(tmp)-1, "%s", HexStr2(STR1, -k & 0xff));
    return strcpy(Result,tmp);
}


static void usage(void)
{
    wprintw(mainw, "\nUsage: pp84 [-apvr012t] hexfile\n");
    wprintw(mainw, "\n       -a     -- don't ask for keypress on finish\n");
    wprintw(mainw, "       -p     -- skip programming pass\n");
    wprintw(mainw, "       -v     -- skip verify pass\n");
    wprintw(mainw, "       -r     -- device readback\n");
    wprintw(mainw, "       -0     -- force using port 0x3BC\n");
    wprintw(mainw, "       -1     -- force using port 0x378\n");
    wprintw(mainw, "       -2     -- force using port 0x278\n");
    wprintw(mainw, "       -t     -- force hardware timing\n");
    wprintw(mainw, "       --help -- display this help screen\n");
    keyw = true;
    done();
}


void main(int argc, char *argv[])
{
    /* --------------- MAIN --------------- */

    short n, i;
    FILE *hexfile;
    long addrs, datval;
    char fname[256], l[256];
    short err;
    char STR3[256];
    char STR6[256];
    char STR7[20];
    struct sched_param schp;
    struct stat sbuf;
    char got_name = false;
    char prog_on = true;
    char vfy_on = true;
    char read_on = false;
    int argn;
    char parm[256];
    char *sp;
    char got_port = false;
    char lp0_lck = false, lp1_lck = false, lp2_lck = false;

    hexfile = NULL;
    LPTDAT = lp1_add;
    LPTSTAT = lp1_add + 1;

    schp.sched_priority = SCHED_RR;
    setpriority(PRIO_PROCESS, 0, -19);
    sched_setparam(0, &schp);

    signal(SIGINT, done);
    signal(SIGTERM, done);

    keyw = true;

    initscr();
    cbreak();
    noecho();
    mainw = newwin(0, 0, 0, 0);
    immedok(mainw, TRUE);
    scrollok(mainw, TRUE);
    werase(mainw);
    wprintw(mainw, "\n *** PP84 - PIC16C84 in-system prototype programmer ***\n");
    wprintw(mainw, " *** 31/03/97 Steve Marchant, Nottingham University ***\n");
    wprintw(mainw, " *** %s Laszlo Nemeth           v%s Linux ***\n\n", RELDATE, VERSION);

    for (argn = (argc - 1); argn > 0; argn--) {
	if (strstr(argv[argn], "-") == argv[argn]) {
	    memset(parm, '\0', sizeof(parm));
	    strsub(parm, argv[argn], 2, 200);
	    if (strcmp(parm, "-help") == 0)
		usage();
	    for (sp = parm; *sp; sp++) {
		switch (*sp) {
		case 'a':
		    keyw = false;
		    break;
		case 'p':
		    prog_on = false;
		    break;
		case 'v':
		    vfy_on = false;
		    break;
		case 'r':
		    prog_on = false;
		    read_on = true;
		    break;
		case '0':
		    port_force = true;
		    lp0_use = true;
		    break;
		case '1':
		    port_force = true;
		    lp1_use = true;
		    break;
		case '2':
		    port_force = true;
		    lp2_use = true;
		    break;
		case 't':
		    hw_timer = true;
		    break;
		default:
		    wprintw(mainw, "Invalid parameter -%c \n", *sp);
		    usage();
		}
	    }
	} else {
	    memset(fname, '\0', sizeof(fname));
	    strncpy(fname, argv[argn], sizeof(fname) - 1);
	    got_name = true;
	}
    }

    wprintw(mainw, "Delay loop cal: ");
    DlyCal = dlyrecal();
    wprintw(mainw, "%li \n", DlyCal);

    Dly(100);
    conf = 0x1f;

    fd0 = open("/dev/lp0", O_RDWR | O_NONBLOCK);
    lp0_lck = (fd0 < 0);

    fd1 = open("/dev/lp1", O_RDWR | O_NONBLOCK);
    lp1_lck = (fd1 < 0);

    fd2 = open("/dev/lp2", O_RDWR | O_NONBLOCK);
    lp2_lck = (fd2 < 0);


    if (port_force) {
	if (lp0_use)
	    LPTDAT = lp0_add;
	if (lp1_use)
	    LPTDAT = lp1_add;
	if (lp2_use)
	    LPTDAT = lp2_add;
	wprintw(mainw, "\n");
	wprintw(mainw, "Forcing programmer to use port 0x%x\n\n", LPTDAT);
	if (hw_timer) {
	    wprintw(mainw, "!!! If you specified the incorrect port CTRL+C will !!!\n");
	    wprintw(mainw, "!!!           exit the program gracefully           !!!\n\n");
	}
	if ((lp0_use && lp0_lck) || (lp1_use && lp1_lck) || (lp2_use && lp2_lck)) {
	    wprintw(mainw, "*** Error port is locked or doesn't exist. Exiting\n");
	    keyw = true;
	    done();
	}
    } else {
	wprintw(mainw, "Looking for PROG84 on LPT port: ");
	if (!lp1_lck && !got_port) {
	    ioperm(lp1_add, 8, 1);
	    ioperm(lp1_add + 1, 8, 1);
	    lp1_use = got_port = TestHardware(lp1_add);
	    ioperm(lp1_add, 8, 0);
	    ioperm(lp1_add + 1, 8, 0);
	    waddch(mainw, ' ');
	}
	if (!lp2_lck && !got_port) {
	    ioperm(lp2_add, 8, 1);
	    ioperm(lp2_add + 1, 8, 1);
	    lp2_use = got_port = TestHardware(lp2_add);
	    ioperm(lp2_add, 8, 0);
	    ioperm(lp2_add + 1, 8, 0);
	    waddch(mainw, ' ');
	}
	if (!lp0_lck && !got_port) {
	    ioperm(lp0_add, 8, 1);
	    ioperm(lp0_add + 1, 8, 1);
	    lp0_use = got_port = TestHardware(lp0_add);
	    ioperm(lp0_add, 8, 0);
	    ioperm(lp0_add + 1, 8, 0);
	}
	if (!got_port) {
	    wprintw(mainw, "\n\n*** Hardware Error, cannot detect PROG84 oscillator\n");
            wprintw(mainw, "*** Is programmer attached? Do you have permission to the ports?\n");
	    if (lp0_lck || lp1_lck || lp2_lck) {
		wprintw(mainw, "*** Port(s) ");
		if (lp0_lck)
		    wprintw(mainw, "0x3bc ");
		if (lp1_lck)
		    wprintw(mainw, "0x378 ");
		if (lp2_lck)
		    wprintw(mainw, "0x278 ");
		wprintw(mainw, "locked or non-existant\n");
	    }
	    keyw = true;
	    done();
	}
    }

    if (!lp1_use && !lp1_lck)
	close(fd1);
    if (!lp2_use && !lp2_lck)
	close(fd2);
    if (!lp0_use && !lp0_lck)
	close(fd0);

    if (lp1_use) {
	LPTDAT = lp1_add;
	LPTSTAT = lp1_add + 1;
    }
    if (lp2_use) {
	LPTDAT = lp2_add;
	LPTSTAT = lp2_add + 1;
    }
    if (lp0_use) {
	LPTDAT = lp0_add;
	LPTSTAT = lp0_add + 1;
    }
    ioperm(LPTDAT, 8, 1);
    ioperm(LPTSTAT, 8, 1);

    waddch(mainw, '\015');
    clrtoeol();
    wprintw(mainw, "Using port: 0x%x \n", LPTDAT);


    if (!got_name) {
	wprintw(mainw, "No HEX file name specified, do a reset cycle...\n");
	outb(0xf4, LPTDAT);
	Dly(100);
	outb(0xe4, LPTDAT);
	done();
    }
    if (read_on) {
	if ((ReadDeviceConfig() & 0x10) == 0) {
	    wprintw(mainw, "Device is code protected, cannot Readback.\n");
	    keyw = true;
	    done();
	}
	ResetProg();
	wprintw(mainw, "Opening %s for device capture\n", fname);
	seteuid(getuid());
	setegid(getgid());
	hexfile = fopen(fname, "w+");
	seteuid(0);
	setegid(0);
	if (hexfile == NULL) {
	    wprintw(mainw, "Can't create output file!\n");
	    keyw = true;
	    done();
	}
	for (i = 0; i <= 127; i++) {
	    GetDeviceProgBlockString(l, i * 8);
	    fprintf(hexfile, "%s\n", l);
	}
	GetDeviceCFGBlockString(l);
	fprintf(hexfile, "%s\n", l);
	for (i = 0; i <= 7; i++) {
	    GetDeviceEEBlockString(l, i * 8);
	    fprintf(hexfile, "%s\n", l);
	}
	fprintf(hexfile, ":00000001FF\n");
	outb(0xe4, LPTDAT);;
	fclose(hexfile);
	wprintw(mainw, "\nReadback done, %s saved.\n", fname);
	if (!vfy_on)
	    done();
    }
    wprintw(mainw, "Object file:        %s\n", fname);
    seteuid(getuid());
    setegid(getgid());
    hexfile = fopen(fname, "r");
    seteuid(0);
    setegid(0);
    if (hexfile == NULL) {
	wprintw(mainw, "Could not open the object file, exiting.\n");
	done();
    }
    stat(fname, &sbuf);
    wprintw(mainw, "File Dated:         %s \n", ctime(&sbuf.st_mtime));

    if (!GetCodeCheckSumOf(hexfile)) {
	wprintw(mainw, "Bad Hex file, exiting\n");
	fclose(hexfile);
	done();
    } else
	wprintw(mainw, "Code Checksum OK\n");

    if (prog_on) {		/* Programming cycle */
	if ((ReadDeviceConfig() & 0x10) == 0) {
	    wprintw(mainw, "Code protected part, bulk erasing.");
	    InitProg();
	    waddch(mainw, '\n');
	} else
	    ResetProg();

	GPCounter = 0;
	seteuid(getuid());
	setegid(getgid());
	hexfile = freopen(fname, "r", hexfile);
	seteuid(0);
	setegid(0);
	if (hexfile == NULL)
	    done();
	err = 0;
	while (!feof(hexfile) && err < 5) {
	    fgets(l, 81, hexfile);
	    if (l[0] != ':' || strlen(l) <= 11)
		continue;
	    n = HexValue(strsub(STR3, l, 2, 2)) / 2;
	    addrs = HexValue(strsub(STR3, l, 4, 4)) / 2;
	    if (strlen(l) <= n * 4 + 10)
		continue;
	    for (i = 1; i <= n; i++) {
		snprintf(STR7, sizeof(STR7), "%s%s",
			strsub(STR3, l, i * 4 + 8, 2), strsub(STR6, l, i * 4 + 6, 2));
		datval = HexValue(STR7);
		if (!Blow(addrs, datval))
		    err++;
		addrs++;
	    }
	}
	if (err == 0) {
	    waddch(mainw, '\015');
	    clrtoeol();
	    wprintw(mainw, "Programming done:   %d locations, no errors", GPCounter);
	} else {
	    waddch(mainw, '\015');
	    clrtoeol();
	}
	if (err == 1)
	    wprintw(mainw, "Programming done:   1 error");
	if (err > 1)
	    wprintw(mainw, "Programming done:   %d errors", err);
	if (feof(hexfile))
	    waddch(mainw, '\n');
	else
	    wprintw(mainw, " - ABORTED\n");

    }				/*Programming cycle end */
    if (vfy_on) {		/*Verify cycle */
	if (!prog_on)
	    ResetProg();
	GPCounter = 0;
	wprintw(mainw, "Verifying...");
	seteuid(getuid());
	setegid(getgid());
	hexfile = freopen(fname, "r", hexfile);
	seteuid(0);
	setegid(0);
	err = 0;
	while (fgets(l, 81, hexfile) != NULL) {
	    if (l[0] != ':' || strlen(l) <= 11)
		continue;
	    n = HexValue(strsub(STR3, l, 2, 2)) / 2;
	    addrs = HexValue(strsub(STR3, l, 4, 4)) / 2;
	    if (strlen(l) <= n * 4 + 10)
		continue;
	    for (i = 1; i <= n; i++) {
		snprintf(STR7, sizeof(STR7), "%s%s",
			strsub(STR3, l, i * 4 + 8, 2), strsub(STR6, l, i * 4 + 6, 2));
		datval = HexValue(STR7);
		if (!Vfy(addrs, datval))
		    err++;
		addrs++;
	    }
	}
	waddch(mainw, '\015');
	clrtoeol();
	wprintw(mainw, "Verify done:        %d locations, ", GPCounter);
	if (err == 0)
	    wprintw(mainw, "no errors\n");
	if (err == 1)
	    wprintw(mainw, "1 error\n");
	if (err > 1)
	    wprintw(mainw, "%d errors\n", err);
    }				/*Verify cycle end */
    fclose(hexfile);
    ShowDeviceConfig();
    if (((conf & 0x10) == 0) & prog_on) {
	wprintw(mainw, "Code Protection requested by HEX file, protecting now...\n");
	ProtectDevice();
    }
    outb(0xe4, LPTDAT);
    done();
}
pp84-1.1.6b/README100775    145    145       11516  6573112647  12375 0ustar  nemethnemethPP84 - Linux release notes v1.1.6b
===================================

            *Prototype programmer for Microchip PIC16C84*

1. General notes
=================
The binary version (pp84-1.1.6b-bin.tar.gz or pp84-1.1.6b-x.i386.rpm) was
built on a Red Hat Linux 5.1 system, with kernel 2.0.35 and glibc 2.0.7.
If you have problems running this, then grab the source (pp84-1.1.6b.tar.gz
or pp84-1.1.6b-x.src.rpm), and compile yourself.
The executable (/usr/bin/pp84) is suid root in order to have access to
the parallel ports, even when run by a normal user. If you feel it a
security hole, then remove the suid bit. Oh, well someone will burn
your INHX8M format rocket launcher code into a PIC... :-) Seriously,
the code is not verified for security, it may contain buffer overflow
situations, which I don't know about. If you remove the suid bit, then
su to root for running it.
The input format is INHX8M, the addresses are compatible with Microchip's
MPASM output. Further description on what's programmed where, is in
pp84.doc. Maybe a man page will be available sometime.
It's possible to read the code from a PIC into an INHX8M file, which
can be programmed into another one later.
Description of the command line options is available with 'pp84 --help'.

URL: http://www.nexus.hu/linux/pp84/index.html

2. Hardware
============
There is a simple parallel port in-system prototype programmer,
designed by Steve Marchant, which is a modified Microchip Inc. AN589
thing. The schematics is in the documentation directory (prog84.pdf)
along with a sample 16C84 design (pic84.pdf) and a sample assembly
code (pic84.asm). I programmed dozens of PIC's with this simple
hardware, without a single error.
In case you have problems with the auto-detection of the hardware,
then you can use the force port command line options. This shouldn't
be needed in any case, you most likely have a hardware problem if
auto-detection doesn't work.
You can't use parallel ports, which are not recognised by the
kernel at boot time.
Theoretically you can use PP84 hardware with no on-board NE555
oscillator. In this case you must force the software to use a
specific parallel port. The software timing might not work on
very slow computers, but I think a 386SX/33 will do the job.
Programming on a board without the oscillator is not recommended
at all, it's just for helping you out, in case you don't have the
components handy. This may reduce the number of reprogramming
cycles due to the somewhat incorrect timing.
In the very unlikely case, that autodetection doesn't work, or
unreliable, but the oscillator works otherwise ok, you have
to force the programmer to the appropriate port, and use the '-t'
switch to override the software timer, and use hardware timer
instead.

3. Compilation
===============
In case you need to compile the source for yourself, the usual procedure
applies.
	make clean
	make all
	make install
Make sure, you are root for the install part.
After this you might want to move the example PIC asm code and the docs
to somewhere you'll find them later...
If using Red Hat, just get the src.rpm, and 'rpm --rebuild pp84*src.rpm',
and everything will be fine. Now I've put my hands on a Maximum RPM book,
so my forthcoming RPMs may be more professional :-)
Btw. this code is ix86 specific, but it can be modified to run on other
platforms as well. Anyone?

4. Bugs
========
This software is BugFree(TM), of course. Still, if you find one report
it to Laszlo Nemeth <nemeth@mzperx.ddns.org>. This only applies to the
Linux version. Not only bug reports, but bug fixes are also welcome, I
will include your name in the doc and the source code. ;-)
If you experience problems that might be related to incorrect timing,
then (1.) do programming on a less loaded system, (2.) fix the code,
and send me a copy. I've done some testing on a well loaded system, and
experienced no problems.

5. Legal stuff
===============
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License   
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

The original Turbo Pascal source was kindly provided for me
by Steve Marchant. The C code is derived from his code.

PIC, 16C84, MPASM are trademarks of Microchip, Incorporated,
other brand names mentioned are trademarks of their respective
owners.

					Laszlo Nemeth
				   <nemeth@mzperx.ddns.org>
pp84-1.1.6b/pic84.pdf100775    145    145      242124  6345102360  13144 0ustar  nemethnemeth%PDF-1.1
%
1 0 obj
[/CalRGB
<<
/WhitePoint [0.9505 1 1.089]
/Gamma [1.8 1.8 1.8]
/Matrix [0.4497 0.2446 0.02518 0.3163 0.672 0.1412 0.1845 0.08334 0.9227]
>>
]
endobj
3 0 obj
<<
/Length 81356
/Filter /LZWDecode
>>
stream
ph(b 4 P a
D"l "#Q@mHiD%-&29,b2q
SPCHCCZP™
PjV)'@@(f2	@F7K{MkmlwKUh9u(BKb1Xv
ck\ƶ+W+6Ig3޻K"#DžEas7<.'u<>(e
0m$`ox]8nK۾/[ì2.+ߠ3t;0ªF"`8NJZ*Haű$=S=<
Lw:OHB-
ҋC(
d
JLC b0sK=62<2E3t
p;q]Q!EQ.S0(7OXhYTT5[WS}CDNp]L庉;ʱS,9j$jz (3VdrrvmVlOMpiLE!tZp]@TaO._mWoY+T3خ&,n8$N7l9;WwYyN-s"fZAyc
#Y!Q5%;+57tW՞DrF Z^U%
3*;^izn}jG活۶ŭg+f=Ͻ%-5)&t4QiB^2q8{>uTa,x˿zu-T{KbԶH5
"i~kJR~np]92+տW2RJpemԢPC5RfM\&Jн7e6\cY9ʼnaezhm
AvPydޔXOBQ-DxbGI(N(%D—[F>,%ⶁq,Z,5v>
#[,8o:4_ug}q.$"bɑNJFCS;&dlՌ%X0z0(eذx^RdA_&ıxM%l;l3EqELy0P5olI39s϶:%X<U5&:H@H'Ɛ@BP̨4$v1&\>,|K/d"4\LL\qO{>230d*hc$3
!24jnpiLˌZcDivRPTBe3\0$V+!*5,&j$5Zj1(5QK3Om$٥Zu<0Li$j\\k*䆥ڿXjU1zN[HsǜC:}TlfyT*m"wRK[ar_c$䲃;KS5PT%EjKL95`<^KJSY;WvN.YjNˍHh%l5"$PohіfߚWeyˀnY4JS&G6:]Ipj@"2|R/x.ڌť߻NjU%؆k[B8pbGu8a_M0~>:uo͢Xc_G9NW.y2mxf/#Ι8Y52ӰκuRCke[,2|]$apQE8~ڡ3{vnBycOnNZ̈I/CZmSGIjH9?vcA56VoexauU;Bm(bϫz>LIk5r{:ݕIsf"(vgOeZJ٣25&&U#c_4gjNY~fZA¡ξQskhY#{1{
פx''8kW/=GIVdTm]=A;L>ZS:Y}grD|]\5;o[==3߅0c5g>$(N	fU؜)?ĤTLlxlG:rotFeꞯ;&Q+pwlB+ԡZŭ]|Ϧ~8N>)
sz(JVDLiN
zʯfn$eb:$k.ﰥe~t	6[JjjN:/RfOv>πeJ|jLeT(v_:Fg/äJzpt˜3UCPY׌>˜dΐ觌)]̨3Cjp5
+
"PX䯪pe)"m20m(Q0<$ЮkH&ĬUo|\RԬkV2/#3np<//~0"Fj~f
)$
gMg(%sqD01t$-XQʹϯsk.q

jEV2/| Ѻ
cљ*8LMv2pcj^ov_K
Wvތ1w6G $
 F	Ty~-bxi?$n	&o-om&;~䢥|fTU?'<4v&OrN&J%I&&zq>*VM,ŦIF.htxU(eFo!IERW0$qo.#0Nбs8HRɪOs&2
Ql8@qxN0.<m#DX%qQ`EkDE'*:xh&:3r719,q6=6QDsVrSF50QhB8lm:=sH8IQ	4-F|@3Mk%5D0=9S@&06QsR)4͙4̓)/qXrSTӹBC,Ƞ"""E.Md7Bds0L93d3]6tZԓ]=ep$Je7s	\6]Ɯrt~$qDRc
(*6+b0^6N/Cpb(yF֣BS@o0t(ICqLL̎Q7E4ҾLĎQ,
KQ7e>3KUo4+N:Tp"%tGAMN*SO TT#\rO1CR	'$jDc2g.D4(`߯$COup*@՗XpD(2N$CBjUk0
Pljf%պS[KOQ3X5|
a]l8[YVc4WLM+>tS426$Π?!0-{]d0o`2/բL2/g3&D~SD%dpAH#W(t-]Fj6v*
Kc=3:Ed2I-^vE2CcgVf͏bpa*u5vu*a*\im&<Ymf4u#BY7Wu:wfi€hoEn?)Ħig\Go҂w5h1n3rlm;pY)H&T>qLn1OXR-p6w[#i#x/a1̒]p薭xd63vGRuKuiU[MJEHK3]5J|7M3U=	3=p"7`>O3xu
r$NrRQBi&ĻeQ$6dHɀjD5c'0'z5Ԏ{븣C$
}QK	JT3xXT"EPnvqÞa)_GCRI-Z*6P!KqEL=>3~&0^"-ȹh-,
:JN֚z_yq>8ڮ^M?
J
;dX}oQc#H=R,~0U6Me8ӪQ583k]l,y"Mx:;yO k82m+mϖ;wԣcUM
evذ%%	R~߹~iedYf)UP|֫%yE6_D'9L!D9ٷĽw
clj9w+
:.=9A+x>>#eK53L׫B?9!Wq:9iVLTdߣ$3b)>n!Mc~&g_ p3!["JwZ,ZzYZX.958yXw3z2C8gOvK{b33thL%gue-:"!C™^;0 #B+B)Q'=Q(LSstl;k7["lDCM6T8vbMX;,=bHuvTuBL-3E{X6ڠAl-'` P
W{4`SOWLRC#ջ4T`E|E1ɬ;:gŜ/ê_3;om1z[
?R\cL8WVc{1
h1<\Ǧo+'F6'%HSx90E`ZDXNy<0]}A;bT#|#I<%d<ɝA
7Wp˻CiU0/_]A+d,mg]veu0Un{ݟ1[{\E[fn[̂I%N'Zߋ
\9EG|K+L"U	;Pick$!/1S4^wK>4.;;{.%T~2(]ݵedۻۧf9^x&Z>BYiVBO]{YfM螚ލYY#$l IS됷}b8N=(X_D'L.Zf}-Ķ&"1У^X#qڷ>R0"~cMe~Q-1);,[!ia!L<W?k۩ͭOU?TbXz5G/e\9IY֝tBi:"G@Ofų7H]0E=fQ3-[0w#ȟ?ѳ.j.`44
xl7C(Q9d0qȸ`3CE821o<ey}4OR	\8bU7zڠ6A`dn`Xqgիa6)k*iQ.ҽipDm*ŌW s:J6;_3_q6idk}^7}紲
r)CU8AeFA[EsgM#
?Nw{JQAF{}V2'$zrS!*fNkڄh
Я+h	Ҋa°'Z	0[rA
6+#;oҤfD
2*Xű`2BҢl>*+J1O-jr̊jҪ	ཌྷ*޷%"\7d”%".JHtz+ GsH裠Q!;-	>ϳtտ޿)o8(I=T
*;Y(;cQ?*Qϸ`کzhXbҴ,ynX
ڱIUsqoJZJL%\"Ty׬ݪYf6Y/u$LuoHX֕ՏH@uc䫂Y#&妯$V`!Heyi	59zu
uI:06h<Lߺ4ޭfkM@i%MLi*,"OdZU2ZFRh-K;٣gCaph(̎gb[<x=}l3j
	\4uK}ZW-g_v:d>F`ck$,:I^KRcxk:0;y<Mԝ	s54~mq~gB{&SxY{a%#x#@*`ፑ'-hhh&Ga+.:KM$D$&8@WU`Җ%\Tu}
$@q$8!h,@A Ķ#BR2Bȿ|PR._:˄%!t0/GhC
K{<f\xlȌV|d=񰝓HS`(R,EB"d|yEC5d!!ҔG("э/2n<I*o$>/IcczD#CTqCeIf&E_ Nc[›mMoT\+2ƙ
57H/n2TfTj]
c!i2]2BB"ԞDL8{D'qfu;rY45dL(@OiVQ[rJf|ELCK(BR#>mVdi|U&>}]-%$PIIu25QZ!C2s@%k%RQ$e!O&Uel\Ԋeu
>
TǬJSXkԜB2JUά&2ȷXfUPb<'md(BqH{a28I"
Pb*
\Y5^
n-`X})غP
Eks,(ql\%I	"tEА$*1j2^+ʷ*P)&0RU#(0
\v1M·ϹQo=rKwT]xk0s>n**>qh\bY,ҧ(6ė}8ȬZR1Ƙ%[mRRk>QќKUˇ7EHFW5ٙƩdٸQhD͒!DȚޯ:U;bUtQ%їE?1.Œayj\ӥsk8gW/tR`PJۗqD4M윟i7,
=d`N+~?̚[	U5tY?ܱ[Ex*Z:itYFTuK龗#EuM͡]v>	ֽq?<1J<B`4sv<.w	r&1qh͙tOC(V^'&
<n^xHiajAf6,LogαoW=C!}i^ZZ,UVHmYî7pohW)m"xy$^I&(~6c~;j%;>J:x;7[}?v\ךxv	3ԴbE$rqo寂H6F!&,a1/19PFZ?VId)_j<阁5JL8g7OC1H$ECx2J"!ɢ&!4.A ?Ф/?\
1/(#.B1C3qdSx'z|Y+4X爼<A.0|B<&1 T$@
q7hݎ\ >(ü7$9quCבŞD:ÈDyDw!2?AKECk;:QA~,@B\2C\#DD,,\&$EB	4jI6y
FNDfL_FDV"Db.򁺋D`׽/C҉D3É6 SG'l#>Y%zH	9x#L-3Ǫ~Ȥh{?,~F<ād{8@qd0PlJB18E\1zE/D$:1d ʢҙ4ɃwH!IZ*!ě(IEk TIs1{˒DAE|Kq#BCAED<Di2tJqA
HtG0ǜh>[.%j:9k2+3|z ӵ$ٴx(SHDŽ|j>L=NZJȤ*EdDAK`DC!YͻkM=mˬ,IBjL	lL,L|O<Np<4ٱ6,LPԿMB*˅+)7*h7ȁ\NN5@L::-!ԙ'#eK3)+9LQ;I4rO 
:0QxQQ|PNS]3SNu2:m.̼H&;2G1T;k
@JΫK(Ĥ;d="N3½
<]Ь5OTΛOE(OѼTuLUu=T*mF"IuU!A+A]յD	뽹ʱ{@AR34YE:t3R(X#;R&8
8T8*V=h#
f)
^WiW{HWWX7DJ(!`7XX<)%ؒօqWu}?lEy@4
VY0
YŔיm &mvYp&ŝ
3VAh@ݑ~C5ZqTLpUٯ#X!*Bu5틶r	y4 7Zk6ګڝſ!qVM5X=UB׵~ͦ(|5܍]GUWi\:}¦]|Zٓ?]nLܽ|Ixu}
<U~-XM
\ޜV\^^}Sڕ1YT,
Uױ+|_^~CZՀԈ=5I=#qMr}qLVW1FxB`
E(_ 3V*H8a8LܭV,2VaqH=0.JXq"ń
$8%U-iawəT,Kj.2*f0
!]3Vn8#V*ɞ&"ɞ)?Rc{B2(?n4b.7 6H:6(^Id+c+PD--aͭueIfEdicI~ZD䨵N&[L6L&N^I
d<BhʬM(Vhfh	]fb	mF[g6qd$u׫>xYvze|cB~ajրͩN)~
Fh`nWתV⮋X+hsg
fa qn:.qŎi~v,4	gi|}vdᎁj^>
k)VΖꆪ莮i覰i9ޓꦬvkN^ah#c3%c.
.*6Ih(kke&n*R&e嶥lXj!PfPgI[gr^/>f.jg*gDVVogNm9Nn[m.cgF}aκ칍hh.eFlvd;^^kfjα.&6al1궅kldꮧo_el}mF$l(w~moah疟p~9n->Iv7j_qwv8phwq>~~lqeG~d.lGw#M/rqN՜v0p/&w2oV,r^ng;n#4t
Ϥ@ex"k8_b	R?Di5K/ASoM	jts_#tl?Q>u>*nUjCjZjȫ
[^XuƬ+vRh.!I	=tOb`4hGbviEr_XPv	-s/^vve	I?vw7yw}R[wo
@tjwGx!M(xwpx?vwωeU}Gxrg=xgs?y_koחydTwmߑlxFٯj*R?{kg:CsvgwVrǪ9Dz|Ÿmvj_vhz{9
C{a"O]{[zϴk6/ow!|lW6|fo'vߟ7M%^tu'3^>:*ag}nDoy0"kg
{O垏z^zppbw%r~wϫ~so"'nFknޮysh{vk/lƲj@L
Gl @m`\6
X0c	C(.FXܢ@6
Ԟ;)a)Ě9OC)*r3
MFATV!AαRU!pkclшp4Za,d10]4}]rtms}O+*M6UT7K;K7׋:hف{lǧIt7NfG5o.WugT~榗Z%ZJ)
)ԼzAh+k@!ű e1l2⤽k
DkpcDZ-QESō`j)74ď<p\PlǾLF|8;jF3EG1H4%&brb:JxNhMS+ЫaB%R쾘IT=-QҬ1D/(AJ{Q:jS3+	NC'4cHVYQ7V5OĪ:Y>ތ6CMsI^єE/ut
7=nbʓzW}VQhwj37ZbmoGjp؅q@-pXXt$B,)\Ld4wYbټэdY%Wxe	fW]WH6}'5`_/.Y2[FFmqSӎ{yZ8iX[YR%}y6a	Zԟ,B/UkFrs*r`o"մ_%ȆU۹=S7׭=ύ/Nq2Ur+ZE\tgwGb=}_[AG-4l~_1%?toa^.u;NpyÕ$8)40	j<{b!zuϠsF
eA 0R)81!ķHOOh8؉7,X`2tq884$h!z1H2K!N0@iHQOhDثMAЌ1r7SFdAN/pqF$S1򡁻m!8	-s ;Y"O%0’(d!Z	;$\
$UK|BHE)%N&r*I,`“@jt[՚3jn$WuH0~X\!!kvS;9S3SБKs C m,#r!I3rXᢜ2Sz
8ٶz(tIQA47.O?diOK&"39LIb12.IәPC4j㢥	1RR@TEiӮGQ'kuQ4}QX),1JdzV|
η&NЋ
WC4xW)b{.LYjȏnIʰ\\:1ST㫼{30d.N=ۛv#12+mc"W.Q쬁[.=|[V
oE㮽0My˥{A*
2-+KnTegM&!b	/lS^ˡnӃIo.r+7~裃|q*GFM뽴͌~qT#ّMNƘY&J\)K`C"yB>*e~).b&ҡ0`vXpj^dz26-yFb,Z+ƴw0<y`vay: LʺVLC]K԰ȘKHfiW/DsvץR"ȼn^ܴAaj8Olz`~+U}nf7@+%C~FS_k,pf$2*c=7ԡ׻4Bm.L{:--Pou|oq۶:24<M"p&͓)#V#Þ)>[B6w,E}Z|{J.Vph{')e͋6Vk.HJyc!.3_(*V<Dڑn8>PŶm	$l&dh<Mv+dm2Y}$W̿弃Ǚ?]{iPxB1(rɭ~Ҽ^7~˞:cwݏ>;P"OGvIU1R6H\ŏErE/=jLPgh珋鶷.,&,9oJ&' «+pd*NuKH2@PRHlNЂmH
'o^nO!py	0hp[oГsp\/%Pe)AY/<2m`dghpһM<cdf͋rNLKw/%1 4
./H1q-ElG*x
TΐBd0[g+߄*Pb+t†ш..xd*&ooeK uQRyHhgZnf|j*,q޴s$)2/AVQ%v,>\qGk(ܱDR,O5$(v%M
/rD# 2vf(4	"͑!(&R.h>r?)<0C'A)/J)!+Vk2/JQ60cfQH0cHΔ+.rڥ|FR fM3bn!i02f/BI*13,DBHPrSTlG22qu17i6l.-1614X10s/Ppz)*ΏEMX֮Ӵ1F$ghqpsu&	=N7vs~{0s%kZ17<N.sz˰$p>FC=u0Vs/! b$lF&BF)6T1?=$k	?PmCI2B;Ek)2~n6FRgA%?!)A6Ԃ4bui4;f+BlI͌bu)Bv}<b-J'X4*nqMT7L͛MINU?BJ9eJrlHmJlEyJJTуP-Gjz0¬~uN P3QiUMh%.9u72"_23G(*pƽVONJL8QT>d),7#t5U40-K3v
<w\+E\\y7D\RqX~\#tFUNYQ>UKA`,20H3F6%u^յG^mR]^5^4+]PHJL3e)`Toe	b)b}vmMy+j̔ry<$D|3/Huh	Dg5%gbhя
iYlp6W6bDuO)goGe;PnGhRv7J,-ep%2464&rm֊6
%f
oKldmob}LϷmfF+j0I76NFeuP*ζάde
ysWwr%wq7uqvzr`wpWMg?w}ZJnflFmr0@=O~vҲɪswl^.ɶ*\e倶U~+Q}GfvLp
n))kb*1 '3yx8GWkjjQBDk5* cMJ&dp`x/kiEPLRhvqe􁇴o0xq@Ʒ$Hh\oaWBt:fjyP)YUΕ?(xr^gf3G{JLfF&39	9W)QcfXՒEqoB$F<ky"Q9W3EBy7]VX܂Ǥd×ljQ<7&ɑ
Vٖ?sB9r{~r|$v`+GkeMfÛKr6"Ýfͅ8Tg1^LrŦ2J`ijObMZP'0s2;
eCSEmwER:(]Ěz`m!M (i8ݚOJcS,^GBIh	֎tQk7&fDM+<wwdlޕZ<ZɴfjdA7kX014apOftOv:]Uk'B cFÉ+q{[ܭrR%$4-~5k`nzo(IX#DskxyuGcǫ)hҕP;&,G{#p~XrFcpwt},DΈ$V!0ӎ
'i^;{8'2~Yj*绬p\/"[}m&i[Oe*D=ơ2X[%[)eϺ{od;u8^(ԛi\`2FBŐ3U
ף|U<9Ȳ]!\NgE0\9tWhޮfCg|t|1WwmdF'mgwgTCjXiv.7Rn6ҷ}yL}YOTW5s2!}h0}q"|]mrwbYqhz}Iq=
}AV761t5kf.]k=ܬX,Wv/tAagU}Љ{"!qSNq]ݖؾ.q]6Ol)f{Č7D~Rؗv|Hɴ17";Z
!u>PWcm$Ho)ފ)^;WqJ]ڇqNY;{~1{[>_P(n^JvJS;vw@H܃vX1ټ5ib6dVk'_iaj*U]腷?/&Vr;wkLH7sY.ƞqӵ@dw?oo42M~V꟝ׂjEYd1nuh#WhJoC5?y?!p1>d"~A\ ql4a
A]
m8(47C!TJH18k'JAs1qq
spl7D!.
0AquJ4smH,,ᴺ-G*͠q/VхgAx(kImu1zαc1]6R'
~B&ITK'"zn1NQl2՚57
Ń.[3EoA-ޭ;+s(kyC,m@<lt?o2LJR7d߆*t.l33
&@,<4LBHH)B02HJrR)hp+J	$!Ipz#!mQ'#/kB4q+M++k/+.hIr%|'
'I4IjK2X)\ȌѐBIRhʮ|Tt/ByP̎5^3|hO@`Y%-R,f,)cZܨ(}[ZًMnbLP%=jT1ll\MpImm<5-'5jgh^+d\˵c1%WHyʙwxo[;Uv*-6BQ:(r<yrm8]ecȵwZ6g?Ƕbk̚2.3편b6@Ӷ[KUؘ&#\[^7 J?C {S
vn[m|0Xf@=i6bՌn)2qǪInMOˊR/TJ}^o'si7P5li!-#[n@Bҹ.A&TZYYZI=8H;Yi+r6skiugveOeU̟$g&@)FW|'mĢ5TeqEI> SVk*gAYY6Hl`
y]C(HTq=a	9M5&\ʦJi',<AMTw1|=RP`4%"U!ԏutc*P)Dc`)*S
$]RX5	XӊZȕ-bњ(YbL[)ʦkVCMB)$dy63Li&U
@mLC+rTJ<܏d()s='Q@vg=4[ZT E1AKHAJ4JP򬤧KԅR G)3ErL(*Ee#AdL!E2d:MM~F:vH[AԋHF
1 ~0QUHDG]^(ijpT+2ӺA"4Q,JVDz^d)薦KEy/3Fa
m{ǨRk쨒l/ejv*C,i5%
cXa]Ƅ6kc)$="FsU-42M`EH,Wee5ß$E;ReBMVx2+VA-:Vg칺h`砹`e).H~ڄ/״g>"/KNsKfh#B_ߋEPī)I+7pjb<Ao276*)$60q.S&,k]&c5&9/};r9s`ZsfJȩMY~f]
nl7kR#Y8'6ti{	:iʲA)qVgL$WYh #9盙Γ2c34z͖rqڙj3nr"Eu-\&Dg-BlL59k{벣Y(unwZ+C;g4~o	7Ct;fe)~$X9"BA,3/՞;넩$',jD(zIԃ5~gۢXM
&_5<P*	[x
:
	^Ot*ʲ}	1
>x>XV'n}5L9)ܓo
N84.ŧSmJڽm7/pVO_3'ƹ^=
c(DGa4mNRV<%^Dy?|?ͻ3ʯ+5h"mpWǕ۞KѾt!44i?:‡$yr%}fO54m|_s8[,NVMۧS7]7cHʌBf:o]|xHWn]12Sncd߶ݶ׾C=.kuc
f=˵?3v@:Kz/
:r8@A
h1ZL'kj\zCS+
[;#'{<!Bdd\;20عB9+>s۱p<)'?9 ;[,T2j%k*|CC4{zJtt<4~CP$c4Aò2s=Rj>h1FL{B2XDaDڽQd6{"z-3 22Z^
+<w``7EGˉY%>m7tV`$Li&hC?%tGfv9#E]lE-2GkF<acFjӦ%i7h&"\;jc<Ŕċ&;["|}.fy
˂
SHFh<EĂ:IWcFÞ{JI|q/
,+P.~/!#HbJd	$#:TalA܈	
zKHԷ˴H|DXI
s|Jh<,6lx"z+yLdɄ1jMLˉҎd"dŜCItKC(?͓͒3N3TP>t*[N:b?*OΐG։DĩD˘D H<f	2:$;
@COŝyHʰ-ȹ	ӟ̄L#JEHO$uL*.ѼPG,K,PPM-ޭrں tM,,BN40$M32 L1LKGS?++"SldS-Ӎ=,
ӊS>tRC7M$`$T"pTu@TDƤDu,3NkK9Y4lPD0Det>5>مMKJP:R=^յ:L5XLPUcSQ 4j_U$Y{DQ=DU)eFQ\rVNT%n}V'*CMb͍oh͌5oBm\HXE"Ώ䶝jTKl5S4Uy۝i[WTVx4
,oRer!T ϦuCl Ri{IVȠEXGv91ɁUY#έ";YMڂ!1"7<]<4r XGEFlkbE͵Edm۬aǂ;eۈɫ}Ɍ;4S5q'J-cT\Z%4RD]<Wո\%]A/]u݄]]C	]I\SݼRݼ]9)]]42G]I?u
U9xؤ@l?^]{M]9
@VX]U
׺EEו'PnP'_ڣQu`:r
ib<QLFA4v^QD_%PA\6Wq/]VMȌuލ]uPeU)FN/*KA0aϮصʐv <.+:6Ⰴކ.&4^cUwb3ͭ<F=M0+`ee.*ǎ>X`n>Lvb.%MU0ͨVy4_=թ`!
~Ae
deC)|^N0 VMB4vd݁w7_Y*YlspaSU[cafMC5afL5caC?mfs'@Ρ[]GZnP`)cb0lܕ<վs)hfQ<f~wZN7ԊҩM1F揔#[2;j
J"_@rHfuh㪠RY$xaƞG%{h,r">d8RO%`8^^
hj_l Ua%6^>iRqIFiP
\ꎗB:[8OJ|<)ο9NR{Eޒl\di*'i&
̨yjD̞i⎦*M<'2lj<k6;ن뚊C9`mfzl즩]fʥm~l*>r֜
Ҭr~n[m^Yo:ek~k[onʝO6m*z,y!VnઈFn?v호N2`v!67mdOk6a;
qiUw
o;jI(ԑR
'ޡhϺf
Zo
 ?^r5@6B?jjsER1z,%ɧpGL@'K+sVFӔjQ2
4!:= ۜVLe[=Yʫ
lpUwaG7btGUntbCgv,~GVvyPەD7\$LZdJoTp>T曺!pO$j'Cw}!V=N_r6guDf7֤FvtJ-ԲO~UkbaSM?R	jv9w8}iLkkeWzqP*dwĪWOoyZvi'dwy'[3x$$zΫOwPp4M\>~v{Kg{Nzv|;/s{`H`{׹Gz귥ߌŭwJEϊxEgvv
zPϷ_zUoZ_"},aZf_'tO0t}w-`_uRs{1VctG=}'Zr0wg?uokP,drN}/wp1d6FC`43A
Ƃl<kF1xDj9B$&'Bc^$2p`2Besvy3cpcQecx-N&9SJ7E:&Y5lmT
*ejU*Z'!\eUMiجd\g=2x,D/Eכ&7XȾl8Vfn/aD
h6ihHC1P3ٌf>͏#	6sf0r:Q>?teFPۛ
G6Y(p!fƮ”<=(V'Pn
 n>8jp0:
>LFlSsk,Z&j$'i"H%r&s/Z.ڋ-)])(e:
"JSY9Bά#/DK,ki^$GRM:t$!P)AF"H	TF[dч(PEDLre*4n);D!PZ:xMa՟e2(6AAir/b+XBqh!דGzEhL钸x>%Δa,\Z1robW8FruAcx?O
K	J%!7j4&hB$.yH&؃Mt֢ı)lӭ[YX͵'	(:g~w(pjOUܕj'fg<J&q5{t6t=NyoMx]/V!+bGe{o*㺻
B@PRqoƅ?گyŸ~uqr򕊩h'0X2K؃J0%B0b
ENb%kR5a<yP>
ۡKn-v5{ConDJ⊫жs2rE0"4_@H{nr`bI_AABxa\|n
H(d{C9wc,CpR%¾Y(K.'IL1&P$yL52L{ˌR,w).VWKҾSj1L)hTzy381]rቨc|梟2MRO\d1)Ddi28Cjv.U( RKyIޒ1d5KR-2܅AB*ͧSNVz'o	!tt	D8GOZ%TJNI`*H
ʗҪe8)t2WDN(4(*Q	
L'.xTF3Q2>tD)ʌJT+M!]4"U)&Lt<mH3ݸ^_o`
^KuWOl=#+AXӋU"jVcFXLϰhuU:DFt#QӍU(erҍUkmi:NgkUAT.KAO.Y[_z>fsTv*o-쟛<_SU)Ut3c-G6ޚc|pFGZf,*VJTUQT	T@ESƍQD~S&<VRi<Ͼ
vb[˓"=ٴD4`tlDvR6Y
J:yʑ䎱~8<\zAr`Nu{^`1⼚qFyyMd2k})9XU9WKq\Y3+	F 0D],J
h?6ǝvFnGG{J|uO]4&)S؇:R(yf,E88)˅^19Y}-!ڶD?)
|Xf3IMWv973^OmN{Ɲ.pG*9)Fچ>ϝ$+]M=cko˧uX$܏ԉ&[ۑ&/u5{7~m+
ͽ~tFؓxt^2Pw?GmjYJvPRw3z}
tjZmK!f/nQnj
ɕiG*Ov.d,5b/ӚS6j뭝{\A+
gjG6K]Ew[9OuLgyںݻc/={q,.~#WO{1WufގeJm,Ds=]z~gS
ro*J$oHt`,#>t+01eJ`ܾ+JFx!i"Il,łr׏>HN	,HD.#D%lcFP?Nҝrd~Pcm!
p|Sh pPԿ̆@wΰ3,n<Eo(ܭβ@Х
ZΪېp	;Mh<ń?031>;*k4	Fά Mq
xQ;pK;
Eqo.kѣ̬ɪ#~Q;1_ -E0oH= Psr	
J)ONTNOfBը-B
!B*oRbqۍn-Zrjqb8Ѭ`r[$p%Qe$v:'RmtNpʵ#/o*c$I!٭0^s9jR;(R[8S.N쩎fjQC./φ5/"O;.&%6jPB00M3K.P$GP8:NҽD7C|33),0.x72=163\
3+5+W1ZC00|08S!3>pc1SPC3S.KfrL25Q)<h1l6Ӧ9S§3p	$=?1AS;˱43<'sN3֮ZDN̫lVƞXS	EtP1C4?Χ/:gQ.s*btI
 8:I,t禰&|nuKKcQ7IgE&_CI( /&t>ijG/NtaF"s;1b)bth+ph^kCTFP11N6kA T2&b TC:ciUB3U3RyTϻPLS$bNS@Ktst'8gOSht*S۫]Nrgu>8MX\&'CU]MP58?[Ӽ[{YIMd	>W՘.uTpt/WlmYqZraV•ssdUkV6;.C[64UC?C/bHtImfk#_eͱ]Pz$5(=esl,ii$^hQjh6_jb#QjWaj7b5F>S@_bG u"l
O-4;n;BS^1XjV6:=#G
zսC5aI!aV:aTLM.oKViZrerϖOI9n?u`46ct}q[ss̝f,VG38&:m]3]&r%won"U8B0R&Z*51ו|/F|ŀ6M>w]'M=|7~
gjy^[~#!-"&\^n"6108$[kW7B#fu_
D7BF"\6*`A4nx]=82FRT֔8l[b(¯"7Xp$	&()RgHmN8pw*$"m=Qynظ'Cbjm'x]8Q)'6."KuqˏؒJ&b@ISő8t91k3GO
ؼx=L8đ9J9ECXL9.;nxD	smw),2a%1$F,8b#eƒͅj"$co#2+OTH`0MY&C99e'Cy̢5{
8[FF|(
&鷇
cfpK6iJYgكgyi<Ră5m')kz6MD"W:Uex		ÏsF#I_
5'^"HE
xm+XF`QxqK1IϪӞٖ7Á\ XSzMZL9.BOYE0[G=\{ٴf2[]F=yʹæw;]jMh_BWaiGY$Gr+$赛;Fj8ZY^7hK*4񽃅\{Y$XE~Efc~`(eQ텯ʍy1hr<1-{{xB c|\Aj<0HB?e.%ӽ|c[<s@*5s8=eTs *i^<%<r
<28*lffݼҶz̻"xㆨ-C|SUj|U+'qף"j/ѷwѼٝQļj=<%N,]FK=+ȭ{\ȴ,J<!$Дm	$NGX|1Iٹz4ꝥ3r:\Q+|1}/LñE"%SI*Mt}Ű[|ةܼw߶Iaې[2<mEπ<@<Ξ:z7duࣥ	O7"1~\{T">+{Ӊ"1K{vDF/߈$9[<x(
֋G)q~>ꐭHUI{ķޓaWVrmIUP	{r؎ݴzk$0-(_7f֬I^f.Q&??ȱ	v~Й؛nabt!>ya[]Ǝiߍ&Z>P=ѕ|a\td駷H#߹ئ>_Y׻؛
G9'i}`wi" r 6AC1\2 Cl6C!gcpфb5`\
5ʠsQf5N$7
#RȺe469FtA*!@`2B$eQ[mKf]Fe!܆4ahh7PhwUfT
s1q_B2͊:
uSC̲ќc1Hq;m!k5p1g|ƴk3.Sxn5t:X-vKdaf|<(gfb9sKz|Xl=.8\6J@/[nD>k>iZ0-a
0k	.H]k>F1\Z-
0³1DlBʄ/>-D7/61sc@΃-s97b\/L6)R3S,PoTBrQrdI5:ǪKMe\"@HRh€._b-6*L5R&-c1*֣:4m4!޺RkH޵zRD6
8nW֍v0ͯ:{	ʮ(ƣ[ns*y~d!/b
lmeeR^b,$L+涩OQ[UAK5L'S	F.Pkv @z|u>\Jͱ쪣L_F9TkrدJ֯eA?- 'l>e?!yC*#ĤKIe*=iJ'%'bi^ϖުͶB:'][e}p\fI٢KՆ]o#]7Qx8@W5&^qg.\?z[ua[]bR.+N3X@VL
hAfJ2qbRNM!	Z6`K\ FvWy!p~L9H8XШUtT^05G%~mݴe dL¢hLUvfY] r?$`I84_ުi9u
TdJ%蜒
amzC}YaE}p6F@bKERv(D*baJ_#@D2d$%|K+ybL}9bBmw.d$DeeSn=8ZN:e}3=8~%'V]5!#*&["]'MhP9qD`|N9E9U'e<4XGT@3O~fyk6D&[0Msedb@L8,Dzu
KLPtFFR%>UT*82F*?ىC(t,fZI#(;CWD3K$ܠEV}Ic_)4I&D9bl,8E@C[d{
y@?_*_TGd<P0dNi}OMn\ːWI?vU[YVᗷ4s&GuA`<*ڗ{OYw!oIy8*BN:ah2/Ee4h0  .|@dA*
`DiX6b{a1~ĕi?<O	|(aR 1&ብ5z]*E?!HJe)@5uiՖ+O3	!&wC7dMA74S@͝FâDUHEs?u:0|
)~n.fP^Vm*y#_^5kV^lE[㬵y[Uz/iP&9(QRׂ0WJulw	u@WFꝠ
۸UuGwR˗[Ss@vt۵\ź/ΛJI׷IV?Z-Hbb
w	]dG]|kZw9"Jd.H[ҵ,0ӑ9EBRs֋]vp[PI[4Y;smS\p
D{2/Y4Ca(&/3v^D:(w/֊Gl?x#}]~W^YcKŖ7{*o!S6o</xs~UCQu}'o.IU#ТաO0@vi={Nm/tK-u,¡2m
8*]_O<s/k;?S,/RڍkX2O29kQ8v>9?8躔؇8+0Ը(.!#ڝ`)8zs @@9?c8(&9j}9{F$
D2B9Jd8A+-PCcC9'/$)-D*>1\"ˬ@782KL|NR_AC8Dۊ($T{	
qVǺTW"9ũ+D_+9ZŚ#AEȜ?|ZFkQlWP򰹙4DlCKFLT<pDT<<ddC<1/
ډ!FkټZ\GǽwFv>4o<ZcH|fȋXIGi&AZG@+@IFh2TGk\<E@ڳX(#㷤HK?8,BH	$=üiI
WAAK3Dʳ8+|Q83[&FZ\\:WFƒSd'CSJF7;HE콈rXFHLcGLT5鵺īAc0X+Gh}=DM|
;}	1|2a9tYIN :RKQKddɳΈˤF|T
14ILLt1[ܽTIM<<f@Y=</ķNKΩ(i$PTf˜A&N?[NL*TtЋ4C4@O*XO
Q9Q$Bd=4RCؚٞC܋J^ƕ  <QPn?d'Q̕J%3$fԬHZHB|A`7ҼiA`Gt0CI1!)hô9PSu=Nʔ58IQ5e!$ZD7C%0ВI%.>DSҬS(R}4"eAL:=-"5LwR7}2
5.TiS=>)\
:;(F`
%cԱ,[!J;Hݘ]hA9<VTh"F\<L!
J4_
9|;3לW-JId|NTC4M-wdN4lX
"YQMJ!mVN~ElulC
]44ɔ	0Au=}sii=uOJ%-τmĝI\F	A%V}Ie=%ZPӿ]Zk>Q1W[[=NbE[PK%?Jե=ŴO-B
Z
mj-Sj&
BV%ݲ
%?Ͱ͙]MQ\̻0}3_YYdJM+(kլ^48KG\
"8ޜ0R<-J^HOMD(y^}LITЊz$Ե
0۠c\FS\0 Q3Q|SIV냑u6`k`~VdR[
7}V菣בLTKѹ{6uahWl@`װ!k:g $qrMg<̓$kNȵO(1Nb[Sⱥ`RyNV6
ID.341Rؖ`~N99)~cb
1c>nFڙ-nJQg|
JYe̾PeZE7Y
y(v\CEe:\8F\E>v\e&TQm8`hحn&`"Q{s֍re]A[AaeNdaeqLF`5j)7Abh^Ƈ੝60Ao<TaŕrˬWM~\1s
>e頃K֖&VvGӆttƖT㈚*C
M}	Eb>.N;N)h5&
ȼ%f
62G<jvF2ڦZ3E֯Qg@񈙚Llu>0&Tf.Q&]Q(dz֦QnSW5.lI;aŚJfѺ& bnJ(ch1$c1`v7iL9ƗiBQ::Qav&Po-lo"(5_!k_kom=(Yxjo
%{kb55p.6CqRDpxkC.G!qҗkqH:%}^F4:L!!F^5e
.] e.&o%%P~%m&m85)ͰP/Od-䮞l]R/Rgr:inీI4gfy!C*nې~A#QHiQ\H.d/bafP=&_uknu$;gcv[.WNrL)kt#G`hj+r-9Kh)[Eo_`Y.w!r^w)wuRx~)<&r?eqҴҲ-2xk2|-Ow|}zd-Z*}qI;<ppzl-OFrsǙ(G6H	*qN֩Rv|	oSuQWOvJv/yo/X"VW<Gd
Y4(Zn	{fec\֕s^|'Ѯ{~0}beg}T05j|8n ~eϰ`~n貑]8aH'6:ĵXMDbqɨ<<?'bf 6AC1\4A\7`hD(m
ÑZHx<4
bAj5GEcs)apb9E@mGcb9KQ!1
)SYT@d.JcIԭf!{Wz=&z-JE]uK),fg1FK62iD*US4*;\71K蠡l0gʜ[s!BGӧl[{S,4
u0fQ;5]?N><K2&Ҭpb'[	([R9:r.mp0{:d6*CrQrP[aa>o1Jdn񽬘pE'#,A};S),MsӬ@҄v"3c4Hj8)Ҽ,
T;71#SC5h)(qT-KRu*GJC<;ku`մ܈?j^DJH%+O2'VLuL6[Q	CZ~UJ!RܻSjrC^]4]X5I\46pܘ`t5:/7T宛Y7Ï5ӍV{4*>PsOӢOO])gўS&h(mZޮԭn]t>ЕU'.S{)	̒o3҅^۟ω\<D l"vO+G[ZN?K$q/a?lJ?Wֿv[Is>v|"+
M5zz:VK\?dR7s-~(RnKyam3(BvΝBY`22DBw/EvL+<qq?8<ժojҤVw4fLE
uo0fKDmD(E2䒈s"% 8\$E)ţ65DW))f91R=f|j):)FN:O$#pf4Htd[NƤ$j/mLJR 逼ʠfdI}K dJ
[>PK]C.r{E(%&XRXw,ZSu-y!H90
nc7"ZqVU9R
2~ce6D)k
“Ƞ->3.h&1
PHΡ,ǹN"m!qMNKF)0.YEIOaNDS;t681P)Q6*KZ_*
2ǺQh*>
y	B'l4jygkkmLj]
DLI_Ȫӯ6
**=`SyS`I3pB4+Da2[d,zje\V1P*YԸ^¨BI_newH{l.-uiܪ,nˆV׋9*.M֮6HG<bM,l%jii.kܸrݶ.N]mLgE
$yi=Ym8V@n$z+"3%[bU^qjeHU:`tTVl;<HID%]WShʘD{eUG.jk3(QLijjo$pKU݊=\&UjMfisM4609Lsd:b7%ʙLEӒ4
sҿOO@u,j~mV.DjٗRh5tm̺Oԝ9.(ZlMw)k[+嵴ҙ~jh&޳b[f?eD˶t[uol2rĥ8)5IN%]&];7#R8e#K
@9:˺>;Lx$kQqF+5IP,0,5&Se~@aP4=Ӎ4k/~M1nLycZ	&n]/]6rU,2^uDu}v{6iT7zxwT㔸siRKг9)x΀]9-q	ExQI=;oVx3iIo%'_db=/D/':T~ۋD`$0	FH.Y5=oj~E^BNHߑ2""߫(O	/f)fH?ʂϯ)ԩ()`Ꮨ7"F+9)X@hijyo0$R)FB$3R	fHxO."'ɐ0nC=Ih
"n88	Ш@!0:PȌ2)ɽW
	Kp?*'#iVNN[
hPPp{.tPp0iWHd60
K6
8⒌
c"TT*Ť# .qjIO%1x˭ΝL&0)f>ErPDEBt:7̹r48pH&'5nph"\ј+
M	ȻCe>&Wm8ʦ!=QQ"(QH$2ymꜯjqʼn~;#hF(#B e1"$v_&"Mbnbt9>$y
)'v+2CQe#&crx0R2Ҽ1b8R21.K,!
rȭ$!r/o.B?Β\*!&D6'1B)bҜ@g.eZH\>C2d-7&J$1y-S56B-3r"*}2-0ME%3E0x!O#$}(S(W'qx_kc'H4S:+N/(N;sS*S8xuc*>3)s(S 3v_5zJسChc/DA/P<"EBt!3:T>3S50U7-&G1DtZ.0'?C3>Tq!gӓxTrhUqCn:@(:Nj`d&Dc9OqF8F?JBP*SL2-4:KT5nf9*}NNA8Ҩ=h&<C/$y:DOra<cNLA-'dUQSD'34SqCT>9:L%*[7?UӇ?mVr`WO{CIT"jNF/=/0sR+YS13t"eOIKP#ISaPFLvU<<SQќL3Rhf$S_gTtLն9ON1VZiv W@LbmB5%4{]633_ƏVKE32(vY]J_?8I_V}4b
ugBcuPѥi5irvP:R$q>YY)kP]TELll6u;rQ5(<BGk(L5;m=n8u`V\Pjկjw]"tW#qWL4Vx0Sh^d6aYk0e5\Vw6de5H51%Ygp6^uo"ig.sk&OEJ7-vtMZW,"FEd!egQy4mk14n%wRw{Nila20e}>)v.l6o~Stnc^2`[]W\vт3lV끶Uw6jF7^+6%{WWb!svggjX-daj8`HEĢP`3㷉)x=5oqm7xH縧㥌XxÅ`X=Vv8Yl厸_,~QygKXtj9-u9:T-!}&1i-
-+VZp0t}Osؐ#֥s&"f(zt&B́xј,Yy7pW"9w9j:ךeY[ߕ9} Kxcj8,ѓuMH͝ӭ8-Mzب"=mFt(F%B-kLHC#CȘ'$ꊘsQvb.NExZ9搿/׊ҧ|OT)[3J2#GdQ6!oq:g,z).o=f~kzb/(LX+NHzHRE6:WZ\?zyPC)?fGP}vDRgp;!zhM_yƅ6eH
gYfRMz'y.lwp!5=fE.zewYf#>{[CAJhZ!y!8Ju;75JgF2H(S[kC}nȯHAd<@ݲ$%#X\	;#1k!(.|"r'F{{ä	O튮a4/<Z|,`$0pĊyt%ni,$#&id.}&i@'Hku%|T0jejeoܪ<jgH	)$%"ʸ|ȰrjUWy<eTܘ!i8+\т3$&$#"<(cKpA$3-@bAd$%Ӣp2\h"J榅|n=u)E|lQM܏ ]:=\~).JYS=rcJ[]/03<EeK[rxw]{oc#ѫt,pSgv*c6N40gJZ;-^=(>B1^g>RiC~*f(EgyTU~zAǵ@d^|ih
 ~`Eӽ@ݾ4}`Q[23p'QH^yqj%xc
^w~	Nߦ^~dgx]F~Kj;@);sgx6$aT_Dux!~;km l~@WI~D#}*(_?z?9e?PKߦ*)=w'=w.l 
#p Eh
C\7•Td0
|F&mI]%dQXL.1
b#a]#Qj6HaAmF	ΏIϢaΡ;F69>c\r9Q'WwܡX
:GGo\ƃ;%L2oq;&yv:.gṬKjtw|wxmnWKu0C͊mo>4Foq'ڙ.cdfWzVl/\w7	RP+N!3@ApAo(\!a./DbnÉhnB`.Ԉ5"Ɇޡ9/b®B j !ki!*Nj񼺷!cV"R)J,MIM{
H6ʤ&oEC@jqʫë,òjNp+PCSj:/*ΒX5<,ui+-6W9KSEwHNu7Lլ]`CAįC%Q]@A+x[)BW8ed9uQT7LUVA=`uݛ7Ox錸d5w\kteunl#7,+mCRR7 c92CUH.;xљ#X.:j/|[3Hb˨l1,)l^͚ɦo$.(:W.]PR5&Q
):~|Nyɞ3s8naBrRDCԝb!@h^;Lz}NߒQKýZkyV%x-x>K"w
W*v8.I#=`m6y[?l"_YKuH)Ef)4v
d2@GM*B" "(+
ON5ád7EdhvM
D%|4IC*2
?nȭ<B!~{,ĕXB]=h$֜IBGbSC!sUj
Results 1 - 1
Help - FTP Sites List - Software Dir.
Searching half a billion files worldwide
© 1997-2009 MARUHN Internet Solutions