<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2117852929156774743</id><updated>2011-04-21T12:40:41.830-06:00</updated><category term='ENDWHILE - TenFold consulting and development'/><title type='text'>ENDWHILE</title><subtitle type='html'>Enterprise TenFold development tips, tricks and ideas</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>32</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-6727190393104184076</id><published>2008-01-30T05:08:00.000-07:00</published><updated>2008-01-30T05:17:21.514-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>HowTo: Quickly and easily display the number of child instances</title><content type='html'>Here's a quick trick for displaying the number of child instances.&lt;br /&gt;1. Create a calculated field on the parent view of the view for which you want to total the number of instances. For example, if you have a set Named ViewCatalog with parent/child views of Catalog..CatalogItems, you put the calculated field on the parent view (Catalog).&lt;br /&gt;2. On the calculated field, right-click and select "Edit field details", then go to "Suggestions" and in the "Evaluate these conditions immediately after query" section, include the following, updated with the appropriate SetName and ViewName: InstanceCount (SetName, "ViewName"). In our example above it would read: InstanceCount (ViewCatalog, "CatalogItems"). Be sure to note that the set name does not use quotation marks but the View name does.&lt;br /&gt;3. You'll probably also want to make the field non-enterable and non-modifiable.&lt;br /&gt;&lt;br /&gt;Now whenever you query in this set, you'll see displayed the number of child instances.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-6727190393104184076?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/6727190393104184076/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=6727190393104184076' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/6727190393104184076'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/6727190393104184076'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2008/01/howto-quickly-and-easily-display-number.html' title='HowTo: Quickly and easily display the number of child instances'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-845620311700682658</id><published>2008-01-28T12:00:00.000-07:00</published><updated>2008-01-28T12:12:57.484-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>HowTo: Improve performance with better READ statements</title><content type='html'>When you're dealing with large sets of data, it's easy to get lazy and kill the performance of a TFL function. For example, I need to process some data in a parent/child set. I only want to process the data if a record in the child view meets certain criteria.&lt;br /&gt;&lt;br /&gt;The lazy way to do this is to READ your set and then WHILE through each parent, WHILE through each child, and then do your processing if a record in the child view meets your criteria.&lt;br /&gt;&lt;br /&gt;However, there's a much better way - READ only those records that have child data which meets your criteria, and don't get any records that don't meet your criteria. That way, you simply process everything that's returned.&lt;br /&gt;&lt;br /&gt;Using a View condition on your child view, or doing the READ below (which is basically the same as a View condition) will still return a parent record even if there is no child record matching your criteria (i.e. you'll still have to WHILE and IF in order to determine if you should process each record):&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt; READ JasonTestQuery ALL WHEN&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;    VIEW=Parent(ParentField1 = vParentValue) &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;    VIEW=Childparentid(ChildField1 = vChildValue)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;However, use the following READ statement and you'll *only* get parent records if there's a child record that matches your criteria - i.e. you can simply process everything that's returned because you already know it meets your criteria.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;READ JasonTestQuery ALL WHEN&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;   VIEW=Parent(ParentField1 = vParentValue AND ChildField1 = vChildValue) &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Enjoy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-845620311700682658?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/845620311700682658/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=845620311700682658' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/845620311700682658'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/845620311700682658'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2008/01/howto-improve-performance-with-better.html' title='HowTo: Improve performance with better READ statements'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-2629683673876260638</id><published>2008-01-24T06:58:00.000-07:00</published><updated>2008-01-25T06:38:22.162-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>Info: Table upgrade considerations</title><content type='html'>This article stems from &lt;a href="http://forum.tenfold.com/topic.asp?TOPIC_ID=402"&gt;this post&lt;/a&gt; on the TenFold message boards. Changing certain attributes or constraints on a logical table definition will require special work to complete an upgrade of the associated physical table. First, here's an explanation:&lt;br /&gt;&lt;br /&gt;Let's say, as in the forum post above, you have a table with two columns:&lt;br /&gt;- FirstName&lt;br /&gt;- LastName&lt;br /&gt;&lt;br /&gt;Let's also assume that you already have data in this table. However, you now want to add a SmartCode column for Gender. DesignDatabase does something quirky when you add a SmartCode column: It makes it requires. Don't ask me why, I have no idea.&lt;br /&gt;&lt;br /&gt;In itself this isn't a big deal, unless you understand the implications of adding a required column to a table that already contains data. Here's what happens and why it was problematic for the above post's author:&lt;br /&gt;1. TenFold creates a temporary table (tfddbackup) that's a copy of your target physical table&lt;br /&gt;2. TenFold copies the data from your target table into the tfddbackup table&lt;br /&gt;3. TenFold truncates the data in the target table and implements the changes (in this case it adds a new, required column)&lt;br /&gt;4. TenFold copies the data from tfddbackup into the *upgraded* target table&lt;br /&gt;&lt;br /&gt;Step 4 is where we run into problems. Because the poster added a new, required column on a table that already had data, when step 4 took place and TenFold tried to commit the data he received an error. The error makes sense once you understand what's happened, because he now has data in a table with a required column, but no data in said required column. The data doesn't meet the new constraints of the table definition and therefore the commit fails.&lt;br /&gt;&lt;br /&gt;The simple way to get around this is to make the SmartCode column non-required. However, there are other cases where you will encounter upgrade problems and you can't work around it by changing a column's attributes (maybe you actually *want* the new column's attributes). In these cases, should you want to preserve your existing data and not use a "Drop and recreate", you have a few options.&lt;br /&gt;&lt;br /&gt;First is to write a table upgrade. It's not terribly difficult, but it's not the most elegant process in the world. You can read about doing so in the DatabaseUpgrades document in Documanage.&lt;br /&gt;&lt;br /&gt;Personally, in all but the most challenging cases, I prefer to work around the issue with a little creativity. In the above example, if you wanted the SmartCode column to be required, you could implement it first as non-required, perform the table upgrade (it will succeed), and then manually or automatically (using a TFL function) update the table so that every instance contains data in the new, required column. You then change the column to be required and perform the upgrade again (which succeeds now that the data in your table meets the new constraint - i.e. every instance has data in the required column).&lt;br /&gt;&lt;br /&gt;I've also done table upgrades by exporting the table from the DB vendor, opening the export file, and changing the CREATE TABLE statement to include the changes I need to make. This works in a few cases and it's incredibly easy (plus, if all else fails, you have a backup of your table on-hand).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-2629683673876260638?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/2629683673876260638/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=2629683673876260638' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/2629683673876260638'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/2629683673876260638'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2008/01/info-table-upgrade-considerations.html' title='Info: Table upgrade considerations'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-7722309171192824265</id><published>2008-01-23T12:10:00.000-07:00</published><updated>2008-01-23T21:10:35.399-07:00</updated><title type='text'>TenFold Layoffs</title><content type='html'>If you haven't heard, TenFold completed a 40% reduction in force today. If your business lost consultants as a result of this development, please &lt;a href="mailto:jason@endwhile.com"&gt;contact me&lt;/a&gt;. ENDWHILE can help support your application while you decide how to proceed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-7722309171192824265?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/7722309171192824265/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=7722309171192824265' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/7722309171192824265'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/7722309171192824265'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2008/01/tenfold-layoffs.html' title='TenFold Layoffs'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-1224698821475941238</id><published>2008-01-08T05:28:00.000-07:00</published><updated>2008-01-08T05:29:32.655-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>Back from the Holidays</title><content type='html'>Getting back into the swing of things. New posts to come shortly. Hang tight...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-1224698821475941238?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/1224698821475941238/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=1224698821475941238' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/1224698821475941238'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/1224698821475941238'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2008/01/back-from-holidays.html' title='Back from the Holidays'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-5547310129543869366</id><published>2007-12-08T05:22:00.000-07:00</published><updated>2007-12-08T05:34:46.889-07:00</updated><title type='text'>Update: READ using Date for a DateTime column</title><content type='html'>&lt;a href="http://sharedtree.com"&gt;Trevor Allred&lt;/a&gt; emailed me and said that this is actually a database issue and that it has nothing to do with TenFold. Fair enough.&lt;br /&gt;&lt;br /&gt;Because I expect to repeatedly encounter this issue (how I've not until this point perplexes me), I've created a couple of functions to make it easy. You pass the date for which you want a date time returned (either the beginning of the day or the end of the day).&lt;br /&gt;&lt;br /&gt;Call it like this:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new; color: rgb(51, 0, 153);"&gt;LET vStartDate = DateToDateTimeStart(&amp;amp;DBToday)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;DateToDateTimeStartDate() looks like this:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new; color: rgb(51, 0, 153);"&gt;&lt;/span&gt;&lt;span style="font-family: courier new; color: rgb(51, 0, 153);"&gt;LET vDateString = DateToString (iStartDate, "YYYY/MM/DD")&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new; color: rgb(51, 0, 153);"&gt;LET vDateTimeString = vDate||'00:00:00'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new; color: rgb(51, 0, 153);"&gt;&lt;/span&gt;&lt;span style="font-family: courier new; color: rgb(51, 0, 153);"&gt;RETURN StringToDate(&lt;/span&gt;&lt;span style="font-family: courier new; color: rgb(51, 0, 153);"&gt;vDateTimeString &lt;/span&gt;&lt;span style="font-family: courier new; color: rgb(51, 0, 153);"&gt;, 'YYYY/MM/DD HH MI SS')&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new; color: rgb(51, 0, 153);"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-5547310129543869366?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/5547310129543869366/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=5547310129543869366' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/5547310129543869366'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/5547310129543869366'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/12/update-read-using-date-for-datetime.html' title='Update: READ using Date for a DateTime column'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-8219299279413751935</id><published>2007-12-06T04:08:00.000-07:00</published><updated>2007-12-06T04:29:54.161-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>How To: READ a date time field with only a date</title><content type='html'>I'd have to say that this little task is about the most annoying thing I've ever encountered in TenFold. Maybe I'm just dumb, or maybe I'm just spoiled because everything else in TenFold is so easy.&lt;br /&gt;&lt;br /&gt;Here's the scoop: I have a table against which I want to READ all the records created on a certain date. For this I want to use the CreationDateTime column in said table, which TenFold populates automatically. The problem is that CreationDateTime is a DateTime column, and I only want to supply a Date.&lt;br /&gt;&lt;br /&gt;Were you to do something like this in an attempt to retrieve all of the records created yesterday...:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153); font-family: courier new;"&gt;CALL AddDays (&amp;amp;DBToday, vDate, -1)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153); font-family: courier new;"&gt;READ Orders WHEN OrderCreationDateTime = vDate&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;...your READ statement would use the DateTime from &amp;amp;DBToday and it would show you only those records created yesterday at the exact same time of day that you run the function. That's not what I'm after.&lt;br /&gt;&lt;br /&gt;I want to know &lt;span style="font-style: italic;"&gt;ALL &lt;/span&gt;the records created yesterday. I tried just about every thing I could think of - converting the &amp;amp;DBToday DateTime to a Date string, using ApplyMask on both the &amp;amp;DBToday string as well as the CreationDateTime field in my set, trying to create a DateTime string for the start of the day and the end of the day and doing a READ between those DateTimes. No luck.&lt;br /&gt;&lt;br /&gt;Finally, I got some help from John Davenport. He saved my ass. I was headed down the right path with the last approach I listed, but there was more to it than I thought. Unfortunately, it's rather cumbersome what one must do to accomplish what should be a simple task. Here goes:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new; color: rgb(51, 0, 153);"&gt;CALL AddDays (&amp;amp;DBToday, vYesterday, -1)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new; color: rgb(51, 0, 153);"&gt;LET vDate = DateToString (vYesterday, "YYYY/MM/DD")&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new; color: rgb(51, 0, 153);"&gt;LET v1 = vDate||'00:00:00'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new; color: rgb(51, 0, 153);"&gt;LET v2 = vDate||'23:59:59'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new; color: rgb(51, 0, 153);"&gt;LET vStartDate = StringToDate(vStartDate, 'YYYY/MM/DD HH MI SS')&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new; color: rgb(51, 0, 153);"&gt;LET vEndDate = StringToDate(vEndDate, 'YYYY/MM/DD HH MI SS')&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new; color: rgb(51, 0, 153);"&gt;#Get list of yesterday's orders&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new; color: rgb(51, 0, 153);"&gt;READ Orders WHEN OrderCreationDateTime BETWEEN vStartDate  AND vEndDate&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;That's a lot of garbage to go through and you're probably not going to remember it the next time you need to do it. I hope there's a better way (I found some information in the documentation, but quite honestly, I couldn't understand it). Feel free to leave a comment if you know how to do this more efficiently.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-8219299279413751935?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/8219299279413751935/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=8219299279413751935' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/8219299279413751935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/8219299279413751935'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/12/how-to-read-date-time-field-with-only.html' title='How To: READ a date time field with only a date'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-1102737463258035735</id><published>2007-12-03T15:30:00.000-07:00</published><updated>2007-12-03T15:34:48.317-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>How To: Use DistributeConfigurations between servers</title><content type='html'>DistributeConfigurations is a super handy tool for performing obtains and delivers. Anybody that's used to doing this manually will agree. However, as with manually obtaining and delivering configurations, you're somewhat stuck if you need to obtain from a product area on one server and deliver to a product area on another server - usually this requires that you FTP the package from your source area to your target area.&lt;br /&gt;&lt;br /&gt;If your network supports it, you can simply mount a drive from your target server to your source server and then define your Product Area definition in DefineProductAreas to point to the target area's /pkg folder and DistributeConfigurations will do the rest. Of course, you can also do this if you're still typing tfobtain... and tfdeliver... manually.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-1102737463258035735?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/1102737463258035735/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=1102737463258035735' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/1102737463258035735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/1102737463258035735'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/12/how-to-use-distributeconfigurations.html' title='How To: Use DistributeConfigurations between servers'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-2992977566730761907</id><published>2007-12-03T15:12:00.000-07:00</published><updated>2007-12-03T15:29:06.029-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>How To: Create a multi-column unique key</title><content type='html'>Here's how to define a multi-column unique key using DesignDatabase. This isn't rocket science, but if you're like me then you just kept doing this using RefineTables and never really bothered to learn to do it in DesignDatabase (which is much easier):&lt;br /&gt;&lt;br /&gt;- Select your table in DesignDatabase and choose the Keys frame&lt;br /&gt;- Click [New] at the top of the screen&lt;br /&gt;- Name your key in the Key/Column field and check the Unique box&lt;br /&gt;- Right-click on the Key/Column field and select "Change key"&lt;br /&gt;- Select the column(s) you wish to comprise your unique key and click [Save and return]&lt;br /&gt;&lt;br /&gt;You may also need to change the priority of your key if you intend it to be used in a POST statement in TFL or for AutoAdd update behavior. Higher-priority = lower number (i.e. 100 is a higher priority than 200).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-2992977566730761907?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/2992977566730761907/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=2992977566730761907' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/2992977566730761907'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/2992977566730761907'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/12/how-to-create-multi-column-unique-key.html' title='How To: Create a multi-column unique key'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-8156561181248560739</id><published>2007-11-28T09:56:00.000-07:00</published><updated>2007-11-28T16:56:20.338-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>How To: AutoAdd data via Reference Field</title><content type='html'>Here's a nice tool to have in your tool kit: The ability to AutoAdd new values in a Reference Field. Here's what I mean:&lt;br /&gt;&lt;br /&gt;Let's say you have a Transaction called ManageContacts. In this transaction, you manage your contacts and their contact information (address, city, state, et cetera). This is a single-view Transaction, and therefore it has only one table - the Contact table. The Contact table has foreign keys to the State and CityState table. These foreign key fields are StateID and CityStateID, respectively.&lt;br /&gt;&lt;br /&gt;The State table stores a list of unique states. The CityState table stores a list unique Cities by State (i.e. each record in the CityState table contains the StateID for the state in which the city is found, and the City Name). In our ManageContacts transaction, this allows us to first pick a State and then limit the Cities we display in a SmartPick based on the StateID.&lt;br /&gt;&lt;br /&gt;What we need is a simple way to enter new Cities. For example, we pick California for our state, and in our Cities SmartPick let's imagine that we see San Francisco, San Diego, La Jolla and Los Angeles. However, we now need to add Ventura to our list of California cities. Here's how to do it:&lt;br /&gt;&lt;br /&gt;In our CityState table, we have the following columns:&lt;br /&gt;- CityStateID (Primary key)&lt;br /&gt;- StateID (Foreign key to State table)&lt;br /&gt;- CityName&lt;br /&gt;&lt;br /&gt;When we use AutoAdd, it checks the highest priority, non-primary key (which must be defined as unique) to see if an existing record exists. If it doesn't, it prompts you to create one. In our example, we'd define our highest-priority, non-primary key as a combination of the StateID and CityName columns, thereby allowing us to have a unique city name for each state. We do this because we &lt;span style="font-style: italic;"&gt;could &lt;/span&gt;have the same city names for multiple states. (Now, before you DB gurus out there get worked up at my choice to not also have a City table and simply store StateID and CityID in the CityState table, I've purposefully &lt;span style="font-style: italic;"&gt;not &lt;/span&gt;done that for the sake of keeping this example simple to understand).&lt;br /&gt;&lt;br /&gt;So where are we currently? Our CityState table contains four records. Let's assume California's StateID is 5. Our CityState table would look like this:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;CityStateID | StateID&lt;/span&gt;     | &lt;span style="font-weight: bold;"&gt;CityName&lt;/span&gt;&lt;br /&gt;1&lt;span style="color: rgb(255, 255, 255);"&gt;.........................&lt;/span&gt;5&lt;span style="color: rgb(255, 255, 255);"&gt;.................&lt;/span&gt;San Diego&lt;br /&gt;2&lt;span style="color: rgb(255, 255, 255);"&gt;.........................&lt;/span&gt;5&lt;span style="color: rgb(255, 255, 255);"&gt;.................&lt;/span&gt;San Francisco&lt;br /&gt;3&lt;span style="color: rgb(255, 255, 255);"&gt;.........................&lt;/span&gt;5&lt;span style="color: rgb(255, 255, 255);"&gt;.................&lt;/span&gt;La Jolla&lt;br /&gt;4&lt;span style="color: rgb(255, 255, 255);"&gt;.........................&lt;/span&gt;5&lt;span style="color: rgb(255, 255, 255);"&gt;.................&lt;/span&gt;Los Angeles&lt;br /&gt;&lt;br /&gt;If we were to populate a new City record for Ventura, DatabaseLibrary would look for an existing record in the CityState table of:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;CityStateID | StateID&lt;/span&gt;     | &lt;span style="font-weight: bold;"&gt;CityName&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;.  ........................&lt;/span&gt;5&lt;span style="color: rgb(255, 255, 255);"&gt;.................&lt;/span&gt;Ventura&lt;br /&gt;&lt;br /&gt;Since it doesn't exist, it would prompt us and ask if we would like to create it, which we do.&lt;br /&gt;&lt;br /&gt;For this to work, we need to do a few things:&lt;br /&gt;1. In our Transaction's Contact view, we need to reference in from the CityStateID column the two columns in the CityState table that comprise our unique key: StateID and CityName.&lt;br /&gt;2. In BuildTransactions..Views we change the Update behavior for the CityStateID reference from "Choose" to "AutoAdd".&lt;br /&gt;3. We must populate every field we've referenced into our view (i.e. StateID and CityName). In this example, I populate the StateID field when I pick my State, which I pick prior to selecting a city (this allows me to limit the cities I display based on the State I selected - clearly I only want to display cities found in the State I've selected). Next, I pick an existing city (if it's already in my CityName SmartPick), or I provide a new one, in this case, Ventura.&lt;br /&gt;&lt;br /&gt;If a record doesn't exist in my CityState table for the combination of StateID and CityName I've provided, I'm prompted and asked if I would like to add it. By choosing Yes, TenFold DatabaseLibrary automatically:&lt;br /&gt;1. Creates a new record in the CityState table for the StateID and CityName combination I supplied&lt;br /&gt;2. Updates the CityStateID (my foreign key to the CityState table) with the PrimaryKey value for this new CityState record.&lt;br /&gt;&lt;br /&gt;Now, were I to go look in my CityState table, I'd see the following:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;CityStateID | StateID&lt;/span&gt;     | &lt;span style="font-weight: bold;"&gt;CityName&lt;/span&gt;&lt;br /&gt;1&lt;span style="color: rgb(255, 255, 255);"&gt;.........................&lt;/span&gt;5&lt;span style="color: rgb(255, 255, 255);"&gt;.................&lt;/span&gt;San Diego&lt;br /&gt;2&lt;span style="color: rgb(255, 255, 255);"&gt;.........................&lt;/span&gt;5&lt;span style="color: rgb(255, 255, 255);"&gt;.................&lt;/span&gt;San Francisco&lt;br /&gt;3&lt;span style="color: rgb(255, 255, 255);"&gt;.........................&lt;/span&gt;5&lt;span style="color: rgb(255, 255, 255);"&gt;.................&lt;/span&gt;La Jolla&lt;br /&gt;4&lt;span style="color: rgb(255, 255, 255);"&gt;.........................&lt;/span&gt;5&lt;span style="color: rgb(255, 255, 255);"&gt;.................&lt;/span&gt;Los Angeles&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;&lt;span style="color: rgb(51, 0, 51);"&gt;5&lt;/span&gt; ........................&lt;/span&gt;5&lt;span style="color: rgb(255, 255, 255);"&gt;.................&lt;/span&gt;Ventura&lt;br /&gt;&lt;br /&gt;The next time I needed to select Ventura, it would be a choice in my CityName SmartPick. In the next few Blog posts I'll explain how to define multi-column unique keys and some details about how DatabaseLibrary validates by reference (which is what it does here).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-8156561181248560739?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/8156561181248560739/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=8156561181248560739' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/8156561181248560739'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/8156561181248560739'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/11/how-to-autoadd-data-via-reference-field.html' title='How To: AutoAdd data via Reference Field'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-8999141594637127912</id><published>2007-11-22T07:31:00.000-07:00</published><updated>2007-11-22T07:55:04.083-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>Info: RETURN arrays</title><content type='html'>RETURN-ing an array is a nice trick I like to use when creating TFL functions that I want to reuse throughout an application. It saves me from having to initialize and pass a bunch of variables as output parameters.&lt;br /&gt;&lt;br /&gt;For instance, let's say that you have a function that performs a bunch of end user data validations - email validation, mailing address validation, telephone number validation, credit card number validation, et cetera. You want to know the status of each of these validation, which you perform in your TFL function.&lt;br /&gt;&lt;br /&gt;Instead of doing something like this in the function from which you call your address validation:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;LET vAddressValidation = NULL&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;LET vPhoneNumberValidation = NULL&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;LET vEmailValidation = NULL&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;LET vCreditCardValidation = NULL&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;Call ValidateEndUserInformation &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;&lt;/span&gt;(vValidationResult,&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt; vAddressValidation,&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt; vPhoneNumberValidation,&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt; vEmailValidation,&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt; vCreditCardValidation,&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt; EndUserSet)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;IF &lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;vValidationResult&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;= 0&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;Call Information ("All validations succeeded")&lt;br /&gt;ELSE&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;Call Error ("At least one validation failed")&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;IF vAddressValidation = 1&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;Call Error ("Address validation failed")&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;ENDIF...&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;ENDIF&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You can instead do something like this:&lt;br /&gt;&lt;br /&gt;(In your calling function)&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;LET ValidationStatus = ValidateEndUserInformation (EndUserSet)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(In your ValidateEndUserInformation TFL function, you RETURN the status of each of your four validations as follows):&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;LET ValidationStatus[1] = 1 #0 if all passed, 1 if any failed&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;LET ValidationStatus[2] = 0 #Address&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;LET ValidationStatus[3] = 1 #Phone number&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;LET ValidationStatus[4] = 0 #Email&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;LET ValidationStatus[5] = 0 #Credit card&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;RETURN ValidationStatus&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(Now back to the calling TFL function):&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;IF ValidationStatus[1] = 0&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;Call Information ("All validations succeeded")&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;ELSE&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;Call Error ("At least one validation failed")&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;IF ValidationStatus[2] = 1 &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;CALL Error ("Address validation failed")&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;ENDIF...&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;ENDIF&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I like this method because it reduces the number of lines in my TFL function logic and I think it's a more convenient method for passing information from a called function back to a calling function.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-8999141594637127912?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/8999141594637127912/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=8999141594637127912' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/8999141594637127912'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/8999141594637127912'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/11/info-return-arrays.html' title='Info: RETURN arrays'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-7453555801704328537</id><published>2007-11-16T16:10:00.000-07:00</published><updated>2007-11-16T16:26:06.685-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>Info: Causing snippets to fire in WindowsClient</title><content type='html'>&lt;span style="font-family:georgia;"&gt;Here's something you should know about WindowsClient: A TFL function that modifies a field in your set does not cause any snippets on or watching that field to fire. For example:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;- I have a field called ExpiredFlag in a parent view&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;- I want the text in the entire view to be red when ExpiredFlag = 'Y'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;- I have a TFL function that determines if the account is expired, and if it is, I use a MODIFY operation to change the ExpiredFlag = 'Y'.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;- None of the text in my view turns red&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;- When I manually check and uncheck the ExpiredFlag checkbox, my context-sensitivity works correctly and my text is red&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;What gives?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;In order to make the snippets that fire the context-sentitive attributes on the fields watching ExpiredFlag do their thing, I have to change the ExpiredFlag value using an output parameter in my TFL function, not a MODIFY operation.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;For example, with an Output parameter defined and mapped to our ExpiredFlag field:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;IF &amp;amp;DBToday &gt; ExpiredDate&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;LET oExpiredFlag = 'Y'&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;ELSE&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;LET oExpiredFlag = 'N'&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="font-family:courier new;"&gt;ENDIF&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;span style="font-family:georgia;"&gt;This will cause the snippets watching my ExpiredFlag field to fire, thereby effecting the context-sensitive attribute that renders my text red when ExpiredFlag = 'Y'.&lt;br /&gt;&lt;br /&gt;Oddly, BrowserClient snippets will fire when you update a field using a MODIFY statement.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-7453555801704328537?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/7453555801704328537/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=7453555801704328537' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/7453555801704328537'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/7453555801704328537'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/11/info-causing-snippets-to-fire-in.html' title='Info: Causing snippets to fire in WindowsClient'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-241635136103415677</id><published>2007-11-14T05:06:00.000-07:00</published><updated>2007-11-14T05:19:14.353-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>Info: Built-in TFL function of the week: GenerateDefaults</title><content type='html'>GenerateDefaults() allows you to, well, generate defaults in a set. This is extremely useful if, for example, you're performing an ADD and you need the primary key value of that ADD statement's record(s) in order to propagate it elsewhere in your application.&lt;br /&gt;&lt;br /&gt;Let's say that you're entering some product information, which is a combination of a Manufacturer, ManufacturerID, ProductName and ProductID. You store this information in the ManufacturerProduct table (an intersection between Manufacturer and Product), and ultimately what you want is to update some set with the resulting primary key (ManufacturerProductID) for the new instance in ManufacturerProduct.&lt;br /&gt;&lt;br /&gt;Since the ADD statement only performs the ADD in memory until the TFL function completes, this creates a problem: You need the primary key value that comes with the completed ADD statement before the function completes - say, to store it in another table.&lt;br /&gt;&lt;br /&gt;Here's where you can use GenerateDefaults(). It might look something like this in TFL:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;#See if we already have a record for this&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;#Manufacturer &amp;amp; Product combination&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;READ ManufacturerProduct WHEN&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;ManufacturerID = iManID AND&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;ProductID = iProdID&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;#If not, ADD it&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;IF &amp;amp;ReadCount = 0&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;ADD ManufacturerProduct&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;ManufacturerID = iManID&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;ProductID = iProdID&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;#Generate defaults to get primary key value&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;Call GenerateDefaults (ManufacturerProduct)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;LET vManufacturerProductID = ManufacturerProductID&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;ENDIF&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;#ADD new ManufacturerProduct record ID to InventoryItems&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;ADD InventoryItem&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;InventoryManufacturerProductID = vManufacturerProductID&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-241635136103415677?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/241635136103415677/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=241635136103415677' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/241635136103415677'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/241635136103415677'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/11/info-built-in-tfl-function-of-week.html' title='Info: Built-in TFL function of the week: GenerateDefaults'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-4966810452176712603</id><published>2007-11-08T21:14:00.000-07:00</published><updated>2007-11-14T05:19:34.076-07:00</updated><title type='text'>New Website!</title><content type='html'>No useful TenFold post today - I just finished a minor overhaul of ENDWHILE's website. Check back tomorrow. It's time for a vodka tonic and some television to numb the mind.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-4966810452176712603?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/4966810452176712603/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=4966810452176712603' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/4966810452176712603'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/4966810452176712603'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/11/new-website.html' title='New Website!'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-3307197928374142394</id><published>2007-11-07T18:40:00.000-07:00</published><updated>2007-11-09T08:25:18.357-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>How To: Use TFL functions in cool ways</title><content type='html'>Any function that RETURNS a value can be used for, say, context-sensitive attributes. For example, let's say you wanted a field in your parent view to only be visible if there were child records, you could do something like this in View field details in BuildTransaction:&lt;br /&gt;&lt;br /&gt;[X] Invisible when: InstanceCount (MyTransaction, "ChildView") = 0&lt;br /&gt;&lt;br /&gt;Or, let's say you want to call a function to update a field. You don't need to attach the function as a Business rule. Instead, you can write the function so that it RETURNS the value you want and attach it as a Simple default. For example, let's say an end user enters their credit card number into a calculated field and you want to store the credit card number in your database, but you want to encrypt it. You write a function that takes an input parameter (the credit card number) and RETURNS the encrypted string. You then attach the function as a Simple default where it might look like this (click on the image to enlarge it):&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_sseyQLP57YY/RzJsxw8_-GI/AAAAAAAAABE/U-TRapQroUY/s1600-h/default.JPG"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://3.bp.blogspot.com/_sseyQLP57YY/RzJsxw8_-GI/AAAAAAAAABE/U-TRapQroUY/s400/default.JPG" alt="" id="BLOGGER_PHOTO_ID_5130282527738558562" border="0" /&gt;&lt;/a&gt;&lt;img style="width: 1px; height: 1px;" src="file:///C:/DOCUME%7E1/CINDYP%7E1/LOCALS%7E1/Temp/moz-screenshot.jpg" alt="" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-3307197928374142394?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/3307197928374142394/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=3307197928374142394' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/3307197928374142394'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/3307197928374142394'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/11/how-to-use-tfl-functions-in-cool-ways.html' title='How To: Use TFL functions in cool ways'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_sseyQLP57YY/RzJsxw8_-GI/AAAAAAAAABE/U-TRapQroUY/s72-c/default.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-1890009111692272042</id><published>2007-11-06T07:58:00.000-07:00</published><updated>2007-11-06T08:06:23.320-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>Info: Best practices for BusinessRule field defaults</title><content type='html'>Calling a Business rule based on data entry is a great feature. One problem, unfortunately, is easily identifying the fields to which you've attached Business rules. It's one thing if you built the application and you remember where to look, it's entirely different if you didn't build the application and you must go in and open every field to see where a particular Business rule is attached. Hell, even in the applications I've built I often forget where I've attached Business rules. After getting annoyed with this, I started doing it differently.&lt;br /&gt;&lt;br /&gt;Now, I never attach Business rules to basis fields. Instead, I create a CalculatedField, give it a descriptive name (like "LaunchCreditCardValidation") and attach my Business rule to *that* field. Now I don't even have to try to remember the fields to which I've attached Business rules, and, if I'm smart about how I name the CalculatedFields to which I attach them, I'll know the function I call just from the field name (i.e. CreditCardValidation).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-1890009111692272042?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/1890009111692272042/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=1890009111692272042' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/1890009111692272042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/1890009111692272042'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/11/info-best-practices-businessrule-field.html' title='Info: Best practices for BusinessRule field defaults'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-9165659740722610351</id><published>2007-11-06T07:53:00.001-07:00</published><updated>2007-11-06T07:57:53.117-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>How To: Make a dual-state checkbox</title><content type='html'>This one might be a bit of a softball post, but if you don't know this, you want to.&lt;br /&gt;&lt;br /&gt;TenFold checkboxes are, by default, three-state: NULL, N, Y. I'd say about 99% of the time, you want your checkboxes to be dual-state (N, Y). You can accomplish this by defining a New instance Literal default of 'N' (no quotes in the actual field) for your checkbox field in BuildTransactions.&lt;br /&gt;&lt;br /&gt;The one drawback to this is that in WindowsClient (iClient or Standard) StandardGrid display, you will actually see an unchecked checkbox on the instance immediately following your last instance. BrowserClient won't display the New instance Literal default, so no problem there.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-9165659740722610351?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/9165659740722610351/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=9165659740722610351' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/9165659740722610351'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/9165659740722610351'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/11/how-to-make-dual-state-checkbox.html' title='How To: Make a dual-state checkbox'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-2498114633887233683</id><published>2007-11-06T04:29:00.001-07:00</published><updated>2007-11-06T04:45:31.154-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>How To: Manually stop and start ServerManager</title><content type='html'>Here's something that's nice to have in your arsenal, especially if you develop using iClient (which requires ServerManager be running, and thereby makes it impossible to stop and restart the ServerManager from your TenFold iClient session).&lt;br /&gt;&lt;br /&gt;1. Log into your server. You can't log in as root, as ServerManager won't start under root. It also used to be the case that whatever user you started your ServerManager under, if you came back later and killed it (by hand) you'd kill ALL ServerManager processes running under that user. TenFold fixed this problem long ago.&lt;br /&gt;2. Set your environment variables - i.e. the TENFOLD_ROOT for your product area and the TENFOLD_OPTIONS for your OptionsFile. One thing to note is that the ServerManager will start with the FastConnect setting you specify in your OptionsFile. Be sure that [FastConnect] DefaultServer has the correct Server and Port information.&lt;br /&gt;3. It won't hurt to run tfstop or tfstop -hard, just to be sure any lingering processes from your previous ServerManager are cleaned up.&lt;br /&gt;4. Here's the command to start ServerManager:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;tfstart ServerManagerName user=&lt;/span&gt;&lt;tenfolduser&gt;&lt;span style="font-family:courier new;"&gt;TenFoldUser password=TenFoldPassword responsibility="ResponsibilityNameInQuotes" outputtype=screen&lt;/span&gt;&lt;tenfoldpassword&gt;&lt;span style="font-family:courier new;"&gt;  &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here's a real example:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;tfstart ConsultingPortalStandard user=jason password=jason responsibility="Applications expert" outputtype=screen&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;If you want to make it really easy, throw it into a script.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/tenfoldpassword&gt;&lt;/tenfolduser&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-2498114633887233683?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/2498114633887233683/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=2498114633887233683' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/2498114633887233683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/2498114633887233683'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/11/how-to-manually-stop-and-start.html' title='How To: Manually stop and start ServerManager'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-6885393472325118271</id><published>2007-11-05T16:15:00.000-07:00</published><updated>2007-11-06T04:45:50.271-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>How To: Launch PowerQuery from TFL</title><content type='html'>Launching PowerQuery from TenFold Language is only half of this post. The other half is actually the reason that I *needed* to launch PowerQuery from TFL - I needed to do a child-view query but ONLY return the records matching my child view query criteria. For example:&lt;br /&gt;&lt;br /&gt;Let's say I have a set called CustomerOrders, which has the Customer table as the parent and the Orders table as its child. I need to query a specific Order, and I only want to get that Order record back (but of course I also want the Customer data, too). Under normal circumstances, if I queried on a child record, and the record existed, TenFold would return all the child records for the parent. I'm not sure I'm a fan of this behavior, but at least it's easy to work around. Hence, PowerQuery.&lt;br /&gt;&lt;br /&gt;In my example I was actually Zooming from one transaction (where I had a list of OrderIDs) to the CustomerOrder transaction. Using the standard AutoQuery mode for my Zoom didn't give me the results I wanted, because I *only* wanted a single order record, but I would instead get back every order record related to the customer.&lt;br /&gt;&lt;br /&gt;Instead of using a Zoom, I wrote a TFL function that launches a PowerQuery, which I create on-the-fly (and never store in the database). You'll want to look up &lt;span style="font-style: italic;"&gt;PowerQuery Set&lt;/span&gt; in DocuManage for more information, but here's the logic for this particular case:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;ADD PowerQuery NOSAVE &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;NameName = 'CustomerOrderByOrderID'&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;NameTransaction = 'CustomerOrders'&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;NameExcludeFlag = 'N'      &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;CriteriaFieldName = 'CustomerOrderID'&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;CriteriaOperationSmartCodeMeaning = '='&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;CriteriaOperationCode = 'EQ'&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;CriteriaOperand = iOrderID&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;CALL LaunchPowerQuery(PowerQuery)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;What am I doing? Here's a run down:&lt;br /&gt;1. Adding my PowerQuery to the PowerQuery Set, but specify NOSAVE so that I don't actually commit it to the database - I only want to create it, use it, and then go away.&lt;br /&gt;2. I specify the Name of my PowerQuery, the Transaction against which I want it to run, and most importantly, the "NameExcludeFlag". Here's the explanation of this Field from PowerQuery Set in DocuManage:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;"SmartCode code for ExcludeResults flag. Valid values are:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;• Y – PowerQuery returns all parent instances that have a&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;child instance that matches your child view query criteria,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;and returns all child instances for those parent instances.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;• N – PowerQuery returns all parent instances that have a&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;child instance that matches your child view query criteria,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;and limits child instances according to your child view&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;query criteria.&lt;/span&gt;&lt;span style="font-style: italic;"&gt;"&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;For my needs, I want to limit the child instances to only the one for which I queried, so I set ExcludeResultsFlag = 'N' (specifying 'N' seems counter-intuitive to me, but hey, it works).&lt;br /&gt;3. I specify the rest of the necessary values in my PowerQuery definition, which are are pretty self-explanitory - I query CustomerOrderID where CustomerOrderID = the value I'm sending in iOrderID (which I get from an input parameter in my TFL function).&lt;br /&gt;4. My TFL logic then calls LaunchPowerQuery (which launches the PowerQuery I added to the PowerQuery set) and voila, I have my CustomerOrder set queried with the sole matching child instance for the Order I specify.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-6885393472325118271?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/6885393472325118271/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=6885393472325118271' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/6885393472325118271'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/6885393472325118271'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/11/how-to-launch-powerquery-from-tfl.html' title='How To: Launch PowerQuery from TFL'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-8781647563422572845</id><published>2007-11-04T04:35:00.000-07:00</published><updated>2007-11-06T04:46:09.914-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>How To: Validate credit cards</title><content type='html'>Here's a TFL function I wrote that does the following:&lt;br /&gt;- Validates the number provided matches the card type provided&lt;br /&gt;- Validates the number length is correct for the card type provided&lt;br /&gt;- Validates that the card has not expired&lt;br /&gt;- Uses the &lt;a href="http://en.wikipedia.org/wiki/Luhn_algorithm"&gt;Luhn formula&lt;/a&gt; (MOD10) to validate the card number&lt;br /&gt;&lt;br /&gt;A few notes:&lt;br /&gt;- The function RETURNS a value of 'Y' or 'N', denoting the success or failure of the validation attempt.&lt;br /&gt;- The function calls ReportError and describes the cause of the failed validation, if applicable.&lt;br /&gt;- The function requires four input parameters, in the following order: CCNumber, CCType, CCExpMo, CCExpYr&lt;br /&gt;- This function simply tells you if the information on the card is valid. It doesn't tell you if the merchant will approve the card. However, if you dinged for every card you try to submit, it's a good way to avoid submitting bad card information and to save yourself some time and money.&lt;br /&gt;&lt;br /&gt;My apologies for the formatting - Blogger makes it a bit tough. You can view the logic in a txt file &lt;a href="http://endwhile.com/stuff/ValidateCreditCard.txt"&gt;here&lt;/a&gt;. Here's the logic:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;#Check card expiration&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#Format the year as YYYY if it's not already&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;IF iExpYr &lt;&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;LET vExpYr = iExpYr + 2000 &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;ELSE    &lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;LET vExpYr = iExpYr &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;ENDIF  &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;LET vExpYrLength = StringLength(vExpYr ) &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;IF vExpYrLength &lt;&gt; 4&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;CALL Error ("Card does not have a valid expiration year string")&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;RETURN 'N'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;ENDIF&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;CALL MonthNumber(&amp;amp;DBToday, vCurrentMonth)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;CALL YearNumber(&amp;amp;DBToday, vCurrentYear)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;IF vCurrentYear &gt; vExpYr&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;CALL Error ("Card has expired")  &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   RETURN 'N'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;ENDIF&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;IF vCurrentYear = vExpYr&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;IF vCurrentMonth &gt; iExpMo&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;CALL Error ("Card has expired")&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;RETURN 'N'&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;ENDIF&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;ENDIF&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#CARD TYPE        Prefix     Length     Check digit algorithm&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#===========   ======   ======   ======================&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#MASTERCARD       51-55       16        mod 10&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#Discover       6011       16        mod 10&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#AMEX              34,37       15        mod 10&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#VISA              4          13,16     mod 10&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#Requires card type of DS, MC, VI, AM&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;IF iCCType NOT IN ('DS', 'MC', 'VI', 'AM')&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;CALL Error ("Card type must be one of the following: DS, MC, VI, AM")&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;RETURN 'N'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;ENDIF&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#Identify mis-matched card number and card type&lt;br /&gt;LET vFirstDigit = SubString(iCCNum, 1, 1)&lt;br /&gt;IF vFirstDigit = 6 AND iCCType &lt;&gt; 'DS' OR&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;vFirstDigit = 5 AND iCCType &lt;&gt; 'MC' OR&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;vFirstDigit = 4 AND iCCType &lt;&gt; 'VI' OR&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;vFirstDigit = 3 AND iCCType &lt;&gt; 'AM'&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;CALL Error ('Card number does not match card type')&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;RETURN 'N'&lt;br /&gt;ENDIF&lt;br /&gt;&lt;br /&gt;#Identify incorrect card number length&lt;br /&gt;LET vNumberLength = StringLength(iCCNum)&lt;br /&gt;IF iCCType IN ('DS', 'MC') AND vNumberLength &lt;&gt; 16 OR&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;iCCType = 'VI' AND vNumberLength NOT IN (13, 16) OR&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;iCCType = 'AM' AND vNumberLength &lt;&gt; 15&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;CALL Error ('Card type and number length mismatch')&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;RETURN 'N'&lt;br /&gt;ENDIF&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#Start from second digit from right going every-other-digit in the card number&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#Multiply number by 2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#If number &gt; 10, add each digit (12 becomes 1 + 2 which equals 3)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#Add all numbers together&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;LET vMODPosition = -2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;LET vMODNumber = NULL&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;LET vMODTotal = 0&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;LET vMODcount = 0&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;WHILE vMODPosition =&gt; vNumberLength * -1&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;LET vMODcount = vMODcount + 1&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;LET vMODNumber[vMODcount] = SubString(iCCNum, vMODPosition, 1) * 2&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;IF vMODNumber[vMODcount] &gt; 9&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;LET vMODNumber[vMODcount] = (vMODNumber[vMODcount] - 10) + 1&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;ENDIF&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;LET vMODTotal = vMODTotal + vMODNumber[vMODcount]&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;LET vMODPosition = vMODPosition - 2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;ENDWHILE&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#Start from first digit from right going every other digit in the card number&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#Add all numbers together&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;LET vNumPosition = -1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;LET vNumber = NULL&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;LET vNumTotal = 0&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;LET vNumCount = 0&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;WHILE vNumPosition =&gt; vNumberLength * -1&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;LET vNumCount = vNumCount + 1&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;LET vNumber[vNumCount] = SubString(iCCNum, vNumPosition, 1)&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;LET vNumTotal = vNumTotal + vNumber[vNumCount]&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;LET vNumPosition = vNumPosition - 2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;ENDWHILE&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#Add totals from two sections above&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;LET vCheckSum = vNumTotal + vMODTotal&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#Determine the last digit of the total. Valid value = 0&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;LET vValidCard = SubString(vCheckSum, -1, 1)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#Failure&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;IF vValidCard &lt;&gt; 0&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;CALL Error ("Invalid card number")&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(255, 255, 255);font-family:courier new;" &gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:courier new;"&gt;RETURN 'N'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;ENDIF&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#Success&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;CALL Information ("Valid card number")&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;RETURN 'Y'&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-8781647563422572845?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/8781647563422572845/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=8781647563422572845' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/8781647563422572845'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/8781647563422572845'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/11/how-to-validate-credit-cards.html' title='How To: Validate credit cards'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-595546416970743044</id><published>2007-11-03T13:09:00.001-06:00</published><updated>2007-11-03T13:12:30.307-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>How To: Request a blog subject</title><content type='html'>Shoot me an email! If there's something you'd like to do, but you don't quite know how to do it, let me know. No question is too silly (believe me, I've already asked them all), too simple, or too crazy. If I can't answer it, I'll find the answer for you.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-595546416970743044?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/595546416970743044/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=595546416970743044' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/595546416970743044'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/595546416970743044'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/11/how-to-request-blog-subject.html' title='How To: Request a blog subject'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-4417747916374107974</id><published>2007-11-03T05:59:00.000-06:00</published><updated>2007-11-03T06:58:51.598-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>How To: Display end-user specific data</title><content type='html'>As I have time, I've been working on an application that I use to run my consulting business. I plan to eventually turn this application into a web-based product. It's called, for now, ConsultingPortal.&lt;br /&gt;&lt;br /&gt;The staple, off-the-shelf business applications out there are ill-suited for my needs. SalesForce.com, QuickBooks, Microsoft Project...I have the same complaints about all of them:&lt;br /&gt;- They're over built for my  simple needs. This makes using them frustrating and confusing.&lt;br /&gt;- They have overlapping functionality (which often requires maintaining duplicate data in different systems).&lt;br /&gt;- They don't talk to one another (at least not without a fair amount of work on my part).&lt;br /&gt;&lt;br /&gt;ConsultingPortal combines the core offerings of these products, eliminates the stuff I don't need, plus includes a handful of other features, into a single application. I'm going on about these silly details to give you some context for the subject of this post: Displaying end-user specific data.&lt;br /&gt;&lt;br /&gt;Let's say I actually find the time to finish ConsultingPortal and I want to release it upon the world. It's web-based, and I'll (hopefully) have MILLIONS of end users. Since I'll be storing important, private data about my customers' businesses, it's important that an end user sees data for their business and ONLY their business. Here's the solution I've implemented to ensure this. It has three main parts:&lt;br /&gt;1. Define a Preference&lt;br /&gt;2. Set a value for this Preference at end user login&lt;br /&gt;3. Limit data queried by this Preference value&lt;br /&gt;&lt;br /&gt;I *could* use SecurityByValue, and I'll likely head down that path in the future, but for now, this solution meets my needs and it's very simple.&lt;br /&gt;&lt;br /&gt;In my case, when I create a new end users account, I store their UserName in my AccountEndUsers table, which is a child of Account (which I populate upon creating a new account - this allows me to have multiple end users associated to the same account - i.e. employees to Company). When an end users signs on, I want to determine to which account they belong and then use a View condition to limit the data they query by AccountID. It sounds simple, and it is!&lt;br /&gt;&lt;br /&gt;Step one: Define a Preference:&lt;br /&gt;&lt;br /&gt;We're going to define a Preference for our AccountID. Doing this will allow me to create an in-memory OptionsFile setting Preference and assign it a value (AccountID), and then use the Preference/value as a view condition.&lt;br /&gt;&lt;br /&gt;- Open Classic..Librarian..Define..Preferences. Enter a Section name (ConsultingPortal), SubSection name (CurrentUserAccount), Application (ConsultingPortal), and Preference (UserAccount).&lt;br /&gt;&lt;br /&gt;Step two: Set a value for the Preference after login (but before launching any transactions):&lt;br /&gt;&lt;br /&gt;- Write a function to set your Preference value in your in-memory OptionsFile. Here's what the logic in my function looks like:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;READ FindUserAccountID WHEN&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;AccountEndUsersEndUserUserName = &amp;amp;User&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;IF &amp;amp;ReadCount = 1&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;CALL SetOption("ConsultingPortal",&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;..................&lt;/span&gt;"CurrentUserAccount",&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;..................&lt;/span&gt;"UserAccount",&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;..................&lt;/span&gt;AccountEndUsersAccountID)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;/span&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;CALL CNSTLaunchConsultingPortal&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;ELSE&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;CALL Error ("Unable to identify an account for this end user")&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);font-family:courier new;" &gt;ENDIF&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;- Open the responsibility your end users will access. Right-click on the Responsibility name and select Advanced menu properties. Add your function to the "First actions" section. Upon logging in and selecting this Responsibility, this function will fire before anything else happens. Having done this, we can now limit the data our end users sees based on their AccountID.&lt;br /&gt;&lt;br /&gt;Step three: Create a View condition for UserAccount..AccountID&lt;br /&gt;&lt;br /&gt;- ConsultingPortal contains a single transaction, so this is quite simple to manage. Open BuildTransactions and query the transactions to which your end users have access. Click on the Views frame, right-click on the parent View name and select "Edit view details". Now, before we create our View condition, we obviously must be storing AccountID in all of our end user transaction's parent tables. Since that's the case, I just define a View condition as follows:&lt;br /&gt;- Field: CompanyAccountID&lt;br /&gt;- Operator: "="&lt;br /&gt;- Preference: UserAccount&lt;br /&gt;&lt;br /&gt;My end user will now only see the records associated with the CompanyAccountID to which his/her end user belongs!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-4417747916374107974?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/4417747916374107974/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=4417747916374107974' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/4417747916374107974'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/4417747916374107974'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/11/how-to-display-end-user-specific-data.html' title='How To: Display end-user specific data'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-2886527471954805979</id><published>2007-11-02T05:50:00.000-06:00</published><updated>2007-11-02T06:42:52.721-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>How To: Display unique instances using "Limit within sort"</title><content type='html'>Enterprise TenFold has a cool feature called "Limit within sort". This allows you to specify a field in a view and limit the number of duplicate instances displayed for that field.&lt;br /&gt;&lt;br /&gt;For example, let's say you have a table called Guestbook. Visitors to your site can sign your guestbook and leave their contact information (name, email address, et cetera). You don't do any sort of validation on posts to your Guestbook, so it's entirely likely you have duplicate records - people sometimes forget and sign your guestbook more than once.&lt;br /&gt;&lt;br /&gt;Now, however, you want to view a list of unique guestbook entries. Here's a case where Limit within sort is super handy. This is how you'd use it to display unique entries:&lt;br /&gt;1. Decide the field you want to use to specify uniqueness - say EmailAddress&lt;br /&gt;2. In BuildTransactions..Views, set your EmailAddress field's "Sort order" to some numeric value like 1.&lt;br /&gt;3. Right-click on the View name and select "Edit view details"&lt;br /&gt;4. Enter a value for "Maximum instances" - this is, stay with me now...the maximum number of matching instances you're going to allow to be displayed for the field you indicate.&lt;br /&gt;5. Select the 1|EmailAddress field from the "Limit within sort" SmartPick.&lt;br /&gt;&lt;br /&gt;When you open your transaction and query all the records in this table, it will now show only 1 instance for each Email address in your database, even if there are more than 1 instances of the same email address in the database.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-2886527471954805979?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/2886527471954805979/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=2886527471954805979' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/2886527471954805979'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/2886527471954805979'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/11/how-to-display-unique-instances-using.html' title='How To: Display unique instances using &quot;Limit within sort&quot;'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-6560467741813388336</id><published>2007-11-02T03:23:00.000-06:00</published><updated>2007-11-02T05:31:49.056-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>How To: Round floating point decimal numbers</title><content type='html'>This post originates from a &lt;a href="http://forum.tenfold.com/topic.asp?TOPIC_ID=1"&gt;message on the TenFold forum&lt;/a&gt;. I ran into it again yesterday, so I thought I'd put it up here. The original post had a bug in the sample code. I've included a fix for that here.&lt;br /&gt;&lt;br /&gt;In short, the problem is that TenFold stores numbers as floating point decimals. That means if you have a product in your application with a price of $19.95 that TenFold actually stores it as 19.94999999999. This can be a problem if you want to use the price, say, in an email confirmation to a customer or to send to a third party for processing.&lt;br /&gt;&lt;br /&gt;To compound the issue, TenFold Language's build in Round function doesn't really work on this. Therefore, you have to work around the issue yourself. Here's some code that'll do that for you.&lt;br /&gt;&lt;br /&gt;Create a function that accepts a single input parameter and returns the good number. In this example, iBadNumber is my input parameter.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;LET vBadNumber2 = Round (vBadNumber * 100,0)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;LET vDecimals = SubString (vBadNumber2, -2, 2)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;LET vBadNumber2 = Round ((vBadNumber2 - vDecimals)/100, 0)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;LET vGoodNumber = vBadNumber2|'.'|vDecimals&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;RETURN vGoodNumber&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This function strips the first two decimal places from my input number, rounds them, then creates and returns a new number string. You'd call the function as follows:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;LET vPrice = FixRounding(ProductPrice)&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-6560467741813388336?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/6560467741813388336/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=6560467741813388336' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/6560467741813388336'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/6560467741813388336'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/11/how-to-round-floating-point-decimal.html' title='How To: Round floating point decimal numbers'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-3595715430513826809</id><published>2007-10-31T17:08:00.000-06:00</published><updated>2007-10-31T17:35:19.415-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>How To: Use Phantom Tables in your application</title><content type='html'>A "Phantom" table is a logical table that has no physical implementation. This means that you can't query or store data for a Phantom table because it doesn't really exist in the database.&lt;br /&gt;&lt;br /&gt;You might wonder why you'd want such a thing, since you are probably building a database-driven application. There are a few reasons. Here's one example:&lt;br /&gt;&lt;br /&gt;I'm currently working on an application for one of my customers that, upon entering a customer's ContactID, it sends an XML request to a third party which returns a list of that customer's current subscriptions.&lt;br /&gt;&lt;br /&gt;We want to know, in real time, a customer's current subscriptions, and we only need to know the current subscriptions for the customer in question. There is no need to persist this information in the database, as it would require around-the-clock processing and would go largely unused (we only get the current subscriptions for a few customers each day, but we have thousands of customers in our system).&lt;br /&gt;&lt;br /&gt;Therefore, we want to simply display a list of current subscriptions, but not store them in the database. This is a perfect scenario for using a Phantom table. Here's how it goes down:&lt;br /&gt;&lt;br /&gt;1. Enter a customer id, which triggers the XML messaging to return their current subscriptions&lt;br /&gt;2. ADD the returned list of current subscriptions to a Phantom table that exists in our set as a child of the Customer table&lt;br /&gt;3. Review the customer's current subscriptions and go about our business&lt;br /&gt;&lt;br /&gt;If we were to change some data in the Customer table, we'd persist those changes to the database, but the list of current subscriptions would simply disappear until the next time we triggered our XML call for the customer's current subscriptions.&lt;br /&gt;&lt;br /&gt;To define and use a Phantom table, there are few things you should know:&lt;br /&gt;1. In DesignDatabase, under the Advanced tab, check the "Phantom table" check box. This will prevent DesignDatabase from implementing this table in your physical database. In fact, you won't even have the option of creating it when you click [Change database]&lt;br /&gt;2. Any time you add this Phantom table to a set, you want to be sure to prevent your transaction from attempting to Read or Save data to the table. To do this, use BuildTransaction to find the view in your set that's based on the Phantom table (Views frame). Right-click on the View field and select "Edit view details". Now check the "Do not read" and "Do not save changes" checkboxes and click [Save and return]. If you forget to do this, you'll get an "Error in reading" or "Error in add" failure. (As a side not, hopefully TenFold will automate this process. You would never want to attempt to Read or Save changes for a Phantom table. These checkboxes should be automatically checked (and be non-modifiable) for any view that's based on a Phantom table).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-3595715430513826809?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/3595715430513826809/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=3595715430513826809' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/3595715430513826809'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/3595715430513826809'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/10/how-to-use-phantom-tables-in-your.html' title='How To: Use Phantom Tables in your application'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-8239283906569542007</id><published>2007-10-30T15:26:00.000-06:00</published><updated>2007-11-02T06:43:41.202-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>How To: Query without clicking [Query]...[Run query]</title><content type='html'>Here's a neat little trick you can often use to query data without actually clicking [Query] and then [Run query].&lt;br /&gt;&lt;br /&gt;For example, let's say you have an application to manage your customers and their orders. Whenever a customer calls you, the first thing you do is bring up their account. To do this, you ask the customer for their telephone number, or their email address, or anything that uniquely identifies them in your system. You enter this information, click [Run query] and voila, their data appears.&lt;br /&gt;&lt;br /&gt;I'm lazy and I don't like to click buttons that don't need to be clicked. I also think that a good application doesn't require an end user to do stuff they shouldn't have to do. Wouldn't it be nice for them to be able to enter, say, the customer's email address and tab out of the field and have their account data query up automatically (no click of [Run query] necessary)?&lt;br /&gt;&lt;br /&gt;Here's how to do just that.&lt;br /&gt;&lt;br /&gt;First, we need to assume that you can query your customer's information based on the customer table's primary key. This should definitely be the case, but it's possible that getting the right ID for the right customer might be a little challenging.&lt;br /&gt;&lt;br /&gt;Let's take the simplest case and just assume that you use your customer's email address as the primary key in your customer table. You will attach a Business rule Function to this field with a single input parameter mapped to the email address field. The function will call TransactionOperate() and perform a KeyQuery. For example, your function might look like this:&lt;br /&gt;&lt;br /&gt;Function name: &lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;AutoQueryCustomerInformation&lt;/span&gt;&lt;br /&gt;Parameters: &lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;iEmailAddress&lt;/span&gt;&lt;br /&gt;Logic:&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt; &lt;/span&gt;Call TransactionOperate("KeyQuery")&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;br /&gt;When you compile the function you'll receive a warning that you never use the input parameter. No big deal. It's only there to trigger the function.&lt;br /&gt;&lt;br /&gt;TransactionOperate("KeyQuery") performs a query on your parent table using the ID in your primary key field (in this case, email address). The end result is that you enter a customer's email address, tab out of the field, and the query happens automatically. With a bit more TFL logic, you can make it intelligent enough to only perform the query if the customer exists, and if they don't, allow you to just start entering their information straight-away. For example:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;READ Customer WHEN Email = iEmailAddress&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;#If customer doesn't exist, let's search&lt;br /&gt;#again or add them to our system&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;IF &amp;amp;ReadCount = 0        &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;CALL Information ("Customer does not exist. Please enter a different email address or enter this customer's information")&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;RETURN&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;ENDIF&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;#If we made it here, we know the customer exists, and&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;#that only one customer exists since we're performing&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;#our READ on the primary key field (i.e. it has to be unique)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;#Therefore, let's query the record up&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;Call TransactionOperate ("KeyQuery")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;That's it!&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-8239283906569542007?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/8239283906569542007/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=8239283906569542007' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/8239283906569542007'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/8239283906569542007'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/10/how-to-query-without-clicking-queryrun.html' title='How To: Query without clicking [Query]...[Run query]'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-3257693148842434239</id><published>2007-10-30T13:52:00.000-06:00</published><updated>2007-11-02T06:45:08.424-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>How To: Simplify calls to ReportError</title><content type='html'>I'm not ashamed to admit that I have only one EndUserMessage defined in most of my applications. The Message is simply '&amp;amp;1', which means that whatever literal string or variable (or combination thereof) I pass ReportError will appear in the message viewer at the bottom of my screen.&lt;br /&gt;&lt;br /&gt;One day I decided it was a pain in the ass to always be typing something like:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;Call ReportError ("BLAH0001", "Error", "Your database just caught fire and burned all your data!")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So, here's what I did: I created two functions, &lt;span style="font-weight: bold;"&gt;Information() &lt;/span&gt;and &lt;span style="font-weight: bold;"&gt;Error()&lt;/span&gt;. Both functions accept a single input parameter (the message I want to display in the message viewer). The functions then execute the full ReportError call. For example, &lt;span style="font-weight: bold;"&gt;Information()&lt;/span&gt; accepts an input parameter of "iMessage". The function's logic looks like this:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;Call ReportError ("ENDW0001", "Information", iMessage)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Nowadays, instead of typing the whole ReportError call, I only need to type this:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;&lt;span style="color: rgb(102, 51, 255);"&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;Call Information ("This is sooo much better")&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-3257693148842434239?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/3257693148842434239/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=3257693148842434239' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/3257693148842434239'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/3257693148842434239'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/10/simplifying-calls-to-reporterror.html' title='How To: Simplify calls to ReportError'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-4664386934337411065</id><published>2007-10-29T17:21:00.000-06:00</published><updated>2007-11-02T06:45:40.069-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>How To: Create a new directory using TFL</title><content type='html'>&lt;span style="font-family:arial;"&gt;There may be another, simpler way of doing this, but I threw this together in a hurry. It's simple and it works.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you're on UNIX, it's very easy. You'll create a function with a single input parameter (in this example, "iDir"). Your logic will look something like this:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family: courier new; color: rgb(0, 0, 102);"&gt;IF RunProgram("mkdir", "Forever", iDir) &lt;&gt; 0&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102); font-family: courier new;"&gt;...&lt;/span&gt;&lt;span style="font-family: courier new; color: rgb(0, 0, 102);"&gt;CALL ReportError ("ABCD0001", "Error", "Failed to create directory "||iDir)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new; color: rgb(0, 0, 102);"&gt;ENDIF&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;For Windows, I simply created a batch file called mkdir.bat which contained "md %1". You run this the same as above, but specify the directory of your mkdir.bat file (i.e. c:\mkdir.bat).&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-4664386934337411065?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/4664386934337411065/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=4664386934337411065' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/4664386934337411065'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/4664386934337411065'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/10/how-to-create-new-directory.html' title='How To: Create a new directory using TFL'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-7489446079473958451</id><published>2007-10-29T10:40:00.000-06:00</published><updated>2007-11-02T06:46:08.803-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>Info: TFL Built-in Function of the week - InstanceCount()</title><content type='html'>InstanceCount tells you the number of instances in a View. I find myself using this simple built-in function all the time. There are a couple of ways to use it:&lt;br /&gt;&lt;br /&gt;1. &lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;LET vCount = InstanceCount (SetName, "ViewName")&lt;/span&gt;&lt;br /&gt;This is a nice, straight-forward way of getting the number of instances in a view into a variable so that you can use it in your TFL function.&lt;br /&gt;&lt;br /&gt;2. &lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;IF InstanceCount (SetName, "ViewName") &gt; 10&lt;/span&gt;&lt;br /&gt;I use InstanceCount in this manner all the time, especially when creating an array and doing an ADD with the result. For example:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;IF InstanceCount (ViewTodaysOrders, "Orders") &gt; 0&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;...&lt;/span&gt;LET i = 0&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;  ...&lt;/span&gt;LET vOrderID = NULL&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;  ...&lt;/span&gt;WHILE Orders&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;  ......&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;LET i = i + 1&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;  ...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;  ..&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;LET vOrderID[i] = OrdersOrderID&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;  ...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;ENDWHILE&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;  ...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;ADD ProcessOrders&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;  ...&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;&lt;span style="color: rgb(255, 255, 255);"&gt;  ..&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 102);font-family:courier new;" &gt;OrdersOrderID = vOrderID&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;ENDIF&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;This makes it simple for me to ONLY create an array and ADD my records IF there are actually records to begin with. You can find the full documentation on InstanceCount in the "Set and Database Functions" document in DocuManage.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-7489446079473958451?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/7489446079473958451/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=7489446079473958451' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/7489446079473958451'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/7489446079473958451'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/10/info-tfl-built-in-function-of-week.html' title='Info: TFL Built-in Function of the week - InstanceCount()'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-9219117672925512347</id><published>2007-10-28T15:26:00.000-06:00</published><updated>2007-10-31T15:56:34.323-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>Idea: BuildFunction &amp; DocuManage integration</title><content type='html'>How many times do you need to stop writing a function to log into Documanage to refresh your memory of a certain built-in TenFold Language function call? For some reason, I can never remember the parameter order for StartTransaction()...&lt;br /&gt;&lt;br /&gt;Wouldn't it be cool if TenFold integrated a web service into DefineFunctions that would allow you to find information like this without even having to leave your TenFold client?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-9219117672925512347?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/9219117672925512347/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=9219117672925512347' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/9219117672925512347'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/9219117672925512347'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/10/tenfold-language-reference-manuala.html' title='Idea: BuildFunction &amp; DocuManage integration'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-5855070412623668141</id><published>2007-10-28T14:58:00.000-06:00</published><updated>2007-10-31T15:56:11.954-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>Info: MySQL user lengths</title><content type='html'>&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:arial;"&gt;I ran into a MySQL issue today that's I've not experienced before. I was setting up a new environment, created from another environment's database export. I updated all the new environmentss implementation values (see below for the script to do this). When I started a new client session, I received a signon failure. I thought this strange since I knew my signon username and password was correct.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;I checked my client log and found the following error message:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="color: rgb(102, 51, 255);font-family:courier new;" &gt;**** EnterpriseTenFold started&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 51, 255);font-family:courier new;" &gt;2007/10/28 11:33:47.390 | Error DBOD0005: From MYSQL: '[MySQL][ODBC 3.51 &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 51, 255);font-family:courier new;" &gt;Driver]Access denied for user 'endwhiledict_pro'@'localhost' (using password: &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 51, 255);font-family:courier new;" &gt;YES)'&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 51, 255);font-family:courier new;" &gt;2007/10/28 11:33:47.390 | Error DBLG2073: End-user 'jason' was unable to sign &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 51, 255);font-family:courier new;" &gt;onto database instance 'ENDWHILEDICT_PROD:endwhiledict_prod' as physical user &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 51, 255);font-family:courier new;" &gt;'endwhiledict_prod'.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 51, 255);font-family:courier new;" &gt;2007/10/28 11:33:47.390 | Error DBCN0558: Failed to signon to the vendor &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 51, 255);font-family:courier new;" &gt;database.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 51, 255);font-family:courier new;" &gt;2007/10/28 11:33:47.390 | Error DBCN0507: Error during DB Sign On.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 51, 255);font-family:courier new;" &gt;2007/10/28 11:33:48.046 | Error SC000038:You entered an invalid end-user name &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 51, 255);font-family:courier new;" &gt;or password. Please check your end-user name and password and try again. &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 51, 255);font-family:courier new;" &gt;Contact your system administrator if this problem persists.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;After banging my head for a while trying to figure out why my client was attempting to sign on using &lt;/span&gt;&lt;/span&gt;&lt;span style=";font-family:arial;font-size:100%;"  &gt;endwhiledict_pro instead of (what I thought was) the correct MySQL user of &lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:arial;"&gt;endwhiledict_prod, I found that MySQL limits the length of MySQL users to 16 characters. I changed my DATABASE implementation to use a different user/pass and was able to move on.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;Here's an example of a script to update the database implementation:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 51, 255);"&gt;Update dd_data_implementations set implementation_data='&lt;user&gt;/&lt;password&gt;' where element_type='DATABASE';&lt;/password&gt;&lt;/user&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 51, 255);"&gt;Update dd_data_implementations set implementation_data='&lt;odbc&gt;:&lt;database&gt;' where element_type='DBINSTANCE';&lt;/database&gt;&lt;/odbc&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 51, 255);"&gt;Truncate table dd_preprocessed_data;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-5855070412623668141?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/5855070412623668141/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=5855070412623668141' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/5855070412623668141'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/5855070412623668141'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/10/mysql-user-lengths.html' title='Info: MySQL user lengths'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2117852929156774743.post-6316752405881875353</id><published>2007-10-28T13:16:00.000-06:00</published><updated>2007-10-31T15:56:22.631-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ENDWHILE - TenFold consulting and development'/><title type='text'>How To: Swap a child view foreign key reference</title><content type='html'>&lt;span style=";font-family:arial;font-size:100%;"  &gt;This post describes how to change the reference used by a child view. This is pretty straight-forward using the classic tools, but I don't think it's supported yet in BuildTransaction.&lt;br /&gt;&lt;br /&gt;Case example: You have a parent-child relationship, which you want to keep, but you want to change the reference used by the child view so that child records are returned based on a different foreign key. For example:&lt;br /&gt;&lt;br /&gt;Parent table: Patient&lt;br /&gt;Child table: PatientVisits&lt;br /&gt;Current child view reference: PatientVisitsPatientIDToPatientPatientID&lt;br /&gt;Join: PatientVisitsToPatient&lt;br /&gt;From table: PatientVisits&lt;br /&gt;From column: PatientID&lt;br /&gt;To table: Patient&lt;br /&gt;To column: PatientID&lt;br /&gt;&lt;br /&gt;Let's say that you've found that you have duplicate records in the Patient table - perhaps due to mis-spelling a patient's name. This means that for the same patient you have multiple PatientIDs. However, let's assume that the Social Security Number for your patients is always correct. You'd like to see all a patient's records regardless of which of the duplicate patient records you might query. To do this, you can simply change the child view's reference to use a join based on Social Security Number (assuming, of course, that your PatientVisits table contains the patient's Social Security Number).&lt;br /&gt;&lt;br /&gt;Step 1: Query your set in RefineSets&lt;br /&gt;Step 2: Select the Views frame&lt;br /&gt;Step 3: Right click on the PatientVisit (child) view's Reference and Zoom to "Reference"&lt;br /&gt;Step 4: In the Links region, right-click on the From table field and Zoom to "RefineTables". If you already have the join you need defined, skip to step 14.&lt;br /&gt;Step 5: Confirm that you have a Key defined for the Social Security Number column (if not, create one)&lt;br /&gt;Step 6: Go back to RefineSets and right-click on the To table column and choose "RefineTables"&lt;br /&gt;Step 7: Confirm that you have a Key defined for the Social Security Number field (if not, create one). Note the Key priority.&lt;br /&gt;Step 8: Go back to the RefineTables instance for the PatientVisit (child) table&lt;br /&gt;Step 9: Select the Joins frame.&lt;br /&gt;Step 10: Click [New]&lt;br /&gt;Step 11: Name your join, select the correct "To table" and select the "To key priority" that you noted above in step seven.&lt;br /&gt;Step 12: Select the "From column" and "To column" values (in this example, SocialSecurityNumber)&lt;br /&gt;Step 13: Click [Done]&lt;br /&gt;Step 14: Go back to RefineSets..References, click [New]&lt;br /&gt;Step 15: Name your reference&lt;br /&gt;Step 16: Select the "From table"&lt;br /&gt;Step 17: Select the name of the join you just created (or that already existed, if you're lucky)&lt;br /&gt;Step 18: Click [Done]&lt;br /&gt;Step 19: Go to the Views frame and select the name of your new reference in the child view's "Reference" field&lt;br /&gt;Step 20: Click [Done]&lt;br /&gt;&lt;br /&gt;You're finished. Re-open your transaction and query your records. You'll now have PatientVisits returned based on their SocialSecurityNumber rather than their PatientID.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2117852929156774743-6316752405881875353?l=endwhile.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://endwhile.blogspot.com/feeds/6316752405881875353/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2117852929156774743&amp;postID=6316752405881875353' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/6316752405881875353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2117852929156774743/posts/default/6316752405881875353'/><link rel='alternate' type='text/html' href='http://endwhile.blogspot.com/2007/10/swapping-foreign-key-reference-in-child.html' title='How To: Swap a child view foreign key reference'/><author><name>Jason Hendrickson</name><uri>http://www.blogger.com/profile/01338271465859833177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
