------Actor

package meetFinder;import java.awt.event.*;

abstract public class Actor implements ActionListener {

public void actionPerformed(ActionEvent ev) {

run();

}

abstract public void run();

}

------AllOfUs

package meetFinder;

import java.util.*;import java.awt.*;import javax.swing.*;

class AllOfUs extends Person {

AllOfUs(String nm,Committee cmte) {

super(nm);

committee = cmte;

}

/////////////////////////////

Committee committee;

/////////////////////////////

void recompute() {

committee.recomputeTotal(this);

}

boolean isComposite() { return true; }

void showMembers(MFDate dt,int slt,int sltPR,

Container mom,int x,int y)

{

Vector victims = committee.allHitBy(dt,slt,sltPR);

if(victims.size()==0) return;

JPopupMenu pop = new JPopupMenu();

Iterator iter = victims.iterator();

while(iter.hasNext())

pop.add(iter.next().toString());

pop.show(mom,x,y);

}

}

------Committee

package meetFinder;

import javax.swing.*;import java.util.*;import java.io.*;

class Committee extends Saveable {

Committee(String nm,File f,Main mn) {

super(nm,f);

main = mn;

members = new Vector();

}

Committee(Main mn) {

main = mn;

members = new Vector();

}

////////////////////////

Main main;

Vector members;

Person allOfUs;

////////////////////////

void add(Person p) {

members.add(p);

}

Person addSummaryMember() {

allOfUs = new AllOfUs("ALL",this);

members.add(allOfUs);

return allOfUs;

}

// tp had been allOfUs

void recomputeTotal(Person tp) {

tp.clear();

Iterator iter = members.iterator();

while(iter.hasNext()) {

Person p = (Person)iter.next();

tp.add(p);

}

}

void fillComboBox(JComboBox cbx) {

cbx.removeAllItems();

Iterator iter = members.iterator();

while(iter.hasNext())

cbx.addItem(iter.next());

}

Person addMember() {

JFileChooser dlg = new JFileChooser();

//fixFileChooser(dlg,chs,'e',main);

setDefault(dlg,"cmbr","Member");

if(dlg.showOpenDialog(main)!=JFileChooser.APPROVE_OPTION)

return null;

File file = dlg.getSelectedFile();

file = Util.forceAnExtension(file,"cmbr");

Person p = new Person(file);

if(file.exists()) try {

p.load();

} catch(Exception ex) {

main.showWarning("CANNOT LOAD: "+file,ex.toString());

return null;

} else {

int res = JOptionPane.showConfirmDialog(

main,"This will be a NEW blank Member",

"Please NOTE:",

JOptionPane.OK_CANCEL_OPTION);

if(res!=JOptionPane.OK_OPTION) return null;

}

add(p);

return p;

}

void removeMember(Person p) {

members.remove(p);

}

void writeTo(BufferedWriter bwr) throws Exception {

bwr.write("name="+name); bwr.newLine();

bwr.write("begins="+DaySchedule.dayBegins); bwr.newLine();

main.writeDateRange(bwr);

Iterator iter = members.iterator();

while(iter.hasNext()) {

Person p = (Person)iter.next();

if(p.file==null) continue;

// Not a saveable person

bwr.write("member="+p.file);

bwr.newLine();

}

}

void saveAll() throws Exception {

Iterator iter = members.iterator();

while(iter.hasNext()) {

Person p = (Person)iter.next();

if(p.file==null) continue;

// Not a saveable person

p.save();

}

}

static String defaultExten() { return "cmte"; }

void loadFrom(BufferedReader brd) throws Exception {

Pair pr;

MFDate[] dtRng = null;

int dtCnt = 0, dtX = 0;

while(true) {

pr = Pair.readFrom(brd);

if(pr==null) break;

Object k = pr.key;

String v = (String)pr.value;

if(k.equals("begins")) {

DaySchedule.dayBegins = Integer.parseInt(v);

continue;

}

if(k.equals("name")) { name = v; continue; }

if(k.equals("file")) { file = new File(v);

continue; }

if(k.equals("date count")) {

dtCnt = Integer.parseInt(v);

dtRng = new MFDate[dtCnt];

continue;

}

if(k.equals("date")) {

if(dtRng==null)

throw new Exception(

"date without date count");

if(dtX>=dtCnt) throw new Exception(

"too many date");

dtRng[dtX++] = new MFDate(v); continue;

}

if(k.equals("member")) {

File mf = new File(v);

Person p = new Person(mf);

if(mf.exists()) try {

p.load();

} catch(Exception ex) {

main.showWarning(

"CANNOT LOAD: "+mf,ex.toString());

continue;

}

add(p); continue;

}

throw new Exception("Unknown Committee key="+k);

}// of the while(true)

main.setRange(dtRng);

}

void setDefault(JFileChooser dlg,String ext,String kind) {

dlg.setCurrentDirectory(main.getDefaultDirectory());

Util.fixFileChooser(dlg,ext,kind,main);

}

void saveas() throws Exception {

JFileChooser dlg = new JFileChooser();

if(file!=null) dlg.setSelectedFile(file);

else dlg.setSelectedFile(

new File(name+'.'+defaultExten()));

setDefault(dlg,"cmte","Committee");

if(dlg.showSaveDialog(null)!=JFileChooser.APPROVE_OPTION)

return;

File f = dlg.getSelectedFile();

f = Util.forceAnExtension(f,"cmte");

writeTo(f);

file = f;

name = Util.nameWOExten(file);

main.setGoodTitle();

}

void open() throws Exception {

members = new Vector();

addSummaryMember();

JFileChooser dlg = new JFileChooser();

setDefault(dlg,"cmte","Committee");

if(dlg.showOpenDialog(main)!=JFileChooser.APPROVE_OPTION)

return;

File file = dlg.getSelectedFile();

file = Util.forceAnExtension(file,"cmte");

if(file.exists()) try {

loadFrom(file);

} catch(Exception ex) {

ex.printStackTrace();

main.showWarning("CANNOT LOAD",

file.toString()+" : "+ex.toString());

return;

}

}

Vector allHitBy(MFDate dt,int slt,int sltPR) {

Vector lst = new Vector();// Of persons

Iterator iter = members.iterator();

while(iter.hasNext()) {

Person p = (Person)iter.next();

if(p.isComposite()) continue;

if(p.isHitBy(dt,slt,sltPR))

lst.add(p);

}

return lst;

}

}

