Re: CTFE Status 2
On Thursday, 16 February 2017 at 21:05:51 UTC, Stefan Koch wrote: [ ... ] Hi there, I just pulled another all nighter. I found a bug in the code that was supposed to adjust the values of || and &&. As will as a mixup in the error messages for overlapping slice-assignment. Both are fixed. I am aware that overlapping slice assignment check is not yet good enough. This is on my short-term todo list. But in the even shorter-term, there are a couple hours sleep waiting to be claimed. Night guys, Stefan
Re: SCons and D
On Thursday, 8 June 2017 at 14:27:53 UTC, Russel Winder wrote: It seems I am on a bit of a roll getting changesets relating to D support for SCons into an appropriate state so that they get merged into the mainline SCons repository. So maybe now is a time to get any "pet peeves" with D support in SCons fixed. When I create a shared library I get an error message. SharedLibrary('lib2', ['lib2.d']) leads to dmd -oflib2.so -shared -defaultlib=libphobos2.so -L-soname=lib2.so lib2.os Error: unrecognized file extension os Apparently using the .os extension works for C but not with dmd.
Re: SCons, Python 3, and D
On Thursday, 8 June 2017 at 09:42:50 UTC, Russel Winder wrote: In case anyone has missed recent news, SCons seems now to work without any problems using Python 3 Nice. I am using Python 3 to run all my SCons D builds. Me too :)
Re: Concept proposal: Safely catching error
I want to start by stating that the discussion around being able to throw Error from nothrow functions and the compiler optimizations that follow is important to the thoughts below. The other aspect of array bounds checking is that those particular checks will not be added in -release. There has been much discussion around this already and I do recall that the solution was that @safe code will retain the array bounds checks (I'm not sure if contracts was included in this). Thus if using -release and @safe you'd be able to rely on having an Error to catch. Now it might make sense for @safe code to throw an ArrayOutOfBounds Exception, but that would mean the function couldn't be marked as nothrow if array indexing is used. This is probably a terrible idea, but @safe nothrow functions could throw ArrayIndexError while @safe could throw ArrayIndexException. It would really suck that adding nothrow would change the semantics silently.
Re: Concept proposal: Safely catching error
On 6/8/17 11:19 AM, Stanislav Blinov wrote: On Thursday, 8 June 2017 at 14:13:53 UTC, Steven Schveighoffer wrote: void foo(Mutex m, Data d) pure { synchronized(m) { // ... manipulate d } // no guarantee m gets unlocked } Isn't synchronized(m) not nothrow? You're right, it isn't. I actually didn't know that. Also forgot to make my function nothrow. Fixed: void foo(Mutex m, Data d) pure nothrow { try { synchronized(m) { // .. manipulate d } } catch(Exception) { } } -Steve
Re: vibe.d on Web Framework Benchmarks
On 06/08/2017 05:09 AM, Dominikus Dittes Scherkl wrote: > Wow. Answer was actually visible before the OP. THAT is what I would > call fast. Did you use vibe.d? Your answer hasn't arrived yet. Using something other than vibe.d? :p Ali
Re: Concept proposal: Safely catching error
On Thursday, 8 June 2017 at 14:13:53 UTC, Steven Schveighoffer wrote: void foo(Mutex m, Data d) pure { synchronized(m) { // ... manipulate d } // no guarantee m gets unlocked } -Steve Isn't synchronized(m) not nothrow?
Re: SCons and D
On Thu, 2017-06-08 at 14:37 +, bachmeier via Digitalmars-d wrote: > On Thursday, 8 June 2017 at 14:27:53 UTC, Russel Winder wrote: > > It seems I am on a bit of a roll getting changesets relating to > > D support for SCons into an appropriate state so that they get > > merged into the mainline SCons repository. So maybe now is a > > time to get any "pet peeves" with D support in SCons fixed. > > > > For myself, I am currently working on a new tool "dub" to > > handle getting dependencies from the Dub repository. It works > > for unit_testing in my D projects, but I need to write some > > proper SCons tests before submitting a pull request to the > > SCons mainline. > > > > Anyone wanting to try the dub tool now will need to use dub.py > > from my SCons_D_Experiments Git repository on BitBucket or > > GitHub. > > > > (The dmd, ldc, and gdc tools in that repository are just > > mirrors of what is in the mainline Mercurial repository on > > BitBucket, unless some experiments rather than bug fixes are > > needed.) > > I'd like to give this a try, but do you have a link to your > repository? Sorry I failed to add the actual links: SCons_D_Experiment on BitBucket: https://bitbucket.org/russel/scons_d_experiment SCons_D_Experiment on GitHub: https://github.com/russel/SCons_D_Experiment My SCons clone on BitBucket: https://bitbucket.org/russel/scons SCons mainline on BitBucket: https://bitbucket.org/scons/scons -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder signature.asc Description: This is a digitally signed message part
Re: sqlite3 vs. sqlite-d
On Thu, 2017-06-08 at 14:55 +, Dejan Lekic via Digitalmars-d wrote: > On Thursday, 8 June 2017 at 13:37:41 UTC, Russel Winder wrote: > > > Exactly my point. Using SQLAlchemy made me actually enjoy > > writing database code. Which I did last year having avoided it > > Using ORM like SQLAlchemy certainly has benefits but like any > other ORM, it generates hideous SQL code, sometimes terribly > slow... SQLAlchemy is not just an ORM, though there is an ORM, there is also the expression language which is an internal DSL for writing SQL. Also the authors of SQLAlchemy do optimise the generated SQL. Though obviously if you are needing the optimal dark corner optimisation of Oracle 11.2.0.4 say, then you are on your own. -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder signature.asc Description: This is a digitally signed message part
Re: Concept proposal: Safely catching error
On 06/08/2017 04:02 PM, Olivier FAURE wrote: That's true. A "pure after cleanup" function is incompatible with catching Errors (unless we introduce a "scope(error)" keyword that also runs on errors, but that comes with other problems). Is pureMalloc supposed to be representative of pure functions, or more of a special case? That's not a rhetorical question, I genuinely don't know. I think it's supposed to be just as pure as any other pure function. Here's the pull request that added it: https://github.com/dlang/druntime/pull/1746 I don't see anything about it being special-cased in the compiler or such. The spec says a pure function "does not read or write any global or static mutable state", which seems incompatible with "save a global, then write it back like it was". True. Something similar is going on with @safe. There's a list of things that are "not allowed in safe functions" [1], but you can do all those things in @trusted code, of course. The list is about what the compiler rejects, not about what a @safe function can actually do. It might be the same with the things that pure functions can/cannot do. I suppose the idea is that it cannot be observed that pureMalloc messes with global state, so it's ok. The assumption being that you don't catch errors. By the way, with regards to purity and errors, `new` is the same as pureMalloc. When `new` throws an OutOfMemoryError and you catch it, you can see that errno has been set. Yet `new` is considered `pure`. In fact, doing so seems contrary to the assumption that you can run any two pure functions on immutable / independent data at the same time and you won't have race conditions. Actually, now I'm wondering whether pureMalloc & co handle potential race conditions at all, or just hope they don't happen. Apparently errno is thread-local. [1] https://dlang.org/spec/function.html#safe-functions
Re: sqlite3 vs. sqlite-d
On Thursday, 8 June 2017 at 13:37:41 UTC, Russel Winder wrote: Exactly my point. Using SQLAlchemy made me actually enjoy writing database code. Which I did last year having avoided it Using ORM like SQLAlchemy certainly has benefits but like any other ORM, it generates hideous SQL code, sometimes terribly slow...
Re: sqlite3 vs. sqlite-d
On Thursday, 8 June 2017 at 13:06:55 UTC, Ozan (O/N/S) wrote: Your sqlite-d solution would be complete if writing sqlite files are also possible. Ignore the SQL parsing stuff, it does not fit in a world of fast data processing. Writing or rather modifying sqlite-dbs is a bit harder then reading them. Since the B-Tree should not get to imbalanced. I started on write support a while back, but at that time I did not understand the structure well enough to guarantee efficient write-support. (which would also require you to keep the index updated and so on ...) As for parsing sql. Unfortunately the column information is stored in form of a create table statement which forces me to parse at-least that much sql. In order to provide a nice interface in which you don't have to look up the position of your columns manually.
Re: SCons and D
On Thursday, 8 June 2017 at 14:27:53 UTC, Russel Winder wrote: It seems I am on a bit of a roll getting changesets relating to D support for SCons into an appropriate state so that they get merged into the mainline SCons repository. So maybe now is a time to get any "pet peeves" with D support in SCons fixed. For myself, I am currently working on a new tool "dub" to handle getting dependencies from the Dub repository. It works for unit_testing in my D projects, but I need to write some proper SCons tests before submitting a pull request to the SCons mainline. Anyone wanting to try the dub tool now will need to use dub.py from my SCons_D_Experiments Git repository on BitBucket or GitHub. (The dmd, ldc, and gdc tools in that repository are just mirrors of what is in the mainline Mercurial repository on BitBucket, unless some experiments rather than bug fixes are needed.) I'd like to give this a try, but do you have a link to your repository?
SCons and D
It seems I am on a bit of a roll getting changesets relating to D support for SCons into an appropriate state so that they get merged into the mainline SCons repository. So maybe now is a time to get any "pet peeves" with D support in SCons fixed. For myself, I am currently working on a new tool "dub" to handle getting dependencies from the Dub repository. It works for unit_testing in my D projects, but I need to write some proper SCons tests before submitting a pull request to the SCons mainline. Anyone wanting to try the dub tool now will need to use dub.py from my SCons_D_Experiments Git repository on BitBucket or GitHub. (The dmd, ldc, and gdc tools in that repository are just mirrors of what is in the mainline Mercurial repository on BitBucket, unless some experiments rather than bug fixes are needed.) -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder signature.asc Description: This is a digitally signed message part
Re: Concept proposal: Safely catching error
On 6/8/17 9:42 AM, Olivier FAURE wrote: On Thursday, 8 June 2017 at 12:20:19 UTC, Steven Schveighoffer wrote: Hm... if you locked an object that was passed in on the stack, for instance, there is no guarantee the object gets unlocked. This wouldn't be allowed unless the object was duplicated / created inside the try block. void foo(Mutex m, Data d) pure { synchronized(m) { // ... manipulate d } // no guarantee m gets unlocked } -Steve
Re: Concept proposal: Safely catching error
On Thursday, 8 June 2017 at 13:02:38 UTC, ag0aep6g wrote: Catching the resulting error is @safe when you throw the int* away. So if f is `pure` and you make sure that the arguments don't survive the `try` block, you're good, because f supposedly cannot have reached anything else. This is your proposal, right? Right. I don't think that's sound. At least, it clashes with another relatively recent development: https://dlang.org/phobos/core_memory.html#.pureMalloc That's a wrapper around C's malloc. C's malloc might set the global errno, so it's impure. pureMalloc achieves purity by resetting errno to the value it had before the call. So a `pure` function may mess with global state, as long as it cleans it up. But when it's interrupted (e.g. by an out-of-bounds error), it may leave globals in an invalid state. So you can't assume that a `pure` function upholds its purity when it throws an error. That's true. A "pure after cleanup" function is incompatible with catching Errors (unless we introduce a "scope(error)" keyword that also runs on errors, but that comes with other problems). Is pureMalloc supposed to be representative of pure functions, or more of a special case? That's not a rhetorical question, I genuinely don't know. The spec says a pure function "does not read or write any global or static mutable state", which seems incompatible with "save a global, then write it back like it was". In fact, doing so seems contrary to the assumption that you can run any two pure functions on immutable / independent data at the same time and you won't have race conditions. Actually, now I'm wondering whether pureMalloc & co handle potential race conditions at all, or just hope they don't happen.
Re: Concept proposal: Safely catching error
On Thursday, 8 June 2017 at 12:20:19 UTC, Steven Schveighoffer wrote: Hm... if you locked an object that was passed in on the stack, for instance, there is no guarantee the object gets unlocked. This wouldn't be allowed unless the object was duplicated / created inside the try block. Aside from the point that this still doesn't solve the problem (pure functions do cleanup too), this means a lot of headache for people who just want to write code. I'd much rather just write an array type and be done. -Steve Fair enough. There are other advantages to writing with "create data with pure functions then process it" idioms (easier to do unit tests, better for parallelism, etc), though.
Re: sqlite3 vs. sqlite-d
On Thu, 2017-06-08 at 11:36 +, Stefan Koch via Digitalmars-d wrote: > […] > The Alternative is not doing SQL at all. > But building the queries inside your code. Exactly my point. Using SQLAlchemy made me actually enjoy writing database code. Which I did last year having avoided it since I was born. > Which is what sqlite-d allows you to do. > and which is the reason I wrote it. > > I wanted to express my desires in code rather then having to log > sql-blocks around. Exactly. sqlpp11 made me think about doing database stuff for Me TV in C++ (currently there is a home grown ORM in the previous versions), but that I thought maybe there is something in D sqlite-d is not mentioned on https://wiki.dlang.org/Libraries_and_Frame works -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder signature.asc Description: This is a digitally signed message part
Re: sqlite3 vs. sqlite-d
On Wednesday, 7 June 2017 at 19:16:07 UTC, Stefan Koch wrote: On Wednesday, 7 June 2017 at 19:10:26 UTC, Ozan wrote: On Wednesday, 7 June 2017 at 17:51:30 UTC, Stefan Koch wrote: Hi guys I made a small video. Mature and heavily optimized C library vs. young D upstart. See for yourself how it turns out. https://www.youtube.com/watch?v=mOeVftcVsvI Cheers, Stefan Great. I like it (not the color of the terminal font - green!!! ;-) What is the cause for different benchmark results (from 30us up to 48us)? With your small number lines, do you implement the complete sqlite functionality? Regards, Ozan It's the Matrix-Movie green ;) I only implement reading the file format. And a few convenience functions for finding a table, iterating by rows, and extracting columns. The cause for the different results it like the scheduling of the OS. Since we do issue quite a large read before iterating. most of our time-slice has been used. which makes it possible for us to get swapped out during processing. I see, Matrix style. Red or blue pill, that's the question. ;-) Your sqlite-d solution would be complete if writing sqlite files are also possible. Ignore the SQL parsing stuff, it does not fit in a world of fast data processing. Regards Ozan
Re: Concept proposal: Safely catching error
On 06/08/2017 11:27 AM, Olivier FAURE wrote: Contracts are made to preempt memory corruption, and to protect against *programming* errors; they're not recoverable because breaking a contract means that from now on the program is in a state that wasn't anticipated by the programmer. Which means the only way to handle them gracefully is to cancel what you were doing and go back to the pre-contract-breaking state, then produce a big, detailed error message and then exit / remove the thread / etc. I might get the idea now. The throwing code could be in the middle of some unsafe operation when it throws the out-of-bounds error. It would have cleaned up after itself, but it can't because of the (unexpected) error. Silly example: void f(ref int* p) @trusted { p = cast(int*) 13; /* corrupt stuff or partially initialize or whatever */ int[] a; auto x = a[0]; /* trigger an out-of-bounds error */ p = new int; /* would have cleaned up */ } Catching the resulting error is @safe when you throw the int* away. So if f is `pure` and you make sure that the arguments don't survive the `try` block, you're good, because f supposedly cannot have reached anything else. This is your proposal, right? I don't think that's sound. At least, it clashes with another relatively recent development: https://dlang.org/phobos/core_memory.html#.pureMalloc That's a wrapper around C's malloc. C's malloc might set the global errno, so it's impure. pureMalloc achieves purity by resetting errno to the value it had before the call. So a `pure` function may mess with global state, as long as it cleans it up. But when it's interrupted (e.g. by an out-of-bounds error), it may leave globals in an invalid state. So you can't assume that a `pure` function upholds its purity when it throws an error. In the end, an error indicates that something is wrong, and probably all guarantees may be compromised.
Re: Concept proposal: Safely catching error
On 6/7/17 12:20 PM, Olivier FAURE wrote: On Monday, 5 June 2017 at 14:05:27 UTC, Steven Schveighoffer wrote: I don't think this will work. Only throwing Error makes a function nothrow. A nothrow function may not properly clean up the stack while unwinding. Not because the stack unwinding code skips over it, but because the compiler knows nothing can throw, and so doesn't include the cleanup code. If the function is @pure, then the only things it can set up will be stored on local or GC data, and it won't matter if they're not properly cleaned up, since they won't be accessible anymore. Hm... if you locked an object that was passed in on the stack, for instance, there is no guarantee the object gets unlocked. I'm not 100% sure about that, though. Can a pure function do impure things in its scope(exit) / destructor code? Even if it does pure things, that can cause problems. Not to mention that only doing this for pure code eliminates usages that sparked the original discussion, as my code communicates with a database, and that wouldn't be allowed in pure code. It would work for sending to a database; but you would need to use the functional programming idiom of "do 99% of the work in pure functions, then send the data to the remaining 1% for impure tasks". Even this still pushes the handling of the error onto the user. I want vibe.d to handle the error, in case I create a bug. But vibe.d can't possibly know what database things I'm going to do. And really this isn't possible. 99% of the work is using the database. A process's structure would be: - Read the inputs from the socket (impure, no catching errors) - Parse them and transform them into database requests (pure) - Send the requests to the database (impure) - Parse / analyse / whatever the results (pure) - Send the results to the socket (impure) And okay, yeah, that list isn't realistic. Using functional programming idioms in real life programs can be a pain in the ass, and lead to convoluted callback-based scaffolding and weird data structures that you need to pass around a bunch of functions that don't really need them. The point is, you could isolate the pure data-manipulating parts of the program from the impure IO parts; and encapsulate the former in Error-catching blocks (which is convenient, since those parts are likely to be more convoluted and harder to foolproof than the IO parts, therefore likely to throw more Errors). Aside from the point that this still doesn't solve the problem (pure functions do cleanup too), this means a lot of headache for people who just want to write code. I'd much rather just write an array type and be done. -Steve
Re: vibe.d on Web Framework Benchmarks
On Wednesday, 7 June 2017 at 21:18:21 UTC, ketmar wrote: Ozan wrote: On Wednesday, 7 June 2017 at 09:44:55 UTC, Ali Çehreli wrote: Is there an issue with the tests? Surprised that vibe.d is not higher in the rating... https://www.techempower.com/benchmarks/#section=data-r14&hw=ph&test=fortune Same for me. I used a lot of Java (Jetty, Tomcat) and Groovy (Grails) stuff before using D (vibe.d). On my machine I got a factor of 10-50 in difference. Vibe.d was always much faster. So where are the results coming from? most of it came from microbenchmarking. "how fast can we parse json and query db?" wow, what a great benchmark! surely, we don't need to do any data processing, let's measure raw speed of parsing data, and then throwing it away! Wow. Answer was actually visible before the OP. THAT is what I would call fast. Did you use vibe.d?
Re: sqlite3 vs. sqlite-d
On Thursday, 8 June 2017 at 08:44:56 UTC, Russel Winder wrote: But what is D's equivalent to Python's SQLAlchemy? C++ now has sqlpp11. Anyone doing SQL code manipulation with strings in another language is doing it wrong. Internal DSLs FTW. The Alternative is not doing SQL at all. But building the queries inside your code. Which is what sqlite-d allows you to do. and which is the reason I wrote it. I wanted to express my desires in code rather then having to log sql-blocks around.
SCons, Python 3, and D
In case anyone has missed recent news, SCons seems now to work without any problems using Python 3 (the one true Python – until Python 4, obviously). I am using Python 3 to run all my SCons D builds. Obviously this relates to using a checkout of the mainline Mercurial repository and using default branch. I am hoping that Bill will move to creating a new release soon. This will then appear on Arch and Fedora Rawhide fairly quickly I suspect. Debian will be ages yet as it is still in Debian 9 lockdown. Ubuntu and Mint, well who knows. I can recommend using SCons from the mainline repository. I use it with alias: alias scons="python3 /home/users/russel/Repositories/Mercurial/Forks/SCons/src/script/scons.py but, obviously, that only works for my location of the clone. -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder signature.asc Description: This is a digitally signed message part
Re: Concept proposal: Safely catching error
On Wednesday, 7 June 2017 at 19:45:05 UTC, ag0aep6g wrote: You gave the argument against catching out-of-bounds errors as: "it means an invariant is broken, which means the code surrounding it probably makes invalid assumptions and shouldn't be trusted." That line of reasoning applies to @trusted code. Only @trusted code can lose its trustworthiness. @safe code is guaranteed trustworthy (except for calls to @trusted code). To clarify, when I said "shouldn't be trusted", I meant in the general sense, not in the memory safety sense. I think Jonathan M Davis put it nicely: On Wednesday, 31 May 2017 at 23:51:30 UTC, Jonathan M Davis wrote: Honestly, once a memory corruption has occurred, all bets are off anyway. The core thing here is that the contract of indexing arrays was violated, which is a bug. If we're going to argue about whether it makes sense to change that contract, then we have to discuss the consequences of doing so, and I really don't see why whether a memory corruption has occurred previously is relevant. [...] In either case, the runtime has no way of determining the reason for the failure, and I don't see why passing a bad value to index an array is any more indicative of a memory corruption than passing an invalid day of the month to std.datetime's Date when constructing it is indicative of a memory corruption. The sane way to protect against memory corruption is to write safe code, not code that *might* shut down brutally onces memory corruption has already occurred. This is done by using @safe and proofreading all @trusted functions in your libs. Contracts are made to preempt memory corruption, and to protect against *programming* errors; they're not recoverable because breaking a contract means that from now on the program is in a state that wasn't anticipated by the programmer. Which means the only way to handle them gracefully is to cancel what you were doing and go back to the pre-contract-breaking state, then produce a big, detailed error message and then exit / remove the thread / etc. I think the issue of @trusted is tangential to this. If you (or the writer of a library you use) are using @trusted to cast away pureness and then have side effects, you're already risking data corruption and undefined behavior, catching Errors or no catching Errors. The point is that an out-of-bounds error implies a bug somewhere. If the bug is in @safe code, it doesn't affect safety at all. There is no explosion. But if the bug is in @trusted code, you can't determine how large the explosion is by looking at the function signature. I don't think there is much overlap between the problems that can be caused by faulty @trusted code and the problems than can be caught by Errors. Not that this is not a philosophical problem. I'm making an empirical claim: "Catching Errors would not open programs to memory safety attacks or accidental memory safety blunders that would not otherwise happen". For instance, if some poorly-written @trusted function causes the size of an int[10] slice to be registered as 20, then your program becomes vulnerable to buffer overflows when you iterate over it; the buffer overflow will not throw any Error. I'm not sure what the official stance is on this. As far as I'm aware, contracts and OOB checks are supposed to prevent memory corruption, not detect it. Any security based on detecting potential memory corruption can ultimately be bypassed by a hacker.
Re: sqlite3 vs. sqlite-d
On Wed, 2017-06-07 at 20:40 +, Stefan Koch via Digitalmars-d wrote: > On Wednesday, 7 June 2017 at 20:12:22 UTC, cym13 wrote: > > > It should be noted that the benchmark isn't fair, it favours > > the sqlite3 implementation as parsing and preparing the > > statement isn't measured. And yes, it's still faster which is > > cool ^^ > > > > Yes the benchmark is biased slightly in favor of sqlite3 C > implementation. > But sqlite-d does not have the ability to parse sql to the point > where it could implement that functionality. > Also sqlite-d is inefficient in quite a few places and is slowed > down by auto-decoding as I discovered just now. But what is D's equivalent to Python's SQLAlchemy? C++ now has sqlpp11. Anyone doing SQL code manipulation with strings in another language is doing it wrong. Internal DSLs FTW. -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder signature.asc Description: This is a digitally signed message part