$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
From: lists.drrngrvy_at_[hidden]
Date: 2008-03-12 13:06:01
Author: drrngrvy
Date: 2008-03-12 13:06:00 EDT (Wed, 12 Mar 2008)
New Revision: 43578
URL: http://svn.boost.org/trac/boost/changeset/43578
Log:
Adding amortization calculator example, which uses Google cTemplate to handle HTML output.
Added:
   sandbox/SOC/2007/cgi/branches/acceptor_work/libs/cgi/example/acgi/amortization/
   sandbox/SOC/2007/cgi/branches/acceptor_work/libs/cgi/example/acgi/amortization/Jamfile.v2   (contents, props changed)
   sandbox/SOC/2007/cgi/branches/acceptor_work/libs/cgi/example/acgi/amortization/acgi_amort.css   (contents, props changed)
   sandbox/SOC/2007/cgi/branches/acceptor_work/libs/cgi/example/acgi/amortization/acgi_amort.js   (contents, props changed)
   sandbox/SOC/2007/cgi/branches/acceptor_work/libs/cgi/example/acgi/amortization/acgi_amort.tpl   (contents, props changed)
   sandbox/SOC/2007/cgi/branches/acceptor_work/libs/cgi/example/acgi/amortization/main.cpp   (contents, props changed)
