[triangle_recursion
strick**20120127074121
 Ignore-this: 443b915866117413a51bd404c817ee42
] hunk ./Expr.java 96
-			return f.globals().get(key);
+			Pro z = f.globals().get(key);
+			say("GetLocalVar: Getting <{0}> from {0}.", z, key);
+			return z;
hunk ./Expr.java 114
+			say("PutLocalVar: Putting <{0}> to {0}.", value, key);
hunk ./ExprTest.java 103
-				+ "   [ a gt: 0 ] run ye: [ g/  self tria: [ a mi: 1 ] run  ] . "
+				+ "   [ a gt: 0 ] run ye: [ g/  [ self tria: [ a mi: 1 ] run ] run pl: a  ] . "
hunk ./ExprTest.java 105
-		        + "   /Foo new tria: 4  ");
-		assertEquals(56.0, e.eval(f).asNum().num);
+		        + "   /Foo new tria: 6  ");
+		assertEquals(21.0, e.eval(f).asNum().num);
hunk ./Pro.java 108
+	int toNearestInt() {
+		Num num = this.asNum();
+		if (num == null) {
+			toss("Object is a {0}, not a Num", this.cls.name);
+		}
+		int i = (int) Math.floor(num.num + 0.5); // closest int
+		return i;
+	}
+
hunk ./Pro.java 520
+
+		abstract static class BinaryStrPredMeth extends JavMeth {
+			BinaryStrPredMeth(Cls cls) {
+				super(cls);
+			}
+			public Pro eval(Frame f, Pro r, Pro[] args) {
+				assert args.length == 1;
+				Str s = r.asStr();
+				Str a = args[0].asStr();
+				if (s == null) {
+					toss("Receiver of Str::pl not a Str");
+				}
+				if (a == null) {
+					toss("Argument of Str::pl not a Str");
+				}
+				return boolPro(f.terp(), compute(s.str, a.str));
+			}
+			abstract boolean compute(String sstr, String astr);
+		}
+		
+		static Hashtable<String, Meth> builtinStrMethods(Terp t) {
+			Hashtable<String, Meth> z = new Hashtable<String, Meth>();
+			z.put("ap:", new JavMeth(t.tJavMeth) {
+				public Pro eval(Frame f, Pro r, Pro[] args) {
+					assert args.length == 1;
+					Str s = r.asStr();
+					Str a = args[0].asStr();
+					if (s == null) {
+						toss("Receiver of Str::pl not a Str");
+					}
+					if (a == null) {
+						toss("Argument of Str::pl not a Str");
+					}
+					return new Str(f.terp(), s.str + a.str);
+				}
+			});
+			z.put("su:to:", new JavMeth(t.tJavMeth) {  // Substring
+				public Pro eval(Frame f, Pro r, Pro[] args) {
+					assert args.length == 2;
+					Str s = r.asStr();
+					assert (s != null);
+					int a = args[0].toNearestInt();
+					int b = args[1].toNearestInt();
+					return new Str(f.terp(), s.str.substring(a, b));
+				}
+			});
+			// TODO: move these up to Obj.
+			z.put("eq:", new BinaryStrPredMeth(t.tJavMeth) {
+				boolean compute(String sstr, String astr) {
+					return sstr.compareTo(astr) == 0;
+				}
+			});
+			z.put("ne:", new BinaryStrPredMeth(t.tJavMeth) {
+				boolean compute(String sstr, String astr) {
+					return sstr.compareTo(astr) != 0;
+				}
+			});
+			z.put("lt:", new BinaryStrPredMeth(t.tJavMeth) {
+				boolean compute(String sstr, String astr) {
+					return sstr.compareTo(astr) < 0;
+				}
+			});
+			z.put("le:", new BinaryStrPredMeth(t.tJavMeth) {
+				boolean compute(String sstr, String astr) {
+					return sstr.compareTo(astr) <= 0;
+				}
+			});
+			z.put("gt:", new BinaryStrPredMeth(t.tJavMeth) {
+				boolean compute(String sstr, String astr) {
+					return sstr.compareTo(astr) > 0;
+				}
+			});
+			z.put("ge:", new BinaryStrPredMeth(t.tJavMeth) {
+				boolean compute(String sstr, String astr) {
+					return sstr.compareTo(astr) >= 0;
+				}
+			});
+			return z;
+		}
hunk ./Pro.java 611
-		int convertIndex(Pro a) {
+		int toNearestIndex(Pro a) {
hunk ./Pro.java 632
-					return self.vec.get(self.convertIndex(args[0]));
+					return self.vec.get(self.toNearestIndex(args[0]));
hunk ./Pro.java 638
-					self.vec.set(self.convertIndex(args[0]), args[1]);
+					self.vec.set(self.toNearestIndex(args[0]), args[1]);
hunk ./Pro.java 646
-					int newSize = self.convertIndex(args[0]);
+					int newSize = self.toNearestIndex(args[0]);