
Building on Brett's suggestion: FrameContext: used in/writable by one frame ContextStack: a FrameContext and its various fallbacks -jJ

On Mon, 21 Aug 2017 01:45:05 -0400 "Jim J. Jewett" <jimjjewett@gmail.com> wrote:
Building on Brett's suggestion:
FrameContext: used in/writable by one frame
It's not frame-specific, it's actually shared by an arbitrary number of frames (by default, all frames in a given thread). Regards Antoine.

On 08/21/2017 04:43 AM, Antoine Pitrou wrote:
On Mon, 21 Aug 2017 01:45:05 -0400 "Jim J. Jewett" <jimjjewett@gmail.com> wrote:
Building on Brett's suggestion:
FrameContext: used in/writable by one frame
It's not frame-specific, it's actually shared by an arbitrary number of frames (by default, all frames in a given thread).
You're thinking too specifically. A FrameContext/LogicalContext/LocalContext/etc is just a larger frame; although I would go with ExecutionContext/ContextFrame, myself. -- ~Ethan~

-1 on using "frame" in PEP 550 terminology. Antoine is right, the API is not frame-specific, and "frame" in Python has only one meaning. I can certainly see how "ContextFrame" can be correct if we think about "frame" as a generic term, but in Python, people will inadvertently think about a connection with frame objects/stacks. Yury

Yury Selivanov wrote:
I can certainly see how "ContextFrame" can be correct if we think about "frame" as a generic term, but in Python, people will inadvertently think about a connection with frame objects/stacks.
Calling it ExecutionContextFrame rather than just ContextFrame would make it clear that it relates to ExecutionContexts in particular. -- Greg

On 22 August 2017 at 10:02, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
Yury Selivanov wrote:
I can certainly see how "ContextFrame" can be correct if we think about "frame" as a generic term, but in Python, people will inadvertently think about a connection with frame objects/stacks.
Calling it ExecutionContextFrame rather than just ContextFrame would make it clear that it relates to ExecutionContexts in particular.
Please, no - it's already hard enough to help people internalise sync/async design concepts without also introducing ambiguity into the meaning of terms like locals & frame. Instead, let's leave those as purely referring to their existing always-synchronous concepts and find another suitable term for the dynamically nested read/write mappings making up the ExecutionContext :) Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

As I understand the key APIs and constraints of the proposal better, I'm leaning towards FooContext (LC) and FooContextStack (EC), for some value of Foo that I haven't determined yet. Perhaps the latter can be shortened to just ContextStack (since the Foo part can probably be guessed from context. :-) -- --Guido van Rossum (python.org/~guido)

Guido van Rossum wrote:
Perhaps the latter can be shortened to just ContextStack (since the Foo part can probably be guessed from context. :-)
-0.9, if I saw something called ContextStack turn up in a traceback I wouldn't necessarily jump to the conclusion that it was a stack of FooContexts rather than some other kind of context. EIBTI here, I think. -- Greg

On 2017-08-23 00:12, Greg Ewing wrote:
Guido van Rossum wrote:
Perhaps the latter can be shortened to just ContextStack (since the Foo part can probably be guessed from context. :-)
-0.9, if I saw something called ContextStack turn up in a traceback I wouldn't necessarily jump to the conclusion that it was a stack of FooContexts rather than some other kind of context. EIBTI here, I think.
The PEP says """This PEP proposes a new mechanism to manage execution state""", so ExecutionState or ExecState?

On Tue, Aug 22, 2017 at 8:22 AM, Guido van Rossum <guido@python.org> wrote:
As I understand the key APIs and constraints of the proposal better, I'm leaning towards FooContext (LC) and FooContextStack (EC), for some value of Foo that I haven't determined yet. Perhaps the latter can be shortened to just ContextStack (since the Foo part can probably be guessed from context. :-)
I guess I'll put in another vote for DynamicContext and DynamicContextStack. Though my earlier suggestion of these [1] sank like a stone, either because no-one saw it or because everyone hated it :-). We could do worse than just plain Context and ContextStack, for that matter. -n [1] https://mail.python.org/pipermail/python-ideas/2017-August/046840.html -- Nathaniel J. Smith -- https://vorpus.org