Added: sandbox/SOC/2007/cgi/branches/acceptor_work/libs/cgi/example/acgi/amortization/Jamfile.v2
==============================================================================
--- (empty file)
+++ sandbox/SOC/2007/cgi/branches/acceptor_work/libs/cgi/example/acgi/amortization/Jamfile.v2	2008-03-12 13:06:00 EDT (Wed, 12 Mar 2008)
@@ -0,0 +1,36 @@
+#             Copyright (c) 2007 Darren Garvey
+#
+# Distributed under the Boost Software License, Version 1.0.
+#     (See accompanying file LICENSE_1_0.txt or copy 
+#        at http://www.boost.org/LICENSE_1_0.txt)
+
+exe acgi_amort
+  :
+    main.cpp
+    /boost/thread/
+    /boost/regex/
+  :
+  :
+    <linkflags>-lctemplate
+  ;
+
+# Our install rule (builds binaries and copies them to <location>)
+install install
+ : acgi_amort
+   acgi_amort.tpl
+ :
+ :
+   <location>$(cgi-bin)
+ ;
+
+install install_extra
+ :
+   acgi_amort.css
+   acgi_amort.js
+ :
+ :
+   <location>$(htdocs)
+ ;
+
+# Only install example if you use `bjam install' or equivalent
+explicit install ;
Added: sandbox/SOC/2007/cgi/branches/acceptor_work/libs/cgi/example/acgi/amortization/acgi_amort.css
==============================================================================
--- (empty file)
+++ sandbox/SOC/2007/cgi/branches/acceptor_work/libs/cgi/example/acgi/amortization/acgi_amort.css	2008-03-12 13:06:00 EDT (Wed, 12 Mar 2008)
@@ -0,0 +1,94 @@
+body,  table, input, select, textarea, .text {
+	font-family: Arial, Helvetica, sans-serif;	
+	font-size: 12px;	
+	color: #333333; 		
+}
+body {
+	background-color: #CCCCCC;
+}
+h1 {
+	font-family: Georgia, Times New Roman; 						
+	font-weight: bold; 						
+	font-size: 20px; 						
+	font-style: normal;
+	color: #4274B7; 								
+	border-bottom-color: #B1AFA2; 					
+}
+hr {
+	color: #B1AFA2;								
+}
+.ssl {
+	border: 1px solid #B1AFA2;					
+}
+a{
+	color: #315688;							
+}
+.color1 {
+	background-color: #BFA280;
+}
+.color2 {
+	background-color: #BFA280;
+}
+.nav {
+	background-color: #89A8E0;
+}
+.top_nav {
+	background-color: #4274B7;
+}
+.right_nav {
+	background-color: #FFFFFF;
+}
+.main_cell {
+	background-color: #FFFFFF;			
+}
+.td1 {
+	background-color: #F0EAE1;
+    padding: 0cm .1cm; 
+	font-weight: normal; 
+	color: #000000;
+}
+.td2 {
+	background-color: #FFFFFF;
+    padding: 0cm .1cm; 
+	font-weight: normal; 
+	color: #000000;
+}
+.row1 {
+	background-color: #F0EAE1;
+    padding: 0cm .1cm; 
+	font-weight: normal; 
+	color: #000000;
+    text-align: right
+}
+.row2 {
+	background-color: #FFFFFF;
+    padding: 0cm .1cm; 
+	font-weight: normal; 
+	color: #000000;
+    text-align: right
+}
+.tblbase {
+	background-color: #B1AFA2; 
+}
+.tblhead {
+	font-weight: bold;
+	color: #FFFFFF;
+	background-color: #315688;
+}
+
+.header a {
+	background-color: #315688;
+	color: #FFFFFF;
+}
+.header a:hover {
+	background-color: #4274B7;
+	color: #FFFFFF;
+}
+.button a {
+	background-color: #BFA280;
+	color: #FFFFFF;
+}
+.button a:hover {
+	background-color: #666666;
+	color: #FFFFFF;
+}
Added: sandbox/SOC/2007/cgi/branches/acceptor_work/libs/cgi/example/acgi/amortization/acgi_amort.js
==============================================================================
--- (empty file)
+++ sandbox/SOC/2007/cgi/branches/acceptor_work/libs/cgi/example/acgi/amortization/acgi_amort.js	2008-03-12 13:06:00 EDT (Wed, 12 Mar 2008)
@@ -0,0 +1,234 @@
+function printable()
+{
+	document.temps.submit();
+	
+}
+
+function clearForm(form) {
+  form.income.value = "";
+  form.auto.value = "";  
+  form.rate.value="";
+  form.payment.value = "";
+  form.amount.value = "";
+}
+
+function housingRatio(income, insurance) {	
+	housing = eval(income * .28)
+  return housing;
+}
+
+function debtRatio(income, auto) {	
+	debt = eval(income * .36) - auto;
+  return debt;
+}
+
+function checkForm(toCheck) {	
+  isNum = true;
+  for (j = 0; j < toCheck.length; j++) {
+    if (((((toCheck.substring(j,j+1) < "0") || (toCheck.substring(j,j+1) > "9")) && (toCheck.substring(j,j+1) != ",")) 
+		|| (toCheck.substring(j,j+1) > "9")) && (toCheck.substring(j,j+1) != ".")){
+      isNum = false;
+      }
+    }
+  if ((isNum == false) || (toCheck.length == 0) || (toCheck == null)) {
+  alert("Please enter only numerical data in all fields.");
+  return false;
+  }
+  else {
+  return true;
+  }
+}     
+function computeForm(form) {
+	basicedit();
+
+	income = replaceChars(form.income.value);
+	income = replaceChar(income);
+	if (income <= "0"){ 
+		alert("You need to be employed to finance a house!")
+		form.payment.value = "0";
+		form.payment2.value = "0";
+		form.amount.value = "0";
+		form.amount2.value = "0";
+		return false;}	
+	auto = replaceChars(form.auto.value);
+	auto = replaceChar(auto);
+	var a = form.rate.value;
+	var a = replacePct(a);
+
+	if (a > 20 )	
+	{	
+		alert ("Interest Rate must not be greater than " + 20 + " percent");			
+		form.rate.value=addPct('20');		
+		a = form.rate.value;
+		a = replacePct(a);	
+	}
+	else
+	if (a < 1 )	
+	{	
+		alert ("Interest Rate must be greater than " + 1 + " percent");			
+		form.rate.value=addPct('1');		
+		a = form.rate.value;
+		a = replacePct(a);	
+	}			
+	
+if (checkForm(income) && checkForm(auto) && checkForm(a)){	
+    housingRatioResult = Math.round(housingRatio(income));
+    debtRatioResult = Math.round(debtRatio(income, auto));
+	
+	if (debtRatioResult <= "0") 
+	{
+		alert("Either your income is too low or your debt is too high!");
+		form.payment.value = "0";
+		form.payment2.value = "0";
+		form.amount.value = "0";
+		form.amount2.value = "0";
+		return false;
+	}	
+	
+      if (housingRatioResult>debtRatioResult) {
+		form.payment.value = formatCurrency(debtRatioResult);
+		form.payment2.value = formatCurrency(debtRatioResult);
+      }
+      else {
+		form.payment.value = formatCurrency(housingRatioResult);
+		form.payment2.value = formatCurrency(housingRatioResult); 
+      }
+	
+    
+    var c = debtRatioResult;	
+    var d = parseFloat(a / 1200); 
+    var f = parseFloat(1 + d);
+	var f2 = parseFloat(1 + d);
+    var g = parseFloat(Math.pow(f, 360));
+	var g2 = parseFloat(Math.pow(f2, 180));
+    var h = parseFloat(1 / g);
+	var h2 = parseFloat(1 / g2);
+    var i = parseFloat(1 - h);
+	var i2 = parseFloat(1 - h2);
+    var j = parseFloat(i / d);
+	var j2 = parseFloat(i2 / d);
+    var k = parseFloat(c * j);
+	var k2 = parseFloat(c * j2);
+    form.amount.value = formatCurrency(Math.round(k));
+	form.amount2.value = formatCurrency(Math.round(k2));
+
+
+}
+return;
+}
+
+
+function replaceChar(entry) {
+	out = "$"; 
+	add = ""; 
+	temp = "" + entry;
+	while (temp.indexOf(out)>-1) {
+		pos= temp.indexOf(out);
+		temp = "" + (temp.substring(0, pos) + add + 
+		temp.substring((pos + out.length), temp.length));
+	}
+	return temp;
+}
+
+function replacePct(entry) {
+	out = "%"; 
+	add = ""; 
+	temp = "" + entry;
+	while (temp.indexOf(out)>-1) {
+		pos= temp.indexOf(out);
+		temp = "" + (temp.substring(0, pos) + add + 
+		temp.substring((pos + out.length), temp.length));
+	}
+	return temp;
+}	
+	
+function replaceChars(entry) {
+	out = ","; 
+	add = ""; 
+	temp = "" + entry;
+	while (temp.indexOf(out)>-1) {
+		pos= temp.indexOf(out);
+		temp = "" + (temp.substring(0, pos) + add + 
+		temp.substring((pos + out.length), temp.length));
+	}
+	return temp;
+}
+
+function formatCurrency(num) {			
+			num=replaceChar(num);
+			num=replaceChars(num);
+		if ( checkForm(num));
+{
+			num = num.toString().replace(/$|,/g,'');
+			if(isNaN(num)) num = "0";
+			num = Math.floor(num).toString();
+		for (var i = 0; i < Math.floor((num.length-(1+i))/3); i++) 
+			num = num.substring(0,num.length-(4*i+3))+','+num.substring(num.length-(4*i+3));
+			 
+	return ('$' + num );	
+}
+}
+
+function basicedit()
+{
+	if 	(!IsMoney(document.temps.income.value) || document.temps.income.value.length ==0)
+		document.temps.income.value='$3,500';
+		
+	if 	(!IsMoney(document.temps.auto.value) || document.temps.auto.value.length ==0)
+		document.temps.auto.value='../../btn-red27px-R.gif';		
+
+	if 	(!IsPct(document.temps.rate.value) || document.temps.rate.value.length ==0)
+		document.temps.rate.value='7.5%';		
+}
+
+function IsMoney(val)
+	{
+		var number="0123456789$,.";
+
+		for (var i=0;i<val.length;i++)
+		{
+			if (number.indexOf(val.charAt(i)) == -1)
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+
+function IsNumber(val)
+	{
+		var number="0123456789.";
+
+		for (var i=0;i<val.length;i++)
+		{
+			if (number.indexOf(val.charAt(i)) == -1)
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+	
+function IsPct(val)
+	{
+		var number="0123456789.%,";
+
+		for (var i=0;i<val.length;i++)
+		{
+			if (number.indexOf(val.charAt(i)) == -1)
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+
+function addPct(pct) {
+			pct=replacePct(pct);
+			pct=parseFloat(pct);		
+		if (checkForm(pct));
+	{
+			return (pct + '%');
+		}
+}
+
Added: sandbox/SOC/2007/cgi/branches/acceptor_work/libs/cgi/example/acgi/amortization/acgi_amort.tpl
==============================================================================
--- (empty file)
+++ sandbox/SOC/2007/cgi/branches/acceptor_work/libs/cgi/example/acgi/amortization/acgi_amort.tpl	2008-03-12 13:06:00 EDT (Wed, 12 Mar 2008)
@@ -0,0 +1,99 @@
+<html><head>
+<link rel="stylesheet" type="text/css" href="/acgi_amort.css">
+
+<Title>Fixed Mortgage Loan Calculator</Title>
+<script type="text/javascript" language="JavaScript1.2" src="/acgi_amort.js"></script>
+</head>
+<body>
+
+{{!--Amortization form}}
+<form name="AmortBrowser" action="acgi_amort" method="post">
+<input type="hidden" name="Amortize" value="1">
+<table width="550" border="0" cellpadding="0" cellspacing="1" class="tblbase">
+<tr><td colspan=4 class=tblhead align=center>FIXED MORTGAGE LOAN CALCULATOR</td></tr>
+<tr><td colspan=2 class=tblhead align=center>Loan Information</td><td colspan=2 class=tblhead align=center>Prepayment Information (optional)</td></tr>
+<tr>
+<td width="250" class="td1">Mortgage Amount</td><td class="td2"><input name="LoanAmt" type="text" onBlur="this.value=formatCurrency(this.value);" value="{{LoanAmt}}" size="10"></td>
+<td width="250" class="td1">Prepayment Frequency</td><td class="td2"><select name="PrePmtFreq" {{PrePmtFreqInvalid}}>{{PrePmtFreq}}</select></td>
+</tr>
+<tr>
+<td class="td1">Interest (APR)</td><td class="td2"><input name="YearlyIntRate" type="text" value="{{YearlyIntRate}}" size="10"></td>
+<td class="td1">Prepayment Amount</td><td class="td2"><input name="PrePmtAmt" type="text" value="{{PrePmtAmt}}" size="17" {{PrePmtFreqInvalid}}></td>
+</tr>
+<tr>
+
+{{!-- Length of Loan selection list }}
+<td class="td1">Length of Loan</td>
+<td class="td2"><select name="TermYrs">
+{{#SELECT_TERM_YEARS}}
+<option value="{{TermYrs}}">{{TermYrs}} Years</option>
+{{/SELECT_TERM_YEARS}}
+</select></td>
+<td class="td1">Start with Payment</td><td class="td2"><input name="PrePmtBegin" type="text" value="{{PrePmtBegin}}" size="17"></td>
+</tr>
+<tr><td class="td1"></td><td class="td2"><input type="submit" value="Calculate"></td></tr>
+
+{{#NotAmortize}}
+<tr><td colspan="4" class="td2"><span class="small">
+DISCLAIMER: The figures above are based upon conventional program guidelines.<br>
+Calculations by this tool are believed to be accurate, yet are not guaranteed. Further review is<br>
+necessary to obtain an exact qualification.  If you have less than 20% equity in your home, a monthly<br>
+mortgage insurance payment may be required.</span></td></tr>
+{{/NotAmortize}}
+
+</table>
+</FORM>
+
+{{!--Prepayment summary table}}
+{{#PrePmtSummary}}
+<table width="550" border="0" cellpadding="0" cellspacing="1" class="tblbase">
+<tr><td colspan=4 class=tblhead align=center>PREPAYMENT vs REGULAR PAYMENT</td></tr>
+<tr><td colspan=2 class=tblhead align=center>Prepayment Results</td><td colspan=2 class=tblhead align=center>Regular Payment Results</td></tr>
+<tr>
+<td class="td1">Number of months to pay loan</td><td class="td2" width="125"><center><b>{{PrePmt_iPmtNo}}</b></center></td>
+<td class="td1"></td><td class="td2" width="125"><center><b>{{RegPmt_iPmtNo}}</b></center></td>
+</tr>
+<tr>
+<td class="td1">Total Interest Paid</td><td class="td2" align="right">{{PrePmt_TotalIntPd}}</td>
+<td class="td1"></td><td class="td2" align="right">{{RegPmt_TotalIntPd}}</td>
+</tr>
+<tr>
+<td width="250" class="td1">Total Payments</td><td class="td2" align="right">{{PrePmt_TotalPmts}}</td>
+<td width="250" class="td1"></td><td class="td2" align="right">{{RegPmt_TotalPmts}}</td>
+</tr>
+<tr><td colspan="4" class="td2"><span class="small">
+<br>
+By applying the prepayments in the schedule above, you would <u>realize these savings</u>:
+<ul>
+<li>You pay the <b>{{RegPmt_term_to_words}}</b> loan in <b>{{PrePmt_term_to_words}}</b>
+<br><br>
+<li>The total loan payments will be <b>{{PrePmt_TotalPmts}}</b> instead of <b>{{RegPmt_TotalPmts}}</b>
+</ul>
+</span></td></tr>
+</table>
+<br>
+{{/PrePmtSummary}}
+
+{{#RegPmtSummary}}
+{{!--Regular Payment summary table}}
+<table width="550" border="0" cellpadding="0" cellspacing="1" class="tblbase">
+<tr><td colspan=4 class=tblhead align=center>REGULAR PAYMENT SUMMARY</td></tr>
+<tr><td class="td1">Monthly Payment</td><td class="td2" width="125" align="right"><b>${{MonthlyPmt}}</b></td></tr>
+<tr><td class="td1">Total Interest Paid</td><td class="td2" width="125" align="right">${{RegPmt_TotalIntPd}}</td></tr>
+<tr><td class="td1">Total Payments</td><td class="td2" width="125" align="right">${{RegPmt_TotalPmts}}</td></tr>
+</table>
+<br>
+{{/RegPmtSummary}}
+
+{{!--Amortization table}}
+
+{{#Amortize}}
+<table border=0 cellpadding=0 cellspacing=1 width=550 class="tblbase"><tr><td colspan=6 class=tblhead align=center>AMORTIZATION TABLE</td></tr><td class=tblhead align=center>Payment</td><td class=tblhead align=center>Mo. Payment</td><td class=tblhead align=center>Interest Pd.</td><td class=tblhead align=center>Principal Pd.</td><td class=tblhead align=center>New Balance</td>
+{{#PaymentEntry}}
+<tr class=row{{ROW_TYPE}}><TD ALIGN=CENTER>{{ROW_NUM}}</td><TD>${{Payment}}</TD><TD>${{InterestPaid}}</TD><TD>${{PrincipalPaid}}</TD><TD>${{Balance}}</TD></tr>
+{{/PaymentEntry}}
+{{/Amortize}}
+
+</body>
+</html>
+
Added: sandbox/SOC/2007/cgi/branches/acceptor_work/libs/cgi/example/acgi/amortization/main.cpp
==============================================================================
--- (empty file)
+++ sandbox/SOC/2007/cgi/branches/acceptor_work/libs/cgi/example/acgi/amortization/main.cpp	2008-03-12 13:06:00 EDT (Wed, 12 Mar 2008)
@@ -0,0 +1,109 @@
+#include <iostream>
+#include <boost/cgi/acgi.hpp>
+#include <boost/algorithm/string/trim.hpp>
+#include <boost/algorithm/string/regex.hpp>
+#include <google/template.h>
+
+using namespace boost::acgi;
+
+std::string string_from_currency(std::string amt)
+{
+  using namespace boost::algorithm;
+  
+  erase_all_regex(amt, boost::regex("[$, ]")); // this is much too hardcore...
+  return amt;
+}
+
+
+int main()
+{
+  service s;
+  request req(s);
+  req.load(true);
+  response resp;
+
+  google::TemplateDictionary dict("example");
+  if (req.POST("LoanAmt").empty())
+    dict.SetValue("LoanAmt", "$250,000");
+  else
+    dict.SetValue("LoanAmt", req.POST("LoanAmt"));
+
+  if (req.POST("YearlyIntRate").empty())
+    dict.SetValue("YearlyIntRate", "6.000");
+  else
+    dict.SetValue("YearlyIntRate", req.POST("YearlyIntRate"));
+
+  boost::array<std::string, 8> year_opts
+    = {{ "5", "7", "10", "20", "30", "40", "50" }};
+    
+  BOOST_FOREACH(std::string& year, year_opts)
+  {
+    dict.SetValueAndShowSection("TermYrs", year, "SELECT_TERM_YEARS");
+  }
+
+  if (req.POST("Amortize").empty())
+    dict.ShowSection("NotAmortize");
+  else
+  {
+    try {
+      double P = boost::lexical_cast<double>(string_from_currency(req.POST("LoanAmt")));
+      double i = boost::lexical_cast<double>(boost::algorithm::trim_copy(req.POST("YearlyIntRate"))) / 1200;
+      double n = boost::lexical_cast<double>(req.POST("TermYrs")) * 12;
+
+      //resp<< "P = " << P << ", i = " << i << ", n = " << n << ", ";
+      double monthly_payments = (P*i) / (1 - std::pow((1+i), -n));
+
+      //resp<< monthly_payments;
+      
+      google::TemplateDictionary* sub_dict = dict.AddSectionDictionary("RegPmtSummary");
+      sub_dict->ShowSection("RegPmtSummary");
+      sub_dict->SetFormattedValue("MonthlyPmt", "%.2f", monthly_payments);
+
+      dict.ShowSection("Amortize");
+
+      double balance = P;
+      int row_num = 0;
+      double interest;
+      double principal_paid;
+      double total_interest;
+      do{
+        google::TemplateDictionary* sub_dict2 = dict.AddSectionDictionary("PaymentEntry");
+        sub_dict2->ShowSection("PaymentEntry");
+        sub_dict2->SetFormattedValue("Payment", "%.2f", monthly_payments);
+        sub_dict2->SetIntValue("ROW_NUM", ++row_num);
+        sub_dict2->SetIntValue("ROW_TYPE", (row_num % 2) + 1);
+        interest = balance * i;
+        total_interest += interest;
+        sub_dict2->SetFormattedValue("InterestPaid", "%.2f", interest);
+
+        principal_paid = monthly_payments - interest;
+        sub_dict2->SetFormattedValue("PrincipalPaid", "%.2f", principal_paid);
+        balance -= principal_paid; // Note: balance can increase.
+        sub_dict2->SetFormattedValue("Balance", "%.2f", balance);
+
+      }while(balance > 0);
+
+      sub_dict->SetFormattedValue("RegPmt_TotalIntPd", "%.2f", total_interest);
+      sub_dict->SetFormattedValue("RegPmt_TotalPmts", "%.2f", total_interest + P);
+
+    }catch(boost::bad_lexical_cast& blc)
+    {
+      std::cout<< "Bad lexical_cast: " << blc.what() << std::endl;
+      return 0;
+    }
+
+  }
+
+  google::Template* tmpl = google::Template::GetTemplate("example.tpl", google::STRIP_WHITESPACE);
+
+  std::string output;
+  tmpl->Expand(&output, &dict);
+  
+  resp<< content_type("text/html")
+      << output;
+
+  resp.send(req.client());
+
+  return 0;
+}
+