PageRenderTime 29ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/code/Context.java

http://silkin.googlecode.com/
Java | 1408 lines | 1100 code | 54 blank | 254 comment | 365 complexity | 3b892b901b56e04fe51c564f72e84121 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. import java.util.*;
  2. import java.text.*;
  3. import java.io.*;
  4. import java.awt.*;
  5. import javax.swing.JOptionPane;
  6. /**
  7. Each instance of Context is a 'workspace' in which a particular culture's Kinship System
  8. is under construction or examination. Each contains its own population of
  9. {@link Family} and {@link Individual} objects, domain theories, etc.
  10. Class-level (static) fields act as global variables.
  11. @author Gary Morris, Northern Virginia Community College garymorris2245@verizon.net
  12. */
  13. public class Context implements Serializable {
  14. static Context current; // for Library Browser purposes only. User's current Context = Library.contextUnderConstruction
  15. static boolean simulation = false;
  16. static float spellingNoise, classNoise;
  17. // --- Debug tools ---
  18. static Individual watchInd;
  19. static int breakCount1 = 0;
  20. static int breakCount2 = 0;
  21. static boolean breakFlag = false;
  22. // --- Instance Variables ---
  23. /** Comments hold special comment from (or about) the author of the data about this culture. */
  24. public String comments = "",
  25. /** Date this context was initialized. */
  26. createDate;
  27. public String dateOfLastSuggestion, dateOfLastDataChange;
  28. ArrayList<String> dataAuthors = new ArrayList<String>();
  29. int indSerNumGen = 0, famSerNumGen = 0, maxBaseDefMisFits = 4;
  30. /** Name of the language spoken in this culture. It is limited administratively to 28 characters. */
  31. public String languageName;
  32. ArrayList<Object> selectedKinTerms;
  33. /** List of all persons in this culture, in serialNmbr order (beginning with 0). */
  34. public ArrayList<Individual> individualCensus = new ArrayList<Individual>();
  35. /** List of all families in this culture, in serialNmbr order (beginning with 0). */
  36. public ArrayList<Family> familyCensus = new ArrayList<Family>();
  37. ArrayList<Object> bagOfEgos = new ArrayList<Object>();
  38. private DomainTheory domTheoryRef, domTheoryAdr;
  39. /** Two-dimensional matrix of all kin terms known for pairs of persons. Row# = Ego's serialNmbr.
  40. Column = Alter's serialNmbr. Each cell contains null or a {@link Node} with the kinTerms
  41. <code>Row</code> (Ego) could use to refer to <code>Column</code> (Alter). */
  42. public KinTermMatrix ktm = new KinTermMatrix();
  43. /** Index of all {@link Node}str according to their kin type. Used to create
  44. * named-data-requests.*/
  45. public KinTypeIndex kti = new KinTypeIndex();
  46. Individual currentEgo;
  47. String editDirectory;
  48. /** True if polygamy is accepted in this culture (regardless of whether it has ever happened). */
  49. public boolean polygamyPermit, featuresHaveChanged = false; // flag -> true when definition added
  50. // These 2 parameters (plus maxNoiseP and ignorableP) control the Learning Algorithm
  51. public boolean doBaseCBs = false, doInduction = false;
  52. /** Optional extra fields, defined by user. Stored as a TreeMap of pairs:
  53. property-name (must begin with '*') -> UserDefinedProperty-object. */
  54. public TreeMap userDefinedProperties;
  55. /** The <code>saveState</code> boolean flag determines whether this instance of Context has its complete state
  56. saved to disk at shut-down. The context in which Data_Gathering is done (the 'target culture') MUST be
  57. saved between sessions. Other contexts can be saved by the User's explicit menu choice. */
  58. public boolean saveState = false, simDataGen = false;
  59. /** The learningHistory (Ref or Adr) is a TreeMap from kinTerm -> ArrayList<HistoryItem>.
  60. * Each history item records a User decision on a Suggestion. */
  61. public TreeMap<String, ArrayList<HistoryItem>> learningHistoryRef = new TreeMap<String, ArrayList<HistoryItem>>();
  62. public TreeMap<String, ArrayList<HistoryItem>> learningHistoryAdr;
  63. /** The autoDef (Ref or Adr) is a TreeMap from kinType -> ArrayList<kinTerm>.
  64. * This indexes by kin type each accepted definition that could apply to that kin type.
  65. * It is used to determine if we should attempt to pre-fill the kinTerm field for a new Alter. */
  66. public TreeMap<String, ArrayList<CB_Ptr>> autoDefRef = new TreeMap<String, ArrayList<CB_Ptr>>();
  67. public TreeMap<String, ArrayList<CB_Ptr>> autoDefAdr;
  68. /* The following fields were added to allow a Context to carry the parameters
  69. * needed by KAES back to the loadFile method. */
  70. public Point origin;
  71. public Dimension area;
  72. public int infoPerson, infoMarriage, labelChoice, ktLabelChoice, maxNoiseP = 25, ignorableP = 5;
  73. public boolean editable, distinctAdrTerms;
  74. /** This zero-arg constructor is for use by Serialization ONLY. */
  75. public Context() {
  76. createDate = UDate.today();
  77. Context.current = this;
  78. }
  79. // end of zero-arg constructor
  80. /**
  81. Constructor with only a {@link DomainTheory} as argument.
  82. @param dt a (possibly empty) domain theory for a Kinship System
  83. */
  84. public Context(DomainTheory dt) {
  85. createDate = UDate.today();
  86. Context.current = this;
  87. dt.ctxt = this;
  88. if (dt.addressTerms) {
  89. domTheoryAdr = dt;
  90. } else {
  91. domTheoryRef = dt;
  92. }
  93. languageName = dt.languageName;
  94. int end = languageName.indexOf("(");
  95. if (end > -1) {
  96. languageName = languageName.substring(0, end);
  97. }
  98. polygamyPermit = dt.polygamyOK;
  99. userDefinedProperties = dt.userDefinedProperties;
  100. Library.activeContexts.put(languageName, this);
  101. } // end of theory-only constructor
  102. /**
  103. Constructor with a {@link DomainTheory} and comments-string.
  104. @param dt a (possibly empty) domain theory for a Kinship System
  105. @param cmts string to begin the Comments field of this instance.
  106. */
  107. public Context(DomainTheory dt, String cmts) {
  108. createDate = UDate.today();
  109. Context.current = this;
  110. dt.ctxt = this;
  111. comments = cmts;
  112. if (dt.addressTerms) {
  113. domTheoryAdr = dt;
  114. } else {
  115. domTheoryRef = dt;
  116. }
  117. languageName = dt.languageName;
  118. int end = languageName.indexOf("(");
  119. if (end > -1) {
  120. languageName = languageName.substring(0, end);
  121. }
  122. polygamyPermit = dt.polygamyOK;
  123. userDefinedProperties = dt.userDefinedProperties;
  124. Library.activeContexts.put(languageName, this);
  125. } // end of 2-arg constructor
  126. public static void breakpoint() {
  127. return;
  128. } // end of breakpoint
  129. public static String convertDoubleQuotes(String s) {
  130. return FamilyPanel.convertBannedCharacters(s);
  131. } // end of method convertDoubleQuotes
  132. /** Add a Domain Theory to this context.
  133. @param theory new theory to be added, covering kinship terms of Reference or Address.
  134. @throws KSInternalErrorException if the new theory will over-write an existing one
  135. */
  136. public void addDomainTheory(DomainTheory theory) throws KSInternalErrorException {
  137. theory.ctxt = this;
  138. if (theory.addressTerms) {
  139. if (domTheoryAdr == null || domTheoryAdr.isEmpty()) {
  140. domTheoryAdr = theory;
  141. } else {
  142. String st = "Attempt to over-write existing Domain Theory (Address) "
  143. + "for language " + theory.languageName;
  144. throw new KSInternalErrorException(st);
  145. }
  146. } else {
  147. if (domTheoryRef == null || domTheoryRef.isEmpty()) {
  148. domTheoryRef = theory;
  149. } else {
  150. String st = "Attempt to over-write existing Domain Theory (Reference) "
  151. + "for language " + theory.languageName;
  152. throw new KSInternalErrorException(st);
  153. }
  154. }
  155. if (userDefinedProperties == null) {
  156. userDefinedProperties = theory.userDefinedProperties;
  157. } else if (theory.userDefinedProperties != null) {
  158. // Aha! Both theories have non-null TreeMaps of userDefinedProperties
  159. // We must merge them. IF THERE ARE CONFLICTS, the newly-added theory's version will overwrite.
  160. Iterator udpIter = theory.userDefinedProperties.entrySet().iterator();
  161. Map.Entry entry;
  162. while (udpIter.hasNext()) {
  163. entry = (Map.Entry) udpIter.next();
  164. userDefinedProperties.put(entry.getKey(), entry.getValue());
  165. } // end iteration over all entries in new theory's TMap
  166. } // end of 2 non-null TreeMaps of userDefinedProperties
  167. } // end of method addDomainTheory
  168. /** Returns the Domain Theory for Terms of Reference in this context. */
  169. public DomainTheory domTheoryRef() throws KSParsingErrorException, JavaSystemException, KSBadHornClauseException,
  170. KSInternalErrorException, KSConstraintInconsistency {
  171. if (domTheoryRef != null) {
  172. return domTheoryRef;
  173. }
  174. String fileName = Library.thyDirectory + languageName + ".thy";
  175. domTheoryRef = Library.readThyFile(fileName);
  176. return domTheoryRef;
  177. } // end of accessor method domTheoryRef
  178. /** Returns the Domain Theory for Terms of Address in this context. */
  179. public DomainTheory domTheoryAdr() throws KSParsingErrorException, JavaSystemException, KSBadHornClauseException,
  180. KSInternalErrorException, KSConstraintInconsistency {
  181. if (domTheoryAdr != null) {
  182. return domTheoryAdr;
  183. }
  184. String fileName = Library.thyDirectory + languageName + "(Adr).thy";
  185. domTheoryAdr = Library.readThyFile(fileName);
  186. return domTheoryAdr;
  187. } // end of accessor method domTheoryAdr
  188. public boolean hasIssues() {
  189. if (domTheoryRef != null && !domTheoryRef.issuesForUser.isEmpty()) {
  190. return true;
  191. }
  192. if (domTheoryAdr != null && !domTheoryAdr.issuesForUser.isEmpty()) {
  193. return true;
  194. }
  195. return false;
  196. }
  197. public boolean domTheoryAdrLoaded() {
  198. return domTheoryAdr != null;
  199. }
  200. public boolean domTheoryRefLoaded() {
  201. return domTheoryRef != null;
  202. }
  203. /** Returns true if a domain theory for Terms of Address exists. It may not be loaded into memory yet. */
  204. public boolean domTheoryAdrExists() {
  205. if (domTheoryAdr != null) {
  206. return true;
  207. }
  208. Library.ContextStub cStub = Library.retrieveOrCreateStub(languageName);
  209. return cStub.adrThyExists;
  210. }
  211. /** Returns true if a domain theory for Terms of Reference exists. It may not be loaded into memory yet. */
  212. public boolean domTheoryRefExists() {
  213. if (domTheoryRef != null) {
  214. return true;
  215. }
  216. Library.ContextStub cStub = Library.retrieveOrCreateStub(languageName);
  217. return cStub.refThyExists;
  218. }
  219. void domTheoryRefNullify() {
  220. domTheoryRef = null;
  221. }
  222. void domTheoryAdrNullify() {
  223. domTheoryAdr = null;
  224. }
  225. /** Remove this domain theory from this context.
  226. @param dt theory to be removed. */
  227. public void removeDomainTheory(DomainTheory dt) {
  228. // They should all be this simple.
  229. if (dt.addressTerms) {
  230. domTheoryAdr = null;
  231. } else {
  232. domTheoryRef = null;
  233. }
  234. dt.ctxt = null;
  235. } // end of method removeDomainTheory
  236. /**Delete all dyads associated with node from the dyadsDefined
  237. * and dyadsUndefined of the 2 DomainTheories for this context.
  238. *
  239. * @param node The source of any dyads.
  240. */
  241. void deleteDyads(Node node, int egoSerial) {
  242. if (node == null) {
  243. return;
  244. }
  245. int alterSerial = node.indiv.serialNmbr;
  246. String kinType = node.pcString;
  247. if (domTheoryRef != null) {
  248. for (Object o : node.kinTermsRef) {
  249. String kinTerm = (String) o;
  250. deleteDyad(domTheoryRef, kinTerm, kinType, egoSerial, alterSerial);
  251. }
  252. for (Object o : node.extKinTermsRef) {
  253. deleteDyad(domTheoryRef, (String) o, kinType, egoSerial, alterSerial);
  254. }
  255. }
  256. if (domTheoryAdr != null) {
  257. for (Object o : node.kinTermsAddr) {
  258. deleteDyad(domTheoryAdr, (String) o, kinType, egoSerial, alterSerial);
  259. }
  260. for (Object o : node.extKinTermsAddr) {
  261. deleteDyad(domTheoryAdr, (String) o, kinType, egoSerial, alterSerial);
  262. }
  263. }
  264. }
  265. void addDyad(DomainTheory dt, Dyad d) {
  266. DyadTMap tm;
  267. if (dt.theory.containsKey(d.kinTerm)) {
  268. tm = dt.dyadsDefined;
  269. } else {
  270. tm = dt.dyadsUndefined;
  271. }
  272. tm.dyAdd(d);
  273. }
  274. void confirmDyad(DomainTheory dt, Dyad dy1) {
  275. DyadTMap tm;
  276. if (dt.theory.containsKey(dy1.kinTerm)) {
  277. tm = dt.dyadsDefined;
  278. } else {
  279. tm = dt.dyadsUndefined;
  280. }
  281. ArrayList<Dyad> lst = tm.findDyadList(dy1);
  282. for (Dyad dy2 : lst) {
  283. if (dy1.equals(dy2)) {
  284. dy2.confirmed = true;
  285. dy2.challenged = false;
  286. break;
  287. }
  288. } // if we get here, did not find a match
  289. String msg = "Did not find match for dyad: " + dy1;
  290. MainPane.displayError(msg, "Internal Error", JOptionPane.ERROR_MESSAGE);
  291. }
  292. void deleteDyad(DomainTheory dt, String kinTerm, String kinType,
  293. int egoSerial, int alterSerial) {
  294. TreeMap kinTypeTree, dyadTMap = dt.dyadsDefined;
  295. if (dyadTMap.containsKey(kinTerm)) {
  296. kinTypeTree = (TreeMap) dyadTMap.get(kinTerm);
  297. } else {
  298. dyadTMap = dt.dyadsUndefined;
  299. kinTypeTree = (TreeMap) dyadTMap.get(kinTerm);
  300. }
  301. if (kinTypeTree != null && kinTypeTree.containsKey(kinType)) {
  302. ArrayList<Object> dyads = (ArrayList<Object>) kinTypeTree.get(kinType);
  303. Iterator dyIter = dyads.iterator();
  304. while (dyIter.hasNext()) {
  305. Dyad dy = (Dyad) dyIter.next();
  306. if (dy.ego.serialNmbr == egoSerial
  307. && dy.alter.serialNmbr == alterSerial) {
  308. dyIter.remove();
  309. break;
  310. }
  311. } // if we deleted a singleton, clean up.
  312. if (dyads.isEmpty()) {
  313. kinTypeTree.remove(kinType);
  314. }
  315. if (kinTypeTree.isEmpty()) {
  316. dyadTMap.remove(kinTerm);
  317. }
  318. }
  319. }
  320. public ArrayList<Object> getPair() throws KSInternalErrorException {
  321. // return 1 male and 1 female person from IndividualCensus
  322. ArrayList<Object> pair = new ArrayList<Object>();
  323. Individual first = individualCensus.get(0), second;
  324. String nextSex = (first.gender.equals("M") ? "F" : "M");
  325. pair.add(first);
  326. Iterator iter = individualCensus.iterator();
  327. while (iter.hasNext()) {
  328. second = (Individual) iter.next();
  329. if (second.gender.equals(nextSex)) {
  330. pair.add(second);
  331. return pair;
  332. } // end of BINGO
  333. } // end of loop thru individualCensus
  334. throw new KSInternalErrorException("Context.getPair couldn't find 1 male & 1 female.");
  335. // return pair;
  336. } // end of method getPair
  337. /**
  338. Add an individual (stored by serial number) to this context.
  339. @param indiv person to be added */
  340. public void addIndividual(Individual indiv) { // just for type-checking
  341. individualCensus.add(indiv.serialNmbr, indiv);
  342. } // end of method addIndividual
  343. /**
  344. Add a family (stored by serial number) to this context.
  345. @param fam family to be added */
  346. public void addFamily(Family fam) { // just for type-checking
  347. familyCensus.add(fam.serialNmbr, fam);
  348. } // end of method addFamily
  349. int litCounter() {
  350. int total = 0;
  351. if (domTheoryRef != null && domTheoryRef.theory != null) {
  352. Iterator iter = domTheoryRef.theory.values().iterator();
  353. while (iter.hasNext()) {
  354. KinTermDef ktd = (KinTermDef) iter.next();
  355. for (int i = 0; i < ktd.definitions.size(); i++) {
  356. ClauseBody cb = (ClauseBody) ktd.definitions.get(i);
  357. total += cb.body.size();
  358. } // end of loop thru definitions
  359. for (int i = 0; i < ktd.expandedDefs.size(); i++) {
  360. ClauseBody cb = (ClauseBody) ktd.expandedDefs.get(i);
  361. total += cb.body.size();
  362. } // end of loop thru expandedDefs
  363. } // end of loop thru theory
  364. } // end of loop thru domThRef
  365. if (domTheoryAdr != null && domTheoryAdr.theory != null) {
  366. Iterator iter = domTheoryAdr.theory.values().iterator();
  367. while (iter.hasNext()) {
  368. KinTermDef ktd = (KinTermDef) iter.next();
  369. for (int i = 0; i < ktd.definitions.size(); i++) {
  370. ClauseBody cb = (ClauseBody) ktd.definitions.get(i);
  371. total += cb.body.size();
  372. } // end of loop thru definitions
  373. for (int i = 0; i < ktd.expandedDefs.size(); i++) {
  374. ClauseBody cb = (ClauseBody) ktd.expandedDefs.get(i);
  375. total += cb.body.size();
  376. } // end of loop thru expandedDefs
  377. } // end of loop thru theory
  378. } // end of loop thru domTheoryAdr
  379. return total;
  380. } // end of method litCounter
  381. /**
  382. Build a string with a brief summary of this context.
  383. @return a string containing:
  384. <ul>
  385. <li> Lanuguage name
  386. <li> Field worker's comments (if any)
  387. <li> A count of the individuals and families in this context
  388. </ul>
  389. */
  390. public String toString() {
  391. String image = createDate + "\nContext for " + languageName + " language";
  392. if (comments == null || comments.length() == 0) {
  393. image += " is:\n";
  394. } else {
  395. image += " (" + comments + ") is:\n";
  396. }
  397. image += indSerNumGen + " individuals and " + famSerNumGen + " families registered.\n";
  398. return image;
  399. } // end of description method -- short (default)
  400. /**
  401. Build a string with a brief summary of this context.
  402. @param style a string containing 'theory' or 'census' or both terms
  403. @return a string containing:
  404. <ul>
  405. <li> Lanuguage name
  406. <li> Field worker's comments (if any)
  407. <li> A count of the individuals and families in this context
  408. <li> (if theory) all known definitions of kinTerms
  409. <li> (if census) List of each individual (short display)
  410. <li> (if census) List of each family (short display)
  411. </ul>
  412. */
  413. public String toString(String style) {
  414. String image = createDate + "\nContext for " + languageName + " language";
  415. if (comments == null || comments.length() == 0) {
  416. image += " is:\n";
  417. } else {
  418. image += " (" + comments + ") is:\n";
  419. }
  420. image += indSerNumGen + " individuals and " + famSerNumGen + " families registered.\n\n";
  421. if (style.indexOf("theory") >= 0) {
  422. if (domTheoryRef != null) {
  423. image += "Terms of Reference:\n";
  424. image += domTheoryRef.toString()
  425. + "\n==================================================\n\n";
  426. }
  427. if (domTheoryAdr != null) {
  428. image += "Terms of Address:\n";
  429. image += domTheoryAdr.toString()
  430. + "\n==================================================\n\n";
  431. }
  432. } // end of if-theory-is-requested
  433. if (style.indexOf("census") >= 0) {
  434. image += "Individuals:\n";
  435. for (int i = 0; i < individualCensus.size(); i++) {
  436. image += individualCensus.get(i);
  437. }
  438. image += "\nFamilies:\n";
  439. for (int j = 0; j < familyCensus.size(); j++) {
  440. image += familyCensus.get(j);
  441. }
  442. image += "-------End------\n";
  443. } // end of if-census-requested
  444. return image;
  445. } // end of description method -- long, with optional details
  446. /** Write out a domain theory to a file.
  447. @param file name of file to hold a complete theory.
  448. @param type if type = 'address' the Terms of Address are written. Else Terms of Reference.
  449. @throws an internal error if the chosen domain theory does not exist or can't be written. */
  450. public void printTheory(PrintWriter file, String type) throws KSInternalErrorException {
  451. if (type.equals("address")) {
  452. domTheoryAdr.toThyFile(file);
  453. } else {
  454. domTheoryRef.toThyFile(file);
  455. }
  456. } // end of method printTheory
  457. /** Write out a domain theory for Terms of Reference to a file.
  458. @param file name of file to hold a complete theory.
  459. @throws an internal error if the chosen domain theory does not exist or can't be written. */
  460. public void printTheory(PrintWriter file)
  461. throws KSInternalErrorException {
  462. domTheoryRef.toThyFile(file);
  463. } // end of method printTheory
  464. /** Write to a file a complete census of Families and Individuals for this context.
  465. @param file name of file to hold the census. */
  466. public void printCensus(PrintWriter file) {
  467. file.print(createDate + "\nContext for " + languageName + " language");
  468. if (comments == null || comments.length() == 0) {
  469. file.println(" is:");
  470. } else {
  471. file.println(" (" + comments + ") is:");
  472. }
  473. file.println(indSerNumGen + " individuals and " + famSerNumGen + " families registered.\n");
  474. file.println("Individuals:");
  475. for (int i = 0; i < individualCensus.size(); i++) {
  476. file.println(individualCensus.get(i));
  477. }
  478. file.println("\nFamilies:");
  479. for (int j = 0; j < familyCensus.size(); j++) {
  480. file.println(familyCensus.get(j));
  481. }
  482. file.println("\n-------End------\n");
  483. file.flush();
  484. file.close();
  485. } // end of method printCensus
  486. void diagnosticPrint(ClauseBody cb, TreeMap bindings) {
  487. System.out.println("\n\n##############################################################");
  488. System.out.println("Generating Examples for: " + cb);
  489. System.out.println("Bindings: ");
  490. Iterator bindIter = bindings.entrySet().iterator();
  491. Map.Entry boundPair;
  492. while (bindIter.hasNext()) {
  493. boundPair = (Map.Entry) bindIter.next();
  494. System.out.println(boundPair.getKey() + " bound to: I-"
  495. + ((Individual) boundPair.getValue()).serialNmbr);
  496. } // end of iteration thru bindings
  497. System.out.println("Individuals:\n");
  498. for (int i = 0; i < individualCensus.size(); i++) {
  499. System.out.println(individualCensus.get(i));
  500. }
  501. System.out.println("\nFamilies:\n");
  502. for (int j = 0; j < familyCensus.size(); j++) {
  503. System.out.println(familyCensus.get(j));
  504. }
  505. System.out.println("-------End------\n");
  506. } // end of diagnosticPrint()
  507. /**
  508. <p>Write output file in GEDCOM (v 5.5) format, containing all individuals and
  509. families in this context.
  510. </p>
  511. File will contain:
  512. <ul>
  513. <li> Header: Source program & version, </li>
  514. <li> Destination program & version, </li>
  515. <li> Date, Filename, GEDCOM version </li>
  516. <li> Individuals: 1 GEDCOM record each </li>
  517. <li> Families: 1 GEDCOM record each </li>
  518. <li> Trailer. </li>
  519. </ul>
  520. @param outFile a {@link PrintWriter} to write to.
  521. @param fileName direct filename; required extension is '.ged'
  522. */
  523. public void exportGEDCOM(PrintWriter outFile, String fileName, String choice) {
  524. // Write out the header, all individual and family records, & then trailer.
  525. outFile.println("0 HEAD");
  526. outFile.println("1 SOUR SILKin");
  527. outFile.println("2 VERS 1.0");
  528. outFile.println("2 NAME SIL Kinship Analysis Tools");
  529. outFile.println("1 DEST Reunion");
  530. String today = UDate.today();
  531. outFile.println("1 DATE " + today);
  532. outFile.println("1 FILE " + fileName);
  533. outFile.println("1 GEDC");
  534. outFile.println("2 VERS 5.5");
  535. outFile.println("2 FORM LINEAGE-LINKED");
  536. outFile.println("1 CHAR ASCII");
  537. Individual ind;
  538. Family fam;
  539. Iterator iter1 = individualCensus.iterator();
  540. while (iter1.hasNext()) {
  541. ind = (Individual) iter1.next();
  542. ind.exportGEDCOM(outFile, today, choice, DomainTheory.current.nonTerms);
  543. } // end of loop through Individuals
  544. Iterator iter2 = familyCensus.iterator();
  545. while (iter2.hasNext()) {
  546. fam = (Family) iter2.next();
  547. fam.exportGEDCOM(outFile, today);
  548. } // end of loop through Families
  549. outFile.println("0 TRLR");
  550. return;
  551. } // end of method exportGEDCOM
  552. private String editorParameters = "";
  553. public void writeSILKFile(File f, String params) throws FileNotFoundException,
  554. KSInternalErrorException, KSDateParseException {
  555. editorParameters = params;
  556. writeSILKFile(f);
  557. }
  558. /**
  559. Write output file in _.silk format, containing all parameters, dyads,
  560. individuals and families in this context. This is an XML-style file, with
  561. blocks defined as follows:
  562. <p>
  563. File will contain:
  564. <ul>
  565. <li> a <parameters> block. </li>
  566. <li> an <IndividualCensus> block containing zero or more <individual> blocks. </li>
  567. <li> a <FamilyCensus> block containing zero or more <family> blocks </li>
  568. <li> a <matrix> block containing zero or more <row> blocks (specified below).
  569. This block represents the contents of the KinTermMatrix. </li>
  570. <li> a <dyadsUndefinedRef> block containing zero or more <dyad> blocks
  571. for terms of reference. </li>
  572. <li> a <dyadsDefinedRef> block containing zero or more <dyad> blocks
  573. for terms of reference. </li>
  574. <li> (optionally) a <dyadsUndefinedAddr> block containing zero or more <dyad> blocks
  575. for terms of address. </li>
  576. <li> (optionally) a <dyadsDefinedAddr> block containing zero or more <dyad> blocks
  577. for terms of address. </li>
  578. </ul> </p>
  579. @param f a file to write to.
  580. */
  581. public void writeSILKFile(File f) throws FileNotFoundException, KSInternalErrorException,
  582. KSDateParseException {
  583. String directory = f.getParent(), path, lang;
  584. PrintWriter silk = null;
  585. try {
  586. silk = new PrintWriter(f, "UTF-8");
  587. } catch (Exception ex) {
  588. System.err.println("Encoding 'UTF-8' rejected.");
  589. System.exit(9);
  590. }
  591. silk.println("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
  592. silk.println("<?xml-stylesheet type=\"text/xsl\" href=\"Silk-status.xsl\"?>");
  593. silk.println("<!DOCTYPE SIL_KinData>");
  594. silk.println("<SIL_KinData>");
  595. writeSILKGuts(silk, directory);
  596. if (domTheoryRef != null && domTheoryRef.issuesForUser != null
  597. && !domTheoryRef.issuesForUser.isEmpty()) {
  598. DomainTheory.current = domTheoryRef;
  599. printSuggestions(silk, domTheoryRef, "Reference");
  600. }
  601. if (domTheoryAdr != null && domTheoryAdr.issuesForUser != null
  602. && !domTheoryAdr.issuesForUser.isEmpty()) {
  603. DomainTheory.current = domTheoryAdr;
  604. printSuggestions(silk, domTheoryAdr, "Address");
  605. }
  606. silk.println("</SIL_KinData>");
  607. silk.flush();
  608. silk.close();
  609. saveState = false;
  610. } // end of method writeSILKFile
  611. /** This method writes the entire saved state of the SIL_Edit session in XML-like format.
  612. * It is used by writeSILKFile for xxx.silk files, and by writeSuggsFile for xxx.sugg files.
  613. *
  614. * @param silk the file to be written
  615. * @param directory the directory containing 'silk', or null
  616. * @param sug true = writing a Suggestion file. false = a SILK file
  617. *
  618. * @throws FileNotFoundException if there's a file system error
  619. * @throws KSInternalErrorException if SILKin code crashes
  620. */
  621. void writeSILKGuts(PrintWriter silk, String directory)
  622. throws FileNotFoundException, KSInternalErrorException, KSDateParseException {
  623. String path, lang;
  624. silk.println("<parameters>");
  625. silk.println(" <language name=\"" + languageName + "\"/>");
  626. if (comments != null && comments.length() > 1) {
  627. silk.print(" <comments txt=\"");
  628. comments = convertDoubleQuotes(comments); // replace doubles with singles, etc.
  629. silk.print(comments);
  630. silk.println("\"/>");
  631. } // end of optional comments
  632. if (createDate != null) {
  633. if (!UDate.validXSD(createDate)) {
  634. createDate = UDate.convertToXSD(createDate);
  635. }
  636. silk.println(" <createDate value=\"" + createDate + "\"/>");
  637. } // end of optional createDate
  638. silk.println(" <dataAuthors>");
  639. for (String auth : dataAuthors) {
  640. silk.println("\t<dataAuthor name=\"" + auth + "\"/>");
  641. }
  642. silk.println(" </dataAuthors>"); // end of dataAuthors
  643. if (dateOfLastDataChange != null) {
  644. silk.println(" <lastDataChangeDate value=\"" + dateOfLastDataChange + "\"/>");
  645. }
  646. if (dateOfLastSuggestion != null) {
  647. silk.println(" <lastSuggestionDate value=\"" + dateOfLastSuggestion + "\"/>");
  648. }
  649. silk.println(" <indSerNum>" + indSerNumGen + "</indSerNum> ");
  650. silk.println(" <famSerNum>" + famSerNumGen + "</famSerNum> ");
  651. silk.println(" <polygamyPermit>" + polygamyPermit + "</polygamyPermit> ");
  652. if (userDefinedProperties != null) {
  653. silk.println("<userDefinedProperties>");
  654. Iterator iter = userDefinedProperties.entrySet().iterator();
  655. Map.Entry entry;
  656. while (iter.hasNext()) {
  657. silk.println("<UDP>");
  658. entry = (Map.Entry) iter.next();
  659. String propName = (String) entry.getKey();
  660. UserDefinedProperty udp = (UserDefinedProperty) entry.getValue();
  661. silk.println("<propertyName>" + propName + "</propertyName>");
  662. silk.println(udp.toSILKString("full"));
  663. silk.println("</UDP>");
  664. } // end of loop thru UDPs
  665. silk.println("</userDefinedProperties>");
  666. } // end of optional UDPs
  667. silk.println("</parameters>");
  668. silk.println("<editorSettings>");
  669. if (currentEgo != null) {
  670. silk.println(" <currentEgo n=\"" + currentEgo.serialNmbr + "\"/>");
  671. }
  672. if (editDirectory != null) {
  673. silk.println(" <editDirectory dir=\"" + editDirectory + "\"/>");
  674. }
  675. silk.println(editorParameters);
  676. if (kti.lastSerial != -1) {
  677. silk.println(" <lastPersonIndexed>" + kti.lastSerial + "</lastPersonIndexed>");
  678. }
  679. silk.println("</editorSettings>\n");
  680. if (domTheoryRef != null) {
  681. silk.println(domTheoryRef.toSILKString(""));
  682. }
  683. if (domTheoryAdr != null) {
  684. silk.println(domTheoryAdr.toSILKString(""));
  685. }
  686. silk.println("<individualCensus>");
  687. for (int i = 0; i < individualCensus.size(); i++) {
  688. Individual ind = individualCensus.get(i);
  689. silk.println(ind.toSILKString());
  690. }
  691. silk.println("</individualCensus>");
  692. silk.println("<familyCensus>");
  693. for (int i = 0; i < familyCensus.size(); i++) {
  694. Family fam = familyCensus.get(i);
  695. silk.println(fam.toSILKString());
  696. }
  697. silk.println("</familyCensus>");
  698. silk.println("<matrix>");
  699. if (ktm.matrix.size() > 0) {
  700. silk.println(ktm.toSILKString());
  701. }
  702. silk.println("</matrix>");
  703. silk.println("<dyadsUndefinedRef>");
  704. if (domTheoryRef != null && domTheoryRef.dyadsUndefined != null) {
  705. silk.print(domTheoryRef.dyadsUndefined.toSILKString());
  706. }
  707. silk.println("</dyadsUndefinedRef>");
  708. silk.println("<dyadsDefinedRef>");
  709. if (domTheoryRef != null && domTheoryRef.dyadsDefined != null) {
  710. silk.print(domTheoryRef.dyadsDefined.toSILKString());
  711. }
  712. silk.println("</dyadsDefinedRef>");
  713. if (domTheoryAdr != null && domTheoryAdr.dyadsUndefined != null) {
  714. silk.println("<dyadsUndefinedAddr>");
  715. silk.print(domTheoryAdr.dyadsUndefined.toSILKString());
  716. silk.println("</dyadsUndefinedAddr>");
  717. }
  718. if (domTheoryAdr != null && domTheoryAdr.dyadsDefined != null) {
  719. silk.println("<dyadsDefinedAddr>");
  720. silk.print(domTheoryAdr.dyadsDefined.toSILKString());
  721. silk.println("</dyadsDefinedAddr>");
  722. }
  723. if (!kti.isEmpty() && directory != null) {
  724. silk.println("\n<kinTypeIndex>");
  725. silk.println(kti.toSILKString());
  726. silk.println("</kinTypeIndex>");
  727. }
  728. if (!learningHistoryRef.isEmpty()) {
  729. silk.println("\n<learning-history type=\"Ref\">");
  730. Iterator iter = learningHistoryRef.entrySet().iterator();
  731. while (iter.hasNext()) {
  732. Map.Entry<String, ArrayList<HistoryItem>> entry =
  733. (Map.Entry<String, ArrayList<HistoryItem>>) iter.next();
  734. String kinTerm = entry.getKey();
  735. ArrayList<HistoryItem> list = entry.getValue();
  736. silk.println("\t<history kinTerm=\"" + kinTerm + "\">");
  737. for (HistoryItem hi : list) {
  738. silk.println("\t" + hi.toSILKString());
  739. }
  740. silk.println("\t</history>");
  741. }
  742. silk.println("</learning-history>\n");
  743. }
  744. if (learningHistoryAdr != null && !learningHistoryAdr.isEmpty()) {
  745. silk.println("\n<learning-history type=\"Adr\">");
  746. Iterator iter = learningHistoryAdr.entrySet().iterator();
  747. while (iter.hasNext()) {
  748. Map.Entry<String, ArrayList<HistoryItem>> entry =
  749. (Map.Entry<String, ArrayList<HistoryItem>>) iter.next();
  750. String kinTerm = entry.getKey();
  751. ArrayList<HistoryItem> list = entry.getValue();
  752. silk.println("\t<history kinTerm=\"" + kinTerm + "\">");
  753. for (HistoryItem hi : list) {
  754. silk.println("\t" + hi.toSILKString());
  755. }
  756. silk.println("\t</history>");
  757. }
  758. silk.println("</learning-history>\n");
  759. }
  760. if (!autoDefRef.isEmpty()) {
  761. printAutoDefs(silk, "Ref");
  762. }
  763. if (autoDefAdr != null && !autoDefAdr.isEmpty()) {
  764. printAutoDefs(silk, "Adr");
  765. }
  766. }
  767. void printAutoDefs(PrintWriter pw, String typ) {
  768. TreeMap<String, ArrayList<CB_Ptr>> autos =
  769. (typ.equals("Ref") ? autoDefRef : autoDefAdr);
  770. pw.println("<auto-def type=\"" + typ + "\">");
  771. Iterator typeIter = autos.entrySet().iterator();
  772. while (typeIter.hasNext()) {
  773. Map.Entry<String, ArrayList<CB_Ptr>> entry =
  774. (Map.Entry<String, ArrayList<CB_Ptr>>) typeIter.next();
  775. String kinType = entry.getKey();
  776. ArrayList<CB_Ptr> lst = entry.getValue();
  777. pw.println("\t<kinType type=\"" + kinType + "\">");
  778. for (CB_Ptr ptr : lst) {
  779. pw.println(ptr.toSILKString("\t\t"));
  780. }
  781. pw.println("\t</kinType>");
  782. }
  783. pw.println("</auto-def>\n");
  784. }
  785. public void printSuggestions(PrintWriter pw, DomainTheory dt, String typ) {
  786. TreeMap<String, ArrayList<Issue>> suggs = dt.issuesForUser;
  787. pw.println("<silkin-issues type=\"" + typ + "\">");
  788. Iterator suggIter = suggs.values().iterator();
  789. while (suggIter.hasNext()) {
  790. ArrayList<Issue> issues = (ArrayList<Issue>) suggIter.next();
  791. for (Issue issue : issues) {
  792. issue.toSILKFile(pw);
  793. }
  794. }
  795. pw.println("</silkin-issues>");
  796. }
  797. /** Update certain elements of this context from a newer one.
  798. @param newCtxt contains new or updated information. */
  799. public void updateFrom(Context newCtxt) throws KSParsingErrorException,
  800. JavaSystemException, KSBadHornClauseException,
  801. KSInternalErrorException, KSConstraintInconsistency {
  802. if (individualCensus.size() != newCtxt.individualCensus.size()
  803. || familyCensus.size() != newCtxt.familyCensus.size()) {
  804. throw new KSInternalErrorException("Number of individuals in XML file"
  805. + "\n does not match number in SILK file.");
  806. }
  807. for (int i = 0; i < individualCensus.size(); i++) {
  808. Individual newRec = newCtxt.individualCensus.get(i),
  809. oldRec = individualCensus.get(i);
  810. oldRec.updateFrom(newRec);
  811. } // end of loop through individuals
  812. for (int i = 0; i < familyCensus.size(); i++) {
  813. Family newRec = newCtxt.familyCensus.get(i),
  814. oldRec = familyCensus.get(i);
  815. oldRec.updateFrom(newRec);
  816. } // end of loop through families
  817. createDate = newCtxt.createDate;
  818. comments += newCtxt.comments;
  819. languageName = newCtxt.languageName;
  820. domTheoryRef = (domTheoryRefExists() ? newCtxt.domTheoryRef() : null);
  821. domTheoryAdr = (domTheoryAdrExists() ? newCtxt.domTheoryAdr() : null);
  822. ktm = newCtxt.ktm;
  823. Iterator egoIter = ktm.matrix.values().iterator();
  824. while (egoIter.hasNext()) {
  825. Iterator alterIter = ((TreeMap) egoIter.next()).values().iterator();
  826. while (alterIter.hasNext()) {
  827. TempNode tNode = (TempNode) alterIter.next();
  828. tNode.indiv = individualCensus.get(tNode.indNmbr);
  829. } // end of loop through cells
  830. } // end of loop thru rows
  831. editDirectory = newCtxt.editDirectory;
  832. polygamyPermit = newCtxt.polygamyPermit;
  833. currentEgo = newCtxt.currentEgo;
  834. userDefinedProperties =
  835. (newCtxt.userDefinedProperties != null ? newCtxt.userDefinedProperties : null);
  836. } // end of method updateFrom
  837. /** Designate a new Ego (interview subject).
  838. @param ego the new person whose data is being gathered (being interviewed). */
  839. public void changeEgoTo(Individual ego) {
  840. // First, store all data for currentEgo
  841. if (currentEgo != null) {
  842. ktm.updateRow(currentEgo, individualCensus);
  843. }
  844. // Now prep for the new currentEgo
  845. currentEgo = ego;
  846. if (ego == null) {
  847. return; // for final storage of KTM before shutdown
  848. }
  849. TreeMap egoRow = ktm.getRow(ego);
  850. for (int i = 0; i < individualCensus.size(); i++) {
  851. Individual person = individualCensus.get(i);
  852. person.dyad = null;
  853. person.node = new Node();
  854. if (egoRow != null && person != ego) {
  855. Node nod = (Node) egoRow.get(new Integer(person.serialNmbr));
  856. if (nod != null) {
  857. person.node = nod;
  858. }
  859. }
  860. } // end of loop thru all people
  861. } // end of method changeEgoTo
  862. /**
  863. Restore this context to a prior state, ELIMINATING all persons and families
  864. created with serial numbers greater-or-equal-to these. USE WITH CAUTION. After this purging,
  865. the census populations will contain 'nmbrIndivs' individuals and 'nmbrFams' families.
  866. @param nmbrIndivs lowest individual serial number to be removed.
  867. @param nmbrFams lowest family serial number to be removed.
  868. @throws KSInternalErrorException if the population counts do not add up
  869. to the proper figures after purging.
  870. */
  871. public void resetTo(int nmbrIndivs, int nmbrFams) throws KSInternalErrorException {
  872. if (nmbrIndivs == 0 && nmbrFams == 0) { // Erase all and start over.
  873. individualCensus = new ArrayList<Individual>();
  874. familyCensus = new ArrayList<Family>();
  875. currentEgo = null;
  876. indSerNumGen = 0;
  877. famSerNumGen = 0;
  878. return;
  879. }
  880. Individual currInd;
  881. Family fam, currFam;
  882. for (int i = individualCensus.size() - 1; i >= nmbrIndivs; i--) {
  883. // work from end of list back to reset point.
  884. currInd = individualCensus.get(i);
  885. indSerNumGen--;
  886. for (int j = 0; j < currInd.marriages.size(); j++) {
  887. fam = (Family) currInd.marriages.get(j);
  888. if (fam.husband == currInd) {
  889. fam.husband = null;
  890. } else if (fam.wife == currInd) {
  891. fam.wife = null;
  892. } else {
  893. String msg = "Indiv lists marriage but is neither H nor W.\n";
  894. msg += currInd + "\n";
  895. msg += fam;
  896. throw new KSInternalErrorException(msg);
  897. } // end of error
  898. } // end of for-each-marriage-she-is-in
  899. if (currInd.birthFamily != null) {
  900. fam = currInd.birthFamily;
  901. int k = fam.children.lastIndexOf(currInd);
  902. if ((k < 0) || (fam.nmbrOfKids <= 0)) {
  903. String msg2 = "Indiv lists birthFamily but is not a child in it.";
  904. msg2 += currInd + "\n";
  905. msg2 += fam;
  906. throw new KSInternalErrorException(msg2);
  907. } // end of error
  908. fam.children.remove(k);
  909. fam.nmbrOfKids--;
  910. } // end of remove-from-birthFamily
  911. individualCensus.remove(i);
  912. } // end of Individual purge
  913. // It is possible that families created after the reset point could have one or both
  914. // parents from prior to the reset point, and even kids created pre-reset. Ergo, we can't
  915. // do any error-checking before purging this family.
  916. for (int i = familyCensus.size() - 1; i >= nmbrFams; i--) {
  917. currFam = familyCensus.get(i);
  918. famSerNumGen--;
  919. if (currFam.husband != null) {
  920. int k = currFam.husband.marriages.lastIndexOf(currFam);
  921. currFam.husband.marriages.remove(k);
  922. } // end of husband processing
  923. if (currFam.wife != null) {
  924. int k = currFam.wife.marriages.lastIndexOf(currFam);
  925. currFam.wife.marriages.remove(k);
  926. } // end of husband processing
  927. for (int j = 0; j < currFam.nmbrOfKids; j++) {
  928. currInd = (Individual) currFam.children.get(j);
  929. currInd.birthFamily = null;
  930. } // end of kid processing
  931. familyCensus.remove(i);
  932. } // end of Family purge
  933. if ((familyCensus.size() != nmbrFams) || (individualCensus.size() != nmbrIndivs)) {
  934. throw new KSInternalErrorException("Population counts after reset-purge don't balance.");
  935. }
  936. return;
  937. } // end of method resetTo
  938. public void cleanNodeFields() {
  939. Individual ind;
  940. for (int i = 0; i < indSerNumGen; i++) {
  941. (individualCensus.get(i)).node = null;
  942. }
  943. } // end of method cleanNodeFields
  944. /** Searches through all persons on this context, seeking one with the target value
  945. that meets all the constraints. SEMANTIC NOTE: If the target value is a list of objects,
  946. this method considers another list to 'match' if it has the same elements IN ANY ORDER.
  947. @param arg an Argument (MathVariable or Constant) with a target value we want to match.
  948. @param starName the name of a UserDefinedPredicate that must hold the target value; must begin with '*'
  949. @param personVar the variable for the person we seek
  950. @param constraints holds all known constraints for varName
  951. @param badBindings a TreeMap (perhaps empty) of keys = argNames and Values = ALists of Individuals who shouldn't be chosen
  952. @param starBindings a list of {@link StarPropertyBinding}str
  953. @param bindings all the bindings of variables thus far
  954. @return an Individual conforming to this set of requirements, or null if none is found.
  955. */
  956. public Individual findConformingPerson(Argument arg, String starName, Variable personVar, ConstraintObj constraints,
  957. TreeMap badBindings, ArrayList<Object> starBindings, TreeMap bindings)
  958. throws KSConstraintInconsistency, KSInternalErrorException, ClassNotFoundException {
  959. if (arg.getVal().isEmpty()) {
  960. return null; // There's no target value, so we must punt.
  961. }
  962. boolean singleVal = true, bbOK;
  963. if (arg.getVal().size() > 1) {
  964. singleVal = false;
  965. }
  966. Object theVal = null;
  967. if (singleVal) {
  968. theVal = arg.getVal().get(0);
  969. }
  970. Iterator indIter = individualCensus.iterator();
  971. Individual ind;
  972. ArrayList<Object> badList = (ArrayList<Object>) badBindings.get(personVar.argName);
  973. UserDefinedProperty udp = (UserDefinedProperty) userDefinedProperties.get(starName); // using the Context's master copy to verify
  974. if ((!singleVal) && udp.singleValue) {
  975. throw new KSInternalErrorException("Multi-valued arg '" + arg.argName + "' linked to single-valued UDP "
  976. + starName + " for " + personVar.argName);
  977. }
  978. while (indIter.hasNext()) {
  979. ind = (Individual) indIter.next();
  980. if (badList != null && badList.contains(ind)) {
  981. bbOK = false;
  982. } else {
  983. bbOK = true;
  984. }
  985. udp = (UserDefinedProperty) ind.userDefinedProperties.get(starName);
  986. if (singleVal) { // single-valued arg
  987. if (udp.value.contains(theVal) && (udp.value.size() == 1) && bbOK
  988. && ind.meetsConstraintsStrictly(personVar, constraints, bindings, starBindings)) {
  989. return ind;
  990. }
  991. } // end of processing for single-valued arg
  992. else { // multi-valued arg
  993. boolean equality = true;
  994. if (udp.value.size() != arg.getVal().size()) {
  995. equality = false;
  996. }
  997. if (equality) {
  998. for (int i = 0; i < udp.value.size(); i++) {
  999. if (!arg.getVal().contains(udp.value.get(i))) {
  1000. equality = false;
  1001. }
  1002. }
  1003. }
  1004. if (equality && bbOK
  1005. && ind.meetsConstraintsStrictly(personVar, constraints, bindings, starBindings)) {
  1006. return ind;
  1007. }
  1008. } // end of processing for multi-valued arg
  1009. } // end of loop thru all persons
  1010. return null;
  1011. } // end of method findConformingPerson
  1012. /** Searches through all persons on this context, seeking one with the target value
  1013. that meets all the constraints.
  1014. @param targetVal the person (target value) we want to match.
  1015. @param starName the name of a UserDefinedPredicate that must hold the target value; must begin with '*'
  1016. @param personVar the variable for the person we seek
  1017. @param constraints holds all known constraints for varName
  1018. @param badBindings a TreeMap (perhaps empty) of keys = argNames and Values = ALists of Individuals who shouldn't be chosen
  1019. @param starBindings a list of {@link StarPropertyBinding}str
  1020. @param bindings all the bindings of variables thus far
  1021. @return an Individual conforming to this set of requirements, or null if none is found.
  1022. */
  1023. public Individual findConformingPerson(Individual targetVal, String starName, Variable personVar,
  1024. ConstraintObj constraints, TreeMap badBindings, ArrayList<Object> starBindings, TreeMap bindings)
  1025. throws KSConstraintInconsistency, KSInternalErrorException, ClassNotFoundException {
  1026. Iterator indIter = individualCensus.iterator();
  1027. Individual ind;
  1028. boolean bbOK;
  1029. UserDefinedProperty udp;
  1030. while (indIter.hasNext()) {
  1031. ind = (Individual) indIter.next();
  1032. ArrayList<Object> badList = (ArrayList<Object>) badBindings.get(personVar.argName);
  1033. bbOK = true;
  1034. if (badList != null && badList.contains(ind)) {
  1035. bbOK = false;
  1036. }
  1037. udp = (UserDefinedProperty) ind.userDefinedProperties.get(starName);
  1038. if (udp.value.contains(targetVal) && (udp.value.size() == 1) && bbOK
  1039. && ind.meetsConstraintsStrictly(personVar, constraints, bindings, starBindings)) {
  1040. return ind;
  1041. }
  1042. } // end of loop thru all persons
  1043. return null;
  1044. } // end of method findConformingPerson
  1045. /** Start from ego and create a {@link Dyad} for each named relationship encountered on a breadth-first
  1046. walk of ego's family tree. We do the walk in 2 passes: the first pass uses ONLY biological links (i.e.
  1047. spousal links and birth links). The second pass adds any Star-Links (based on UDPs) which add new relatives
  1048. of Ego. This 2-pass method is required because kinship defined in terms …

Large files files are truncated, but you can click here to view the full file