------ControlPane

package meetFinder;

import javax.swing.*;import javax.swing.border.*;import java.awt.*;

class ControlPane extends JPanel {

ControlPane(Main mn) {

main = mn;

layout = new DividerLayout();

setLayout(layout);

//------begin date selector

JButton ok = new JButton("OK");

beginDS = MFDate.makeSelector("First Day:",2003,ok);

ok.addActionListener(new Actor() {

public void run() { setRange();

}});

dayCountTF = new JTextField(3);

beginDS.addCell(0,2,3,new JLabel("For:"),"L");

beginDS.addCell(1,2,3,dayCountTF,"L");

beginDS.setBorder(new EtchedBorder());

layout.setNextCell(0,2,0,1);

add(beginDS,"");

//------Person selection

layout.setNextCell(0,1,1,2);

add(new JLabel("Member:"),"");

layout.setNextCell(1,2,1,2);

addPersonSel("LR");

//------time step selection

layout.setNextCell(0,1,2,3);

add(new JLabel("Time Step:"),"");

layout.setNextCell(1,2,2,3);

addIncrSel("");

}

//////////////////////////////////

Main main;

MFDate.Selector beginDS;

DividerLayout layout;

JComboBox incrCB;

JComboBox groupCB;

JTextField dayCountTF;

//////////////////////////////////

void setRange() {

MFDate dt = beginDS.getSelectedDate();

if(dt==null) return;

int nd = 0;

if(dt.isWeekday()) {

nd = 7;

dt = new MFDate(1,1);

dayCountTF.setText("7");

} else try {

nd = Integer.parseInt(dayCountTF.getText());

} catch(Exception ex) {

nd = 7;

dayCountTF.setText("7");

}

main.setRange(dt,nd);

}

void setSelectedDate(MFDate dt) {

beginDS.setSelectedDate(dt);

}

void remakeGroup() {

main.committee.fillComboBox(groupCB);

}

void addPersonSel(String jst) {

groupCB = new JComboBox();

main.committee.fillComboBox(groupCB);

groupCB.addActionListener(new Actor() {

public void run() {

Person p = (Person)groupCB.getSelectedItem();

main.schedulePane.setPerson(p);

}});

add(groupCB,"LR");

}

void setPerson(Person p) {

groupCB.setSelectedItem(p);

}

Person getPerson() {

return (Person) groupCB.getSelectedItem();

}

void addIncrSel(String jst) {

Object defIS = main.newIncrSelector("1 hour",4);

incrCB = new JComboBox(

new Object[] {

main.newIncrSelector("15 min",1),

main.newIncrSelector("30 min",2),

defIS

}

);

incrCB.setSelectedItem(defIS);

incrCB.addActionListener(new Actor() {

public void run() {

Runnable sel = (Runnable)

incrCB.getSelectedItem();

if(sel!=null) sel.run();

}});

add(incrCB,jst);

}

}

