[med-svn] [nutsqlite] 01/05: New upstream version 1.9.9.6

Iain R. Learmonth irl at moszumanska.debian.org
Thu Aug 31 21:41:49 UTC 2017


This is an automated email from the git hooks/post-receive script.

irl pushed a commit to branch master
in repository nutsqlite.

commit 8db86df6e5ff52618e711a07e878899574dce663
Author: Iain R. Learmonth <irl at debian.org>
Date:   Thu Aug 31 22:33:55 2017 +0100

    New upstream version 1.9.9.6
---
 CHANGES                  |  39 +++-
 README                   |   4 +-
 bigNUT/EXAMPLES          | 474 +++++++++++++++++++++++++++++++++++++++
 bigNUT/README            |  51 +++++
 bigNUT/analysis.sqlite3  |   6 +
 bigNUT/lite.sqlite3      |  28 +++
 bigNUT/lite2big.tcl      |  56 +++++
 bigNUT/load.sqlite3      | 466 ++++++++++++++++++++++++++++++++++++++
 bigNUT/logic.sqlite3     | 569 +++++++++++++++++++++++++++++++++++++++++++++++
 bigNUT/meal.sqlite3      |   5 +
 bigNUT/nextday.sqlite3   |  40 ++++
 bigNUT/nextmeal.sqlite3  |  27 +++
 bigNUT/ranalysis.sqlite3 |   5 +
 bigNUT/user.sqlite3      | 416 ++++++++++++++++++++++++++++++++++
 nutdoc.html => nut.1     | 548 +++++++++++++++++++++------------------------
 nut.tcl                  |   2 +-
 nutdoc.html              |  71 +++---
 updateNUT.tcl            | 168 +++++++++++---
 18 files changed, 2594 insertions(+), 381 deletions(-)

diff --git a/CHANGES b/CHANGES
index e450609..6461403 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,30 @@
+2017-06-26 NUTsqlite-1.9.9.6 released.
+
+2017-06-20 Multiple changes:  special commented-out code to make it easier to
+           modify GUI to show non-fiber carb DV percentages instead of the gram
+           weight; change to calorie auto-set algorithm to hopefully make it
+           work better to quickly home in on the right calorie level; added
+           Retinol & Glycine as Daily Value nutrients but only for PCF purposes
+           (you have to use sqlite3 directly to change the DV because there's
+           no place in the GUI to deal with it or even show the percentages,
+           and you put the value you want in the dv_default field, not the
+           nutopt field which should be 0.0).
+
+2017-05-12 NUTsqlite-1.9.9.5 released.
+
+2017-05-12 Updated email address everywhere.
+
+2017-05-05 Added bigNUT, the wonderful new SQL-only version of NUT.
+
+2017-02-22 NUTsqlite-1.9.9.4 released.
+
+2017-02-21 GUI not right for case when Calories are set to "adjust to my meals"
+           so I changed procs InitializePersonalOptions and 
+           ChangePersonalOptions to allow right fat and non-fiber carb choices.
+
+2016-11-30 In proc theusualAdd, order by Shrt_Desc instead of Long_Desc so meal
+           list menu looks more like it knows what it is doing.
+
 2016-10-22 NUTsqlite-1.9.9.3 released.
 
 2016-09-26 Changed AcceptNewMeasurements to return calorie auto-set feature to
@@ -61,12 +88,12 @@
 
 2015-07-14 The original GUI works well on Windows and Mac, so it is retained if
            the appSize variable in nut.tcl is 0.0; however, on Linux when there
-           there is no resolution-independent window manager, it does not scale
-           well.  Therefore, I wrote an alternate GUI that is invoked when
-           appSize is greater than 0.0.  Some of the widgets work differently
-           due to the needs of the different geometry manager employed, but the
-           size and appearance are now more consistent over the whole range of
-           screen resolutions and "appSize" settings.
+           is no resolution-independent window manager, it does not scale well.
+           Therefore, I wrote an alternate GUI that is invoked when appSize is
+           greater than 0.0.  Some of the widgets work differently due to the
+           needs of the different geometry manager employed, but the size and
+           appearance are now more consistent over the whole range of screen
+           resolutions and "appSize" settings.
 
 2015-07-10 In proc format_meal_id there is a call to the Tcl math func "int"
            that erroneously blows up if you pass it the string "08" which it
diff --git a/README b/README
index 77a5ede..b919c97 100644
--- a/README
+++ b/README
@@ -1,5 +1,5 @@
 NUT nutrition software
-Copyright (C) 1996-2016 by Jim Jozwiak.
+Copyright (C) 1996-2017 by Jim Jozwiak.
 
    NUT is nutrition software to record what you eat and analyze your meals for
    nutrient composition.  Besides the usual features of nutrition software, NUT
@@ -70,4 +70,4 @@ INSTALLATION of NUTsqlite
 
 Jim Jozwiak
 http://nut.sourceforge.net