On Tue, Aug 22, 2017 at 7:12 PM, Nathaniel Smith <njs@pobox.com> wrote:
We could do worse than just plain Context and ContextStack, for that matter.
I worry that that's going to lead more people astray thinking this has something to do with contextlib, which it really doesn't (it's much more closely related to threading.local()). Regarding DynamicAnything, I certainly saw it and didn't like it -- the only place where I've ever seen dynamic scoping was in Emacs Lisp, and I believe was first shown to me as anti-pattern thirty years ago. -- --Guido van Rossum (python.org/~guido)

On Tue, Aug 22, 2017 at 8:51 PM, Guido van Rossum <guido@python.org> wrote:
On Tue, Aug 22, 2017 at 7:12 PM, Nathaniel Smith <njs@pobox.com> wrote:
We could do worse than just plain Context and ContextStack, for that matter.
I worry that that's going to lead more people astray thinking this has something to do with contextlib, which it really doesn't (it's much more closely related to threading.local()).
I guess that could be an argument for LocalContext and LocalContextStack, to go back full circle... -n -- Nathaniel J. Smith -- https://vorpus.org

On 23 August 2017 at 13:51, Guido van Rossum <guido@python.org> wrote:
Regarding DynamicAnything, I certainly saw it and didn't like it -- the only place where I've ever seen dynamic scoping was in Emacs Lisp, and I believe was first shown to me as anti-pattern thirty years ago.
As the original proponent of a Dynamic* naming scheme, I'll note that I eventually decided I didn't like it for the same reason I already didn't like naming schemes using either the word "local" or the word "frame": they all suggest a coupling to the synchronous call stack that deliberately isn't part of the proposal. That is (at least for me): - "local" suggests the implicit context will change when locals() changes - "frame" suggests the implicit context will change when the running frame changes - "dynamic" suggest dynamic scoping, which again suggests the implicit context will change on every function call None of those associations are true, since the essential point of the proposal is to *share* implicit state between frames of execution. The tricky part is defining exactly which frames should and shouldn't share their implicit context - threading.locals() is our current best attempt, and the PEP is mainly driven by the problems introduced by relying solely on that in programs that implement concurrent execution of Python code independently of the underlying operating system threads. My concern with "logical" context is different, which is that as a term it feels too *broad* to me: I'd expect the lexical context (nonlocals, module globals), the explicit context (function parameters), and the runtime context (process globals, threading.locals()) to also be considered part of the overall logical context. It's also a very computer-sciencey term of art - if you ask an arbitrary English speaker "What does 'logical' mean?", they're very *un*likely to give you an answer that has anything to do with logical threads of control in computer programs. My latest suggestion (ImplicitContext) has some of the same issues as "logical context" (since the runtime context is also implicit), but seems more defensible on the grounds of it aiming to be a more robust way of accessing and manipulating implicit state in concurrent programs, rather than it being the only kind of implicit state that exists in an application. As an English word, the sense of "capable of being understood from something else though unexpressed" (the first definition that Merriam-Webster give) also has the benefit of describing *exactly* what the PEP is aiming to achieve. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Tue, Aug 22, 2017 at 11:21 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
As the original proponent of a Dynamic* naming scheme, I'll note that I eventually decided I didn't like it for the same reason I already didn't like naming schemes using either the word "local" or the word "frame": they all suggest a coupling to the synchronous call stack that deliberately isn't part of the proposal.
However, there is still *some* connection with the frame, though it's subtle. In particular the LC (using PEP v3 terms) for a generator is tied to that generator's frame (it becomes the top of the EC stack whenever that generator is resumed). I don't think we should call this out in the naming scheme though. -- --Guido van Rossum (python.org/~guido)

For the record, I'm starting to think that "implicit context" is a reasonable name. (in case anyone is interested in those 2 cents of mine :-)) Regards Antoine.

I think that "implicit context" is not an accurate description of what LogicalContext is. "implicit context" only makes sense when we talk about decimal context. For instance, in: Decimal(1) + Decimal(2) decimal context is implicit. But this is "implicit" from the standpoint of that code. Decimal will manage its context *explicitly*. Fixing decimal context is only one part of the PEP though. EC will also allow to implement asynchronous task locals: current_request = new_context_key() async def handle_http_request(request): current_request.set(request) Here we explicitly set and will explicitly get values from the EC. We will explicitly manage the EC in asyncio.Task and when we schedule callbacks. Values stored in the EC are essentially globals (or TLS), which we don't call "implicit" in Python. PEP 550 calls generators and asynchronous tasks as "logical threads", and "logical context" stems directly from that notion. "implicit" only covers one part of what LC really is. It implies that all EC/LC operations are implicit, which they are not. Logical Context is a neutral abstract term. Implicit Context bears a specific meaning that I don't think is accurate. Yury

On Wed, 23 Aug 2017 12:19:40 -0400 Yury Selivanov <yselivanov.ml@gmail.com> wrote:
PEP 550 calls generators and asynchronous tasks as "logical threads", and "logical context" stems directly from that notion.
I wouldn't refer to a generator as a "thread" personally. A thread essentially executes without intervention from outside code, which is not the case for a generator (where resumption is controlled by explicit next() calls or iteration by the consumer). That is also why I proposed the more general "task" (and "task context"). Of course, capitalized "Task" is given a specific meaning by asyncio... Regards Antoine.

On Wed, Aug 23, 2017 at 12:56 PM, Antoine Pitrou <solipsis@pitrou.net> wrote:
On Wed, 23 Aug 2017 12:19:40 -0400 Yury Selivanov <yselivanov.ml@gmail.com> wrote:
PEP 550 calls generators and asynchronous tasks as "logical threads", and "logical context" stems directly from that notion.
I wouldn't refer to a generator as a "thread" personally. A thread essentially executes without intervention from outside code, which is not the case for a generator (where resumption is controlled by explicit next() calls or iteration by the consumer).
I agree. That's why we are rewriting the PEP without mentioning "logical threads".
That is also why I proposed the more general "task" (and "task context"). Of course, capitalized "Task" is given a specific meaning by asyncio...
Yeah.. I like TaskContext when it's applied to asynchronous code. It doesn't really work for generators because we never refer to generators as tasks. Out of what was proposed so far to replace Logical Context: 1. DynamicContext: close to "dynamic scoping", but tries to avoid mentioning "scopes". There are only a few languages where dynamic scoping is implemented, so people are generally not aware of it. 2. ContextFrame and all frame-related names: implies that EC is somehow implemented on top of frames or is frame-specific (which is not always true). 3. ImplicitContext: covers one specific property observed from specific examples. Context in PEP 550 is managed explicitly in some cases. There are many use cases when API users will be working with it explicitly too (to wrirte/read data from it). FWIW I believe that "ExplicitContext" would be more accurate than "ImplicitContext". 4. LocalContext: we use "local" to describe local variables and scoping in Python, we want to avoid any confusion here. 5. TaskContext: works for asynchronous tasks, but not for generators. I don't think that replacing LogicalContext with any name in this list will make any improvement. Yury

In favor of ImplicitContext is one point: it is indeed "implicit" if you compare it with the "explicit" way of passing state around, which would require an extra argument containing the state for any function that uses the state *or calls a function that uses the state* (recursively). On Wed, Aug 23, 2017 at 11:27 AM, Yury Selivanov <yselivanov.ml@gmail.com> wrote:
On Wed, Aug 23, 2017 at 12:56 PM, Antoine Pitrou <solipsis@pitrou.net> wrote:
On Wed, 23 Aug 2017 12:19:40 -0400 Yury Selivanov <yselivanov.ml@gmail.com> wrote:
PEP 550 calls generators and asynchronous tasks as "logical threads", and "logical context" stems directly from that notion.
I wouldn't refer to a generator as a "thread" personally. A thread essentially executes without intervention from outside code, which is not the case for a generator (where resumption is controlled by explicit next() calls or iteration by the consumer).
I agree. That's why we are rewriting the PEP without mentioning "logical threads".
That is also why I proposed the more general "task" (and "task context"). Of course, capitalized "Task" is given a specific meaning by asyncio...
Yeah.. I like TaskContext when it's applied to asynchronous code. It doesn't really work for generators because we never refer to generators as tasks.
Out of what was proposed so far to replace Logical Context:
1. DynamicContext: close to "dynamic scoping", but tries to avoid mentioning "scopes". There are only a few languages where dynamic scoping is implemented, so people are generally not aware of it.
2. ContextFrame and all frame-related names: implies that EC is somehow implemented on top of frames or is frame-specific (which is not always true).
3. ImplicitContext: covers one specific property observed from specific examples. Context in PEP 550 is managed explicitly in some cases. There are many use cases when API users will be working with it explicitly too (to wrirte/read data from it). FWIW I believe that "ExplicitContext" would be more accurate than "ImplicitContext".
4. LocalContext: we use "local" to describe local variables and scoping in Python, we want to avoid any confusion here.
5. TaskContext: works for asynchronous tasks, but not for generators.
I don't think that replacing LogicalContext with any name in this list will make any improvement.
Yury _______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/ guido%40python.org
-- --Guido van Rossum (python.org/~guido)

On Wed, Aug 23, 2017 at 2:47 PM, Guido van Rossum <guido@python.org> wrote:
In favor of ImplicitContext is one point: it is indeed "implicit" if you compare it with the "explicit" way of passing state around, which would require an extra argument containing the state for any function that uses the state *or calls a function that uses the state* (recursively).
This is a good point, now I understand the reasoning better. I guess I'm looking at this from a perspective of PEP 550 users. They will use either ContextKey-like API described in the PEP now, or something similar to threading.local() to store values in the context of a generator or an async task. From the standpoint of the user, they work with some sort of of a "global" variable. To me, renaming LC to ImplicitContext sounds similar to saying that using global variables is implicit, or calling "global" scope "implicit". Yury

On 08/23/2017 11:27 AM, Yury Selivanov wrote:
Out of what was proposed so far to replace Logical Context:
[...]
I don't think that replacing LogicalContext with any name in this list will make any improvement.
How about ExecutionContext and ContextVars ? We are already used to different levels of variables: global, local, non-local, class. I think having variables tied to a Context, and having search flow back to previous Contexts, would be easy to understand. -- ~Ethan~

How about ExecutionContext and ContextVars ?
We are already used to different levels of variables: global, local, non-local, class. I think having variables tied to a Context, and having search flow back to previous Contexts, would be easy to understand.
Yeah, I had this idea about ContextVars and so far I like it more than Context Keys and Context Values. In the next version of the PEP (will post it soon), we use Execution Context, Logical Context, and Context Variable terminology (the debate if we should use other names is, of course, still open). Yury

On 08/23/2017 12:17 PM, Yury Selivanov wrote:
How about ExecutionContext and ContextVars ?
We are already used to different levels of variables: global, local, non-local, class. I think having variables tied to a Context, and having search flow back to previous Contexts, would be easy to understand.
Yeah, I had this idea about ContextVars and so far I like it more than Context Keys and Context Values.
In the next version of the PEP (will post it soon), we use Execution Context, Logical Context, and Context Variable terminology (the debate if we should use other names is, of course, still open).
ContextVars is actually a different name for LogicalContext. So it would be: ExecutionContext = [ContextVars()[, ContextVars()[ ...]]] and you get the (thread.local similar) ContextVars by context_vars = sys.get_context_vars() # or whatever context_vars.verbose = ... -- ~Ethan~

On 24 August 2017 at 08:47, Ethan Furman <ethan@stoneleaf.us> wrote:
ContextVars is actually a different name for LogicalContext. So it would be:
ExecutionContext = [ContextVars()[, ContextVars()[ ...]]]
and you get the (thread.local similar) ContextVars by
context_vars = sys.get_context_vars() # or whatever context_vars.verbose = ...
Migrating a (variant of a) naming subthread from python-ideas over to here, does the following sound plausible to anyone else?: ContextLocal - read/write access API (via get()/set() methods) ContextLocalNamespace - active mapping that CL.get()/set() manipulates ExecutionContext - current stack of context local namespaces Building a threading.local() style helper API would then look something like: class ContextLocals: def __init__(self, key_prefix): self._key_prefix = key_prefix def __getattr__(self, attr): debugging_name = "{}.{}".format(self._key_prefix, attr) self.__dict__[attr] = new_local = sys.new_context_local(debugging_name) return new_local def __setattr__(self, attr, value): getattr(self, attr).set(value) def __delattr__(self, attr): getattr(self, attr).set(None) my_state = ContextLocals(__name__) Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

It shouldn't be called a namespace unless the dominant access is via attributes. On Thu, Aug 24, 2017 at 4:37 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
On 24 August 2017 at 08:47, Ethan Furman <ethan@stoneleaf.us> wrote:
ContextVars is actually a different name for LogicalContext. So it would be:
ExecutionContext = [ContextVars()[, ContextVars()[ ...]]]
and you get the (thread.local similar) ContextVars by
context_vars = sys.get_context_vars() # or whatever context_vars.verbose = ...
Migrating a (variant of a) naming subthread from python-ideas over to here, does the following sound plausible to anyone else?:
ContextLocal - read/write access API (via get()/set() methods) ContextLocalNamespace - active mapping that CL.get()/set() manipulates ExecutionContext - current stack of context local namespaces
Building a threading.local() style helper API would then look something like:
class ContextLocals: def __init__(self, key_prefix): self._key_prefix = key_prefix
def __getattr__(self, attr): debugging_name = "{}.{}".format(self._key_prefix, attr) self.__dict__[attr] = new_local = sys.new_context_local(debugging_name) return new_local
def __setattr__(self, attr, value): getattr(self, attr).set(value)
def __delattr__(self, attr): getattr(self, attr).set(None)
my_state = ContextLocals(__name__)
Cheers, Nick.
-- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia _______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/ guido%40python.org
-- --Guido van Rossum (python.org/~guido)

On 25 August 2017 at 01:00, Guido van Rossum <guido@python.org> wrote:
It shouldn't be called a namespace unless the dominant access is via attributes.
That makes sense. Since the main purpose of that part of the Python API is to offer an opaque handle to where the context locals store their values, something semantically neutral like "State" may work: - ContextLocal: read/write API - ContextLocalState: where ContextLocal instances actually store things - ExecutionContext: nested stack of context local states The attribute on generators and coroutines could then be called "__context_locals__", and that would either be None (indicating that any context local references will just use the already active context local storage), or else it would be set to a ContextLocalState instance (indicate that starting & stopping the operation will push & pop the given context local state). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

I think we should let the naming issue go for now, while Yury et al. are rewriting the PEP. We'll revisit it after we're more comfortable with the semantics. On Thu, Aug 24, 2017 at 9:55 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
On 25 August 2017 at 01:00, Guido van Rossum <guido@python.org> wrote:
It shouldn't be called a namespace unless the dominant access is via attributes.
That makes sense.
Since the main purpose of that part of the Python API is to offer an opaque handle to where the context locals store their values, something semantically neutral like "State" may work:
- ContextLocal: read/write API - ContextLocalState: where ContextLocal instances actually store things - ExecutionContext: nested stack of context local states
The attribute on generators and coroutines could then be called "__context_locals__", and that would either be None (indicating that any context local references will just use the already active context local storage), or else it would be set to a ContextLocalState instance (indicate that starting & stopping the operation will push & pop the given context local state).
Cheers, Nick.
-- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
-- --Guido van Rossum (python.org/~guido)

On Thu, Aug 24, 2017 at 5:37 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
Migrating a (variant of a) naming subthread from python-ideas over to here, does the following sound plausible to anyone else?:
ContextLocal - read/write access API (via get()/set() methods) ContextLocalNamespace - active mapping that CL.get()/set() manipulates ExecutionContext - current stack of context local namespaces
Overall it makes sense. The following derivative might be more clear: ContextLocal ContextLocals ChainedContextLocals (or some variation explicitly calling out the chaining) Alternatively, similar to other suggestions: ContextVar ContextVars ChainedContextVars I also think "state" helps disambiguate "context": ContextVar ContextState ChainedContextState or: ContextVar ContextVars ContextState (perhaps a little too ambiguous without the explicit "chained") -eric

On Wed, 23 Aug 2017 14:27:55 -0400 Yury Selivanov <yselivanov.ml@gmail.com> wrote:
Yeah.. I like TaskContext when it's applied to asynchronous code. It doesn't really work for generators because we never refer to generators as tasks.
Out of what was proposed so far to replace Logical Context:
1. DynamicContext: close to "dynamic scoping", but tries to avoid mentioning "scopes". There are only a few languages where dynamic scoping is implemented, so people are generally not aware of it.
2. ContextFrame and all frame-related names: implies that EC is somehow implemented on top of frames or is frame-specific (which is not always true).
3. ImplicitContext: covers one specific property observed from specific examples. Context in PEP 550 is managed explicitly in some cases. There are many use cases when API users will be working with it explicitly too (to wrirte/read data from it). FWIW I believe that "ExplicitContext" would be more accurate than "ImplicitContext".
4. LocalContext: we use "local" to describe local variables and scoping in Python, we want to avoid any confusion here.
5. TaskContext: works for asynchronous tasks, but not for generators.
I don't think that replacing LogicalContext with any name in this list will make any improvement.
I think you have a point. Though every time I want to type "logical context" it seems my fingers slip and type "local context" instead :-) Now remains the question of why the logical context stack is named "execution context" and not "logical context stack" (or "logical context chain" to keep the ChainMap analogy) :-) Regards Antoine.