------DayHeader

package meetFinder;import javax.swing.*;import java.awt.*;

class DayHeader extends JPanel {

DayHeader(MFDate[] rng,FontMetrics fm) {

dateRange = rng;

fixSize(fm);

}

/////////////////////

MFDate[] dateRange;

/////////////////////

static Dimension prefSize;

static int charHgt;

static int charWid;

/////////////////////

void fixSize(FontMetrics fm) {

charHgt = fm.getHeight();

charWid = fm.charWidth(' ');

fixSize();

}

void fixSize() {

prefSize = new Dimension(

dateRange.length*DayPane.dayWidth,

2*charHgt+9);

}

void setRange(MFDate[] rng) {

dateRange = rng;

fixSize();

}

public Dimension getPreferredSize() { return prefSize; }

public void paintComponent(Graphics g) {

super.paintComponent(g);

//g.setColor(Color.white);

//g.drawLine(0,0,prefSize.width,prefSize.height);

int x=0, dx=0;

int ht = prefSize.height;

int wd = DayPane.prefSize.width;

int cnt = dateRange.length;

int offs = 2*charWid+3;

g.setFont(Main.font);

while(dx<cnt) {

g.setColor(Color.black);

MFDate dt = dateRange[dx];

g.drawString(dt.toStringMD(),

x+5,

charHgt+3);

g.drawString(dt.toStringW(),

x+offs,

ht-3);

g.drawLine(x,0,x,ht);

x += wd;

++dx;

}

g.drawLine(x,0,x,ht);

}

}

------DayPane

package meetFinder;

import javax.swing.*;import java.awt.*;import java.awt.event.*;

class DayPane extends JPanel {

DayPane(DaySchedule ds,Person p) {

day = ds;

person = p;

weekday = p.getDay(day.date.getWeekdayFor());

setBackground(Color.white);

addMouseListener();

}

/////////////////////

DaySchedule day;

DaySchedule weekday;

Person person;

/////////////////////

static boolean includeWeekly;// usually cached from Main

static protected int slotPerRow;

static int dayHeight, dayWidth;

static Dimension prefSize;

final static int MAXOCCUCOLOR =4;

static Color[] occuColor;

/////////////////////

static {

occuColor = new Color[MAXOCCUCOLOR+1];

for(int k=0;k<MAXOCCUCOLOR+1;++k) {

int v = 255 - 255*k/MAXOCCUCOLOR;

occuColor[k] = new Color(v,v,v);

}

}

static void setDaySize(int wid,int hgt,int nspr) {

// call AFTER DaySchedule.setDivision

slotPerRow = nspr;

dayHeight = hgt; dayWidth = wid;

prefSize = new Dimension(dayWidth,

dayHeight*DaySchedule.slotCount/slotPerRow);

}

static void setSlotPR(int nspr) {

slotPerRow = nspr;

prefSize = new Dimension(dayWidth,

dayHeight*DaySchedule.slotCount/slotPerRow);

TimeSider.fixSize();

}

void addMouseListener() {

addMouseListener(new MouseAdapter() {

public void mouseClicked(MouseEvent ev) {

java.awt.Point p = ev.getPoint();

int row = ev.getY()/dayHeight;

if(person.isComposite())

showVictims(p,row);

else toggleRow(row);

}});

}

void showVictims(java.awt.Point p,int row) {

Container tlanc = getTopLevelAncestor();

SwingUtilities.convertPointToScreen(p,this);

SwingUtilities.convertPointFromScreen(p,tlanc);

person.showMembers(day.date,row*slotPerRow,slotPerRow,

tlanc,p.x,p.y);

}

void toggleRow(int row) {

int usg = day.occupancy(row*slotPerRow,slotPerRow);

int tog = (usg==0)?1:0;

day.setOccupancy(row*slotPerRow,slotPerRow,tog);

repaint();

}

public Dimension getPreferredSize() { return prefSize; }

public void paintComponent(Graphics g) {

super.paintComponent(g);

//g.setColor(Color.red);

//g.drawLine(0,0,prefSize.width,prefSize.height);

g.setColor(Color.blue);

g.drawRect(0,0,prefSize.width,prefSize.height-1);

int x=0, y=0, slot=0;

while(slot<DaySchedule.slotCount) {

int usg = day.occupancy(slot,slotPerRow);

if(includeWeekly) {

int wku = weekday.occupancy(slot,slotPerRow);

if(wku>usg) usg=wku;

}

if(usg>0) {

if(usg>MAXOCCUCOLOR) usg=MAXOCCUCOLOR;

g.setColor(occuColor[usg]);

g.fillRect(1,y+1,dayWidth-1,dayHeight-1);

}

slot += slotPerRow;

y = y+dayHeight;

g.setColor(Color.blue);

g.drawLine(0,y,dayWidth,y);

}

}

}