-jozwiak at gmail.com, av832 at lafn.org
+jozwiak at gmail.com
diff --git a/bigNUT/EXAMPLES b/bigNUT/EXAMPLES
new file mode 100644
index 0000000..f44cfa7
--- /dev/null
+++ b/bigNUT/EXAMPLES
@@ -0,0 +1,474 @@
+-- GENERAL
+-- See the names for all the tables and views
+.tables
+
+-- See the schema for the table shopping
+.schema shopping
+
+-- See the schema for the view am_analysis
+.schema am_analysis
+
+-- OPTIONS
+-- Set the number of meals to analyze to 3
+update options set defanal_am = 3;
+
+-- Set the meals per day to 1 (you always need to record all the meals the
+-- program is set for; otherwise it throws off the calculations--so record
+-- a glass of water or something for each missing meal--although there is no
+-- harm in totally stopping your recording for a while while you collect
+-- your thoughts.)  When meals per day changes, meals from the old meals
+-- per day are archived, and archived meals at the new meals per day are
+-- restored.
+update options set meals_per_day = 1;
+
+-- Set the weight display to ounces avoirdupois when using the currentmeal view
+update options set grams = 0;
+
+-- Set the weight display to grams when using the currentmeal view
+update options set grams = 1;
+
+-- Set the current meal to March 16, 2017 meal #3
+update options set currentmeal = 2017031603;
+
+-- NUTRIENTS
+-- See all the defined nutrients
+select * from nutr_def;
+
+-- Set the Daily Value (nutrient standard) for Non-Fiber Carb to 250 grams
+update nutr_def set nutopt = 250.0 where NutrDesc = 'Non-Fiber Carb';
+
+-- Set the Daily Value for Total Fat to the default
+update nutr_def set nutopt = 0.0 where NutrDesc = 'Total Fat';
+
+-- Set the Daily Value for Protein to equal whatever is in your meals
+update nutr_def set nutopt = -1.0 where NutrDesc = 'Protein';
+
+-- Find where the Magnesium is coming from in your meals
+select * from nut_in_meals where NutrDesc = 'Magnesium';
+
+-- Find where the Magnesium is coming from in your meals in percentages of DV
+select * from nutdv_in_meals where NutrDesc = 'Magnesium';
+
+-- Find the percentages of protein/carb/fat in your meals
+select macropct from am_analysis_header;
+
+-- Find the Omega-6/3 balance of your meals
+select n6balance from am_analysis_header;
+
+-- List the defined food groups
+select * from fd_group;
+
+-- List the "Sweets"
+select NDB_No, Long_Desc from food_des where FdGrp_Cd = 1900;
+
+-- Find the 15 vegetables with the most Magnesium in 100 grams
+select Long_Desc from fd_group natural join food_des natural join nut_data
+where FdGrp_Desc like '%veg%' and Nutr_No = 304 order by Nutr_Val desc limit 15;
+
+-- Find the 15 vegetables with the most Magnesium that aren't dried
+select Long_Desc from fd_group natural join food_des natural join nut_data
+natural join nutr_def where FdGrp_Desc like '%veg%' and Long_Desc not like
+'%dried%' and NutrDesc = 'Magnesium' order by Nutr_Val desc limit 15;
+
+-- 
+-- We interrupt our examples because Senorita SQL has dropped by.  Senorita,
+-- what would you like to show us?
+
+-- Senorita SQL:  Let's imagine we have something we want to know and we don't
+-- have the faintest idea how to do it; so we do little pieces of it and later
+-- fit the pieces together and see if it works.
+
+-- Imagine this:  you have been changing protein and calories over the last few
+-- days and you remember some of how you felt on various days, but are unsure
+-- just what you were doing.  Say the last three weeks.  Can we get the Calories
+-- numbers for days in the last three weeks?  We know all our meal information
+-- is based in the table "mealfoods" so let's just list mealfoods out for the
+-- meals we care about.  I am going to use a limit clause initially so that I
+-- don't have to do a lot of scrolling to get an idea what is being presented,
+-- but if I left off the limit clause, I would get the whole thing.
+
+bigNUT> select * from mealfoods where meal_id >= 2017030101 limit 10;
+2017030101|1009|20.7769953051641
+2017030101|2047|1.0
+2017030101|11457|28.349523
+2017030101|11529|42.5242845
+2017030101|12563|11.4830311483027
+2017030101|15088|31.1844753
+2017030101|19165|5.4
+2017030101|99000|240.9709455
+2017030101|99010|17.0
+2017030101|99014|9.89645784739827
+
+-- Good start!  Do we want nutrients per meal or per day or what?  Don't we
+-- want nutrients per day?  Here's how we change it to get days:
+
+bigNUT> select meal_id / 100 as day, NDB_No, Gm_Wgt from mealfoods
+   ...> where meal_id >= 2017030101 limit 10;
+20170301|1009|20.7769953051641
+20170301|2047|1.0
+20170301|11457|28.349523
+20170301|11529|42.5242845
+20170301|12563|11.4830311483027
+20170301|15088|31.1844753
+20170301|19165|5.4
+20170301|99000|240.9709455
+20170301|99010|17.0
+20170301|99014|9.89645784739827
+
+-- We had to actually name the columns instead of the asterisk and make a new
+-- column called day.
+
+-- Now, for each combination of day and food, let's add the weights together
+-- to get the total weight of each food per day:
+
+bigNUT> select meal_id / 100 as day, NDB_No, sum(Gm_Wgt) from mealfoods 
+   ...> where meal_id >= 2017030101 group by day, NDB_No limit 10;
+20170301|1009|63.1549295774641
+20170301|2047|3.0
+20170301|11098|85.048569
+20170301|11457|85.048569
+20170301|11529|127.5728535
+20170301|12563|29.0097629009752
+20170301|15088|93.5534259
+20170301|19041|17.0097138
+20170301|19165|16.2
+20170301|20037|319.13830518051
+
+-- We had to use the sum function and the "group by" clause to show what to add
+-- together, namely each day's individual foods.
+
+-- So, we have the day, the food, and its total gram weight.  Remember, we are
+-- actually concerned with Calories and Protein.  How do attach the Calories
+-- to these records?  Calories per 100 grams of food are in the nut_data table,
+-- and so you don't have to look it up, I'll mention Calories are nutrient
+-- number 208 (Nutr_No = 208).  So, to chain it together we do a join using
+-- the food identifier, the NDB_No, and ask for only the calories records:
+
+bigNUT> select meal_id / 100 as day, NDB_No, sum(Gm_Wgt), cals.Nutr_Val 
+   ...> from mealfoods join nut_data cals using (NDB_No) 
+   ...> where meal_id >= 2017030101 and cals.Nutr_No = 208 
+   ...> group by day, NDB_No limit 10;
+20170301|1009|63.1549295774641|404.0
+20170301|2047|3.0|0.0
+20170301|11098|85.048569|43.0
+20170301|11457|85.048569|23.0
+20170301|11529|127.5728535|18.0
+20170301|12563|29.0097629009752|598.0
+20170301|15088|93.5534259|208.0
+20170301|19041|17.0097138|544.0
+20170301|19165|16.2|228.0
+20170301|20037|319.13830518051|123.0
+
+-- We provided an alias for the nut_data called "cals" so we know which nutrient
+-- value is which because we are going to now add Protein the same way:
+
+bigNUT> select meal_id / 100 as day, NDB_No, sum(Gm_Wgt), cals.Nutr_Val, 
+   ...> pro.Nutr_Val from mealfoods join nut_data cals using (NDB_No) 
+   ...> join nut_data pro using (NDB_No) 
+   ...> where meal_id >= 2017030101 and cals.Nutr_No = 208 
+   ...> and pro.Nutr_No = 203 group by day, NDB_No limit 10;
+20170301|1009|63.1549295774641|404.0|22.87
+20170301|2047|3.0|0.0|0.0
+20170301|11098|85.048569|43.0|3.38
+20170301|11457|85.048569|23.0|2.86
+20170301|11529|127.5728535|18.0|0.88
+20170301|12563|29.0097629009752|598.0|20.96
+20170301|15088|93.5534259|208.0|24.62
+20170301|19041|17.0097138|544.0|61.3
+20170301|19165|16.2|228.0|19.6
+20170301|20037|319.13830518051|123.0|2.74
+
+-- nut_data records are per 100 grams, but we rarely eat exactly 100 grams so
+-- we have to scale the nut_data to what we actually ate using the gram weight:
+
+bigNUT> select meal_id / 100 as day, NDB_No, 
+   ...> sum(Gm_Wgt / 100.0 * cals.Nutr_Val) as calories, 
+   ...> sum(Gm_Wgt / 100.0 * pro.Nutr_Val) as protein from mealfoods 
+   ...> join nut_data cals using (NDB_No) join nut_data pro using (NDB_No) 
+   ...> where meal_id >= 2017030101 and cals.Nutr_No = 208 
+   ...> and pro.Nutr_No = 203 group by day, NDB_No limit 10;
+20170301|1009|255.145915492955|14.443532394366
+20170301|2047|0.0|0.0
+20170301|11098|36.57088467|2.8746416322
+20170301|11457|19.56117087|2.4323890734
+20170301|11529|22.96311363|1.1226411108
+20170301|12563|173.478382147832|6.0804463040444
+20170301|15088|194.591125872|23.03285345658
+20170301|19041|92.532843072|10.4269545594
+20170301|19165|36.936|3.1752
+20170301|20037|392.540115372027|8.74438956194598
+
+-- We don't care about foods at this point, just the day and the sums of the
+-- calories and protein.  So we treat this output as a whole table by putting
+-- it in parentheses and then we select from it and sum it and group it just
+-- like we did before!
+
+bigNUT> select day, round(sum(calories)), round(sum(protein)) from 
+   ...> (select meal_id / 100 as day, NDB_No, 
+   ...> sum(Gm_Wgt / 100.0 * cals.Nutr_Val) as calories, 
+   ...> sum(Gm_Wgt / 100.0 * pro.Nutr_Val) as protein 
+   ...> from mealfoods join nut_data cals using (NDB_No) 
+   ...> join nut_data pro using (NDB_No) 
+   ...> where meal_id >= 2017030101 and cals.Nutr_No = 208 
+   ...> and pro.Nutr_No = 203 group by day, NDB_No)
+   ...> group by day;
+20170301|2379.0|125.0
+20170302|2388.0|125.0
+20170303|2470.0|125.0
+20170304|2453.0|125.0
+20170305|2669.0|125.0
+20170306|2465.0|125.0
+20170307|2415.0|125.0
+20170308|2401.0|125.0
+20170309|2489.0|125.0
+20170310|2528.0|125.0
+20170311|2580.0|120.0
+20170312|2701.0|113.0
+20170313|2398.0|115.0
+20170314|2400.0|120.0
+20170315|2400.0|120.0
+20170316|2402.0|120.0
+20170317|2399.0|120.0
+20170318|2401.0|122.0
+20170319|2401.0|125.0
+20170320|2340.0|125.0
+20170321|2311.0|125.0
+
+-- Thank you, Senorita!  That was a complicated example, though.  Maybe we 
+-- should get back to some simpler examples...
+
+-- FOODS and SERVING SIZES
+-- Find the fast food tacos
+select NDB_No, Long_Desc from food_des where Long_Desc like '%fast food%taco%';
+ 
+-- See the "preferred weight" of a soft chicken taco
+select Gm_Wgt, Amount, Msre_Desc from pref_Gm_Wgt where NDB_No = 21487;
+
+-- Change the preferred weight to show 220 grams of soft chicken tacos
+update pref_Gm_Wgt set Gm_Wgt = 220.0 where NDB_No = 21487;
+select Gm_Wgt, Amount, Msre_Desc from pref_Gm_Wgt where NDB_No = 21487;
+
+-- List the USDA-defined serving units for doughnuts, NDB_No = 18255
+select * from weight where NDB_No = 18255;
+
+-- Show the preferred serving for NDB_No = 18255
+select * from pref_Gm_Wgt where NDB_No = 18255;
+
+-- The second column of a weight record, Seq, controls which serving unit is
+-- preferred.  Set Seq = 0 to make "jumbo" (Seq = 5) the preferred serving unit.
+-- (The previous Seq = 0, if there is one, will be moved out of the
+-- way by a "trigger".)
+update weight set Seq = 0 where NDB_No = 18255 and Seq = 5;
+select * from pref_Gm_Wgt where NDB_No = 18255;
+
+-- See all the nutrients in soft chicken tacos at the preferred weight
+select * from view_foods where NDB_No = 21487;
+
+-- See selected nutrients in doughnuts at the preferred weight
+select * from view_foods where NDB_No = 18255 and 
+NutrDesc in ('Calories', 'Protein', 'Non-Fiber Carb', 'Total Fat');
+
+-- RECORD MEALS
+-- Set the current meal to April 1, 2017 meal #1
+update options set currentmeal = 2017040101;
+
+-- Insert a food into the current meal at the preferred weight with no portion
+-- control.
+insert into currentmeal values (99051, null, null);
+
+-- Insert a food into the current meal with portion control for Panto. Acid.
+insert into currentmeal values (99051, null, 'Panto. Acid');
+
+-- Update weight of sardines in the current meal to 2.5 ounces
+uodate currentmeal set Gm_Wgt = 2.5 * 28.35 where NDB_No = 15088;
+
+-- Update Amount of sardines in the current meal to 4 sardines
+update pref_Gm_Wgt set Amount = 4 where NDB_No = 15088;
+
+-- Delete a food from the current meal
+delete from currentmeal where NDB_No = 99051;
+
+-- CUSTOMARY MEALS AKA theusual
+-- Insert customary meal 'Breakfast' into currentmeal
+insert into currentmeal select NDB_No, Gm_Wgt, NutrDesc from theusual 
+where meal_name = 'Breakfast';
+
+-- Save currentmeal as customary meal called 'Keto Chicken'
+insert into theusual values ('Keto Chicken', null, null, null);
+
+-- Delete a customary meal named 'FrankenFood'
+delete from theusual where meal_name = 'FrankenFood';
+
+-- MEAL ANALYSIS
+-- See an analysis where the Calories are coming from in your meals
+select * from nut_in_meals where NutrDesc = 'Calories';
+
+-- See the previous in terms of percent of Daily Value
+select * from nutdv_in_meals where NutrDesc = 'Calories';
+
+-- See your average daily food consumption during the analysis period
+select * from daily_food;
+
+-- Show the nutrient name and percent of the Daily Value for the nutrients
+-- for which you have not achieved the DV during the analysis period
+select NutrDesc, dvpct_offset + 100 from am_analysis natural join am_dv natural join nutr_def where dvpct_offset < 0.0;
+
+-- Show your average intake of the amino acid Glycine
+select Nutr_Val from am_analysis natural join nutr_def 
+where NutrDesc = 'Glycine';
+
+-- WEIGHT LOG
+-- View the weight log
+select * from wlog;
+
+-- Insert today's weight and bodyfat percentage measurements into the 
+-- weight log.
+insert into wlog values (144.1, 14.1, null, null);
+
+-- View an expanded version of the weight log that presents the date of
+-- measurement, the weight, the bodyfat percentage, the total lean mass,
+-- the total fat mass, a body composition index where higher is better,
+-- and the cleardate for the entry (if it has been cleared).
+select * from wlview;
+
+-- View a summary of the uncleared part of the weight log
+select * from wlsummary;
+
+-- Clear the weight log (only when not using the Calorie Auto-Set feature)
+insert into wlsummary select 'clear';
+
+-- Enable the Calorie Auto-Set feature which, based on daily measurements,
+-- attempts to achieve a calorie level which allows both lean mass gain and
+-- fat mass loss, and then clears the weight log and starts another cycle.
+update options set autocal = 2;
+
+--
+-- Senorita SQL has returned to offer a benediction on our examples.
+-- Senorita, what would be the ultimate example?
+
+-- Senorita SQL:  Let's ask the question "What is the most nutritious food in
+-- the database?"  It's a complicated question, but we can start just by listing
+-- all the foods:
+
+bigNUT> select NDB_No, Long_Desc from food_des limit 10;
+1001|Butter, salted
+1002|Butter, whipped, with salt
+1003|Butter oil, anhydrous
+1004|Cheese, blue
+1005|Cheese, brick
+1006|Cheese, brie
+1007|Cheese, camembert
+1008|Cheese, caraway
+1009|Cheese, cheddar
+1010|Cheese, cheshire
+
+-- As before, we will use a limit clause so we can get an idea of the output
+-- without a lot of scrolling.  Let's define "most nutritious" first.
+-- Wouldn't it be a food that meets as many of the daily values as possible
+-- in a single food?  Let's use the "dv_default" field of the table nutr_def
+-- as a standard, but exclude the macronutrients, protein, fat, and carbs:
+
+bigNUT> select NDB_No, Long_Desc, Nutr_No, NutrDesc, dv_default
+   ...> from food_des join nutr_def
+   ...> where dv_default > 0.0
+   ...> and NutrDesc not in ('Calories', 'Protein', 'Total Fat',
+   ...> 'Total Carb', 'Non-Fiber Carb', 'Fiber', 'Sat Fat', 'Mono Fat',
+   ...> 'Poly Fat', 'Omega-6', 'LA', 'AA', 'Omega-3', 'ALA', 'EPA',
+   ...> 'DHA', 'Cholesterol')
+   ...> limit 10;
+1001|Butter, salted|301|Calcium|1000.0
+1002|Butter, whipped, with salt|301|Calcium|1000.0
+1003|Butter oil, anhydrous|301|Calcium|1000.0
+1004|Cheese, blue|301|Calcium|1000.0
+1005|Cheese, brick|301|Calcium|1000.0
+1006|Cheese, brie|301|Calcium|1000.0
+1007|Cheese, camembert|301|Calcium|1000.0
+1008|Cheese, caraway|301|Calcium|1000.0
+1009|Cheese, cheddar|301|Calcium|1000.0
+1010|Cheese, cheshire|301|Calcium|1000.0
+
+-- A good start, but let's repeat the previous ordered by food so we see
+-- if we are getting more nutrients than just Calcium:
+
+bigNUT> select NDB_No, Long_Desc, Nutr_No, NutrDesc, dv_default
+   ...> from food_des join nutr_def
+   ...> where dv_default > 0.0
+   ...> and NutrDesc not in ('Calories', 'Protein', 'Total Fat',
+   ...> 'Total Carb', 'Non-Fiber Carb', 'Fiber', 'Sat Fat', 'Mono Fat',
+   ...> 'Poly Fat', 'Omega-6', 'LA', 'AA', 'Omega-3', 'ALA', 'EPA',
+   ...> 'DHA', 'Cholesterol')
+   ...> order by NDB_No limit 10; 
+1001|Butter, salted|301|Calcium|1000.0
+1001|Butter, salted|303|Iron|18.0
+1001|Butter, salted|304|Magnesium|400.0
+1001|Butter, salted|305|Phosphorus|1000.0
+1001|Butter, salted|306|Potassium|3500.0
+1001|Butter, salted|307|Sodium|2400.0
+1001|Butter, salted|309|Zinc|15.0
+1001|Butter, salted|312|Copper|2.0
+1001|Butter, salted|315|Manganese|2.0
+1001|Butter, salted|317|Selenium|70.0
+
+-- Remember how we add the nutrient values from nut_data?
+
+bigNUT> select NDB_No, Long_Desc, Nutr_No, NutrDesc,
+   ...> dv_default, Nutr_Val
+   ...> from food_des join nutr_def natural join nut_data
+   ...> where dv_default > 0.0
+   ...> and NutrDesc not in ('Calories', 'Protein', 'Total Fat',
+   ...> 'Total Carb', 'Non-Fiber Carb', 'Fiber', 'Sat Fat', 'Mono Fat',
+   ...> 'Poly Fat', 'Omega-6', 'LA', 'AA', 'Omega-3', 'ALA', 'EPA',
+   ...> 'DHA', 'Cholesterol')
+   ...> order by NDB_No limit 10;
+1001|Butter, salted|301|Calcium|1000.0|24.0
+1001|Butter, salted|303|Iron|18.0|0.02
+1001|Butter, salted|304|Magnesium|400.0|2.0
+1001|Butter, salted|305|Phosphorus|1000.0|24.0
+1001|Butter, salted|306|Potassium|3500.0|24.0
+1001|Butter, salted|307|Sodium|2400.0|643.0
+1001|Butter, salted|309|Zinc|15.0|0.09
+1001|Butter, salted|312|Copper|2.0|0.0
+1001|Butter, salted|315|Manganese|2.0|0.0
+1001|Butter, salted|317|Selenium|70.0|1.0
+
+-- Well, this time the join was easier!  We used a natural join which means
+-- there is only one record in nut_data which will correspond to the NDB_No
+-- and Nutr_No of the original record, so attach it!
+
+-- Now let's create a new column, a nutrient index which is the Nutr_Val
+-- divided by the dv_default.  In other words, how many DVs are there in
+-- 100 grams of this food?
+
+bigNUT> select NDB_No, Long_Desc, Nutr_No, NutrDesc,
+   ...> Nutr_Val / dv_default as nutindex
+   ...> from food_des join nutr_def natural join nut_data
+   ...> where dv_default > 0.0
+   ...> and NutrDesc not in ('Calories', 'Protein', 'Total Fat',
+   ...> 'Total Carb', 'Non-Fiber Carb', 'Fiber', 'Sat Fat', 'Mono Fat',
+   ...> 'Poly Fat', 'Omega-6', 'LA', 'AA', 'Omega-3', 'ALA', 'EPA',
+   ...> 'DHA', 'Cholesterol')
+   ...> order by NDB_No limit 10;
+1001|Butter, salted|301|Calcium|0.024
+1001|Butter, salted|303|Iron|0.00111111111111111
+1001|Butter, salted|304|Magnesium|0.005
+1001|Butter, salted|305|Phosphorus|0.024
+1001|Butter, salted|306|Potassium|0.00685714285714286
+1001|Butter, salted|307|Sodium|0.267916666666667
+1001|Butter, salted|309|Zinc|0.006
+1001|Butter, salted|312|Copper|0.0
+1001|Butter, salted|315|Manganese|0.0
+1001|Butter, salted|317|Selenium|0.0142857142857143
+
+-- Now let's sum the nutrient indices by food and see what comes out on top!
+
+bigNUT> select NDB_No, Long_Desc, sum(Nutr_Val / dv_default) as nutindex
+   ...> from food_des join nutr_def natural join nut_data
+   ...> where dv_default > 0.0 
+   ...> and NutrDesc not in ('Calories', 'Protein', 'Total Fat',
+   ...> 'Total Carb', 'Non-Fiber Carb', 'Fiber', 'Sat Fat', 'Mono Fat',
+   ...> 'Poly Fat', 'Omega-6', 'LA', 'AA', 'Omega-3', 'ALA', 'EPA',
+   ...> 'DHA', 'Cholesterol')
+   ...> group by NDB_No order by nutindex desc limit 1;
+23424|Beef, New Zealand, imported, variety meats and by-products liver, cooked, boiled|210.575222197513
+
+-- Thank you, Senorita.  See you next time!
diff --git a/bigNUT/README b/bigNUT/README
new file mode 100644
index 0000000..0eb3e7a
--- /dev/null
+++ b/bigNUT/README
@@ -0,0 +1,51 @@
+The database for NUTsqlite features denormalized tables and heavy Tcl 
+involvement to boost performance, and indeed, the performance is excellent.
+However, it is a development dead-end because, if one picks some language other
+than Tcl for a new nutrition program, the NUTsqlite database becomes useless
+because it won't work without Tcl and has to be completely recoded.
+
+The project to develop a database without Tcl wasn't getting anywhere because
+of the tedium of working on an abstract API.  I realized I needed to think of
+the project as just another version of NUT that I could use if I liked it and I
+immediately got interested.  So, now you can run NUT from the command line 
+solely using SQL--no Tcl, no GUI, no compiling, etc.
+
+This will probably not interest most users, but if you understand what
+NUTsqlite is doing and you are interested in SQL, trying to use this new
+version may be an entertaining way to teach yourself SQL.  If you are a 
+developer interested in a nutrition database, trying to use this database
+can be a painless way to learn the NUT API without doing any coding or
+attempting to fathom a lot of abstraction, and you can prune away the fluff
+to get a useful pre-written backend for your application.
+
+Here's how you do it.  You need to have sqlite3 and you need to have the 
+USDA ascii tables unzipped in your directory.  You need to edit the
+lite2big.tcl script to point to the NUTsqlite db (nut.sqlite) if you want to
+transfer your NUTsqlite personal data to the new database; otherwise you omit
+the final lite2big.tcl step from the following command sequence:
+
+sqlite3 -init load.sqlite3 nut.db
+.quit
+sqlite3 -init logic.sqlite3 nut.db
+.quit
+./lite2big.tcl
+
+You can use lite2big.tcl as often as you like, perhaps after every meal to cut
+the effort involved using the big database.  You only need the load.sqlite3 and
+logic.sqlite3 init steps when initializing or upgrading to a new USDA database.
+Neither loading nor refreshing the logic erases or changes your personal data.
+To use the database all other times, type:
+
+sqlite3 -init user.sqlite3 nut.db
+
+Only the initial PRAGMA in user.sqlite3 that sets recursive triggers and the
+code for automatic portion control are absolutely necessary at each invocation
+of the database, but user.sqlite3 also has my personal views and triggers that
+I have found helpful.  You can add, delete, or change most of user.sqlite3 to
+customize it as you wish.  Read the comments and SQL in all the init files to
+understand what is going on, and look at the EXAMPLES file to see SQL
+statements that perform the most common NUT functions.
+
+Jim Jozwiak
+http://nut.sourceforge.net
+jozwiak at gmail.com
diff --git a/bigNUT/analysis.sqlite3 b/bigNUT/analysis.sqlite3
new file mode 100644
index 0000000..89e92f1
--- /dev/null
+++ b/bigNUT/analysis.sqlite3
@@ -0,0 +1,6 @@
+/*
+  This is the select that I use to look at the nutrient values for the
+  whole analysis period.
+*/
+
+select NutrDesc, round(Nutr_Val, 1) || ' ' || Units, cast(cast(round(100.0 + dvpct_offset) as int) as text) || '%' from am_analysis natural join am_dv natural join nutr_def order by dvpct_offset desc;
diff --git a/bigNUT/lite.sqlite3 b/bigNUT/lite.sqlite3
new file mode 100644
index 0000000..3c8714b
--- /dev/null
+++ b/bigNUT/lite.sqlite3
@@ -0,0 +1,28 @@
+/*
+  If you want to overwrite the NUTsqlite database with the germane data from
+  bigNUT, first change the following line to point to your nut.sqlite db:
+*/
+
+attach '../nut/nut.sqlite' as lite;
+
+/* 
+  Now, run this init file like this:  sqlite3 -init lite.sqlite3 nut.db
+
+  If you are already looking at a bigNUT prompt you could also do it this way:
+  bigNUT> .read lite.sqlite3
+*/
+
+begin;
+delete from lite.wlog;
+insert into lite.wlog select weight, bodyfat, wldate, cleardate from z_wl;
+delete from lite.mealfoods;
+insert into lite.mealfoods select meal_id / 100, meal_id % 100, NDB_No, Gm_Wgt / 100.0 from mealfoods;
+delete from lite.theusual;
+insert into lite.theusual select meal_name, NDB_No, case when Nutr_No is null then 'No Auto Portion Control' else NutrDesc end from z_tu left join nutr_def using (Nutr_No);
+update lite.options set defanal_am = (select defanal_am from options);
+update lite.nutr_def set nutopt = (select nutopt from nutr_def where NutrDesc = 'Protein') where NutrDesc = 'Protein';
+update lite.nutr_def set nutopt = (select nutopt from nutr_def where NutrDesc = 'Total Fat') where NutrDesc = 'Total Fat';
+update lite.nutr_def set nutopt = (select nutopt from nutr_def where NutrDesc = 'Non-Fiber Carb') where NutrDesc = 'Non-Fiber Carb';
+update lite.nutr_def set nutopt = (select nutopt from nutr_def where NutrDesc = 'Calories') where NutrDesc = 'Calories';
+commit;
+detach lite;
diff --git a/bigNUT/lite2big.tcl b/bigNUT/lite2big.tcl
new file mode 100755
index 0000000..4669695
--- /dev/null
+++ b/bigNUT/lite2big.tcl
@@ -0,0 +1,56 @@
+#!/bin/sh
+# the next line restarts using tclsh \
+exec tclsh "$0" "$@"
+
+# NUT nutrition software
+# Copyright (C) 1996-2015 by Jim Jozwiak.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#
+# Change the following two code lines to show the locations of your NUTsqlite
+# and NUTsqlheavy databases then run this script to copy your personal data
+# from the former to the latter.
+#
+
+set lite [file nativename ~/src/nut/nut.sqlite]
+set big [file nativename ~/src/bigNUT/nut.db]
+
+package require sqlite3
+sqlite3 db $big
+
+db eval {ATTACH $lite AS lite}
+db eval {begin}
+db eval {update options set currentmeal = 0}
+db eval {delete from mealfoods; insert into mealfoods select meal_date * 100 + meal, NDB_No, mhectograms * 100, null from lite.mealfoods}
+db eval {delete from archive_mealfoods; insert into archive_mealfoods select meal_date * 100 + meal, NDB_No, mhectograms * 100, meals_per_day from lite.archive_mealfoods}
+db eval {delete from z_wl; insert into z_wl select * from lite.wlog order by wldate, cleardate}
+db eval {delete from z_tu; insert into z_tu select meal_name, NDB_No, Nutr_No from lite.theusual left join lite.nutr_def on NutrDesc = PCF}
+db eval {select Tagname, Nutr_No, nutopt from lite.nutr_def} {
+ db eval "insert or ignore into nut_data select NDB_No, $Nutr_No, $Tagname from lite.food_des where NDB_No >= 99000 and $Tagname is not null"
+ db eval {update nutr_def set nutopt = $nutopt where Nutr_No = $Nutr_No}
+ }
+db eval {insert or ignore into food_des select NDB_No, FdGrp_Cd, Long_Desc, Shrt_Desc, Ref_desc, Refuse, Pro_Factor, Fat_Factor, CHO_Factor from lite.food_des where NDB_No >= 99000}
+db eval {create temp table zweight (NDB_No int, Seq int, Amount real, Msre_Desc text, Gm_Wgt real, origSeq int, origGm_Wgt, primary key(NDB_No, origSeq))}
+db eval {insert or ignore into zweight select * from weight}
+db eval {insert or replace into zweight select NDB_No, Seq, origAmount, Msre_Desc, whectograms * 100.0, origSeq, orighectograms * 100.0 from lite.weight where NDB_No >= 99000 or Seq != origSeq or whectograms != orighectograms}
+db eval {insert or replace into weight select * from zweight}
+db eval {drop table zweight}
+db eval {PRAGMA recursive_triggers = 1; analyze main}
+db eval {update options set defanal_am = case when (select defanal_am from lite.options) = 0 then 2147123119 else (select defanal_am from lite.options) end, currentmeal = (select lastmeal_rm from lite.options), FAPU1 = (select FAPU1 from lite.options), grams = (select grams from lite.options), wltweak = (select wltweak from lite.options), wlpolarity = (select wlpolarity from lite.options), autocal = (select autocal from lite.options)}
+db eval {delete from shopping; insert into shopping select * from lite.shopping}
+db eval {commit}
+
+db close
diff --git a/bigNUT/load.sqlite3 b/bigNUT/load.sqlite3
new file mode 100644
index 0000000..50b5e98
--- /dev/null
+++ b/bigNUT/load.sqlite3
@@ -0,0 +1,466 @@
+begin;
+
+/* These temp tables must start out corresponding exactly to the USDA schemas
+   for import from the USDA's distributed files but in some cases we need
+   transitional temp tables to safely add what's new from the USDA to what the
+   user already has. 
+*/
+
+/* For NUTR_DEF, we get rid of the tildes which escape non-numeric USDA fields,
+   and add two fields:  dv_default to use when Daily Value is undefined, and
+   nutopt which has three basic values:  -1 which means DV is whatever is in
+   the user's analysis unless null or <= 0.0 in which case the dv_default is
+   used; 0.0 which means the default Daily Value or computation; and > 0.0 which
+   is a specific gram amount of the nutrient.
+
+   We also shorten the names of nutrients so they can better fit on the screen
+   and add some nutrients that are derived from USDA values.
+*/
+
+create temp table ttnutr_def (Nutr_No text, Units text, Tagname text, NutrDesc text, Num_Dec text, SR_Order int);
+create temp table tnutr_def (Nutr_No int primary key, Units text, Tagname text, NutrDesc text, dv_default real, nutopt real);
+
+/* FD_GROUP
+*/
+
+create temp table tfd_group (FdGrp_Cd int, FdGrp_Desc text);
+
+/* FOOD_DES gets a new Long_Desc which is the USDA Long_Desc with the SciName
+   appended in parenthesis.  If the new Long_Desc is <= 60 characters, it
+   replaces the USDA's Shrt_Desc, which is sometimes unnecessarily cryptic.
+*/
+
+create temp table tfood_des (NDB_No text, FdGrp_Cd text, Long_Desc text, Shrt_Desc text, ComName text, ManufacName text, Survey text, Ref_desc text, Refuse integer, SciName text, N_Factor real, Pro_Factor real, Fat_Factor real, CHO_Factor real);
+
+/* WEIGHT gets two new fields, origSeq and origGm_Wgt.  USDA Seq numbers start
+   at one, so we change the Seq to 0 when we want to save the user's serving
+   unit preference.  origSeq allows us to put the record back to normal if the
+   user later chooses another Serving Unit.  The first record for a food when
+   ordered by Seq can have its Gm_Wgt changed, and later we will define views
+   that present the Amount of the serving unit as Gm_Wgt / origGm_Wgt * Amount.
+*/
+
+create temp table tweight (NDB_No text, Seq text, Amount real, Msre_Desc text, Gm_Wgt real, Num_Data_P int, Std_Dev real);
+create temp table zweight (NDB_No int, Seq int, Amount real, Msre_Desc text, Gm_Wgt real, origSeq int, origGm_Wgt real, primary key(NDB_No, origSeq));
+create temp table tnut_data (NDB_No text, Nutr_No text, Nutr_Val real, Num_Data_Pts int, Std_Error real, Src_Cd text, Deriv_Cd text, Ref_NDB_No text, Add_Nutr_Mark text, Num_Studies int, Min real, Max real, DF int, Low_EB real, Up_EB real, Stat_cmt text, AddMod_Date text, CC text);
+
+/* The USDA uses a caret as a column separator and has no special end-of-line */
+
+.separator "^"
+
+/* We import the USDA data to the temp tables */
+
+.import NUTR_DEF.txt ttnutr_def
+.import FD_GROUP.txt tfd_group
+.import FOOD_DES.txt tfood_des
+.import WEIGHT.txt tweight
+.import NUT_DATA.txt tnut_data
+
+/* These real NUT tables may already exist and contain user data */
+
+create table if not exists nutr_def (Nutr_No int primary key, Units text, Tagname text, NutrDesc text, dv_default real, nutopt real); 
+create table if not exists fd_group (FdGrp_Cd int primary key, FdGrp_Desc text);
+create table if not exists food_des (NDB_No int primary key, FdGrp_Cd int, Long_Desc text, Shrt_Desc text, Ref_desc text, Refuse integer, Pro_Factor real, Fat_Factor real, CHO_Factor real);
+create table if not exists weight (NDB_No int, Seq int, Amount real, Msre_Desc text, Gm_Wgt real, origSeq int, origGm_Wgt real, primary key(NDB_No, origSeq));
+create table if not exists nut_data (NDB_No int, Nutr_No int, Nutr_Val real, primary key(NDB_No, Nutr_No));
+
+/* Update table nutr_def. */
+
+insert into tnutr_def select * from nutr_def;
+insert or ignore into tnutr_def select trim(Nutr_No, '~'), trim(Units, '~'), trim(Tagname, '~'), trim(NutrDesc, '~'), NULL, NULL from ttnutr_def;
+update tnutr_def set Tagname = 'ADPROT' where Nutr_No = 257;
+update tnutr_def set Tagname = 'VITD_BOTH' where Nutr_No = 328;
+update tnutr_def set Tagname = 'LUT_ZEA' where Nutr_No = 338;
+update tnutr_def set Tagname = 'VITE_ADDED' where Nutr_No = 573;
+update tnutr_def set Tagname = 'VITB12_ADDED' where Nutr_No = 578;
+update tnutr_def set Tagname = 'F22D1T' where Nutr_No = 664;
+update tnutr_def set Tagname = 'F18D2T' where Nutr_No = 665;
+update tnutr_def set Tagname = 'F18D2I' where Nutr_No = 666;
+update tnutr_def set Tagname = 'F22D1C' where Nutr_No = 676;
+update tnutr_def set Tagname = 'F18D3I' where Nutr_No = 856;
+update tnutr_def set Units = 'mcg' where hex(Units) = 'B567';
+update tnutr_def set Units = 'kc' where Nutr_No = 208;
+update tnutr_def set NutrDesc = 'Protein' where Nutr_No = 203;
+update tnutr_def set NutrDesc = 'Total Fat' where Nutr_No = 204;
+update tnutr_def set NutrDesc = 'Total Carb' where Nutr_No = 205;
+update tnutr_def set NutrDesc = 'Ash' where Nutr_No = 207;
+update tnutr_def set NutrDesc = 'Calories' where Nutr_No = 208;
+update tnutr_def set NutrDesc = 'Starch' where Nutr_No = 209;
+update tnutr_def set NutrDesc = 'Sucrose' where Nutr_No = 210;
+update tnutr_def set NutrDesc = 'Glucose' where Nutr_No = 211;
+update tnutr_def set NutrDesc = 'Fructose' where Nutr_No = 212;
+update tnutr_def set NutrDesc = 'Lactose' where Nutr_No = 213;
+update tnutr_def set NutrDesc = 'Maltose' where Nutr_No = 214;
+update tnutr_def set NutrDesc = 'Ethyl Alcohol' where Nutr_No = 221;
+update tnutr_def set NutrDesc = 'Water' where Nutr_No = 255;
+update tnutr_def set NutrDesc = 'Adj. Protein' where Nutr_No = 257;
+update tnutr_def set NutrDesc = 'Caffeine' where Nutr_No = 262;
+update tnutr_def set NutrDesc = 'Theobromine' where Nutr_No = 263;
+update tnutr_def set NutrDesc = 'Sugars' where Nutr_No = 269;
+update tnutr_def set NutrDesc = 'Galactose' where Nutr_No = 287;
+update tnutr_def set NutrDesc = 'Fiber' where Nutr_No = 291;
+update tnutr_def set NutrDesc = 'Calcium' where Nutr_No = 301;
+update tnutr_def set NutrDesc = 'Iron' where Nutr_No = 303;
+update tnutr_def set NutrDesc = 'Magnesium' where Nutr_No = 304;
+update tnutr_def set NutrDesc = 'Phosphorus' where Nutr_No = 305;
+update tnutr_def set NutrDesc = 'Potassium' where Nutr_No = 306;
+update tnutr_def set NutrDesc = 'Sodium' where Nutr_No = 307;
+update tnutr_def set NutrDesc = 'Zinc' where Nutr_No = 309;
+update tnutr_def set NutrDesc = 'Copper' where Nutr_No = 312;
+update tnutr_def set NutrDesc = 'Fluoride' where Nutr_No = 313;
+update tnutr_def set NutrDesc = 'Manganese' where Nutr_No = 315;
+update tnutr_def set NutrDesc = 'Selenium' where Nutr_No = 317;
+update tnutr_def set NutrDesc = 'Vitamin A' where Nutr_No = 318;
+update tnutr_def set NutrDesc = 'Retinol' where Nutr_No = 319;
+update tnutr_def set NutrDesc = 'Vit. A, RAE' where Nutr_No = 320;
+update tnutr_def set NutrDesc = 'B-Carotene' where Nutr_No = 321;
+update tnutr_def set NutrDesc = 'A-Carotene' where Nutr_No = 322;
+update tnutr_def set NutrDesc = 'A-Tocopherol' where Nutr_No = 323;
+update tnutr_def set NutrDesc = 'Vitamin D' where Nutr_No = 324;
+update tnutr_def set NutrDesc = 'Vitamin D2' where Nutr_No = 325;
+update tnutr_def set NutrDesc = 'Vitamin D3' where Nutr_No = 326;
+update tnutr_def set NutrDesc = 'Vitamin D2+D3' where Nutr_No = 328;
+update tnutr_def set NutrDesc = 'B-Cryptoxanth.' where Nutr_No = 334;
+update tnutr_def set NutrDesc = 'Lycopene' where Nutr_No = 337;
+update tnutr_def set NutrDesc = 'Lutein+Zeaxan.' where Nutr_No = 338;
+update tnutr_def set NutrDesc = 'B-Tocopherol' where Nutr_No = 341;
+update tnutr_def set NutrDesc = 'G-Tocopherol' where Nutr_No = 342;
+update tnutr_def set NutrDesc = 'D-Tocopherol' where Nutr_No = 343;
+update tnutr_def set NutrDesc = 'A-Tocotrienol' where Nutr_No = 344;
+update tnutr_def set NutrDesc = 'B-Tocotrienol' where Nutr_No = 345;
+update tnutr_def set NutrDesc = 'G-Tocotrienol' where Nutr_No = 346;
+update tnutr_def set NutrDesc = 'D-Tocotrienol' where Nutr_No = 347;
+update tnutr_def set NutrDesc = 'Vitamin C' where Nutr_No = 401;
+update tnutr_def set NutrDesc = 'Thiamin' where Nutr_No = 404;
+update tnutr_def set NutrDesc = 'Riboflavin' where Nutr_No = 405;
+update tnutr_def set NutrDesc = 'Niacin' where Nutr_No = 406;
+update tnutr_def set NutrDesc = 'Panto. Acid' where Nutr_No = 410;
+update tnutr_def set NutrDesc = 'Vitamin B6' where Nutr_No = 415;
+update tnutr_def set NutrDesc = 'Folate' where Nutr_No = 417;
+update tnutr_def set NutrDesc = 'Vitamin B12' where Nutr_No = 418;
+update tnutr_def set NutrDesc = 'Choline' where Nutr_No = 421;
+update tnutr_def set NutrDesc = 'Menaquinone-4' where Nutr_No = 428;
+update tnutr_def set NutrDesc = 'Dihydro-K1' where Nutr_No = 429;
+update tnutr_def set NutrDesc = 'Vitamin K1' where Nutr_No = 430;
+update tnutr_def set NutrDesc = 'Folic Acid' where Nutr_No = 431;
+update tnutr_def set NutrDesc = 'Folate, food' where Nutr_No = 432;
+update tnutr_def set NutrDesc = 'Folate, DFE' where Nutr_No = 435;
+update tnutr_def set NutrDesc = 'Betaine' where Nutr_No = 454;
+update tnutr_def set NutrDesc = 'Tryptophan' where Nutr_No = 501;
+update tnutr_def set NutrDesc = 'Threonine' where Nutr_No = 502;
+update tnutr_def set NutrDesc = 'Isoleucine' where Nutr_No = 503;
+update tnutr_def set NutrDesc = 'Leucine' where Nutr_No = 504;
+update tnutr_def set NutrDesc = 'Lysine' where Nutr_No = 505;
+update tnutr_def set NutrDesc = 'Methionine' where Nutr_No = 506;
+update tnutr_def set NutrDesc = 'Cystine' where Nutr_No = 507;
+update tnutr_def set NutrDesc = 'Phenylalanine' where Nutr_No = 508;
+update tnutr_def set NutrDesc = 'Tyrosine' where Nutr_No = 509;
+update tnutr_def set NutrDesc = 'Valine' where Nutr_No = 510;
+update tnutr_def set NutrDesc = 'Arginine' where Nutr_No = 511;
+update tnutr_def set NutrDesc = 'Histidine' where Nutr_No = 512;
+update tnutr_def set NutrDesc = 'Alanine' where Nutr_No = 513;
+update tnutr_def set NutrDesc = 'Aspartic acid' where Nutr_No = 514;
+update tnutr_def set NutrDesc = 'Glutamic acid' where Nutr_No = 515;
+update tnutr_def set NutrDesc = 'Glycine' where Nutr_No = 516;
+update tnutr_def set NutrDesc = 'Proline' where Nutr_No = 517;
+update tnutr_def set NutrDesc = 'Serine' where Nutr_No = 518;
+update tnutr_def set NutrDesc = 'Hydroxyproline' where Nutr_No = 521;
+update tnutr_def set NutrDesc = 'Vit. E added' where Nutr_No = 573;
+update tnutr_def set NutrDesc = 'Vit. B12 added' where Nutr_No = 578;
+update tnutr_def set NutrDesc = 'Cholesterol' where Nutr_No = 601;
+update tnutr_def set NutrDesc = 'Trans Fat' where Nutr_No = 605;
+update tnutr_def set NutrDesc = 'Sat Fat' where Nutr_No = 606;
+update tnutr_def set NutrDesc = '4:0' where Nutr_No = 607;
+update tnutr_def set NutrDesc = '6:0' where Nutr_No = 608;
+update tnutr_def set NutrDesc = '8:0' where Nutr_No = 609;
+update tnutr_def set NutrDesc = '10:0' where Nutr_No = 610;
+update tnutr_def set NutrDesc = '12:0' where Nutr_No = 611;
+update tnutr_def set NutrDesc = '14:0' where Nutr_No = 612;
+update tnutr_def set NutrDesc = '16:0' where Nutr_No = 613;
+update tnutr_def set NutrDesc = '18:0' where Nutr_No = 614;
+update tnutr_def set NutrDesc = '20:0' where Nutr_No = 615;
+update tnutr_def set NutrDesc = '18:1' where Nutr_No = 617;
+update tnutr_def set NutrDesc = '18:2' where Nutr_No = 618;
+update tnutr_def set NutrDesc = '18:3' where Nutr_No = 619;
+update tnutr_def set NutrDesc = '20:4' where Nutr_No = 620;
+update tnutr_def set NutrDesc = '22:6n-3' where Nutr_No = 621;
+update tnutr_def set NutrDesc = '22:0' where Nutr_No = 624;
+update tnutr_def set NutrDesc = '14:1' where Nutr_No = 625;
+update tnutr_def set NutrDesc = '16:1' where Nutr_No = 626;
+update tnutr_def set NutrDesc = '18:4' where Nutr_No = 627;
+update tnutr_def set NutrDesc = '20:1' where Nutr_No = 628;
+update tnutr_def set NutrDesc = '20:5n-3' where Nutr_No = 629;
+update tnutr_def set NutrDesc = '22:1' where Nutr_No = 630;
+update tnutr_def set NutrDesc = '22:5n-3' where Nutr_No = 631;
+update tnutr_def set NutrDesc = 'Phytosterols' where Nutr_No = 636;
+update tnutr_def set NutrDesc = 'Stigmasterol' where Nutr_No = 638;
+update tnutr_def set NutrDesc = 'Campesterol' where Nutr_No = 639;
+update tnutr_def set NutrDesc = 'BetaSitosterol' where Nutr_No = 641;
+update tnutr_def set NutrDesc = 'Mono Fat' where Nutr_No = 645;
+update tnutr_def set NutrDesc = 'Poly Fat' where Nutr_No = 646;
+update tnutr_def set NutrDesc = '15:0' where Nutr_No = 652;
+update tnutr_def set NutrDesc = '17:0' where Nutr_No = 653;
+update tnutr_def set NutrDesc = '24:0' where Nutr_No = 654;
+update tnutr_def set NutrDesc = '16:1t' where Nutr_No = 662;
+update tnutr_def set NutrDesc = '18:1t' where Nutr_No = 663;
+update tnutr_def set NutrDesc = '22:1t' where Nutr_No = 664;
+update tnutr_def set NutrDesc = '18:2t' where Nutr_No = 665;
+update tnutr_def set NutrDesc = '18:2i' where Nutr_No = 666;
+update tnutr_def set NutrDesc = '18:2t,t' where Nutr_No = 669;
+update tnutr_def set NutrDesc = '18:2CLA' where Nutr_No = 670;
+update tnutr_def set NutrDesc = '24:1c' where Nutr_No = 671;
+update tnutr_def set NutrDesc = '20:2n-6c,c' where Nutr_No = 672;
+update tnutr_def set NutrDesc = '16:1c' where Nutr_No = 673;
+update tnutr_def set NutrDesc = '18:1c' where Nutr_No = 674;
+update tnutr_def set NutrDesc = '18:2n-6c,c' where Nutr_No = 675;
+update tnutr_def set NutrDesc = '22:1c' where Nutr_No = 676;
+update tnutr_def set NutrDesc = '18:3n-6c,c,c' where Nutr_No = 685;
+update tnutr_def set NutrDesc = '17:1' where Nutr_No = 687;
+update tnutr_def set NutrDesc = '20:3' where Nutr_No = 689;
+update tnutr_def set NutrDesc = 'TransMonoenoic' where Nutr_No = 693;
+update tnutr_def set NutrDesc = 'TransPolyenoic' where Nutr_No = 695;
+update tnutr_def set NutrDesc = '13:0' where Nutr_No = 696;
+update tnutr_def set NutrDesc = '15:1' where Nutr_No = 697;
+update tnutr_def set NutrDesc = '18:3n-3c,c,c' where Nutr_No = 851;
+update tnutr_def set NutrDesc = '20:3n-3' where Nutr_No = 852;
+update tnutr_def set NutrDesc = '20:3n-6' where Nutr_No = 853;
+update tnutr_def set NutrDesc = '20:4n-6' where Nutr_No = 855;
+update tnutr_def set NutrDesc = '18:3i' where Nutr_No = 856;
+update tnutr_def set NutrDesc = '21:5' where Nutr_No = 857;
+update tnutr_def set NutrDesc = '22:4' where Nutr_No = 858;
+update tnutr_def set NutrDesc = '18:1n-7t' where Nutr_No = 859;
+insert or ignore into tnutr_def values(3000,'kc','PROT_KCAL','Protein Calories', NULL, NULL);
+insert or ignore into tnutr_def values(3001,'kc','FAT_KCAL','Fat Calories', NULL, NULL);
+insert or ignore into tnutr_def values(3002,'kc','CHO_KCAL','Carb Calories', NULL, NULL);
+insert or ignore into tnutr_def values(2000,'g','CHO_NONFIB','Non-Fiber Carb', NULL, NULL);
+insert or ignore into tnutr_def values(2001,'g','LA','LA', NULL, NULL);
+insert or ignore into tnutr_def values(2002,'g','AA','AA', NULL, NULL);
+insert or ignore into tnutr_def values(2003,'g','ALA','ALA', NULL, NULL);
+insert or ignore into tnutr_def values(2004,'g','EPA','EPA', NULL, NULL);
+insert or ignore into tnutr_def values(2005,'g','DHA','DHA', NULL, NULL);
+insert or ignore into tnutr_def values(2006,'g','OMEGA6','Omega-6', NULL, NULL);
+insert or ignore into tnutr_def values(3003,'g','SHORT6','Short-chain Omega-6', NULL, NULL);
+insert or ignore into tnutr_def values(3004,'g','LONG6','Long-chain Omega-6', NULL, NULL);
+insert or ignore into tnutr_def values(2007,'g','OMEGA3','Omega-3', NULL, NULL);
+insert or ignore into tnutr_def values(3005,'g','SHORT3','Short-chain Omega-3', NULL, NULL);
+insert or ignore into tnutr_def values(3006,'g','LONG3','Long-chain Omega-3', NULL, NULL);
+insert or ignore into tnutr_def values(2008,'IU','VITE','Vitamin E', NULL, NULL);
+update tnutr_def set dv_default = 2000.0 where Tagname = 'ENERC_KCAL';
+update tnutr_def set dv_default = 50.0 where Tagname = 'PROCNT';
+update tnutr_def set dv_default = 65.0 where Tagname = 'FAT';
+update tnutr_def set dv_default = 300.0 where Tagname = 'CHOCDF';
+update tnutr_def set dv_default = 25.0 where Tagname = 'FIBTG';
+update tnutr_def set dv_default = 275.0 where Tagname = 'CHO_NONFIB';
+update tnutr_def set dv_default = 1000.0 where Tagname = 'CA';
+update tnutr_def set dv_default = 1000.0 where Tagname = 'P';
+update tnutr_def set dv_default = 18.0 where Tagname = 'FE';
+update tnutr_def set dv_default = 2400.0 where Tagname = 'NA';
+update tnutr_def set dv_default = 3500.0 where Tagname = 'K';
+update tnutr_def set dv_default = 400.0 where Tagname = 'MG';
+update tnutr_def set dv_default = 15.0 where Tagname = 'ZN';
+update tnutr_def set dv_default = 2.0 where Tagname = 'CU';
+update tnutr_def set dv_default = 2.0 where Tagname = 'MN';
+update tnutr_def set dv_default = 70.0 where Tagname = 'SE';
+update tnutr_def set dv_default = 5000.0 where Tagname = 'VITA_IU';
+update tnutr_def set dv_default = 30.0 where Tagname = 'VITE';
+update tnutr_def set dv_default = 80.0 where Tagname = 'VITK1';
+update tnutr_def set dv_default = 1.5 where Tagname = 'THIA';
+update tnutr_def set dv_default = 1.7 where Tagname = 'RIBF';
+update tnutr_def set dv_default = 20.0 where Tagname = 'NIA';
+update tnutr_def set dv_default = 10.0 where Tagname = 'PANTAC';
+update tnutr_def set dv_default = 2.0 where Tagname = 'VITB6A';
+update tnutr_def set dv_default = 400.0 where Tagname = 'FOL';
+update tnutr_def set dv_default = 6.0 where Tagname = 'VITB12';
+update tnutr_def set dv_default = 60.0 where Tagname = 'VITC';
+update tnutr_def set dv_default = 20.0 where Tagname = 'FASAT';
+update tnutr_def set dv_default = 300.0 where Tagname = 'CHOLE';
+update tnutr_def set dv_default = 400.0 where Tagname = 'VITD';
+update tnutr_def set dv_default = 8.9 where Tagname = 'FAPU';
+update tnutr_def set dv_default = 0.2 where Tagname = 'AA';
+update tnutr_def set dv_default = 3.8 where Tagname = 'ALA';
+update tnutr_def set dv_default = 0.1 where Tagname = 'EPA';
+update tnutr_def set dv_default = 0.1 where Tagname = 'DHA';
+update tnutr_def set dv_default = 4.7 where Tagname = 'LA';
+update tnutr_def set dv_default = 4.0 where Tagname = 'OMEGA3';
+update tnutr_def set dv_default = 4.9 where Tagname = 'OMEGA6';
+update tnutr_def set dv_default = 32.6 where Tagname = 'FAMS';
+update tnutr_def set nutopt = 0.0 where dv_default > 0.0 and nutopt is null;
+delete from nutr_def;
+insert into nutr_def select * from tnutr_def;
+create index if not exists tagname_index on nutr_def (Tagname asc);
+drop table ttnutr_def;
+drop table tnutr_def;
+
+/* Update table fg_group */
+
+insert or replace into fd_group select trim(FdGrp_Cd, '~'), trim(FdGrp_Desc, '~') from tfd_group;
+insert or replace into fd_group values (9999, 'Added Recipes');
+drop table tfd_group;
+
+/* Update table food_des. */
+
+INSERT OR REPLACE INTO food_des (NDB_No, FdGrp_Cd, Long_Desc, Shrt_Desc, Ref_desc, Refuse, Pro_Factor, Fat_Factor, CHO_Factor) select trim(NDB_No, '~'), trim(FdGrp_Cd, '~'), replace(trim(trim(Long_Desc, '~') || ' (' || trim(SciName, '~') || ')',' ('),' ()',''), upper(substr(trim(Shrt_Desc, '~'),1,1)) || lower(substr(trim(Shrt_Desc, '~'),2)), trim(Ref_desc, '~'), Refuse, Pro_Factor, Fat_Factor, CHO_Factor from tfood_des;
+update food_des set Shrt_Desc = Long_Desc where length(Long_Desc) <= 60;
+  
+drop table tfood_des;
+  
+/* 
+   the weight table is next, and needs a little explanation.  The Seq
+   column is a key and starts at 1 from the USDA; however, we want
+   the user to be able to select his own serving unit, and we do that
+   by changing the serving unit the user wants to Seq = 0, while saving
+   what the original Seq was in the origSeq column so that we can get back
+   later.  Furthermore, a min(Seq) as grouped by NDB_No can have its weight
+   modified in order to save a preferred serving size, so we also make a copy
+   of the original weight of the serving unit called origGm_Wgt.  Thus we
+   always get the Amount of the serving to be displayed by the equation:
+	Amount displayed = Gm_Wgt / origGm_Wgt * Amount
+*/
+
+update tweight set NDB_No = trim(NDB_No,'~');
+update tweight set Seq = trim(Seq,'~');
+update tweight set Msre_Desc = trim(Msre_Desc,'~');
+
+--We want every food to have a weight, so we make a '100 grams' weight
+insert or replace into zweight select NDB_No, 99, 100, 'grams', 100, 99, 100 from food_des;
+
+--Now we update zweight with the user's existing weight preferences
+insert or replace into zweight select * from weight where Seq != origSeq or Gm_Wgt != origGm_Wgt;
+
+--We overwrite real weight table with new USDA records
+INSERT OR REPLACE INTO weight select NDB_No, Seq, Amount, Msre_Desc, Gm_Wgt, Seq, Gm_Wgt from tweight;
+
+--We overwrite the real weight table with the original user mods
+insert or replace into weight select * from zweight;
+drop table tweight;
+drop table zweight;
+
+/* Update table nut_data */
+
+insert or replace into nut_data select trim(NDB_No, '~'), trim(Nutr_No, '~'), Nutr_Val from tnut_data;
+drop table tnut_data;
+  
+/* NUT has derived nutrient values that are handled as if they are
+   USDA nutrients to save a lot of computation and confusion at runtime
+   because the values are already there */
+
+  --insert VITE records into nut_data
+insert or replace into nut_data select f.NDB_No, 2008, case when vite_added.Nutr_Val is null then tocpha.Nutr_Val * 1.5 when tocpha.Nutr_Val is null then vite_added.Nutr_Val / 0.45 else (vite_added.Nutr_Val / 0.45) + (tocpha.Nutr_Val - vite_added.Nutr_Val) * 1.5 end from food_des f left join nut_data tocpha on f.NDB_No = tocpha.NDB_No and tocpha.Nutr_No = 323 left join nut_data vite_added on f.NDB_No = vite_added.NDB_No and vite_added.Nutr_No = 573 where tocpha.Nutr_Val is not null or vi [...]
+  
+  --insert LA records into nut_data
+insert or replace into nut_data select f.NDB_No, 2001, case when f18d2cn6.Nutr_Val is not null then f18d2cn6.Nutr_Val when f18d2.Nutr_Val is not null then f18d2.Nutr_Val - ifnull(f18d2t.Nutr_Val, 0.0) - ifnull(f18d2tt.Nutr_Val, 0.0) - ifnull(f18d2i.Nutr_Val, 0.0) - ifnull(f18d2cla.Nutr_Val, 0.0) end from food_des f left join nut_data f18d2 on f.NDB_No = f18d2.NDB_No and f18d2.Nutr_No = 618 left join nut_data f18d2cn6 on f.NDB_No = f18d2cn6.NDB_No and f18d2cn6.Nutr_No = 675 left join nut_ [...]
+  
+  --insert ALA records into nut_data
+insert or replace into nut_data select f.NDB_No, 2003, case when f18d3cn3.Nutr_Val is not null then f18d3cn3.Nutr_Val when f18d3.Nutr_Val is not null then f18d3.Nutr_Val - ifnull(f18d3cn6.Nutr_Val, 0.0) - ifnull(f18d3i.Nutr_Val, 0.0) end from food_des f left join nut_data f18d3 on f.NDB_No = f18d3.NDB_No and f18d3.Nutr_No = 619 left join nut_data f18d3cn3 on f.NDB_No = f18d3cn3.NDB_No and f18d3cn3.Nutr_No = 851 left join nut_data f18d3cn6 on f.NDB_No = f18d3cn6.NDB_No and f18d3cn6.Nutr_N [...]
+  
+  --insert SHORT6 records into nut_data
+insert or replace into nut_data select f.NDB_No, 3003, ifnull(la.Nutr_Val, 0.0) + ifnull(f18d3cn6.Nutr_Val, 0.0) from food_des f left join nut_data la on f.NDB_No = la.NDB_No and la.Nutr_No = 2001 left join nut_data f18d3cn6 on f.NDB_No = f18d3cn6.NDB_No and f18d3cn6.Nutr_No = 685 where la.Nutr_Val is not null or f18d3cn6.Nutr_Val is not null;
+  
+  --insert SHORT3 records into nut_data
+insert or replace into nut_data select f.NDB_No, 3005, ifnull(ala.Nutr_Val, 0.0) + ifnull(f18d4.Nutr_Val, 0.0) from food_des f left join nut_data ala on f.NDB_No = ala.NDB_No and ala.Nutr_No = 2003 left join nut_data f18d4 on f.NDB_No = f18d4.NDB_No and f18d4.Nutr_No = 627 where ala.Nutr_Val is not null or f18d4.Nutr_Val is not null;
+  
+  --insert AA records into nut_data
+insert or replace into nut_data select f.NDB_No, 2002, case when f20d4n6.Nutr_Val is not null then f20d4n6.Nutr_Val else f20d4.Nutr_Val end from food_des f left join nut_data f20d4 on f.NDB_No = f20d4.NDB_No and f20d4.Nutr_No = 620 left join nut_data f20d4n6 on f.NDB_No = f20d4n6.NDB_No and f20d4n6.Nutr_No = 855 where f20d4.Nutr_Val is not null or f20d4n6.Nutr_Val is not null;
+  
+  --insert LONG6 records into nut_data
+insert or replace into nut_data select f.NDB_No, 3004, case when f20d3n6.Nutr_Val is not null then ifnull(aa.Nutr_Val,0.0) + f20d3n6.Nutr_Val + ifnull(f22d4.Nutr_Val,0.0) else ifnull(aa.Nutr_Val,0.0) + ifnull(f20d3.Nutr_Val,0.0) + ifnull(f22d4.Nutr_Val, 0.0) end from food_des f left join nut_data aa on f.NDB_No = aa.NDB_No and aa.Nutr_No = 2002 left join nut_data f20d3n6 on f.NDB_No = f20d3n6.NDB_No and f20d3n6.Nutr_No = 853 left join nut_data f20d3 on f.NDB_No = f20d3.NDB_No and f20d3.N [...]
+  
+  --insert EPA records into nut_data
+insert or replace into nut_data select f.NDB_No, 2004, f20d5.Nutr_Val from food_des f left join nut_data f20d5 on f.NDB_No = f20d5.NDB_No and f20d5.Nutr_No = 629 where f20d5.Nutr_Val is not null;
+  
+  --insert DHA records into nut_data
+insert or replace into nut_data select f.NDB_No, 2005, f22d6.Nutr_Val from food_des f left join nut_data f22d6 on f.NDB_No = f22d6.NDB_No and f22d6.Nutr_No = 621 where f22d6.Nutr_Val is not null;
+  
+  --insert LONG3 records into nut_data
+insert or replace into nut_data select f.NDB_No, 3006, ifnull(epa.Nutr_Val, 0.0) + ifnull(dha.Nutr_Val, 0.0) + ifnull(f20d3n3.Nutr_Val, 0.0) + ifnull(f22d5.Nutr_Val, 0.0) from food_des f left join nut_data epa on f.NDB_No = epa.NDB_No and epa.Nutr_No = 2004 left join nut_data dha on f.NDB_No = dha.NDB_No and dha.Nutr_No = 2005 left join nut_data f20d3n3 on f.NDB_No = f20d3n3.NDB_No and f20d3n3.Nutr_No = 852 left join nut_data f22d5 on f.NDB_No = f22d5.NDB_No and f22d5.Nutr_No = 631 where [...]
+  
+  --insert OMEGA6 records into nut_data
+insert or replace into nut_data select f.NDB_No, 2006, ifnull(short6.Nutr_Val, 0.0) + ifnull(long6.Nutr_Val, 0.0) from food_des f left join nut_data short6 on f.NDB_No = short6.NDB_No and short6.Nutr_No = 3003 left join nut_data long6 on f.NDB_No = long6.NDB_No and long6.Nutr_No = 3004 where short6.Nutr_Val is not null or long6.Nutr_Val is not null;
+  
+  --insert OMEGA3 records into nut_data
+insert or replace into nut_data select f.NDB_No, 2007, ifnull(short3.Nutr_Val, 0.0) + ifnull(long3.Nutr_Val, 0.0) from food_des f left join nut_data short3 on f.NDB_No = short3.NDB_No and short3.Nutr_No = 3005 left join nut_data long3 on f.NDB_No = long3.NDB_No and long3.Nutr_No = 3006 where short3.Nutr_Val is not null or long3.Nutr_Val is not null;
+  
+  --insert CHO_NONFIB records into nut_data
+insert or replace into nut_data select f.NDB_No, 2000, case when chocdf.Nutr_Val - ifnull(fibtg.Nutr_Val, 0.0) < 0.0 then 0.0 else chocdf.Nutr_Val - ifnull(fibtg.Nutr_Val, 0.0) end from food_des f left join nut_data chocdf on f.NDB_No = chocdf.NDB_No and chocdf.Nutr_No = 205 left join nut_data fibtg on f.NDB_No = fibtg.NDB_No and fibtg.Nutr_No = 291 where chocdf.Nutr_Val is not null;
+  
+  --replace empty strings with values for macronutrient factors in food_des
+update food_des set Pro_Factor = 4.0 where Pro_Factor = '';
+update food_des set Fat_Factor = 9.0 where Fat_Factor = '';
+update food_des set CHO_Factor = 4.0 where CHO_Factor = '';
+  
+  --insert calories from macronutrients into nut_data
+insert or replace into nut_data select f.NDB_No, 3000, f.Pro_Factor * procnt.Nutr_Val from food_des f join nut_data procnt on f.NDB_No = procnt.NDB_No and procnt.Nutr_No = 203;
+insert or replace into nut_data select f.NDB_No, 3001, f.Fat_Factor * fat.Nutr_Val from food_des f join nut_data fat on f.NDB_No = fat.NDB_No and fat.Nutr_No = 204;
+insert or replace into nut_data select f.NDB_No, 3002, f.CHO_Factor * chocdf.Nutr_Val from food_des f join nut_data chocdf on f.NDB_No = chocdf.NDB_No and chocdf.Nutr_No = 205;
+  
+/* NUT needs some additional permanent tables for options, mealfoods, archive
+   of mealfoods if meals per day changes, customary meals (theusual), and
+   the weight log */
+
+/* This table is global options:  
+    defanal_am    how many meals to analyze starting at the latest and going
+                  back in time
+    FAPU1         the "target" for Omega-6/3 balance
+    meals_per_day yes, meals per day
+    grams         boolean true means grams, false means ounces avoirdupois and
+                  never means fluid ounces
+    currentmeal   10 digit integer YYYYMMDDxx where xx is daily meal number
+    wltweak       Part of the automatic calorie set feature.  If NUT moves the
+                  calories during a cycle to attempt better body composition,
+                  wltweak is true.  It is always changed to false at the
+                  beginning of a cycle.
+    wlpolarity    In order not to favor gaining lean mass over losing fat mass,
+                  NUT cycles this between true and false to alternate strategies
+    autocal       0 means no autocal feature, 2 means feature turned on.
+                  The autocal feature moves calories to try to achieve
+                  a calorie level that allows both fat mass loss and lean mass
+                  gain.
+*/
+
+create table if not exists options(protect integer primary key, defanal_am integer default 2147123119, FAPU1 real default 0.0, meals_per_day int default 3, grams int default 1, currentmeal int default 0, wltweak integer default 0, wlpolarity integer default 0, autocal integer default 0);
+
+/*
+   The table of what and how much eaten at each meal.
+*/
+ 
+create table if not exists mealfoods(meal_id int, NDB_No int, Gm_Wgt real, Nutr_No int, primary key(meal_id, NDB_No));
+
+/* 
+   There is no easy way to analyze a meal where each day can have a 
+   different number of meals per day because you have to do a lot of computation
+   to combine the meals, and for any particular meal, you cannot provide 
+   guidance because you don't know how many more meals are coming for the day.
+   So, when the user changes meals_per_day we archive the non-compliant meals
+   (different number of meals per day from new setting)  and restore the
+   compliant ones (same number of meals per day as new setting).
+*/
+
+create table if not exists archive_mealfoods(meal_id int, NDB_No int, Gm_Wgt real, meals_per_day integer, primary key(meal_id desc, NDB_No asc, meals_per_day));
+
+/* Table of customary meals which also has has Nutr_No for specification of
+   PCF or automatic portion control.  We call it z_tu so we can define a
+   "theusual" view later to better control user interaction.
+*/
+
+create table if not exists z_tu(meal_name text, NDB_No int, Nutr_No int, primary key(meal_name, NDB_No), unique(meal_name, Nutr_No));
+
+/* The weight log.  When the weight log is "cleared" the info is not erased.
+   Null cleardates identify the current log.  As we have been doing, we call
+   the real table z_wl, so we can have a couple of views that allow us to
+   control user interaction, wlog and wlsummary.
+*/
+
+create table if not exists z_wl(weight real, bodyfat real, wldate int, cleardate int, primary key(wldate, cleardate));
+
+/* To protect table options from extraneous inserts we create a trigger */
+
+drop trigger if exists protect_options;
+create trigger protect_options after insert on options begin delete from options where protect != 1; end;
+
+/* This insert will have no effect if options are already there */
+
+insert into options default values;
+
+drop trigger protect_options;
+commit;
+vacuum;
diff --git a/bigNUT/logic.sqlite3 b/bigNUT/logic.sqlite3
new file mode 100644
index 0000000..449fe5e
--- /dev/null
+++ b/bigNUT/logic.sqlite3
@@ -0,0 +1,569 @@
+/* 
+   This begins the NUT application logic which is implemented as SQL
+   tables and triggers in order that the NUT code be independent of the
+   GUI and its language, be implemented in C for performance,
+   and be implemented by SQLite for portability.
+*/ 
+
+begin;
+    
+/* 
+   First we create various tables just for internal computation
+  
+   The following tables are for intermediate values in the computation
+   of Daily Values
+*/
+  
+DROP TABLE if exists z_vars1;
+CREATE TABLE z_vars1 (am_cals2gram_pro real, am_cals2gram_fat real, am_cals2gram_cho real, am_alccals real, am_fa2fat real, balance_of_calories int);
+
+DROP TABLE if exists z_vars2;
+CREATE TABLE z_vars2 (am_fat_dv_not_boc real, am_cho_nonfib_dv_not_boc real, am_chocdf_dv_not_boc real);
+
+DROP TABLE if exists z_vars3;
+CREATE TABLE z_vars3 (am_fat_dv_boc real, am_chocdf_dv_boc real, am_cho_nonfib_dv_boc real);
+
+DROP TABLE if exists z_vars4;
+CREATE TABLE z_vars4 (Nutr_No int, dv real, Nutr_Val real);
+  
+/*
+  The following table is used in conjunction with recursive triggers to
+  compute essential fatty acid reference values
+*/  
+
+DROP TABLE if exists z_n6;
+CREATE TABLE z_n6 (n6hufa real, FAPU1 real, pufa_reduction real, iter int, reduce int, p3 real, p6 real, h3 real, h6 real, o real);
+
+/*  
+   The following table is the am analysis minus the currentmeal.  That way,
+   we avoid the overhead of reanalyzing everything while we are
+   doing automatic portion control.  The "am_analysis" view is the
+   sum of the analyses in this table and those in the "rm_analysis"
+   table, the analysis of the current meal.  Of course, this means we
+   have to redo this table whenever the currentmeal changes to a
+   different meal, and we always need to have a good rm_analysis
+   before we can see a good am_analysis.
+*/
+  
+drop table if exists z_anal;
+create table z_anal (Nutr_No int primary key, null_value int, Nutr_Val real);
+
+/*    
+   The following tables and views are intermediates for functions in NUT.
+   The prefixes are:
+	am	Analyze meals
+	rm	Record meals aka currentmeal
+*/    
+
+/* An "analysis header" is various info that is not specifically nutrient
+   values:
+   maxmeal is maximum number of meals the user can get no matter how many he
+              asks for
+   mealcount is actual number of meals being analyzed
+   meals_per_day is yes, meals per day
+   firstmeal is earliest meal in the analysis
+   lastmeal is latest meal in the analysis
+   currentmeal is the current meal as specified in the options table
+   caloriebutton - NUT has a calorie button that specifies the calorie DV, so
+                   here it is
+   macropct is the percentages of protein, carbs, and fat calories in the
+               analysis
+   n6balance is the supposed percentages of omega-6 and omega-3 in tissue
+             phospholipids according to William Lands' equation if these fatty
+             acids saturate the phospholipids as they probably do due to
+             excessive omega-6 in modern diets
+*/
+
+drop table if exists am_analysis_header;
+create table am_analysis_header (maxmeal int, mealcount int, meals_per_day int, firstmeal integer, lastmeal integer, currentmeal integer, caloriebutton text, macropct text, n6balance text);
+
+/* This table lists the nutrient and its computed Daily Value or dv.  It also
+   has the cryptically named dvpct_offset which is the percentage by which the
+   actual nutrient value is off from 100% of the DV.  So if you have 99% of the
+   DV for potassium the dvpct_offset is -1.0, if you have 103% the dvpct_offset
+   is 3.0.  So, you get the % of the DV by adding 100.0 to the dvpct_offset.
+*/
+
+drop table if exists am_dv;
+create table am_dv (Nutr_No int primary key asc, dv real, dvpct_offset real);
+    
+drop table if exists rm_analysis_header;
+create table rm_analysis_header (maxmeal int, mealcount int, meals_per_day int, firstmeal integer, lastmeal integer, currentmeal integer, caloriebutton text, macropct text, n6balance text);
+
+drop table if exists rm_analysis;
+create table rm_analysis (Nutr_No int primary key asc, null_value int, Nutr_Val real);
+
+drop table if exists rm_dv;
+create table rm_dv (Nutr_No int primary key asc, dv real, dvpct_offset real);
+
+drop view if exists am_analysis;
+create view am_analysis as select am.Nutr_No as Nutr_No, case when currentmeal between firstmeal and lastmeal and am.null_value = 1 and rm.null_value = 1 then 1 when currentmeal not between firstmeal and lastmeal and am.null_value = 1 then 1 else 0 end as null_value, case when currentmeal between firstmeal and lastmeal then ifnull(am.Nutr_Val,0.0) + 1.0 / mealcount * ifnull(rm.Nutr_Val, 0.0) else am.Nutr_Val end as Nutr_Val from z_anal am left join rm_analysis rm on am.Nutr_No = rm.Nutr_ [...]
+    
+/*
+   PCF is automatic portion control; aka protein/carb/fat which was extended
+   to include all DV nutrients.  The idea is you can control macronutrients
+   per meal, but also include a modicum of micronutrients for which
+   experience has shown that one's diet never achieves the nutrition standard
+   otherwise.  PCF means to adjust the quantity of a particular food to
+   achieve a particular nutrition standard for an entire meal.  PCF processing
+   only applies to the currentmeal and is accomplished by complicated recursive
+   triggers instead of linear algebra.
+
+   Triggers for PCF have to be in "user.sqlite3" because if they are always
+   turned on, it is impossible to do any bulk update of the database.
+*/
+
+/*
+   Some of the triggers need repetitive elements since we don't have
+   a lot of choices for how they flow.  Thus this table is used to
+   to start triggers so we can use the same code in different
+   triggers without literally repeating it in every trigger that
+   needs it
+*/  
+
+drop table if exists z_trig_ctl;
+CREATE TABLE z_trig_ctl(am_analysis_header integer default 0, rm_analysis_header integer default 0, am_analysis_minus_currentmeal integer default 0, am_analysis_null integer default 0, am_analysis integer default 0, rm_analysis integer default 0, rm_analysis_null integer default 0, am_dv integer default 0, PCF_processing integer default 0, block_setting_preferred_weight integer default 0, block_mealfoods_insert_trigger default 0, block_mealfoods_delete_trigger integer default 0);
+insert into z_trig_ctl default values;
+  
+/*
+   Procedures implemented as triggers started by a true bool in z_trig_ctl
+*/  
+
+drop trigger if exists am_analysis_header_trigger;
+CREATE TRIGGER am_analysis_header_trigger after update of am_analysis_header on z_trig_ctl when NEW.am_analysis_header = 1 begin 
+update z_trig_ctl set am_analysis_header = 0;
+delete from am_analysis_header;
+insert into am_analysis_header select (select count(distinct meal_id) from mealfoods) as maxmeal, count(meal_id) as mealcount, meals_per_day, ifnull(min(meal_id),0) as firstmeal, ifnull(max(meal_id),0) as lastmeal, currentmeal, NULL as caloriebutton, NULL as macropct, NULL as n6balance from options left join (select distinct meal_id from mealfoods order by meal_id desc limit (select defanal_am from options));
+end;
+  
+drop trigger if exists rm_analysis_header_trigger;
+CREATE TRIGGER rm_analysis_header_trigger after update of rm_analysis_header on z_trig_ctl when NEW.rm_analysis_header = 1 begin 
+update z_trig_ctl set rm_analysis_header = 0;
+delete from rm_analysis_header;
+insert into rm_analysis_header select maxmeal, case when (select count(*) from mealfoods where meal_id = currentmeal) = 0 then 0 else 1 end as mealcount, meals_per_day, currentmeal as firstmeal, currentmeal as lastmeal, currentmeal as currentmeal, NULL as caloriebutton, NULL as macropct, NULL as n6balance from am_analysis_header;
+end;
+    
+drop trigger if exists am_analysis_minus_currentmeal_trigger;
+CREATE TRIGGER am_analysis_minus_currentmeal_trigger after update of am_analysis_minus_currentmeal on z_trig_ctl when NEW.am_analysis_minus_currentmeal = 1 begin 
+update z_trig_ctl set am_analysis_minus_currentmeal = 0;
+delete from z_anal;
+insert into z_anal select Nutr_No, case when sum(mhectograms * Nutr_Val) is null then 1 else 0 end, ifnull(sum(mhectograms * Nutr_Val), 0.0) from (select NDB_No, total(Gm_Wgt / 100.0 / mealcount * meals_per_day) as mhectograms from mealfoods join am_analysis_header where meal_id between firstmeal and lastmeal and meal_id != currentmeal group by NDB_No) join nutr_def natural left join nut_data group by Nutr_No;
+end;
+  
+/*  We need null triggers because processing is so different when the analysis
+    is null; i.e. there is no food in the analysis.
+
+    Sharp eyes will notice that when the database is pristine before the user
+    has added any meals at all, everything is null and the null processing
+    for z_anal and all the analyses fails to work and instead produces non-null
+    zeros for the analyses.  This is a coding error on my part;
+    however, if you have a GUI and the first thing the user sees on the
+    analysis screen before adding any meals are a bunch of zeros, it actually
+    makes sense to the user that everything is zero rather than some kind of
+    "No Data" indication, so I have not tried to fix these particular errors
+    and I offer them as an intelligent feature.
+*/
+
+drop trigger if exists am_analysis_null_trigger;
+CREATE TRIGGER am_analysis_null_trigger after update of am_analysis_null on z_trig_ctl when NEW.am_analysis_null = 1 begin 
+update z_trig_ctl set am_analysis_null = 0;
+delete from z_anal;
+insert into z_anal select Nutr_No, 0, 0.0 from nutr_def;
+update am_analysis_header set macropct = '0 / 0 / 0', n6balance = '0 / 0';
+end;
+   
+drop trigger if exists rm_analysis_null_trigger;
+CREATE TRIGGER rm_analysis_null_trigger after update of rm_analysis_null on z_trig_ctl when NEW.rm_analysis_null = 1 begin 
+update z_trig_ctl set rm_analysis_null = 0;
+delete from rm_analysis;
+insert into rm_analysis select Nutr_No, 0, 0.0 from nutr_def;
+update rm_analysis_header set caloriebutton = (select caloriebutton from am_analysis_header), macropct = '0 / 0 / 0', n6balance = '0 / 0';
+end;
+
+/* 
+   These triggers are gnarly because many DVs require the results of other DVs
+   so it takes many steps.  And also, figuring the omega-6/3 balance and
+   the essential fatty acid DVs requires division; however, the values
+   themselves are often the divisors so we get division by zero unless we fudge
+   and put a trace of the nutrient in when the value is actually zero.  Plus
+   we need a lot of joins to get all the necessary nutrient values together
+   for computation.
+*/
+  
+drop trigger if exists am_analysis_trigger;
+CREATE TRIGGER am_analysis_trigger after update of am_analysis on z_trig_ctl when NEW.am_analysis = 1 begin 
+update z_trig_ctl set am_analysis = 0;
+update am_analysis_header set macropct = (select cast (ifnull(round(100 * PROT_KCAL.Nutr_Val / ENERC_KCAL.Nutr_Val,0),0) as int) || ' / ' || cast (ifnull(round(100 * CHO_KCAL.Nutr_Val / ENERC_KCAL.Nutr_Val,0),0) as int) || ' / ' || cast (ifnull(round(100 * FAT_KCAL.Nutr_Val / ENERC_KCAL.Nutr_Val,0),0) as int) from am_analysis ENERC_KCAL join am_analysis PROT_KCAL on ENERC_KCAL.Nutr_No = 208 and PROT_KCAL.Nutr_No = 3000 join am_analysis CHO_KCAL on CHO_KCAL.Nutr_No = 3002 join am_analysis [...]
+delete from z_n6;
+insert into z_n6 select NULL, NULL, NULL, 1, 1, 900.0 * case when SHORT3.Nutr_Val > 0.0 then SHORT3.Nutr_Val else 0.000000001 end / case when ENERC_KCAL.Nutr_Val > 0.0 then ENERC_KCAL.Nutr_Val else 0.000000001 end, 900.0 * case when SHORT6.Nutr_Val > 0.0 then SHORT6.Nutr_Val else 0.000000001 end / case when ENERC_KCAL.Nutr_Val > 0.0 then ENERC_KCAL.Nutr_Val else 0.000000001 end, 900.0 * case when LONG3.Nutr_Val > 0.0 then LONG3.Nutr_Val else 0.000000001 end / case when ENERC_KCAL.Nutr_Va [...]
+update am_analysis_header set n6balance = (select case when n6hufa_int = 0 or n6hufa_int is null then 0 when n6hufa_int between 1 and 14 then 15 when n6hufa_int > 90 then 90 else n6hufa_int end || ' / ' || (100 - case when n6hufa_int = 0 then 100 when n6hufa_int between 1 and 14 then 15 when n6hufa_int > 90 then 90 else n6hufa_int end) from (select cast (round(n6hufa,0) as int) as n6hufa_int from z_n6));
+update am_analysis_header set n6balance = case when n6balance is null then '0 / 0' else n6balance end;
+end;
+
+drop trigger if exists rm_analysis_trigger;
+CREATE TRIGGER rm_analysis_trigger after update of rm_analysis on z_trig_ctl when NEW.rm_analysis = 1 begin 
+update z_trig_ctl set rm_analysis = 0;
+delete from rm_analysis;
+insert into rm_analysis select Nutr_No, case when sum(mhectograms * Nutr_Val) is null then 1 else 0 end, ifnull(sum(mhectograms * Nutr_Val), 0.0) from (select NDB_No, total(Gm_Wgt / 100.0 * meals_per_day) as mhectograms from mealfoods join am_analysis_header where meal_id = currentmeal group by NDB_No) join nutr_def natural left join nut_data group by Nutr_No;
+update rm_analysis_header set caloriebutton = (select caloriebutton from am_analysis_header), macropct = (select cast (ifnull(round(100 * PROT_KCAL.Nutr_Val / ENERC_KCAL.Nutr_Val,0),0) as int) || ' / ' || cast (ifnull(round(100 * CHO_KCAL.Nutr_Val / ENERC_KCAL.Nutr_Val,0),0) as int) || ' / ' || cast (ifnull(round(100 * FAT_KCAL.Nutr_Val / ENERC_KCAL.Nutr_Val,0),0) as int) from rm_analysis ENERC_KCAL join rm_analysis PROT_KCAL on ENERC_KCAL.Nutr_No = 208 and PROT_KCAL.Nutr_No = 3000 join  [...]
+delete from z_n6;
+insert into z_n6 select NULL, NULL, NULL, 1, 1, 900.0 * case when SHORT3.Nutr_Val > 0.0 then SHORT3.Nutr_Val else 0.000000001 end / case when ENERC_KCAL.Nutr_Val > 0.0 then ENERC_KCAL.Nutr_Val else 0.000000001 end, 900.0 * case when SHORT6.Nutr_Val > 0.0 then SHORT6.Nutr_Val else 0.000000001 end / case when ENERC_KCAL.Nutr_Val > 0.0 then ENERC_KCAL.Nutr_Val else 0.000000001 end, 900.0 * case when LONG3.Nutr_Val > 0.0 then LONG3.Nutr_Val else 0.000000001 end / case when ENERC_KCAL.Nutr_Va [...]
+update rm_analysis_header set n6balance = (select case when n6hufa_int = 0 or n6hufa_int is null then 0 when n6hufa_int between 1 and 14 then 15 when n6hufa_int > 90 then 90 else n6hufa_int end || ' / ' || (100 - case when n6hufa_int = 0 then 100 when n6hufa_int between 1 and 14 then 15 when n6hufa_int > 90 then 90 else n6hufa_int end) from (select cast (round(n6hufa,0) as int) as n6hufa_int from z_n6));
+end;
+
+drop trigger if exists am_dv_trigger;
+CREATE TRIGGER am_dv_trigger after update of am_dv on z_trig_ctl when NEW.am_dv = 1 begin 
+update z_trig_ctl set am_dv = 0;
+delete from am_dv;
+insert into am_dv select Nutr_No, dv, 100.0 * Nutr_Val / dv - 100.0 from (select Nutr_No, Nutr_Val, case when nutopt = 0.0 then dv_default when nutopt = -1.0 and Nutr_Val > 0.0 then Nutr_Val when nutopt = -1.0 and Nutr_Val <= 0.0 then dv_default else nutopt end as dv from nutr_def natural join am_analysis where dv_default > 0.0 and (Nutr_No = 208 or Nutr_No between 301 and 601 or Nutr_No = 2008));
+insert into am_dv select Nutr_No, dv, 100.0 * Nutr_Val / dv - 100.0 from (select Nutr_No, Nutr_Val, case when nutopt = 0.0 then (select Nutr_Val from am_analysis where Nutr_No = 208) / 2000.0 * dv_default when nutopt = -1.0 and Nutr_Val > 0.0 then Nutr_Val when nutopt = -1.0 and Nutr_Val <= 0.0 then (select Nutr_Val from am_analysis where Nutr_No = 208) / 2000.0 * dv_default else nutopt end as dv from nutr_def natural join am_analysis where Nutr_No = 291);
+delete from z_vars1;
+insert into z_vars1 select ifnull(PROT_KCAL.Nutr_Val / PROCNT.Nutr_Val, 4.0), ifnull(FAT_KCAL.Nutr_Val / FAT.Nutr_Val, 9.0), ifnull(CHO_KCAL.Nutr_Val / CHOCDF.Nutr_Val, 4.0), ifnull(ALC.Nutr_Val * 6.93, 0.0), ifnull((FASAT.Nutr_Val + FAMS.Nutr_Val + FAPU.Nutr_Val) / FAT.Nutr_Val, 0.94615385), case when ENERC_KCALopt.nutopt = -1 then 208 when FATopt.nutopt <= 0.0 and CHO_NONFIBopt.nutopt = 0.0 then 2000 else 204 end from am_analysis PROT_KCAL join am_analysis PROCNT on PROT_KCAL.Nutr_No = [...]
+insert into am_dv select Nutr_No, dv, 100.0 * Nutr_Val / dv - 100.0 from (select PROCNTnd.Nutr_No, case when (PROCNTnd.nutopt = 0.0 and ENERC_KCAL.dv > 0.0) or (PROCNTnd.nutopt = -1.0 and PROCNT.Nutr_Val <= 0.0) then 0.1 * ENERC_KCAL.dv / am_cals2gram_pro when PROCNTnd.nutopt > 0.0 then PROCNTnd.nutopt else PROCNT.Nutr_Val end as dv, PROCNT.Nutr_Val from nutr_def PROCNTnd natural join am_analysis PROCNT join z_vars1 join am_dv ENERC_KCAL on ENERC_KCAL.Nutr_No = 208 where PROCNTnd.Nutr_No [...]
+delete from z_vars2;
+insert into z_vars2 select am_fat_dv_not_boc, am_cho_nonfib_dv_not_boc, am_cho_nonfib_dv_not_boc + FIBTGdv from (select case when FATnd.nutopt = -1 and FAT.Nutr_Val > 0.0 then FAT.Nutr_Val when FATnd.nutopt > 0.0 then FATnd.nutopt else ENERC_KCAL.dv * 0.3 / am_cals2gram_fat end as am_fat_dv_not_boc, case when CHO_NONFIBnd.nutopt = -1 and CHO_NONFIB.Nutr_Val > 0.0 then CHO_NONFIB.Nutr_Val when CHO_NONFIBnd.nutopt > 0.0 then CHO_NONFIBnd.nutopt else (ENERC_KCAL.dv * 0.6 / am_cals2gram_cho) [...]
+delete from z_vars3;
+insert into z_vars3 select am_fat_dv_boc, am_chocdf_dv_boc, am_chocdf_dv_boc - FIBTGdv from (select (ENERC_KCAL.dv - (PROCNT.dv * am_cals2gram_pro) - (am_chocdf_dv_not_boc * am_cals2gram_cho)) / am_cals2gram_fat as am_fat_dv_boc, (ENERC_KCAL.dv - (PROCNT.dv * am_cals2gram_pro) - (am_fat_dv_not_boc * am_cals2gram_fat)) / am_cals2gram_cho as am_chocdf_dv_boc, FIBTG.dv as FIBTGdv from z_vars1 join z_vars2 join am_dv ENERC_KCAL on ENERC_KCAL.Nutr_No = 208 join am_dv PROCNT on PROCNT.Nutr_No  [...]
+insert into am_dv select Nutr_No, case when balance_of_calories = 204 then am_fat_dv_boc else am_fat_dv_not_boc end, case when balance_of_calories = 204 then 100.0 * Nutr_Val / am_fat_dv_boc - 100.0 else 100.0 * Nutr_Val / am_fat_dv_not_boc - 100.0 end from z_vars1 join z_vars2 join z_vars3 join nutr_def on Nutr_No = 204 natural join am_analysis;
+insert into am_dv select Nutr_No, case when balance_of_calories = 2000 then am_cho_nonfib_dv_boc else am_cho_nonfib_dv_not_boc end, case when balance_of_calories = 2000 then 100.0 * Nutr_Val / am_cho_nonfib_dv_boc - 100.0 else 100.0 * Nutr_Val / am_cho_nonfib_dv_not_boc - 100.0 end from z_vars1 join z_vars2 join z_vars3 join nutr_def on Nutr_No = 2000 natural join am_analysis;
+insert into am_dv select Nutr_No, case when balance_of_calories = 2000 then am_chocdf_dv_boc else am_chocdf_dv_not_boc end, case when balance_of_calories = 2000 then 100.0 * Nutr_Val / am_chocdf_dv_boc - 100.0 else 100.0 * Nutr_Val / am_chocdf_dv_not_boc - 100.0 end from z_vars1 join z_vars2 join z_vars3 join nutr_def on Nutr_No = 205 natural join am_analysis;
+insert into am_dv select FASATnd.Nutr_No, case when FASATnd.nutopt = -1.0 and FASAT.Nutr_Val > 0.0 then FASAT.Nutr_Val when FASATnd.nutopt > 0.0 then FASATnd.nutopt else ENERC_KCAL.dv / 2000.0 * FASATnd.dv_default end, case when FASATnd.nutopt = -1.0 and FASAT.Nutr_Val > 0.0 then 0.0 when FASATnd.nutopt > 0.0 then 100.0 * FASAT.Nutr_Val / FASATnd.nutopt - 100.0 else 100.0 * FASAT.Nutr_Val / (ENERC_KCAL.dv / 2000.0 * FASATnd.dv_default) - 100.0 end from z_vars1 join nutr_def FASATnd on FA [...]
+insert into am_dv select FAPUnd.Nutr_No, case when FAPUnd.nutopt = -1.0 and FAPU.Nutr_Val > 0.0 then FAPU.Nutr_Val when FAPUnd.nutopt > 0.0 then FAPUnd.nutopt else ENERC_KCAL.dv * 0.04 / am_cals2gram_fat end, case when FAPUnd.nutopt = -1.0 and FAPU.Nutr_Val > 0.0 then 0.0 when FAPUnd.nutopt > 0.0 then 100.0 * FAPU.Nutr_Val / FAPUnd.nutopt - 100.0 else 100.0 * FAPU.Nutr_Val / (ENERC_KCAL.dv * 0.04 / am_cals2gram_fat) - 100.0 end from z_vars1 join nutr_def FAPUnd on FAPUnd.Nutr_No = 646 jo [...]
+insert into am_dv select FAMSnd.Nutr_No, (FAT.dv * am_fa2fat) - FASAT.dv - FAPU.dv, 100.0 * FAMS.Nutr_Val / ((FAT.dv * am_fa2fat) - FASAT.dv - FAPU.dv) - 100.0 from z_vars1 join am_dv FAT on FAT.Nutr_No = 204 join am_dv FASAT on FASAT.Nutr_No = 606 join am_dv FAPU on FAPU.Nutr_No = 646 join nutr_def FAMSnd on FAMSnd.Nutr_No = 645 join am_analysis FAMS on FAMS.Nutr_No = 645;
+delete from z_n6;
+insert into z_n6 select NULL, case when FAPU1 = 0.0 then 50.0 when FAPU1 < 15.0 then 15.0 when FAPU1 > 90.0 then 90.0 else FAPU1 end, case when FAPUval.Nutr_Val / FAPU.dv >= 1.0 then FAPUval.Nutr_Val / FAPU.dv else 1.0 end, 1, 0, 900.0 * case when SHORT3.Nutr_Val > 0.0 then SHORT3.Nutr_Val else 0.000000001 end / ENERC_KCAL.dv, 900.0 * case when SHORT6.Nutr_Val > 0.0 then SHORT6.Nutr_Val else 0.000000001 end / ENERC_KCAL.dv / case when FAPUval.Nutr_Val / FAPU.dv >= 1.0 then FAPUval.Nutr_V [...]
+delete from z_vars4;
+insert into z_vars4 select Nutr_No, case when Nutr_Val > 0.0 and reduce = 3 then Nutr_Val / pufa_reduction when Nutr_Val > 0.0 and reduce = 6 then Nutr_Val / pufa_reduction - Nutr_Val / pufa_reduction * 0.01 * (iter - 1) else dv_default end, Nutr_Val from nutr_def natural join am_analysis join z_n6 where Nutr_No in (2006, 2001, 2002);
+insert into z_vars4 select Nutr_No, case when Nutr_Val > 0.0 and reduce = 6 then Nutr_Val when Nutr_Val > 0.0 and reduce = 3 then Nutr_Val - Nutr_Val * 0.01 * (iter - 2) else dv_default end, Nutr_Val from nutr_def natural join am_analysis join z_n6 where Nutr_No in (2007, 2003, 2004, 2005);
+insert into am_dv select Nutr_No, dv, 100.0 * Nutr_Val / dv - 100.0 from z_vars4;
+update am_analysis_header set caloriebutton = 'Calories (' || (select cast (round(dv) as int) from am_dv where Nutr_No = 208) || ')';
+delete from rm_dv;
+insert into rm_dv select Nutr_No, dv, 100.0 * Nutr_Val / dv - 100.0 from rm_analysis natural join am_dv;
+insert or replace into mealfoods select meal_id, NDB_No, Gm_Wgt - dv * dvpct_offset / (select meals_per_day from options) / Nutr_Val, Nutr_No from rm_dv natural join nut_data natural join mealfoods where abs(dvpct_offset) > 0.001 order by abs(dvpct_offset) desc limit 1;
+end;
+
+/*
+  This view is NUT's idea how to update mealfoods to achieve portion control.
+  We need it now because it is referenced in the following trigger.
+*/
+
+drop view if exists z_pcf;
+create view z_pcf as select meal_id, 
+NDB_No, Gm_Wgt + dv / meals_per_day * dvpct_offset / Nutr_Val * -1.0 as Gm_Wgt, Nutr_No
+from mealfoods natural join rm_dv natural join nut_data join options 
+where abs(dvpct_offset) >= 0.05 order by abs(dvpct_offset);
+
+drop trigger if exists PCF_processing;
+CREATE TRIGGER PCF_processing after update of PCF_processing on z_trig_ctl when NEW.PCF_processing = 1 begin 
+update z_trig_ctl set PCF_processing = 0;
+replace into mealfoods select * from z_pcf limit 1;
+update z_trig_ctl set block_mealfoods_delete_trigger = 0;
+end;
+  
+/*
+   Now start the actual triggers that kick off when something happens.
+   They replay the previous procedures as required by the different
+   circumstances that update the appropriate column in z_trig_ctl to true.
+*/  
+
+/*
+   Update to defanal_am in options (number of meals to analyze)
+   so we need to rewrite the am_analysis and am_dv and thus practically
+   everything
+*/
+  
+drop trigger if exists defanal_am_trigger;
+CREATE TRIGGER defanal_am_trigger after update of defanal_am on options begin 
+update z_trig_ctl set am_analysis_header = 1;
+update z_trig_ctl set am_analysis_minus_currentmeal = case when (select mealcount from am_analysis_header) > 1 then 1 when (select mealcount from am_analysis_header) = 1 and (select lastmeal from am_analysis_header) != (select currentmeal from am_analysis_header) then 1 else 0 end;
+update z_trig_ctl set am_analysis_null = case when (select mealcount from am_analysis_header) > 1 then 0 when (select mealcount from am_analysis_header) = 1 and (select lastmeal from am_analysis_header) != (select currentmeal from am_analysis_header) then 0 else 1 end;
+update z_trig_ctl set am_analysis = 1;
+update z_trig_ctl set am_dv = 1;
+update z_trig_ctl set PCF_processing = 1;
+end;
+  
+/*
+   Update to currentmeal in options
+   so we need to rewrite practically everything
+*/  
+
+drop trigger if exists currentmeal_trigger;
+CREATE TRIGGER currentmeal_trigger after update of currentmeal on options begin 
+update mealfoods set Nutr_No = null where Nutr_No is not null;
+update z_trig_ctl set am_analysis_header = 1;
+update z_trig_ctl set am_analysis_minus_currentmeal = case when (select mealcount from am_analysis_header) > 1 then 1 when (select mealcount from am_analysis_header) = 1 and (select lastmeal from am_analysis_header) != (select currentmeal from am_analysis_header) then 1 else 0 end;
+update z_trig_ctl set am_analysis_null = case when (select mealcount from am_analysis_header) > 1 then 0 when (select mealcount from am_analysis_header) = 1 and (select lastmeal from am_analysis_header) != (select currentmeal from am_analysis_header) then 0 else 1 end;
+update z_trig_ctl set rm_analysis_header = 1;
+update z_trig_ctl set rm_analysis = case when (select mealcount from rm_analysis_header) = 1 then 1 else 0 end;
+update z_trig_ctl set rm_analysis_null = case when (select mealcount from rm_analysis_header) = 0 then 1 else 0 end;
+update z_trig_ctl set am_analysis = 1;
+update z_trig_ctl set am_dv = 1;
+end;
+  
+/*
+   Input: table z_n6 to compute column n6hufa
+   Output column:  n6hufa
+   Purpose:  First step to set reference value for essential fatty acids
+             Compute Lands' n6hufa % and set up for following triggers to
+             determine reference values
+*/
+ 
+drop trigger if exists z_n6_insert_trigger;
+CREATE TRIGGER z_n6_insert_trigger after insert on z_n6 begin 
+update z_n6 set n6hufa = (select 100.0 / (1.0 + 0.0441 / p6 * (1.0 + p3 / 0.0555 + h3 / 0.005 + o / 5.0 + p6 / 0.175)) + 100.0 / (1.0 + 0.7 / h6 * (1.0 + h3 / 3.0))), reduce = 0, iter = 0;
+end;
+    
+/*
+   Input:  If column "reduce" is set right, this trigger recursively
+           subtracts omega-6 fatty acids to produce n6hufa numbers to match the
+           option for Omega-6/3 balance
+   Output:  recursive
+   Purpose:  determine daily values for n-6 when we know n-6 is excessive
+             because n6hufa > target FAPU1 from options
+*/
+
+drop trigger if exists z_n6_reduce6_trigger;
+CREATE TRIGGER z_n6_reduce6_trigger after update on z_n6 when NEW.n6hufa > OLD.FAPU1 and NEW.iter < 100 and NEW.reduce in (0, 6) begin 
+update z_n6 set iter = iter + 1, reduce = 6, n6hufa = (select 100.0 / (1.0 + 0.0441 / (p6 - iter * .01 * p6) * (1.0 + p3 / 0.0555 + h3 / 0.005 + o / 5.0 + p6 / 0.175)) + 100.0 / (1.0 + 0.7 / (h6 - iter * .01 * h6) * (1.0 + h3 / 3.0)));
+end;
+    
+/*
+   Input:  If column "reduce" is set right, this trigger recursively
+           subtracts omega-3 fatty acids to produce n6hufa numbers to match the
+           option for Omega-6/3 balance
+   Output:  recursive
+   Purpose:  determine daily values for n-3 when we know n-3 is excessive
+             because n6hufa < target FAPU1
+*/
+  
+drop trigger if exists z_n6_reduce3_trigger;
+CREATE TRIGGER z_n6_reduce3_trigger after update of n6hufa on z_n6 when NEW.n6hufa < OLD.FAPU1 and NEW.iter < 100 and NEW.reduce in (0, 3) begin 
+update z_n6 set iter = iter + 1, reduce = 3, n6hufa = (select 100.0 / (1.0 + 0.0441 / p6 * (1.0 + (p3 - iter * .01 * p3) / 0.0555 + (h3 - iter * .01 * h3) / 0.005 + o / 5.0 + p6 / 0.175)) + 100.0 / (1.0 + 0.7 / h6 * (1.0 + (h3 - iter * .01 * h3) / 3.0)));
+end;
+    
+/*
+  First insert into currentmeal is special because it changes everything!
+*/
+
+drop trigger if exists insert_mealfoods_trigger;
+ 
+CREATE TRIGGER insert_mealfoods_trigger after insert on mealfoods when NEW.meal_id = (select currentmeal from options) and (select count(*) from mealfoods where meal_id = NEW.meal_id) = 1 begin 
+update z_trig_ctl set am_analysis_header = 1;
+update z_trig_ctl set am_analysis_minus_currentmeal = case when (select mealcount from am_analysis_header) > 1 then 1 when (select mealcount from am_analysis_header) = 1 and (select lastmeal from am_analysis_header) != (select currentmeal from am_analysis_header) then 1 else 0 end;
+update z_trig_ctl set am_analysis_null = case when (select mealcount from am_analysis_header) > 1 then 0 when (select mealcount from am_analysis_header) = 1 and (select lastmeal from am_analysis_header) != (select currentmeal from am_analysis_header) then 0 else 1 end;
+update z_trig_ctl set rm_analysis_header = 1;
+update z_trig_ctl set rm_analysis = case when (select mealcount from rm_analysis_header) = 1 then 1 else 0 end;
+update z_trig_ctl set rm_analysis_null = case when (select mealcount from rm_analysis_header) = 0 then 1 else 0 end;
+update z_trig_ctl set am_analysis = 1;
+update z_trig_ctl set am_dv = 1;
+end;
+  
+/*
+  Last delete from currentmeal is special because it changes everything!
+*/
+  
+drop trigger if exists delete_mealfoods_trigger;
+CREATE TRIGGER delete_mealfoods_trigger after delete on mealfoods when OLD.meal_id = (select currentmeal from options) and (select count(*) from mealfoods where meal_id = OLD.meal_id) = 0 begin 
+update mealfoods set Nutr_No = null where Nutr_No is not null;
+update z_trig_ctl set am_analysis_header = 1;
+update z_trig_ctl set am_analysis_minus_currentmeal = case when (select mealcount from am_analysis_header) > 1 then 1 when (select mealcount from am_analysis_header) = 1 and (select lastmeal from am_analysis_header) != (select currentmeal from am_analysis_header) then 1 else 0 end;
+update z_trig_ctl set am_analysis_null = case when (select mealcount from am_analysis_header) > 1 then 0 when (select mealcount from am_analysis_header) = 1 and (select lastmeal from am_analysis_header) != (select currentmeal from am_analysis_header) then 0 else 1 end;
+update z_trig_ctl set rm_analysis_header = 1;
+update z_trig_ctl set rm_analysis = case when (select mealcount from rm_analysis_header) = 1 then 1 else 0 end;
+update z_trig_ctl set rm_analysis_null = case when (select mealcount from rm_analysis_header) = 0 then 1 else 0 end;
+update z_trig_ctl set am_analysis = 1;
+update z_trig_ctl set am_dv = 1;
+end;
+  
+/*
+  Input: mealfoods modified Gm_Wgt
+  Output: weight Gm_Wgt
+  Purpose:  NUT remembers user serving size preference in first weight record
+            when ordered by Seq (although origSeq is the actual key).
+*/
+    
+drop trigger if exists update_mealfoods2weight_trigger;
+CREATE TRIGGER update_mealfoods2weight_trigger AFTER UPDATE ON mealfoods when NEW.Gm_Wgt > 0.0 and (select block_setting_preferred_weight from z_trig_ctl) = 0 BEGIN 
+update weight set Gm_Wgt = NEW.Gm_Wgt where NDB_No = NEW.NDB_No and Seq = (select min(Seq) from weight where NDB_No = NEW.NDB_No) ;
+end;
+    
+drop trigger if exists insert_mealfoods2weight_trigger;
+CREATE TRIGGER insert_mealfoods2weight_trigger AFTER INSERT ON mealfoods when NEW.Gm_Wgt > 0.0 and (select block_setting_preferred_weight from z_trig_ctl) = 0 BEGIN 
+update weight set Gm_Wgt = NEW.Gm_Wgt where NDB_No = NEW.NDB_No and Seq = (select min(Seq) from weight where NDB_No = NEW.NDB_No) ;
+end;
+    
+    
+/*
+  If you follow the weight saga so far, you realize that if the user wants to
+  always see a different serving unit, you have to change the Seq to 0 for that
+  record.  Here is a convenience trigger that changes the current Seq = 0
+  record back to the original Seq immediately before the change so you don't
+  have to explicitly do it:
+*/
+
+drop trigger if exists update_weight_Seq;
+create trigger update_weight_Seq BEFORE update of Seq on weight when NEW.Seq = 0 BEGIN
+update weight set Seq = origSeq, Gm_Wgt = origGm_Wgt where NDB_No = NEW.NDB_No;
+end;
+
+/*
+  Now we need some stuff to support the weight log mini-application.  First,
+  a view to figure the slope and y-intercept of uncleared weight records.
+  The slope is the average daily weight gain or loss in the user's units,
+  whatever they might be; the y-intercept is the prediction for today; and
+  finally we present "n" which is the sample count.  We use linear regression
+  to get all these values.
+*/
+
+drop view if exists z_wslope;
+CREATE VIEW z_wslope as select ifnull(weightslope,0.0) as "weightslope", ifnull(round(sumy / n - weightslope * sumx / n,1),0.0) as "weightyintercept", n as "weightn" from (select (sumxy - (sumx * sumy / n)) / (sumxx - (sumx * sumx / n)) as weightslope, sumy, n, sumx from (select sum(x) as sumx, sum(y) as sumy, sum(x*y) as sumxy, sum(x*x) as sumxx, n from (select cast (cast (julianday(substr(wldate,1,4) || '-' || substr(wldate,5,2) || '-' || substr(wldate,7,2)) - julianday('now', 'localti [...]
+
+/*
+  Basically the same thing for the slope, y-intercept, and "n" of fat mass.
+*/
+
+drop view if exists z_fslope;
+CREATE VIEW z_fslope as select ifnull(fatslope,0.0) as "fatslope", ifnull(round(sumy / n - fatslope * sumx / n,1),0.0) as "fatyintercept", n as "fatn" from (select (sumxy - (sumx * sumy / n)) / (sumxx - (sumx * sumx / n)) as fatslope, sumy, n, sumx from (select sum(x) as sumx, sum(y) as sumy, sum(x*y) as sumxy, sum(x*x) as sumxx, n from (select cast (cast (julianday(substr(wldate,1,4) || '-' || substr(wldate,5,2) || '-' || substr(wldate,7,2)) - julianday('now', 'localtime') as int) as re [...]
+
+/*
+  In our computations we not only need the number of samples, we also need the
+  "span" which enumerates how many days from the first measurement to the
+  present.
+*/
+
+drop view if exists z_span;
+create view z_span as select abs(min(cast (julianday(substr(wldate,1,4) || '-' || substr(wldate,5,2) || '-' || substr(wldate,7,2)) - julianday('now', 'localtime') as int))) as span from z_wl where cleardate is null;
+
+/*
+  Here's the user's view of the weight log which we provide only so we can
+  control inserts.
+*/
+
+drop view if exists wlog;
+create view wlog as select * from z_wl;
+
+/*
+  Insert to wlog.  User supplies weight and bodyfat percentage plus two
+  nulls, but we supply today's date.
+*/
+
+drop trigger if exists wlog_insert;
+create trigger wlog_insert instead of insert on wlog begin
+insert or replace into z_wl values (NEW.weight, NEW.bodyfat, (select strftime('%Y%m%d', 'now', 'localtime')), null);
+end;
+
+/*
+  Here's the user's view of the weight log with some additional interesting
+  columns.
+*/
+
+drop view if exists wlview;
+CREATE VIEW wlview as select wldate, weight, bodyfat, round(weight - weight * bodyfat / 100, 1) as leanmass, round(weight * bodyfat / 100, 1) as fatmass, round(weight - 2 * weight * bodyfat / 100) as bodycomp, cleardate from z_wl;
+
+/*
+  Here's the verbiage associated with analysis of the user's measurements.
+*/
+
+drop view if exists wlsummary;
+create view wlsummary as select case 
+when (select weightn from z_wslope) > 1 then
+'Weight:  ' || (select round(weightyintercept,1) from z_wslope) || char(13) || char(10) ||
+'Bodyfat:  ' || case when (select weightyintercept from z_wslope) > 0.0 then round(1000.0 * (select fatyintercept from z_fslope) / (select weightyintercept from z_wslope)) / 10.0 else 0.0 end || '%' || char(13) || char(10)
+when (select weightn from z_wslope) = 1 then
+'Weight:  ' || (select weight from z_wl where cleardate is null) || char(13) || char(10) || 
+'Bodyfat:  ' || (select bodyfat from z_wl where cleardate is null) || '%'
+else 
+'Weight:  0.0' || char(13) || char(10) || 
+'Bodyfat:  0.0%'
+end || char(13) || char(10) ||
+'Today' || "'" || 's Calorie level = ' || (select cast(round(nutopt) as int) from nutr_def where Nutr_No = 208)
+|| char(13) || char(10)
+|| char(13) || char(10) ||
+case when (select weightn from z_wslope) = 0 then '0 data points so far...' 
+when (select weightn from z_wslope) = 1 then '1 data point so far...' 
+else
+'Based on the trend of ' || (select cast(cast(weightn as int) as text) from z_wslope) || ' data points so far...' || char(13) || char(10) || char(10) ||
+'Predicted lean mass today = ' ||
+(select cast(round(10.0 * (weightyintercept - fatyintercept)) / 10.0 as text) from z_wslope, z_fslope) || char(13) || char(10) ||
+'Predicted fat mass today  =  ' ||
+(select cast(round(fatyintercept, 1) as text) from z_fslope) || char(13) || char(10) || char(10) ||
+'If the predictions are correct, you ' ||
+case when (select weightslope - fatslope from z_wslope, z_fslope) >= 0.0 then 'gained ' else 'lost ' end ||
+(select cast(abs(round((weightslope - fatslope) * span * 1000.0) / 1000.0) as text) from z_wslope, z_fslope, z_span) ||
+' lean mass over ' ||
+(select span from z_span) || 
+case when (select span from z_span) = 1 then ' day' else ' days' end || char(13) || char(10) ||
+case when (select fatslope from z_fslope) >= 0.0 then 'and gained ' else 'and lost ' end ||
+(select cast(abs(round(fatslope * span * 1000.0) / 1000.0) as text) from z_fslope, z_span) || ' fat mass.'
+
+end
+as verbiage;
+
+/*
+  The user indicates he wants to clear the weight log
+  with an "insert into wlsummary select 'clear'" but we only actually clear if
+  the user is not using the calorie autoset feature.
+*/
+
+drop trigger if exists clear_wlsummary;
+create trigger clear_wlsummary instead of insert on wlsummary
+when (select autocal from options) = 0
+begin
+update z_wl set cleardate = (select strftime('%Y%m%d', 'now', 'localtime'))
+where cleardate is null;
+insert into z_wl select weight, bodyfat, wldate, null from z_wl
+where wldate = (select max(wldate) from z_wl);
+end;
+
+/*
+  When the user takes the autocal function, we initialize wltweak, a boolean
+  that indicates if calorie level has been "tweaked" and wlpolarity, a boolean
+  that bounces between true and false to balance bias between fat mass loss
+  and lean mass gain.
+
+  Note:  These bools are not operative in the current version of autocl.
+*/
+
+drop trigger if exists autocal_initialization;
+create trigger autocal_initialization after update of autocal on options
+when NEW.autocal in (1, 2, 3) and OLD.autocal not in (1, 2, 3)
+begin
+update options set wltweak = 0, wlpolarity = 0;
+end;
+
+/*
+  Updating meals_per_day on options results in archiving the meals at the old
+  meals_per_day and restoring meals archived from the new meals_per_day
+*/
+
+drop trigger if exists mpd_archive;
+create trigger mpd_archive after update of meals_per_day on options
+when NEW.meals_per_day != OLD.meals_per_day
+begin
+insert or ignore into archive_mealfoods select meal_id, NDB_No, Gm_Wgt, OLD.meals_per_day from mealfoods;
+delete from mealfoods;
+insert or ignore into mealfoods select meal_id, NDB_No, Gm_Wgt, null from archive_mealfoods where meals_per_day = NEW.meals_per_day;
+delete from archive_mealfoods where meals_per_day = NEW.meals_per_day;
+end;
+
+/*
+  Now we're done with setting it all up and we need to initialize after the load
+  because NUT expects the analysis to already be there when it comes up.
+  So, write the first analysis after a USDA load and initialize nutopts if
+  necessary.
+*/
+  
+update nutr_def set nutopt = 0.0 where nutopt is null;
+update options set currentmeal = case when currentmeal is null then 0 else currentmeal end;
+update options set defanal_am = case when defanal_am is null then 0 else defanal_am end;
+    
+/* 
+  SQLite supposedly performs better if it has analyzed how big the tables are
+*/
+
+commit;
+analyze main;
+
+/*
+  End of NUT application logic implemented by SQL tables and triggers
+*/
diff --git a/bigNUT/meal.sqlite3 b/bigNUT/meal.sqlite3
new file mode 100644
index 0000000..8a7365c
--- /dev/null
+++ b/bigNUT/meal.sqlite3
@@ -0,0 +1,5 @@
+/*
+  This is the screen I look at when editing or viewing the current meal.
+*/
+
+select * from shopview; select * from currentmeal; select * from am_analysis_header;
diff --git a/bigNUT/nextday.sqlite3 b/bigNUT/nextday.sqlite3
new file mode 100644
index 0000000..5e2af25
--- /dev/null
+++ b/bigNUT/nextday.sqlite3
@@ -0,0 +1,40 @@
+/*
+  Custom script to add next day's meals automatically.  Invoke it thus:
+	.read nextday.sqlite3
+*/
+
+begin;
+drop table if exists meal_add_list;
+create temp table meal_add_list (n integer primary key, meal_id integer, meal_name text);
+with meallist as (
+ with idbase as (
+  with nextday as (
+   with formattedld as (
+    with lastday as (select max(meal_id) / 100 from mealfoods)
+    select
+    substr( (select * from lastday), 1, 4 ) || '-' ||
+    substr( (select * from lastday), 5, 2 ) || '-' ||
+    substr( (select * from lastday), 7, 2 )
+    )
+   select date( (select * from formattedld), '+1 day')
+   )
+  select
+  substr( (select * from nextday), 1, 4 ) ||
+  substr( (select * from nextday), 6, 2 ) ||
+  substr( (select * from nextday), 9, 2 )
+  )
+ select (select * from idbase) * 100 + 1, 'BC' union
+ select (select * from idbase) * 100 + 2, 'DC' union
+ select (select * from idbase) * 100 + 3, 'SC'
+ )
+insert into meal_add_list select null, * from meallist;
+
+update options set currentmeal = (select meal_id from meal_add_list where n = 1);
+insert into currentmeal select NDB_No, Gm_Wgt, NutrDesc from theusual where meal_name = (select meal_name from meal_add_list where n = 1);
+update options set currentmeal = (select meal_id from meal_add_list where n = 2);
+insert into currentmeal select NDB_No, Gm_Wgt, NutrDesc from theusual where meal_name = (select meal_name from meal_add_list where n = 2);
+update options set currentmeal = (select meal_id from meal_add_list where n = 3);
+insert into currentmeal select NDB_No, Gm_Wgt, NutrDesc from theusual where meal_name = (select meal_name from meal_add_list where n = 3);
+
+drop table meal_add_list;
+commit;
diff --git a/bigNUT/nextmeal.sqlite3 b/bigNUT/nextmeal.sqlite3
new file mode 100644
index 0000000..bdd60ce
--- /dev/null
+++ b/bigNUT/nextmeal.sqlite3
@@ -0,0 +1,27 @@
+/*
+  Custom script to add next meal automatically.  Invoke it thus:
+	.read nextmeal.sqlite3
+*/
+
+begin;
+
+with newcm (meal_id) as (
+ with cm1 (base, meal) as (
+  with cm (base, meal) as (
+   select currentmeal / 100, currentmeal % 100 from options
+   )
+  select case when meal = 3 then date(substr(base, 1, 4) || '-' || substr(base, 5, 2) || '-' || substr(base, 7, 2), '+1 day') else substr(base, 1, 4) || '-' || substr(base, 5, 2) || '-' || substr(base, 7, 2) end, case when meal = 3 then 1 else meal + 1 end from cm
+  )
+ select cast( substr(base, 1, 4) || substr(base, 6, 2) || substr(base, 9, 2) as int) * 100 + meal from cm1
+ )
+update options set currentmeal = (select meal_id from newcm);
+
+with meal_name (mn) as (
+ with meal (m) as (
+  select currentmeal % 100 from options
+  )
+ select case when m = 1 then 'BC' when m = 2 then 'DC' else 'SC' end from meal
+ )
+insert into currentmeal select NDB_No, Gm_Wgt, NutrDesc from theusual where meal_name = (select mn from meal_name);
+
+commit;
diff --git a/bigNUT/ranalysis.sqlite3 b/bigNUT/ranalysis.sqlite3
new file mode 100644
index 0000000..173144e
--- /dev/null
+++ b/bigNUT/ranalysis.sqlite3
@@ -0,0 +1,5 @@
+/*
+  This is the select that I use to look at the nutrient values for the current meal.
+*/
+
+select NutrDesc, round(Nutr_Val, 1) || ' ' || Units, cast(cast(round(100.0 + dvpct_offset) as int) as text) || '%' from rm_analysis natural join rm_dv natural join nutr_def order by dvpct_offset desc;
diff --git a/bigNUT/user.sqlite3 b/bigNUT/user.sqlite3
new file mode 100644
index 0000000..3be9c93
--- /dev/null
+++ b/bigNUT/user.sqlite3
@@ -0,0 +1,416 @@
+/*
+  User initiated stuff goes here.  The following PRAGMA is essential at each
+  invocation, but most of the stuff in this file isn't necessary.  If it is
+  necessary, with the exception of automatic portion control, it should go into 
+  logic.sqlite3.
+*/
+
+PRAGMA recursive_triggers = 1;
+
+begin;
+
+/*
+  HEERE BEGYNNETH AUTOMATIC PORTION CONTROL (PCF)
+*/
+
+/*
+  If a mealfoods replace causes the delete trigger to start, we get a
+  recursive nightmare.  So we need a before insert trigger.
+*/
+
+drop trigger if exists before_mealfoods_insert_pcf;
+create temp trigger before_mealfoods_insert_pcf before insert on mealfoods
+when (select block_mealfoods_insert_trigger from z_trig_ctl) = 0
+begin
+update z_trig_ctl set block_mealfoods_delete_trigger = 1;
+end;
+
+/*
+  A mealfoods insert trigger
+*/
+
+drop trigger if exists mealfoods_insert_pcf;
+create temp trigger mealfoods_insert_pcf after insert on mealfoods
+when NEW.meal_id = (select currentmeal from options)
+and (select block_mealfoods_insert_trigger from z_trig_ctl) = 0
+begin
+update z_trig_ctl set rm_analysis = 1;
+update z_trig_ctl set am_analysis = 1;
+update z_trig_ctl set am_dv = 1;
+update z_trig_ctl set PCF_processing = 1;
+end;
+
+/*
+  A mealfoods update trigger
+*/
+
+drop trigger if exists mealfoods_update_pcf;
+create temp trigger mealfoods_update_pcf after update on mealfoods
+when OLD.meal_id = (select currentmeal from options)
+begin
+update z_trig_ctl set rm_analysis = 1;
+update z_trig_ctl set am_analysis = 1;
+update z_trig_ctl set am_dv = 1;
+update z_trig_ctl set PCF_processing = 1;
+end;
+
+/*
+  A mealfoods delete trigger
+*/
+
+drop trigger if exists mealfoods_delete_pcf;
+create temp trigger mealfoods_delete_pcf after delete on mealfoods
+when OLD.meal_id = (select currentmeal from options)
+and (select block_mealfoods_delete_trigger from z_trig_ctl) = 0
+begin
+update z_trig_ctl set rm_analysis = 1;
+update z_trig_ctl set am_analysis = 1;
+update z_trig_ctl set am_dv = 1;
+update z_trig_ctl set PCF_processing = 1;
+end;
+
+/*
+  Another thing that can start automatic portion control is changing the
+  nutopt in nutr_def which will change the Daily Values.  And then the same
+  thing for FAPU1 in options.
+*/
+
+drop trigger if exists update_nutopt_pcf;
+create temp trigger update_nutopt_pcf after update of nutopt on nutr_def
+begin
+update z_trig_ctl set rm_analysis = 1;
+update z_trig_ctl set am_analysis = 1;
+update z_trig_ctl set am_dv = 1;
+update z_trig_ctl set PCF_processing = 1;
+end;
+
+drop trigger if exists update_FAPU1_pcf;
+create temp trigger update_FAPU1_pcf after update of FAPU1 on options
+begin
+update z_trig_ctl set rm_analysis = 1;
+update z_trig_ctl set am_analysis = 1;
+update z_trig_ctl set am_dv = 1;
+update z_trig_ctl set PCF_processing = 1;
+end;
+
+/*
+  HEERE ENDETH AUTOMATIC PORTION CONTROL (PCF)
+*/
+
+/*
+  We often want to grab the preferred weight for a food so we create a special
+  view that dishes it up!  This view delivers the preferred Gm_Wgt and the
+  newly computed Amount of the serving unit.  The preferred weight is never
+  zero or negative, so if the Gm_Wgt might not be > 0.0 you need special logic.
+*/
+
+drop view if exists pref_Gm_Wgt;
+create view pref_Gm_Wgt as select NDB_No, Seq, Gm_Wgt / origGm_Wgt * Amount as Amount, Msre_Desc, Gm_Wgt, origSeq, origGm_Wgt, Amount as origAmount from weight natural join (select NDB_No, min(Seq) as Seq from weight group by NDB_No);
+
+/*
+  Here's an "INSTEAD OF" trigger to allow updating the Gm_Wgt of the
+  preferred weight record.
+*/
+
+drop trigger if exists pref_weight_Gm_Wgt;
+create trigger pref_weight_Gm_Wgt instead of update of Gm_Wgt on pref_Gm_Wgt
+when NEW.Gm_Wgt > 0.0 begin
+update weight set Gm_Wgt = NEW.Gm_Wgt where NDB_No = NEW.NDB_No and Seq =
+(select min(Seq) from weight where NDB_No = NEW.NDB_No);
+end;
+  
+/*
+  This is a variant of the previous trigger to change the preferred Gm_Wgt
+  of a food by specifying the Amount of the serving unit, the Msre_Desc.
+  In addition, it proffers an update to the Gm_Wgt of the food in the
+  current meal, just in case that is the reason for the update.
+*/
+
+drop trigger if exists pref_weight_Amount;
+create trigger pref_weight_Amount instead of update of Amount on pref_Gm_Wgt
+when NEW.Amount > 0.0 begin
+update weight set Gm_Wgt = origGm_Wgt * NEW.Amount / Amount 
+where NDB_No = NEW.NDB_No and 
+Seq = (select min(Seq) from weight where NDB_No = NEW.NDB_No);
+update currentmeal set Gm_Wgt = null where NDB_No = NEW.NDB_No;
+end;
+  
+/*
+  Using the preferred weight, we can View Foods in various ways.
+*/
+
+drop view if exists view_foods;
+create view view_foods as select NutrDesc, NDB_No, substr(Shrt_Desc,1,45), round(Nutr_Val * Gm_Wgt / 100.0,1) as Nutr_Val, Units, cast(cast(round(Nutr_Val * Gm_Wgt / dv) as int) as text) || '% DV' from nutr_def natural join nut_data left join am_dv using (Nutr_No) natural join food_des natural join pref_Gm_Wgt;
+
+/*
+  We create a convenience view of the current meal, aka mealfoods.
+*/
+
+drop view if exists currentmeal;
+CREATE VIEW currentmeal as select mf.NDB_No as NDB_No, case when (select grams from options) then cast (cast (round(mf.Gm_Wgt) as int) as text) || ' g' else cast(round(mf.Gm_Wgt / 28.35 * 8.0) / 8.0 as text) || ' oz' end || ' (' || cast(round(case when mf.Gm_Wgt <= 0.0 or mf.Gm_Wgt != pGW.Gm_Wgt then mf.Gm_Wgt / origGm_Wgt * origAmount else Amount end * 8.0) / 8.0 as text) || ' ' || Msre_Desc || ') ' || Shrt_Desc || ' ' as Gm_Wgt, NutrDesc from mealfoods mf natural join food_des left joi [...]
+
+/*
+  OK, now the INSTEAD OF trigger to simplify somewhat the insertion of a 
+  meal food:
+*/
+
+drop trigger if exists currentmeal_insert;
+create trigger currentmeal_insert instead of insert on currentmeal begin
+update mealfoods set Nutr_No = null where Nutr_No = (select Nutr_No from
+nutr_def where NutrDesc = NEW.NutrDesc);
+insert or replace into mealfoods values ((select currentmeal from options),
+NEW.NDB_No, case when NEW.Gm_Wgt is null then (select Gm_Wgt from pref_Gm_Wgt
+where NDB_No = NEW.NDB_No) else NEW.Gm_Wgt end, case when NEW.NutrDesc is null 
+then null when (select count(*) from nutr_def where NutrDesc = NEW.NutrDesc
+and dv_default > 0.0) = 1 then (select Nutr_No from nutr_def where NutrDesc
+= NEW.NutrDesc) when (select count(*) from nutr_def where Nutr_No =
+NEW.NutrDesc and dv_default > 0.0) = 1 then NEW.NutrDesc else null end);
+end;
+
+/*
+  It's simpler to delete a mealfood with currentmeal than to just delete
+  it from mealfoods because you don't have to specify the meal_id.
+*/
+
+drop trigger if exists currentmeal_delete;
+create trigger currentmeal_delete instead of delete on currentmeal begin
+delete from mealfoods where meal_id = (select currentmeal from options)
+and NDB_No = OLD.NDB_No;
+end;
+
+/*
+  We often want to update a Gm_Wgt in the current meal.
+*/
+
+drop trigger if exists currentmeal_upd_Gm_Wgt;
+create trigger currentmeal_upd_Gm_Wgt instead of update of Gm_Wgt on
+currentmeal begin
+update mealfoods set Gm_Wgt = case when NEW.Gm_Wgt is null then (select Gm_Wgt from pref_Gm_Wgt where NDB_No = NEW.NDB_No) else NEW.Gm_Wgt end where NDB_No = NEW.NDB_No and
+meal_id = (select currentmeal from options);
+end;
+
+/*
+  And finally, we often want to modify automatic portion control on the
+  current meal.
+*/
+
+drop trigger if exists currentmeal_upd_pcf;
+create trigger currentmeal_upd_pcf instead of update of NutrDesc on
+currentmeal begin
+update mealfoods set Nutr_No = null 
+where Nutr_No = (select Nutr_No from nutr_def where NutrDesc = NEW.NutrDesc);
+update mealfoods set Nutr_No = (select Nutr_No from nutr_def where NutrDesc =
+NEW.NutrDesc) where NDB_No = NEW.NDB_No and
+meal_id = (select currentmeal from options);
+end;
+
+/*
+  Here's a convenience view of customary meals, aka theusual
+*/
+
+drop view if exists theusual;
+create view theusual as select meal_name, NDB_No, Gm_Wgt, NutrDesc from 
+z_tu natural join pref_Gm_Wgt left join nutr_def using (Nutr_No);
+
+/*
+  We have the view, now we need the triggers.
+
+  First, we handle inserts from the current meal.
+*/
+
+drop trigger if exists theusual_insert;
+create trigger theusual_insert instead of insert on theusual
+when NEW.meal_name is not null and NEW.NDB_No is null and NEW.Gm_Wgt is null
+and NEW.NutrDesc is null
+begin
+delete from z_tu where meal_name = NEW.meal_name;
+insert or ignore into z_tu select NEW.meal_name, mf.NDB_No, mf.Nutr_No from mealfoods mf left join nutr_def where meal_id = (select currentmeal from options);
+end;
+
+/*
+  Now we allow customary meals to be deleted.
+*/
+
+drop trigger if exists theusual_delete;
+create trigger theusual_delete instead of delete on theusual
+when OLD.meal_name is not null
+begin
+delete from z_tu where meal_name = OLD.meal_name;
+end;
+
+/*
+  Sorry I didn't write triggers to handle each theusual eventuality,
+  but you can always work directly on z_tu for your intricate updating needs.
+*/
+
+/*
+  We create convenience views to report which foods in the meal analysis are
+  contributing to a nutrient intake.  Use it like this (for example):
+	select * from nut_in_meals where NutrDesc = 'Protein';
+	select * from nutdv_in_meals where NutrDesc = 'Zinc';
+
+  nutdv_in_meals returns nothing if nutrient has no DV
+
+  Then a view of average daily food consumption over the analysis period.
+*/
+
+drop view if exists nut_in_meals;
+create view nut_in_meals as select NutrDesc, round(sum(Gm_Wgt * Nutr_Val / 100.0 / (select mealcount from am_analysis_header) * (select meals_per_day from options)),1) as Nutr_Val, Units, Shrt_Desc from mealfoods mf join food_des using (NDB_No) join nutr_def nd join nut_data data on mf.NDB_No = data.NDB_No and nd.Nutr_No = data.Nutr_No where meal_id >= (select firstmeal from am_analysis_header) group by mf.NDB_No, NutrDesc order by Nutr_Val desc; 
+
+drop view if exists nutdv_in_meals;
+create view nutdv_in_meals as select NutrDesc, cast(cast(round(sum(Gm_Wgt * Nutr_Val / dv / (select mealcount from am_analysis_header) * (select meals_per_day from options))) as int) as text) || '%' as val, Shrt_Desc from mealfoods mf join food_des using (NDB_No) join nutr_def nd join nut_data data on mf.NDB_No = data.NDB_No and nd.Nutr_No = data.Nutr_No join am_dv on nd.Nutr_No = am_dv.Nutr_No where meal_id >= (select firstmeal from am_analysis_header) group by mf.NDB_No, NutrDesc order [...]
+
+drop view if exists daily_food;
+create view daily_food as select cast(round((sum(mf.Gm_Wgt) / mealcount * meals_per_day) / origGm_Wgt * origAmount * 8.0) / 8.0 as text) || ' ' || Msre_Desc || ' ' || Shrt_Desc from mealfoods mf natural join food_des join pref_Gm_Wgt using (NDB_No) join am_analysis_header where meal_id between firstmeal and lastmeal group by NDB_No order by Shrt_Desc;
+
+/*
+  The actual autocal triggers that run the weight log application have to be
+  invoked by the user because they would really run amok during bulk updates.
+
+  The autocal feature is kicked off by an insert to z_wl, the actual weight
+  log table.  There are many combinations of responses, each implemented by
+  a different trigger.
+
+  First, the proceed or do nothing trigger.
+*/
+
+/*
+drop trigger if exists autocal_proceed;
+create temp trigger autocal_proceed after insert on z_wl
+when (select autocal = 2 and weightn > 1 and (weightslope - fatslope) >= 0.0 and fatslope <= 0.0 from z_wslope, z_fslope, z_span, options)
+begin
+select null;
+end;
+*/
+
+/*
+  Just joking!  It doesn't do anything so we don't need it!  But as we change
+  the conditions, the action changes.
+
+  For instance, lean mass is going down or fat mass is going up, so we give up
+  on this cycle and clear the weightlog to move to the next cycle.
+  We always add a new entry to get a head start on the next cycle, but in this
+  case we save the last y-intercepts as the new start.  We also make an
+  adjustment to calories:  up 20 calories if both lean mass and fat mass are
+  going down, or down 20 calories if they were both going up.  If fat was
+  going up and and lean was going down we make no adjustment because, well,
+  we just don't know!
+*/
+
+drop table if exists z_save_it;
+create table z_save_it (weight real, fat real, wldate integer, span integer, today integer);
+
+drop trigger if exists autocal_cutting;
+create temp trigger autocal_cutting after insert on z_wl
+when (select autocal = 2 and weightn > 1 and fatslope > 0.0 and (weightslope - fatslope) > 0.0 from z_wslope, z_fslope, options)
+-- when (select autocal = 2 and weightn > 1 and fatslope > 0.0 and (weightslope - fatslope) > 0.0 and (weightslope - fatslope) < fatslope from z_wslope, z_fslope, options)
+begin
+delete from z_save_it;
+insert into z_save_it select weightyintercept, fatyintercept, wldate, span, today from z_wslope, z_fslope, z_span, (select min(wldate) as wldate from z_wl where
+cleardate is null), (select strftime('%Y%m%d', 'now', 'localtime') as today);
+update z_wl set cleardate = (select today from z_save_it) where cleardate is null;
+insert into z_wl select weight, round(100.0 * fat / weight,1), today, null from z_save_it;
+update nutr_def set nutopt = nutopt - 20.0 where Nutr_No = 208;
+end;
+
+drop trigger if exists autocal_bulking;
+create temp trigger autocal_bulking after insert on z_wl
+when (select autocal = 2 and weightn > 1 and fatslope < 0.0 and (weightslope - fatslope) < 0.0 from z_wslope, z_fslope, options)
+begin
+delete from z_save_it;
+insert into z_save_it select weightyintercept, fatyintercept, wldate, span, today from z_wslope, z_fslope, z_span, (select min(wldate) as wldate from z_wl where
+cleardate is null), (select strftime('%Y%m%d', 'now', 'localtime') as today);
+update z_wl set cleardate = (select today from z_save_it) where cleardate is null;
+insert into z_wl select weight, round(100.0 * fat / weight,1), today, null from z_save_it;
+update nutr_def set nutopt = nutopt + 20.0 where Nutr_No = 208;
+end;
+
+drop trigger if exists autocal_cycle_end;
+create temp trigger autocal_cycle_end after insert on z_wl
+when (select autocal = 2 and weightn > 1 and fatslope > 0.0 and (weightslope - fatslope) < 0.0 from z_wslope, z_fslope, options)
+begin
+delete from z_save_it;
+insert into z_save_it select weightyintercept, fatyintercept, wldate, span, today from z_wslope, z_fslope, z_span, (select min(wldate) as wldate from z_wl where
+cleardate is null), (select strftime('%Y%m%d', 'now', 'localtime') as today);
+update z_wl set cleardate = (select today from z_save_it) where cleardate is null;
+insert into z_wl select weight, round(100.0 * fat / weight,1), today, null from z_save_it;
+end;
+
+/*
+  We create a shopping list where the "n" column automatically gives a serial
+  number for easy deletion of obtained items, or we can delete by store.
+  Insert into the table this way:
+	INSERT into shopping values (null, 'potatoes', 'tj');
+*/
+
+CREATE TABLE if not exists shopping (n integer primary key, item text, store text);
+drop view if exists shopview;
+CREATE VIEW shopview as select 'Shopping List ' || group_concat(n || ': ' || item || ' (' || store || ')', ' ') from (select * from shopping order by store, item);
+
+/*
+  A purely personal view.  max_chick is about portion control for various parts
+  of a cut-up chicken.
+*/
+
+drop view if exists max_chick;
+CREATE VIEW max_chick as select NDB_No, Shrt_Desc, round(13.0 / Nutr_Val * 100 / origGm_Wgt * Amount * 8) / 8.0 as Amount, Msre_Desc from food_des natural join nut_data natural join weight where NDB_No > 99000 and Shrt_Desc like '%chick%mic%' and Nutr_No = 203 and Seq = (select min(Seq) from weight where NDB_No = food_des.NDB_No);
+
+/*
+  View showing daily macros and body composition index
+*/
+
+drop view if exists daily_macros;
+create view daily_macros as
+select day, round(sum(calories)) as calories, 
+cast(round(100.0 * sum(procals) / sum(calories)) as int) || '/' ||
+cast(round(100.0 * sum(chocals) / sum(calories)) as int) || '/' ||
+cast(round(100.0 * sum(fatcals) / sum(calories)) as int) as macropct,
+round(sum(protein)) as protein,
+round(sum(nfc)) as nfc, round(sum(fat)) as fat,
+bodycomp 
+from 
+(select meal_id / 100 as day, NDB_No, 
+sum(Gm_Wgt / 100.0 * cals.Nutr_Val) as calories, 
+sum(Gm_Wgt / 100.0 * pro.Nutr_Val) as protein, 
+sum(Gm_Wgt / 100.0 * crb.Nutr_Val) as nfc, 
+sum(Gm_Wgt / 100.0 * totfat.Nutr_Val) as fat,
+sum(Gm_Wgt / 100.0 * pcals.Nutr_Val) as procals,
+sum(Gm_Wgt / 100.0 * ccals.Nutr_Val) as chocals,
+sum(Gm_Wgt / 100.0 * fcals.Nutr_Val) as fatcals,
+bodycomp
+from mealfoods join nut_data cals using (NDB_No) 
+join nut_data pro using (NDB_No) 
+join nut_data crb using (NDB_No) 
+join nut_data totfat using (NDB_No) 
+join nut_data pcals using (NDB_No) 
+join nut_data ccals using (NDB_No) 
+join nut_data fcals using (NDB_No) 
+left join (select * from wlview group by wldate) on day = wldate
+where cals.Nutr_No = 208 and
+pro.Nutr_No = 203 and
+crb.Nutr_No = 2000 and
+totfat.Nutr_No = 204 and
+pcals.Nutr_No = 3000 and
+ccals.Nutr_No = 3002 and
+fcals.Nutr_No = 3001
+group by day, NDB_No) group by day;
+
+/*
+  This is the select that I use to look at the nutrient values for the current meal.
+*/
+
+drop view if exists ranalysis;
+create view ranalysis as select NutrDesc, round(Nutr_Val, 1) || ' ' || Units, cast(cast(round(100.0 + dvpct_offset) as int) as text) || '%' from rm_analysis natural join rm_dv natural join nutr_def order by dvpct_offset desc;
+
+/*
+  This is the select that I use to look at the nutrient values for the
+  whole analysis period.
+*/
+
+drop view if exists analysis;
+create view analysis as select NutrDesc, round(Nutr_Val, 1) || ' ' || Units, cast(cast(round(100.0 + dvpct_offset) as int) as text) || '%' from am_analysis natural join am_dv natural join nutr_def order by dvpct_offset desc;
+
+commit;
+
+PRAGMA user_version = 5;
+.prompt 'bigNUT> '
diff --git a/nutdoc.html b/nut.1
similarity index 85%
copy from nutdoc.html
copy to nut.1
index dd82a8e..04333af 100644
--- a/nutdoc.html
+++ b/nut.1
@@ -1,27 +1,19 @@
-Content-type: text/html
+.\" manual page [] for nut
+.\" SH section heading
+.\" SS subsection heading
+.\" LP paragraph
+.\" IP indented paragraph
+.\" TP hanging label
+.TH "nut" "1" "2016.10.30" "" ""
+.SH "NAME"
+.B nut 
+- analyze meals with the USDA Nutrient Database
+.SH "SYNOPSIS"
+.B nut
+.SH "DESCRIPTION"
+.PP
 
-<HTML><HEAD><TITLE>NUTsqlite Documentation</TITLE>
-</HEAD><BODY>
-<H1>nut</H1>
-Section:  (1)<BR>Updated: 2014.06.14<BR><A HREF="#index">Index</A>
-<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
-
-<A NAME="lbAB"> </A>
-<H2>NAME</H2>
-
-<B>nut - analyze meals with the USDA Nutrient Database</B>
-
-<A NAME="lbAC"> </A>
-<H2>SYNOPSIS</H2>
-
-<B>nut.tcl</B>
-
-<A NAME="lbAD"> </A>
-<H2>DESCRIPTION</H2>
-
-<P>
-
-<B>NUT</B>
+.B NUT
 
 allows you to record what you eat and analyze your meals for nutrient
 composition.  
@@ -30,76 +22,76 @@ as a percentage of the DV or Daily Value,
 the familiar standard of food labeling in the United States.
 The essential fatty acids, Omega-6 and Omega-3, are not currently mentioned in
 these standards, and a reference value has been supplied.
-<P>
-<B>NUT</B>
+.PP
+.B NUT
 uses Tcl/Tk to create an SQLite database that holds its own code,
 the 
 USDA Nutrient Database for Standard Reference,
 and your personal data for meals, recipes, and weight logs.
-<P>
-<B>INSTALLATION and LOAD of USDA Database:  </B>
+.PP
+.B INSTALLATION and LOAD of USDA Database:  
 
 If your desktop system does not have Tcl/Tk available, download and install the free
 (community) version of ActiveTcl from 
-<A HREF="http://www.activestate.com/">http://www.activestate.com/</A>.
+http://www.activestate.com/.
 
-<P>
+.PP
 
 Download the full ascii version of the USDA Nutrient Database,
 available from 
-<A HREF="http://www.ars.usda.gov/nutrientdata">http://www.ars.usda.gov/nutrientdata</A>
+http://www.ars.usda.gov/nutrientdata
 or from
-<A HREF="http://nut.sourceforge.net">http://nut.sourceforge.net</A>,
+http://nut.sourceforge.net,
 and unzip it in some directory.
 
-<P>
+.PP
 
 Run "updateNUT.tcl", an executable included in the
-<B>NUT</B>
+.B NUT
 distribution, in the same directory where you put the USDA database.
 This script will load your new 
-<B>NUT</B>
+.B NUT
 database with the 
-<B>NUT</B>
+.B NUT
 code.
 After this step, run "nut.tcl" to start
-<B>NUT</B>.
+.B NUT.
 Initially,
-<B>NUT</B>
+.B NUT
 will see the USDA tables and load them as well as
 any legacy files from previous versions
 of
-<B>NUT</B>.
+.B NUT.
 After these steps, both "updateNUT.tcl" and the USDA files are not 
 required and can be deleted.  
-<P>
+.PP
 "nut.tcl" can start the program with
 a different location for
 the 
-<B>NUT</B> 
+.B NUT 
 database and a different location for legacy files.
 These changes are easily made by editing "nut.tcl".  
-<P>
+.PP
 In addition, a value can be changed in "nut.tcl" to make the program usable
 on screens with a high resolution.  
-<B>NUT</B>
+.B NUT
 will check how many pixels you have and create a font/window combination
 that is always legible.  Change the "appSize" variable in "nut.tcl"
 to between 0.7 (small) and 1.3 (almost fullscreen) to magnify the default Tk
 font and window sizes appropriately.
-<P>
-<B>OVERVIEW of PROGRAM</B>
+.PP
+.B OVERVIEW of PROGRAM
 
-<P>
+.PP
 
 A typical session with
-<B>NUT</B>
+.B NUT
 begins with a glance at "Analyze Meals" to see the daily 
 averages from the
 last few meals.  
 Normally, one analyzes more than one day but less than two weeks to
 get a fairly recent overview of nutritional quality and adherence to plan.
-<P>
+.PP
 "Record Meals & Recipes" is where meals are planned or else simply recorded if
 unplanned.  
 A slider can  either be moved directly or else clicked 
@@ -115,13 +107,13 @@ your personal regimen.
 This function also allows you to save a "meal" as a recipe to be added to
 the USDA database, or to designate a meal as a Customary Meal for easier data
 entry later.
-<P>
+.PP
 "View Foods" shows comprehensive nutrient listings for each food,
 in serving sizes as described by the USDA nutrient database.  Any of these
 serving sizes can be scaled and easily added to a meal, and
-<B>NUT</B>
+.B NUT
 remembers your preferred serving sizes.
-<P>
+.PP
 "Personal Options" allows the nutrient standards to be changed.  These
 personal standards are customized and the rest of the program follows
 these standards.  
@@ -133,16 +125,16 @@ In addition, there is a facility to record weight and
 bodyfat percentages daily and see a linear extrapolation of the trend so
 that you do not have to wait weeks to know how a new strategy is
 working.  
-<B>NUT</B> will also automatically move calories up and down by gradual increments in order to keep lean mass up and 
+.B NUT will also automatically move calories up and down by gradual increments in order to keep lean mass up and 
 fat mass down with the Calorie Auto-Set feature.
-<P>
+.PP
 Whenever you press a nutrient button you go to a screen that describes
 "The Story" for that nutrient.  This includes  various lists of foods 
 sorted to help you find the nutrients you need.  
-<P>
+.PP
 
-<B>ANALYZE MEALS</B>
-<P>
+.B ANALYZE MEALS
+.PP
 Meal analysis is always a daily rate of intake and not a sum.  For instance,
 if you eat 2000 calories a day and analyze a week of meals, the analysis
 reports 2000 calories, not 14,000.  Likewise, if you eat three meals a day and
@@ -150,47 +142,47 @@ reports 2000 calories, not 14,000.  Likewise, if you eat three meals a day and
 the analysis reports 100% of calories, not
 33% of calories.
 Think of 
-<B>NUT</B>
+.B NUT
 meal analysis
 as a speedometer, not an odometer.
-<P>
+.PP
 The range of meals shown on the screen controls many other functions in the
 program as it not only sets the range for showing  food lists, but
 also the exact Daily Values used in portion control.  Therefore, if you
 want automatic portion control to be as accurate as possible, analyzing 
 just one meal while you are planning meals is best,  although it is 
 not required most of the time--just when you are changing strategies, such as from high-carb to low-carb.
-<P>
+.PP
 The spin button controlling how many consecutive meals to analyze can be selected and cleared with a backspace to speed up making large changes.
 A very large value will resolve to all the meals
 in the database, but do remember, if automatic portion control is in effect, there will be a lot of processing to get all of the program functions into sync because portion control always needs to reanalyze all meals until it is sure the requirements are properly met.
-<P>
-<P>
-<B>RECORD MEALS & RECIPES</B>
-<P>
+.PP
+.PP
+.B RECORD MEALS & RECIPES
+.PP
 For the program analysis to come out right you must record
 all the meals the program is set for.
 For instance, if 
-<B>NUT</B>
+.B NUT
 is set for three meals a day, and
 you eat more than three, combine them into three; if you eat less than three, 
 record some minimal item such as an ounce of water for each missing meal.
 In this way, even if you take breaks from recording,
-<B>NUT</B>
+.B NUT
 will report fairly accurate daily averages and just concatenate over the
 breaks; but otherwise
-<B>NUT</B>
+.B NUT
 will wrongly weight the meals as a wrong percentage of a day.
-<P>
+.PP
 When the program first starts, there is a button to "Delete all Meals and
 Set Meals per Day".  Although meals are deleted from view, they are
 actually archived, so that if you return to the current number of meals per
 day, the meals will return to the active database.  If meal planning is not your
 forte, or if your meal schedules are highly irregular, set
-<B>NUT</B> 
+.B NUT 
 to 1 meal per day and record a daily running total of all foods eaten.
 
-<P>
+.PP
 To actually record a meal, first determine if the slider in the upper left
 corner of the screen shows the correct meal; if not, click on the left or right
 of the slider to nudge it one meal at a time in the right direction until
@@ -198,12 +190,12 @@ the correct meal is showing.  Then click on the "Food Search" entry area to
 open up the search screen.  Type a part of a food name and all the foods that
 match will be shown below as you type.  Select one with a click and it will
 be added to the meal.
-<P>
+.PP
 You can specify quantities in either gram or ounce weights by adjusting the
 spin button, or by clicking on the food to open up "View Foods" so you can
 choose a serving size based on cups or some other volume measurement,
 but you can also let
-<B>NUT</B>
+.B NUT
 set the quantity with "Auto Portion Control".  To achieve portion control
 based on calories, it is necessary to choose each of a protein, fat, and
 non-fiber carb food (unless some of these macronutrients are set to
@@ -219,28 +211,28 @@ really want to eat.
 When the Auto Portion Control algorithm is running, the "Food Search" entry
 area turns into an indeterminate progress bar and the food quantities flip
 around as they find the best possible solution. 
-<P>
+.PP
 The more "Auto Portion Control" selections you make, the more complicated
 the process of finding the answer becomes, some combinations become
 impossible,  and some combinations might send the algorithm off the deep end,
 in that it never completes.
 Perhaps later
 versions of
-<B>NUT</B>
+.B NUT
 will have a better way to predict what is going to happen.  For the time
 being, if you need a complicated solution using many portion-controlled
 foods,
 be ready to blow away the window
 running
-<B>NUT</B>
+.B NUT
 and start over if it doesn't work. And if a Tcl error message dialog appears, just click "OK", because the error
 is a transient consequence of an unexpected set of foods that cannot be
 portion controlled to the selected specification.
 These problems will be rare occurrences as 
-<B>NUT</B>
+.B NUT
 is able to recognize many combinations of foods and portion-control 
 settings that are not compatible.
-<P>
+.PP
 When you have a good meal planned and think you may want to repeat it, use
 the Customary Meals feature to save the meal.  Later, when you want something
 similar, add the customary meal to the new meal you are planning.  If you
@@ -249,7 +241,7 @@ refresh the Automatic Portion Control easily by adding the meal again.
 Likewise, you can save the meal multiple times without duplicating the meal
 foods.  Customary Meals can always be adapted to whatever you are going to
 have, by adding and deleting foods as required, and by changing quantities.
-<P>
+.PP
 Record a recipe in exactly the same way as a meal, but press the "Save  as
 a Recipe" button to add your recipe as a new food to the USDA database.  Then,
 fill in the blanks with the recipe name, the number of servings, any volume measurement you want to use to measure a serving, such as cups, teaspoons or pieces, etc., and if you
@@ -257,14 +249,14 @@ know the weight of a serving after preparation, the recipe will be adjusted
 for water gained or lost in preparation.  Furthermore, you will be presented
 with the complete nutrient screens so you can adjust the nutrient values.  This allows you to create a "recipe" that is actually just a processed food or food supplement, where the real ingredients are similar to the processed food or
 maybe just some water,
-but you are changing the nutrient information to match the label on
+but you are changing the nutrient .nfrmation to match the label on
 a product.
 On these recipe nutrient screens, the "Daily Value" 
 percentages are the standard 2000
 calorie values, not any modifications you may have made from
 "Personal Options", so that they will match the nutrition labels; however,
 nutrient values can always be entered in grams.   When you "Save" this new recipe, it becomes just like any other food in the database.
-<P>
+.PP
 A non-obvious use for recipes is to add a new serving size to an
 existing food to make portion control easier.  Take one of my favorites, a
 roasted chicken wing.  The meat weighs 34 grams in an average wing
@@ -277,28 +269,28 @@ Then, at mealtime, if you need strict portion control, you go
 to "View Foods" and set a number of servings corresponding to the weight of
 the wings on the bone and add it to the meal, and only the weight of the meat
  shows up in the meal.
-<P>
+.PP
 Yet another use for "Save as a Recipe":  Use it to quickly delete an entire meal,
 and then cancel the recipe.
-<P>
-<B>VIEW FOODS</B>
-<P>
+.PP
+.B VIEW FOODS
+.PP
 Here's where you can check out the whole nutritional record for a food based
 on whatever serving size you want to see represented.  Notice that many
 processed foods have very brief summaries of nutrients with many "[No Data]"
 entries.  When added to meals, "[No Data]" is treated as a zero, and since
 nutrient values for specific foods vary considerably, analyses are always
 approximate and not nearly as precise as 
-<B>NUT</B>
+.B NUT
 seems to suggest.  
-<P>
-Additional information on this screen includes refuse percentages and 
+.PP
+Additional .nfrmation on this screen includes refuse percentages and 
 descriptions that can
 help in visualizing how much food is required, and serving sizes can be
 computed by calorie level as well as by weight.
-<P>
-<B>PERSONAL OPTIONS</B>
-<P>
+.PP
+.B PERSONAL OPTIONS
+.PP
 In the simplest case, you are just typing the number of grams of some nutrient
 that you want to ingest daily, or else clicking an option that
 will automatically set the value for you.  Because the spinbuttons move so
@@ -307,7 +299,7 @@ and type the new value you want.   All of NUT is hooked together internally,
 so if your changes impact automatic portion control, there will be lots of
 activity to get the meal and its analyses all in sync and save everything to
 the database.
-<P>
+.PP
 "Adjust to my meals" is the setting if you don't care what the value for a
 nutrient should be, or if you do care, but you manage the 
 value by different means.
@@ -315,11 +307,11 @@ For instance, if you are eating low-carb, and you always plan meals to have
 minimal carbohydrate, "Adjust to my meals" means you don't have to hit a
 particular carb target and yet everything will mesh properly as if you had
 set a carb target that was exactly equal to what is in your meals.
-<P>
+.PP
 Either "Total Fat" or "Non-Fiber Carb" can be set to "Balance of Calories" and
 sometimes this option will automatically appear if required in order to meet
 the Calorie requirement.
-<P>
+.PP
 The  options  for  polyunsaturated fat and the "Omega-6/3 Balance" target
 select reference values (there are no "Daily Values" for  these)  based
 on Dr. William Lands' empirical equation for the percentages of Omega-6
@@ -329,19 +321,19 @@ good indicator of what your body does with the fatty acids because the
 individual fatty acids have different "strengths" as they compete for
 conversion to the forms that make up the cell membrane and get chosen at
 random to provide a signal that is either strong or weak in its effect
-on inflammation, blood clotting, etc.  Further information about this
+on .nfammation, blood clotting, etc.  Further .nfrmation about this
 biochemistry is on the 
-<B>NUT</B>
+.B NUT
 site at 
 <A HREF="http://nut.sourceforge.net/">http://nut.sourceforge.net/</A>.
-<P>
+.PP
 (Following is a description of the rightmost column on the screen that concerns
 the weight log.  At some lower screen resolutions, this column is partially occluded.  However, if you move the mouse
 over the imaginary line between the program settings and the weight log columns,
 there will appear a double arrow that you can click and drag to the left to
 bring the weight log column into full view.)
-<P>
-<B>NUT</B>
+.PP
+.B NUT
 records daily weight and bodyfat percentage measurements
 and uses linear regression to filter out the random noise and show the actual
 trend.  Are you gaining mostly fat mass or losing mostly lean mass?  This
@@ -349,17 +341,17 @@ feature can tell you if you have a bathroom scale that
 can read bodyfat percentage.  
 The weight measurement is free of units, so pounds, kilos, or even stone will
 work.  Although
-<B>NUT</B>
+.B NUT
 reports its findings with high precision, realize that the numbers are not
 absolutely true, but you are concerned with the trends the numbers represent, so that you can modify your nutrition
 strategy.
 For example, if total weight is fairly constant but lean mass is going down and
 fat mass is going up, would a little more protein 
 or less carbohydrate solve the problem? or would it make it worse?
-<P>
+.PP
 To use the feature, weigh yourself once a day at some appointed time and
 enter the weight and bodyfat numbers; then click on "Accept New Measurements".
-<B>NUT</B>
+.B NUT
 will only accept one set of measurements per day, but there is no harm in missing a
 day because the feature runs every day whether you add a measurement or not.
 Think of each new set of measurements as a small correction to the equation to get
@@ -367,58 +359,44 @@ a truer picture where you are going, and that's how you tell if it is working,
 because its predictions eventually do seem to be about right.  
 Weight loss gurus often advise against daily weighing because they are afraid
 you will freak out on days weight goes up.  But 
-<B>NUT</B>
+.B NUT
 uses linear regression to remove the noise of daily measurement error and
 produce a clear signal which way the weight is trending, and the more daily
 samples, the stronger the signal.  This way you can find out more quickly that a
 particular strategy just isn't working.  Also, you can become more aware of
 weight loss strategies that work by reducing lean mass instead of fat mass.
-<P>
+.PP
 Calorie "Auto-Set" means that you will eat according to the calorie level that
-<B>NUT</B>
+.B NUT
 shows and also record your weight and bodyfat percentage daily.
-<B>NUT</B>
+.B NUT
 can then determine how best to move the calorie level to achieve gains in
 lean mass and loss of fat mass. A cycle begins when there are two weight/bodyfat data points recorded.  
-<B>NUT</B>
-will move calories by a maximum of 20 calories a day during a  cycle. 
+.B NUT
+will move calories by a maximum of 20 calories a day. 
 If both lean mass and fat mass are trending down, 
-<B>NUT</B> 
-raises calories; if both lean mass and fat mass are trending up,
-<B>NUT</B>
-lowers calories.  When fat mass is trending up and lean mass is trending
+.B NUT 
+raises calories and starts a new cycle; if both lean mass and fat mass are trending up,
+.B NUT
+lowers calories and starts a new cycle.  When fat mass is trending up and lean mass is trending
 down, 
-<B>NUT</B> alternates between
-a cycle to prevent fat mass gain and a cycle to prevent lean mass loss.
-A cycle ends when fat mass is trending down and lean mass is trending up. (When a
-cycle begins with this favorable trend, it is allowed to continue.)
-At the end of a cycle, the average calories per day during the cycle
-becomes the new calorie level, and this  change may be more than 20 calories from the previous calorie setting.
-<P>
+.B NUT starts a new cycle without changing calories.
+When a
+cycle begins with the favorable trend of increasing lean mass and
+decreasing fat mass, it is allowed to continue.
+.PP
 If you are not using the Calorie Auto-Set
 feature, you can clear the weight log whenever you like; the usual reason would
 be that you have started a new strategy and therefore want to see the new
 trend.   For instance, I tend to make five to seven days of measurements, check the numbers, move calories up or down as required, and then clear the weight log when I am trying to find the right calorie level for my latest experiment. The last weight log entry is always retained after clearing the weight log to enable a quicker start to the next cycle of logging.
-<P>
-So, should you use the Weight Log manually or use the Calorie Auto-Set feature?
-I think the Calorie Auto-Set feature is best when you really do have to cut
-calories and would rather delegate the responsibility to 
-<B>NUT</B>
-to avoid the psychological torture of having to cut yourself back.  
-And
-<B>NUT</B> can slowly improve your body composition without you having to
-really think about it.
-But do
-remember that you can always turn the feature off and refine your strategy if
-there is excessive hunger or other problems, or you can 
- adjust the calorie level manually to speed up or slow down the progress of the Calorie Auto-Set algorithm.
-<P>
-<B>THE STORY</B>
-<P>
+.PP
+.PP
+.B THE STORY
+.PP
 When you click on a yellow nutrient button, you are taken to a tab that
 expounds the nutrient's story.  The screen features a list of
 foods sorted from most to least of the nutrient of interest, and a simple graph of intake during the current analysis period that you set in "Analyze Meals".
-<P>
+.PP
 The food lists can be queried in multiple ways.  The basic queries are by
 weight, by calories, by an approximate serving, and by weight of food in the
 analyzed daily meals, but the results can be modified to only look at a 
@@ -428,37 +406,37 @@ normal, that means there are
 no foods that meet the criteria.  For instance, if I look at "Foods Ranked
 per Daily Recorded Meals" and the food group "Breakfast Cereals" but I have
 eaten no breakfast cereal, I will get a white screen.
-<P>
+.PP
 If a food from the list looks interesting, click on it so it will open up in "View Foods".
-<P>
-<B>USING THE SQLITE DATABASE APART FROM NUT</B>
-<P>
+.PP
+.B USING THE SQLITE DATABASE APART FROM NUT
+.PP
 This is an advanced topic that will be expanded as I receive  questions
 about it.  The SQLite3 database can be queried independently of the use of
-<B>NUT</B>
+.B NUT
 and indeed, that is one reason I wrote this version of the software.
 However, I doubt that knowledge of SQL is  widespread, so  first I will give
 an example of a question I asked my database:  What date did I have the
 greatest amount of lean mass and how much was it?
-<P>
+.PP
 The table we will use is "wlog", and first we are curious about the schema,
 or what data is in "wlog".  For this example, I will use the "sqlite3" commands
 that come with SQLite, but any third-party software for querying SQLite will
 work.
-<P>
+.PP
 I start up the software with the command "sqlite3 nut.sqlite" and get the
 output:
-<P>
-<B><PRE>
+.PP
+.nf
 SQLite version 3.7.13 2012-06-11 02:05:22
 Enter ".help" for instructions
 Enter SQL statements terminated with a ";"
 sqlite> 
-</B></PRE>
-<P>
+.fi
+.PP
 If I need to be reminded what table I am looking for, I ask to see a list of all the
 tables:
-<B><PRE>
+.nf
 sqlite> .tables
 am                 fd_group           recipe             vf               
 am_zero            food_des           rm                 vf_zero          
@@ -467,36 +445,36 @@ archive_mealfoods  meals              sql_statements     weightslope
 dv                 nut_opts           tcl_code           wlog             
 dv_defaults        nutr_def           theusual         
 fatslope           options            version
-</B></PRE>
-<P>
+.fi
+.PP
 (It should be noted that some of the views require Tcl procedures and thus can't
 be queried apart from
-<B>NUT</B>.)
-<P>
+.B NUT.)
+.PP
 Now I ask what data is in the "wlog" table by asking to see the "schema":
-<P>
-<B><PRE>
+.PP
+.nf
 sqlite> .schema wlog
 CREATE TABLE wlog(weight real, bodyfat real, wldate int, cleardate int, primary key(wldate, cleardate));
-</B></PRE>
-<P>
+.fi
+.PP
 This is the exact SQL that created the wlog table.
 Now I ask "what is the most lean mass I have had?"
-<P>
-<B><PRE>
+.PP
+.nf
 sqlite> select max(weight - weight * bodyfat / 100) as leanmass from wlog;
 125.1486
-</B></PRE>
-<P>
+.fi
+.PP
 (Don't be shocked if you think this is too low; I am not a bodybuilder
 or a big guy.)
 Now I ask, "what was the date I had this much lean mass?"
-<P>
-<B><PRE>
+.PP
+.nf
 sqlite> select wldate from wlog where weight - weight * bodyfat / 100 = (select max(weight - weight * bodyfat / 100) from wlog);
 20110706
-</B></PRE>
-<P>
+.fi
+.PP
 Increasing lean mass is great, but as the sole measure of  body
 composition 
 it leads to obesity; decreasing fat mass is great,
@@ -504,8 +482,8 @@ but as the sole measure of  body composition it leads to frailty.
 What we need is an equation which increases in value as body
 composition improves.  
 Perhaps the simplest is lean mass minus fat mass, or in other words, what is the "spread" between the lean mass and the fat mass quantities:
-<P>
-<B><PRE>
+.PP
+.nf
 sqlite> select wldate, round(weight - weight * bodyfat / 100, 1) as leanmass, round(weight * bodyfat / 100, 1) as fatmass, round(weight - 2 * weight * bodyfat / 100, 1) as bodycomp from wlog group by wldate; 
 20150603|122.9|34.3|88.7
 20150605|123.4|33.2|90.2
@@ -523,48 +501,48 @@ sqlite> select wldate, round(weight - weight * bodyfat / 100, 1) as leanmass, ro
 20150617|124.2|32.4|91.8
 20150618|124.8|32.8|92.0
 20150619|125.3|32.3|93.0
-</B></PRE>
-<P>
+.fi
+.PP
 The Calorie Auto-Set feature alternates between cycles that potentially favor
 either lean mass gain or fat mass loss in the cases when fat mass is trending up
 and lean mass is trending down.  This is a switch you can manipulate, and it is
 the wlpolarity column in the table options.  "1" means favor lean mass gain, "0" means favor fat mass loss, and you would issue the command at the start
 of each Calorie Auto-Set cycle because the wlpolarity switches its state at the end of each cycle:
-<P>
-<B><PRE>
+.PP
+.nf
 sqlite> update options set wlpolarity = 1;
-</B></PRE>
-<P>
+.fi
+.PP
 Now, let's turn to a different task.  I've created a bad recipe and I want to
 delete it from the database.  First, I find the record in the food_des table and
 ask to see  "NDB_No", the primary key for foods:
-<P>
-<B><PRE>
+.PP
+.nf
 sqlite> select NDB_No, Long_Desc from food_des where Long_Desc like '%ramen jello%';
 99008|Ramen jello toast, artisanal, with gelatin from pastured pork
-</B></PRE>
-<P>
+.fi
+.PP
 When I know the NDB_No, I can delete the food record from food_des and any
 associated weight records from weight:
-<P>
-<B><PRE>
+.PP
+.nf
 sqlite> delete from food_des where NDB_No = 99008;
 sqlite> delete from weight where NDB_No = 99008;
-</B></PRE>   
-<P>
+.fi   
+.PP
 Hopefully you will never need to do this, but it is possible that
 automatic portion control could write a completely awry meal that
-<B>NUT</B>
+.B NUT
 is unable to analyze when it tries to come up.  The only recourse 
 then is to delete the meal
 from the database using the meal_date and meal number like this:
-<P>
-<B><PRE>
+.PP
+.nf
 sqlite> delete from mealfoods where meal_date = 20150413 and meal = 3;
-</B></PRE>
-<P>
+.fi
+.PP
 Although you can update some of the 
-<B>NUT</B>
+.B NUT
 data manually as in the previous examples,
 do note that if you update nutrient values in the food_des
 table, your updates will not propagate to the
@@ -572,50 +550,50 @@ existing meals in the meals table unless you reload the
 USDA nutrient database, this as a consequence of the table joins done at load time to
 improve performance at
 runtime.
-<P>
+.PP
 Now a question which was difficult to answer with the legacy
-<B>NUT</B>
+.B NUT
 program but fairly easy to answer with SQL.  I was buying the most expensive
 eggs because they had more Omega-3, but decided to use cheaper eggs and just
 take a little more fish oil.  What date did I change over?  First, I need the
 NDB_No of the expensive eggs:
-<P>
-<B><PRE>
+.PP
+.nf
 sqlite> select NDB_No, Long_Desc from food_des where Long_Desc like '%egg%' and Long_Desc like '%organic%';
 99010|Egg,yolk,raw,fresh,organic,brown,omega3,trader joe's
 99011|Egg,whole,cooked,hard-boiled,organic,brn,omega3,trader joe's
-</B></PRE>
-<P>
+.fi
+.PP
 I want to see just the raw yolks, and I want to query the "mealfoods" table,
 which holds the exact foods and quantities for each meal.
 I know mealfoods has a "meal_date" in addition to the NDB_No, 
 so here's how I see the latest date I
 ate the expensive egg yolks:
-<P>
-<B><PRE>
+.PP
+.nf
 sqlite> select max(meal_date) from mealfoods where NDB_No = 99010;
 20140423
-</B></PRE>
-<P>
+.fi
+.PP
 Here's something you frugalvores might be interested in.  I added a table called "cost":
-<P>                         
-<B><PRE>
+.PP                         
+.nf
 sqlite> .schema cost
 CREATE TABLE cost (NDB_No int primary key, cost real, store text);
-</B></PRE>
-<P>
+.fi
+.PP
 The actual cost column is dollars per 100 grams of food and after I figure out the NDB_No for the food I set it with an insert command like this:
-<P>
-<B><PRE>
+.PP
+.nf
 sqlite> select NDB_No, Long_Desc from food_des where Long_Desc like '%romaine%';
 11251|Lettuce, cos or romaine, raw (Lactuca sativa var. logifolia)
 sqlite> insert into cost values (11251, 0.25841296, 'Smart & Final');
-</B></PRE>
-<P>
+.fi
+.PP
 This says that 100 grams of romaine lettuce costs about $0.25 when bought from Smart & Final.
 Here's how I find my actual cost per day for the last week:
-<P>
-<B><PRE>
+.PP
+.nf
 sqlite> select meal_date, round(sum(mhectograms * cost),2) from mealfoods natural join food_des natural join cost group by meal_date order by meal_date desc limit 7;
 20150224|10.32
 20150223|10.16
@@ -624,17 +602,17 @@ sqlite> select meal_date, round(sum(mhectograms * cost),2) from mealfoods natura
 20150220|10.84
 20150219|10.6
 20150218|10.84
-</B></PRE>
-<P>
+.fi
+.PP
 A "natural join" means you don't have to specify the columns you are using for
 a join between tables, and the database has been set up so that natural joins 
 will
 work most of the time to get useful results.
-<P>
+.PP
 If I want to see the previous query every day but it is too much of a drag to
 type it in every time, I can create a view:
-<P>
-<B><PRE>
+.PP
+.nf
 sqlite> create view weeklycost as select meal_date, round(sum(mhectograms * cost),2) from mealfoods natural join food_des natural join cost group by meal_date order by meal_date desc limit 7;
 sqlite> select * from weeklycost;
 20150224|10.32
@@ -644,20 +622,20 @@ sqlite> select * from weeklycost;
 20150220|10.84
 20150219|10.6
 20150218|10.84
-</B></PRE>
-<P>
+.fi
+.PP
 Here's how I find which of the foods I buy is the cheapest source of copper (see below for how I know the copper column is named "CU"):
-<P>
-<B><PRE>
+.PP
+.nf
 sqlite> select Shrt_Desc, cost / CU as val from cost natural join food_des where val is not null order by val limit 1;
-Seeds, sunflower seed kernels, dried (helianthus annuus)|0.332843857072932
-</B></PRE>
-<P>
+Seeds, s.nfower seed kernels, dried (helianthus annuus)|0.332843857072932
+.fi
+.PP
 In the same vein, although not joinable to the other tables because it
 allows non-food items, if I need
 a shopping list:
-<P>
-<B><PRE>
+.PP
+.nf
 sqlite> .schema shopping
 CREATE TABLE shopping (n integer primary key, item text);
 sqlite> insert into shopping values (null, 'radishes');
@@ -665,33 +643,33 @@ sqlite> insert into shopping values (null, 'salmon');
 sqlite> select * from shopping;
 1|radishes
 2|salmon
-</B></PRE>
-<P>
+.fi
+.PP
 Now a food question relevant to ketogenic diets:  How do the lettuces rate for
 maximum potassium per gram of non-fiber carb?
-<P>
-<B><PRE>
+.PP
+.nf
 sqlite> select NDB_No, Shrt_Desc, round(K / CHO_NONFIB) as val from food_des where Long_Desc like 'Lettuce%' order by val desc;
 11250|Lettuce,butterhead (incl boston&bibb types),raw|211.0
 11251|Lettuce, cos or romaine, raw (lactuca sativa var. logifolia)|208.0
 11257|Lettuce, red leaf, raw (lactuca sativa var. crispa)|138.0
 11253|Lettuce, green leaf, raw (lactuca sativa var. crispa)|124.0
 11252|Lettuce,iceberg (incl crisphead types),raw|80.0
-</B></PRE>
-<P>
+.fi
+.PP
 I've been experimenting with coconut oil on my ketogenic diet.
 Sometimes I feel I've been having too much and I cut back and other
 times I feel I could use more, so I increase it, but I do not have any
 idea what amount of coconut oil per meal has seemed satisfactory most
 of the time.  I know the NDB_No is 4047, so what I am going to do is
 to make a list of how much coconut oil I had per meal for the various
-days and then count the occurences of each amount of coconut oil, to
+days and then count the occurrences of each amount of coconut oil, to
 see what were my most popular amounts of coconut oil per meal.
 The first column is ounces of coconut oil and the second column is a count of the
 days when I had that much.  I can see that 1.1 ounces per meal (a little over 2
 tablespoons) was my most common dosage per meal:
-<P>
-<B><PRE>
+.PP
+.nf
 sqlite> select val, count(meal_date) as ct from (select meal_date, round(sum(mhectograms / .2835 / 3.0),1) as val from mealfoods where NDB_No = 4047 group by meal_date order by val) group by val order by ct;
 0.1|1
 0.3|1
@@ -710,63 +688,63 @@ sqlite> select val, count(meal_date) as ct from (select meal_date, round(sum(mhe
 1.2|18
 1.0|19
 1.1|27
-</B></PRE>
-<P>
+.fi
+.PP
 If you're interested in Omega-3 fatty acids, here's a view that does the
 computation that
-<B>NUT</B>
+.B NUT
 uses, and then we can answer the question "What (supposedly)
 was the percentage of Omega-6 in my tissue phospholipids
 during the summer of 2014?" 
-<P>
-<B><PRE>
+.PP
+.nf
 sqlite> .schema n6hufacalc
-CREATE VIEW n6hufacalc as select meal_id, 100.0 / (1.0 + 0.0441 / (900 * SHORT6 / ENERC_KCAL) * (1.0 + (900 * SHORT3 / ENERC_KCAL) / 0.0555 + (900 * LONG3 / ENERC_KCAL) / 0.005 + (900 * (FASAT + FAMS + FAPU - SHORT6 - LONG6 - SHORT3 - LONG3) / ENERC_KCAL) / 5.0 + (900 * SHORT6 / ENERC_KCAL) / 0.175)) + 100.0 / (1.0 + 0.7 / (900 * LONG6 / ENERC_KCAL) * (1.0 + (900 * SHORT3 / ENERC_KCAL) / 3.0)) as n6hufa from meals;
+CREATE VIEW n6hufacalc as select meal_id, 100.0 / (1.0 + 0.0441 / (900 * SHORT6 / ENERC_KCAL) * (1.0 + (900 * SHORT3 / ENERC_KCAL) / 0.0555 + (900 * LONG3 / ENERC_KCAL) / 0.005 + (900 * (FASAT + FAMS + FAPU - SHORT6 - LONG6 - SHORT3 - LONG3) / ENERC_KCAL) / 5.0 + (900 * SHORT6 / ENERC_KCAL) / 0.175)) + 100.0 / (1.0 + 0.7 / (900 * LONG6 / ENERC_KCAL) * (1.0 + (900 * LONG3 / ENERC_KCAL) / 3.0)) as n6hufa from meals;
 sqlite> select round(avg(n6hufa)) from n6hufacalc where meal_id between 2014060000 and 2014090000;
 57.0
-</B></PRE>
-<P>
+.fi
+.PP
 The next query concerns how non-fiber carb has varied in my diet, but I
 need to explain a few technicalities first.  If you compare the
-<B>NUT</B>
+.B NUT
 tables to the USDA tables, you can see that
-<B>NUT</B>
+.B NUT
 doesn't have the USDA's "nut_data" table which contains the nutrient values.
 This is because the food_des and meals tables have columns that contain the
 nutrient values, and these columns are named after the corresponding "Tagname"
 column in the table nutr_def, the nutrient definitions.  For instance:
-<P>                         
-<B><PRE>
+.PP                         
+.nf
 sqlite> select Tagname, NutrDesc from nutr_def where NutrDesc = 'Non-Fiber Carb';
 CHO_NONFIB|Non-Fiber Carb
-</B></PRE>
-<P>
+.fi
+.PP
 So, "CHO_NONFIB" is the "Non-Fiber Carb" column in both food_des and meals.
 The meals table contains the nutrient values for each meal; think of it as 
 the sum of the foods in the mealfoods table grouped by each meal.  But while
 mealfoods has a "meal_date" and "meal" column to identify a meal, the meals
 table has a single "meal_id" column which concatenates both meal_date and meal
 into a single 10-digit long integer:
-<P>
-<B><PRE>
+.PP
+.nf
 sqlite> select max(meal_id) from meals;
 2014100701
-</B></PRE>
-<P>
+.fi
+.PP
 This is meal #1 from October 7, 2014.
 Using integer division using whole numbers only, I can divide to get just the
 year and month like this:
-<P>
-<B><PRE>
+.PP
+.nf
 sqlite> select max(meal_id) / 10000 from meals;
 201410
-</B></PRE>
-<P>
+.fi
+.PP
 So now here's the query to answer the question "What was my average non-fiber
 carb intake each month?"  Since I eat three meals a day and each meal is a
 third of a day, I need to also multiply the average by three:
-<P>
-<B><PRE>
+.PP
+.nf
 sqlite> select meal_id / 10000, avg(CHO_NONFIB) * 3 from meals group by meal_id / 10000;
 201310|304.619325085423
 201311|308.119947531993
@@ -781,13 +759,13 @@ sqlite> select meal_id / 10000, avg(CHO_NONFIB) * 3 from meals group by meal_id
 201408|20.2894606139836
 201409|17.1093763102545
 201410|20.3265642461782
-</B></PRE>
-<P>
+.fi
+.PP
 To tie it all together, let's join this result to the wlog table to answer the question "How did my lean mass vary with these monthly
 carb levels?"  Because I am joining on a customized date representation, I can't use a
 natural join, and I have to spell out the whole syntax for joins to specify what is going to be equal to what:
-<P>                                                          
-<B><PRE>
+.PP                                                          
+.nf
 sqlite> select m.meal_id / 10000, avg(m.CHO_NONFIB) * 3, avg(w.weight - w.weight * w.bodyfat / 100) from meals m join wlog w on m.meal_id / 10000 = w.wldate / 100 group by m.meal_id / 10000;
 201310|304.619325085423|120.8396
 201311|308.119947531993|119.149733333333
@@ -802,48 +780,20 @@ sqlite> select m.meal_id / 10000, avg(m.CHO_NONFIB) * 3, avg(w.weight - w.weight
 201409|17.1093763102544|119.682223076924
 201410|20.3265642461782|120.523828571428
 sqlite> .quit
-</B></PRE>
-<P>
-<A NAME="lbAE"> </A>
-<H2>FILES</H2>
-
-<PRE>
-
-nut.sqlite      All personal data, the USDA Nutrient Database, and Tcl scripts
-updateNUT.tcl	Tcl script to create or update the NUT code in the database
-nut.tcl		Tcl script to start the NUTsqlite program
-</PRE>
-
-<A NAME="lbAF"> </A>
-<H2>AUTHOR</H2>
-
-<P>
-
-<PRE>
-Jim Jozwiak (<A HREF="mailto:jozwiak at gmail.com">jozwiak at gmail.com</A>, <A HREF="mailto:av832 at lafn.org">av832 at lafn.org</A>)
-<A HREF="http://nut.sourceforge.net/">http://nut.sourceforge.net/</A>
-</PRE><A NAME="lbAG"> </A>
-<H2>COPYING</H2>
-
-<P>
-
-Copyright (C) 1996-2016 by Jim Jozwiak.
-<P>
-
-<HR>
-<A NAME="index"> </A><H2>Index</H2>
-<DL>
-<DT><A HREF="#lbAB">NAME</A><DD>
-<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
-<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
-<DT><A HREF="#lbAE">FILES</A><DD>
-<DT><A HREF="#lbAF">AUTHOR</A><DD>
-<DT><A HREF="#lbAG">COPYING</A><DD>
-</DL>
-<HR>
-This document was created by
-<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
-using the manual pages.<BR>
-Time: 19:56:09 GMT, June 13, 2014
-</BODY>
-</HTML>
+.fi
+.PP
+.LP 
+.SH "FILES"
+.nf
+nut.sqlite    All personal data, the USDA Nutrient Database, and Tcl scripts
+updateNUT.tcl Tcl script to create or update the NUT code in the database
+nut.tcl       Tcl script to start the NUTsqlite program
+.fi 
+.SH "AUTHOR"
+.LP 
+.nf
+Jim Jozwiak (jozwiak at gmail.com)
+http://nut.sourceforge.net/
+.SH "COPYING"
+.LP 
+Copyright (C) 1996-2017 by Jim Jozwiak.
diff --git a/nut.tcl b/nut.tcl
index 77a9892..1bda053 100755
--- a/nut.tcl
+++ b/nut.tcl
@@ -3,7 +3,7 @@
 exec tclsh "$0" "$@"
 
 # NUT nutrition software
-# Copyright (C) 1996-2016 by Jim Jozwiak.
+# Copyright (C) 1996-2017 by Jim Jozwiak.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/nutdoc.html b/nutdoc.html
index dd82a8e..34456a5 100644
--- a/nutdoc.html
+++ b/nutdoc.html
@@ -336,7 +336,7 @@ site at
 <A HREF="http://nut.sourceforge.net/">http://nut.sourceforge.net/</A>.
 <P>
 (Following is a description of the rightmost column on the screen that concerns
-the weight log.  At some lower screen resolutions, this column is partially occluded.  However, if you move the mouse
+the weight log.  At some lower screen resolutions, this column can be partially occluded.  However, if you move the mouse
 over the imaginary line between the program settings and the weight log columns,
 there will appear a double arrow that you can click and drag to the left to
 bring the weight log column into full view.)
@@ -378,40 +378,25 @@ Calorie "Auto-Set" means that you will eat according to the calorie level that
 <B>NUT</B>
 shows and also record your weight and bodyfat percentage daily.
 <B>NUT</B>
-can then determine how best to move the calorie level to achieve gains in
-lean mass and loss of fat mass. A cycle begins when there are two weight/bodyfat data points recorded.  
+can then determine how best to move the calorie level so that gains in
+lean mass and loss of fat mass are possible. A cycle begins when there are two weight/bodyfat data points recorded.  
 <B>NUT</B>
-will move calories by a maximum of 20 calories a day during a  cycle. 
+will move calories by a maximum of 20 calories a day. 
 If both lean mass and fat mass are trending down, 
 <B>NUT</B> 
-raises calories; if both lean mass and fat mass are trending up,
+raises calories and starts a new cycle; if both lean mass and fat mass are trending up,
 <B>NUT</B>
-lowers calories.  When fat mass is trending up and lean mass is trending
+lowers calories and starts a new cycle.  When fat mass is trending up and lean mass is trending
 down, 
-<B>NUT</B> alternates between
-a cycle to prevent fat mass gain and a cycle to prevent lean mass loss.
-A cycle ends when fat mass is trending down and lean mass is trending up. (When a
-cycle begins with this favorable trend, it is allowed to continue.)
-At the end of a cycle, the average calories per day during the cycle
-becomes the new calorie level, and this  change may be more than 20 calories from the previous calorie setting.
+<B>NUT</B> starts a new cycle without changing calories.
+A cycle which begins with lean mass going up and fat mass going down is allowed to continue as long as the favorable trend prevails.  The last set of
+measurements is always retained for a quick start to the next cycle which means
+that whenever the weight log is cleared, you see  "1 data point so far..."
 <P>
 If you are not using the Calorie Auto-Set
 feature, you can clear the weight log whenever you like; the usual reason would
 be that you have started a new strategy and therefore want to see the new
-trend.   For instance, I tend to make five to seven days of measurements, check the numbers, move calories up or down as required, and then clear the weight log when I am trying to find the right calorie level for my latest experiment. The last weight log entry is always retained after clearing the weight log to enable a quicker start to the next cycle of logging.
-<P>
-So, should you use the Weight Log manually or use the Calorie Auto-Set feature?
-I think the Calorie Auto-Set feature is best when you really do have to cut
-calories and would rather delegate the responsibility to 
-<B>NUT</B>
-to avoid the psychological torture of having to cut yourself back.  
-And
-<B>NUT</B> can slowly improve your body composition without you having to
-really think about it.
-But do
-remember that you can always turn the feature off and refine your strategy if
-there is excessive hunger or other problems, or you can 
- adjust the calorie level manually to speed up or slow down the progress of the Calorie Auto-Set algorithm.
+trend.   For instance, I tend to make five to seven days of measurements, check the numbers, move calories up or down as required, and then clear the weight log when I am trying to find the right calorie level for my latest experiment. The last weight log entry is again retained after clearing the weight log to enable a quicker start to the next cycle of logging.
 <P>
 <B>THE STORY</B>
 <P>
@@ -525,16 +510,6 @@ sqlite> select wldate, round(weight - weight * bodyfat / 100, 1) as leanmass, ro
 20150619|125.3|32.3|93.0
 </B></PRE>
 <P>
-The Calorie Auto-Set feature alternates between cycles that potentially favor
-either lean mass gain or fat mass loss in the cases when fat mass is trending up
-and lean mass is trending down.  This is a switch you can manipulate, and it is
-the wlpolarity column in the table options.  "1" means favor lean mass gain, "0" means favor fat mass loss, and you would issue the command at the start
-of each Calorie Auto-Set cycle because the wlpolarity switches its state at the end of each cycle:
-<P>
-<B><PRE>
-sqlite> update options set wlpolarity = 1;
-</B></PRE>
-<P>
 Now, let's turn to a different task.  I've created a bad recipe and I want to
 delete it from the database.  First, I find the record in the food_des table and
 ask to see  "NDB_No", the primary key for foods:
@@ -563,6 +538,15 @@ from the database using the meal_date and meal number like this:
 sqlite> delete from mealfoods where meal_date = 20150413 and meal = 3;
 </B></PRE>
 <P>
+If the previous strategy then fails again when a meal is reloaded, it
+probably means the weight table has recorded some impossible weight.
+For instance, if you have determined there is more spinach in the meal
+than molecules in the universe, this command will fix it:
+<P>
+<B><PRE>
+sqlite> update weight set Amount = origAmount, whectograms = orighectograms where NDB_No = 11457;
+</B></PRE>
+<P>
 Although you can update some of the 
 <B>NUT</B>
 data manually as in the previous examples,
@@ -721,11 +705,20 @@ during the summer of 2014?"
 <P>
 <B><PRE>
 sqlite> .schema n6hufacalc
-CREATE VIEW n6hufacalc as select meal_id, 100.0 / (1.0 + 0.0441 / (900 * SHORT6 / ENERC_KCAL) * (1.0 + (900 * SHORT3 / ENERC_KCAL) / 0.0555 + (900 * LONG3 / ENERC_KCAL) / 0.005 + (900 * (FASAT + FAMS + FAPU - SHORT6 - LONG6 - SHORT3 - LONG3) / ENERC_KCAL) / 5.0 + (900 * SHORT6 / ENERC_KCAL) / 0.175)) + 100.0 / (1.0 + 0.7 / (900 * LONG6 / ENERC_KCAL) * (1.0 + (900 * SHORT3 / ENERC_KCAL) / 3.0)) as n6hufa from meals;
+CREATE VIEW n6hufacalc as select meal_id, 100.0 / (1.0 + 0.0441 / (900 * SHORT6 / ENERC_KCAL) * (1.0 + (900 * SHORT3 / ENERC_KCAL) / 0.0555 + (900 * LONG3 / ENERC_KCAL) / 0.005 + (900 * (FASAT + FAMS + FAPU - SHORT6 - LONG6 - SHORT3 - LONG3) / ENERC_KCAL) / 5.0 + (900 * SHORT6 / ENERC_KCAL) / 0.175)) + 100.0 / (1.0 + 0.7 / (900 * LONG6 / ENERC_KCAL) * (1.0 + (900 * LONG3 / ENERC_KCAL) / 3.0)) as n6hufa from meals;
 sqlite> select round(avg(n6hufa)) from n6hufacalc where meal_id between 2014060000 and 2014090000;
 57.0
 </B></PRE>
 <P>
+One of the users wanted a food journal in a particular format.  It looked
+simple but the SQL was surprisingly complicated:
+<P>
+<B><PRE>
+qlite> select id || group_concat(' ' || food) from (select cast(substr(meal_date, 5, 2) as int) || '/' || cast(substr(meal_date, 7) as int) || ' ' || case when meal = 1 then 'breakfast:' when meal = 2 then 'lunch:' else 'dinner:' end as id, token1 || ' ' || case when commapos = 0 then token2 else substr(token2, 1, commapos - 1) end as food from (select meal_date, meal, token1, token2, instr(token2, ',') as commapos from (select meal_date, meal, trim(substr(Long_Desc, 1, instr(Long_Desc,  [...]
+6/22 breakfast: Cheese cheddar, Oil coconut, Spinach raw (Spinacia oleracea), Tomatoes red, Nuts almonds, Beverages coffee, Fish sardine, Snacks pork skins, Cocoa dry powder, Oil flaxseed, Egg yolk, Chicken liver, Mushrooms brown, Artichokes (globe or french), Pork fresh, Beef ground
+6/22 lunch: Cheese cheddar, Oil coconut, Brussels sprouts raw (Brassica oleracea (Gemmifera Group)), Spinach raw (Spinacia oleracea), Tomatoes red, Nuts almonds, Beverages coffee, Snacks pork skins, Cocoa dry powder, Oil flaxseed, Egg yolk, Chicken liver, Mushrooms brown, Pork fresh, Chicken broilers or fryers, Beef ground
+</B></PRE>
+<P>
 The next query concerns how non-fiber carb has varied in my diet, but I
 need to explain a few technicalities first.  If you compare the
 <B>NUT</B>
@@ -820,14 +813,14 @@ nut.tcl		Tcl script to start the NUTsqlite program
 <P>
 
 <PRE>
-Jim Jozwiak (<A HREF="mailto:jozwiak at gmail.com">jozwiak at gmail.com</A>, <A HREF="mailto:av832 at lafn.org">av832 at lafn.org</A>)
+Jim Jozwiak (<A HREF="mailto:jozwiak at gmail.com">jozwiak at gmail.com</A>)
 <A HREF="http://nut.sourceforge.net/">http://nut.sourceforge.net/</A>
 </PRE><A NAME="lbAG"> </A>
 <H2>COPYING</H2>
 
 <P>
 
-Copyright (C) 1996-2016 by Jim Jozwiak.
+Copyright (C) 1996-2017 by Jim Jozwiak.
 <P>
 
 <HR>
diff --git a/updateNUT.tcl b/updateNUT.tcl
index 42b1401..a2ad976 100755
--- a/updateNUT.tcl
+++ b/updateNUT.tcl
@@ -3,7 +3,7 @@
 exec tclsh "$0" "$@"
 
 # NUT nutrition software
-# Copyright (C) 1996-2016 by Jim Jozwiak.
+# Copyright (C) 1996-2017 by Jim Jozwiak.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -29,7 +29,7 @@ db eval {create table if not exists version(version text primary key unique, upd
 set Main {
  
 # NUT nutrition software
-# Copyright (C) 1996-2016 by Jim Jozwiak.
+# Copyright (C) 1996-2017 by Jim Jozwiak.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -410,7 +410,7 @@ grid [scrollbar .nut.rm.frmenu.scrollv -width [expr {$::magnify * 5}] -relief su
 grid rowconfig .nut.rm.frmenu 0 -weight 1 -minsize 0
 grid columnconfig .nut.rm.frmenu 0 -weight 1 -minsize 0
 
-set ::PCFchoices {{No Auto Portion Control} {Protein} {Non-Fiber Carb} {Total Fat} {Vitamin A} {Thiamin} {Riboflavin} {Niacin} {Panto. Acid} {Vitamin B6} {Folate} {Vitamin B12} {Vitamin C} {Vitamin D} {Vitamin E} {Vitamin K1} {Calcium} {Copper} {Iron} {Magnesium} {Manganese} {Phosphorus} {Potassium} {Selenium} {Zinc} {Fiber}}
+set ::PCFchoices {{No Auto Portion Control} {Protein} {Non-Fiber Carb} {Total Fat} {Vitamin A} {Thiamin} {Riboflavin} {Niacin} {Panto. Acid} {Vitamin B6} {Folate} {Vitamin B12} {Vitamin C} {Vitamin D} {Vitamin E} {Vitamin K1} {Calcium} {Copper} {Iron} {Magnesium} {Manganese} {Phosphorus} {Potassium} {Selenium} {Zinc} {Glycine} {Retinol} {Fiber}}
 set ::rmMenu .nut.rm.frmenu
 grid remove .nut.rm.frmenu
 
@@ -489,8 +489,14 @@ foreach x {am rm vf ar} {
   }
  foreach nut {CHO_NONFIB} {
   grid [ttk::button .nut.${x}.nbw.screen${screen}.b${nut} -textvariable ::${nut}b -command "NewStory $nut $x" -style "nutbutton.TButton"] -row $row -column $bcol -columnspan 3 -sticky we
-  if {$x == "ar"} {grid [ttk::entry .nut.${x}.nbw.screen${screen}.l${nut} -textvariable ::${nut}${x}1 -justify right -width 8] -row $row -column $valcol -columnspan 2 -sticky e} else {grid [ttk::label .nut.${x}.nbw.screen${screen}.l${nut} -textvariable ::${nut}${x}1 -style ${x}.TLabel] -row $row -column $valcol -columnspan 2 -sticky e}
-  grid [ttk::label .nut.${x}.nbw.screen${screen}.lu${nut} -textvariable ::${nut}u -style ${x}.TLabel] -row $row -column $ucol -sticky w
+   if {$x == "ar"} {grid [ttk::entry .nut.${x}.nbw.screen${screen}.l${nut} -textvariable ::${nut}${x}1 -justify right -width 8] -row $row -column $valcol -columnspan 2 -sticky e} else {grid [ttk::label .nut.${x}.nbw.screen${screen}.l${nut} -textvariable ::${nut}${x}1 -style ${x}.TLabel] -row $row -column $valcol -columnspan 2 -sticky e}
+   grid [ttk::label .nut.${x}.nbw.screen${screen}.lu${nut} -textvariable ::${nut}u -style ${x}.TLabel] -row $row -column $ucol -sticky w
+
+#uncomment these two lines and comment out the previous two if user insists he
+#must see CHO_NONFIB percentage of DV instead of grams
+
+#   if {$x == "ar"} {grid [ttk::entry .nut.${x}.nbw.screen${screen}.l${nut} -textvariable ::${nut}${x}1 -justify right -width 8] -row $row -column $valcol -columnspan 2 -sticky e} else {grid [ttk::label .nut.${x}.nbw.screen${screen}.l${nut} -textvariable ::${nut}${x}dv -style ${x}.TLabel] -row $row -column $valcol -columnspan 2 -sticky e}
+#   grid [ttk::label .nut.${x}.nbw.screen${screen}.lu${nut} -text "%" -style ${x}.TLabel] -row $row -column $ucol -sticky w
   incr row
   }
  set row 3
@@ -941,6 +947,15 @@ destroy .loadframe
 set Start_NUT {
 
 db nullvalue "\[No Data\]"
+
+#If user didn't reload USDA database, he won't pickup Retinol & Glycine change.
+#This ensures Retinol & Glycine are now DV nutrients
+
+db eval {update nutr_def set dv_default = case when (select dv_default from nutr_def where NutrDesc = 'Retinol') = 0.0 then 7.0 else dv_default end where NutrDesc = 'Retinol'}
+db eval {update nutr_def set dv_default = case when (select dv_default from nutr_def where NutrDesc = 'Glycine') = 0.0 then 7.0 else dv_default end where NutrDesc = 'Glycine'}
+
+#end of special Retinol & Glycine update
+
 db eval {select Tagname, NutrDesc, Units from nutr_def} {
  set nut $Tagname
  set ::${nut}b $NutrDesc
@@ -1454,6 +1469,11 @@ proc InitializePersonalOptions {args} {
   set ::CHO_NONFIBpo 0 
   .nut.po.pane.optframe.fat_cb2 configure -text "Balance of Calories"
   }
+ if {$::ENERC_KCALopt == -1.0} {
+  .nut.po.pane.optframe.fat_cb2 configure -text "DV 30% of Calories"
+  .nut.po.pane.optframe.nfc_cb2 configure -text "DV 60% of Calories"
+  }
+  
 
  if {$::FIBTGopt == -1.0} {
   .nut.po.pane.optframe.fiber_s configure -state disabled -textvariable ::FIBTGdv
@@ -1511,14 +1531,20 @@ proc ChangePersonalOptions {nuttag args} {
    db eval {update options set autocal = 2}
    set ::ENERC_KCALopt $::ENERC_KCALdv
    .nut.po.pane.optframe.cal_s configure -state normal -textvariable ::ENERC_KCALopt
+   .nut.po.pane.optframe.nfc_cb2 configure -text "Balance of Calories"
+   .nut.po.pane.optframe.nfc_cb2 invoke
    } elseif {$povar == 0} {
    db eval {update options set autocal = 0}
    set ::ENERC_KCALopt $::ENERC_KCALdv
    .nut.po.pane.optframe.cal_s configure -state normal -textvariable ::ENERC_KCALopt
+   .nut.po.pane.optframe.nfc_cb2 configure -text "Balance of Calories"
+   .nut.po.pane.optframe.nfc_cb2 invoke
    } else {
    db eval {update options set autocal = 0}
    .nut.po.pane.optframe.cal_s configure -state disabled -textvariable ::ENERC_KCALdv
    set ::ENERC_KCALopt -1
+   .nut.po.pane.optframe.fat_cb2 configure -text "DV 30% of Calories"
+   .nut.po.pane.optframe.nfc_cb2 configure -text "DV 60% of Calories"
    }
   RefreshWeightLog
   } elseif {$nuttag == "FAT"} {
@@ -1528,13 +1554,13 @@ proc ChangePersonalOptions {nuttag args} {
    } elseif {$povar == 0} {
    set ::FATopt $::FATdv
    .nut.po.pane.optframe.fat_s configure -state normal -textvariable ::FATopt
-   if {$::CHO_NONFIBopt != 0.0} {
+   if {$::CHO_NONFIBopt != 0.0 && $::ENERC_KCALopt >= 0.0} {
     .nut.po.pane.optframe.nfc_cb2 invoke
     }
    } else {
    .nut.po.pane.optframe.fat_s configure -state disabled -textvariable ::FATdv
    set ::FATopt -1
-   if {$::CHO_NONFIBopt != 0.0} {
+   if {$::CHO_NONFIBopt != 0.0 && $::ENERC_KCALopt >= 0.0} {
     .nut.po.pane.optframe.nfc_cb2 invoke
     }
    }
@@ -1558,14 +1584,14 @@ proc ChangePersonalOptions {nuttag args} {
    set ::CHO_NONFIBopt $::CHO_NONFIBdv
    .nut.po.pane.optframe.nfc_s configure -state normal -textvariable ::CHO_NONFIBopt
    .nut.po.pane.optframe.fat_cb2 configure -text "Balance of Calories"
-   if {$::FATopt != 0.0} {
+   if {$::FATopt != 0.0 && $::ENERC_KCALopt >= 0.0} {
     .nut.po.pane.optframe.fat_cb2 invoke
     }
    } else {
    .nut.po.pane.optframe.nfc_s configure -state disabled -textvariable ::CHO_NONFIBdv
    set ::CHO_NONFIBopt -1
    .nut.po.pane.optframe.fat_cb2 configure -text "Balance of Calories"
-   if {$::FATopt != 0.0} {
+   if {$::FATopt != 0.0 && $::ENERC_KCALopt >= 0.0} {
     .nut.po.pane.optframe.fat_cb2 invoke
     }
    }
@@ -1671,7 +1697,7 @@ proc RefreshWeightLog {args} {
  if {($leanslope > 0.0 && $::fatslope > 0.0) || ($wlpolarity == 0 && $::fatslope > 0.0)} {set CASmode Cutting}
  set datapoints [db eval {select count(*) from wlog where cleardate is null}]
  if {$datapoints > 1} {
-  set ::wlogsummary "Based on the trend of $datapoints data points so far...\n\nPredicted lean mass today = [expr {round(10.0 * ($::weightyintercept - $::fatyintercept)) / 10.0 }]\n\nPredicted fat mass today = $::fatyintercept\n\nIf the predictions are correct, you [expr {$leanslope >= 0.0 ? "gained" : "lost"}] [expr {abs(round($leanslope * $::span * 1000.0) / 1000.0)}] lean mass over $::span [expr {$::span == 1 ? "day" : "days"}] and [expr {$::fatslope >= 0.0 ? "gained" : "lost"}] [expr [...]
+  set ::wlogsummary "Based on the trend of $datapoints data points so far...\n\nPredicted lean mass today = [expr {round(10.0 * ($::weightyintercept - $::fatyintercept)) / 10.0 }]\n\nPredicted fat mass today = $::fatyintercept\n\nIf the predictions are correct, you [expr {$leanslope >= 0.0 ? "gained" : "lost"}] [expr {abs(round($leanslope * $::span * 1000.0) / 1000.0)}] lean mass over $::span [expr {$::span == 1 ? "day" : "days"}] and [expr {$::fatslope >= 0.0 ? "gained" : "lost"}] [expr [...]
   } else { set ::wlogsummary "" } 
  if {$datapoints == 1} {
   db eval {select weight as "::weightyintercept", bodyfat as "::currentbfp" from wlog where cleardate is null} { }
@@ -1689,12 +1715,12 @@ proc ClearWeightLog {args} {
 db eval {select * from wlog order by wldate desc limit 1} { }
 db eval {update wlog set cleardate = $wldate where cleardate is null}
 db eval {insert into wlog values ($weight, $bodyfat, $wldate, NULL)}
-db eval {update options set wltweak = 0}
 RefreshWeightLog
 }
 
 #end ClearWeightLog
 }
+
 set AcceptNewMeasurements {
 
 proc AcceptNewMeasurements {args} {
@@ -1702,37 +1728,27 @@ proc AcceptNewMeasurements {args} {
 set today [db eval {select strftime('%Y%m%d', 'now', 'localtime')}]
 db eval {insert into wlog values ( $::weightyintercept, $::currentbfp, $today, NULL)}
 RefreshWeightLog
-db eval {select autocal, wlpolarity, wltweak, "::weightslope", "::fatslope", "::weightslope" - "::fatslope" as leanslope, "::fatyintercept" from options, weightslope, fatslope} { }
+db eval {select autocal, "::weightslope", "::fatslope", "::weightslope" - "::fatslope" as leanslope, "::fatyintercept" from options, weightslope, fatslope} { }
 
 if {$autocal == 2} {
  if {$leanslope > 0.0 && $::fatslope > 0.0} {
   set ::ENERC_KCALopt [expr {$::ENERC_KCALopt - 20.0}]
-  db eval {update options set wltweak = 1}
+  db eval {update wlog set cleardate = $today where cleardate is NULL}
+  set ::currentbfp [expr {round(1000.0 * $::fatyintercept / $::weightyintercept) / 10.0}]
+  db eval {insert into wlog values ( $::weightyintercept, $::currentbfp, $today, NULL)}
   auto_cal
   } elseif {$leanslope < 0.0 && $::fatslope < 0.0} { 
   set ::ENERC_KCALopt [expr {$::ENERC_KCALopt + 20.0}]
-  db eval {update options set wltweak = 1}
-  auto_cal
-  } elseif {$wlpolarity == 0 && $::fatslope > 0.0} {
-  set ::ENERC_KCALopt [expr {$::ENERC_KCALopt - 20.0}]
-  db eval {update options set wltweak = 1}
-  auto_cal
-  } elseif {$wlpolarity == 1 && $leanslope < 0.0} {
-  set ::ENERC_KCALopt [expr {$::ENERC_KCALopt + 20.0}]
-  db eval {update options set wltweak = 1}
-  auto_cal
-  } elseif {$leanslope > 0.0 && $::fatslope < 0.0 && $wltweak == 1} {
-  set firstwldate [db eval {select min(wldate) from wlog where cleardate is null}]
-  set newcalorielevel [db eval "select round(sum(ENERC_KCAL) / $::span ) from meals where meal_id / 100 >= $firstwldate and meal_id / 100 < $today"]
   db eval {update wlog set cleardate = $today where cleardate is NULL}
   set ::currentbfp [expr {round(1000.0 * $::fatyintercept / $::weightyintercept) / 10.0}]
   db eval {insert into wlog values ( $::weightyintercept, $::currentbfp, $today, NULL)}
-  db eval {update options set wltweak = 0, wlpolarity = case when wlpolarity = 1 then 0 else 1 end}
-  set ::ENERC_KCALopt $newcalorielevel
   auto_cal
+  } elseif {$::fatslope > 0.0} {
+  db eval {update wlog set cleardate = $today where cleardate is NULL}
+  set ::currentbfp [expr {round(1000.0 * $::fatyintercept / $::weightyintercept) / 10.0}]
+  db eval {insert into wlog values ( $::weightyintercept, $::currentbfp, $today, NULL)}
   }
  }
-
 RefreshWeightLog
 }
 
@@ -3411,7 +3427,7 @@ proc theusualPopulateMenu { } {
 set theusualAdd {
 
 proc theusualAdd {mealname} {
- set addlist [db eval {select t.NDB_No, PCF, Shrt_Desc from theusual t, food_des f using (NDB_No) where meal_name = $mealname order by Long_Desc asc}]
+ set addlist [db eval {select t.NDB_No, PCF, Shrt_Desc from theusual t, food_des f using (NDB_No) where meal_name = $mealname order by Shrt_Desc asc}]
  if {[llength $addlist] > 0} {
   if {!$::ALTGUI} {
    grid remove .nut.rm.setmpd
@@ -3724,7 +3740,7 @@ set gramsvf 0
 set ouncesvf 0
 set caloriesvf 0
 set Amountvf 0
-set ::PCFchoices {{No Auto Portion Control} {Protein} {Non-Fiber Carb} {Total Fat} {Vitamin A} {Thiamin} {Riboflavin} {Niacin} {Panto. Acid} {Vitamin B6} {Folate} {Vitamin B12} {Vitamin C} {Vitamin D} {Vitamin E} {Vitamin K1} {Calcium} {Copper} {Iron} {Magnesium} {Manganese} {Phosphorus} {Potassium} {Selenium} {Zinc} {Fiber}}
+set ::PCFchoices {{No Auto Portion Control} {Protein} {Non-Fiber Carb} {Total Fat} {Vitamin A} {Thiamin} {Riboflavin} {Niacin} {Panto. Acid} {Vitamin B6} {Folate} {Vitamin B12} {Vitamin C} {Vitamin D} {Vitamin E} {Vitamin K1} {Calcium} {Copper} {Iron} {Magnesium} {Manganese} {Phosphorus} {Potassium} {Selenium} {Zinc} {Glycine} {Retinol} {Fiber}}
 set ::rmMenu .nut.rm.frmenu
 
 ttk::notebook .nut 
@@ -4154,9 +4170,19 @@ foreach x {am rm vf ar} {
   if {$x == "ar"} {
    ttk::entry .nut.${x}.nbw.screen${screen}.l${nut} -textvariable ::${nut}${x}1 -justify right
    } else {
-   label .nut.${x}.nbw.screen${screen}.l${nut} -textvariable ::${nut}${x}1 -background $background($x) -anchor e
+    label .nut.${x}.nbw.screen${screen}.l${nut} -textvariable ::${nut}${x}1 -background $background($x) -anchor e
+
+#uncomment this line and comment out the previous if user insists he
+#must see CHO_NONFIB percentage of DV instead of grams
+
+#    label .nut.${x}.nbw.screen${screen}.l${nut} -textvariable ::${nut}${x}dv -background $background($x) -anchor e
    }
-  label .nut.${x}.nbw.screen${screen}.lu${nut} -textvariable ::${nut}u -background $background($x) -anchor w
+   label .nut.${x}.nbw.screen${screen}.lu${nut} -textvariable ::${nut}u -background $background($x) -anchor w
+
+#uncomment this line and comment out the previous if user insists he
+#must see CHO_NONFIB percentage of DV instead of grams
+
+#   label .nut.${x}.nbw.screen${screen}.lu${nut} -text "%" -background $background($x) -anchor w
   place .nut.${x}.nbw.screen${screen}.b${nut} -relx 0.665 -rely $rely -relheight 0.06 -relwidth 0.165
   place .nut.${x}.nbw.screen${screen}.l${nut} -relx 0.84 -rely $rely -relheight 0.06 -relwidth 0.1
   place .nut.${x}.nbw.screen${screen}.lu${nut} -relx 0.94 -rely $rely -relheight 0.06 -relwidth 0.055
@@ -7323,6 +7349,70 @@ proc ::VITEnew_vf {args} {
 #end ::VITEnew_vf
 }
 
+set ::GLY_Gdv_change {
+
+proc ::GLY_Gdv_change {args} {
+ }
+
+#end ::GLY_Gdv_change
+}
+
+set ::GLY_Gnew_dv {
+
+proc ::GLY_Gnew_dv {args} {
+ }
+
+#end ::GLY_Gnew_dv
+}
+
+set ::GLY_Gnew_rm {
+
+proc ::GLY_Gnew_rm {args} {
+ }
+
+#end ::GLY_Gnew_rm
+}
+
+set ::GLY_Gnew_vf {
+
+proc ::GLY_Gnew_vf {args} {
+ }
+
+#end ::GLY_Gnew_vf
+}
+
+set ::RETOLdv_change {
+
+proc ::RETOLdv_change {args} {
+ }
+
+#end ::RETOLdv_change
+}
+
+set ::RETOLnew_dv {
+
+proc ::RETOLnew_dv {args} {
+ }
+
+#end ::RETOLnew_dv
+}
+
+set ::RETOLnew_rm {
+
+proc ::RETOLnew_rm {args} {
+ }
+
+#end ::RETOLnew_rm
+}
+
+set ::RETOLnew_vf {
+
+proc ::RETOLnew_vf {args} {
+ }
+
+#end ::RETOLnew_vf
+}
+
 set load_nutr_def {
 
 proc load_nutr_def {args} {
@@ -7551,6 +7641,8 @@ dbmem eval {update nutr_def set dv_default = 4.7 where Tagname = 'LA'}
 dbmem eval {update nutr_def set dv_default = 4.0 where Tagname = 'OMEGA3'}
 dbmem eval {update nutr_def set dv_default = 4.9 where Tagname = 'OMEGA6'}
 dbmem eval {update nutr_def set dv_default = 32.6 where Tagname = 'FAMS'}
+dbmem eval {update nutr_def set dv_default = 7.0 where Tagname = 'GLY_G'}
+dbmem eval {update nutr_def set dv_default = 900.0 where Tagname = 'RETOL'}
 dbmem eval {COMMIT}
 dbmem eval {drop table ttnutr_def}
 dbmem eval {drop table tnutr_def}
@@ -7863,7 +7955,7 @@ if {[dbmem eval {select count(*) from options}] == 0} {
 }
 
 db eval {BEGIN}
-db eval {insert or replace into version values('NUTsqlite 1.9.9.3',NULL)}
+db eval {insert or replace into version values('NUTsqlite 1.9.9.6',NULL)}
 db eval {delete from tcl_code}
 db eval {insert or replace into tcl_code values('Main',$Main)}
 db eval {insert or replace into tcl_code values('InitialLoad',$InitialLoad)}
@@ -8110,6 +8202,14 @@ db eval {insert or replace into tcl_code values('::VITEdv_change',$::VITEdv_chan
 db eval {insert or replace into tcl_code values('::VITEnew_dv',$::VITEnew_dv)}
 db eval {insert or replace into tcl_code values('::VITEnew_rm',$::VITEnew_rm)}
 db eval {insert or replace into tcl_code values('::VITEnew_vf',$::VITEnew_vf)}
+db eval {insert or replace into tcl_code values('::GLY_Gdv_change',$::GLY_Gdv_change)}
+db eval {insert or replace into tcl_code values('::GLY_Gnew_dv',$::GLY_Gnew_dv)}
+db eval {insert or replace into tcl_code values('::GLY_Gnew_rm',$::GLY_Gnew_rm)}
+db eval {insert or replace into tcl_code values('::GLY_Gnew_vf',$::GLY_Gnew_vf)}
+db eval {insert or replace into tcl_code values('::RETOLdv_change',$::RETOLdv_change)}
+db eval {insert or replace into tcl_code values('::RETOLnew_dv',$::RETOLnew_dv)}
+db eval {insert or replace into tcl_code values('::RETOLnew_rm',$::RETOLnew_rm)}
+db eval {insert or replace into tcl_code values('::RETOLnew_vf',$::RETOLnew_vf)}
 db eval {insert or replace into tcl_code values('load_nutr_def',$load_nutr_def)}
 db eval {insert or replace into tcl_code values('load_fd_group',$load_fd_group)}
 db eval {insert or replace into tcl_code values('load_food_des1',$load_food_des1)}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/nutsqlite.git



More information about the debian-med-commit mailing list