On 24 August 2017 at 02:19, Yury Selivanov <yselivanov.ml@gmail.com> wrote:
I think that "implicit context" is not an accurate description of what LogicalContext is.
"implicit context" only makes sense when we talk about decimal context. For instance, in:
Decimal(1) + Decimal(2)
decimal context is implicit. But this is "implicit" from the standpoint of that code. Decimal will manage its context *explicitly*.
Fixing decimal context is only one part of the PEP though. EC will also allow to implement asynchronous task locals:
current_request = new_context_key()
async def handle_http_request(request): current_request.set(request)
Here we explicitly set and will explicitly get values from the EC. We will explicitly manage the EC in asyncio.Task and when we schedule callbacks.
The implicit behaviour that "implicit context" refers to is the fact that if you look at an isolated snippet of code, you have no idea what context you're actually going to be querying or modifying - that's implicit in the execution of the whole program. As a user of the read/write API though, you shouldn't need to care all that much - the whole point of PEP 550 is to define default behaviours and guidelines such that it will be something sensible. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Thu, Aug 24, 2017 at 1:22 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
On 24 August 2017 at 02:19, Yury Selivanov <yselivanov.ml@gmail.com> wrote:
I think that "implicit context" is not an accurate description of what LogicalContext is.
"implicit context" only makes sense when we talk about decimal context. For instance, in:
Decimal(1) + Decimal(2)
decimal context is implicit. But this is "implicit" from the standpoint of that code. Decimal will manage its context *explicitly*.
Fixing decimal context is only one part of the PEP though. EC will also allow to implement asynchronous task locals:
current_request = new_context_key()
async def handle_http_request(request): current_request.set(request)
Here we explicitly set and will explicitly get values from the EC. We will explicitly manage the EC in asyncio.Task and when we schedule callbacks.
The implicit behaviour that "implicit context" refers to is the fact that if you look at an isolated snippet of code, you have no idea what context you're actually going to be querying or modifying - that's implicit in the execution of the whole program.
How about: RuntimeContext and RuntimeContextStack -n -- Nathaniel J. Smith -- https://vorpus.org
participants (11)
-
Antoine Pitrou
-
Eric Snow
-
Ethan Furman
-
Greg Ewing
-
Guido van Rossum
-
Jim J. Jewett
-
MRAB
-
Nathaniel Smith
-
Nick Coghlan
-
Simon Cross
-
Yury Selivanov