Thanks Henry. Those hints will aid my redesign/replacement of the Zulu addon.
Ian On Tue, 31 May 2022 at 13:33, Henry Rich <[email protected]> wrote: > 1. An x argument to timex will give the average over x tries. > > 2. If z is short, you are mostly timing the execution of the adverbs and > conjunctions that make up the definition of the verb. For example, when > you write > > ;: inv > > the system looks up inv as ^:_1 and then executes ;:^:_1 . That in turn > calls the parser (recursively) to parse the string > > }:@;@(,&' '&.>"1) :. ;: > > which is the actual inverse. The execution of all those @ &. and :. to > define the verb takes more time than running the verb on a short argument. > > 3. If you care about the performance on short y, you can either > > * use ;:inv inside a tacit verb so that the parsing is done when the > verb is created; > * in an explicit definition, use (;:^._1) . This engages PPPP > (pre-parsed parenthesized primitives): ;:^:_1 will be parsed when the > explicit definition is created, and executed without even the overhead > of a name lookup. > > 4. For timing, you have to be careful using named arguments. ;:inv can > execute inplace on suitable y. 'Suitable' here means that all the boxed > contents are not being used anywhere else. In that case, adding the ' ' > at the end can be done inplace (and the ; executes faster as well). > When you test on ';:^:_1 z', z is not a suitable y (because the value is > used in the name) and you will get slower results than if you timed > ';:^:_1 expression&.>' Heisenberg! If you use a named z you get slower > code, and if you have the expression you aren't timing ;:^:_1 only. For > unboxed arguments you could use z_: to make the value of z inplaceable, > but I don't that that suffices for boxed z. > > Henry Rich > > > On 5/30/2022 8:08 PM, Ian Clark wrote: > > Henry wrote: > >> Testing things so short, test multiple runs. > > Also, here you are including parsing times which might exceed executing > > time. > > > > I've run the following test plan with j904 Beta-d: > > > > 9!:56'cpu' > > > > $z=: fread '/Applications/j904/system/main/stdlib.ijs' > > > > timex'(;:inv) z' > > > > timex'([: ; '' '',each~ ])z' > > > > > > on: > > > > ++ Mac MBA early 2014 (x86_64) > > ++ Mac mini M1 chip (native arm64) > > ++ Mac mini M1 chip (Rosetta x86_64 emulation) > > > > > > Note the substantially longer sample LF-string I've used, viz the text of > > stdlib.ijs . > > > > > > I do have a somewhat smarter method of averaging repeated timings. But > for > > a forensic session I thought I'd use what everyone else has got. > > > > > > Mac MBA early 2014 (x86_64) > > > > 9!:56'cpu' > > x86_64 > > $z=: fread '/Applications/j904/system/main/stdlib.ijs' > > 60421 > > timex'(;:inv) z' > > 0.015428 > > timex'(;:inv) z' > > 0.013476 > > timex'(;:inv) z' > > 0.013629 > > timex'(;:inv) z' > > 0.013494 > > timex'(;:inv) z' > > 0.014735 > > timex'(;:inv) z' > > 0.013335 > > timex'(;:inv) z' > > 0.013783 > > timex'(;:inv) z' > > 0.013353 > > > > (inserted by hand): mean value: 0.0139041 > > > > timex'([: ; '' '',each~ ])z' > > 0.013806 > > timex'([: ; '' '',each~ ])z' > > 0.013383 > > timex'([: ; '' '',each~ ])z' > > 0.013903 > > timex'([: ; '' '',each~ ])z' > > 0.013341 > > timex'([: ; '' '',each~ ])z' > > 0.013323 > > timex'([: ; '' '',each~ ])z' > > 0.013576 > > timex'([: ; '' '',each~ ])z' > > 0.011759 > > timex'([: ; '' '',each~ ])z' > > 0.013209 > > > > (inserted by hand): mean value: 0.0132875 > > > > Mac mini M1 chip (native arm64) > > > > 9!:56'cpu' > > arm64 > > $z=: fread '/Applications/j904/system/main/stdlib.ijs' > > 60421 > > timex'(;:inv) z' > > 0.012289 > > timex'(;:inv) z' > > 0.013109 > > timex'(;:inv) z' > > 0.01277 > > timex'(;:inv) z' > > 0.013593 > > timex'(;:inv) z' > > 0.014168 > > timex'(;:inv) z' > > 0.014498 > > timex'(;:inv) z' > > 0.011915 > > timex'(;:inv) z' > > 0.011848 > > > > (inserted by hand): mean value: 0.0130238 > > > > timex'([: ; '' '',each~ ])z' > > 0.011718 > > timex'([: ; '' '',each~ ])z' > > 0.013287 > > timex'([: ; '' '',each~ ])z' > > 0.011614 > > timex'([: ; '' '',each~ ])z' > > 0.01695 > > timex'([: ; '' '',each~ ])z' > > 0.015872 > > timex'([: ; '' '',each~ ])z' > > 0.013207 > > timex'([: ; '' '',each~ ])z' > > 0.012396 > > timex'([: ; '' '',each~ ])z' > > 0.014463 > > > > (inserted by hand): mean value: 0.0136884 > > > > Mac mini M1 chip (Rosetta x86_64 emulation) > > > > 9!:56'cpu' > > x86_64 > > $z=: fread '/Applications/j904/system/main/stdlib.ijs' > > 60421 > > timex'(;:inv) z' > > 0.014958 > > timex'(;:inv) z' > > 0.013211 > > timex'(;:inv) z' > > 0.014644 > > timex'(;:inv) z' > > 0.012561 > > timex'(;:inv) z' > > 0.012615 > > timex'(;:inv) z' > > 0.012795 > > timex'(;:inv) z' > > 0.012811 > > timex'(;:inv) z' > > 0.014273 > > > > (inserted by hand): mean value: 0.0134835 > > > > timex'([: ; '' '',each~ ])z' > > 0.010994 > > timex'([: ; '' '',each~ ])z' > > 0.011156 > > timex'([: ; '' '',each~ ])z' > > 0.011643 > > timex'([: ; '' '',each~ ])z' > > 0.011929 > > timex'([: ; '' '',each~ ])z' > > 0.0116 > > timex'([: ; '' '',each~ ])z' > > 0.012876 > > timex'([: ; '' '',each~ ])z' > > 0.011646 > > timex'([: ; '' '',each~ ])z' > > 0.01134 > > > > (inserted by hand): mean value: 0.011648 > > > > > > I conclude from this trial that with such a long string (z) there is > > surprisingly little difference in execution time between j phrases, > > architectures, or even Mac models. > > > > Maybe z is too long? I wonder if just one non-CPU-dependent process isn't > > dominating the transaction. Memory allocation? Both the MBA and Mac mini > > use flash memory. Maybe that hasn't improved as much as CPUs since 2014, > > the date of my MBA. > > > > I typically use Zulu (the existing addon) with short strings: 10 to 100 > > bytes, so the parsing time is part of the deal for me. Though Zulu's > > follow-on will get used routinely to process jscripts – though maybe only > > line-by-line. So I'm back in the 10-100 byte bracket. > > > > Ian Clark > > > > On Mon, 30 May 2022 at 11:47, Henry Rich <[email protected]> wrote: > > > >> Testing things so short, test multiple runs. > >> > >> Also, here you are including parsing times which might exceed executing > >> time. > >> > >> Henry Rich > >> > >> On Sun, May 29, 2022, 11:16 PM Ian Clark <[email protected]> wrote: > >> > >>>> As well ask why you found it at all. > >>> I doubt I'd have found it at all, had not j904 crashed as soon as I > gave > >> it > >>> my pet startup.ijs. > >>> Which just happens to run a deeply paranoid test. > >>> > >>>> I am surprised that ;:inv is slower than ([: ; SP,each~ ]). > >>> So was I… > >>> > >>> z=: ;:'alpha bravo charlie ' > >>> > >>> timex'(;:inv) z' > >>> > >>> 3.8e_5 > >>> > >>> timex'([: ; '' '',each~ ])z' > >>> > >>> 3.1e_5 > >>> > >>> JVERSION > >>> > >>> Engine: j904/j64/darwin > >>> > >>> Beta-d: commercial/2022-05-19T20:41:44 > >>> > >>> Library: 9.04.01 > >>> > >>> Qt IDE: 2.0.3/6.2.4(6.2.4) > >>> > >>> Platform: Darwin 64 > >>> > >>> Installer: J904 install > >>> > >>> InstallPath: /applications/j904 > >>> > >>> Contact: www.jsoftware.com > >>> > >>> > >>> Even slower, in jconsole… > >>> > >>> > >>> z=: ;:'alpha bravo charlie ' > >>> timex'(;:inv)z' > >>> 4.2e_5 > >>> timex'([: ; '' '',each~ ])z' > >>> 2.7e_5 > >>> JVERSION > >>> Engine: j904/j64/darwin > >>> Beta-d: commercial/2022-05-19T20:41:44 > >>> Library: 9.04.01 > >>> Platform: Darwin 64 > >>> Installer: J904 install > >>> InstallPath: /applications/j904 > >>> Contact: www.jsoftware.com > >>> > >>> > >>> But the more I use it, I sense the Apple M1 chip in my Mac mini is > >>> lightning-fast at moving bytes around in memory, as opposed to doing > >>> significant computation – when it doesn't perform all that much better > >> than > >>> the Intel chip Apple has discarded. > >>> > >>> Maybe not that surprising when you ponder the meaning of "reduced > >>> instruction set". > >>> M1 is an ARM architecture. (Which JVERSION doesn't show – maybe it > >> should?) > >>> Unless j904_mac64.zip is compiled for ARM, then j904 will be running > >> under > >>> Rosetta emulation of Intel architecture. I don't know how to discover > if > >>> that's happening. > >>> > >>> > >>> On Sat, 28 May 2022 at 04:22, Henry Rich <[email protected]> wrote: > >>> > >>>> I am surprised that ;:inv is slower than ([: ; SP,each~ ]). That > needs > >>>> looking into. But ([: ; SP,each~ ]) uses a few features I have added > >>>> (append in place inside boxes, and support for ;@:(f&.>) with fewer > >>>> passes over the data) which is gratifying. > >>>> > >>>> When would you have found the beta-d bug you found? As well ask why > >> you > >>>> found it at all. AFAICS no intentional change in beta-d caused the > >>>> error: a bit was being cleared erroneously and somehow in beta-d the > >> bit > >>>> was in an address. > >>>> > >>>> The older I get the more I realize there is no such thing as a working > >>>> program. Even IEFBR14 had a bug. > >>>> > >>>> Henry Rich > >>>> > >>>> > >>>> > >>>> > >>>> On 5/27/2022 10:53 PM, Ian Clark wrote: > >>>>> Thanks for the ideas, Raul. Here's my grid: > >>>>> > >>>>> ┌───┬───────────────┬───────────────┬───────────────┬───────────────┐ > >>>>> > >>>>> │ │ B(boxed) │ F(LFend) │ O(open) │ X(matrix) │ > >>>>> > >>>>> ├───┼───────────────┼───────────────┼───────────────┼───────────────┤ > >>>>> > >>>>> │B4*│] │cuT&aLF │cuT&aSP │[: dtb each <"1│ > >>>>> > >>>>> ├───┼───────────────┼───────────────┼───────────────┼───────────────┤ > >>>>> > >>>>> │F4*│[: ; LF,each~ ]│aLF │(SP,LF)&charsub│[: F4B B4X │ > >>>>> > >>>>> ├───┼───────────────┼───────────────┼───────────────┼───────────────┤ > >>>>> > >>>>> │O4*│[: ; SP,each~ ]│(LF,SP)&charsub│aSP │[: O4B B4X │ > >>>>> > >>>>> ├───┼───────────────┼───────────────┼───────────────┼───────────────┤ > >>>>> > >>>>> │X4*│> │>&(cuT&aLF) │>&(cuT&aSP) │] │ > >>>>> > >>>>> └───┴───────────────┴───────────────┴───────────────┴───────────────┘ > >>>>> > >>>>> > >>>>> SP=: ' ' NB. (which IMO ought to be in stdlib) > >>>>> > >>>>> cuT=: <;._2 > >>>>> > >>>>> aLF=: ] , LF #~ LF ~: {: NB. append LF if not there already > >>>>> > >>>>> aSP=: ] , SP #~ SP ~: {: NB. append ' ' if not there already > >>>>> > >>>>> > >>>>> *Observations*: > >>>>> > >>>>> > >>>>> I wish I'd known stdlib had cutLF, so thanks for that. > >>>>> > >>>>> Your use of (;:inv) is neat. > >>>>> However timex tells me ([: ; SP,each~ ]) is faster on the Mac with M1 > >>>> chip, > >>>>> so I'll go with that for now. > >>>>> > >>>>> > >>>>> Providing verbs B4B, F4F… looks otiose, but simplifies the design of > >>>>> consistency tests. > >>>>> > >>>>> > >>>>> Personally I prefer the name O4X (say) to X2O. I used to employ the > >>>> latter, > >>>>> but saw Roger preferring names the other way round and found it > >>>>> worked better for me too. Easier to check visually: see the last > >> column > >>>>> above. > >>>>> > >>>>> Accordingly I extended Zulu (~addons/format/zulu/*) with yet another > >>>>> optional script, which defined o4x=:x2o etc. But that just made it > >> even > >>>>> more unwieldy. > >>>>> > >>>>> > >>>>> This design, which I'm calling BFOX, corrects the wrong Zulu policy > >>>>> regarding 'f' format by making a final LF mandatory in the new 'F' > >>>> format. > >>>>> This has several advantages. For a start it's what you get with: > >>>>> > >>>>> zuF=: noun define > >>>>> > >>>>> alpha > >>>>> > >>>>> bravo > >>>>> > >>>>> charlie > >>>>> > >>>>> ) > >>>>> > >>>>> In Zulu this gives 4 rows, not 3 as under the current design. > >>>>> > >>>>> > >>>>> It seems logical to me to extend the same policy to O format, since I > >>>> mean > >>>>> to implement O and F with identical code, merely switching SP <--> > >> LF. > >>>>> > >>>>> I want to avoid breaking existing code. So I think I'll create a new > >>>> addon: > >>>>> BFOX (~addons/format/bfox.ijs --all in a single script) and > >> standardize > >>>> on > >>>>> *4* naming. > >>>>> > >>>>> > >>>>> Instead of a mandatory test on loading the addon, I'll also provide a > >>>>> separate test script (as addons are supposed to do), which checks > >>> logical > >>>>> consistency by converting via several routes back to the original, > >> plus > >>>>> addressing nouns with 0 or 1 "rows", plus all the other good things > >>> Zulu > >>>>> does. I've yet to do this, but I fancy it'll all be a lot neater, > >> with > >>>>> fewer edge cases to handle. > >>>>> > >>>>> > >>>>> At least that was my plan until it struck me BFOX might make a better > >>>>> Foreign in the (3!:) range, than yet another potentially klugey > >> addon. > >>>> But > >>>>> this is all making work for Henry…! > >>>>> > >>>>> > >>>>> Another thought: if Zulu hadn't done its mandatory suite of tests on > >>>>> loading, when if ever would I have hit this bug in Beta-d? > >>>>> > >>>>> > >>>>> > >>>>> > >>>>> > >>>>> On Thu, 26 May 2022 at 17:23, Raul Miller <[email protected]> > >>> wrote: > >>>>>> (I sort of ignored the empty string case, obviously - in some cases > >>>>>> these conversions would discard them. In others, it would preserve > >>>>>> them. It's something of a judgement call ... somewhat analogous to > >>>>>> forum choice, which I perhaps abused in my previous message.) > >>>>>> > >>>>>> -- > >>>>>> Raul > >>>>>> > >>>>>> On Thu, May 26, 2022 at 12:19 PM Raul Miller <[email protected] > >>>>>> wrote: > >>>>>>> Here's how I think I'd tackle that "grid": > >>>>>>> > >>>>>>> b2f ;,&LF&.> b > >>>>>>> b2o ;:inv b > >>>>>>> b2x > b > >>>>>>> > >>>>>>> f2b cutLF f > >>>>>>> f2o rplc&(LF,' ') f > >>>>>>> f2x >cutLF f > >>>>>>> > >>>>>>> o2b cut o > >>>>>>> o2f rplc&(' ',LF) o > >>>>>>> o2x >cut o > >>>>>>> > >>>>>>> x2b <@dtb"1 x > >>>>>>> x2f ;<@(,&LF)@dtb"1 x > >>>>>>> x2o deb,' ',. x > >>>>>>> > >>>>>>> FYI, > >>>>>>> > >>>>>>> -- > >>>>>>> Raul > >>>>>>> > >>>>>>> On Thu, May 26, 2022 at 11:46 AM Ian Clark <[email protected]> > >>>>>> wrote: > >>>>>>>> Henry wrote: > >>>>>>>>> The problem was with the form > >>>>>>>> [&.>@:(<"0) 'ab' > >>>>>>>> (used in x2b). > >>>>>>>> > >>>>>>>> x2b is defined as: > >>>>>>>> [: (#~ ([: +./\. ' '&~:))&.> <"1 > >>>>>>>> so I guess that was a typo. But I get the idea. > >>>>>>>> > >>>>>>>> So… no need for me to make any changes to 'format/zulu' just yet. > >>>>>>>> > >>>>>>>> ASIDE: > >>>>>>>> --but when I do, I'll throw away the entire implementation. > >>>>>>>> > >>>>>>>> Zulu addresses an enduring need for the J beginner wanting to > >>> develop > >>>>>> code > >>>>>>>> for distribution. But it's deprecated for operational use. > >>>>>>>> > >>>>>>>> Zulu is an awful example of the edge-case 'tail' wagging the JAL > >>>> 'dog'. > >>>>>>>> If we ever get a *usable* addon, or a primitive (?), which > >>>>>> comprehensively > >>>>>>>> supports dictionaries, or even just collections of strings, then I > >>>>>> hope & > >>>>>>>> pray it eats Zulu for breakfast. > >>>>>>>> > >>>>>>>> > >>>>>>>> Zulu's aims could be met by publishing a 4x4 grid of recommended > >>>>>>>> *consistent* conversions between the 4 common "strings" formats: > >>>>>>>> > >>>>>>>> b - boxed > >>>>>>>> > >>>>>>>> f - LF-separated > >>>>>>>> > >>>>>>>> o - open > >>>>>>>> > >>>>>>>> x - matrix > >>>>>>>> > >>>>>>>> See the lab: Strings conversion package. > >>>>>>>> > >>>>>>>> > >>>>>>>> WHAT'S MORE: > >>>>>>>> > >>>>>>>> A user-facing app doing smart things with LF-separated strings > >> must > >>>>>> adopt a > >>>>>>>> policy towards final LF, especially for handling a collection of > >>>>>> substrings > >>>>>>>> containing 0 or 1 members. > >>>>>>>> > >>>>>>>> Zulu adopts the wrong policy. And pays for it with lots of slow > >>>>>> edge-case > >>>>>>>> code. > >>>>>>>> > >>>>>>>> On Wed, 25 May 2022 at 18:24, Henry Rich <[email protected]> > >>>> wrote: > >>>>>>>>> Fixed for next beta. The problem was with the form > >>>>>>>>> > >>>>>>>>> [&.>@:(<"0) 'ab' > >>>>>>>>> > >>>>>>>>> (used in x2b). The <"n created virtual blocks but erroneously > >>>>>> flagged > >>>>>>>>> them as inplaceable. > >>>>>>>>> > >>>>>>>>> Workaround: replace (<"n) with (<"<"n). > >>>>>>>>> > >>>>>>>>> Henry Rich > >>>>>>>>> > >>>>>>>>> On 5/24/2022 8:25 PM, Ian Clark wrote: > >>>>>>>>>> Note: Addon 'format/zulu' does not crash 903 or earlier. > >>>>>>>>>> > >>>>>>>>>> > >>>>>>>>>> JVERSION > >>>>>>>>>> > >>>>>>>>>> Engine: j904/j64/darwin > >>>>>>>>>> > >>>>>>>>>> Beta-d: commercial/2022-05-19T20:41:44 > >>>>>>>>>> > >>>>>>>>>> Library: 9.04.01 > >>>>>>>>>> > >>>>>>>>>> Qt IDE: 2.0.3/6.2.4(6.2.4) > >>>>>>>>>> > >>>>>>>>>> Platform: Darwin 64 > >>>>>>>>>> > >>>>>>>>>> Installer: J904 install > >>>>>>>>>> > >>>>>>>>>> InstallPath: /applications/j904 > >>>>>>>>>> > >>>>>>>>>> Contact: www.jsoftware.com > >>>>>>>>>> > >>>>>>>>>> > >>>>>>>>>> Addon 'format/zulu' is required by various addons, notably > >>>>>> math/tabula. > >>>>>>>>>> If loaded directly or indirectly by your ~config/startup.ijs > >>>>>>>>>> > >>>>>>>>>> then JQt will terminate without showing output. > >>>>>>>>>> > >>>>>>>>>> > >>>>>>>>>> jconsole will terminate also, but gives a briefer, clearer crash > >>>>>> report: > >>>>>>>>>> jconsole(2607,0x104ba4580) malloc: *** error for object > >>>>>> 0x138091fc0: > >>>>>>>>>> pointer being freed was not allocated > >>>>>>>>>> > >>>>>>>>>> jconsole(2607,0x104ba4580) malloc: *** set a breakpoint in > >>>>>>>>>> malloc_error_break to debug > >>>>>>>>>> > >>>>>>>>>> zsh: abort /Applications/j904/bin/jconsole > >>>>>>>>>> > >>>>>>>>>> > >>>>>>>>>> Saving session... > >>>>>>>>>> > >>>>>>>>>> ...copying shared history... > >>>>>>>>>> > >>>>>>>>>> ...saving history...truncating history files... > >>>>>>>>>> > >>>>>>>>>> ...completed. > >>>>>>>>>> > >>>>>>>>>> > >>>>>>>>>> [Process completed] > >>>>>>>>>> > >>>>>>>>>> > >>>>>>>>>> The crash is caused by execution of a verb: zutest_zulu_ . > >>>>>>>>>> > >>>>>>>>>> This verb gets executed as the final step in loading addon > >>>>>> 'format/zulu' > >>>>>>>>> . > >>>>>>>>>> It contributes nothing to the functionality of this suite of > >>> string > >>>>>>>>>> utilities, but gives all the working verbs a thorough test. > >>>>>>>>>> > >>>>>>>>>> > >>>>>>>>>> I hope to find out why it crashes before the weekend. Meanwhile, > >>>>>> here is > >>>>>>>>> a > >>>>>>>>>> workaround. > >>>>>>>>>> > >>>>>>>>>> It won't affect the operational behavior of the addon, but it's > >>>>>> like > >>>>>>>>>> turning off the fire alarms. > >>>>>>>>>> > >>>>>>>>>> Launch either jqt or jcon (any recent version)… > >>>>>>>>>> > >>>>>>>>>> > >>>>>>>>>> STEP 1 > >>>>>>>>>> > >>>>>>>>>> open'~addons/format/zulu/zutest.ijs' > >>>>>>>>>> > >>>>>>>>>> > >>>>>>>>>> STEP 2 > >>>>>>>>>> > >>>>>>>>>> Comment-out lines 64-66: > >>>>>>>>>> > >>>>>>>>>> > >>>>>>>>>> ok1=. ; 0 zutest each ;:'zu z1 z0' > >>>>>>>>>> > >>>>>>>>>> ok2=. ;0j1 zutest each ;:'zu z1 z0' NB. for conversions: a2* > >>>>>>>>>> > >>>>>>>>>> ZUTEST_z_=: ok1 , ok2 > >>>>>>>>>> > >>>>>>>>>> > >>>>>>>>>> STEP 3 > >>>>>>>>>> > >>>>>>>>>> Save the updated script. > >>>>>>>>>> > >>>>>>>>>> > >>>>>>>>>> Now you can triger the crash at will in either JQt or jcon like > >>>>>> this: > >>>>>>>>>> load 'format/zulu' NB. should not crash now > >>>>>>>>>> > >>>>>>>>>> 0 zutest 'zu' NB. crashes > >>>>>>>>>> > >> ---------------------------------------------------------------------- > >>>>>>>>>> For information about J forums see > >>>>>> http://www.jsoftware.com/forums.htm > >>>>>>>>> -- > >>>>>>>>> This email has been checked for viruses by AVG. > >>>>>>>>> https://www.avg.com > >>>>>>>>> > >>>>>>>>> > >> ---------------------------------------------------------------------- > >>>>>>>>> For information about J forums see > >>>>>> http://www.jsoftware.com/forums.htm > >>> ---------------------------------------------------------------------- > >>>>>>>> For information about J forums see > >>>> http://www.jsoftware.com/forums.htm > >> ---------------------------------------------------------------------- > >>>>>> For information about J forums see > >>> http://www.jsoftware.com/forums.htm > >> ---------------------------------------------------------------------- > >>>>> For information about J forums see > >> http://www.jsoftware.com/forums.htm > >>>> > >>>> -- > >>>> This email has been checked for viruses by AVG. > >>>> https://www.avg.com > >>>> > >>>> ---------------------------------------------------------------------- > >>>> For information about J forums see > http://www.jsoftware.com/forums.htm > >>>> > >>> ---------------------------------------------------------------------- > >>> For information about J forums see http://www.jsoftware.com/forums.htm > >>> > >> ---------------------------------------------------------------------- > >> For information about J forums see http://www.jsoftware.com/forums.htm > >> > > ---------------------------------------------------------------------- > > For information about J forums see http://www.jsoftware.com/forums.htm > > > -- > This email has been checked for viruses by AVG. > https://www.avg.com > > ---------------------------------------------------------------------- > For information about J forums see http://www.jsoftware.com/forums.htm > ---------------------------------------------------------------------- For information about J forums see http://www.jsoftware.com/forums.htm
