Re: Schemes for record level access control
On Mon, May 15, 2017 at 8:01 AM, Kirk Brooks via 4D_Tech < 4d_tech@lists.4d.com> wrote: > David, > Thanks for throwing this in. It really does make more sense to use a > longint even if it is (currently) only a binary choice. > Kirk: If you're using a number to represent a hierarchy, the surest way to think of another category "after the code is done" is to use 1, 2, 3, 4, 5, etc. as integers. Prior experience with Murphy would make me lean toward 10, 20, 30, 40, 50 so as to allow 15, 17, 38, etc. -- Douglas von Roeder 949-336-2902 ** 4D Internet Users Group (4D iNUG) FAQ: http://lists.4d.com/faqnug.html Archive: http://lists.4d.com/archives.html Options: http://lists.4d.com/mailman/options/4d_tech Unsub: mailto:4d_tech-unsubscr...@lists.4d.com **
Re: Schemes for record level access control
Hi Kirk, > On 16 May 2017, at 24:59 AEST, Kirk Brooks via 4D_Tech <4d_tech@lists.4d.com> > wrote: > > Thanks much for taking the time to share. The immediate situation I'm > trying to work with isn't as formally hierarchical as your example plus I > need to exclude 'restricted' data from even Read Only. I'm managing the > table & field access separately. ie. permission to even see a given table > is restricted by one's user group. Same idea is applied to fields within > the table. The mechanism is very similar to the one you illustrate. > > What I'm honing now is how to identify specific records that may or may not > be accessible and efficiently manage them. Your experience is confirming my > initial take. For the restrictions to a complete record in a table introduce a LongInt field to every table. I call mine always “xStatus” and if it is set to “1” then it will be interpreted as "not deleted” record. So, LongInt gives you a couple of numbers you can use to define the status of a record. ;-) As for specific field restrictions use a table called [xFieldInfo] and hold the parameters for every field in every table in it. Of the fop of my head, use a LongInt field “AccessLevel” in [xFieldInfo] and think about how Unix handles ownership/access rights: UserGroup Other READ 4 4 4 Write2 2 2 EXECUTE 1 1 1 With "chmod 777” you’ll give everyone everything. Nice idea actually I might implement something like this myself, but not that early, on an empty stomach and with no caffein in the system. ;-) Cheers Jörg ** 4D Internet Users Group (4D iNUG) FAQ: http://lists.4d.com/faqnug.html Archive: http://lists.4d.com/archives.html Options: http://lists.4d.com/mailman/options/4d_tech Unsub: mailto:4d_tech-unsubscr...@lists.4d.com **
Re: Schemes for record level access control
David, Thanks for throwing this in. It really does make more sense to use a longint even if it is (currently) only a binary choice. On Fri, May 12, 2017 at 6:03 PM, David Adams via 4D_Tech < 4d_tech@lists.4d.com> wrote: > Just as a simple point, it's nice to have access values as a number: > > 1 2 3 4 5 > -- Kirk Brooks San Francisco, CA === *The only thing necessary for the triumph of evil is for good men to do nothing.* *- Edmund Burke* ** 4D Internet Users Group (4D iNUG) FAQ: http://lists.4d.com/faqnug.html Archive: http://lists.4d.com/archives.html Options: http://lists.4d.com/mailman/options/4d_tech Unsub: mailto:4d_tech-unsubscr...@lists.4d.com **
Re: Schemes for record level access control
Hi Jorg, Thanks much for taking the time to share. The immediate situation I'm trying to work with isn't as formally hierarchical as your example plus I need to exclude 'restricted' data from even Read Only. I'm managing the table & field access separately. ie. permission to even see a given table is restricted by one's user group. Same idea is applied to fields within the table. The mechanism is very similar to the one you illustrate. What I'm honing now is how to identify specific records that may or may not be accessible and efficiently manage them. Your experience is confirming my initial take. On Fri, May 12, 2017 at 5:51 PM, Jörg Knebel via 4D_Tech < 4d_tech@lists.4d.com> wrote: > G’day Kirk, > > > On 13 May 2017, at 05:42 AEST, Kirk Brooks via 4D_Tech < > 4d_tech@lists.4d.com> wrote: > > > > I'd like to hear from some of you who have implemented systems that allow > > for record-level access control in a 4D database. > > Pick me! ;-) > > You’re sure you want to discuss this on the list down to the last detail? > > Here are some important starting points: > > First, forget everything about putting users in groups the 4D-way, > actually forget/don’t touch the 4D-Access implementation at all. > > Now think of access strictly in to ways: Read Only and Read/Write. > > Imagine an organisation structure 5 level deep (relation arrows like in > 4D): > > Organisation <—— Branch <—— Department <—— Unit <—— User (have a table for > each and you can build your application to be a multi-tenant one) > > Define access levels and apply for RO and RW (2D array LongInt): > > Full access (Designer) FA > Org access OA > Branch access BA > Department access DA > Unit access UA > Author/User access AA > NO access NA > > apply these levels to a spread sheet with columns like this: > > 4dTable name/# RO_FA RO_OA … —> … RW_AA RW_NA > > > - Keep this matrix for each and every user. > > At log in time assign the relevant information to interprocess variables > or to an object. > > have the following LongInt reference fields in EVERY table > > UserCreated > UnitCreated > DepartmentCreated > BranchCreated > OrgCreated > > Every time someone likes to access the content of a table one has to check > the access rights like this > > (code snippet sample) > > Case of > : ($vlAccess=0) //No Access > > If ($vlStatusField>0) > QUERY($TablePtr->; & ;Field($TableNo;$vlStatusField)->=-9) > End if > $0:=2 > : ($vlAccess=1) //Author Access > > If ($vbWholeTable) //all non deleted records in table > If ($vlCreatorField>0) > QUERY($TablePtr->;Field($TableNo;$vlCreatorField)->=<>vlUserID;*) > If ($vlDepartmentField>0) > QUERY($TablePtr->; & ;Field($TableNo;$vlDepartmentField)->=<> > vlUserDepartment;*) > End if > If ($vlBranchField>0) > QUERY($TablePtr->; & ;Field($TableNo;$vlBranchField)->=<>vlUserBranch;*) > End if > If ($vlUnitField>0) > QUERY($TablePtr->; & ;Field($TableNo;$vlUnitField)->=<>vlUserUnit;*) > End if > If ($vlStatusField>0) > QUERY($TablePtr->; & ;Field($TableNo;$vlStatusField)->=1) > Else > QUERY($TablePtr->) > End if > $vbAccess:=True > Else > $0:=2 > End if > Else // in the current selection only > If ($vlCreatorField>0) > QUERY SELECTION($TablePtr->;Field($TableNo;$vlCreatorField)->=<> > vlUserID;*) > If ($vlDepartmentField>0) > QUERY SELECTION($TablePtr->; & ;Field($TableNo;$vlDepartmentField)->=<> > vlUserDepartment;*) > End if > If ($vlBranchField>0) > QUERY SELECTION($TablePtr->; & ;Field($TableNo;$vlBranchField)->=<> > vlUserBranch;*) > End if > If ($vlUnitField>0) > QUERY SELECTION($TablePtr->; & ;Field($TableNo;$vlUnitField)- > >=<>vlUserUnit) > Else > QUERY SELECTION($TablePtr->) > End if > $vbAccess:=True > Else > $0:=2 > End if > End if > end case > > > This is all I have time for, but I hope that helps. > > Cheers > Jörg > > > > ** > 4D Internet Users Group (4D iNUG) > FAQ: http://lists.4d.com/faqnug.html > Archive: http://lists.4d.com/archives.html > Options: http://lists.4d.com/mailman/options/4d_tech > Unsub: mailto:4d_tech-unsubscr...@lists.4d.com > ** > -- Kirk Brooks San Francisco, CA === *The only thing necessary for the triumph of evil is for good men to do nothing.* *- Edmund Burke* ** 4D Internet Users Group (4D iNUG) FAQ: http://lists.4d.com/faqnug.html Archive: http://lists.4d.com/archives.html Options: http://lists.4d.com/mailman/options/4d_tech Unsub: mailto:4d_tech-unsubscr...@lists.4d.com **
Re: Schemes for record level access control
Like I said, many developers don't like 4D access system, in fact, any 4D inbuilt-tools such as QR editor, Query Editor, Label Editor, Sequence Number, Triggers etc. I'm weird and kept using them intensively even after developing on 4D for 27 years. I'm happily remained to be amature:-) Alan Chan 4D iNug Technical <4d_tech@lists.4d.com> writes: >Much like others have indicated, stay as far away as you can from the built in >4D access shit, it's for amatures. ** 4D Internet Users Group (4D iNUG) FAQ: http://lists.4d.com/faqnug.html Archive: http://lists.4d.com/archives.html Options: http://lists.4d.com/mailman/options/4d_tech Unsub: mailto:4d_tech-unsubscr...@lists.4d.com **
RE: Schemes for record level access control
Hi Kirk, I'll get back to my usual NUG posting -- Private I think it depends on what you need to do, and how "general" it needs to be. I have a system that is accessed by multiple business entities, where most are limited to their own records, while one can "see" all records. In this case, the restriction applies to customers, so each entity has a list of customers they are allowed to see (modification is another story), and then all that is linked to the customer, i.e. orders, invoices, AR, history, etc. In my case, it was simpler to create an "Allowed" list for each entity, and then just use that list to narrow down the selection in any access points. This allowed me to accommodate users moving between entities (does happen, a lot), without any additional processing or change to any code. My structure link a user to a group for access control (modification and visibility is handled down to field level by table), and also a link to an entity table, which control the records that this entity can access. In my case, I use inclusion. i.e. values on the entity list were allowed, but you could also use it as a disallowed list. Since it's values (customer_ID), it's easy and fast to filter. Hope this makes sense. Much like others have indicated, stay as far away as you can from the built in 4D access shit, it's for amatures. Oh, about the listbox, I don't think its different in v16. Lahav -Original Message- From: 4D_Tech [mailto:4d_tech-boun...@lists.4d.com] On Behalf Of Kirk Brooks via 4D_Tech Sent: Friday, May 12, 2017 6:14 PM To: 4D iNug Technical <4d_tech@lists.4d.com> Cc: Kirk Brooks <lists.k...@gmail.com> Subject: Re: Schemes for record level access control Right - so the ultimate permission is the most permissive of all available. On Fri, May 12, 2017 at 4:56 PM, Alan Chan via 4D_Tech <4d_tech@lists.4d.com > wrote: > I assume a member might belongs to multiple teams but will a member > belongs to multiple clubs? > > Alan Chan > > 4D iNug Technical <4d_tech@lists.4d.com> writes: > >Hi Alan, > >Those are the go-to solutions. In my case we aren't using the 4D > >password system so I can't rely on that. Plus I need actual record > >level restriction. So to follow your example, I may want a Team to be > >able to > see > >themselves and other teams in their Club (just making this up) but > >not teams in other Clubs. > > > > > > ** > 4D Internet Users Group (4D iNUG) > FAQ: http://lists.4d.com/faqnug.html > Archive: http://lists.4d.com/archives.html > Options: http://lists.4d.com/mailman/options/4d_tech > Unsub: mailto:4d_tech-unsubscr...@lists.4d.com > ** > -- Kirk Brooks San Francisco, CA === *The only thing necessary for the triumph of evil is for good men to do nothing.* *- Edmund Burke* ** 4D Internet Users Group (4D iNUG) FAQ: http://lists.4d.com/faqnug.html Archive: http://lists.4d.com/archives.html Options: http://lists.4d.com/mailman/options/4d_tech Unsub: mailto:4d_tech-unsubscr...@lists.4d.com ** ** 4D Internet Users Group (4D iNUG) FAQ: http://lists.4d.com/faqnug.html Archive: http://lists.4d.com/archives.html Options: http://lists.4d.com/mailman/options/4d_tech Unsub: mailto:4d_tech-unsubscr...@lists.4d.com **
Re: Schemes for record level access control
On Sat, May 13, 2017 at 9:04 AM, David Adamswrote: > > > Just as a simple point, it's nice to have access values as a number: > > 1 2 3 4 5 > > Imagine that access increases at each step. > > // On after query > C_LONGINT($1;$user_access_level) > $user_access_level:=$1 > > QUERY SELECTION([Foo];[Foo]Minimum_access_score <= $user_access_level) > +1, especially when "...then you don't have to jump through any more hoops when using 4D's built-in editors and tools. " Steve Simpson Cimarron Software ** 4D Internet Users Group (4D iNUG) FAQ: http://lists.4d.com/faqnug.html Archive: http://lists.4d.com/archives.html Options: http://lists.4d.com/mailman/options/4d_tech Unsub: mailto:4d_tech-unsubscr...@lists.4d.com **
Re: Schemes for record level access control
Just as a simple point, it's nice to have access values as a number: 1 2 3 4 5 Imagine that access increases at each step. // On after query C_LONGINT($1;$user_access_level) $user_access_level:=$1 QUERY SELECTION([Foo];[Foo]Minimum_access_score <= $user_access_level) So, if the user has a level of 3, they only get a selection of records allowed to people with a score of 1, 2, or 3. If their level were 2, they would only get records with a value of 1 or 2. If the initial selection found a more restricted record, it's filtered out very easily I like to filter selections because then you don't have to jump through any more hoops when using 4D's built-in editors and tools. That's code off the top of my head, it only accounts for some requirements, etc., etc. ** 4D Internet Users Group (4D iNUG) FAQ: http://lists.4d.com/faqnug.html Archive: http://lists.4d.com/archives.html Options: http://lists.4d.com/mailman/options/4d_tech Unsub: mailto:4d_tech-unsubscr...@lists.4d.com **
Re: Schemes for record level access control
G’day Kirk, > On 13 May 2017, at 05:42 AEST, Kirk Brooks via 4D_Tech <4d_tech@lists.4d.com> > wrote: > > I'd like to hear from some of you who have implemented systems that allow > for record-level access control in a 4D database. Pick me! ;-) You’re sure you want to discuss this on the list down to the last detail? Here are some important starting points: First, forget everything about putting users in groups the 4D-way, actually forget/don’t touch the 4D-Access implementation at all. Now think of access strictly in to ways: Read Only and Read/Write. Imagine an organisation structure 5 level deep (relation arrows like in 4D): Organisation <—— Branch <—— Department <—— Unit <—— User (have a table for each and you can build your application to be a multi-tenant one) Define access levels and apply for RO and RW (2D array LongInt): Full access (Designer) FA Org access OA Branch access BA Department access DA Unit access UA Author/User access AA NO access NA apply these levels to a spread sheet with columns like this: 4dTable name/# RO_FA RO_OA … —> … RW_AA RW_NA - Keep this matrix for each and every user. At log in time assign the relevant information to interprocess variables or to an object. have the following LongInt reference fields in EVERY table UserCreated UnitCreated DepartmentCreated BranchCreated OrgCreated Every time someone likes to access the content of a table one has to check the access rights like this (code snippet sample) Case of : ($vlAccess=0) //No Access If ($vlStatusField>0) QUERY($TablePtr->; & ;Field($TableNo;$vlStatusField)->=-9) End if $0:=2 : ($vlAccess=1) //Author Access If ($vbWholeTable) //all non deleted records in table If ($vlCreatorField>0) QUERY($TablePtr->;Field($TableNo;$vlCreatorField)->=<>vlUserID;*) If ($vlDepartmentField>0) QUERY($TablePtr->; & ;Field($TableNo;$vlDepartmentField)->=<>vlUserDepartment;*) End if If ($vlBranchField>0) QUERY($TablePtr->; & ;Field($TableNo;$vlBranchField)->=<>vlUserBranch;*) End if If ($vlUnitField>0) QUERY($TablePtr->; & ;Field($TableNo;$vlUnitField)->=<>vlUserUnit;*) End if If ($vlStatusField>0) QUERY($TablePtr->; & ;Field($TableNo;$vlStatusField)->=1) Else QUERY($TablePtr->) End if $vbAccess:=True Else $0:=2 End if Else // in the current selection only If ($vlCreatorField>0) QUERY SELECTION($TablePtr->;Field($TableNo;$vlCreatorField)->=<>vlUserID;*) If ($vlDepartmentField>0) QUERY SELECTION($TablePtr->; & ;Field($TableNo;$vlDepartmentField)->=<>vlUserDepartment;*) End if If ($vlBranchField>0) QUERY SELECTION($TablePtr->; & ;Field($TableNo;$vlBranchField)->=<>vlUserBranch;*) End if If ($vlUnitField>0) QUERY SELECTION($TablePtr->; & ;Field($TableNo;$vlUnitField)->=<>vlUserUnit) Else QUERY SELECTION($TablePtr->) End if $vbAccess:=True Else $0:=2 End if End if end case This is all I have time for, but I hope that helps. Cheers Jörg ** 4D Internet Users Group (4D iNUG) FAQ: http://lists.4d.com/faqnug.html Archive: http://lists.4d.com/archives.html Options: http://lists.4d.com/mailman/options/4d_tech Unsub: mailto:4d_tech-unsubscr...@lists.4d.com **
Re: Schemes for record level access control
It would be a lot easier if 4D password system is activated. Just a new group "TeamAccess_Bypass". LIke I said before, 4D password system does great help on achieving this. While we find 4D password system is invaluable, I know many developers don't like it. Alan Chan 4D iNug Technical <4d_tech@lists.4d.com> writes: >Right - so the ultimate permission is the most permissive of all available. > >On Fri, May 12, 2017 at 4:56 PM, Alan Chan via 4D_Tech <4d_tech@lists.4d.com >> wrote: > >> I assume a member might belongs to multiple teams but will a member >> belongs to multiple clubs? >> >> Alan Chan >> >> 4D iNug Technical <4d_tech@lists.4d.com> writes: >> >Hi Alan, >> >Those are the go-to solutions. In my case we aren't using the 4D password >> >system so I can't rely on that. Plus I need actual record level >> >restriction. So to follow your example, I may want a Team to be able to >> see >> >themselves and other teams in their Club (just making this up) but not >> >teams in other Clubs. >> > >> > > ** 4D Internet Users Group (4D iNUG) FAQ: http://lists.4d.com/faqnug.html Archive: http://lists.4d.com/archives.html Options: http://lists.4d.com/mailman/options/4d_tech Unsub: mailto:4d_tech-unsubscr...@lists.4d.com **
Re: Schemes for record level access control
Right - so the ultimate permission is the most permissive of all available. On Fri, May 12, 2017 at 4:56 PM, Alan Chan via 4D_Tech <4d_tech@lists.4d.com > wrote: > I assume a member might belongs to multiple teams but will a member > belongs to multiple clubs? > > Alan Chan > > 4D iNug Technical <4d_tech@lists.4d.com> writes: > >Hi Alan, > >Those are the go-to solutions. In my case we aren't using the 4D password > >system so I can't rely on that. Plus I need actual record level > >restriction. So to follow your example, I may want a Team to be able to > see > >themselves and other teams in their Club (just making this up) but not > >teams in other Clubs. > > > > > > ** > 4D Internet Users Group (4D iNUG) > FAQ: http://lists.4d.com/faqnug.html > Archive: http://lists.4d.com/archives.html > Options: http://lists.4d.com/mailman/options/4d_tech > Unsub: mailto:4d_tech-unsubscr...@lists.4d.com > ** > -- Kirk Brooks San Francisco, CA === *The only thing necessary for the triumph of evil is for good men to do nothing.* *- Edmund Burke* ** 4D Internet Users Group (4D iNUG) FAQ: http://lists.4d.com/faqnug.html Archive: http://lists.4d.com/archives.html Options: http://lists.4d.com/mailman/options/4d_tech Unsub: mailto:4d_tech-unsubscr...@lists.4d.com **
Re: Schemes for record level access control
If implemented correctly, performance hit could be minimum. Do what query if(records in selection([WhateverTable]>0) if(<>TeamAccessRequired)\\some customers do not need this feature Query selection with array([WhateverTable]Team;<>CurTeam) end if end if <>CurTeam is loaded from team member table at startup method. Query selection with array is NOT preemptive in 4D 13/15 that might have performance hit on server. Based on v16 doc, this command would be preemptive and hopefully it does not have hidden limitation. Alan Chan 4D iNug Technical <4d_tech@lists.4d.com> writes: >That sounds like real DOD level stuff. Fortunately I don't need that level >but it gives me some ideas. > >What kind of performance hit did you see as a result of all that extra >processing? ** 4D Internet Users Group (4D iNUG) FAQ: http://lists.4d.com/faqnug.html Archive: http://lists.4d.com/archives.html Options: http://lists.4d.com/mailman/options/4d_tech Unsub: mailto:4d_tech-unsubscr...@lists.4d.com **
Re: Schemes for record level access control
I assume a member might belongs to multiple teams but will a member belongs to multiple clubs? Alan Chan 4D iNug Technical <4d_tech@lists.4d.com> writes: >Hi Alan, >Those are the go-to solutions. In my case we aren't using the 4D password >system so I can't rely on that. Plus I need actual record level >restriction. So to follow your example, I may want a Team to be able to see >themselves and other teams in their Club (just making this up) but not >teams in other Clubs. > > ** 4D Internet Users Group (4D iNUG) FAQ: http://lists.4d.com/faqnug.html Archive: http://lists.4d.com/archives.html Options: http://lists.4d.com/mailman/options/4d_tech Unsub: mailto:4d_tech-unsubscr...@lists.4d.com **
Re: Schemes for record level access control
Hi Alan, Those are the go-to solutions. In my case we aren't using the 4D password system so I can't rely on that. Plus I need actual record level restriction. So to follow your example, I may want a Team to be able to see themselves and other teams in their Club (just making this up) but not teams in other Clubs. On Fri, May 12, 2017 at 4:33 PM, Alan Chan via 4D_Tech <4d_tech@lists.4d.com > wrote: > We restricted record access based on Team (Field related to Team and > Member table), Module (menu bar), History (Date) and other access such as > cross team and also by field level such as viewing cost, modifying sales > price, bypassing margin control > or credit control, just name a few, through 4D standard user/group access > feature. > > With combination of all of above, we can restrict/control access from > users on almost all level. > > 4D standard user/groups access are extremely helpful for these kind of > control and we have more than 200 user groups for these purpose. > > Alan Chan > > 4D iNug Technical <4d_tech@lists.4d.com> writes: > >Hi folks, > >I'd like to hear from some of you who have implemented systems that allow > >for record-level access control in a 4D database. This is the sort of > thing > >where we want to prevent unauthorized users from seeing or inferring the > >'restricted' records. > > > >Theoretically it's pretty easy - include a field on relevant tables called > >'restricted' or some such and the rules are you filter those records out > if > >the user's permission doesn't allow them. Simple enough but, as we know, > >there be devils there. Maybe it's a whole different approach to the > >structure? > > > >I want to hear about the details of what it took to make that work with > >respect to related records, queries on related records, sorting and so on. > > > > ** > 4D Internet Users Group (4D iNUG) > FAQ: http://lists.4d.com/faqnug.html > Archive: http://lists.4d.com/archives.html > Options: http://lists.4d.com/mailman/options/4d_tech > Unsub: mailto:4d_tech-unsubscr...@lists.4d.com > ** > -- Kirk Brooks San Francisco, CA === *The only thing necessary for the triumph of evil is for good men to do nothing.* *- Edmund Burke* ** 4D Internet Users Group (4D iNUG) FAQ: http://lists.4d.com/faqnug.html Archive: http://lists.4d.com/archives.html Options: http://lists.4d.com/mailman/options/4d_tech Unsub: mailto:4d_tech-unsubscr...@lists.4d.com **
Re: Schemes for record level access control
Kirk: Of course there are all sorts of ways this could be done. It all depends on the complexity. We had to record by each user which records they were restricted from seeing. We also needed to permit / restrict by a group as well. Therefore we could not put a ‘flag’ within the record. When a record was first found (i.e. Query) before being displayed we would have to check each record in the selection to see if there was a record in our ‘Restricted’ table for the currently signed in User. There could be different levels of restrictions as well. For some kinds of restricted records we also needed to record what the query was that found the record(s). This was to see if they were hunting for that record, or it was by accident. Therefore for each user there was an associated table that indicated which groups they were in. We used the record keys (Primary Key) to search for each record to see if the current user was restricted in regard to the record. Of course this could be much easier if there are less possibilities. Jody > On 05/12/2017, at 1:42 PM, Kirk Brooks via 4D_Tech <4d_tech@lists.4d.com> > wrote: > > Hi folks, > I'd like to hear from some of you who have implemented systems that allow > for record-level access control in a 4D database. This is the sort of thing > where we want to prevent unauthorized users from seeing or inferring the > 'restricted' records. > > Theoretically it's pretty easy - include a field on relevant tables called > 'restricted' or some such and the rules are you filter those records out if > the user's permission doesn't allow them. Simple enough but, as we know, > there be devils there. Maybe it's a whole different approach to the > structure? > > I want to hear about the details of what it took to make that work with > respect to related records, queries on related records, sorting and so on. > > -- > Kirk Brooks > San Francisco, CA > === > > *The only thing necessary for the triumph of evil is for good men to do > nothing.* > > *- Edmund Burke* > ** > 4D Internet Users Group (4D iNUG) > FAQ: http://lists.4d.com/faqnug.html > Archive: http://lists.4d.com/archives.html > Options: http://lists.4d.com/mailman/options/4d_tech > Unsub: mailto:4d_tech-unsubscr...@lists.4d.com > ** ** 4D Internet Users Group (4D iNUG) FAQ: http://lists.4d.com/faqnug.html Archive: http://lists.4d.com/archives.html Options: http://lists.4d.com/mailman/options/4d_tech Unsub: mailto:4d_tech-unsubscr...@lists.4d.com **