------DaySchedule

package meetFinder;import java.io.*;

class DaySchedule {

DaySchedule(MFDate d) {

date = d;

used = new byte[slotCount];

}

DaySchedule(DaySchedule ds,MFDate d) {

date = d;

used = ds.used;

}

///////////////////////

MFDate date;

byte[] used;// in increments of

///////////////////////

static int dayBegins;// minutes since midnight

static int dayEnds;// same.

final static int slotInterval=15;// in minutes

static int slotCount;

static String[] hours = {

" 12:"," 1:"," 2:"," 3:"," 4:"," 5:",

" 6:"," 7:"," 8:"," 9:"," 10:"," 11:","p12:",

"p 1:","p 2:","p 3:","p 4:","p 5:","p 6:","p 7:","p 8:",

"p 9:","p10:","p11:" };

static char[] minWork = new char[2];

///////////////////////

static void setDivision(int hB,int mB,int hE,int mE) {

dayBegins = minutes(hB,mB);

dayEnds = minutes(hE,mE);

slotCount = (dayEnds-dayBegins+

slotInterval-1)/slotInterval;

}

static int minutes(int hr,int m) { return 60*hr+m; }

static String slotName(int k) {

int tm = dayBegins+k*slotInterval;

int m = tm%60;

return hours[tm/60]+(char)('0'+m/10)+(char)('0'+m%10);

}

static DaySchedule[] makeRange(MFDate[] rng) {

int nd = rng.length;

DaySchedule[] days = new DaySchedule[nd];

for(int k=0;k<nd;++k)

days[k] = new DaySchedule(rng[k]);

return days;

}

String dayName() {

return date.toStringMD();

}

void setUsed(String d) {

// Ignored parts of d too long.

// Fills missing parts of d as zeros.

int mx = d.length();

if(mx>slotCount) mx=slotCount;

else if(mx<slotCount) {

for(int k=mx;k<slotCount;++k) used[k] = 0;

}

for(int k=0;k<mx;++k)

used[k] = (byte)Character.digit(d.charAt(k),10);

}

void dump() {

System.err.println("DaySchedule for "+date);

for(int k=0;k<used.length;++k) System.err.print((used[k]==0)?"0":"1");

System.err.println(" ");

}

int occupancy(int slot,int cnt) {

// cnt many slots starting at slot

int res = 0;

for(int k=0;k<cnt;++k) {

int us = used[slot+k];

if(us>res) res = us;

}

return res;

}

void setOccupancy(int slot,int cnt,int occ) {

// cnt many slots starting at slot

for(int k=0;k<cnt;++k)

used[slot+k] = (byte)occ;

}

void clear() {

for(int k=0;k<slotCount;++k)

used[k] =0;

}

void add(DaySchedule ds) {

for(int k=0;k<slotCount;++k)

used[k] += ds.used[k];

}

void writeTo(BufferedWriter bwr) throws Exception {

boolean any=false;

for(int k=0;k<used.length;++k)

if(used[k]>0) { any=true; break; }

if(!any) return;

bwr.write("date="+date); bwr.newLine();

bwr.write("used=");

for(int k=0;k<used.length;++k)

bwr.write((used[k]==0)?'0':'1');

bwr.newLine();

}

static void writeConfigTo(BufferedWriter bwr) throws Exception {

bwr.write("begins="+dayBegins); bwr.newLine();

}

}

------EMFrame

package meetFinder;import javax.swing.*;import java.awt.*;

import java.awt.event.*;import java.util.*;import java.io.*;

