Boost logo

Boost-Commit :

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;
+}
+


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk