lmi-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lmi-commits] [5717] Write tab-delimited group roster file


From: Greg Chicares
Subject: [lmi-commits] [5717] Write tab-delimited group roster file
Date: Tue, 23 Apr 2013 02:19:33 +0000

Revision: 5717
          http://svn.sv.gnu.org/viewvc/?view=rev&root=lmi&revision=5717
Author:   chicares
Date:     2013-04-23 02:19:32 +0000 (Tue, 23 Apr 2013)
Log Message:
-----------
Write tab-delimited group roster file

Modified Paths:
--------------
    lmi/trunk/ChangeLog
    lmi/trunk/census_view.cpp
    lmi/trunk/census_view.hpp
    lmi/trunk/census_view_old.cpp
    lmi/trunk/census_view_old.hpp
    lmi/trunk/emit_ledger.cpp
    lmi/trunk/illustration_view.cpp
    lmi/trunk/ledger_text_formats.cpp
    lmi/trunk/ledger_text_formats.hpp
    lmi/trunk/main_wx.cpp
    lmi/trunk/mc_enum_type_enums.hpp
    lmi/trunk/mc_enum_types.cpp
    lmi/trunk/mec_view.cpp
    lmi/trunk/menus.xrc
    lmi/trunk/toolbar.xrc

Modified: lmi/trunk/ChangeLog
===================================================================
--- lmi/trunk/ChangeLog 2013-04-21 23:52:18 UTC (rev 5716)
+++ lmi/trunk/ChangeLog 2013-04-23 02:19:32 UTC (rev 5717)
@@ -32231,3 +32231,21 @@
   group_values.cpp
 Refactor.
 
+20130423T0219Z <address@hidden> [542]
+
+  census_view.cpp
+  census_view.hpp
+  census_view_old.cpp
+  census_view_old.hpp
+  emit_ledger.cpp
+  illustration_view.cpp
+  ledger_text_formats.cpp
+  ledger_text_formats.hpp
+  main_wx.cpp
+  mc_enum_type_enums.hpp
+  mc_enum_types.cpp
+  mec_view.cpp
+  menus.xrc
+  toolbar.xrc
+Write tab-delimited group roster file.
+

Modified: lmi/trunk/census_view.cpp
===================================================================
--- lmi/trunk/census_view.cpp   2013-04-21 23:52:18 UTC (rev 5716)
+++ lmi/trunk/census_view.cpp   2013-04-23 02:19:32 UTC (rev 5717)
@@ -818,6 +818,7 @@
     EVT_MENU(XRCID("print_case"            ),CensusView::UponPrintCase)
     EVT_MENU(XRCID("print_case_to_disk"    ),CensusView::UponPrintCaseToDisk)
     EVT_MENU(XRCID("print_spreadsheet"     
),CensusView::UponRunCaseToSpreadsheet)
+    EVT_MENU(XRCID("print_group_roster"    
),CensusView::UponRunCaseToGroupRoster)
     EVT_MENU(XRCID("paste_census"          ),CensusView::UponPasteCensus)
     EVT_MENU(XRCID("add_cell"              ),CensusView::UponAddCell)
     EVT_MENU(XRCID("delete_cells"          ),CensusView::UponDeleteCells)
@@ -833,6 +834,7 @@
     EVT_UPDATE_UI(XRCID("print_case"           
),CensusView::UponUpdateAlwaysEnabled)
     EVT_UPDATE_UI(XRCID("print_case_to_disk"   
),CensusView::UponUpdateAlwaysEnabled)
     EVT_UPDATE_UI(XRCID("print_spreadsheet"    
),CensusView::UponUpdateAlwaysEnabled)
+    EVT_UPDATE_UI(XRCID("print_group_roster"   
),CensusView::UponUpdateAlwaysEnabled)
     EVT_UPDATE_UI(XRCID("paste_census"         
),CensusView::UponUpdateAlwaysEnabled)
     EVT_UPDATE_UI(XRCID("add_cell"             
),CensusView::UponUpdateAlwaysEnabled)
     EVT_UPDATE_UI(XRCID("delete_cells"         
),CensusView::UponUpdateNonemptySelection)
@@ -1610,6 +1612,13 @@
     DoAllCells(mce_emit_spreadsheet);
 }
 
+/// Print tab-delimited roster to file loadable in spreadsheet programs.
+
+void CensusView::UponRunCaseToGroupRoster(wxCommandEvent&)
+{
+    DoAllCells(mce_emit_group_roster);
+}
+
 /// Paste a census from the clipboard.
 ///
 /// See unit tests in Skeleton::UponTestPasting().

Modified: lmi/trunk/census_view.hpp
===================================================================
--- lmi/trunk/census_view.hpp   2013-04-21 23:52:18 UTC (rev 5716)
+++ lmi/trunk/census_view.hpp   2013-04-23 02:19:32 UTC (rev 5717)
@@ -83,6 +83,7 @@
     void UponRunCell                (wxCommandEvent&);
     void UponRunCase                (wxCommandEvent&);
     void UponRunCaseToSpreadsheet   (wxCommandEvent&);
+    void UponRunCaseToGroupRoster   (wxCommandEvent&);
     void UponUpdateAlwaysEnabled    (wxUpdateUIEvent&);
     void UponUpdateSingleSelection  (wxUpdateUIEvent&);
     void UponUpdateNonemptySelection(wxUpdateUIEvent&);

Modified: lmi/trunk/census_view_old.cpp
===================================================================
--- lmi/trunk/census_view_old.cpp       2013-04-21 23:52:18 UTC (rev 5716)
+++ lmi/trunk/census_view_old.cpp       2013-04-23 02:19:32 UTC (rev 5717)
@@ -95,6 +95,7 @@
     EVT_MENU(XRCID("print_case"            ),CensusViewOld::UponPrintCase)
     EVT_MENU(XRCID("print_case_to_disk"    
),CensusViewOld::UponPrintCaseToDisk)
     EVT_MENU(XRCID("print_spreadsheet"     
),CensusViewOld::UponRunCaseToSpreadsheet)
+    EVT_MENU(XRCID("print_group_roster"    
),CensusViewOld::UponRunCaseToGroupRoster)
     EVT_MENU(XRCID("paste_census"          ),CensusViewOld::UponPasteCensus)
     EVT_MENU(XRCID("add_cell"              ),CensusViewOld::UponAddCell)
     EVT_MENU(XRCID("delete_cells"          ),CensusViewOld::UponDeleteCells)
@@ -111,6 +112,7 @@
     EVT_UPDATE_UI(XRCID("print_case"           
),CensusViewOld::UponUpdateApplicable)
     EVT_UPDATE_UI(XRCID("print_case_to_disk"   
),CensusViewOld::UponUpdateApplicable)
     EVT_UPDATE_UI(XRCID("print_spreadsheet"    
),CensusViewOld::UponUpdateApplicable)
+    EVT_UPDATE_UI(XRCID("print_group_roster"   
),CensusViewOld::UponUpdateApplicable)
     EVT_UPDATE_UI(XRCID("paste_census"         
),CensusViewOld::UponUpdateApplicable)
     EVT_UPDATE_UI(XRCID("add_cell"             
),CensusViewOld::UponUpdateApplicable)
     EVT_UPDATE_UI(XRCID("delete_cells"         
),CensusViewOld::UponUpdateApplicable)
@@ -945,6 +947,13 @@
     DoAllCells(mce_emit_spreadsheet);
 }
 
+/// Print tab-delimited roster to file loadable in spreadsheet programs.
+
+void CensusViewOld::UponRunCaseToGroupRoster(wxCommandEvent&)
+{
+    DoAllCells(mce_emit_group_roster);
+}
+
 /// Paste a census from the clipboard.
 ///
 /// See unit tests in Skeleton::UponTestPasting().

Modified: lmi/trunk/census_view_old.hpp
===================================================================
--- lmi/trunk/census_view_old.hpp       2013-04-21 23:52:18 UTC (rev 5716)
+++ lmi/trunk/census_view_old.hpp       2013-04-23 02:19:32 UTC (rev 5717)
@@ -30,13 +30,13 @@
 
 #include "input.hpp"
 #include "ledger.hpp"
-#include "mc_enum_type_enums.hpp" // enum mcenum_emission
+#include "mc_enum_type_enums.hpp"       // enum mcenum_emission
 #include "obstruct_slicing.hpp"
 #include "uncopyable_lmi.hpp"
 
 #include <boost/shared_ptr.hpp>
 
-#include <wx/defs.h> // wx shared-library 'attributes'
+#include <wx/defs.h>                    // wx shared-library 'attributes'
 
 #include <string>
 #include <vector>
@@ -81,6 +81,7 @@
     void UponRunCell                (wxCommandEvent&);
     void UponRunCase                (wxCommandEvent&);
     void UponRunCaseToSpreadsheet   (wxCommandEvent&);
+    void UponRunCaseToGroupRoster   (wxCommandEvent&);
     void UponUpdateApplicable       (wxUpdateUIEvent&);
 
     bool DoAllCells(mcenum_emission);

Modified: lmi/trunk/emit_ledger.cpp
===================================================================
--- lmi/trunk/emit_ledger.cpp   2013-04-21 23:52:18 UTC (rev 5716)
+++ lmi/trunk/emit_ledger.cpp   2013-04-23 02:19:32 UTC (rev 5717)
@@ -62,6 +62,17 @@
             ;
         std::remove(spreadsheet_filename.c_str());
         }
+    if(emission & mce_emit_group_roster)
+        {
+        LMI_ASSERT(!tsv_filepath.empty());
+        std::string spreadsheet_filename =
+                tsv_filepath.string()
+            +   ".roster"
+            +   configurable_settings::instance().spreadsheet_file_extension()
+            ;
+        std::remove(spreadsheet_filename.c_str());
+        PrintRosterHeaders(spreadsheet_filename);
+        }
 
     return timer.stop().elapsed_seconds();
 }
@@ -82,7 +93,9 @@
 /// to require a command-line program to invoke an external GUI
 /// program.
 ///
-/// The 'tsv_filepath' argument is used only for mce_emit_spreadsheet,
+/// The 'tsv_filepath' argument is used only for
+///   mce_emit_spreadsheet
+///   mce_emit_group_roster
 /// for which a single output file encompasses all cells in a census,
 /// whereas other output types produce a separate file for each cell.
 
@@ -130,6 +143,16 @@
             +   configurable_settings::instance().spreadsheet_file_extension()
             );
         }
+    if(emission & mce_emit_group_roster)
+        {
+        LMI_ASSERT(!tsv_filepath.empty());
+        PrintRosterTabDelimited
+            (ledger
+            ,   tsv_filepath.string()
+            +   ".roster"
+            +   configurable_settings::instance().spreadsheet_file_extension()
+            );
+        }
     if(emission & mce_emit_text_stream)
         {
         PrintLedgerFlatText(ledger, std::cout);

Modified: lmi/trunk/illustration_view.cpp
===================================================================
--- lmi/trunk/illustration_view.cpp     2013-04-21 23:52:18 UTC (rev 5716)
+++ lmi/trunk/illustration_view.cpp     2013-04-23 02:19:32 UTC (rev 5717)
@@ -89,6 +89,7 @@
     EVT_UPDATE_UI(XRCID("print_case"           
),IllustrationView::UponUpdateInapplicable)
     EVT_UPDATE_UI(XRCID("print_case_to_disk"   
),IllustrationView::UponUpdateInapplicable)
     EVT_UPDATE_UI(XRCID("print_spreadsheet"    
),IllustrationView::UponUpdateInapplicable)
+    EVT_UPDATE_UI(XRCID("print_group_roster"   
),IllustrationView::UponUpdateInapplicable)
     EVT_UPDATE_UI(XRCID("paste_census"         
),IllustrationView::UponUpdateInapplicable)
     EVT_UPDATE_UI(XRCID("add_cell"             
),IllustrationView::UponUpdateInapplicable)
     EVT_UPDATE_UI(XRCID("delete_cells"         
),IllustrationView::UponUpdateInapplicable)

Modified: lmi/trunk/ledger_text_formats.cpp
===================================================================
--- lmi/trunk/ledger_text_formats.cpp   2013-04-21 23:52:18 UTC (rev 5716)
+++ lmi/trunk/ledger_text_formats.cpp   2013-04-23 02:19:32 UTC (rev 5717)
@@ -682,6 +682,137 @@
     LMI_ASSERT(os.good());
 }
 
+/// Write group-roster headers to a tab-delimited file suitable for 
spreadsheets.
+
+void PrintRosterHeaders(std::string const& file_name)
+{
+    std::ofstream os(file_name.c_str(), ios_out_app_binary());
+
+    os << "FOR BROKER-DEALER USE ONLY. NOT TO BE SHARED WITH CLIENTS.\n\n";
+
+    // Skip authentication for non-interactive regression testing.
+    // Surround the date in single quotes because one popular
+    // spreadsheet would otherwise interpret it as a date, which
+    // is likely not to fit in a default-width cell.
+    if(!global_settings::instance().regression_testing())
+        {
+        authenticate_system();
+        os << "DatePrepared\t\t'" << calendar_date().str() << "'\n\n";
+        }
+    else
+        {
+        // For regression tests, write an arbitrary constant as
+        // date prepared, in order to avoid gratuitous failures.
+        os << "DatePrepared\t\t'" << calendar_date(2000, 1, 1).str() << 
"'\n\n";
+        }
+
+    char const* cheaders[] =
+        {"Insured1"
+        ,"ContractNumber"
+        ,"DateOfBirth"
+        ,"IssueAge"
+        ,"CurrentAge"
+        ,"UWClass"
+        ,"Smoker"
+        ,"SpecifiedAmount"
+        ,"ModalMinimumPremium"
+        ,"ErMode"
+        ,"CorpName"
+        ,"EffDate"
+        ,"PremiumTaxState"
+        ,"StateOfJurisdiction"
+        ,"CurrentGeneralAccountInterestRate"
+        ,"PolicyFee"
+        ,"DacTaxLoad"
+        ,"MaxPremiumTaxLoad"
+        ,"MaxTargetPremiumLoad"
+        ,"ProductName"
+        ,"PolicyForm"
+        ,"CurrentCoiMultiplier"
+        ,"Waiver"
+        ,"AccidentalDeath"
+        ,"TermRider"
+        ,"ChildRider"
+        ,"SpouseRider"
+        };
+
+    std::vector<std::string> const sheaders
+        (cheaders
+        ,cheaders + lmi_array_size(cheaders)
+        );
+    typedef std::vector<std::string>::const_iterator vsi;
+    for(vsi i = sheaders.begin(); i != sheaders.end(); ++i)
+        {
+        os << *i << '\t';
+        }
+    os << "\n\n";
+
+    LMI_ASSERT(os.good());
+}
+
+/// Write group roster to a tab-delimited file suitable for spreadsheets.
+///
+/// The file is appended to, rather than replaced, so that all cells
+/// in a census can be written to the same file.
+///
+/// The composite is deliberately skipped. For an inforce census with
+/// varying issue years, no year in the composite would match the sum
+/// of inforce-year cell values, because the composite is summed by
+/// policy year.
+
+void PrintRosterTabDelimited
+    (Ledger const& ledger_values
+    ,std::string const& file_name
+    )
+{
+    if(ledger_values.GetIsComposite())
+        {
+        return;
+        }
+
+    LedgerInvariant const& Invar = ledger_values.GetLedgerInvariant();
+    LedgerVariant   const& Curr_ = ledger_values.GetCurrFull();
+
+    std::ofstream os(file_name.c_str(), ios_out_app_binary());
+
+    int d = static_cast<int>(Invar.InforceYear);
+    LMI_ASSERT(d < Invar.GetLength());
+    LMI_ASSERT(d < Curr_.GetLength());
+
+    os
+        << Invar.value_str("Insured1"               ) << '\t'
+        << Invar.value_str("ContractNumber"         ) << '\t'
+        << "'" << Invar.DateOfBirth                   << "'\t"
+        << Invar.value_str("Age"                    ) << '\t'
+        << Invar.Age + Invar.InforceYear              << '\t'
+        << Invar.value_str("UWClass"                ) << '\t'
+        << Invar.value_str("Smoker"                 ) << '\t'
+        << Invar.value_str("SpecAmt"              ,d) << '\t'
+        << Invar.value_str("ModalMinimumPremium"  ,d) << '\t'
+        << Invar.ErMode                           [d] << '\t'
+        << Invar.value_str("CorpName"               ) << '\t'
+        << "'" << Invar.EffDate                       << "'\t"
+        << Invar.value_str("PremiumTaxState"        ) << '\t'
+        << Invar.value_str("StatePostalAbbrev"      ) << '\t'
+        << Curr_.value_str("AnnGAIntRate"         ,d) << '\t'
+        << Curr_.value_str("InitMlyPolFee"          ) << '\t'
+        << Invar.value_str("InitDacTaxRate"         ) << '\t'
+        << Invar.value_str("InitPremTaxRate"        ) << '\t'
+        << Curr_.value_str("InitTgtPremHiLoadRate"  ) << '\t'
+        << Invar.value_str("ProductName"            ) << '\t'
+        << Invar.value_str("PolicyForm"             ) << '\t'
+        << Invar.value_str("CurrentCoiMultiplier"   ) << '\t'
+        << Invar.value_str("HasWP"                  ) << '\t'
+        << Invar.value_str("HasADD"                 ) << '\t'
+        << Invar.value_str("HasTerm"                ) << '\t'
+        << Invar.value_str("HasChildRider"          ) << '\t'
+        << Invar.value_str("HasSpouseRider"         ) << '\t'
+        << '\n'
+        ;
+
+    LMI_ASSERT(os.good());
+}
+
 class FlatTextLedgerPrinter
     :        private lmi::uncopyable <FlatTextLedgerPrinter>
     ,virtual private obstruct_slicing<FlatTextLedgerPrinter>

Modified: lmi/trunk/ledger_text_formats.hpp
===================================================================
--- lmi/trunk/ledger_text_formats.hpp   2013-04-21 23:52:18 UTC (rev 5716)
+++ lmi/trunk/ledger_text_formats.hpp   2013-04-23 02:19:32 UTC (rev 5717)
@@ -39,10 +39,13 @@
 std::string LMI_SO FormatSelectedValuesAsHtml(Ledger const&);
 std::string LMI_SO FormatSelectedValuesAsTsv (Ledger const&);
 
-void LMI_SO PrintCellTabDelimited(Ledger const&, std::string const& file_name);
+void LMI_SO PrintCellTabDelimited  (Ledger const&, std::string const& 
file_name);
 
-void LMI_SO PrintLedgerFlatText  (Ledger const&, std::ostream&);
+void LMI_SO PrintRosterHeaders     (               std::string const& 
file_name);
+void LMI_SO PrintRosterTabDelimited(Ledger const&, std::string const& 
file_name);
 
+void LMI_SO PrintLedgerFlatText    (Ledger const&, std::ostream&);
+
 std::string ledger_format
     (double                            d
     ,std::pair<int,oenum_format_style> f

Modified: lmi/trunk/main_wx.cpp
===================================================================
--- lmi/trunk/main_wx.cpp       2013-04-21 23:52:18 UTC (rev 5716)
+++ lmi/trunk/main_wx.cpp       2013-04-23 02:19:32 UTC (rev 5717)
@@ -164,6 +164,7 @@
     EVT_UPDATE_UI(XRCID("print_case"           
),Skeleton::UponUpdateInapplicable)
     EVT_UPDATE_UI(XRCID("print_case_to_disk"   
),Skeleton::UponUpdateInapplicable)
     EVT_UPDATE_UI(XRCID("print_spreadsheet"    
),Skeleton::UponUpdateInapplicable)
+    EVT_UPDATE_UI(XRCID("print_group_roster"   
),Skeleton::UponUpdateInapplicable)
     EVT_UPDATE_UI(XRCID("paste_census"         
),Skeleton::UponUpdateInapplicable)
     EVT_UPDATE_UI(XRCID("add_cell"             
),Skeleton::UponUpdateInapplicable)
     EVT_UPDATE_UI(XRCID("delete_cells"         
),Skeleton::UponUpdateInapplicable)

Modified: lmi/trunk/mc_enum_type_enums.hpp
===================================================================
--- lmi/trunk/mc_enum_type_enums.hpp    2013-04-21 23:52:18 UTC (rev 5716)
+++ lmi/trunk/mc_enum_type_enums.hpp    2013-04-23 02:19:32 UTC (rev 5717)
@@ -50,8 +50,9 @@
     ,mce_emit_pdf_to_viewer  =   32 // GUI only.
     ,mce_emit_test_data      =   64
     ,mce_emit_spreadsheet    =  128
-    ,mce_emit_text_stream    =  256
-    ,mce_emit_custom_0       =  512
+    ,mce_emit_group_roster   =  256
+    ,mce_emit_text_stream    =  512
+    ,mce_emit_custom_0       = 1024
     };
 
 /// Rounding styles.

Modified: lmi/trunk/mc_enum_types.cpp
===================================================================
--- lmi/trunk/mc_enum_types.cpp 2013-04-21 23:52:18 UTC (rev 5716)
+++ lmi/trunk/mc_enum_types.cpp 2013-04-23 02:19:32 UTC (rev 5717)
@@ -67,6 +67,7 @@
     ,mce_emit_pdf_to_viewer
     ,mce_emit_test_data
     ,mce_emit_spreadsheet
+    ,mce_emit_group_roster
     ,mce_emit_text_stream
     ,mce_emit_custom_0
     };
@@ -80,11 +81,12 @@
     ,"emit_pdf_to_viewer"
     ,"emit_test_data"
     ,"emit_spreadsheet"
+    ,"emit_group_roster"
     ,"emit_text_stream"
     ,"emit_custom_0"
     };
 template<> struct mc_enum_key<mcenum_emission>
-  :public mc_enum_data<mcenum_emission, 11, emission_enums, emission_strings> 
{};
+  :public mc_enum_data<mcenum_emission, 12, emission_enums, emission_strings> 
{};
 template class mc_enum<mcenum_emission>;
 
 extern rounding_style const rounding_style_enums[] =

Modified: lmi/trunk/mec_view.cpp
===================================================================
--- lmi/trunk/mec_view.cpp      2013-04-21 23:52:18 UTC (rev 5716)
+++ lmi/trunk/mec_view.cpp      2013-04-23 02:19:32 UTC (rev 5717)
@@ -84,6 +84,7 @@
     EVT_UPDATE_UI(XRCID("print_case"           
),mec_view::UponUpdateInapplicable)
     EVT_UPDATE_UI(XRCID("print_case_to_disk"   
),mec_view::UponUpdateInapplicable)
     EVT_UPDATE_UI(XRCID("print_spreadsheet"    
),mec_view::UponUpdateInapplicable)
+    EVT_UPDATE_UI(XRCID("print_group_roster"   
),mec_view::UponUpdateInapplicable)
     EVT_UPDATE_UI(XRCID("paste_census"         
),mec_view::UponUpdateInapplicable)
     EVT_UPDATE_UI(XRCID("add_cell"             
),mec_view::UponUpdateInapplicable)
     EVT_UPDATE_UI(XRCID("delete_cells"         
),mec_view::UponUpdateInapplicable)

Modified: lmi/trunk/menus.xrc
===================================================================
--- lmi/trunk/menus.xrc 2013-04-21 23:52:18 UTC (rev 5716)
+++ lmi/trunk/menus.xrc 2013-04-23 02:19:32 UTC (rev 5717)
@@ -345,6 +345,10 @@
         <bitmap stock_id="write-spreadsheet"/>
         <help>Run and print all cells to a spreadsheet file</help>
     </object>
+    <object class="wxMenuItem" name="print_group_roster">
+        <label>Print r_oster to spreadsheet\tCtrl-Shift-O</label>
+        <help>Run and print group roster to a spreadsheet file</help>
+    </object>
     <object class="separator"/>
     <object class="wxMenuItem" name="paste_census">
         <label>Pa_ste census data\tCtrl-Shift-S</label>

Modified: lmi/trunk/toolbar.xrc
===================================================================
--- lmi/trunk/toolbar.xrc       2013-04-21 23:52:18 UTC (rev 5716)
+++ lmi/trunk/toolbar.xrc       2013-04-23 02:19:32 UTC (rev 5717)
@@ -110,6 +110,13 @@
         <bitmap stock_id="write-spreadsheet"/>
         <longhelp>Run and print all cells to a spreadsheet file</longhelp>
     </object>
+<!-- SOMEDAY !! One might imagine wanting this on the toolbar.
+    <object class="tool" name="print_group_roster">
+        <tooltip>Print roster to spreadsheet</tooltip>
+        <bitmap stock_id="NO ICON DESIGNED YET"/>
+        <longhelp>Run and print group roster to a spreadsheet file</longhelp>
+    </object>
+-->
     <object class="separator"/>
     <object class="tool" name="paste_census">
         <tooltip>Paste census</tooltip>




reply via email to

[Prev in Thread] Current Thread [Next in Thread]