public class EMFrame extends JFrame

{

public EMFrame(String ttl,File dfdr) {

super(ttl);

defaultDirectory = dfdr;

makeMenuBar();

mainPane = getContentPane();

addWindowListener(new WindowAdapter() {

public void windowClosing(WindowEvent ev) {

closing();

}});

}

///////////////////////////////////////

protected Container mainPane;

protected File defaultDirectory;

protected JMenu fileMenu;

///////////////////////////////////////

protected JMenu addMenu(String lbl) {

JMenu men = new JMenu(lbl);

getJMenuBar().add(men);

return men;

}

protected JMenuItem addMenuItem(

String name,Actor act,JComponent mom) {

JMenuItem mit = new JMenuItem(name);

mit.addActionListener(act);

mom.add(mit);

return mit;

}

protected JMenuItem addMenuItem(String name,char mne,boolean en,

Actor act,JComponent mom)

{

JMenuItem mit = addMenuItem(name,act,mom);

mit.setMnemonic(mne);

mit.setEnabled(en);

return mit;

}

protected void makeMenuBar() {

JMenuBar menuBar = new JMenuBar();

setJMenuBar(menuBar);

}

protected void makeFileMenu() {

fileMenu = addMenu("File"); fileMenu.setMnemonic('f');

}

public void showWarning(String ttl,String msg) {

JOptionPane.showMessageDialog(this,msg,ttl,

JOptionPane.WARNING_MESSAGE);

}

protected void closing() {

System.exit(0);

}

public void losing(JComponent vwr) {

}

public File getDefaultDirectory() { return defaultDirectory; }

public void setDefaultDirectory(File dd) { defaultDirectory=dd; }

public void makeViewable() {

show();

}

public void showMessage(String ttl,String msg) {

JOptionPane.showMessageDialog(this,msg,ttl,

JOptionPane.INFORMATION_MESSAGE);

}

}

------ExtensionFileFilter

package meetFinder;

import javax.swing.filechooser.*;import java.io.*;

public class ExtensionFileFilter

extends javax.swing.filechooser.FileFilter

{

String extension, description;

public ExtensionFileFilter(String exten,String descr) {

extension = exten;

description = descr;

}

public boolean accept(File f) {

boolean ok = f.isDirectory() ||

f.getName().toLowerCase().endsWith(extension);

//System.out.println("file "+f+"="+f.getName()+" is "+ok);

return ok;

}

public String getDescription() { return description+"%"; }

}

------Main

package meetFinder;import java.io.*;import javax.swing.*;

import java.awt.*;import java.awt.event.*;

public class Main extends EMFrame {

Main(File dfdr) {

super("Meeting Scheduler",dfdr);

makeFileMenu();

extendFileMenu();

makeMemberMenu();

setVisible(true);

font = new Font("courier",Font.PLAIN,12);

Graphics g = getGraphics();

System.err.println("g="+g);

fontMetrics = g.getFontMetrics(font);

System.err.println("fm="+fontMetrics);

charHgt = fontMetrics.getHeight();

setVisible(false);

DayPane.includeWeekly = includeWeekly;// Breaks RULE#1

dummyUp();

setVisible(true);

pack();

}

////////////////////////////////////

Committee committee;

MFDate[] dateRange;// also set into schedulePane

// and dayHeader

boolean includeWeekly = true;

////////////////////////////////////

ControlPane control;

SchedulePane schedulePane;

TimeSider timeSider;

DayHeader dayHeader;

JMenu memberMenu;

////////////////////////////////////

static Font font;

static FontMetrics fontMetrics;

static int charHgt;

////////////////////////////////////

void setGoodTitle() {

setTitle(committee.toString()+" Meet Finder");

}

void extendFileMenu() {

addMenuItem("open",new Actor() {

public void run() {

try {

committee = new Committee(Main.this);

committee.open();

control.remakeGroup();

setPerson(committee.allOfUs);

setGoodTitle();

} catch(Exception ex) {

showWarning(

"CAN’T open Committee: "

+committee.name,

ex.toString());

}

}},fileMenu);

addSaverItem("save",false);

addSaverItem("save as",true);

}

void addSaverItem(String lbl,final boolean as) {

addMenuItem(lbl,new Actor() {

public void run() {

try {

if(as) committee.saveas();

else committee.save();

committee.saveAll();

} catch(Exception ex) {

ex.printStackTrace();

showWarning(

"CANNOT save Committee: "

+committee.name,

ex.toString());

}

}},fileMenu);

}

void setPerson(Person p) {

schedulePane.setPerson(p);

control.setPerson(p);

}

void makeMemberMenu() {

memberMenu = addMenu("Member");

addMenuItem("add",new Actor() {

public void run() {

Person p = committee.addMember();

if(p==null) return;

//p.dump();

control.remakeGroup();

setPerson(p);

//System.err.print("AGAIN> "); p.dump();

}

},memberMenu);

addMenuItem("remove",new Actor() {

public void run() {

Person p = control.getPerson();

committee.removeMember(p);

control.remakeGroup();

}

},memberMenu);

addMemberSaver("save",false);

addMemberSaver("save as",true);

addMenuItem("Summary",new Actor() {

public void run() {

setPerson(committee.allOfUs);

}},memberMenu);

}

void addMemberSaver(String lbl,final boolean as) {

addMenuItem(lbl,new Actor() {

public void run() {

try {

Person p = control.getPerson();

if(p==null) return;

if(as) {

p.saveas(Main.this);

control.remakeGroup();

setPerson(p);

} else p.save();

} catch(Exception ex) {

ex.printStackTrace();

showWarning(

"CANNOT SAVE MEMBER",

ex.toString());

}

}},memberMenu);

}

void dummyUp() {

committee = new Committee("UN-NAMED",null,this);

setGoodTitle();

Person p = committee.addSummaryMember();

DaySchedule.setDivision(9,0,17,0);

DayPane.setDaySize(fontMetrics.stringWidth(

" May 31 "),20,4);

TimeSider.fixSize(fontMetrics);

dateRange = MFDate.makeRange(new MFDate(2003,1,7),1);

mainPane.setLayout(new BorderLayout());

schedulePane = new SchedulePane(p,dateRange);

JScrollPane scrp = new JScrollPane(schedulePane);

timeSider = new TimeSider();

scrp.setRowHeaderView(timeSider);

dayHeader = new DayHeader(dateRange,fontMetrics);

scrp.setColumnHeaderView(dayHeader);

mainPane.add(scrp,BorderLayout.CENTER);

control = new ControlPane(this);

mainPane.add(control,BorderLayout.NORTH);

}

Runnable newIncrSelector(String nm,int v) {

IncrSelector is = new IncrSelector();

is.name = nm; is.value = v;

return is;

}

class IncrSelector implements Runnable {

////////////////////////////////

String name; int value;

////////////////////////////////

public String toString() { return name; }

public void run() {

DayPane.setSlotPR(value);

schedulePane.fixSize();

setPerson(control.getPerson());

repaint();

}

}

void setRange(MFDate[] dtRng) {

dateRange = dtRng;

control.setSelectedDate(dtRng[0]);

schedulePane.setRange(dtRng);

dayHeader.setRange(dtRng);

dayHeader.fixSize();

pack();

repaint();

}

void setRange(MFDate dt,int nd) {

MFDate[] dtRng = MFDate.makeRange(dt,nd);

setRange(dtRng);

}

void writeDateRange(BufferedWriter bwr) throws Exception {

int nd = dateRange.length;

bwr.write("date count="+nd); bwr.newLine();

for(int k=0;k<nd;++k) {

bwr.write("date="+dateRange[k]); bwr.newLine();

}

}

static public void main(String[]args) {

//File dfdr = new File(

//System.getProperty("user.home"));

JFileChooser fch = new JFileChooser();// NEVER displayed

File dfdr = fch.getCurrentDirectory();

dfdr = new File(dfdr,"My-Committees");

System.err.println("dfdr="+dfdr);

dfdr.mkdirs();

new Main(dfdr);

}

}

------Pair

package meetFinder;import java.io.*;

class Pair {

Pair(Object k,Object v) {

key = k; value = v;

}

///////////////////////

public Object key,value;

///////////////////////

static Pair readFrom(BufferedReader brd) throws Exception {

String line = brd.readLine();

if(line==null) return null;

int edot = line.indexOf('=');

if(edot<0)

return new Pair(line,null);

return new Pair(

line.substring(0,edot),

line.substring(edot+1)

);

}

}

------Person

package meetFinder;import java.util.*;import java.io.*;

import java.awt.*;import javax.swing.*;

class Person extends Saveable {

Person(String nm) {

super(nm,null);

schedule = new Hashtable();

}

Person(File f) {